Admin set default reactions (#9404)

Co-authored-by: ThatOneCalculator <kainoa@t1c.dev>
Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9404
This commit is contained in:
Kainoa Kanter 2023-01-05 04:06:48 +00:00
parent 0e121bff03
commit 508b33e503
33 changed files with 81 additions and 48 deletions

View file

@ -104,6 +104,8 @@
- Improve blocking instances - Improve blocking instances
- Release notes - Release notes
- New post style - New post style
- Admins set default reaction emoji
- Allows custom emoji
- MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1) - MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1)
- [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996) - [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996)
- [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056) - [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056)

View file

@ -556,7 +556,6 @@ tokenRequested: "منح حق الوصول إلى الحساب"
pluginTokenRequestedDescription: "ستتمكن الإضافة من استخدام هذه الأذونات." pluginTokenRequestedDescription: "ستتمكن الإضافة من استخدام هذه الأذونات."
notificationType: "أنواع الإشعارات" notificationType: "أنواع الإشعارات"
edit: "التعديل" edit: "التعديل"
useStarForReactionFallback: "استخدم ★ كبديل إذا كان التفاعل مجهولًا"
emailServer: "خادم البريد الإلكتروني" emailServer: "خادم البريد الإلكتروني"
emailConfigInfo: "يستخدم لتأكيد عنوان بريدك الإلكتروني ولإعادة تعيين كلمة المرور إن نسيتها." emailConfigInfo: "يستخدم لتأكيد عنوان بريدك الإلكتروني ولإعادة تعيين كلمة المرور إن نسيتها."
email: "البريد الإلكتروني " email: "البريد الإلكتروني "

View file

@ -577,7 +577,6 @@ tokenRequested: "অ্যাকাউন্টে অ্যাক্সেস
pluginTokenRequestedDescription: "এই প্লাগইনটি এখানে দেওয়া অনুমুতিসমূহ ব্যাবহার করবে" pluginTokenRequestedDescription: "এই প্লাগইনটি এখানে দেওয়া অনুমুতিসমূহ ব্যাবহার করবে"
notificationType: "বিজ্ঞপ্তির ধরন" notificationType: "বিজ্ঞপ্তির ধরন"
edit: "সম্পাদনা" edit: "সম্পাদনা"
useStarForReactionFallback: "রিঅ্যাকশনের ইমোজি না জানলে ★ ব্যবহার করুন"
emailServer: "ইমেইল সার্ভার" emailServer: "ইমেইল সার্ভার"
enableEmail: "ইমেইল বিতরণ চালু করুন" enableEmail: "ইমেইল বিতরণ চালু করুন"
emailConfigInfo: "আপনার ইমেল ঠিকানা নিশ্চিত করতে এবং আপনার পাসওয়ার্ড পুনরায় সেট করতে ব্যবহৃত হয়" emailConfigInfo: "আপনার ইমেল ঠিকানা নিশ্চিত করতে এবং আপনার পাসওয়ার্ড পুনরায় সেট করতে ব্যবহৃত হয়"

View file

@ -581,7 +581,6 @@ tokenRequested: "Zugriff zum Benutzerkonto gewähren"
pluginTokenRequestedDescription: "Dieses Plugin wird die hier konfigurierten Berechtigungen verwenden können." pluginTokenRequestedDescription: "Dieses Plugin wird die hier konfigurierten Berechtigungen verwenden können."
notificationType: "Art der Benachrichtigung" notificationType: "Art der Benachrichtigung"
edit: "Bearbeiten" edit: "Bearbeiten"
useStarForReactionFallback: "Verwende ★ falls das Reaktions-Emoji unbekannt ist"
emailServer: "Email-Server" emailServer: "Email-Server"
enableEmail: "Email-Versand aktivieren" enableEmail: "Email-Versand aktivieren"
emailConfigInfo: "Zur Email-Bestätigung bei Registrierung oder zum Zurücksetzen des Passworts verwendet" emailConfigInfo: "Zur Email-Bestätigung bei Registrierung oder zum Zurücksetzen des Passworts verwendet"

View file

