diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 9fdbeab913..6608761c13 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -50,8 +50,8 @@ jobs: - run: pnpm i --frozen-lockfile - name: Check pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml - - name: Build misskey-js - run: pnpm --filter misskey-js build + - name: Build dependent packages + run: pnpm -F misskey-js -F misskey-bubble-game -F misskey-reversi build - name: Build storybook run: pnpm --filter frontend build-storybook - name: Publish to Chromatic diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d072bfa8..3966d5fa7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Feat: 設定の管理が強化されました - 自動でバックアップされるように - 任意の設定項目をデバイス間で同期できるように +- Feat: 画面を重ねて表示するオプションを実装(実験的) - Enhance: プラグインの管理が強化されました - インストール/アンインストール/設定の変更時にリロード不要になりました - Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように @@ -17,6 +18,7 @@ - Enhance: 投稿フォームの設定メニューを改良 - 投稿フォームをリセットできるように - 文字数カウントを復活 +- Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように - Enhance: 投稿フォームの絵文字ピッカーに独立したウィンドウを使用できるように - リアクションピッカーと絵文字ピッカーで表示スタイルの設定が分離しました。絵文字ピッカーでのみウィンドウスタイルを使用可能です。 - Fix: テーマ切り替え時に一部の色が変わらない問題を修正 @@ -24,6 +26,8 @@ ### Server - Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正 - Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正 +- Fix: 連合無しモードでも外部から照会可能だった問題を修正 +- Fix: テスト用WebHookのペイロードの`emojis`パラメータが実際のものと異なる問題を修正 ## 2025.3.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c63f69cf1..a3aedfa9eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -273,7 +273,6 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド query?: Record; loginRequired?: boolean; hash?: string; - globalCacheKey?: string; children?: RouteDef[]; } ``` diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 4966007061..5e936da80c 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1013,6 +1013,7 @@ flip: "اقلب" lastNDays: "آخر {n} أيام" surrender: "ألغِ" postForm: "أنشئ ملاحظة" +information: "عن" _delivery: stop: "مُعلّق" _initialAccountSetting: diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 6aea5a1999..36d142bd0b 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -853,6 +853,7 @@ renotes: "রিনোট" sourceCode: "সোর্স কোড" flip: "উল্টান" postForm: "নোট লিখুন" +information: "আপনার সম্পর্কে" _delivery: stop: "স্থগিত করা হয়েছে" _type: diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index c89a6b173b..23b958252a 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} està parlant sobre \"{word}\"" makeActive: "Activar" display: "Veure" copy: "Copiar" +copiedToClipboard: "Copiat al porta papers" metrics: "Mètriques" overview: "Visió General" logs: "Registres" @@ -1139,7 +1140,7 @@ channelArchiveConfirmDescription: "Un Canal arxivat no apareixerà a la llista d thisChannelArchived: "Aquest Canal ha sigut arxivat." displayOfNote: "Mostrar notes" initialAccountSetting: "Configuració del perfil" -youFollowing: "Seguint" +youFollowing: "Segueixes " preventAiLearning: "Descartar l'ús d'aprenentatge automàtic (IA Generativa)" preventAiLearningDescription: "Demanar els indexadors no fer servir els texts, imatges, etc. en cap conjunt de dades per alimentar l'aprenentatge automàtic (IA Predictiva/ Generativa). Això s'aconsegueix afegint la etiqueta \"noai\" com a resposta HTML al contingut corresponent. Prevenir aquest ús totalment pot ser que no sigui aconseguit, ja que molts indexadors poden obviar aquesta etiqueta." options: "Opcions" @@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "Cancel·lar l'activació de la sincronitzac paste: "Pegar" emojiPalette: "Calaix d'emojis" postForm: "Formulari de publicació" +textCount: "Nombre de caràcters " +information: "Informació" _emojiPalette: palettes: "Calaixos d'emojis" enableSyncBetweenDevicesForPalettes: "Activa la sincronització dels calaixos d'emojis entre dispositius" @@ -1355,6 +1358,8 @@ _settings: appearanceBanner: "Pots configurar les preferències relacionades amb la visualització i l'aspecte del client segons el teu parer." soundsBanner: "Configuració dels sons que reproduirà el client." timelineAndNote: "Línia de temps i nota" + makeEveryTextElementsSelectable: "Fes que tots els elements del text siguin seleccionables" + makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions." _preferencesProfile: profileName: "Nom del perfil" profileNameDescription: "Estableix un nom que identifiqui aquest dispositiu." @@ -2519,6 +2524,7 @@ _notification: achievementEarned: "Assoliment desbloquejat" exportCompleted: "Exportació completada" login: "Iniciar sessió" + createToken: "Creació de tokens d'accés " test: "Prova la notificació" app: "Notificacions d'aplicacions" _actions: @@ -2668,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Assegura't que qui distribueix aquest recurs és fiable abans d'instal·lar-ho." _plugin: title: "Vols instal·lar aquest afegit?" - metaTitle: "Informació de l'afegit " _theme: title: "Vols instal·lar aquest tema?" - metaTitle: "Informació del tema" _meta: base: "Paleta de colors base" _vendorInfo: diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index a509280862..11ad97c3a5 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -169,6 +169,9 @@ addAccount: "Přidat účet" reloadAccountsList: "Obnovit list účtů" loginFailed: "Přihlášení se nezdařilo." showOnRemote: "Více na původním profilu" +continueOnRemote: "Pokračujte na původní profil" +chooseServerOnMisskeyHub: "Vyberete si server z Misskey Hubu" +inputHostName: "Zadejte doménu" general: "Obecně" wallpaper: "Obrázek na pozadí" setWallpaper: "Nastavení obrázku na pozadí" @@ -193,6 +196,7 @@ perHour: "za hodinu" perDay: "za den" stopActivityDelivery: "Přestat zasílat aktivitu" blockThisInstance: "Blokovat tuto instanci" +silenceThisInstance: "Utišit tuto instanci" operations: "Operace" software: "Software" version: "Verze" @@ -1099,6 +1103,7 @@ flip: "Otočit" lastNDays: "Posledních {n} dnů" surrender: "Zrušit" postForm: "Formulář pro odeslání" +information: "Informace" _delivery: stop: "Suspendováno" _type: diff --git a/locales/de-DE.yml b/locales/de-DE.yml index db692d65e5..c6cc416638 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1309,6 +1309,7 @@ availableRoles: "Verfügbare Rollen" federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren." federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren." postForm: "Notizfenster" +information: "Über" _settings: webhook: "Webhook" _accountSettings: @@ -2524,10 +2525,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Überprüfe vor Installation die Vertrauenswürdigkeit des Vertreibers." _plugin: title: "Möchtest du dieses Plugin installieren?" - metaTitle: "Plugininformation" _theme: title: "Möchten du dieses Farbschema installieren?" - metaTitle: "Farbschemainfo" _meta: base: "Farbschemavorlage" _vendorInfo: diff --git a/locales/el-GR.yml b/locales/el-GR.yml index be81a824c7..727565ae21 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -289,6 +289,7 @@ icon: "Εικονίδιο" replies: "Απάντηση" renotes: "Κοινοποίηση σημειώματος" postForm: "Φόρμα δημοσίευσης" +information: "Πληροφορίες" _email: _follow: title: "Έχετε ένα νέο ακόλουθο" diff --git a/locales/en-US.yml b/locales/en-US.yml index 1e7c4730d1..79805e65e1 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} said something about \"{word}\"" makeActive: "Activate" display: "Display" copy: "Copy" +copiedToClipboard: "Copied to clipboard" metrics: "Metrics" overview: "Overview" logs: "Logs" @@ -1316,14 +1317,29 @@ unmarkAsSensitiveConfirm: "Do you want to remove the sensitive designation for t preferences: "Preferences" accessibility: "Accessibility" preferencesProfile: "Preferences profile" -copyPreferenceId: "Copy the proference ID" +copyPreferenceId: "Copy the preference ID" resetToDefaultValue: "Revert to default" overrideByAccount: "Override by the account" untitled: "Untitled" noName: "No name" skip: "Skip" restore: "Restore" +syncBetweenDevices: "Sync between devices" +preferenceSyncConflictTitle: "The configured value exists on the server." +preferenceSyncConflictText: "The sync enabled settings will save their values to the server. However, there are existing values on the server. Which set of values would you like to overwrite?" +preferenceSyncConflictChoiceServer: "Configured value on server" +preferenceSyncConflictChoiceDevice: "Configured value on device" +preferenceSyncConflictChoiceCancel: "Cancel enabling sync" +paste: "Paste" +emojiPalette: "Emoji palette" postForm: "Posting form" +textCount: "Character count" +information: "About" +_emojiPalette: + palettes: "Palette" + enableSyncBetweenDevicesForPalettes: "Enable palette sync between devices" + paletteForMain: "Main palette" + paletteForReaction: "Reaction palette" _settings: driveBanner: "You can manage and configure the drive, check usage, and configure file upload settings." pluginBanner: "You can extend client features with plugins. You can install plugins, configure and manage individually." @@ -1341,6 +1357,9 @@ _settings: preferencesBanner: "You can configure the overall behavior of the client according to your preferences." appearanceBanner: "You can configure the appearance and display settings for the client according to your preferences." soundsBanner: "You can configure the sound settings for playback in the client." + timelineAndNote: "Timeline and note" + makeEveryTextElementsSelectable: "Make all text elements selectable" + makeEveryTextElementsSelectable_description: "Enabling this may reduce usability in some situations." _preferencesProfile: profileName: "Profile name" profileNameDescription: "Set a name that identifies this device." @@ -2505,6 +2524,7 @@ _notification: achievementEarned: "Achievement unlocked" exportCompleted: "The export has been completed" login: "Sign In" + createToken: "Create access token" test: "Notification test" app: "Notifications from linked apps" _actions: @@ -2532,6 +2552,7 @@ _deck: useSimpleUiForNonRootPages: "Use simple UI for navigated pages" usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled" flexible: "Auto-adjust width" + enableSyncBetweenDevicesForProfiles: "Enable profile information sync between devices" _columns: main: "Main" widgets: "Widgets" @@ -2653,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Make sure the distributor of this resource is trustworthy before installation." _plugin: title: "Do you want to install this plugin?" - metaTitle: "Plugin information" _theme: title: "Do you want to install this theme?" - metaTitle: "Theme information" _meta: base: "Base color scheme" _vendorInfo: @@ -2857,8 +2876,8 @@ _selfXssPrevention: description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window." description3: "For more information, please refer to this. {link}" _followRequest: - recieved: "Received application" - sent: "Sent application" + recieved: "Received request" + sent: "Sent request" _remoteLookupErrors: _federationNotAllowed: title: "Unable to communicate with this server" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 4933b41ddb..cd96d348c3 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1300,6 +1300,7 @@ target: "Para" federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador." federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores" postForm: "Formulario" +information: "Información" _settings: webhook: "Webhook" _accountSettings: @@ -2521,10 +2522,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Asegúrate de que el distribuidor de este recurso es de confianza antes de proceder a la instalación." _plugin: title: "¿Quieres instalar este plugin?" - metaTitle: "Información del plugin" _theme: title: "¿Quieres instalar este tema?" - metaTitle: "Información del tema" _meta: base: "Esquema de color base" _vendorInfo: diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 6d3a3bb882..4bdcd89422 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -1278,6 +1278,7 @@ lockdown: "Verrouiller" pleaseSelectAccount: "Sélectionner un compte" availableRoles: "Rôles disponibles" postForm: "Formulaire de publication" +information: "Informations" _abuseUserReport: forward: "Transférer" forwardDescription: "Transférer le signalement vers une instance distante en tant qu'anonyme." @@ -2295,10 +2296,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Veuillez confirmer que le distributeur est fiable avant l'installation." _plugin: title: "Voulez-vous installer cette extension ?" - metaTitle: "Informations sur l'extension" _theme: title: "Voulez-vous installer ce thème ?" - metaTitle: "Informations sur le thème" _meta: base: "Palette de couleurs de base" _vendorInfo: diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 62ddc35cad..9a291ca381 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -1262,6 +1262,7 @@ modified: "Diubah" thereAreNChanges: "Ada {n} perubahan" prohibitedWordsForNameOfUser: "Kata yang dilarang untuk nama pengguna" postForm: "Buat catatan" +information: "Informasi" _settings: webhook: "Webhook" _abuseUserReport: @@ -2492,10 +2493,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Pastikan sumber dari sumber daya ini terpercaya sebelum melakukan pemasangan." _plugin: title: "Apakah kamu ingin memasang plugin ini?" - metaTitle: "Informasi plugin" _theme: title: "Apakah kamu ingin memasang tema ini?" - metaTitle: "Informasi tema" _meta: base: "Skema warna dasar" _vendorInfo: diff --git a/locales/index.d.ts b/locales/index.d.ts index 54772fe735..3960bf7cbf 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2818,6 +2818,10 @@ export interface Locale extends ILocale { * コピー */ "copy": string; + /** + * クリップボードにコピーされました + */ + "copiedToClipboard": string; /** * メトリクス */ @@ -5354,6 +5358,10 @@ export interface Locale extends ILocale { * 文字数 */ "textCount": string; + /** + * 情報 + */ + "information": string; "_emojiPalette": { /** * パレット @@ -10359,20 +10367,12 @@ export interface Locale extends ILocale { * このプラグインをインストールしますか? */ "title": string; - /** - * プラグイン情報 - */ - "metaTitle": string; }; "_theme": { /** * このテーマをインストールしますか? */ "title": string; - /** - * テーマ情報 - */ - "metaTitle": string; }; "_meta": { /** diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 6d69a07721..4d17d0bf7b 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} ha Notato a riguardo di \"{word}\"" makeActive: "Attiva" display: "Visualizza" copy: "Copia" +copiedToClipboard: "Copiato negli appunti" metrics: "Statistiche" overview: "Anteprima" logs: "Log" @@ -973,7 +974,7 @@ check: "Verifica" driveCapOverrideLabel: "Modificare la capienza del Drive per questo profilo" driveCapOverrideCaption: "Se viene specificato meno di 0, viene annullato." requireAdminForView: "Per visualizzarli, è necessario aver effettuato l'accesso con un profilo amministratore." -isSystemAccount: "Questi profili vengono creati e gestiti automaticamente dal sistema" +isSystemAccount: "Si tratta di un profilo creato e gestito automaticamente dal sistema." typeToConfirm: "Digita {x} per continuare" deleteAccount: "Eliminazione profilo" document: "Documentazione" @@ -1323,7 +1324,22 @@ untitled: "Senza titolo" noName: "Senza nome" skip: "Salta" restore: "Ripristina" +syncBetweenDevices: "Sincronizzazione tra i dispositivi" +preferenceSyncConflictTitle: "Sul server esiste già il valore impostato" +preferenceSyncConflictText: "Le impostazione sincronizzata salverà il valore sul server. Però, bada che esiste già un valore sul server. Quale vorresti sovrascrivere?" +preferenceSyncConflictChoiceServer: "Valore del server" +preferenceSyncConflictChoiceDevice: "Valore del dispositivo" +preferenceSyncConflictChoiceCancel: "Annulla la sincronizzazione" +paste: "Incolla" +emojiPalette: "Tavolozza emoji" postForm: "Finestra di pubblicazione" +textCount: "Il numero di caratteri" +information: "Informazioni" +_emojiPalette: + palettes: "Tavolozza" + enableSyncBetweenDevicesForPalettes: "Attiva la sincronizzazione tra dispositivi" + paletteForMain: "Tavolozza principale" + paletteForReaction: "Tavolozza per reazioni" _settings: driveBanner: "Permette di gestire e configurare il Drive, controllare il consumo di spazio e configurare il caricamento dei file." pluginBanner: "Consentono di migliorare le funzionalità. Le estensioni si possono configurare e gestire singolarmente." @@ -1341,6 +1357,9 @@ _settings: preferencesBanner: "Puoi personalizzare il comportamento del tuo dispositivo." appearanceBanner: "Puoi personalizzare l'aspetto nel dispositivo, in base alle tue preferenze." soundsBanner: "Puoi personalizzare i suoni emessi dagli eventi sul tuo dispositivo." + timelineAndNote: "Note e Timeline" + makeEveryTextElementsSelectable: "Imposta ogni elemento come selezionabile" + makeEveryTextElementsSelectable_description: "Potrebbe ridurre l'usabilità in alcune situazioni." _preferencesProfile: profileName: "Nome del profilo" profileNameDescription: "Impostare il nome che indentifica questo dispositivo." @@ -2505,6 +2524,7 @@ _notification: achievementEarned: "Risultato raggiunto" exportCompleted: "Esportazione completata" login: "Accessi" + createToken: "Creare un token di accesso" test: "Notifiche di test" app: "Notifiche da applicazioni" _actions: @@ -2532,6 +2552,7 @@ _deck: useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice" usedAsMinWidthWhenFlexible: "Se \"larghezza flessibile\" è abilitato, questa diventa la larghezza minima" flexible: "Larghezza flessibile" + enableSyncBetweenDevicesForProfiles: "Abilita la sincronizzazione delle informazioni profilo tra dispositivi" _columns: main: "Principale" widgets: "Riquadri" @@ -2653,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Prima di installare, assicurati che la fonte sia affidabile." _plugin: title: "Vuoi davvero installare questo componente aggiuntivo?" - metaTitle: "Informazioni sul componente aggiuntivo" _theme: title: "Vuoi davvero installare questa variazione grafica?" - metaTitle: "Informazioni sulla variazione grafica" _meta: base: "Combinazione base di colori" _vendorInfo: diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 8626044409..b90db4b086 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -700,6 +700,7 @@ userSaysSomethingAbout: "{name}が「{word}」について何かを言いまし makeActive: "アクティブにする" display: "表示" copy: "コピー" +copiedToClipboard: "クリップボードにコピーされました" metrics: "メトリクス" overview: "概要" logs: "ログ" @@ -1334,6 +1335,7 @@ paste: "ペースト" emojiPalette: "絵文字パレット" postForm: "投稿フォーム" textCount: "文字数" +information: "情報" _emojiPalette: palettes: "パレット" @@ -2749,10 +2751,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "配布元が信頼できるかを確認した上でインストールしてください。" _plugin: title: "このプラグインをインストールしますか?" - metaTitle: "プラグイン情報" _theme: title: "このテーマをインストールしますか?" - metaTitle: "テーマ情報" _meta: base: "基本のカラースキーム" _vendorInfo: diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index ae45379086..9c0bff4f95 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -1312,6 +1312,7 @@ federationDisabled: "このサーバーは連合が無効化されてるで。 confirmOnReact: "ツッコむときに確認とる" reactAreYouSure: "\" {emoji} \" でツッコむ?" postForm: "投稿フォーム" +information: "情報" _settings: webhook: "Webhook" _accountSettings: @@ -2610,10 +2611,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "配ってるとこが信頼できるか確認した上でインストールしてな。" _plugin: title: "このプラグイン、インストールする?" - metaTitle: "プラグイン情報" _theme: title: "このテーマインストールする?" - metaTitle: "テーマ情報" _meta: base: "" _vendorInfo: diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index ce83ef0e07..8ff11d35d9 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -655,6 +655,7 @@ replies: "답하기" renotes: "리노트" attach: "옇기" surrender: "아이예" +information: "정보" _delivery: stop: "고만 보내예" _type: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 798c371bc2..4a02b0c64a 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1330,6 +1330,7 @@ preferenceSyncConflictChoiceDevice: "장치 설정값" paste: "붙여넣기" emojiPalette: "이모지 팔레트" postForm: "글 입력란" +information: "정보" _emojiPalette: palettes: "팔레트" paletteForMain: "메인으로 사용할 팔레트" @@ -2650,10 +2651,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "제공자를 신뢰할 수 있는 경우에만 설치하십시오." _plugin: title: "이 플러그인을 설치하시겠습니까?" - metaTitle: "플러그인 정보" _theme: title: "이 테마를 설치하시겠습니까?" - metaTitle: "테마 정보" _meta: base: "기본 컬러 스키마" _vendorInfo: diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 06acda44be..52b5a28fb2 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -394,6 +394,7 @@ searchByGoogle: "ຄົ້ນຫາ" file: "ໄຟລ໌" replies: "ຕອບ​ກັບ" renotes: "Renote" +information: "ກ່ຽວກັບ" _delivery: stop: "ໂຈະ" _type: diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 320b9d62ba..e2f6017f20 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -462,6 +462,7 @@ loggedInAsBot: "Momenteel als bot ingelogd" icon: "Avatar" replies: "Antwoord" renotes: "Herdelen" +information: "Over" _delivery: stop: "Opgeschort" _type: diff --git a/locales/no-NO.yml b/locales/no-NO.yml index c1b145cab4..7981360c41 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -463,6 +463,7 @@ icon: "Avatar" replies: "Svar" renotes: "Renote" surrender: "Avbryt" +information: "Informasjon" _delivery: stop: "Suspendert" _initialAccountSetting: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index a4538ee7b2..21b715714d 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -1045,6 +1045,7 @@ lastNDays: "W ciągu ostatnich {n} dni" surrender: "Odrzuć" gameRetry: "Spróbuj ponownie" postForm: "Formularz tworzenia wpisu" +information: "Informacje" _delivery: stop: "Zawieszono" _type: diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 4511ce662f..2f46eda784 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1302,6 +1302,7 @@ pleaseSelectAccount: "Selecione uma conta" availableRoles: "Cargos disponíveis" acknowledgeNotesAndEnable: "Ative após compreender as precauções." postForm: "Campo de postagem" +information: "Informações" _settings: webhook: "Webhook" _accountSettings: @@ -2598,10 +2599,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Tenha certeza de que o distribuidor desse recurso é confiável antes da instalação." _plugin: title: "Deseja instalar esse plugin?" - metaTitle: "Informações do plugin" _theme: title: "Deseja instalar esse tema?" - metaTitle: "Informações do tema" _meta: base: "Paleta de cores base" _vendorInfo: diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 0d43e174a7..5d1459480d 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -646,6 +646,7 @@ show: "Arată" icon: "Avatar" replies: "Răspunde" renotes: "Re-notează" +information: "Despre" _delivery: stop: "Suspendat" _type: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 2a200deac0..33a09d198a 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1182,6 +1182,7 @@ alwaysConfirmFollow: "Всегда подтверждать подписку" inquiry: "Связаться" messageToFollower: "Сообщение подписчикам" postForm: "Форма отправки" +information: "Описание" _settings: webhook: "Вебхук" _delivery: diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 7ae264081f..cc8ef9298a 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -918,6 +918,7 @@ sourceCode: "Zdrojový kód" flip: "Preklopiť" lastNDays: "Posledných {n} dní" postForm: "Napísať poznámku" +information: "Informácie" _delivery: stop: "Zmrazené" _type: diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 91413e3bc7..c740ab1c0c 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -562,6 +562,7 @@ inquiry: "Kontakt" tryAgain: "Försök igen senare" signinWithPasskey: "Logga in med nyckel" unknownWebAuthnKey: "Okänd nyckel" +information: "Om" _delivery: stop: "Suspenderad" _type: diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 939b0d7269..784e9049dd 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -1293,6 +1293,7 @@ prohibitedWordsForNameOfUserDescription: "หากมีสตริงใด yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม" yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ" postForm: "แบบฟอร์มการโพสต์" +information: "เกี่ยวกับ" _settings: webhook: "Webhook" _abuseUserReport: @@ -2572,10 +2573,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "โปรดตรวจสอบให้แน่ใจว่าแหล่งแจกหน่ายมีความน่าเชื่อถือก่อนทำการติดตั้ง" _plugin: title: "ต้องการติดตั้งปลั๊กอินนี้ใช่ไหม?" - metaTitle: "ข้อมูลส่วนเสริม" _theme: title: "ต้องการติดตั้งธีมนี้ใช่ไหม?" - metaTitle: "ข้อมูลธีม" _meta: base: "โทนสีพื้นฐาน" _vendorInfo: diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 3e068127f5..a63e39eff4 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -910,6 +910,7 @@ sourceCode: "Вихідний код" flip: "Перевернути" lastNDays: "Останні {n} днів" postForm: "Створення нотатки" +information: "Інформація" _delivery: stop: "Призупинено" _type: diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index c70802e417..d5b7d4b770 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -841,6 +841,7 @@ icon: "Avatar" replies: "Javob berish" renotes: "Qayta qayd etish" flip: "Teskari" +information: "Haqida" _delivery: stop: "To'xtatilgan" _type: diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index d2107eaba4..8edcebcd08 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1120,6 +1120,7 @@ cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải lastNDays: "{n} ngày trước" surrender: "Từ chối" postForm: "Mẫu đăng" +information: "Giới thiệu" _delivery: stop: "Đã vô hiệu hóa" _type: diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 53925dbdef..ad3eebfebd 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} 说了关于「{word}」的什么" makeActive: "启用" display: "显示" copy: "复制" +copiedToClipboard: "已复制到剪贴板" metrics: "指标" overview: "概览" logs: "日志" @@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "取消同步" paste: "粘贴" emojiPalette: "表情符号调色板" postForm: "投稿窗口" +textCount: "字数" +information: "关于" _emojiPalette: palettes: "调色板" enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步" @@ -2671,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "请在安装前确保来源可靠" _plugin: title: "要安装此插件吗?" - metaTitle: "插件信息" _theme: title: "要安装此主题吗?" - metaTitle: "主题信息" _meta: base: "基本配色方案" _vendorInfo: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 6f27306702..0de267688c 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} 說了一些關於「{word}」的話" makeActive: "啟用" display: "檢視" copy: "複製" +copiedToClipboard: "已複製到剪貼簿" metrics: "指標" overview: "概覽" logs: "日誌" @@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "取消啟用同步" paste: "貼上" emojiPalette: "表情符號調色盤" postForm: "發文視窗" +textCount: "字數" +information: "關於" _emojiPalette: palettes: "調色盤" enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化" @@ -1355,6 +1358,8 @@ _settings: appearanceBanner: "您可以根據喜好設定與用戶端外觀和顯示方式相關的設定。" soundsBanner: "您可以調整用戶端播放的聲音設定。" timelineAndNote: "時間軸及貼文" + makeEveryTextElementsSelectable: "允許選取所有文字" + makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。" _preferencesProfile: profileName: "設定檔案名稱" profileNameDescription: "設定一個名稱來識別此裝置。" @@ -2519,6 +2524,7 @@ _notification: achievementEarned: "獲得成就" exportCompleted: "已完成匯出。" login: "登入" + createToken: "建立存取權杖" test: "通知測試" app: "應用程式通知" _actions: @@ -2668,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "安裝前請確認提供者是可信賴的。" _plugin: title: "要安裝此外掛嘛?" - metaTitle: "外掛資訊" _theme: title: "要安裝此佈景主題嗎?" - metaTitle: "佈景主題資訊" _meta: base: "基本配色方案" _vendorInfo: diff --git a/package.json b/package.json index 7b81c6a349..51422b3638 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.3.2-beta.1", + "version": "2025.3.2-beta.6", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index f83dec67bf..e1a7801bb1 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -7,42 +7,16 @@ import { Injectable } from '@nestjs/common'; import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js'; -import { AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js'; -import { Packed } from '@/misc/json-schema.js'; +import { type AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { type Packed } from '@/misc/json-schema.js'; import { type WebhookEventTypes } from '@/models/Webhook.js'; +import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js'; import { QueueService } from '@/core/QueueService.js'; import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js'; const oneDayMillis = 24 * 60 * 60 * 1000; -function generateAbuseReport(override?: Partial): AbuseReportPayload { - const result: MiAbuseUserReport = { - id: 'dummy-abuse-report1', - targetUserId: 'dummy-target-user', - targetUser: null, - reporterId: 'dummy-reporter-user', - reporter: null, - assigneeId: null, - assignee: null, - resolved: false, - forwarded: false, - comment: 'This is a dummy report for testing purposes.', - targetUserHost: null, - reporterHost: null, - resolvedAs: null, - moderationNote: 'foo', - ...override, - }; - - return { - ...result, - targetUser: result.targetUser ? toPackedUserLite(result.targetUser) : null, - reporter: result.reporter ? toPackedUserLite(result.reporter) : null, - assignee: result.assignee ? toPackedUserLite(result.assignee) : null, - }; -} - function generateDummyUser(override?: Partial): MiUser { return { id: 'dummy-user-1', @@ -134,124 +108,6 @@ function generateDummyNote(override?: Partial): MiNote { }; } -function toPackedNote(note: MiNote, detail = true, override?: Packed<'Note'>): Packed<'Note'> { - return { - id: note.id, - createdAt: new Date().toISOString(), - deletedAt: null, - text: note.text, - cw: note.cw, - userId: note.userId, - user: toPackedUserLite(note.user ?? generateDummyUser()), - replyId: note.replyId, - renoteId: note.renoteId, - isHidden: false, - visibility: note.visibility, - mentions: note.mentions, - visibleUserIds: note.visibleUserIds, - fileIds: note.fileIds, - files: [], - tags: note.tags, - poll: null, - emojis: note.emojis, - channelId: note.channelId, - channel: note.channel, - localOnly: note.localOnly, - reactionAcceptance: note.reactionAcceptance, - reactionEmojis: {}, - reactions: {}, - reactionCount: 0, - renoteCount: note.renoteCount, - repliesCount: note.repliesCount, - uri: note.uri ?? undefined, - url: note.url ?? undefined, - reactionAndUserPairCache: note.reactionAndUserPairCache, - ...(detail ? { - clippedCount: note.clippedCount, - reply: note.reply ? toPackedNote(note.reply, false) : null, - renote: note.renote ? toPackedNote(note.renote, true) : null, - myReaction: null, - } : {}), - ...override, - }; -} - -function toPackedUserLite(user: MiUser, override?: Packed<'UserLite'>): Packed<'UserLite'> { - return { - id: user.id, - name: user.name, - username: user.username, - host: user.host, - avatarUrl: user.avatarUrl, - avatarBlurhash: user.avatarBlurhash, - avatarDecorations: user.avatarDecorations.map(it => ({ - id: it.id, - angle: it.angle, - flipH: it.flipH, - url: 'https://example.com/dummy-image001.png', - offsetX: it.offsetX, - offsetY: it.offsetY, - })), - isBot: user.isBot, - isCat: user.isCat, - emojis: user.emojis, - onlineStatus: 'active', - badgeRoles: [], - ...override, - }; -} - -function toPackedUserDetailedNotMe(user: MiUser, override?: Packed<'UserDetailedNotMe'>): Packed<'UserDetailedNotMe'> { - return { - ...toPackedUserLite(user), - url: null, - uri: null, - movedTo: null, - alsoKnownAs: [], - createdAt: new Date().toISOString(), - updatedAt: user.updatedAt?.toISOString() ?? null, - lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null, - bannerUrl: user.bannerUrl, - bannerBlurhash: user.bannerBlurhash, - isLocked: user.isLocked, - isSilenced: false, - isSuspended: user.isSuspended, - description: null, - location: null, - birthday: null, - lang: null, - fields: [], - verifiedLinks: [], - followersCount: user.followersCount, - followingCount: user.followingCount, - notesCount: user.notesCount, - pinnedNoteIds: [], - pinnedNotes: [], - pinnedPageId: null, - pinnedPage: null, - publicReactions: true, - followersVisibility: 'public', - followingVisibility: 'public', - twoFactorEnabled: false, - usePasswordLessLogin: false, - securityKeys: false, - roles: [], - memo: null, - moderationNote: undefined, - isFollowing: false, - isFollowed: false, - hasPendingFollowRequestFromYou: false, - hasPendingFollowRequestToYou: false, - isBlocking: false, - isBlocked: false, - isMuted: false, - isRenoteMuted: false, - notify: 'none', - withReplies: true, - ...override, - }; -} - const dummyUser1 = generateDummyUser(); const dummyUser2 = generateDummyUser({ id: 'dummy-user-2', @@ -284,6 +140,7 @@ export class WebhookTestService { }; constructor( + private customEmojiService: CustomEmojiService, private userWebhookService: UserWebhookService, private systemWebhookService: SystemWebhookService, private queueService: QueueService, @@ -354,31 +211,31 @@ export class WebhookTestService { switch (params.type) { case 'note': { - send('note', { note: toPackedNote(dummyNote1) }); + send('note', { note: await this.toPackedNote(dummyNote1) }); break; } case 'reply': { - send('reply', { note: toPackedNote(dummyReply1) }); + send('reply', { note: await this.toPackedNote(dummyReply1) }); break; } case 'renote': { - send('renote', { note: toPackedNote(dummyRenote1) }); + send('renote', { note: await this.toPackedNote(dummyRenote1) }); break; } case 'mention': { - send('mention', { note: toPackedNote(dummyMention1) }); + send('mention', { note: await this.toPackedNote(dummyMention1) }); break; } case 'follow': { - send('follow', { user: toPackedUserDetailedNotMe(dummyUser1) }); + send('follow', { user: await this.toPackedUserDetailedNotMe(dummyUser1) }); break; } case 'followed': { - send('followed', { user: toPackedUserLite(dummyUser2) }); + send('followed', { user: await this.toPackedUserLite(dummyUser2) }); break; } case 'unfollow': { - send('unfollow', { user: toPackedUserDetailedNotMe(dummyUser3) }); + send('unfollow', { user: await this.toPackedUserDetailedNotMe(dummyUser3) }); break; } // まだ実装されていない (#9485) @@ -427,7 +284,7 @@ export class WebhookTestService { switch (params.type) { case 'abuseReport': { - send('abuseReport', generateAbuseReport({ + send('abuseReport', await this.generateAbuseReport({ targetUserId: dummyUser1.id, targetUser: dummyUser1, reporterId: dummyUser2.id, @@ -436,7 +293,7 @@ export class WebhookTestService { break; } case 'abuseReportResolved': { - send('abuseReportResolved', generateAbuseReport({ + send('abuseReportResolved', await this.generateAbuseReport({ targetUserId: dummyUser1.id, targetUser: dummyUser1, reporterId: dummyUser2.id, @@ -448,7 +305,7 @@ export class WebhookTestService { break; } case 'userCreated': { - send('userCreated', toPackedUserLite(dummyUser1)); + send('userCreated', await this.toPackedUserLite(dummyUser1)); break; } case 'inactiveModeratorsWarning': { @@ -474,4 +331,153 @@ export class WebhookTestService { } } } + + @bindThis + private async generateAbuseReport(override?: Partial): Promise { + const result: MiAbuseUserReport = { + id: 'dummy-abuse-report1', + targetUserId: 'dummy-target-user', + targetUser: null, + reporterId: 'dummy-reporter-user', + reporter: null, + assigneeId: null, + assignee: null, + resolved: false, + forwarded: false, + comment: 'This is a dummy report for testing purposes.', + targetUserHost: null, + reporterHost: null, + resolvedAs: null, + moderationNote: 'foo', + ...override, + }; + + return { + ...result, + targetUser: result.targetUser ? await this.toPackedUserLite(result.targetUser) : null, + reporter: result.reporter ? await this.toPackedUserLite(result.reporter) : null, + assignee: result.assignee ? await this.toPackedUserLite(result.assignee) : null, + }; + } + + @bindThis + private async toPackedNote(note: MiNote, detail = true, override?: Packed<'Note'>): Promise> { + return { + id: note.id, + createdAt: new Date().toISOString(), + deletedAt: null, + text: note.text, + cw: note.cw, + userId: note.userId, + user: await this.toPackedUserLite(note.user ?? generateDummyUser()), + replyId: note.replyId, + renoteId: note.renoteId, + isHidden: false, + visibility: note.visibility, + mentions: note.mentions, + visibleUserIds: note.visibleUserIds, + fileIds: note.fileIds, + files: [], + tags: note.tags, + poll: null, + emojis: await this.customEmojiService.populateEmojis(note.emojis, note.userHost), + channelId: note.channelId, + channel: note.channel, + localOnly: note.localOnly, + reactionAcceptance: note.reactionAcceptance, + reactionEmojis: {}, + reactions: {}, + reactionCount: 0, + renoteCount: note.renoteCount, + repliesCount: note.repliesCount, + uri: note.uri ?? undefined, + url: note.url ?? undefined, + reactionAndUserPairCache: note.reactionAndUserPairCache, + ...(detail ? { + clippedCount: note.clippedCount, + reply: note.reply ? await this.toPackedNote(note.reply, false) : null, + renote: note.renote ? await this.toPackedNote(note.renote, true) : null, + myReaction: null, + } : {}), + ...override, + }; + } + + @bindThis + private async toPackedUserLite(user: MiUser, override?: Packed<'UserLite'>): Promise> { + return { + id: user.id, + name: user.name, + username: user.username, + host: user.host, + avatarUrl: user.avatarUrl, + avatarBlurhash: user.avatarBlurhash, + avatarDecorations: user.avatarDecorations.map(it => ({ + id: it.id, + angle: it.angle, + flipH: it.flipH, + url: 'https://example.com/dummy-image001.png', + offsetX: it.offsetX, + offsetY: it.offsetY, + })), + isBot: user.isBot, + isCat: user.isCat, + emojis: await this.customEmojiService.populateEmojis(user.emojis, user.host), + onlineStatus: 'active', + badgeRoles: [], + ...override, + }; + } + + @bindThis + private async toPackedUserDetailedNotMe(user: MiUser, override?: Packed<'UserDetailedNotMe'>): Promise> { + return { + ...await this.toPackedUserLite(user), + url: null, + uri: null, + movedTo: null, + alsoKnownAs: [], + createdAt: new Date().toISOString(), + updatedAt: user.updatedAt?.toISOString() ?? null, + lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null, + bannerUrl: user.bannerUrl, + bannerBlurhash: user.bannerBlurhash, + isLocked: user.isLocked, + isSilenced: false, + isSuspended: user.isSuspended, + description: null, + location: null, + birthday: null, + lang: null, + fields: [], + verifiedLinks: [], + followersCount: user.followersCount, + followingCount: user.followingCount, + notesCount: user.notesCount, + pinnedNoteIds: [], + pinnedNotes: [], + pinnedPageId: null, + pinnedPage: null, + publicReactions: true, + followersVisibility: 'public', + followingVisibility: 'public', + twoFactorEnabled: false, + usePasswordLessLogin: false, + securityKeys: false, + roles: [], + memo: null, + moderationNote: undefined, + isFollowing: false, + isFollowed: false, + hasPendingFollowRequestFromYou: false, + hasPendingFollowRequestToYou: false, + isBlocking: false, + isBlocked: false, + isMuted: false, + isRenoteMuted: false, + notify: 'none', + withReplies: true, + ...override, + }; + } } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index ac74d68c95..100fb69585 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -166,6 +166,7 @@ export interface Schema extends OfSchema { readonly maximum?: number; readonly minimum?: number; readonly pattern?: string; + readonly additionalProperties?: Schema | boolean; } type RequiredPropertyNames = { @@ -217,6 +218,13 @@ type ObjectSchemaTypeDef