@ -583,7 +583,6 @@ tokenRequested: "Grant access to account"
pluginTokenRequestedDescription: "This plugin will be able to use the permissions set here." pluginTokenRequestedDescription: "This plugin will be able to use the permissions set here."
notificationType: "Notification type" notificationType: "Notification type"
edit: "Edit" edit: "Edit"
useStarForReactionFallback: "Use ★ as fallback if the reaction emoji is unknown"
emailServer: "Email server" emailServer: "Email server"
enableEmail: "Enable email distribution" enableEmail: "Enable email distribution"
emailConfigInfo: "Used to confirm your email during sign-up or if you forget your password" emailConfigInfo: "Used to confirm your email during sign-up or if you forget your password"
@ -930,6 +929,7 @@ moveFrom: "Move to this account from an older account"
moveFromLabel: "Account you're moving from:" moveFromLabel: "Account you're moving from:"
moveFromDescription: "This will set an alias of your old account so that you can move from that account to this current one. Do this BEFORE moving from your older account. Please enter the tag of the account formatted like @person@instance.com" moveFromDescription: "This will set an alias of your old account so that you can move from that account to this current one. Do this BEFORE moving from your older account. Please enter the tag of the account formatted like @person@instance.com"
migrationConfirm: "Are you absolutely sure you want to migrate your acccount to {account}? Once you do this, you won't be able to reverse it, and you won't be able to use your account normally again.\nAlso, please ensure that you've set this current account as the account you're moving from." migrationConfirm: "Are you absolutely sure you want to migrate your acccount to {account}? Once you do this, you won't be able to reverse it, and you won't be able to use your account normally again.\nAlso, please ensure that you've set this current account as the account you're moving from."
defaultReaction: "Default emoji reaction for outgoing and incoming posts"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server." description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."

View file

@ -580,7 +580,6 @@ tokenRequested: "Permiso de acceso a la cuenta"
pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí" pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí"
notificationType: "Tipo de notificación" notificationType: "Tipo de notificación"
edit: "Editar" edit: "Editar"
useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella"
emailServer: "Servidor de correo" emailServer: "Servidor de correo"
enableEmail: "Activar el envío de correos electrónicos" enableEmail: "Activar el envío de correos electrónicos"
emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña" emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña"

View file

@ -567,14 +567,13 @@ large: "Grand"
medium: "Moyen" medium: "Moyen"
small: "Petit" small: "Petit"
generateAccessToken: "Générer un jeton d'accès" generateAccessToken: "Générer un jeton d'accès"
permission: "Autorisations " permission: "Autorisations"
enableAll: "Tout activer" enableAll: "Tout activer"
disableAll: "Tout désactiver" disableAll: "Tout désactiver"
tokenRequested: "Autoriser l'accès au compte" tokenRequested: "Autoriser l'accès au compte"
pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies ici." pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies ici."
notificationType: "Type de notifications" notificationType: "Type de notifications"
edit: "Editer" edit: "Editer"
useStarForReactionFallback: "Utiliser ★ comme alternative si lémoji de réaction est inconnu"
emailServer: "Serveur mail" emailServer: "Serveur mail"
enableEmail: "Activer la distribution de courriel" enableEmail: "Activer la distribution de courriel"
emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas doubli." emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas doubli."

View file

@ -577,7 +577,6 @@ tokenRequested: "Berikan ijin akses ke akun"
pluginTokenRequestedDescription: "Plugin ini dapat menggunakan setelan ijin disini." pluginTokenRequestedDescription: "Plugin ini dapat menggunakan setelan ijin disini."
notificationType: "Jenis pemberitahuan" notificationType: "Jenis pemberitahuan"
edit: "Sunting" edit: "Sunting"
useStarForReactionFallback: "Gunakan ★ sebagai fallback jika reaksi emoji tidak diketahui"
emailServer: "Peladen surel" emailServer: "Peladen surel"
enableEmail: "Nyalakan distribusi surel" enableEmail: "Nyalakan distribusi surel"
emailConfigInfo: "Digunakan untuk mengonfirmasi surel kamu disaat mendaftar dan lupa kata sandi" emailConfigInfo: "Digunakan untuk mengonfirmasi surel kamu disaat mendaftar dan lupa kata sandi"

View file

@ -573,7 +573,6 @@ tokenRequested: "Autorizza accesso all'account"
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui." pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui."
notificationType: "Tipo di notifiche" notificationType: "Tipo di notifiche"
edit: "Modifica" edit: "Modifica"
useStarForReactionFallback: "Se è sconosciuto l'emoji di reazione, usare la ★ come alternativa."
emailServer: "Server email" emailServer: "Server email"
enableEmail: "Abilita consegna email" enableEmail: "Abilita consegna email"
emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica e per reimpostare la tua password" emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica e per reimpostare la tua password"

View file

@ -583,7 +583,6 @@ tokenRequested: "アカウントへのアクセス許可"
pluginTokenRequestedDescription: "このプラグインはここで設定した権限を行使できるようになります。" pluginTokenRequestedDescription: "このプラグインはここで設定した権限を行使できるようになります。"
notificationType: "通知の種類" notificationType: "通知の種類"
edit: "編集" edit: "編集"
useStarForReactionFallback: "リアクション絵文字が不明な場合、代わりに★を使う"
emailServer: "メールサーバー" emailServer: "メールサーバー"
enableEmail: "メール配信機能を有効化する" enableEmail: "メール配信機能を有効化する"
emailConfigInfo: "メールアドレスの確認やパスワードリセットの際に使います" emailConfigInfo: "メールアドレスの確認やパスワードリセットの際に使います"

View file

@ -579,7 +579,6 @@ tokenRequested: "アカウントへのアクセス許可"
pluginTokenRequestedDescription: "このプラグインはここで設定した権限を使えるようになるで。" pluginTokenRequestedDescription: "このプラグインはここで設定した権限を使えるようになるで。"
notificationType: "通知の種類" notificationType: "通知の種類"
edit: "編集" edit: "編集"
useStarForReactionFallback: "リアクションがようわからん場合、★を使う"
emailServer: "メールサーバー" emailServer: "メールサーバー"
enableEmail: "メール配信を受け取る" enableEmail: "メール配信を受け取る"
emailConfigInfo: "メールアドレスの確認とかパスワードリセットの時に使うで" emailConfigInfo: "メールアドレスの確認とかパスワードリセットの時に使うで"

View file

@ -580,7 +580,6 @@ tokenRequested: "계정 접근 허용"
pluginTokenRequestedDescription: "이 플러그인은 여기서 설정한 권한을 사용할 수 있게 됩니다." pluginTokenRequestedDescription: "이 플러그인은 여기서 설정한 권한을 사용할 수 있게 됩니다."
notificationType: "알림 유형" notificationType: "알림 유형"
edit: "편집" edit: "편집"
useStarForReactionFallback: "알 수 없는 리액션 이모지 대신 ★ 사용"
emailServer: "메일 서버" emailServer: "메일 서버"
enableEmail: "이메일 송신 기능 활성화" enableEmail: "이메일 송신 기능 활성화"
emailConfigInfo: "가입 시 메일 주소 확인이나 비밀번호 초기화 시에 사용합니다." emailConfigInfo: "가입 시 메일 주소 확인이나 비밀번호 초기화 시에 사용합니다."

View file

@ -572,7 +572,6 @@ tokenRequested: "Przydziel dostęp do konta"
pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawionych tu uprawnień." pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawionych tu uprawnień."
notificationType: "Rodzaj powiadomień" notificationType: "Rodzaj powiadomień"
edit: "Edytuj" edit: "Edytuj"
useStarForReactionFallback: "Użyj ★ jako zapasowego emoji, gdy emoji reakcji jest nieznane"
emailServer: "Serwer poczty e-mail" emailServer: "Serwer poczty e-mail"
enableEmail: "Włącz dostarczanie wiadomości e-mail" enableEmail: "Włącz dostarczanie wiadomości e-mail"
emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji, lub gdy zapomnisz hasła" emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji, lub gdy zapomnisz hasła"

View file

@ -576,7 +576,6 @@ tokenRequested: "Acordă acces la cont"
pluginTokenRequestedDescription: "Acest plugin va putea să folosească permisiunile setate aici." pluginTokenRequestedDescription: "Acest plugin va putea să folosească permisiunile setate aici."
notificationType: "Tipul notificării" notificationType: "Tipul notificării"
edit: "Editează" edit: "Editează"
useStarForReactionFallback: "Folosește ★ ca fallback dacă emoji-ul este necunoscut"
emailServer: "Server email" emailServer: "Server email"
enableEmail: "Activează distribuția de emailuri" enableEmail: "Activează distribuția de emailuri"
emailConfigInfo: "Folosit pentru a confirma emailul tău în timpul logări dacă îți uiți parola" emailConfigInfo: "Folosit pentru a confirma emailul tău în timpul logări dacă îți uiți parola"

View file

@ -580,7 +580,6 @@ tokenRequested: "Открыть доступ к учётной записи"
pluginTokenRequestedDescription: "Это расширение сможет пользоваться разрешениями, установленными здесь." pluginTokenRequestedDescription: "Это расширение сможет пользоваться разрешениями, установленными здесь."
notificationType: "Тип уведомления" notificationType: "Тип уведомления"
edit: "Изменить" edit: "Изменить"
useStarForReactionFallback: "Ставить ★ в качестве реакции вместо неизвестного эмодзи"
emailServer: "Сервер электронной почты" emailServer: "Сервер электронной почты"
enableEmail: "Включить обмен электронной почтой" enableEmail: "Включить обмен электронной почтой"
emailConfigInfo: "Используется для подтверждения адреса электронной почты и сброса пароля." emailConfigInfo: "Используется для подтверждения адреса электронной почты и сброса пароля."

View file

@ -579,7 +579,6 @@ tokenRequested: "Povoliť prístup k účtu"
pluginTokenRequestedDescription: "Tento plugin bude môcť používať oprávnenia nastavené tu." pluginTokenRequestedDescription: "Tento plugin bude môcť používať oprávnenia nastavené tu."
notificationType: "Typ oznámenia" notificationType: "Typ oznámenia"
edit: "Upraviť" edit: "Upraviť"
useStarForReactionFallback: "Použiť ★ keď emoji reakcie nie je známe"
emailServer: "Email server" emailServer: "Email server"
enableEmail: "Zapnúť email" enableEmail: "Zapnúť email"
emailConfigInfo: "Používa sa na overenie emaily pri registrácii alebo pri zabudnutí hesla" emailConfigInfo: "Používa sa na overenie emaily pri registrácii alebo pri zabudnutí hesla"