= : p['anyOf'] extends ReadonlyArray ? never : // see CONTRIBUTING.md p['allOf'] extends ReadonlyArray ? UnionToIntersection> : + p['additionalProperties'] extends true ? Record : + p['additionalProperties'] extends Schema ? + p['additionalProperties'] extends infer AdditionalProperties ? + AdditionalProperties extends Schema ? + Record> : + never : + never : any; type ObjectSchemaType

= NullOrUndefined>; diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts index 725e1c8ba2..95fe0a2c6a 100644 --- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts @@ -6,6 +6,7 @@ import * as fs from 'node:fs'; import { Inject, Injectable } from '@nestjs/common'; import { ZipReader } from 'slacc'; +import { IsNull } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { EmojisRepository, DriveFilesRepository } from '@/models/_.js'; import type Logger from '@/logger.js'; @@ -86,6 +87,7 @@ export class ImportCustomEmojisProcessorService { const emojiPath = outputPath + '/' + record.fileName; await this.emojisRepository.delete({ name: emojiInfo.name, + host: IsNull(), }); try { diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 20e985aaf2..48c80e5e61 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -13,7 +13,7 @@ import accepts from 'accepts'; import vary from 'vary'; import secureJson from 'secure-json-parse'; import { DI } from '@/di-symbols.js'; -import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js'; +import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js'; import * as url from '@/misc/prelude/url.js'; import type { Config } from '@/config.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; @@ -42,6 +42,9 @@ export class ActivityPubServerService { @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -102,6 +105,11 @@ export class ActivityPubServerService { @bindThis private inbox(request: FastifyRequest, reply: FastifyReply) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + let signature; try { @@ -173,6 +181,11 @@ export class ActivityPubServerService { request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>, reply: FastifyReply, ) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const cursor = request.query.cursor; @@ -265,6 +278,11 @@ export class ActivityPubServerService { request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>, reply: FastifyReply, ) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const cursor = request.query.cursor; @@ -354,6 +372,11 @@ export class ActivityPubServerService { @bindThis private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const user = await this.usersRepository.findOneBy({ @@ -398,6 +421,11 @@ export class ActivityPubServerService { }>, reply: FastifyReply, ) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const sinceId = request.query.since_id; @@ -482,6 +510,11 @@ export class ActivityPubServerService { @bindThis private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + if (user == null) { reply.code(404); return; @@ -564,6 +597,11 @@ export class ActivityPubServerService { fastify.get<{ Params: { note: string; } }>('/notes/:note', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => { vary(reply.raw, 'Accept'); + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const note = await this.notesRepository.findOneBy({ id: request.params.note, visibility: In(['public', 'home']), @@ -594,6 +632,11 @@ export class ActivityPubServerService { fastify.get<{ Params: { note: string; } }>('/notes/:note/activity', async (request, reply) => { vary(reply.raw, 'Accept'); + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const note = await this.notesRepository.findOneBy({ id: request.params.note, userHost: IsNull(), @@ -634,6 +677,11 @@ export class ActivityPubServerService { // publickey fastify.get<{ Params: { user: string; } }>('/users/:user/publickey', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const user = await this.usersRepository.findOneBy({ @@ -661,6 +709,11 @@ export class ActivityPubServerService { fastify.get<{ Params: { user: string; } }>('/users/:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => { vary(reply.raw, 'Accept'); + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const userId = request.params.user; const user = await this.usersRepository.findOneBy({ @@ -674,6 +727,11 @@ export class ActivityPubServerService { fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => { vary(reply.raw, 'Accept'); + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const acct = Acct.parse(request.params.acct); const user = await this.usersRepository.findOneBy({ @@ -688,6 +746,11 @@ export class ActivityPubServerService { // emoji fastify.get<{ Params: { emoji: string; } }>('/emojis/:emoji', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const emoji = await this.emojisRepository.findOneBy({ host: IsNull(), name: request.params.emoji, @@ -705,6 +768,11 @@ export class ActivityPubServerService { // like fastify.get<{ Params: { like: string; } }>('/likes/:like', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const reaction = await this.noteReactionsRepository.findOneBy({ id: request.params.like }); if (reaction == null) { @@ -726,6 +794,11 @@ export class ActivityPubServerService { // follow fastify.get<{ Params: { follower: string; followee: string; } }>('/follows/:follower/:followee', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + // This may be used before the follow is completed, so we do not // check if the following exists. @@ -752,6 +825,11 @@ export class ActivityPubServerService { // follow fastify.get<{ Params: { followRequestId: string; } }>('/follows/:followRequestId', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + // This may be used before the follow is completed, so we do not // check if the following exists and only check if the follow request exists. diff --git a/packages/backend/src/server/WellKnownServerService.ts b/packages/backend/src/server/WellKnownServerService.ts index 8e326da89a..d106be5bc8 100644 --- a/packages/backend/src/server/WellKnownServerService.ts +++ b/packages/backend/src/server/WellKnownServerService.ts @@ -8,7 +8,7 @@ import { IsNull } from 'typeorm'; import vary from 'vary'; import fastifyAccepts from '@fastify/accepts'; import { DI } from '@/di-symbols.js'; -import type { UsersRepository } from '@/models/_.js'; +import type { MiMeta, UsersRepository } from '@/models/_.js'; import type { Config } from '@/config.js'; import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js'; import type { MiUser } from '@/models/User.js'; @@ -26,6 +26,9 @@ export class WellKnownServerService { @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -66,6 +69,11 @@ export class WellKnownServerService { }); fastify.get('/.well-known/host-meta', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + reply.header('Content-Type', xrd); return XRD({ element: 'Link', attributes: { rel: 'lrdd', @@ -75,6 +83,11 @@ export class WellKnownServerService { }); fastify.get('/.well-known/host-meta.json', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + reply.header('Content-Type', 'application/json'); return { links: [{ @@ -86,6 +99,11 @@ export class WellKnownServerService { }); fastify.get('/.well-known/nodeinfo', async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + return { links: this.nodeinfoServerService.getLinks() }; }); @@ -99,6 +117,11 @@ fastify.get('/.well-known/change-password', async (request, reply) => { */ fastify.get<{ Querystring: { resource: string } }>(webFingerPath, async (request, reply) => { + if (this.meta.federation === 'none') { + reply.code(403); + return; + } + const fromId = (id: MiUser['id']): FindOptionsWhere => ({ id, host: IsNull(), diff --git a/packages/backend/test/unit/WebhookTestService.ts b/packages/backend/test/unit/WebhookTestService.ts index 45bc932469..736aac40b4 100644 --- a/packages/backend/test/unit/WebhookTestService.ts +++ b/packages/backend/test/unit/WebhookTestService.ts @@ -14,6 +14,7 @@ import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersReposi import { IdService } from '@/core/IdService.js'; import { DI } from '@/di-symbols.js'; import { QueueService } from '@/core/QueueService.js'; +import { CustomEmojiService } from '@/core/CustomEmojiService.js'; describe('WebhookTestService', () => { let app: TestingModule; @@ -56,6 +57,11 @@ describe('WebhookTestService', () => { providers: [ WebhookTestService, IdService, + { + provide: CustomEmojiService, useFactory: () => ({ + populateEmojis: jest.fn(), + }), + }, { provide: QueueService, useFactory: () => ({ systemWebhookDeliver: jest.fn(), diff --git a/packages/frontend-embed/src/components/EmImgWithBlurhash.vue b/packages/frontend-embed/src/components/EmImgWithBlurhash.vue index bf976c71ae..0bff048ce4 100644 --- a/packages/frontend-embed/src/components/EmImgWithBlurhash.vue +++ b/packages/frontend-embed/src/components/EmImgWithBlurhash.vue @@ -33,13 +33,11 @@ const canvasPromise = new Promise(resol Math.min(navigator.hardwareConcurrency - 1, 4), ); resolve(workers); - if (_DEV_) console.log('WebGL2 in worker is supported!'); } else { const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; resolve(canvas); - if (_DEV_) console.log('WebGL2 in worker is not supported...'); } testWorker.terminate(); }); diff --git a/packages/frontend-shared/js/config.ts b/packages/frontend-shared/js/config.ts index ae1dcae10b..26dd36d6c3 100644 --- a/packages/frontend-shared/js/config.ts +++ b/packages/frontend-shared/js/config.ts @@ -12,6 +12,7 @@ const siteName = document.querySelector('meta[property="og:site export const host = address.host; export const hostname = address.hostname; export const url = address.origin; +export const port = address.port; export const apiUrl = location.origin + '/api'; export const wsOrigin = location.origin; export const lang = localStorage.getItem('lang') ?? 'en-US'; diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index c47b48bd7f..3f6bfb62ff 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -64,12 +64,12 @@ initialize({ initLocalStorage(); queueMicrotask(() => { Promise.all([ - import('../src/components'), - import('../src/directives'), - import('../src/widgets'), - import('../src/theme'), - import('../src/preferences'), - import('../src/os'), + import('../src/components/index.js'), + import('../src/directives/index.js'), + import('../src/widgets/index.js'), + import('../src/theme.js'), + import('../src/preferences.js'), + import('../src/os.js'), ]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => { setup((app) => { moduleInitialized = true; diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js index 8aa70c66a2..fa2fcce95a 100644 --- a/packages/frontend/eslint.config.js +++ b/packages/frontend/eslint.config.js @@ -52,7 +52,11 @@ export default [ 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'], // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため - 'id-denylist': ['error', 'window', 'e'], + // close ... window.closeと衝突 or 紛らわしい + // open ... window.openと衝突 or 紛らわしい + // fetch ... window.fetchと衝突 or 紛らわしい + // location ... window.locationと衝突 or 紛らわしい + 'id-denylist': ['error', 'window', 'e', 'close', 'open', 'fetch', 'location'], 'no-shadow': ['warn'], 'vue/attributes-order': ['error', { alphabetical: false, diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts index c90cc6bdd0..24fafce18c 100644 --- a/packages/frontend/src/_boot_.ts +++ b/packages/frontend/src/_boot_.ts @@ -12,7 +12,7 @@ import '@/style.scss'; import { mainBoot } from '@/boot/main-boot.js'; import { subBoot } from '@/boot/sub-boot.js'; -const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete']; +const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions']; if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) { subBoot(); diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 10bcddbde7..402ccca587 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -26,8 +26,6 @@ import { deckStore } from '@/ui/deck/deck-store.js'; import { analytics, initAnalytics } from '@/analytics.js'; import { miLocalStorage } from '@/local-storage.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; -import { setupRouter } from '@/router/main.js'; -import { createMainRouter } from '@/router/definition.js'; import { prefer } from '@/preferences.js'; import { $i } from '@/i.js'; @@ -267,8 +265,6 @@ export async function common(createVue: () => App) { const app = createVue(); - setupRouter(app, createMainRouter); - if (_DEV_) { app.config.performance = true; } @@ -304,24 +300,26 @@ export async function common(createVue: () => App) { removeSplash(); //#region Self-XSS 対策メッセージ - console.log( - `%c${i18n.ts._selfXssPrevention.warning}`, - 'color: #f00; background-color: #ff0; font-size: 36px; padding: 4px;', - ); - console.log( - `%c${i18n.ts._selfXssPrevention.title}`, - 'color: #f00; font-weight: 900; font-family: "Hiragino Sans W9", "Hiragino Kaku Gothic ProN", sans-serif; font-size: 24px;', - ); - console.log( - `%c${i18n.ts._selfXssPrevention.description1}`, - 'font-size: 16px; font-weight: 700;', - ); - console.log( - `%c${i18n.ts._selfXssPrevention.description2}`, - 'font-size: 16px;', - 'font-size: 20px; font-weight: 700; color: #f00;', - ); - console.log(i18n.tsx._selfXssPrevention.description3({ link: 'https://misskey-hub.net/docs/for-users/resources/self-xss/' })); + if (!_DEV_) { + console.log( + `%c${i18n.ts._selfXssPrevention.warning}`, + 'color: #f00; background-color: #ff0; font-size: 36px; padding: 4px;', + ); + console.log( + `%c${i18n.ts._selfXssPrevention.title}`, + 'color: #f00; font-weight: 900; font-family: "Hiragino Sans W9", "Hiragino Kaku Gothic ProN", sans-serif; font-size: 24px;', + ); + console.log( + `%c${i18n.ts._selfXssPrevention.description1}`, + 'font-size: 16px; font-weight: 700;', + ); + console.log( + `%c${i18n.ts._selfXssPrevention.description2}`, + 'font-size: 16px;', + 'font-size: 20px; font-weight: 700; color: #f00;', + ); + console.log(i18n.tsx._selfXssPrevention.description3({ link: 'https://misskey-hub.net/docs/for-users/resources/self-xss/' })); + } //#endregion return { diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 64e3a236e8..62ee0c5d72 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -24,7 +24,7 @@ import { miLocalStorage } from '@/local-storage.js'; import { claimAchievement, claimedAchievements } from '@/utility/achievements.js'; import { initializeSw } from '@/utility/initialize-sw.js'; import { emojiPicker } from '@/utility/emoji-picker.js'; -import { mainRouter } from '@/router/main.js'; +import { mainRouter } from '@/router.js'; import { makeHotkey } from '@/utility/hotkey.js'; import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js'; import { prefer } from '@/preferences.js'; @@ -201,6 +201,8 @@ export async function mainBoot() { prefer.commit('sound.on.noteMy', store.s.sound_noteMy as any); prefer.commit('sound.on.notification', store.s.sound_notification as any); prefer.commit('sound.on.reaction', store.s.sound_reaction as any); + prefer.commit('defaultNoteVisibility', store.s.defaultNoteVisibility); + prefer.commit('defaultNoteLocalOnly', store.s.defaultNoteLocalOnly); window.setTimeout(() => { unisonReload(); diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue index 8e37317779..d6f65eca5d 100644 --- a/packages/frontend/src/components/MkAbuseReport.vue +++ b/packages/frontend/src/components/MkAbuseReport.vue @@ -88,9 +88,9 @@ import { i18n } from '@/i18n.js'; import { dateString } from '@/filters/date.js'; import MkFolder from '@/components/MkFolder.vue'; import RouterView from '@/components/global/RouterView.vue'; -import { useRouterFactory } from '@/router/supplier'; import MkTextarea from '@/components/MkTextarea.vue'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; +import { createRouter } from '@/router.js'; const props = defineProps<{ report: Misskey.entities.AdminAbuseUserReportsResponse[number]; @@ -100,10 +100,9 @@ const emit = defineEmits<{ (ev: 'resolved', reportId: string): void; }>(); -const routerFactory = useRouterFactory(); -const targetRouter = routerFactory(`/admin/user/${props.report.targetUserId}`); +const targetRouter = createRouter(`/admin/user/${props.report.targetUserId}`); targetRouter.init(); -const reporterRouter = routerFactory(`/admin/user/${props.report.reporterId}`); +const reporterRouter = createRouter(`/admin/user/${props.report.reporterId}`); reporterRouter.init(); const moderationNote = ref(props.report.moderationNote ?? ''); @@ -135,7 +134,7 @@ function forward() { function showMenu(ev: MouseEvent) { os.popupMenu([{ - icon: 'ti ti-id', + icon: 'ti ti-hash', text: 'Copy ID', action: () => { copyToClipboard(props.report.id); diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue index a634a748e9..dbac5e9dd7 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.vue +++ b/packages/frontend/src/components/MkAbuseReportWindow.vue @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index 071dbba5eb..6a1a91a9f4 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 25a29a4ae7..fbdb7d261e 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -4,31 +4,28 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/components/global/StackingRouterView.vue b/packages/frontend/src/components/global/StackingRouterView.vue new file mode 100644 index 0000000000..c95c74aef3 --- /dev/null +++ b/packages/frontend/src/components/global/StackingRouterView.vue @@ -0,0 +1,243 @@ + + + + + + + diff --git a/packages/frontend/src/components/grid/MkDataCell.vue b/packages/frontend/src/components/grid/MkDataCell.vue index f7f6f5c140..7c8a5d64d7 100644 --- a/packages/frontend/src/components/grid/MkDataCell.vue +++ b/packages/frontend/src/components/grid/MkDataCell.vue @@ -39,10 +39,12 @@ SPDX-License-Identifier: AGPL-3.0-only {{ cell.value }}

-
+
- - diff --git a/packages/frontend/src/pages/welcome.setup.vue b/packages/frontend/src/pages/welcome.setup.vue index d9e3ca9966..7a4fa20bcf 100644 --- a/packages/frontend/src/pages/welcome.setup.vue +++ b/packages/frontend/src/pages/welcome.setup.vue @@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index 0a2c0e9952..8378dddfef 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -12,10 +12,10 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 29248b2720..d85745bde6 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -7,17 +7,29 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - -
-
+
+
+ + + +
+
+ + +
+
+ + + + + +
+
@@ -25,19 +37,6 @@ SPDX-License-Identifier: AGPL-3.0-only -
- - - - - -
- diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 051bfbfa68..ddc3761b04 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -4,66 +4,24 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -75,12 +33,10 @@ import XCommon from './_common_/common.vue'; import type { PageMetadata } from '@/page.js'; import * as os from '@/os.js'; import { instance } from '@/instance.js'; -import XSigninDialog from '@/components/MkSigninDialog.vue'; -import XSignupDialog from '@/components/MkSignupDialog.vue'; import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js'; import { i18n } from '@/i18n.js'; import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue'; -import { mainRouter } from '@/router/main.js'; +import { mainRouter } from '@/router.js'; import { DI } from '@/di.js'; const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index'); @@ -103,39 +59,11 @@ provideMetadataReceiver((metadataGetter) => { }); provideReactiveMetadata(pageMetadata); -const announcements = { - endpoint: 'announcements', - limit: 10, -}; - -const isTimelineAvailable = ref(instance.policies.ltlAvailable || instance.policies.gtlAvailable); - -const showMenu = ref(false); const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD); const narrow = ref(window.innerWidth < 1280); -const keymap = computed(() => { - return { - 's': () => { - mainRouter.push('/search'); - }, - }; -}); - -function signin() { - const { dispose } = os.popup(XSigninDialog, { - autoSet: true, - }, { - closed: () => dispose(), - }); -} - -function signup() { - const { dispose } = os.popup(XSignupDialog, { - autoSet: true, - }, { - closed: () => dispose(), - }); +function goHome() { + mainRouter.push('/'); } onMounted(() => { @@ -145,149 +73,64 @@ onMounted(() => { }, { passive: true }); } }); - -defineExpose({ - showMenu: showMenu, -}); - diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue index 99248abecf..8a09ad80d9 100644 --- a/packages/frontend/src/ui/zen.vue +++ b/packages/frontend/src/ui/zen.vue @@ -4,21 +4,23 @@ SPDX-License-Identifier: AGPL-3.0-only -->