View file

@ -580,7 +580,6 @@ tokenRequested: "ให้สิทธิ์การเข้าถึงบั
pluginTokenRequestedDescription: "ปลั๊กอินนี้จะสามารถใช้การอนุญาตที่ตั้งค่าไว้ที่นี่นะ" pluginTokenRequestedDescription: "ปลั๊กอินนี้จะสามารถใช้การอนุญาตที่ตั้งค่าไว้ที่นี่นะ"
notificationType: "ประเภทการแจ้งเตือน" notificationType: "ประเภทการแจ้งเตือน"
edit: "แก้ไข" edit: "แก้ไข"
useStarForReactionFallback: "ใช้ ★ เป็นทางเลือกแทนถ้าหากไม่ทราบอิโมจิ"
emailServer: "อีเมล์เซิร์ฟเวอร์" emailServer: "อีเมล์เซิร์ฟเวอร์"
enableEmail: "เปิดใช้งานการกระจายอีเมล" enableEmail: "เปิดใช้งานการกระจายอีเมล"
emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างการสมัครหรือถ้าหากคุณลืมรหัสผ่าน" emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างการสมัครหรือถ้าหากคุณลืมรหัสผ่าน"

View file

@ -577,7 +577,6 @@ tokenRequested: "Надати доступ до акаунту"
pluginTokenRequestedDescription: "Цей плагін зможе використовувати дозволи які тут вказані." pluginTokenRequestedDescription: "Цей плагін зможе використовувати дозволи які тут вказані."
notificationType: "Тип сповіщення" notificationType: "Тип сповіщення"
edit: "Редагувати" edit: "Редагувати"
useStarForReactionFallback: "Використовувати ★ як запасний варіант, якщо емодзі реакції невідомий"
emailServer: "Сервер електронної пошти" emailServer: "Сервер електронної пошти"
enableEmail: "Увімкнути функцію доставки пошти" enableEmail: "Увімкнути функцію доставки пошти"
emailConfigInfo: "Використовується для підтвердження електронної пошти підчас реєстрації, а також для відновлення паролю." emailConfigInfo: "Використовується для підтвердження електронної пошти підчас реєстрації, а також для відновлення паролю."

View file

@ -580,7 +580,6 @@ tokenRequested: "Cấp quyền truy cập vào tài khoản"
pluginTokenRequestedDescription: "Plugin này sẽ có thể sử dụng các quyền được đặt ở đây." pluginTokenRequestedDescription: "Plugin này sẽ có thể sử dụng các quyền được đặt ở đây."
notificationType: "Loại thông báo" notificationType: "Loại thông báo"
edit: "Sửa" edit: "Sửa"
useStarForReactionFallback: "Dùng ★ nếu emoji biểu cảm không có"
emailServer: "Email máy chủ" emailServer: "Email máy chủ"
enableEmail: "Bật phân phối email" enableEmail: "Bật phân phối email"
emailConfigInfo: "Được dùng để xác minh email của bạn lúc đăng ký hoặc nếu bạn quên mật khẩu của mình" emailConfigInfo: "Được dùng để xác minh email của bạn lúc đăng ký hoặc nếu bạn quên mật khẩu của mình"

View file

@ -580,7 +580,6 @@ tokenRequested: "允许访问账户"
pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限" pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限"
notificationType: "通知类型" notificationType: "通知类型"
edit: "编辑" edit: "编辑"
useStarForReactionFallback: "如果回应的是未知表情符号,则使用★作为代替"
emailServer: "邮件服务器" emailServer: "邮件服务器"
enableEmail: "启用发送邮件功能" enableEmail: "启用发送邮件功能"
emailConfigInfo: "用于确认电子邮件和密码重置" emailConfigInfo: "用于确认电子邮件和密码重置"

View file

@ -580,7 +580,6 @@ tokenRequested: "允許存取帳戶"
pluginTokenRequestedDescription: "此外掛將擁有在此設定的權限。" pluginTokenRequestedDescription: "此外掛將擁有在此設定的權限。"
notificationType: "通知形式" notificationType: "通知形式"
edit: "編輯" edit: "編輯"
useStarForReactionFallback: "以★代替未知的表情符號"
emailServer: "電郵伺服器" emailServer: "電郵伺服器"
enableEmail: "啟用發送電郵功能" enableEmail: "啟用發送電郵功能"
emailConfigInfo: "用於確認電郵地址及密碼重置" emailConfigInfo: "用於確認電郵地址及密碼重置"

View file

@ -0,0 +1,12 @@
export class DefaultReaction1672882664294 {
name = 'DefaultReaction1672882664294'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "defaultReaction" character varying(256) NOT NULL DEFAULT '⭐'`);
await queryRunner.query(`COMMENT ON COLUMN "meta"."defaultReaction" IS 'The fallback reaction for emoji reacts'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "defaultReaction"`);
}
}

View file

@ -21,7 +21,7 @@ const legacies: Record<string, string> = {
export async function getFallbackReaction(): Promise<string> { export async function getFallbackReaction(): Promise<string> {
const meta = await fetchMeta(); const meta = await fetchMeta();
return meta.useStarForReactionFallback ? '⭐' : '👍'; return meta.defaultReaction;
} }
export function convertLegacyReactions(reactions: Record<string, number>) { export function convertLegacyReactions(reactions: Record<string, number>) {

View file

@ -57,10 +57,10 @@ export class Meta {
}) })
public disableGlobalTimeline: boolean; public disableGlobalTimeline: boolean;
@Column('boolean', { @Column('varchar', {
default: false, length: 256, default: '⭐',
}) })
public useStarForReactionFallback: boolean; public defaultReaction: string;
@Column('varchar', { @Column('varchar', {
length: 64, array: true, default: '{}', length: 64, array: true, default: '{}',

View file

@ -4,16 +4,18 @@ import { NoteReaction } from '@/models/entities/note-reaction.js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
import { Emojis } from '@/models/index.js'; import { Emojis } from '@/models/index.js';
import renderEmoji from './emoji.js'; import renderEmoji from './emoji.js';
import { fetchMeta } from '@/misc/fetch-meta.js';
export const renderLike = async (noteReaction: NoteReaction, note: Note) => { export const renderLike = async (noteReaction: NoteReaction, note: Note) => {
const reaction = noteReaction.reaction; const reaction = noteReaction.reaction;
const meta = await fetchMeta();
const object = { const object = {
type: 'Like', type: 'Like',
id: `${config.url}/likes/${noteReaction.id}`, id: `${config.url}/likes/${noteReaction.id}`,
actor: `${config.url}/users/${noteReaction.userId}`, actor: `${config.url}/users/${noteReaction.userId}`,
object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`, object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`,
... (!['\u2b50', '\u1f44d'].includes(reaction) ? { ... (!meta.defaultReaction.includes(reaction) ? {
content: reaction, content: reaction,
_misskey_reaction: reaction, _misskey_reaction: reaction,
} : {}), } : {}),

View file

@ -159,10 +159,6 @@ export const meta = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
userStarForReactionFallback: {
type: 'boolean',
optional: true, nullable: false,
},
recommendedInstances: { recommendedInstances: {
type: 'array', type: 'array',
optional: true, nullable: false, optional: true, nullable: false,
@ -368,6 +364,10 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,
}, },
defaultReaction: {
type: 'string',
optional: false, nullable: false,
},
}, },
}, },
} as const; } as const;
@ -425,7 +425,7 @@ export default define(meta, paramDef, async (ps, me) => {
pinnedPages: instance.pinnedPages, pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId, pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
useStarForReactionFallback: instance.useStarForReactionFallback, defaultReaction: instance.defaultReaction,
recommendedInstances: instance.recommendedInstances, recommendedInstances: instance.recommendedInstances,
pinnedUsers: instance.pinnedUsers, pinnedUsers: instance.pinnedUsers,
customMOTD: instance.customMOTD, customMOTD: instance.customMOTD,

View file

@ -18,7 +18,7 @@ export const paramDef = {
disableLocalTimeline: { type: 'boolean', nullable: true }, disableLocalTimeline: { type: 'boolean', nullable: true },
disableRecommendedTimeline: { type: 'boolean', nullable: true }, disableRecommendedTimeline: { type: 'boolean', nullable: true },
disableGlobalTimeline: { type: 'boolean', nullable: true }, disableGlobalTimeline: { type: 'boolean', nullable: true },
useStarForReactionFallback: { type: 'boolean', nullable: true }, defaultReaction: { type: 'string', nullable: true },
recommendedInstances: { type: 'array', nullable: true, items: { recommendedInstances: { type: 'array', nullable: true, items: {
type: 'string', type: 'string',
} }, } },
@ -141,8 +141,8 @@ export default define(meta, paramDef, async (ps, me) => {
set.disableGlobalTimeline = ps.disableGlobalTimeline; set.disableGlobalTimeline = ps.disableGlobalTimeline;
} }
if (typeof ps.useStarForReactionFallback === 'boolean') { if (typeof ps.defaultReaction === 'string') {
set.useStarForReactionFallback = ps.useStarForReactionFallback; set.defaultReaction = ps.defaultReaction;
} }
if (Array.isArray(ps.pinnedUsers)) { if (Array.isArray(ps.pinnedUsers)) {

View file

@ -309,6 +309,11 @@ export const meta = {
optional: true, nullable: false, optional: true, nullable: false,
default: false, default: false,
}, },
defaultReaction: {
type: 'string',
optional: 'false', nullable: false,
default: '⭐',
},
}, },
}, },
} as const; } as const;
@ -401,6 +406,7 @@ export default define(meta, paramDef, async (ps, me) => {
enableServiceWorker: instance.enableServiceWorker, enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable: instance.deeplAuthKey != null,
defaultReaction: instance.defaultReaction,
...(ps.detail ? { ...(ps.detail ? {
pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages, pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages,

View file

@ -1,12 +1,13 @@
import { DOMWindow, JSDOM } from 'jsdom'; import { URL } from 'node:url';
import { JSDOM } from 'jsdom';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js';
import { Instance } from '@/models/entities/instance.js'; import type { Instance } from '@/models/entities/instance.js';
import { Instances } from '@/models/index.js'; import { Instances } from '@/models/index.js';
import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js'; import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js';
import Logger from './logger.js'; import Logger from './logger.js';
import { URL } from 'node:url'; import type { DOMWindow } from 'jsdom';
const logger = new Logger('metadata', 'cyan'); const logger = new Logger('metadata', 'cyan');
@ -235,7 +236,7 @@ async function getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | n
} }
if (manifest) { if (manifest) {
return manifest?.name || manifest?.short_name; return manifest.name || manifest.short_name;
} }
return null; return null;
@ -261,7 +262,7 @@ async function getDescription(info: NodeInfo | null, doc: DOMWindow['document']
} }
if (manifest) { if (manifest) {
return manifest?.name || manifest?.short_name; return manifest.name || manifest.short_name;
} }
return null; return null;

View file

@ -1,12 +1,14 @@
<template> <template>
<button v-tooltip.noDelay.bottom="i18n.ts._gallery.like" class="skdfgljsdkf _button" @click="star($event)"> <button v-tooltip.noDelay.bottom="i18n.ts._gallery.like" class="skdfgljsdkf _button" @click="star($event)">
<i v-if="defaultStore.state.woozyMode === false" class="ph-star-bold ph-lg"></i> <svg v-if="defaultStore.state.woozyMode === true" width="1.1em" height="1.1em" viewBox="0 0 36 36"><g fill="currentColor">
<svg v-else width="1.1em" height="1.1em" viewBox="0 0 36 36"><g fill="currentColor">
<path d="m17.809-0.20898c-9.9294 2.3e-7 -18 8.0706-18 18 5.8e-7 9.9294 8.0706 18 18 18 9.9294 0 18-8.0706 18-18 0-9.9294-8.0706-18-18-18zm0 1.9785c8.8604 1e-7 16.021 7.1611 16.021 16.021 0 8.8604-7.1611 16.023-16.021 16.023-8.8604 0-16.021-7.163-16.021-16.023-3e-7 -8.8604 7.1611-16.021 16.021-16.021z"/> <path d="m17.809-0.20898c-9.9294 2.3e-7 -18 8.0706-18 18 5.8e-7 9.9294 8.0706 18 18 18 9.9294 0 18-8.0706 18-18 0-9.9294-8.0706-18-18-18zm0 1.9785c8.8604 1e-7 16.021 7.1611 16.021 16.021 0 8.8604-7.1611 16.023-16.021 16.023-8.8604 0-16.021-7.163-16.021-16.023-3e-7 -8.8604 7.1611-16.021 16.021-16.021z"/>
<path d="m6.001 11c-0.552 0-1-0.448-1-1 0-0.551 0.445-0.998 0.996-1 0.156-2e-3 3.569-0.086 6.205-3.6 0.331-0.44 0.957-0.532 1.4-0.2 0.442 0.331 0.531 0.958 0.2 1.4-3.263 4.35-7.617 4.4-7.801 4.4zm24.986 2.393c0.128 0.537-0.204 1.077-0.741 1.205-0.536 0.128-1.074-0.202-1.204-0.737-0.038-0.151-0.911-3.452-4.941-5.201-0.505-0.22-0.739-0.808-0.519-1.315s0.809-0.739 1.315-0.519c4.989 2.165 6.047 6.388 6.09 6.567z"/> <path d="m6.001 11c-0.552 0-1-0.448-1-1 0-0.551 0.445-0.998 0.996-1 0.156-2e-3 3.569-0.086 6.205-3.6 0.331-0.44 0.957-0.532 1.4-0.2 0.442 0.331 0.531 0.958 0.2 1.4-3.263 4.35-7.617 4.4-7.801 4.4zm24.986 2.393c0.128 0.537-0.204 1.077-0.741 1.205-0.536 0.128-1.074-0.202-1.204-0.737-0.038-0.151-0.911-3.452-4.941-5.201-0.505-0.22-0.739-0.808-0.519-1.315s0.809-0.739 1.315-0.519c4.989 2.165 6.047 6.388 6.09 6.567z"/>
<path d="m23.186 29.526c-0.993 0-1.952-0.455-2.788-1.339-2.816-2.985-3.569-2.333-4.817-1.251-0.781 0.679-1.754 1.523-3.205 1.523-2.351 0-3.969-2.302-4.036-2.4-0.314-0.454-0.2-1.077 0.254-1.391 0.451-0.312 1.074-0.2 1.39 0.251 0.301 0.429 1.317 1.54 2.393 1.54 0.704 0 1.256-0.479 1.895-1.033 1.816-1.578 3.764-2.655 7.583 1.388 0.823 0.873 1.452 0.774 1.908 0.592 1.659-0.665 3.205-3.698 3.197-5.15-3e-3 -0.552 0.442-1.002 0.994-1.005h6e-3c0.55 0 0.997 0.444 1 0.995 0.012 2.103-1.854 5.976-4.454 7.017-0.443 0.175-0.885 0.262-1.32 0.263z"/> <path d="m23.186 29.526c-0.993 0-1.952-0.455-2.788-1.339-2.816-2.985-3.569-2.333-4.817-1.251-0.781 0.679-1.754 1.523-3.205 1.523-2.351 0-3.969-2.302-4.036-2.4-0.314-0.454-0.2-1.077 0.254-1.391 0.451-0.312 1.074-0.2 1.39 0.251 0.301 0.429 1.317 1.54 2.393 1.54 0.704 0 1.256-0.479 1.895-1.033 1.816-1.578 3.764-2.655 7.583 1.388 0.823 0.873 1.452 0.774 1.908 0.592 1.659-0.665 3.205-3.698 3.197-5.15-3e-3 -0.552 0.442-1.002 0.994-1.005h6e-3c0.55 0 0.997 0.444 1 0.995 0.012 2.103-1.854 5.976-4.454 7.017-0.443 0.175-0.885 0.262-1.32 0.263z"/>
<path d="m14.815 15.375c-0.584 2.114-1.642 3.083-3.152 2.666-1.509-0.417-2.343-1.909-1.76-4.023 0.583-2.112 2.175-3.363 3.684-2.946 1.511 0.417 1.812 2.19 1.228 4.303zm11.416-0.755c0.473 2.141-0.675 4.838-2.204 5.176s-3.28-1.719-3.753-3.86c-0.473-2.14 0.419-3.971 1.948-4.309s3.536 0.853 4.009 2.993z"/> <path d="m14.815 15.375c-0.584 2.114-1.642 3.083-3.152 2.666-1.509-0.417-2.343-1.909-1.76-4.023 0.583-2.112 2.175-3.363 3.684-2.946 1.511 0.417 1.812 2.19 1.228 4.303zm11.416-0.755c0.473 2.141-0.675 4.838-2.204 5.176s-3.28-1.719-3.753-3.86c-0.473-2.14 0.419-3.971 1.948-4.309s3.536 0.853 4.009 2.993z"/>
</g></svg> </g></svg>
<i v-else-if="instance.defaultReaction === '👍'" class="ph-thumbs-up-bold ph-lg"></i>
<i v-else-if="instance.defaultReaction === ''" class="ph-heart-bold ph-lg"></i>
<i v-else class="ph-star-bold ph-lg"></i>
</button> </button>
</template> </template>
@ -17,6 +19,7 @@ import { pleaseLogin } from '@/scripts/please-login';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { instance } from '@/instance';
const props = defineProps<{ const props = defineProps<{
note: Note; note: Note;
@ -26,7 +29,7 @@ function star(ev?: MouseEvent): void {
pleaseLogin(); pleaseLogin();
os.api('notes/reactions/create', { os.api('notes/reactions/create', {
noteId: props.note.id, noteId: props.note.id,
reaction: defaultStore.state.woozyMode === true ? '🥴' : '⭐', reaction: defaultStore.state.woozyMode === true ? '🥴' : instance.defaultReaction,
}); });
const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
if (el) { if (el) {

View file

@ -1,6 +1,6 @@
import { computed, reactive } from 'vue'; import { computed, reactive } from 'vue';
import * as Misskey from 'calckey-js';
import { api } from './os'; import { api } from './os';
import type * as Misskey from 'calckey-js';
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
@ -14,7 +14,7 @@ export const instance: Misskey.entities.InstanceMetadata = reactive(instanceData
export async function fetchInstance() { export async function fetchInstance() {
const meta = await api('meta', { const meta = await api('meta', {
detail: false detail: false,
}); });
for (const [k, v] of Object.entries(meta)) { for (const [k, v] of Object.entries(meta)) {

View file

@ -58,6 +58,24 @@
<FormInfo class="_formBlock">{{ i18n.ts.disablingTimelinesInfo }}</FormInfo> <FormInfo class="_formBlock">{{ i18n.ts.disablingTimelinesInfo }}</FormInfo>
</FormSection> </FormSection>
<FormSection>
<MkRadios v-model="defaultReaction" class="_formBlock">
<template #label>{{ i18n.ts.defaultReaction }}</template>
<option value="⭐">
<MkEmoji class="emoji" emoji="⭐" style="height: 1.7em"/>
</option>
<option value="👍">
<MkEmoji class="emoji" emoji="👍" style="height: 1.7em"/>
</option>
<option value="❤️">
<MkEmoji class="emoji" emoji="❤️" style="height: 1.7em"/>
</option>
<option value="custom">
<FormInput v-model="defaultReactionCustom" class="_formBlock" :small="true" :placeholder="`:custom:`" style="margin: 0 0 !important"/>
</option>
</MkRadios>
</FormSection>
<FormSection> <FormSection>
<template #label>{{ i18n.ts.theme }}</template> <template #label>{{ i18n.ts.theme }}</template>
@ -175,7 +193,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { } from 'vue'; import { ref } from 'vue';
import FormSwitch from '@/components/form/switch.vue'; import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue'; import FormInput from '@/components/form/input.vue';
import FormTextarea from '@/components/form/textarea.vue'; import FormTextarea from '@/components/form/textarea.vue';
@ -183,6 +201,7 @@ import FormInfo from '@/components/MkInfo.vue';
import FormSection from '@/components/form/section.vue'; import FormSection from '@/components/form/section.vue';
import FormSplit from '@/components/form/split.vue'; import FormSplit from '@/components/form/split.vue';
import FormSuspense from '@/components/form/suspense.vue'; import FormSuspense from '@/components/form/suspense.vue';
import MkRadios from '@/components/form/radios.vue';
import * as os from '@/os'; import * as os from '@/os';
import { fetchInstance } from '@/instance'; import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
@ -217,6 +236,8 @@ let swPublicKey: any = $ref(null);
let swPrivateKey: any = $ref(null); let swPrivateKey: any = $ref(null);
let deeplAuthKey: string = $ref(''); let deeplAuthKey: string = $ref('');
let deeplIsPro: boolean = $ref(false); let deeplIsPro: boolean = $ref(false);
let defaultReaction: string = $ref('');
let defaultReactionCustom: string = $ref('');
async function init() { async function init() {
const meta = await os.api('admin/meta'); const meta = await os.api('admin/meta');
@ -249,9 +270,14 @@ async function init() {
swPrivateKey = meta.swPrivateKey; swPrivateKey = meta.swPrivateKey;
deeplAuthKey = meta.deeplAuthKey; deeplAuthKey = meta.deeplAuthKey;
deeplIsPro = meta.deeplIsPro; deeplIsPro = meta.deeplIsPro;
defaultReaction = ['⭐', '👍', '❤️'].includes(meta.defaultReaction) ? meta.defaultReaction : 'custom';
defaultReactionCustom = ['⭐', '👍', '❤️'].includes(meta.defaultReaction) ? '' : meta.defaultReaction;
} }
function save() { function save() {
if (defaultReaction === 'custom') {
defaultReaction = defaultReactionCustom;
}
os.apiWithDialog('admin/update-meta', { os.apiWithDialog('admin/update-meta', {
name, name,
description, description,
@ -282,6 +308,7 @@ function save() {
swPrivateKey, swPrivateKey,
deeplAuthKey, deeplAuthKey,
deeplIsPro, deeplIsPro,
defaultReaction,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });

View file

@ -135,7 +135,7 @@
import { watch } from 'vue'; import { watch } from 'vue';
import { Virtual } from 'swiper'; import { Virtual } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/vue'; import { Swiper, SwiperSlide } from 'swiper/vue';
import * as misskey from 'calckey-js'; import type * as misskey from 'calckey-js';
import MkChart from '@/components/MkChart.vue'; import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue'; import MkObjectView from '@/components/MkObjectView.vue';
import FormLink from '@/components/form/link.vue'; import FormLink from '@/components/form/link.vue';
@ -147,7 +147,6 @@ import MkSelect from '@/components/form/select.vue';
import FormSwitch from '@/components/form/switch.vue'; import FormSwitch from '@/components/form/switch.vue';
import * as os from '@/os'; import * as os from '@/os';
import number from '@/filters/number'; import number from '@/filters/number';
import bytes from '@/filters/bytes';
import { iAmModerator } from '@/account'; import { iAmModerator } from '@/account';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import { deviceKind } from '@/scripts/device-kind'; import { deviceKind } from '@/scripts/device-kind';