diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 3be8f095f1..5cffbd81bc 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -14,7 +14,7 @@ jobs: - run: corepack enable - name: Setup Node.js - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index 75a458424e..d604f9b16d 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -37,7 +37,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -54,7 +54,7 @@ jobs: - name: Copy API.json run: cp packages/backend/built/api.json ${{ matrix.api-json-name }} - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: api-artifact path: ${{ matrix.api-json-name }} @@ -67,7 +67,7 @@ jobs: PR_NUMBER: ${{ github.event.number }} run: | echo "$PR_NUMBER" > ./pr_number - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: api-artifact path: pr_number diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5096e54af8..d6832278e8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: with: version: 8 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' @@ -46,7 +46,7 @@ jobs: with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' @@ -72,7 +72,7 @@ jobs: with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.0 + - uses: actions/setup-node@v4.0.1 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/report-api-diff.yml b/.github/workflows/report-api-diff.yml index 2868d6cc09..309516772f 100644 --- a/.github/workflows/report-api-diff.yml +++ b/.github/workflows/report-api-diff.yml @@ -56,7 +56,7 @@ jobs: - name: Echo full diff run: cat ./api-full.json.diff - name: Upload full diff to Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: api-artifact path: | diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 6e8327ca07..9681cbec59 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -17,7 +17,7 @@ jobs: services: postgres: - image: postgres:13 + image: postgres:15 ports: - 54312:5432 env: @@ -38,7 +38,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 50c225189d..83740bf156 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -25,7 +25,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -56,7 +56,7 @@ jobs: services: postgres: - image: postgres:13 + image: postgres:15 ports: - 54312:5432 env: @@ -83,7 +83,7 @@ jobs: version: 7 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -108,12 +108,12 @@ jobs: wait-on: 'http://localhost:61812' headed: true browser: ${{ matrix.browser }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: failure() with: name: ${{ matrix.browser }}-cypress-screenshots path: cypress/screenshots - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: ${{ matrix.browser }}-cypress-videos diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 76e170b3e3..055152f321 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -26,7 +26,7 @@ jobs: - run: corepack enable - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 694fa1a8f5..9e02c0d8f8 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -28,7 +28,7 @@ jobs: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.0 + uses: actions/setup-node@v4.0.1 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.vscode/settings.json b/.vscode/settings.json index 71fb02a59d..e2a82b1ffe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,15 @@ { - "search.exclude": { - "**/node_modules": true - }, - "typescript.tsdk": "node_modules/typescript/lib", - "files.associations": { - "*.test.ts": "typescript" - }, - "jest.jestCommandLine": "pnpm run jest", - "jest.autoRun": "off" -} \ No newline at end of file + "search.exclude": { + "**/node_modules": true + }, + "typescript.tsdk": "node_modules/typescript/lib", + "files.associations": { + "*.test.ts": "typescript" + }, + "jest.jestCommandLine": "pnpm run jest", + "jest.autoRun": "off", + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, + "editor.formatOnSave": false +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8644bb0482..5695b5e392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,17 +5,18 @@ - ### Client -- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 -- Fix: MFMでルビの中のテキストがnyaizeされない問題を修正 +- ### Server - --> -## 2023.x.x (unreleased) +## 2023.12.0 ### Note +- Node.js 20.10.0が最小要件になりました +- 絵文字の追加辞書を既にインストールしている場合は、お手数ですが再インストールのほどお願いします - 絵文字ピッカーにピン留め表示する絵文字設定が「リアクション用」と「絵文字入力用」に分かれました。以前の設定は「リアクション用」として使用されます。 **影響:** @@ -30,14 +31,20 @@ - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) - Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83) - Feat: TL上からノートが見えなくなるワードミュートであるハードミュートを追加 +- Enhance: 公開ロールにアサインされたときに通知が作成されるように - Enhance: アイコンデコレーションを複数設定できるように - Enhance: アイコンデコレーションの位置を微調整できるように +- Enhance: つながりの公開範囲をフォロー/フォロワーで個別に設定可能に #12072 +- Enhance: ローカリゼーションの更新 +- Enhance: 依存関係の更新 - Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正 ### Client - Feat: 今日誕生日のフォロー中のユーザーを一覧表示できるウィジェットを追加 -- Feat: データセーバーでコードハイライトの読み込みを削減できるように -- Feat: MFMのアニメーション要素(`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`)に `delay` オプションを追加 +- Feat: 画面に雪を降らせられるように +- Enhance: MFMのアニメーション要素(`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`)に `delay` オプションを追加 +- Enhance: センシティブと判断されたウェブサイトのサムネイルを非表示に + - ウェブサイトをセンシティブと判断する仕組みが動いていないため、summalyProxyを使用しないと機能しません。 - Enhance: 投稿フォームの絵文字ピッカーをリアクション時に使用するものと同じのを使用するように #12336 #12560 - Enhance: リアクション用ピン留め絵文字と投稿時の絵文字入力用ピン留め絵文字を分けて設定できるように #12560 - Enhance: 絵文字のオートコンプリート機能強化 #12364 @@ -48,16 +55,25 @@ - Enhance: Shareページで投稿を完了すると、親ウィンドウ(親フレーム)にpostMessageするように - Enhance: チャンネル、クリップ、ページ、Play、ギャラリーにURLのコピーボタンを設置 #11305 - Enhance: ノートプレビューに「内容を隠す」が反映されるように +- Enhance: データセーバーでコードハイライトの読み込みを削減できるように - Enhance: データセーバーの適用範囲を個別で設定できるように - 従来のデータセーバーの設定はリセットされます - Enhance: タイムライン上のタブからリスト、アンテナ、チャンネルの管理ページにジャンプできるように - Enhance: ユーザー名、プロフィール、お知らせ、ページの編集画面でMFMや絵文字のオートコンプリートが使用できるように - Enhance: プロフィール、お知らせの編集画面でMFMのプレビューを表示できるように -- Feat: センシティブと判断されたウェブサイトのサムネイルをぼかすように - - ウェブサイトをセンシティブと判断する仕組みが動いていないため、summalyProxyを使用しないと機能しません。 -- fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 -- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Enhance: 絵文字の詳細ページに記載される情報を追加 +- Enhance: リアクションの表示幅制限を設定可能に +- Enhance: Unicode 15.0のサポート +- Enhance: コードブロックのハイライト機能を利用するには言語を明示的に指定させるように + - MFMでコードブロックを利用する際に意図しないハイライトが起こらないようになりました + - 逆に、MFMでコードハイライトを利用したい際は言語を明示的に指定する必要があります + (例: ` ```js ` → Javascript, ` ```ais ` → AiScript) +- Enhance: 絵文字などのオートコンプリートでShift+Tabを押すと前の候補を選択できるように +- Enhance: チャンネルに新規の投稿がある場合にバッジを表示させる +- Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 +- Enhance: 設定したタグをトレンドに表示させないようにする項目を管理画面で設定できるように +- Fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 +- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 - Fix: プロフィールの「ファイル」にセンシティブな画像がある際のデザインを修正 - Fix: 一度に大量の通知が入った際に通知音が音割れする問題を修正 @@ -67,10 +83,20 @@ - Fix: セキュリティ向上のためAiScriptの`Mk:apiExternal`を無効化 - Fix: ノート中の絵文字をタップして「リアクションする」からリアクションした際にリアクションサウンドが鳴らない不具合を修正 - Fix: ノート中のリアクションの表示を微調整 #12650 +- Fix: AiScriptの`readline`が不正な値を返すことがある問題を修正 +- Fix: 投票のみ/画像のみの引用RNが、通知欄でただのRNとして判定されるバグを修正 +- Fix: CWをつけて引用RNしても、普通のRNとして扱われてしまうバグを修正しました。 +- Fix: 「画像が1枚のみのメディアリストの高さ」を「デフォルト」以外に設定していると、CWの中などに添付された画像が見られないバグを修正 +- Fix: DeepL TranslationのPro accountトグルスイッチが表示されていなかったのを修正 +- Fix: twitterの埋め込みカード内リンクからリンク先を開けない問題を修正 +- Fix: WebKitブラウザー上でも「デバイスの画面を常にオンにする」機能が効くように +- Fix: ページ一覧ページの表示がモバイル環境において崩れているのを修正 +- Fix: MFMでルビの中のテキストがnyaizeされない問題を修正 ### Server - Enhance: MFM `$[ruby ]` が他ソフトウェアと連合されるように - Enhance: Meilisearchを有効にした検索で、ユーザーのミュートやブロックを考慮するように +- Enhance: カスタム絵文字のインポート時の動作を改善 - Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 - Fix: api.jsonの生成ロジックを改善 #12402 @@ -85,6 +111,9 @@ - Fix: 「みつける」が年越し時に壊れる問題を修正 - Fix: アカウントをブロックした際に、自身のユーザーのページでノートが相手に表示される問題を修正 - Fix: モデレーションログがモデレーターは閲覧できないように修正 +- Fix: ハッシュタグのトレンド除外設定が即時に効果を持つように修正 +- Fix: HTTP Digestヘッダのアルゴリズム部分に大文字の"SHA-256"しか使えない +- Fix: 管理者用APIのアクセス権限が適切に設定されていない問題を修正 ## 2023.11.1 @@ -104,7 +133,6 @@ - 例: `$[unixtime 1701356400]` - Enhance: プラグインでエラーが発生した場合のハンドリングを強化 - Enhance: 細かなUIのブラッシュアップ -- Enhance: サウンド設定に「サウンドを出力しない」と「Misskeyがアクティブな時のみサウンドを出力する」を追加 - Fix: 効果音が再生されるとデバイスで再生している動画や音声が停止する問題を修正 #12339 - Fix: デッキに表示されたチャンネルの表示先チャンネルを切り替えた際、即座に反映されない問題を修正 #12236 - Fix: プラグインでノートの表示を書き換えられない問題を修正 @@ -132,7 +160,7 @@ ### General - Feat: アイコンデコレーション機能 - サーバーで用意された画像をアイコンに重ねることができます - - 画像のテンプレートはこちらです: https://misskey-hub.net/avatar-decoration-template.png + - 画像のテンプレートはこちらです: https://misskey-hub.net/brand-assets/ - 最大でも黄色いエリア内にデコレーションを収めることを推奨します。 - 画像は512x512pxを推奨します。 - Feat: チャンネル設定にリノート/引用リノートの可否を設定できる項目を追加 @@ -149,7 +177,7 @@ ### Client - Feat: プラグイン・テーマを外部サイトから直接インストールできるようになりました - 外部サイトでの実装が必要です。詳細は Misskey Hub をご覧ください - https://misskey-hub.net/docs/advanced/publish-on-your-website.html + https://misskey-hub.net/docs/for-developers/publish-on-your-website/ - Feat: 通知をグルーピングして表示するオプション(オプトアウト) - Feat: Misskeyの基本的なチュートリアルを実装 - Feat: スワイプしてタイムラインを再読込できるように diff --git a/README.md b/README.md index 80a3c6ce19..e7cca50910 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -<div align="center"> -<a href="https://misskey-hub.net"> - <img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/> -</a> - -**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀** - - ---- -</div> - -# 当フォークについて - -当フォークは PrisMisskey.space で使用しているフォークになります。 -このコードを一部でも使用する場合はクレジット表示をお願いします。 +<div align="center"> +<a href="https://misskey-hub.net"> + <img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/> +</a> + +**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀** + + +--- +</div> + +# 当フォークについて + +当フォークは PrisMisskey.space で使用しているフォークになります。 +このコードを一部でも使用する場合はクレジット表示をお願いします。 diff --git a/chart/templates/Deployment.yml b/chart/templates/Deployment.yml index d5dd14f59e..3c73837801 100644 --- a/chart/templates/Deployment.yml +++ b/chart/templates/Deployment.yml @@ -27,7 +27,7 @@ spec: ports: - containerPort: 3000 - name: postgres - image: postgres:14-alpine + image: postgres:15-alpine env: - name: POSTGRES_USER value: "example-misskey-user" @@ -38,7 +38,7 @@ spec: ports: - containerPort: 5432 - name: redis - image: redis:alpine + image: redis:7-alpine ports: - containerPort: 6379 volumes: diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 6ac56ffc29..0a7d86cc89 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -120,7 +120,6 @@ sensitive: "محتوى حساس" add: "إضافة" reaction: "التفاعلات" reactions: "التفاعلات" -reactionSetting: "التفاعلات المراد عرضها في منتقي التفاعلات." reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة." rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات" attachCancel: "أزل المرفق" @@ -817,8 +816,6 @@ makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك classic: "تقليدي" muteThread: "اكتم النقاش" unmuteThread: "ارفع الكتم عن النقاش" -ffVisibility: "مرئية المتابِعين/المتابَعين" -ffVisibilityDescription: "يسمح لك بتحديد من يمكنهم رؤية متابِعيك ومتابَعيك." continueThread: "اعرض بقية النقاش" deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟" incorrectPassword: "كلمة السر خاطئة." @@ -947,9 +944,12 @@ rolesAssignedToMe: "الأدوار المسندة إلي" resetPasswordConfirm: "هل تريد إعادة تعيين كلمة السر؟" license: "الرخصة" unfavoriteConfirm: "أتريد إزالتها من المفضلة؟" +reactionsDisplaySize: "حجم التفاعلات" +limitWidthOfReaction: "تصغير حجم التفاعلات" noteIdOrUrl: "معرف الملاحظة أو رابطها" video: "فيديو" videos: "فيديوهات" +dataSaver: "موفر البيانات" accountMigration: "ترحيل الحساب" accountMoved: "نقل هذا المستخدم حسابه:" accountMovedShort: "رُحل هذا الحساب." @@ -957,6 +957,7 @@ operationForbidden: "عملية ممنوعة" forceShowAds: "أظهر الإعلانات التجارية دائما" reactionsList: "التفاعلات" renotesList: "إعادات النشر" +notificationDisplay: "إشعارات" leftTop: "أعلى اليسار" rightTop: "أعلى اليمين" leftBottom: "أسفل اليسار" @@ -979,6 +980,7 @@ thisChannelArchived: "أُرشفت هذه القناة." displayOfNote: "عرض الملاحظة" initialAccountSetting: "إعداد الملف الشخصي" youFollowing: "متابَع" +preventAiLearning: "منع استخدام البيانات في تعليم الآلة" options: "خيارات" specifyUser: "مستخدم محدد" failedToPreviewUrl: "تتعذر المعاينة" @@ -992,7 +994,16 @@ later: "لاحقاً" goToMisskey: "لميسكي" additionalEmojiDictionary: "قواميس إيموجي إضافية" installed: "مُثبت" +enableServerMachineStats: "نشر إحصائيات عتاد الخادم" +turnOffToImprovePerformance: "تفعيله قد يزيد الأداء." +createInviteCode: "ولِّد دعوة" +inviteCodeCreated: "ولِّدت دعوة" +inviteLimitExceeded: "وصلتَ لحد عدد الدعوات المسموح لك توليدها." +createLimitRemaining: "حد عدد الدعوات: {limit} دعوة" expirationDate: "تاريخ انتهاء الصلاحية" +noExpirationDate: "لا نهاية لصلاحيتها" +inviteCodeUsedAt: "اُستخدم رمز الدعوة في" +registeredUserUsingInviteCode: "اِستخدم رمز الدعوة" unused: "غير مستعمَل" expired: "منتهية صلاحيته" icon: "الصورة الرمزية" @@ -1549,3 +1560,4 @@ _webhookSettings: _moderationLogTypes: suspend: "علِق" resetPassword: "أعد تعيين كلمتك السرية" + createInvitation: "ولِّد دعوة" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index c6784269c4..c659e13250 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -108,7 +108,6 @@ sensitive: "সংবেদনশীল বিষয়বস্তু" add: "যুক্ত করুন" reaction: "প্রতিক্রিয়া" reactions: "প্রতিক্রিয়া" -reactionSetting: "রিঅ্যাকশন পিকারে যেসকল প্রতিক্রিয়া দেখানো হবে" reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।" rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন" attachCancel: "অ্যাটাচমেন্ট সরান " @@ -794,8 +793,6 @@ makeReactionsPublicDescription: "আপনার পূর্ববর্তী classic: "ক্লাসিক" muteThread: "থ্রেড মিউট করুন" unmuteThread: "থ্রেড আনমিউট করুন" -ffVisibility: "অনুসরণ/অনুসরণকারীদের দৃশ্যমান্যতা" -ffVisibilityDescription: "আপনি কাকে অনুসরণ করেন এবং কে আপনাকে অনুসরণ করে, সেটা কারা দেখতে পাবে তা নির্ধারণ করে।" continueThread: "আরো থ্রেড দেখুন" deleteAccountConfirm: "আপনার অ্যাকাউন্ট মুছে ফেলা হবে। ঠিক আছে?" incorrectPassword: "আপনার দেওয়া পাসওয়ার্ডটি ভুল।" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 018645768d..727e473cf3 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -121,7 +121,12 @@ sensitive: "NSFW" add: "Afegir" reaction: "Reaccions" reactions: "Reaccions" -reactionSetting: "Reaccions a mostrar al selector de reaccions" +emojiPicker: "Selecció d'emojis" +pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb el qual reaccionar" +pinnedEmojisSettingDescription: "Selecciona l'emoji amb el qual reaccionar" +emojiPickerDisplay: "Visualitza el selector d'emojis" +overwriteFromPinnedEmojisForReaction: "Reemplaça els emojis de la reacció" +overwriteFromPinnedEmojis: "Sobreescriu des dels emojis fixats" reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir." rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes" attachCancel: "Eliminar el fitxer adjunt" @@ -214,6 +219,9 @@ clearQueueConfirmText: "Les notes no lliurades que quedin a la cua no es federar clearCachedFiles: "Esborra la memòria cau" clearCachedFilesConfirm: "Segur que voleu eliminar tots els fitxers de la memòria cau?" blockedInstances: "Instàncies bloquejades" +blockedInstancesDescription: "Llista els enllaços d'amfitrió de les instàncies que vols bloquejar separades per un salt de pàgina. Les instàncies llistades no podran comunicar-se amb aquesta instància." +silencedInstances: "Instàncies silenciades" +silencedInstancesDescription: "Llista els enllaços d'amfitrió de les instàncies que vols silenciar. Tots els comptes de les instàncies llistades s'establiran com silenciades i només podran fer sol·licitacions de seguiment, i no podran mencionar als comptes locals si no els segueixen. Això no afectarà les instàncies bloquejades." muteAndBlock: "Silencia i bloca" mutedUsers: "Usuaris silenciats" blockedUsers: "Usuaris bloquejats" @@ -228,9 +236,12 @@ preview: "Vista prèvia" default: "Per defecte" defaultValueIs: "Per defecte: {value}" noCustomEmojis: "Cap emoji personalitzat" +noJobs: "No hi ha feines" federating: "Federant" blocked: "Bloquejat" suspended: "Suspés" +all: "tot" +subscribing: "Subscrit a" publishing: "S'està publicant" notResponding: "Sense resposta" instanceFollowing: "Seguits del servidor" @@ -255,11 +266,31 @@ removed: "Eliminat" removeAreYouSure: "Segur que voleu retirar «{x}»?" deleteAreYouSure: "Segur que voleu retirar «{x}»?" resetAreYouSure: "Segur que voleu restablir-ho?" +areYouSure: "Està segur?" saved: "S'ha desat" messaging: "Xat" upload: "Puja" +keepOriginalUploading: "Guarda la imatge original" +keepOriginalUploadingDescription: "Guarda la imatge pujada com hi és. Si està apagat, una versió per a la visualització a la xarxa serà generada quan sigui pujada." +fromDrive: "Des de la unitat" +fromUrl: "Des d'un enllaç" +uploadFromUrl: "Carrega des d'un enllaç" +uploadFromUrlDescription: "Enllaç del fitxer que vols carregar" +uploadFromUrlRequested: "Càrrega sol·licitada" +uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot prendre un temps" +explore: "Explora" +messageRead: "Vist" +noMoreHistory: "No hi resta més per veure" +startMessaging: "Començar a xatejar" +nUsersRead: "Vist per {n}" +agreeTo: "Accepto que {0}" +agree: "Hi estic d'acord" +agreeBelow: "Hi estic d'acord amb el següent" +basicNotesBeforeCreateAccount: "Notes importants" +termsOfService: "Condicions d'ús" start: "Comença" home: "Inici" +remoteUserCaution: "Ja que aquest usuari resideix a una instància remota, la informació mostrada es podria trobar incompleta." activity: "Activitat" images: "Imatges" image: "Imatges" @@ -275,16 +306,34 @@ dark: "Fosc" lightThemes: "Temes clars" darkThemes: "Temes foscos" syncDeviceDarkMode: "Sincronitza el mode fosc amb la configuració del dispositiu" +drive: "Unitat" +fileName: "Nom del Fitxer" +selectFile: "Selecciona fitxers" +selectFiles: "Selecciona fitxers" +selectFolder: "Selecció de carpeta" +selectFolders: "Selecció de carpeta" renameFile: "Canvia el nom del fitxer" folderName: "Nom de la carpeta" createFolder: "Crea una carpeta" renameFolder: "Canvia el nom de la carpeta" deleteFolder: "Elimina la carpeta" +folder: "Carpeta " addFile: "Afegeix un fitxer" +emptyDrive: "La teva unitat és buida" emptyFolder: "La carpeta està buida" unableToDelete: "No es pot eliminar" +inputNewFileName: "Introduïu el nom de fitxer nou" +inputNewDescription: "Inserta una nova llegenda" +inputNewFolderName: "Introduïu el nom de la carpeta nova" +circularReferenceFolder: "La carpeta destinatària és una subcarpeta de la carpeta a la qual la desitges moure" +hasChildFilesOrFolders: "No és possible esborrar aquesta carpeta ja que no és buida" copyUrl: "Copia l'URL" rename: "Canvia el nom" +avatar: "Icona" +banner: "Bàner" +displayOfSensitiveMedia: "Visualització de contingut sensible" +whenServerDisconnected: "Quan es perdi la connexió al servidor" +disconnectedFromServer: "Desconnectat pel servidor" reload: "Actualitza" doNothing: "Ignora" accept: "Accepta" @@ -354,33 +403,132 @@ notFound: "No s'ha trobat" markAsReadAllUnreadNotes: "Marca-ho tot com a llegit" help: "Ajuda" invites: "Convida" +title: "Títol" +text: "Text" +enable: "Habilita" next: "Següent" +retype: "Torneu a introduir-la" noteOf: "Publicació de: {user}" +quoteAttached: "Frase adjunta" +quoteQuestion: "Vols annexar-la com a cita?" +noMessagesYet: "Encara no hi ha missatges" +newMessageExists: "Has rebut un nou missatge" +onlyOneFileCanBeAttached: "Només pots adjuntar un fitxer a un missatge" +signinRequired: "Si us plau, Registra't o inicia la sessió abans de continuar" invitations: "Convida" +invitationCode: "Codi d'invitació" +checking: "Comprovació en curs..." +available: "Disponible" +unavailable: "No és disponible" +usernameInvalidFormat: "Pots fer servir lletres (majúscules i minúscules), números i barres baixes (\"_\")" +tooShort: "Massa curt" +tooLong: "Massa llarg" +weakPassword: "Contrasenya insegura" +normalPassword: "Bona contrasenya" +strongPassword: "Contrasenya segura" +passwordMatched: "Correcte!" +passwordNotMatched: "No coincideix" +signinWith: "Inicia sessió amb amb {x}" +signinFailed: "Autenticació sense èxit. Intenta-ho un altre cop utilitzant la contrasenya i el nom correctes." +or: "O" +language: "Idioma" +uiLanguage: "Idioma de l'interfície" +aboutX: "Respecte a {x}" +emojiStyle: "Estil d'emoji" +native: "Nadiu" +disableDrawer: "No mostrar els menús en calaixos" +showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor" +noHistory: "No hi ha un registre previ" +signinHistory: "Historial d'autenticacions" +enableAdvancedMfm: "Habilitar l'MFM avançat" +enableAnimatedMfm: "Habilitar l'MFM amb moviment" +doing: "Processant..." +category: "Categoria" tags: "Etiquetes" docSource: "Font del document" createAccount: "Crea un compte" existingAccount: "Compte existent" regenerate: "Regenera" fontSize: "Mida del text" +mediaListWithOneImageAppearance: "Altura de la llista de fitxers amb una única imatge" +limitTo: "Limita a {x}" noFollowRequests: "No tens sol·licituds de seguiment" +openImageInNewTab: "Obre imatges a una nova pestanya" dashboard: "Panell de control" local: "Local" remote: "Remot" total: "Total" +weekOverWeekChanges: "Canvis l'última setmana" +dayOverDayChanges: "Canvis ahir" appearance: "Aparença" clientSettings: "Configuració del client" accountSettings: "Configuració del compte" +promotion: "Promocionat" +promote: "Promoure" +numberOfDays: "Nombre de dies" hideThisNote: "Amaga la publicació" showFeaturedNotesInTimeline: "Mostra publicacions destacades en la línia de temps" +objectStorage: "Emmagatzematge d'objectes\n" +useObjectStorage: "Utilitzar l'emmagatzematge d'objectes" +objectStorageBaseUrl: "Base d'enllaç" +objectStorageBaseUrlDesc: "Prefix d'enllaç utilitzat per a fer referencia als fitxers. Especifica l'enllaç del teu CDN o Proxy si n'estàs utilitzant qualsevol, en cas contrari, especifica l'enllaç al que es pot accedir públicament segons la guia de servei que vosté utilitza.\nPer l'ús d'S3 utilitza 'https://<bucket>.s3.amazonaws.com' I per a GCS o serveis equivalents utilitza 'https://storage.googleapis.com/<bucket>'." newNoteRecived: "Hi ha publicacions noves" installedDate: "Data d'instal·lació" state: "Estat" sort: "Ordena" ascendingOrder: "Ascendent" descendingOrder: "Descendent" +removeAllFollowing: "Deixar de seguir tots els usuaris seguits" +removeAllFollowingDescription: "El fet d'executar això, et farà deixar de seguir a tots els usuaris de {host}. Si us plau, executa això si l'amfitrió, per exemple, ja no existeix." +userSuspended: "Aquest usuari ha sigut suspès" +userSilenced: "Aquest usuari està sent silenciat" +yourAccountSuspendedTitle: "Aquest compte és suspès" +yourAccountSuspendedDescription: "Aquest compte ha sigut suspès a causa de la violació de les condicions d'ús o similars. Contacta l'administrador si en vol saber més. Si us plau, no en faci un altre compte." +tokenRevoked: "Codi de seguretat no vàlid" +tokenRevokedDescription: "La petició més recent ha estat denegada perquè contenia un codi de seguretat no vàlid. Actualitza la pàgina i torna-ho a provar." +accountDeleted: "Compte eliminat amb èxit" +accountDeletedDescription: "Aquest compte ha sigut eliminat" +menu: "Menú" +divider: "Divisor" +addItem: "Afegir element" +rearrange: "Torna a ordenar" +relays: "Relés" +addRelay: "Afegeix relés" +inboxUrl: "Enllaç de la safata d'entrada" +addedRelays: "Relés afegits" +serviceworkerInfo: "És obligatòria l'activació per a obtenir notificacions push" deletedNote: "Publicacions eliminades" invisibleNote: "Publicacions amagades" +enableInfiniteScroll: "Carrega més automàticament\n" +visibility: "Visibilitat" +poll: "Enquesta" +useCw: "Amaga el contingut" +enablePlayer: "Obre el reproductor de vídeo" +disablePlayer: "Tanca el reproductor de vídeo" +expandTweet: "Expandir post" +themeEditor: "Editor de temes" +description: "Descripció" +describeFile: "Afegir subtitulació" +enterFileDescription: "Afegeix un títol" +author: "Autor" +leaveConfirm: "Hi ha canvis sense guardar. Els vols descartar?" +manage: "Administració" +plugins: "Extensions" +preferencesBackups: "Configuracions de les Còpies de seguretat" +deck: "Escriptori" +undeck: "Tanca l'escriptori" +useBlurEffectForModal: "Utilitzar l'efecte de difuminació a modals" +useFullReactionPicker: "Utilitza el cercador de reaccions d'escala sencera" +width: "Amplada" +height: "Alçària" +large: "Gran" +medium: "Mitjà" +small: "Petit" +generateAccessToken: "Genera codi d'accés" +permission: "Permisos" +enableAll: "Habilita tot" +disableAll: "Deshabilita tot" +tokenRequested: "Donar accés al compte" smtpHost: "Amfitrió" smtpUser: "Nom d'usuari" smtpPass: "Contrasenya" @@ -390,12 +538,17 @@ clearCache: "Esborra la memòria cau" showingPastTimeline: "Estàs veient una línia de temps antiga" info: "Informació" user: "Usuaris" +administration: "Administració" +middle: "Mitjà" global: "Global" searchByGoogle: "Cercar" file: "Fitxers" +icon: "Icona" replies: "Respondre" renotes: "Impulsa" _role: + _priority: + middle: "Mitjà" _options: antennaMax: "Nombre màxim d'antenes" _email: @@ -404,9 +557,11 @@ _email: _instanceMute: instanceMuteDescription: "Silencia tots els impulsos dels servidors seleccionats, també els usuaris que responen a altres d'un servidor silenciat." _theme: + description: "Descripció" keys: mention: "Menció" renote: "Renotar" + divider: "Divisor" _sfx: note: "Notes" notification: "Notificacions" @@ -448,6 +603,8 @@ _timelines: local: "Local" social: "Social" global: "Global" +_play: + summary: "Descripció" _pages: contents: "Contingut" blocks: diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 8221da44ea..1e064c4911 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -120,7 +120,6 @@ sensitive: "NSFW" add: "Přidat" reaction: "Reakce" reactions: "Reakce" -reactionSetting: "Reakce zobrazené ve výběru reakcí" reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte \"+\" k přidání" rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky" attachCancel: "Odstranit přílohu" @@ -855,8 +854,6 @@ makeReactionsPublicDescription: "Tohle zviditelný seznam vašich předchozích classic: "Klasický" muteThread: "Ztlumit vlákno" unmuteThread: "Zrušit ztlumení vlákna" -ffVisibility: "Viditelnost Sledovaných/Sledujících" -ffVisibilityDescription: "Umožní vám nastavit kdo uvidí koho sledujete a kdo vás sleduje." continueThread: "Zobrazit pokračování vlákna" deleteAccountConfirm: "Tohle nenávratně smaže váš účet, chcete pokračovat?" incorrectPassword: "Nesprávné heslo." diff --git a/locales/de-DE.yml b/locales/de-DE.yml index db6aea29c4..4c32b3dda4 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -121,7 +121,6 @@ sensitive: "Sensibel" add: "Hinzufügen" reaction: "Reaktionen" reactions: "Reaktionen" -reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen" reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen" rememberNoteVisibility: "Notizsichtbarkeit merken" attachCancel: "Anhang entfernen" @@ -874,8 +873,6 @@ makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktion classic: "Classic" muteThread: "Thread stummschalten" unmuteThread: "Threadstummschaltung aufheben" -ffVisibility: "Sichtbarkeit von Gefolgten/Followern" -ffVisibilityDescription: "Konfiguriere wer sehen kann, wem du folgst sowie wer dir folgt." continueThread: "Weiteren Threadverlauf anzeigen" deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?" incorrectPassword: "Falsches Passwort." diff --git a/locales/el-GR.yml b/locales/el-GR.yml index a1c2d25391..30a52b726e 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -104,7 +104,6 @@ clickToShow: "Κάντε κλικ για εμφάνιση" add: "Προσθέστε" reaction: "Αντιδράσεις" reactions: "Αντιδράσεις" -reactionSetting: "Αντιδράσεις για εμφάνιση στην επιλογή αντίδρασης" reactionSettingDescription2: "Σύρετε για να αλλάξετε τη σειρά, κάντε κλικ για να διαγράψετε, πατήστε \"+\" για να προσθέσετε." rememberNoteVisibility: "Θυμήσου τις ρυθμίσεις ορατότητας σημειώματος" attachCancel: "Διαγραφή αρχείου" diff --git a/locales/en-US.yml b/locales/en-US.yml index e31efe131b..0a5b7b4ea5 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -121,7 +121,6 @@ sensitive: "Sensitive" add: "Add" reaction: "Reactions" reactions: "Reactions" -reactionSetting: "Reactions to show in the reaction picker" reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add." rememberNoteVisibility: "Remember note visibility settings" attachCancel: "Remove attachment" @@ -548,7 +547,7 @@ showInPage: "Show in page" popout: "Pop-out" volume: "Volume" masterVolume: "Master volume" -notUseSound: "No sounds output." +notUseSound: "Disable sound" useSoundOnlyWhenActive: "Output sounds only if Misskey is active." details: "Details" chooseEmoji: "Select an emoji" @@ -879,8 +878,6 @@ makeReactionsPublicDescription: "This will make the list of all your past reacti classic: "Classic" muteThread: "Mute thread" unmuteThread: "Unmute thread" -ffVisibility: "Follows/Followers Visibility" -ffVisibilityDescription: "Allows you to configure who can see who you follow and who follows you." continueThread: "View thread continuation" deleteAccountConfirm: "This will irreversibly delete your account. Proceed?" incorrectPassword: "Incorrect password." @@ -1177,6 +1174,7 @@ cwNotationRequired: "If \"Hide content\" is enabled, a description must be provi doReaction: "Add reaction" code: "Code" reloadRequiredToApplySettings: "Reloading is required to apply the settings." +decorate: "Decorate" _announcement: forExistingUsers: "Existing users only" forExistingUsersDescription: "This announcement will only be shown to users existing at the point of publishment if enabled. If disabled, those newly signing up after it has been posted will also see it." @@ -1266,7 +1264,7 @@ _initialTutorial: sensitiveSucceeded: "When attaching files, please set sensitivities in accordance with the server guidelines." doItToContinue: "Mark the attachment file as sensitive to proceed." _done: - title: "The tutorial is complete! 🎉" + title: "You've completed the tutorial! 🎉" description: "The functions introduced here are just a small part. For a more detailed understanding of using Misskey, please refer to {link}." _timelineDescription: home: "In the Home timeline, you can see notes from accounts you follow." @@ -2178,6 +2176,7 @@ _notification: pollEnded: "Poll results have become available" newNote: "New note" unreadAntennaNote: "Antenna {name}" + roleAssigned: "Role given" emptyPushNotificationMessage: "Push notifications have been updated" achievementEarned: "Achievement unlocked" testNotification: "Test notification" @@ -2199,6 +2198,7 @@ _notification: pollEnded: "Polls ending" receiveFollowRequest: "Received follow requests" followRequestAccepted: "Accepted follow requests" + roleAssigned: "Role given" achievementEarned: "Achievement unlocked" app: "Notifications from linked apps" _actions: diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 3c36e2b29f..a079cf01f9 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -121,7 +121,6 @@ sensitive: "Marcado como sensible" add: "Agregar" reaction: "Reacción" reactions: "Reacción" -reactionSetting: "Reacciones para mostrar en el menú de reacciones" reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir." rememberNoteVisibility: "Recordar visibilidad" attachCancel: "Quitar adjunto" @@ -874,8 +873,6 @@ makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán pú classic: "Clásico" muteThread: "Silenciar hilo" unmuteThread: "Mostrar hilo" -ffVisibility: "Visibilidad de seguidores y seguidos" -ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen" continueThread: "Ver la continuación del hilo" deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?" incorrectPassword: "La contraseña es incorrecta" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index bc0676eb0a..e12b508617 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -121,7 +121,12 @@ sensitive: "Contenu sensible" add: "Ajouter" reaction: "Réactions" reactions: "Réactions" -reactionSetting: "Réactions à afficher dans le sélecteur de réactions" +emojiPicker: "Sélecteur d’émojis" +pinnedEmojisForReactionSettingDescription: "Vous pouvez définir les émojis épinglés lors de la réaction" +pinnedEmojisSettingDescription: "Vous pouvez définir les émojis épinglés lors de la saisie de l'émoji" +emojiPickerDisplay: "Affichage du sélecteur d'émojis" +overwriteFromPinnedEmojisForReaction: "Remplacer par les émojis épinglés pour la réaction" +overwriteFromPinnedEmojis: "Remplacer par les émojis épinglés globalement" reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter." rememberNoteVisibility: "Se souvenir de la visibilité des notes" attachCancel: "Supprimer le fichier attaché" @@ -873,8 +878,8 @@ makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos réactions d classic: "Classique" muteThread: "Masquer cette discussion" unmuteThread: "Ne plus masquer le fil" -ffVisibility: "Visibilité des abonnés/abonnements" -ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu suis et les personnes qui te suivent." +followingVisibility: "Visibilité des abonnements" +followersVisibility: "Visibilité des abonnés" continueThread: "Afficher la suite du fil" deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?" incorrectPassword: "Le mot de passe est incorrect." @@ -1024,6 +1029,8 @@ license: "Licence" myClips: "Mes clips" drivecleaner: "Nettoyeur du Disque" retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur." +enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants" +enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes" showClipButtonInNoteFooter: "Ajouter « Clip » au menu d'action de la note" reactionsDisplaySize: "Taille de l'affichage des réactions" limitWidthOfReaction: "Limiter la largeur maximale des réactions et les afficher en taille réduite" @@ -1067,6 +1074,7 @@ options: "Options" specifyUser: "Spécifier l'utilisateur·rice" failedToPreviewUrl: "Aperçu d'URL échoué" update: "Mettre à jour" +rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction" later: "Plus tard" goToMisskey: "Retour vers Misskey" additionalEmojiDictionary: "Dictionnaires d'émojis additionnels" @@ -1129,6 +1137,9 @@ doReaction: "Réagir" code: "Code" reloadRequiredToApplySettings: "Le rafraîchissement est nécessaire pour que les paramètres prennent effet." remainingN: "Restants : {n}" +overwriteContentConfirm: "Voulez-vous remplacer le contenu actuel ?" +seasonalScreenEffect: "Effet d'écran saisonnier" +decorate: "Décorer" _announcement: readConfirmTitle: "Marquer comme lu ?" shouldNotBeUsedToPresentPermanentInfo: "Puisque cela pourrait nuire considérablement à l'expérience utilisateur pour les nouveaux utilisateurs, il est recommandé d'utiliser les annonces pour afficher des informations temporaires plutôt que des informations persistantes." @@ -1888,6 +1899,7 @@ _notification: yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté" pollEnded: "Les résultats du sondage sont disponibles" unreadAntennaNote: "Antenne {name}" + roleAssigned: "Rôle attribué" emptyPushNotificationMessage: "Les notifications push ont été mises à jour" achievementEarned: "Accomplissement" testNotification: "Tester la notification" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index eebdf90646..dc5600151a 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -121,7 +121,6 @@ sensitive: "Konten sensitif" add: "Tambahkan" reaction: "Reaksi" reactions: "Reaksi" -reactionSetting: "Reaksi untuk dimunculkan di bilah reaksi" reactionSettingDescription2: "Geser untuk memindah urutan emoji, klik untuk menghapus, tekan \"+\" untuk menambahkan" rememberNoteVisibility: "Ingat pengaturan visibilitas catatan" attachCancel: "Hapus lampiran" @@ -261,6 +260,7 @@ removed: "Telah dihapus" removeAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?" deleteAreYouSure: "Apakah kamu yakin ingin menghapus \"{x}\"?" resetAreYouSure: "Yakin mau atur ulang?" +areYouSure: "Apakah kamu yakin?" saved: "Telah disimpan" messaging: "Pesan" upload: "Unggah" @@ -311,6 +311,7 @@ folderName: "Nama folder" createFolder: "Buat folder" renameFolder: "Ubah nama folder" deleteFolder: "Hapus folder" +folder: "Folder" addFile: "Tambahkan berkas" emptyDrive: "Drive kosong" emptyFolder: "Folder kosong" @@ -543,6 +544,8 @@ showInPage: "Tampilkan di halaman" popout: "Pop-out" volume: "Volume" masterVolume: "Master volume" +notUseSound: "Tidak ada keluaran suara" +useSoundOnlyWhenActive: "Hanya keluarkan suara jika Misskey sedang aktif" details: "Selengkapnya" chooseEmoji: "Pilih emoji" unableToProcess: "Operasi tersebut tidak dapat diselesaikan." @@ -871,8 +874,6 @@ makeReactionsPublicDescription: "Pengaturan ini akan membuat daftar dari semua r classic: "Klasik" muteThread: "Bisukan thread" unmuteThread: "Suarakan thread" -ffVisibility: "Visibilitas Mengikuti/Pengikut" -ffVisibilityDescription: "Mengatur siapa yang dapat melihat pengikutmu dan yang kamu ikuti." continueThread: "Lihat lanjutan thread" deleteAccountConfirm: "Akun akan dihapus. Apakah kamu yakin?" incorrectPassword: "Kata sandi salah." @@ -1023,6 +1024,8 @@ resetPasswordConfirm: "Yakin untuk mereset kata sandimu?" sensitiveWords: "Kata sensitif" sensitiveWordsDescription: "Visibilitas dari semua catatan mengandung kata yang telah diatur akan dijadikan \"Beranda\" secara otomatis. Kamu dapat mendaftarkan kata tersebut lebih dari satu dengan menuliskannya di baris baru." sensitiveWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler." +hiddenTags: "Tagar tersembunyi" +hiddenTagsDescription: "Pilih tanda yang mana akan tidak diperlihatkan dalam daftar tren.\nTanda lebih dari satu dapat didaftarkan dengan tiap baris." notesSearchNotAvailable: "Pencarian catatan tidak tersedia." license: "Lisensi" unfavoriteConfirm: "Yakin ingin menghapusnya dari favorit?" @@ -1035,6 +1038,7 @@ enableChartsForRemoteUser: "Buat bagan data pengguna instansi luar" enableChartsForFederatedInstances: "Buat bagan data peladen instansi luar" showClipButtonInNoteFooter: "Tambahkan \"Klip\" ke menu aksi catatan" reactionsDisplaySize: "Ukuran tampilan reaksi" +limitWidthOfReaction: "Batasi lebar maksimum reaksi dan tampilkan dalam ukuran terbatasi." noteIdOrUrl: "ID catatan atau URL" video: "Video" videos: "Video" @@ -1161,6 +1165,9 @@ useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan" signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa." cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan." doReaction: "Tambahkan reaksi" +code: "Kode" +reloadRequiredToApplySettings: "Muat ulang diperlukan untuk menerapkan pengaturan." +remainingN: "Sisa : {n}" _announcement: forExistingUsers: "Hanya pengguna yang telah ada" forExistingUsersDescription: "Pengumuman ini akan dimunculkan ke pengguna yang sudah ada dari titik waktu publikasi jika dinyalakan. Apabila dimatikan, mereka yang baru mendaftar setelah publikasi ini akan juga melihatnya." @@ -1189,12 +1196,17 @@ _initialAccountSetting: _initialTutorial: launchTutorial: "Lihat Tutorial" title: "Tutorial" + wellDone: "Kerja bagus!" skipAreYouSure: "Berhenti dari Tutorial?" _landing: title: "Selamat datang di Tutorial" description: "Di sini kamu dapat mempelajari dasar-dasar dari penggunaan Misskey dan fitur-fiturnya." _note: title: "Apa itu Catatan?" + _reaction: + title: "Apa itu Reaksi?" + _timeline: + title: "Konsep Lini Masa" _postNote: title: "Pengaturan posting Catatan" _visibility: @@ -1202,6 +1214,12 @@ _initialTutorial: home: "Hanya publik ke lini masa Beranda. Pengguna yang mengunjungi profilmu melalui pengikut dan renote dapat melihatnya." followers: "Perlihatkan ke pengikut saja. Hanya pengikut yang dapat melihat postinganmu dan tidak dapat direnote oleh siapapun." direct: "Hanya perlihatkan ke pengguna spesifik dan penerima akan diberi tahu. Dapat juga digunakan sebagai alternatif dari pesan langsung." + _cw: + _exampleNote: + cw: "Peringatan: Bikin Lapar!" + note: "Baru aja makan donat berlapis coklat 🍩😋" + _howToMakeAttachmentsSensitive: + title: "Bagaimana menandai lampiran sebagai sensitif?" _serverRules: description: "Daftar peraturan akan ditampilkan sebelum pendaftaran. Mengatur ringkasan dari Syarat dan Ketentuan sangat direkomendasikan." _serverSettings: diff --git a/locales/index.d.ts b/locales/index.d.ts index d9f84ade00..a437b95689 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -137,8 +137,8 @@ export interface Locale { "pinnedEmojisForReactionSettingDescription": string; "pinnedEmojisSettingDescription": string; "emojiPickerDisplay": string; - "copyFromPinnedEmojisForReaction": string; - "copyFromPinnedEmojis": string; + "overwriteFromPinnedEmojisForReaction": string; + "overwriteFromPinnedEmojis": string; "reactionSettingDescription2": string; "rememberNoteVisibility": string; "attachCancel": string; @@ -918,8 +918,8 @@ export interface Locale { "classic": string; "muteThread": string; "unmuteThread": string; - "ffVisibility": string; - "ffVisibilityDescription": string; + "followingVisibility": string; + "followersVisibility": string; "continueThread": string; "deleteAccountConfirm": string; "incorrectPassword": string; @@ -1221,6 +1221,8 @@ export interface Locale { "reloadRequiredToApplySettings": string; "remainingN": string; "overwriteContentConfirm": string; + "seasonalScreenEffect": string; + "decorate": string; "_announcement": { "forExistingUsers": string; "forExistingUsersDescription": string; @@ -2382,6 +2384,7 @@ export interface Locale { "pollEnded": string; "newNote": string; "unreadAntennaNote": string; + "roleAssigned": string; "emptyPushNotificationMessage": string; "achievementEarned": string; "testNotification": string; @@ -2403,6 +2406,7 @@ export interface Locale { "pollEnded": string; "receiveFollowRequest": string; "followRequestAccepted": string; + "roleAssigned": string; "achievementEarned": string; "app": string; }; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 8c233dd66a..6ce6cd5604 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -121,7 +121,12 @@ sensitive: "Allegato esplicito" add: "Aggiungi" reaction: "Reazioni" reactions: "Reazioni" -reactionSetting: "Reazioni visualizzate sul pannello" +emojiPicker: "Selettore emoji" +pinnedEmojisForReactionSettingDescription: "Scegli quale sia l'emoji in cima, quando reagisci" +pinnedEmojisSettingDescription: "Scegli quale sia l'emoji in cima, quando reagisci" +emojiPickerDisplay: "Visualizza selettore" +overwriteFromPinnedEmojisForReaction: "Sovrascrivi con le impostazioni reazioni" +overwriteFromPinnedEmojis: "Sovrascrivi con le impostazioni globali" reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere." rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note" attachCancel: "Rimuovi allegato" @@ -261,6 +266,7 @@ removed: "Eliminato con successo" removeAreYouSure: "Vuoi davvero eliminare \"{x}\"?" deleteAreYouSure: "Vuoi davvero eliminare \"{x}\"?" resetAreYouSure: "Ripristinare?" +areYouSure: "Confermi?" saved: "Salvato" messaging: "Messaggi" upload: "Carica" @@ -875,8 +881,6 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di classic: "Classico" muteThread: "Silenzia conversazione" unmuteThread: "Riattiva la conversazione" -ffVisibility: "Visibilità delle connessioni" -ffVisibilityDescription: "Puoi scegliere a chi mostrare le tue relazioni con altri profili nel fediverso." continueThread: "Altre conversazioni" deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?" incorrectPassword: "La password è errata." @@ -1157,6 +1161,7 @@ tosAndPrivacyPolicy: "Condizioni d'uso e informativa privacy" avatarDecorations: "Decorazioni foto profilo" attach: "Applica" detach: "Rimuovi" +detachAll: "Togli tutto" angle: "Angolo" flip: "Inverti" showAvatarDecorations: "Mostra decorazione della foto profilo" @@ -1170,6 +1175,10 @@ cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplici doReaction: "Reagisci" code: "Codice" reloadRequiredToApplySettings: "Per applicare le impostazioni, occorre ricaricare." +remainingN: "Rimangono: {n}" +overwriteContentConfirm: "Vuoi davvero sostituire l'attuale contenuto?" +seasonalScreenEffect: "Schermate in base alla stagione" +decorate: "Decora" _announcement: forExistingUsers: "Solo ai profili attuali" forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio." @@ -1601,6 +1610,7 @@ _role: canHideAds: "Nascondere i banner" canSearchNotes: "Ricercare nelle Note" canUseTranslator: "Tradurre le Note" + avatarDecorationLimit: "Numero massimo di decorazioni foto profilo installabili" _condition: isLocal: "Profilo locale" isRemote: "Profilo remoto" @@ -2037,6 +2047,7 @@ _profile: changeAvatar: "Modifica immagine profilo" changeBanner: "Cambia intestazione" verifiedLinkDescription: "Puoi verificare il tuo profilo mostrando una icona. Devi inserire la URL alla pagina che contiene un link al tuo profilo." + avatarDecorationMax: "Puoi aggiungere fino a {max} decorazioni." _exportOrImport: allNotes: "Tutte le note" favoritedNotes: "Note preferite" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 1cf74ff149..f6858bf8be 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -134,8 +134,8 @@ emojiPicker: "絵文字ピッカー" pinnedEmojisForReactionSettingDescription: "リアクション時にピン留め表示する絵文字を設定できます" pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する絵文字を設定できます" emojiPickerDisplay: "ピッカーの表示" -copyFromPinnedEmojisForReaction: "リアクション設定からコピーする" -copyFromPinnedEmojis: "絵文字設定からコピーする" +overwriteFromPinnedEmojisForReaction: "リアクション設定から上書きする" +overwriteFromPinnedEmojis: "全般設定から上書きする" reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。" rememberNoteVisibility: "公開範囲を記憶する" attachCancel: "添付取り消し" @@ -915,8 +915,8 @@ makeReactionsPublicDescription: "あなたがしたリアクション一覧を classic: "クラシック" muteThread: "スレッドをミュート" unmuteThread: "スレッドのミュートを解除" -ffVisibility: "つながりの公開範囲" -ffVisibilityDescription: "自分のフォロー/フォロワー情報の公開範囲を設定できます。" +followingVisibility: "フォローの公開範囲" +followersVisibility: "フォロワーの公開範囲" continueThread: "さらにスレッドを見る" deleteAccountConfirm: "アカウントが削除されます。よろしいですか?" incorrectPassword: "パスワードが間違っています。" @@ -1218,6 +1218,8 @@ code: "コード" reloadRequiredToApplySettings: "設定の反映にはリロードが必要です。" remainingN: "残り: {n}" overwriteContentConfirm: "現在の内容に上書きされますがよろしいですか?" +seasonalScreenEffect: "季節に応じた画面の演出" +decorate: "デコる" _announcement: forExistingUsers: "既存ユーザーのみ" @@ -2284,6 +2286,7 @@ _notification: pollEnded: "アンケートの結果が出ました" newNote: "新しい投稿" unreadAntennaNote: "アンテナ {name}" + roleAssigned: "ロールが付与されました" emptyPushNotificationMessage: "プッシュ通知の更新をしました" achievementEarned: "実績を獲得" testNotification: "通知テスト" @@ -2306,6 +2309,7 @@ _notification: pollEnded: "アンケートが終了" receiveFollowRequest: "フォロー申請を受け取った" followRequestAccepted: "フォローが受理された" + roleAssigned: "ロールが付与された" achievementEarned: "実績の獲得" app: "連携アプリからの通知" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index c1d60d8a4c..4bd44f56d9 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -121,7 +121,12 @@ sensitive: "気いつけて見いや" add: "増やす" reaction: "ツッコミ" reactions: "ツッコミ" -reactionSetting: "ピッカーに出しとくツッコミ" +emojiPicker: "絵文字ピッカー" +pinnedEmojisForReactionSettingDescription: "リアクションしたときにピンで留めてる表示をする絵文字を設定するで" +pinnedEmojisSettingDescription: "絵文字打ったときにピン留め表示する絵文字設定できるで" +emojiPickerDisplay: "ピッカーの表示" +overwriteFromPinnedEmojisForReaction: "リアクション設定から上書きする" +overwriteFromPinnedEmojis: "全般設定から上書きする" reactionSettingDescription2: "ドラッグで並び替え、クリックで削除、+を押して追加やで。" rememberNoteVisibility: "公開範囲覚えといて" attachCancel: "のっけるのやめる" @@ -261,6 +266,7 @@ removed: "ほかしたで!" removeAreYouSure: "「{x}」はほかしてええか?" deleteAreYouSure: "「{x}」はほかしてええか?" resetAreYouSure: "リセットしてええん?" +areYouSure: "いいん?" saved: "保存したで!" messaging: "チャット" upload: "アップロード" @@ -875,8 +881,6 @@ makeReactionsPublicDescription: "あんたがしたツッコミ一覧を誰で classic: "クラシック" muteThread: "スレッドをミュート" unmuteThread: "スレッドのミュートを解除" -ffVisibility: "つながりの公開範囲" -ffVisibilityDescription: "あんたのフォロー/フォロワー情報の公開範囲を設定できるで。" continueThread: "さらにスレッドを見るで" deleteAccountConfirm: "アカウントを消すで?ええんか?" incorrectPassword: "パスワードがちゃうわ。" @@ -1157,6 +1161,7 @@ tosAndPrivacyPolicy: "利用規約・プライバシーポリシー" avatarDecorations: "アイコンデコレーション" attach: "のっける" detach: "取る" +detachAll: "全部とる" angle: "角度" flip: "反転" showAvatarDecorations: "アイコンのデコレーション映す" @@ -1170,6 +1175,10 @@ cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカ doReaction: "ツッコむで" code: "コード" reloadRequiredToApplySettings: "設定を見るんにはリロードが必要やで。" +remainingN: "残り:{n}" +overwriteContentConfirm: "今の内容に上書きされるけどいい?" +seasonalScreenEffect: "季節にあった画面の動き" +decorate: "デコる" _announcement: forExistingUsers: "もうおるユーザーのみ" forExistingUsersDescription: "オンにしたらこのお知らせができた時点でおる人らにだけお知らせが行くで。切ったらこの知らせが行ったあとにアカウント作った人にもちゃんとお知らせが行くで。" @@ -1601,6 +1610,7 @@ _role: canHideAds: "広告映さへん" canSearchNotes: "ノート探せるかどうか" canUseTranslator: "翻訳使えるかどうか" + avatarDecorationLimit: "アイコンデコのいっちばんつけれる数" _condition: isLocal: "ローカルユーザー" isRemote: "リモートユーザー" @@ -2037,6 +2047,7 @@ _profile: changeAvatar: "アバター画像を変更するで" changeBanner: "バナー画像を変更するで" verifiedLinkDescription: "内容をURLに設定すると、リンク先のwebサイトに自分のプロフのリンクが含まれてる場合に所有者確認済みアイコンを表示させることができるで。" + avatarDecorationMax: "最大{max}つまでデコつけれんで" _exportOrImport: allNotes: "全てのノート" favoritedNotes: "お気に入りにしたノート" diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index 760247c483..9b113ad1b9 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -15,7 +15,7 @@ gotIt: "알것어예" cancel: "아이예" noThankYou: "뎃어예" enterUsername: "사용자 이럼 서기" -renotedBy: "{user}님이 리노트햇십니다" +renotedBy: "{user}님이 리노트햇어예" noNotes: "노트가 없십니다" noNotifications: "알림이 없십니다" instance: "서버" @@ -76,7 +76,7 @@ export: "내가기" files: "파일" download: "내리받기" driveFileDeleteConfirm: "‘{name}’ 파일얼 뭉캡니꺼? 요 파일얼 서넌 콘텐츠도 뭉캐집니다." -unfollowConfirm: "{name}님얼 고만 팔로잉합니꺼?" +unfollowConfirm: "{name}님얼 고마 팔로잉합니꺼?" exportRequested: "내가기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다. 요청이 껕나모 ‘드라이브’에 옇십니다." importRequested: "가오기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다." lists: "리스트" @@ -113,7 +113,7 @@ cantReRenote: "리노트넌 지럴 리노트 몬 합니다." quote: "따오기" inChannelRenote: "채널 안 리노트" inChannelQuote: "채널 안 따오기" -pinnedNote: "프로필에 붙인 노트" +pinnedNote: "붙인 노트" pinned: "프로필에 붙이기" you: "나" clickToShow: "누질라서 보기" @@ -121,7 +121,6 @@ sensitive: "수ᇚ힛섭니다" add: "옇기" reaction: "반엉" reactions: "반엉" -reactionSetting: "모엄함서 포시할 반엉" reactionSettingDescription2: "꺼시서 두고, 누질라서 뭉캐고, ‘+’럴 누질라서 옇십니다." rememberNoteVisibility: "공개 범위럴 기억하기" attachCancel: "붙임 빼기" @@ -330,7 +329,7 @@ whenServerDisconnected: "서버하고 옌겔이 껂기모" disconnectedFromServer: "서버하고 옌겔이 껂깃십니다" reload: "새로곤침" doNothing: "무시하기" -reloadConfirm: "새로곤침합니까?" +reloadConfirm: "새로곤침합니꺼?" watch: "간심 갖기" unwatch: "간심 고마 갖기" accept: "받기" @@ -368,7 +367,7 @@ pinnedUsersDescription: "‘살펴보기’서 붙일라넌 사용자럴 줄 바 pinnedPages: "붙인 바닥" pinnedPagesDescription: "서버으 대문서 붙일라넌 바닥으 겡로럴 줄 바꿈해서로 적십니다." pinnedClipId: "붙일 클립으 아이디" -pinnedNotes: "프로필에 붙인 노트" +pinnedNotes: "붙인 노트" hcaptcha: "에이치캡차" enableHcaptcha: "에이치캡차 키기" hcaptchaSiteKey: "사이트키" @@ -381,7 +380,7 @@ turnstile: "턴스타일" enableTurnstile: "턴스타일 키기" turnstileSiteKey: "사이트키" turnstileSecretKey: "시크릿키" -avoidMultiCaptchaConfirm: "오만 캡차럴 서모 간섭이 잇얼 깁니다. 다린 캡차를 껍니까? ‘아이예’럴 누질리모 오만 캡차럴 키 둘 수도 잇십니다." +avoidMultiCaptchaConfirm: "오만 캡차럴 서모 간섭이 잇얼 깁니다. 다린 캡차를 껍니꺼? ‘아이예’럴 누질리모 오만 캡차럴 키 둘 수도 잇십니다." antennas: "안테나" manageAntennas: "안테나 간리" name: "이럼" @@ -413,7 +412,7 @@ userList: "리스트" about: "정보" aboutMisskey: "Misskey넌예" administrator: "간리자" -token: "학인 코드" +token: "학인 기호" 2fa: "두 단게 정멩" setupOf2fa: "두 단게 정멩 설정" totp: "정멩 앱" @@ -426,13 +425,45 @@ moderationLogs: "중재 일지" nUsersMentioned: "{n}멩이 이바구하고 잇어예" securityKeyAndPasskey: "보안키·패스키" securityKey: "보안키" +unregister: "맨걸기 무루기" +share: "노누기" +notFound: "몬 찾앗십니다" +help: "도움말" invites: "초대하기" +retype: "다시 서기" +noteOf: "{user}님으 노트" invitations: "초대하기" +checking: "학인하고 잇십니다" +passwordMatched: "맞십니다" +passwordNotMatched: "안 맞십니다" language: "언어" +remote: "웬겍" +script: "스크립트" manage: "간리" +emailServer: "전자우펜 서버" +email: "전자우펜" +emailAddress: "전자우펜 주소" smtpHost: "호스트 이럼" +smtpPort: "포트" smtpUser: "사용자 이럼" smtpPass: "비밀번호" +abuseReports: "신고하기" +reportAbuse: "신고하기" +reportAbuseRenote: "리노트 신고하기" +reportAbuseOf: "{name}님얼 신고하기" +reporter: "신고한 사람" +reporteeOrigin: "신고덴 사람" +reporterOrigin: "신고한 곳" +forwardReport: "웬겍 서버에 신고 보내기" +random: "무작이" +system: "시스템" +clip: "클립 맨걸기" +notesCount: "노트 수" +renotesCount: "리노트한 수" +renotedCount: "리노트덴 수" +followingCount: "팔로우 수" +followersCount: "팔로워 수" +clips: "클립 맨걸기" clearCache: "캐시 비우기" unlikeConfirm: "좋네예럴 무룹니꺼?" info: "정보" @@ -440,6 +471,7 @@ user: "사용자" administration: "간리" on: "킴" off: "껌" +clickToFinishEmailVerification: "[{ok}]럴 누질라서 전자우펜 정멩얼 껕내이소." searchByGoogle: "찾기" tenMinutes: "십 분" oneHour: "한 시간" @@ -459,6 +491,20 @@ likeOnly: "좋네예마" icon: "아바타" replies: "답하기" renotes: "리노트" +_initialAccountSetting: + startTutorial: "길라잡이 하기" +_initialTutorial: + launchTutorial: "길라잡이 보기" + title: "길라잡이" + skipAreYouSure: "길라잡이럴 껕냅니까?" + _landing: + title: "길라잡이에 어서 오이소" + _done: + title: "길라잡이가 껕낫십니다!🎉" +_achievements: + _types: + _tutorialCompleted: + description: "길라잡이럴 껕냇십니다" _gallery: liked: "좋네예한 걸" like: "좋네예!" @@ -466,13 +512,16 @@ _gallery: _email: _follow: title: "새 팔로워가 잇십니다" +_channel: + removeBanner: "배너 뭉캐기" _theme: keys: mention: "멘션" _sfx: - note: "노트" + note: "새 노트" notification: "알림" _2fa: + step3Title: "학인 기호럴 서기" renewTOTPCancel: "뎃어예" _widgets: profile: "프로필" @@ -501,11 +550,15 @@ _charts: federation: "옌합" _timelines: home: "덜머리" +_play: + script: "스크립트" _pages: like: "좋네예" unlike: "좋네예 무루기" blocks: image: "이미지" + _note: + id: "노트 아이디" _notification: youWereFollowed: "새 팔로워가 잇십니다" _types: @@ -526,3 +579,6 @@ _webhookSettings: name: "이럼" _moderationLogTypes: suspend: "얼우기" + deleteNote: "노트 뭉캐기" + deleteUserAnnouncement: "사용자 공지 걸 뭉캐기" + resolveAbuseReport: "신고 해겔하기" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 2673e947f3..d8efa7f04e 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -121,7 +121,12 @@ sensitive: "열람 주의" add: "추가" reaction: "리액션" reactions: "리액션" -reactionSetting: "선택기에 표시할 리액션" +emojiPicker: "이모지 선택기" +pinnedEmojisForReactionSettingDescription: "리액션을 할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다" +pinnedEmojisSettingDescription: "이모지를 입력할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다" +emojiPickerDisplay: "선택기 표시" +overwriteFromPinnedEmojisForReaction: "리액션 설정을 덮어쓰기" +overwriteFromPinnedEmojis: "일반 설정을 덮어쓰기" reactionSettingDescription2: "끌어서 순서 변경, 클릭해서 삭제, +를 눌러서 추가할 수 있습니다." rememberNoteVisibility: "공개 범위를 기억하기" attachCancel: "첨부 취소" @@ -261,6 +266,7 @@ removed: "삭제하였습니다" removeAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?" deleteAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?" resetAreYouSure: "초기화 하시겠습니까?" +areYouSure: "계속 진행하시겠습니까?" saved: "저장하였습니다" messaging: "대화" upload: "업로드" @@ -686,7 +692,7 @@ defaultNavigationBehaviour: "기본 탐색 동작" editTheseSettingsMayBreakAccount: "이 설정을 변경하면 계정이 손상될 수 있습니다." instanceTicker: "노트의 서버 정보" waitingFor: "{x}을(를) 기다리고 있습니다" -random: "랜덤" +random: "무작위" system: "시스템" switchUi: "UI 전환" desktop: "데스크탑" @@ -875,8 +881,8 @@ makeReactionsPublicDescription: "나의 리액션을 누구나 볼 수 있게 classic: "클래식" muteThread: "글타래 뮤트" unmuteThread: "글타래 뮤트 해제" -ffVisibility: "내 인맥의 공개 범위" -ffVisibilityDescription: "나의 팔로우와 팔로워 정보에 대한 공개 범위를 설정할 수 있습니다." +followingVisibility: "팔로우의 공개 범위" +followersVisibility: "팔로워의 공개 범위" continueThread: "글타래 더 보기" deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 됩니다. 계속하시겠습니까? " incorrectPassword: "비밀번호가 올바르지 않습니다." @@ -1156,7 +1162,8 @@ privacyPolicyUrl: "개인정보 보호 정책 URL" tosAndPrivacyPolicy: "약관 및 개인정보 보호 정책" avatarDecorations: "아바타 장식" attach: "붙이기" -detach: "떼기" +detach: "빼기" +detachAll: "모두 빼기" angle: "각도" flip: "플립" showAvatarDecorations: "아바타 장식 표시" @@ -1170,6 +1177,10 @@ cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 doReaction: "리액션 추가" code: "문자열" reloadRequiredToApplySettings: "설정을 적용하려면 새로고침을 해야 합니다." +remainingN: "나머지: {n}" +overwriteContentConfirm: "현재 내용을 덮어쓰기 합니다. 계속 진행하시겠습니까?" +seasonalScreenEffect: "철에 맞는 화면으로 꾸미기" +decorate: "장식하기" _announcement: forExistingUsers: "기존 유저에게만 알림" forExistingUsersDescription: "활성화하면 이 공지사항을 게시한 시점에서 이미 가입한 유저에게만 표시합니다. 비활성화하면 게시 후에 가입한 유저에게도 표시합니다." @@ -1601,6 +1612,7 @@ _role: canHideAds: "광고 숨기기" canSearchNotes: "노트 검색 이용 가능 여부" canUseTranslator: "번역 기능의 사용" + avatarDecorationLimit: "아바타 장식의 최대 붙임 개수" _condition: isLocal: "로컬 사용자" isRemote: "리모트 사용자" @@ -1828,8 +1840,8 @@ _soundSettings: driveFileWarn: "드라이브에 있는 파일을 선택하세요." driveFileTypeWarn: "이 파일은 지원되지 않습니다." driveFileTypeWarnDescription: "오디오 파일을 선택하세요." - driveFileDurationWarn: "오디오가 너무 길어요." - driveFileDurationWarnDescription: "길은 오디오를 사용하시는 경우 미스키 사용에 지장이 갈 수도 있습니다. 그래도 괜찮습니까?" + driveFileDurationWarn: "오디오가 너무 깁니다" + driveFileDurationWarnDescription: "긴 오디오로 설정할 경우 미스키 사용에 지장이 갈 수도 있습니다. 그래도 괜찮습니까?" _ago: future: "미래" justNow: "방금 전" @@ -2037,6 +2049,7 @@ _profile: changeAvatar: "아바타 이미지 변경" changeBanner: "배너 이미지 변경" verifiedLinkDescription: "내용에 자신의 프로필로 향하는 링크가 포함된 페이지의 URL을 삽입하면 소유자 인증 마크가 표시됩니다." + avatarDecorationMax: "최대 {max}개까지 장식을 할 수 있습니다." _exportOrImport: allNotes: "모든 노트" favoritedNotes: "즐겨찾기한 노트" @@ -2158,6 +2171,7 @@ _notification: pollEnded: "투표 결과가 발표되었습니다" newNote: "새 게시물" unreadAntennaNote: "안테나 {name}" + roleAssigned: "역할이 부여 되었습니다." emptyPushNotificationMessage: "푸시 알림이 갱신되었습니다" achievementEarned: "도전 과제를 달성했습니다" testNotification: "알림 테스트" @@ -2270,9 +2284,9 @@ _moderationLogTypes: createAd: "광고 생성" deleteAd: "광고 삭제" updateAd: "광고 수정" - createAvatarDecoration: "아이콘 장식 추가" - updateAvatarDecoration: "아이콘 장식 수정" - deleteAvatarDecoration: "아이콘 장식 삭제" + createAvatarDecoration: "아바타 장식 만들기" + updateAvatarDecoration: "아바타 장식 수정" + deleteAvatarDecoration: "아바타 장식 삭제" unsetUserAvatar: "유저 아바타 제거" unsetUserBanner: "유저 배너 제거" _fileViewer: diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index c1bdbede2c..98f1693129 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -119,7 +119,6 @@ sensitive: "NSFW" add: "Toevoegen" reaction: "Reacties" reactions: "Reacties" -reactionSetting: "Reacties die in de reactie-selector worden getoond" reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen" rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen" attachCancel: "Verwijder bijlage" diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 44944f8465..195b1d0717 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -102,7 +102,6 @@ clickToShow: "Klikk for å vise" add: "Legg til" reaction: "Reaksjon" reactions: "Reaksjoner" -reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." rememberNoteVisibility: "Husk innstillingene for synlighet av Notes" attachCancel: "Fjern vedlegg" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 3a83f9b7ee..496e9bfc30 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -111,7 +111,6 @@ sensitive: "NSFW" add: "Dodaj" reaction: "Reakcja" reactions: "Reakcja" -reactionSetting: "Reakcje do pokazania w wyborniku reakcji" reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć, naciśnij „+” aby dodać" rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu" attachCancel: "Usuń załącznik" @@ -807,8 +806,6 @@ makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotyc classic: "Klasyczny" muteThread: "Wycisz wątek" unmuteThread: "Wyłącz wyciszenie wątku" -ffVisibility: "Widoczność obserwowanych/obserwujących" -ffVisibilityDescription: "Pozwala skonfigurować, kto może zobaczyć, kogo obserwujesz i kto Cię obserwuje." continueThread: "Pokaż kontynuację wątku" deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?" incorrectPassword: "Nieprawidłowe hasło." diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index b7a333f9e7..f969d711c0 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -121,7 +121,6 @@ sensitive: "Conteúdo sensível" add: "Adicionar" reaction: "Reações" reactions: "Reações" -reactionSetting: "Quais reações exibir no seletor de reações" reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar." rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas" attachCancel: "Remover anexo" @@ -859,8 +858,6 @@ makeReactionsPublicDescription: "Isto vai deixar o histórico de todas as suas r classic: "Clássico" muteThread: "Silenciar esta conversa" unmuteThread: "Desativar silêncio desta conversa" -ffVisibility: "Visibilidade de Seguidos/Seguidores" -ffVisibilityDescription: "Permite configurar quem pode ver quem lhe segue e quem você está seguindo." continueThread: "Ver mais desta conversa" deleteAccountConfirm: "Deseja realmente excluir a conta?" incorrectPassword: "Senha inválida." diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 4a90d1e006..10be9539cf 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -121,7 +121,6 @@ sensitive: "NSFW" add: "Adaugă" reaction: "Reacție" reactions: "Reacție" -reactionSetting: "Reacții care să apară in selectorul de reacții" reactionSettingDescription2: "Trage pentru a rearanja, apasă pe \"+\" pentru a adăuga." rememberNoteVisibility: "Amintește setarea de vizibilitate a notelor" attachCancel: "Înlătură atașament" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index bea08a19fd..b8095d7256 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -120,7 +120,6 @@ sensitive: "Содержимое не для всех" add: "Добавить" reaction: "Реакции" reactions: "Реакции" -reactionSetting: "Реакции, отображаемые в палитре" reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»." rememberNoteVisibility: "Запоминать видимость заметок" attachCancel: "Удалить вложение" @@ -857,8 +856,6 @@ makeReactionsPublicDescription: "Список сделанных вами реа classic: "Классика" muteThread: "Скрыть цепочку" unmuteThread: "Отменить сокрытие цепочки" -ffVisibility: "Видимость подписок и подписчиков" -ffVisibilityDescription: "Здесь можно настроить, кто будет видеть ваши подписки и подписчиков." continueThread: "Показать следующие ответы" deleteAccountConfirm: "Учётная запись будет безвозвратно удалена. Подтверждаете?" incorrectPassword: "Пароль неверен." diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 19b06b475a..e8401af1cd 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -113,7 +113,6 @@ sensitive: "NSFW" add: "Pridať" reaction: "Reakcie" reactions: "Reakcie" -reactionSetting: "Reakcie zobrazené vo výbere reakcií" reactionSettingDescription2: "Ťahaním preusporiadate, kliknutím odstránite, Stlačením \"+\" pridáte" rememberNoteVisibility: "Zapamätať nastavenia viditeľnosti poznámky" attachCancel: "Odstrániť prílohu" @@ -822,8 +821,6 @@ makeReactionsPublicDescription: "Toto spraví všetky vaše minulé reakcie vidi classic: "Klasika" muteThread: "Ztíšiť vlákno" unmuteThread: "Zrušiť stíšenie vlákna" -ffVisibility: "Viditeľnosť sledujúcich/sledovaných" -ffVisibilityDescription: "Umožňuje nastaviť kto vidí koho sledujete a kto vás sleduje." continueThread: "Zobraziť pokračovanie vlákna" deleteAccountConfirm: "Toto nezvrátiteľne vymaže váš účet. Pokračovať?" incorrectPassword: "Nesprávne heslo." diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 92678afef8..e5816ba105 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -118,7 +118,6 @@ sensitive: "Känsligt innehåll" add: "Lägg till" reaction: "Reaktioner" reactions: "Reaktioner" -reactionSetting: "Reaktioner som ska visas i reaktionsväljaren" reactionSettingDescription2: "Dra för att omordna, klicka för att radera, tryck \"+\" för att lägga till." rememberNoteVisibility: "Komihåg notvisningsinställningar" attachCancel: "Ta bort bilaga" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index d27e90b855..7cb2d68321 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -121,7 +121,6 @@ sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW add: "เพิ่ม" reaction: "รีแอคชั่น" reactions: "รีแอคชั่น" -reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น" reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม" rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต" attachCancel: "ลบไฟล์ออกที่แนบมา" @@ -870,8 +869,6 @@ makeReactionsPublicDescription: "การทำเช่นนี้จะท classic: "คลาสสิค" muteThread: "ปิดเสียงเธรด" unmuteThread: "เปิดเสียงเธรด" -ffVisibility: "การมองเห็นผู้ติดตาม/ผู้ติดตาม" -ffVisibilityDescription: "ช่วยให้คุณสามารถกำหนดค่าได้ว่าใครสามารถดูได้ว่าคุณติดตามใครและใครติดตามคุณบ้าง" continueThread: "ดูความต่อเนื่องเธรด" deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?" incorrectPassword: "รหัสผ่านไม่ถูกต้อง" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 3dd7a5b797..0793592d34 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -121,7 +121,6 @@ sensitive: "Hassas içerik" add: "Ekle" reaction: "Tepkiler" reactions: "Tepkiler" -reactionSetting: "Palette görünecek tepkiler" reactionSettingDescription2: "Sıralamak için sürükleyin, silmek için tıklayın, eklemek için \"+\" tuşuna tıklayın." rememberNoteVisibility: "Görünürlük ayarlarını hatırla" attachCancel: "Eki sil" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index f10f257fa0..9b609edebb 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -55,6 +55,7 @@ copyRSS: "Скопіювати RSS" copyUsername: "Скопіювати ім’я користувача" copyUserId: "Копіювати ID користувача" copyNoteId: "блокнот ID користувача" +copyFileId: "Скопіювати ідентифікатор файлу." searchUser: "Пошук користувачів" reply: "Відповісти" loadMore: "Показати більше" @@ -115,7 +116,6 @@ sensitive: "NSFW" add: "Додати" reaction: "Реакції" reactions: "Реакції" -reactionSetting: "Налаштування реакцій" reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати." rememberNoteVisibility: "Пам’ятати параметри видимісті" attachCancel: "Видалити вкладення" @@ -133,6 +133,7 @@ unblockConfirm: "Ви впевнені, що хочете розблокуват suspendConfirm: "Ви впевнені, що хочете призупинити цей акаунт?" unsuspendConfirm: "Ви впевнені, що хочете відновити цей акаунт?" selectList: "Виберіть список" +editList: "Редагувати список." selectChannel: "Виберіть канал" selectAntenna: "Виберіть антену" selectWidget: "Виберіть віджет" @@ -448,6 +449,7 @@ or: "або" language: "Мова" uiLanguage: "Мова інтерфейсу" aboutX: "Про {x}" +native: "місцевий" disableDrawer: "Не використовувати висувні меню" noHistory: "Історія порожня" signinHistory: "Історія входів" @@ -526,6 +528,8 @@ output: "Вихід" script: "Скрипт" disablePagesScript: "Вимкнути AiScript на Сторінках" updateRemoteUser: "Оновити інформацію про віддаленого користувача" +unsetUserAvatar: "Деактивувати піктограму." +unsetUserBanner: "Випустити прапор." deleteAllFiles: "Видалити всі файли" deleteAllFilesConfirm: "Ви дійсно хочете видалити всі файли?" removeAllFollowing: "Скасувати всі підписки" @@ -813,7 +817,6 @@ makeReactionsPublicDescription: "Це зробить список усіх ва classic: "Класичний" muteThread: "Приглушити тред" unmuteThread: "Скасувати глушіння" -ffVisibility: "Видимість підписок/підписників" continueThread: "Показати продовження треду" deleteAccountConfirm: "Це незворотно видалить ваш акаунт. Продовжити?" incorrectPassword: "Неправильний пароль." diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index 8d3e8043f3..54e20b001d 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -120,7 +120,6 @@ sensitive: "Sezuvchan" add: "Qo'shish" reaction: "Reaktsiyalar" reactions: "Reaktsiyalar" -reactionSetting: "Reaksiyalar ro'yxati" reactionSettingDescription2: "Qayta tartiblash uchun ushlab turib siljiting, oʻchirish uchun bosing, qoʻshish uchun “+” tugmasini bosing." rememberNoteVisibility: "Qaydning ko'rinish sozlamarini eslab qolish" attachCancel: "Qo'shimchani olib tashlash" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 0f60578963..c2d68d8b27 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -121,7 +121,6 @@ sensitive: "Nhạy cảm" add: "Thêm" reaction: "Biểu cảm" reactions: "Biểu cảm" -reactionSetting: "Chọn những biểu cảm hiển thị" reactionSettingDescription2: "Kéo để sắp xếp, nhấn để xóa, nhấn \"+\" để thêm." rememberNoteVisibility: "Lưu kiểu tút mặc định" attachCancel: "Gỡ tập tin đính kèm" @@ -858,8 +857,6 @@ makeReactionsPublicDescription: "Điều này sẽ hiển thị công khai danh classic: "Cổ điển" muteThread: "Không quan tâm nữa" unmuteThread: "Quan tâm tút này" -ffVisibility: "Hiển thị Theo dõi/Người theo dõi" -ffVisibilityDescription: "Quyết định ai có thể xem những người bạn theo dõi và những người theo dõi bạn." continueThread: "Tiếp tục xem chuỗi tút" deleteAccountConfirm: "Điều này sẽ khiến tài khoản bị xóa vĩnh viễn. Vẫn tiếp tục?" incorrectPassword: "Sai mật khẩu." diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 1b440284ab..bfacc03e0a 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -121,7 +121,6 @@ sensitive: "敏感内容" add: "添加" reaction: "回应" reactions: "回应" -reactionSetting: "在选择器中显示回应" reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。" rememberNoteVisibility: "保存上次设置的可见性" attachCancel: "删除附件" @@ -867,8 +866,6 @@ makeReactionsPublicDescription: "将您发表过的回应设置成公开可见 classic: "经典" muteThread: "屏蔽帖子列表" unmuteThread: "取消屏蔽帖子列表" -ffVisibility: "关注关系的可见范围" -ffVisibilityDescription: "您可以设置您的关注/关注者信息的公开范围" continueThread: "查看更多帖子" deleteAccountConfirm: "将要删除账户。是否确认?" incorrectPassword: "密码错误" @@ -1164,7 +1161,7 @@ _serverSettings: appIconUsageExample: "例如:作为书签添加到 PWA 或手机主屏幕的时候" appIconStyleRecommendation: "因为有可能会被裁切为圆形或者圆角矩形,建议使用边缘带有留白背景的图标。" appIconResolutionMustBe: "分辨率必须为 {resolution}。" - manifestJsonOverride: "覆盖 mainfest.json" + manifestJsonOverride: "覆盖 manifest.json" shortName: "简称" shortNameDescription: "如果服务器的正式名称很长,可以用简称或者別名来替代。" _accountMigration: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 7f3399ed90..d05691d42e 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -121,7 +121,12 @@ sensitive: "敏感內容" add: "新增" reaction: "反應" reactions: "反應" -reactionSetting: "在選擇器中顯示反應" +emojiPicker: "表情符號選擇器" +pinnedEmojisForReactionSettingDescription: "選擇反應時可以設定要固定顯示在頂端的表情符號" +pinnedEmojisSettingDescription: "輸入表情符號時可以設定要固定顯示在頂端的表情符號" +emojiPickerDisplay: "顯示表情符號選擇器" +overwriteFromPinnedEmojisForReaction: "從反應複寫設定" +overwriteFromPinnedEmojis: "從一般複寫設定" reactionSettingDescription2: "拖動以交換,點擊以刪除,按下「+」以新增。" rememberNoteVisibility: "記住貼文可見性" attachCancel: "移除附件" @@ -261,7 +266,7 @@ removed: "已刪除" removeAreYouSure: "確定要刪掉「{x}」嗎?" deleteAreYouSure: "確定要刪掉「{x}」嗎?" resetAreYouSure: "確定要重設嗎?" -areYouSure: "您確定要移除所有裝飾嗎?" +areYouSure: "是否確定?" saved: "已儲存" messaging: "聊天" upload: "上傳" @@ -782,7 +787,7 @@ receiveAnnouncementFromInstance: "接收由本實例發出的電郵通知" emailNotification: "郵件通知" publish: "發布" inChannelSearch: "頻道内搜尋" -useReactionPickerForContextMenu: "點擊右鍵開啟反應工具欄" +useReactionPickerForContextMenu: "點擊右鍵開啟反應選擇器" typingUsers: "{users}輸入中" jumpToSpecifiedDate: "跳轉到特定日期" showingPastTimeline: "顯示過往的時間軸" @@ -876,8 +881,8 @@ makeReactionsPublicDescription: "將您做過的反應設為公開可見。" classic: "經典" muteThread: "將貼文串設為靜音" unmuteThread: "將貼文串的靜音解除" -ffVisibility: "連繫的可見性" -ffVisibilityDescription: "您可以設定追隨或追隨者資訊的公開範圍" +followingVisibility: "追隨中的可見性" +followersVisibility: "追隨者的可見性" continueThread: "查看更多貼文" deleteAccountConfirm: "將要刪除帳戶。是否確定?" incorrectPassword: "密碼錯誤。" @@ -1173,6 +1178,9 @@ doReaction: "做出反應" code: "程式碼" reloadRequiredToApplySettings: "需要重新載入頁面設定才能生效。" remainingN: "剩餘:{n}" +overwriteContentConfirm: "確定要覆蓋目前的內容嗎?" +seasonalScreenEffect: "隨季節變換畫面的呈現" +decorate: "設置頭像裝飾" _announcement: forExistingUsers: "僅限既有的使用者" forExistingUsersDescription: "啟用代表僅向現存使用者顯示;停用代表張貼後註冊的新使用者也會看到。" @@ -1209,7 +1217,7 @@ _initialTutorial: skipAreYouSure: "結束教學模式?" _landing: title: "歡迎使用本教學課程" - description: "在這裡您可以查看Misskey的基本使用方法和功能。" + description: "在這裡您可以查看 Misskey 的基本使用方法和功能。" _note: title: "什麼是貼文?" description: "在Misskey上發布的內容稱為「貼文」。貼文在時間軸上按時間順序排列,並即時更新。" @@ -2041,7 +2049,7 @@ _profile: changeAvatar: "更換大頭貼" changeBanner: "變更橫幅圖像" verifiedLinkDescription: "如果輸入包含您個人資料的網站 URL,欄位旁邊將出現驗證圖示。" - avatarDecorationMax: "最多可以設置{max}個裝飾。" + avatarDecorationMax: "最多可以設置 {max} 個裝飾。" _exportOrImport: allNotes: "所有貼文" favoritedNotes: "「我的最愛」貼文" @@ -2163,6 +2171,7 @@ _notification: pollEnded: "問卷調查已產生結果" newNote: "新的貼文" unreadAntennaNote: "天線 {name}" + roleAssigned: "已授予角色" emptyPushNotificationMessage: "推送通知已更新" achievementEarned: "獲得成就" testNotification: "通知測試" diff --git a/package.json b/package.json index 3057c5d804..d39b800a18 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "misskey", - "version": "2023.12.0-beta.4", + "version": "2023.12.0", "codename": "nasubi", "repository": { "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@8.10.5", + "packageManager": "pnpm@8.12.1", "workspaces": [ "packages/frontend", "packages/backend", @@ -46,10 +46,10 @@ }, "dependencies": { "execa": "8.0.1", - "cssnano": "6.0.1", + "cssnano": "6.0.2", "js-yaml": "4.1.0", "postcss": "8.4.32", - "terser": "5.24.0", + "terser": "5.26.0", "typescript": "5.3.3" }, "devDependencies": { @@ -57,7 +57,7 @@ "@typescript-eslint/parser": "6.14.0", "cross-env": "7.0.3", "cypress": "13.6.1", - "eslint": "8.55.0", + "eslint": "8.56.0", "start-server-and-test": "2.0.3", "ncp": "2.0.0" }, diff --git a/packages/backend/migration/1702718871541-ffVisibility.js b/packages/backend/migration/1702718871541-ffVisibility.js new file mode 100644 index 0000000000..24b1873134 --- /dev/null +++ b/packages/backend/migration/1702718871541-ffVisibility.js @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class ffVisibility1702718871541 { + constructor() { + this.name = 'ffVisibility1702718871541'; + } + async up(queryRunner) { + await queryRunner.query(`CREATE TYPE "public"."user_profile_followingvisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`CREATE TYPE "public"."user_profile_followersVisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "followingVisibility" "public"."user_profile_followingvisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "followersVisibility" "public"."user_profile_followersVisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`UPDATE "user_profile" SET "followingVisibility" = "ffVisibility"`); + await queryRunner.query(`UPDATE "user_profile" SET "followersVisibility" = "ffVisibility"`); + await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followersVisibility_enum")`); + await queryRunner.query(`DROP CAST ("public"."user_profile_ffvisibility_enum" AS "public"."user_profile_followingvisibility_enum")`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "ffVisibility"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_ffvisibility_enum"`); + } + async down(queryRunner) { + await queryRunner.query(`CREATE TYPE "public"."user_profile_ffvisibility_enum" AS ENUM('public', 'followers', 'private')`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD "ffVisibility" "public"."user_profile_ffvisibility_enum" NOT NULL DEFAULT 'public'`); + await queryRunner.query(`CREATE CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum") WITH INOUT AS ASSIGNMENT`); + await queryRunner.query(`UPDATE "user_profile" SET ffVisibility = "user_profile"."followingVisibility"`); + await queryRunner.query(`DROP CAST ("public"."user_profile_followingvisibility_enum" AS "public"."user_profile_ffvisibility_enum")`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followersVisibility"`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "followingVisibility"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_followersVisibility_enum"`); + await queryRunner.query(`DROP TYPE "public"."user_profile_followingvisibility_enum"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 504cc882ff..6848d88e03 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "engines": { - "node": ">=18.16.0" + "node": ">=20.10.0" }, "scripts": { "start": "node ./built/boot/entry.js", @@ -65,7 +65,7 @@ "@bull-board/api": "5.10.2", "@bull-board/fastify": "5.10.2", "@bull-board/ui": "5.10.2", - "@discordapp/twemoji": "14.1.2", + "@discordapp/twemoji": "15.0.2", "@fastify/accepts": "4.3.0", "@fastify/cookie": "9.2.0", "@fastify/cors": "8.4.2", @@ -83,6 +83,7 @@ "@smithy/node-http-handler": "2.1.10", "@swc/cli": "0.1.63", "@swc/core": "1.3.100", + "@twemoji/parser": "15.0.0", "accepts": "1.3.8", "ajv": "8.12.0", "archiver": "6.0.1", @@ -90,7 +91,7 @@ "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.2", - "bullmq": "4.15.3", + "bullmq": "4.15.4", "cacheable-lookup": "7.0.0", "cbor": "9.0.1", "chalk": "5.3.0", @@ -107,7 +108,7 @@ "file-type": "18.7.0", "fluent-ffmpeg": "2.1.2", "form-data": "4.0.0", - "got": "13.0.0", + "got": "14.0.0", "happy-dom": "10.0.3", "hpagent": "1.2.0", "http-link-header": "1.1.1", @@ -121,8 +122,8 @@ "jsonld": "8.3.2", "jsrsasign": "10.9.0", "meilisearch": "0.36.0", - "mfm-js": "0.23.3", - "microformats-parser": "1.5.2", + "mfm-js": "0.24.0", + "microformats-parser": "2.0.2", "mime-types": "2.1.35", "misskey-js": "workspace:*", "ms": "3.0.0-canary.1", @@ -166,7 +167,6 @@ "tmp": "0.2.1", "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", - "twemoji-parser": "14.0.0", "typeorm": "0.3.17", "typescript": "5.3.3", "ulid": "2.3.0", @@ -195,7 +195,7 @@ "@types/jsrsasign": "10.5.12", "@types/mime-types": "2.1.4", "@types/ms": "0.7.34", - "@types/node": "20.10.4", + "@types/node": "20.10.5", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.14", "@types/oauth": "0.9.4", @@ -222,8 +222,8 @@ "@typescript-eslint/parser": "6.14.0", "aws-sdk-client-mock": "3.0.0", "cross-env": "7.0.3", - "eslint": "8.55.0", - "eslint-plugin-import": "2.29.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1", "execa": "8.0.1", "jest": "29.7.0", "jest-mock": "29.7.0", diff --git a/packages/backend/src/core/FeaturedService.ts b/packages/backend/src/core/FeaturedService.ts index d970ffa43b..595383c82c 100644 --- a/packages/backend/src/core/FeaturedService.ts +++ b/packages/backend/src/core/FeaturedService.ts @@ -77,6 +77,17 @@ export class FeaturedService { return Array.from(ranking.keys()); } + @bindThis + private async removeFromRanking(name: string, windowRange: number, element: string): Promise<void> { + const currentWindow = this.getCurrentWindow(windowRange); + const previousWindow = currentWindow - 1; + + const redisPipeline = this.redisClient.pipeline(); + redisPipeline.zrem(`${name}:${currentWindow}`, element); + redisPipeline.zrem(`${name}:${previousWindow}`, element); + await redisPipeline.exec(); + } + @bindThis public updateGlobalNotesRanking(noteId: MiNote['id'], score = 1): Promise<void> { return this.updateRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, noteId, score); @@ -126,4 +137,9 @@ export class FeaturedService { public getHashtagsRanking(threshold: number): Promise<string[]> { return this.getRankingOf('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, threshold); } + + @bindThis + public removeHashtagsFromRanking(hashtag: string): Promise<void> { + return this.removeFromRanking('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, hashtag); + } } diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index 508544dc07..80e8020961 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -11,6 +11,7 @@ import { MiMeta } from '@/models/Meta.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import { FeaturedService } from '@/core/FeaturedService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() @@ -25,6 +26,7 @@ export class MetaService implements OnApplicationShutdown { @Inject(DI.db) private db: DataSource, + private featuredService: FeaturedService, private globalEventService: GlobalEventService, ) { //this.onMessage = this.onMessage.bind(this); @@ -95,6 +97,8 @@ export class MetaService implements OnApplicationShutdown { @bindThis public async update(data: Partial<MiMeta>): Promise<MiMeta> { + let before: MiMeta | undefined; + const updated = await this.db.transaction(async transactionalEntityManager => { const metas = await transactionalEntityManager.find(MiMeta, { order: { @@ -102,10 +106,10 @@ export class MetaService implements OnApplicationShutdown { }, }); - const meta = metas[0]; + before = metas[0]; - if (meta) { - await transactionalEntityManager.update(MiMeta, meta.id, data); + if (before) { + await transactionalEntityManager.update(MiMeta, before.id, data); const metas = await transactionalEntityManager.find(MiMeta, { order: { @@ -119,6 +123,21 @@ export class MetaService implements OnApplicationShutdown { } }); + if (data.hiddenTags) { + process.nextTick(() => { + const hiddenTags = new Set<string>(data.hiddenTags); + if (before) { + for (const previousHiddenTag of before.hiddenTags) { + hiddenTags.delete(previousHiddenTag); + } + } + + for (const hiddenTag of hiddenTags) { + this.featuredService.removeHashtagsFromRanking(hiddenTag); + } + }); + } + this.globalEventService.publishInternalEvent('metaUpdated', updated); return updated; diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 0e7c73b636..f1b53ffd55 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -262,7 +262,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // Check blocking - if (data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)) { + if (this.isQuote(data)) { if (data.renote.userHost === null) { if (data.renote.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id); @@ -590,7 +590,7 @@ export class NoteCreateService implements OnApplicationShutdown { // If it is renote if (data.renote) { - const type = data.text ? 'quote' : 'renote'; + const type = this.isQuote(data) ? 'quote' : 'renote'; // Notify if (data.renote.userHost === null) { @@ -697,6 +697,12 @@ export class NoteCreateService implements OnApplicationShutdown { return false; } + @bindThis + private isQuote(note: Option): note is Option & { renote: MiNote } { + // sync with misc/is-quote.ts + return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll); + } + @bindThis private incRenoteCount(renote: MiNote) { this.notesRepository.createQueryBuilder().update() @@ -762,7 +768,7 @@ export class NoteCreateService implements OnApplicationShutdown { private async renderNoteOrRenoteActivity(data: Option, note: MiNote) { if (data.localOnly) return null; - const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0) + const content = data.renote && !this.isQuote(data) ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 6b8fe191a9..7a7ee1a13a 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -6,7 +6,14 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { In } from 'typeorm'; -import type { MiRole, MiRoleAssignment, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js'; +import { ModuleRef } from '@nestjs/core'; +import type { + MiRole, + MiRoleAssignment, + RoleAssignmentsRepository, + RolesRepository, + UsersRepository, +} from '@/models/_.js'; import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js'; import type { MiUser } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; @@ -16,12 +23,13 @@ import { CacheService } from '@/core/CacheService.js'; import type { RoleCondFormulaValue } from '@/models/Role.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { IdService } from '@/core/IdService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; import type { Packed } from '@/misc/json-schema.js'; import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; -import type { OnApplicationShutdown } from '@nestjs/common'; +import { NotificationService } from '@/core/NotificationService.js'; +import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; export type RolePolicies = { gtlAvailable: boolean; @@ -84,14 +92,17 @@ export const DEFAULT_POLICIES: RolePolicies = { }; @Injectable() -export class RoleService implements OnApplicationShutdown { +export class RoleService implements OnApplicationShutdown, OnModuleInit { private rolesCache: MemorySingleCache<MiRole[]>; private roleAssignmentByUserIdCache: MemoryKVCache<MiRoleAssignment[]>; + private notificationService: NotificationService; public static AlreadyAssignedError = class extends Error {}; public static NotAssignedError = class extends Error {}; constructor( + private moduleRef: ModuleRef, + @Inject(DI.redis) private redisClient: Redis.Redis, @@ -126,6 +137,10 @@ export class RoleService implements OnApplicationShutdown { this.redisForSub.on('message', this.onMessage); } + async onModuleInit() { + this.notificationService = this.moduleRef.get(NotificationService.name); + } + @bindThis private async onMessage(_: string, data: string): Promise<void> { const obj = JSON.parse(data); @@ -436,6 +451,12 @@ export class RoleService implements OnApplicationShutdown { this.globalEventService.publishInternalEvent('userRoleAssigned', created); + if (role.isPublic) { + this.notificationService.createNotification(userId, 'roleAssigned', { + roleId: roleId, + }); + } + if (moderator) { const user = await this.usersRepository.findOneByOrFail({ id: userId }); this.moderationLogService.log(moderator, 'assignRole', { diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index 702c731fc3..b6e4e1e884 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -3,30 +3,34 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; import * as Redis from 'ioredis'; +import { ModuleRef } from '@nestjs/core'; import type { UserListMembershipsRepository } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; import type { MiUserList } from '@/models/UserList.js'; import type { MiUserListMembership } from '@/models/UserListMembership.js'; import { IdService } from '@/core/IdService.js'; +import type { GlobalEvents } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { bindThis } from '@/decorators.js'; -import { RoleService } from '@/core/RoleService.js'; import { QueueService } from '@/core/QueueService.js'; import { RedisKVCache } from '@/misc/cache.js'; -import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import { RoleService } from '@/core/RoleService.js'; @Injectable() -export class UserListService implements OnApplicationShutdown { +export class UserListService implements OnApplicationShutdown, OnModuleInit { public static TooManyUsersError = class extends Error {}; public membersCache: RedisKVCache<Set<string>>; + private roleService: RoleService; constructor( + private moduleRef: ModuleRef, + @Inject(DI.redis) private redisClient: Redis.Redis, @@ -38,7 +42,6 @@ export class UserListService implements OnApplicationShutdown { private userEntityService: UserEntityService, private idService: IdService, - private roleService: RoleService, private globalEventService: GlobalEventService, private proxyAccountService: ProxyAccountService, private queueService: QueueService, @@ -54,6 +57,10 @@ export class UserListService implements OnApplicationShutdown { this.redisForSub.on('message', this.onMessage); } + async onModuleInit() { + this.roleService = this.moduleRef.get(RoleService.name); + } + @bindThis private async onMessage(_: string, data: string): Promise<void> { const obj = JSON.parse(data); diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index e723ea5a55..704081ed00 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -15,8 +15,8 @@ import type { Packed } from '@/misc/json-schema.js'; import { bindThis } from '@/decorators.js'; import { isNotNull } from '@/misc/is-not-null.js'; import { FilterUnionByProperty, notificationTypes } from '@/types.js'; +import { RoleEntityService } from './RoleEntityService.js'; import type { OnModuleInit } from '@nestjs/common'; -import type { CustomEmojiService } from '../CustomEmojiService.js'; import type { UserEntityService } from './UserEntityService.js'; import type { NoteEntityService } from './NoteEntityService.js'; @@ -27,7 +27,7 @@ const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 're export class NotificationEntityService implements OnModuleInit { private userEntityService: UserEntityService; private noteEntityService: NoteEntityService; - private customEmojiService: CustomEmojiService; + private roleEntityService: RoleEntityService; constructor( private moduleRef: ModuleRef, @@ -43,14 +43,13 @@ export class NotificationEntityService implements OnModuleInit { //private userEntityService: UserEntityService, //private noteEntityService: NoteEntityService, - //private customEmojiService: CustomEmojiService, ) { } onModuleInit() { this.userEntityService = this.moduleRef.get('UserEntityService'); this.noteEntityService = this.moduleRef.get('NoteEntityService'); - this.customEmojiService = this.moduleRef.get('CustomEmojiService'); + this.roleEntityService = this.moduleRef.get('RoleEntityService'); } @bindThis @@ -81,6 +80,7 @@ export class NotificationEntityService implements OnModuleInit { detail: false, }) ) : undefined; + const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; return await awaitAll({ id: notification.id, @@ -92,6 +92,9 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'reaction' ? { reaction: notification.reaction, } : {}), + ...(notification.type === 'roleAssigned' ? { + role: role, + } : {}), ...(notification.type === 'achievementEarned' ? { achievement: notification.achievement, } : {}), @@ -216,6 +219,8 @@ export class NotificationEntityService implements OnModuleInit { }); } + const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -226,6 +231,9 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'reaction' ? { reaction: notification.reaction, } : {}), + ...(notification.type === 'roleAssigned' ? { + role: role, + } : {}), ...(notification.type === 'achievementEarned' ? { achievement: notification.achievement, } : {}), diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 3a5dc0d017..28653706cf 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -332,13 +332,13 @@ export class UserEntityService implements OnModuleInit { const profile = opts.detail ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null; const followingCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followingCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : + (profile.followingVisibility === 'public') || isMe ? user.followingCount : + (profile.followingVisibility === 'followers') && (relation && relation.isFollowing) ? user.followingCount : null; const followersCount = profile == null ? null : - (profile.ffVisibility === 'public') || isMe ? user.followersCount : - (profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : + (profile.followersVisibility === 'public') || isMe ? user.followersCount : + (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : null; const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null; @@ -418,7 +418,8 @@ export class UserEntityService implements OnModuleInit { pinnedPageId: profile!.pinnedPageId, pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null, publicReactions: profile!.publicReactions, - ffVisibility: profile!.ffVisibility, + followersVisibility: profile!.followersVisibility, + followingVisibility: profile!.followingVisibility, twoFactorEnabled: profile!.twoFactorEnabled, usePasswordLessLogin: profile!.usePasswordLessLogin, securityKeys: profile!.twoFactorEnabled diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts index 24e4092aeb..37ecde6eb1 100644 --- a/packages/backend/src/misc/emoji-regex.ts +++ b/packages/backend/src/misc/emoji-regex.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -// taken from twemoji-parser/dist/lib/regex.js -const twemojiRegex = /(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef0-\udef6]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedd-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude74\ude78-\ude7c\ude80-\ude86\ude90-\udeac\udeb0-\udeba\udec0-\udec2\uded0-\uded9\udee0-\udee7]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g; +// taken from @twemoji/parser/dist/lib/regex.js +const twemojiRegex = /(?:\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83d\udc68\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc68\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc68\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc68\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffc-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffd-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb\udffc\udffe\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffd\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc68\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83d\udc69\ud83c[\udffb-\udfff]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c[\udffb-\udffe]|\ud83d\udc69\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83d\udc69\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udffb\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffc-\udfff]|\ud83e\uddd1\ud83c\udffb\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffd-\udfff]|\ud83e\uddd1\ud83c\udffc\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\uddd1\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffd\udfff]|\ud83e\uddd1\ud83c\udffe\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83e\uddd1\ud83c\udfff\u200d\u2764\ufe0f\u200d\ud83e\uddd1\ud83c[\udffb-\udffe]|\ud83e\uddd1\ud83c\udfff\u200d\ud83e\udd1d\u200d\ud83e\uddd1\ud83c[\udffb-\udfff]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83e\udef1\ud83c\udffb\u200d\ud83e\udef2\ud83c[\udffc-\udfff]|\ud83e\udef1\ud83c\udffc\u200d\ud83e\udef2\ud83c[\udffb\udffd-\udfff]|\ud83e\udef1\ud83c\udffd\u200d\ud83e\udef2\ud83c[\udffb\udffc\udffe\udfff]|\ud83e\udef1\ud83c\udffe\u200d\ud83e\udef2\ud83c[\udffb-\udffd\udfff]|\ud83e\udef1\ud83c\udfff\u200d\ud83e\udef2\ud83c[\udffb-\udffe]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1|\ud83d\udc6b\ud83c[\udffb-\udfff]|\ud83d\udc6c\ud83c[\udffb-\udfff]|\ud83d\udc6d\ud83c[\udffb-\udfff]|\ud83d\udc8f\ud83c[\udffb-\udfff]|\ud83d\udc91\ud83c[\udffb-\udfff]|\ud83e\udd1d\ud83c[\udffb-\udfff]|\ud83d[\udc6b-\udc6d\udc8f\udc91]|\ud83e\udd1d)|(?:\ud83d[\udc68\udc69]|\ud83e\uddd1)(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf7c\udf84\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddaf-\uddb3\uddbc\uddbd])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc70\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddcd-\uddcf\uddd4\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83d\ude36\u200d\ud83c\udf2b\ufe0f|\u2764\ufe0f\u200d\ud83d\udd25|\u2764\ufe0f\u200d\ud83e\ude79|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc15\u200d\ud83e\uddba|\ud83d\udc3b\u200d\u2744\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83d\ude2e\u200d\ud83d\udca8|\ud83d\ude35\u200d\ud83d\udcab|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f|\ud83d\udc08\u200d\u2b1b|\ud83d\udc26\u200d\u2b1b)|[#*0-9]\ufe0f?\u20e3|(?:[©®\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|\ud83e\udef0|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd0c\udd0f\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\udd77\uddb5\uddb6\uddb8\uddb9\uddbb\uddcd-\uddcf\uddd1-\udddd\udec3-\udec5\udef1-\udef8]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udc8e\udc90\udc92-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\uded5-\uded7\udedc-\udedf\udeeb\udeec\udef4-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0d\udd0e\udd10-\udd17\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd3f-\udd45\udd47-\udd76\udd78-\uddb4\uddb7\uddba\uddbc-\uddcc\uddd0\uddde-\uddff\ude70-\ude7c\ude80-\ude88\ude90-\udebd\udebf-\udec2\udece-\udedb\udee0-\udee8]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f/g; export const emojiRegex = new RegExp(`(${twemojiRegex.source})`); diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts index 059f6a4b5f..db72d1d57a 100644 --- a/packages/backend/src/misc/is-quote.ts +++ b/packages/backend/src/misc/is-quote.ts @@ -7,5 +7,6 @@ import type { MiNote } from '@/models/Note.js'; // eslint-disable-next-line import/no-default-export export default function(note: MiNote): boolean { + // sync with NoteCreateService.isQuote return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0)); } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index 49f35b9b74..176978d35f 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -38,6 +38,7 @@ import { packedFlashSchema } from '@/models/json-schema/flash.js'; import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; import { packedSigninSchema } from '@/models/json-schema/signin.js'; import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js'; +import { packedAdSchema } from '@/models/json-schema/ad.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -49,6 +50,7 @@ export const refs = { User: packedUserSchema, UserList: packedUserListSchema, + Ad: packedAdSchema, Announcement: packedAnnouncementSchema, App: packedAppSchema, Note: packedNoteSchema, diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index 1d5fc124e2..3bc2edaa0d 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -3,11 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { notificationTypes } from '@/types.js'; import { MiUser } from './User.js'; import { MiNote } from './Note.js'; -import { MiFollowRequest } from './FollowRequest.js'; import { MiAccessToken } from './AccessToken.js'; +import { MiRole } from './Role.js'; export type MiNotification = { type: 'note'; @@ -68,6 +67,11 @@ export type MiNotification = { id: string; createdAt: string; notifierId: MiUser['id']; +} | { + type: 'roleAssigned'; + id: string; + createdAt: string; + roleId: MiRole['id']; } | { type: 'achievementEarned'; id: string; diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 6659a01412..328dbeaa1c 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -4,7 +4,7 @@ */ import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; -import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from '@/types.js'; +import { obsoleteNotificationTypes, followingVisibilities, followersVisibilities, notificationTypes } from '@/types.js'; import { id } from './util/id.js'; import { MiUser } from './User.js'; import { MiPage } from './Page.js'; @@ -94,10 +94,16 @@ export class MiUserProfile { public publicReactions: boolean; @Column('enum', { - enum: ffVisibility, + enum: followingVisibilities, default: 'public', }) - public ffVisibility: typeof ffVisibility[number]; + public followingVisibility: typeof followingVisibilities[number]; + + @Column('enum', { + enum: followersVisibilities, + default: 'public', + }) + public followersVisibility: typeof followersVisibilities[number]; @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/models/json-schema/ad.ts b/packages/backend/src/models/json-schema/ad.ts new file mode 100644 index 0000000000..649ffcd4dc --- /dev/null +++ b/packages/backend/src/models/json-schema/ad.ts @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const packedAdSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, + nullable: false, + format: 'id', + example: 'xxxxxxxxxx', + }, + expiresAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + startsAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + place: { + type: 'string', + optional: false, + nullable: false, + }, + priority: { + type: 'string', + optional: false, + nullable: false, + }, + ratio: { + type: 'number', + optional: false, + nullable: false, + }, + url: { + type: 'string', + optional: false, + nullable: false, + }, + imageUrl: { + type: 'string', + optional: false, + nullable: false, + }, + memo: { + type: 'string', + optional: false, + nullable: false, + }, + dayOfWeek: { + type: 'integer', + optional: false, + nullable: false, + }, + }, +} as const; diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 77a61c2da3..cfc9879f29 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -74,6 +74,14 @@ export const packedUserLiteSchema = { format: 'url', nullable: false, optional: false, }, + offsetX: { + type: 'number', + nullable: false, optional: true, + }, + offsetY: { + type: 'number', + nullable: false, optional: true, + }, }, }, }, @@ -312,7 +320,12 @@ export const packedUserDetailedNotMeOnlySchema = { type: 'boolean', nullable: false, optional: false, }, - ffVisibility: { + followingVisibility: { + type: 'string', + nullable: false, optional: false, + enum: ['public', 'followers', 'private'], + }, + followersVisibility: { type: 'string', nullable: false, optional: false, enum: ['public', 'followers', 'private'], @@ -550,9 +563,7 @@ export const packedMeDetailedOnlySchema = { mention: notificationRecieveConfig, reaction: notificationRecieveConfig, pollEnded: notificationRecieveConfig, - achievementEarned: notificationRecieveConfig, receiveFollowRequest: notificationRecieveConfig, - followRequestAccepted: notificationRecieveConfig, }, }, emailNotificationTypes: { diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index e239b6fdec..eb76fce1dd 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -156,8 +156,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.systemQueueWorker .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => systemLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => systemLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => systemLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => systemLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -194,8 +194,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.dbQueueWorker .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => dbLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => dbLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => dbLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => dbLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -218,8 +218,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.deliverQueueWorker .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => deliverLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => deliverLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => deliverLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => deliverLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -242,8 +242,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.inboxQueueWorker .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) - .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => inboxLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => inboxLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => inboxLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => inboxLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -266,8 +266,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.webhookDeliverQueueWorker .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => webhookLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => webhookLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => webhookLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => webhookLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -295,8 +295,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.relationshipQueueWorker .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => relationshipLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => relationshipLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => relationshipLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => relationshipLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => relationshipLogger.warn(`stalled id=${jobId}`)); //#endregion @@ -318,8 +318,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.objectStorageQueueWorker .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => objectStorageLogger.error(`error ${err}`, { e: renderError(err) })) + .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => objectStorageLogger.error(`error ${err.stack}`, { e: renderError(err) })) .on('stalled', (jobId) => objectStorageLogger.warn(`stalled id=${jobId}`)); //#endregion diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 78d2daa403..68e426b5bc 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -138,7 +138,7 @@ export class ActivityPubServerService { return; } - const algo = match[1]; + const algo = match[1].toUpperCase(); const digestValue = match[2]; if (algo !== 'SHA-256') { @@ -195,11 +195,11 @@ export class ActivityPubServerService { //#region Check ff visibility const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followersVisibility === 'private') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followersVisibility === 'followers') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; @@ -287,11 +287,11 @@ export class ActivityPubServerService { //#region Check ff visibility const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followingVisibility === 'private') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followingVisibility === 'followers') { reply.code(403); reply.header('Cache-Control', 'public, max-age=30'); return; @@ -493,8 +493,7 @@ export class ActivityPubServerService { @bindThis public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - // addConstraintStrategy の型定義がおかしいため - (fastify.addConstraintStrategy as any)({ + fastify.addConstraintStrategy({ name: 'apOrHtml', storage() { const store = {} as any; diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 247ef73de8..c19846ee81 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -61,6 +61,9 @@ export class FileServerService { public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.addHook('onRequest', (request, reply, done) => { reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\''); + if (process.env.NODE_ENV === 'development') { + reply.header('Access-Control-Allow-Origin', '*'); + } done(); }); diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index be4fc82f0c..484118cd46 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -13,6 +13,8 @@ import { AbuseUserReportEntityService } from '@/core/entities/AbuseUserReportEnt export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index 070e88f6f3..07f24d2995 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -15,6 +15,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + res: { type: 'object', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 60e928ccbe..86f4b0709b 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -14,6 +14,8 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts index 686341582b..bc292fd53a 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts @@ -13,6 +13,8 @@ import { ApiError } from '@/server/api/error.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireAdmin: true, @@ -23,6 +25,11 @@ export const meta = { id: 'cb865949-8af5-4062-a88c-ef55e8786d1d', }, }, + res: { + type: 'object', + optional: false, nullable: false, + ref: 'User', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index 17f792639b..087ae4befc 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -13,8 +13,16 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, + res: { + type: 'object', + optional: false, + nullable: false, + ref: 'Ad', + }, } as const; export const paramDef = { @@ -61,7 +69,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- ad: ad, }); - return ad; + return { + id: ad.id, + expiresAt: ad.expiresAt.toISOString(), + startsAt: ad.startsAt.toISOString(), + dayOfWeek: ad.dayOfWeek, + url: ad.url, + imageUrl: ad.imageUrl, + priority: ad.priority, + ratio: ad.ratio, + place: ad.place, + memo: ad.memo, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index 8097133a4c..ba655a6aa3 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 8cdeaae179..12528917dc 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -12,8 +12,21 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, + res: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + ref: 'Ad', + }, + }, } as const; export const paramDef = { @@ -44,7 +57,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- } const ads = await query.limit(ps.limit).getMany(); - return ads; + return ads.map(ad => ({ + id: ad.id, + expiresAt: ad.expiresAt.toISOString(), + startsAt: ad.startsAt.toISOString(), + dayOfWeek: ad.dayOfWeek, + url: ad.url, + imageUrl: ad.imageUrl, + memo: ad.memo, + place: ad.place, + priority: ad.priority, + ratio: ad.ratio, + })); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index d065f9ec50..b83c163004 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 69c31a05eb..fb432336e4 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -10,6 +10,8 @@ import { AnnouncementService } from '@/core/AnnouncementService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index 80ec281253..e84e63c666 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 9630299a6e..e98ef0b169 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -14,6 +14,8 @@ import { IdService } from '@/core/IdService.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index 717866aead..e2ec344899 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts index ec143fcb53..158435ed21 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts @@ -10,6 +10,8 @@ import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts index 6f1f386871..06083cc180 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', errors: { diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts index d9c669377d..49a8718bce 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts @@ -15,6 +15,8 @@ import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts index 5ea9a40762..3d8f3d63de 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageAvatarDecorations', diff --git a/packages/backend/src/server/api/endpoints/admin/delete-account.ts b/packages/backend/src/server/api/endpoints/admin/delete-account.ts index 9ef09b172e..adc446d14b 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-account.ts @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index e47ecd81cf..1fdbbfb12e 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts index 8af44029c5..3f23319a5f 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts @@ -10,6 +10,8 @@ import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index 75d689966f..fd8fa46a47 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index ac8a70e3da..816bbfbc45 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -13,6 +13,8 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index 4e5320007e..61cb843558 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -14,6 +14,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index 66ee4cab3b..5333adb624 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 7f4474419c..74da1a3688 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -14,6 +14,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', @@ -29,6 +31,8 @@ export const meta = { id: 'f7a3462c-4e6e-4069-8421-b9bd4f4c3975', }, }, + + ref: 'EmojiDetailed', } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 5b41dfb514..87260faa43 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index e6c1bf317f..c483794a40 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index 58aa0b9950..e15af7717b 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts index 208616c0ac..b75616f3cc 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts @@ -8,7 +8,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueueService } from '@/core/QueueService.js'; export const meta = { - secure: true, + kind: 'write:admin', requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index 855ab8cd24..a383e09338 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -15,6 +15,8 @@ import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 8fba829c5e..18933cc964 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -15,6 +15,8 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index a5dd6d5e3a..8e92db1daf 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 515053f57b..5a06b5b32f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index 8e834ad1dd..b3e9c6df13 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts index 2dc9595a7e..c59d13ad16 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts @@ -10,6 +10,8 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index 7512e88c05..104b163224 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireRolePolicy: 'canManageCustomEmojis', diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index b63f01bec3..b81297413c 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 6dbfe3c4f5..6cc4e3087f 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index 36ea390e45..18884dfca6 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -12,6 +12,8 @@ import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index 357bf83e87..4232d42ba5 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -14,6 +14,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index 4bd9e7de7f..b81d9857d7 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -12,7 +12,19 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin', + tags: ['admin'], + res: { + type: 'array', + items: { + type: 'object', + properties: { + tablename: { type: 'string' }, + indexname: { type: 'string' }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index f953b889a3..c104f653ef 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -12,6 +12,8 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin', + tags: ['admin'], res: { diff --git a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts index 6afa824703..76c32f2a9f 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts @@ -12,8 +12,29 @@ import { IdService } from '@/core/IdService.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, + res: { + type: 'array', + optional: false, + nullable: false, + items: { + type: 'object', + optional: false, + nullable: false, + properties: { + ip: { type: 'string' }, + createdAt: { + type: 'string', + optional: false, + nullable: false, + format: 'date-time', + }, + }, + }, + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts index c6ee45735e..96de772edc 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/invite/list.ts b/packages/backend/src/server/api/endpoints/admin/invite/list.ts index ff57940d48..3b7dc72e11 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/list.ts @@ -12,6 +12,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index ec39b1b8fe..9fe23c7ace 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -13,6 +13,8 @@ import { DEFAULT_POLICIES } from '@/core/RoleService.js'; export const meta = { tags: ['meta'], + kind: 'read:admin', + requireCredential: true, requireAdmin: true, diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index 4061e1b5df..e2befec50f 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -13,6 +13,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts index c9142e9885..1d565e8f24 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts @@ -11,6 +11,8 @@ import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 1515ae4c74..30005fc666 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -11,6 +11,8 @@ import type { DeliverQueue } from '@/core/QueueModule.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index febe0d07c6..aa8b6edee5 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -11,6 +11,8 @@ import type { InboxQueue } from '@/core/QueueModule.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts index 0cba5b4e25..8f46cd6375 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts @@ -11,6 +11,8 @@ import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index 2f09e70b62..bb6c340ada 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -10,6 +10,8 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index b675db2b89..53b83560cf 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -12,6 +12,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/relays/list.ts b/packages/backend/src/server/api/endpoints/admin/relays/list.ts index 0633c57ed5..35c8e05487 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/list.ts @@ -10,6 +10,8 @@ import { RelayService } from '@/core/RelayService.js'; export const meta = { tags: ['admin'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts index 661b4243c4..fdc53cb708 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts @@ -10,6 +10,8 @@ import { RelayService } from '@/core/RelayService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 13e9c30ed8..73bbd1f091 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -14,6 +14,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index fb5ac7a335..fb26c82a9d 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -15,6 +15,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts index a0f3edd867..bbd4cfabbe 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts index fb53815333..ac6085d921 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts @@ -11,6 +11,8 @@ import { RoleService } from '@/core/RoleService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts index 7b989050eb..f60d6754a5 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/list.ts b/packages/backend/src/server/api/endpoints/admin/roles/list.ts index 71b8e44e77..30917ce984 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/list.ts @@ -12,6 +12,8 @@ import { RoleEntityService } from '@/core/entities/RoleEntityService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/show.ts b/packages/backend/src/server/api/endpoints/admin/roles/show.ts index 1ca952a3f8..91e32d95be 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/show.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/show.ts @@ -13,6 +13,8 @@ import { RoleEntityService } from '@/core/entities/RoleEntityService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'read:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts index 4c27583111..701fea1ed5 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts @@ -13,6 +13,8 @@ import { RoleService } from '@/core/RoleService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts index b4e7e29e90..066fc73234 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts @@ -11,6 +11,8 @@ import { MetaService } from '@/core/MetaService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 6031e2363e..6cfcd8ca4a 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -14,6 +14,8 @@ import { RoleService } from '@/core/RoleService.js'; export const meta = { tags: ['admin', 'role'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts index b7f9aa0495..6a0f7f9987 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts @@ -16,6 +16,8 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['admin', 'role', 'users'], + kind: 'read:admin', + requireCredential: false, requireAdmin: true, @@ -26,6 +28,20 @@ export const meta = { id: '224eff5e-2488-4b18-b3e7-f50d94421648', }, }, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string', format: 'misskey:id' }, + createdAt: { type: 'string', format: 'date-time' }, + user: { ref: 'UserDetailed' }, + expiresAt: { type: 'string', format: 'date-time', nullable: true }, + }, + required: ['id', 'createdAt', 'user'], + }, + } } as const; export const paramDef = { @@ -78,7 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- id: assign.id, createdAt: this.idService.parse(assign.id).date.toISOString(), user: await this.userEntityService.pack(assign.user!, me, { detail: true }), - expiresAt: assign.expiresAt, + expiresAt: assign.expiresAt?.toISOString() ?? null, }))); }); } diff --git a/packages/backend/src/server/api/endpoints/admin/send-email.ts b/packages/backend/src/server/api/endpoints/admin/send-email.ts index b9f2c6a6f1..d22066909e 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-email.ts @@ -10,6 +10,8 @@ import { EmailService } from '@/core/EmailService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index 3169373b0e..d3c3bebff6 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -17,6 +17,8 @@ export const meta = { tags: ['admin', 'meta'], + kind: 'read:admin', + res: { type: 'object', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts index 34c247343a..c82532ed67 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -16,6 +16,8 @@ export const meta = { requireCredential: true, requireAdmin: true, + kind: 'read:admin', + res: { type: 'array', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index f550c4fd28..f1e7b75a32 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -17,6 +17,8 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin', + res: { type: 'object', nullable: false, optional: false, diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index fc810987d2..5081383687 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -17,6 +17,8 @@ export const meta = { requireCredential: true, requireModerator: true, + kind: 'read:admin', + res: { type: 'array', nullable: false, optional: false, diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index 9464f4b677..35c3f37481 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -19,6 +19,8 @@ import { QueueService } from '@/core/QueueService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts index ac10f1b6fd..2309493937 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; @@ -39,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { if (user == null) { throw new Error('user not found'); } - + if (user.avatarId == null) return; await this.usersRepository.update(user.id, { diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts index 66acd367df..468c634e5b 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 5e523bbc31..8cdd317eae 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -13,6 +13,8 @@ import { DI } from '@/di-symbols.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 46d59b041c..3b7e6ad224 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -12,6 +12,8 @@ import { MetaService } from '@/core/MetaService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireAdmin: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts index bfccc2a2a5..dd0b777373 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts @@ -12,6 +12,8 @@ import { ModerationLogService } from '@/core/ModerationLogService.js'; export const meta = { tags: ['admin'], + kind: 'write:admin', + requireCredential: true, requireModerator: true, } as const; diff --git a/packages/backend/src/server/api/endpoints/endpoint.ts b/packages/backend/src/server/api/endpoints/endpoint.ts index cecaded20a..66ac8f664f 100644 --- a/packages/backend/src/server/api/endpoints/endpoint.ts +++ b/packages/backend/src/server/api/endpoints/endpoint.ts @@ -11,6 +11,23 @@ export const meta = { requireCredential: false, tags: ['meta'], + + res: { + type: 'object', + nullable: true, + properties: { + params: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + type: { type: 'string' }, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index e3ffea7b7e..6548142d41 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -18,6 +18,92 @@ export const meta = { allowGet: true, cacheSec: 60 * 60, + + res: { + type: 'object', + optional: false, + nullable: false, + properties: { + topSubInstances: { + type: 'array', + optional: false, + nullable: false, + items: { + properties: { + id: { type: 'string' }, + firstRetrievedAt: { type: 'string' }, + host: { type: 'string' }, + usersCount: { type: 'number' }, + notesCount: { type: 'number' }, + followingCount: { type: 'number' }, + followersCount: { type: 'number' }, + isNotResponding: { type: 'boolean' }, + isSuspended: { type: 'boolean' }, + isBlocked: { type: 'boolean' }, + softwareName: { type: 'string' }, + softwareVersion: { type: 'string' }, + openRegistrations: { type: 'boolean' }, + name: { type: 'string' }, + description: { type: 'string' }, + maintainerName: { type: 'string' }, + maintainerEmail: { type: 'string' }, + isSilenced: { type: 'boolean' }, + iconUrl: { type: 'string' }, + faviconUrl: { type: 'string' }, + themeColor: { type: 'string' }, + infoUpdatedAt: { + type: 'string', + nullable: true, + }, + latestRequestReceivedAt: { + type: 'string', + nullable: true, + }, + } + }, + }, + otherFollowersCount: { type: 'number' }, + topPubInstances: { + type: 'array', + optional: false, + nullable: false, + items: { + properties: { + id: { type: 'string' }, + firstRetrievedAt: { type: 'string' }, + host: { type: 'string' }, + usersCount: { type: 'number' }, + notesCount: { type: 'number' }, + followingCount: { type: 'number' }, + followersCount: { type: 'number' }, + isNotResponding: { type: 'boolean' }, + isSuspended: { type: 'boolean' }, + isBlocked: { type: 'boolean' }, + softwareName: { type: 'string' }, + softwareVersion: { type: 'string' }, + openRegistrations: { type: 'boolean' }, + name: { type: 'string' }, + description: { type: 'string' }, + maintainerName: { type: 'string' }, + maintainerEmail: { type: 'string' }, + isSilenced: { type: 'boolean' }, + iconUrl: { type: 'string' }, + faviconUrl: { type: 'string' }, + themeColor: { type: 'string' }, + infoUpdatedAt: { + type: 'string', + nullable: true, + }, + latestRequestReceivedAt: { + type: 'string', + nullable: true, + }, + } + }, + }, + otherFollowingCount: { type: 'number' }, + }, + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts index d7b46cc666..6391a2f580 100644 --- a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts +++ b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts @@ -32,6 +32,18 @@ export const meta = { id: '693ba8ba-b486-40df-a174-72f8279b56a4', }, }, + + res: { + type: 'object', + properties: { + type: { + type: 'string', + }, + data: { + type: 'string', + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index 37859d8330..b2dee83fe9 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -16,6 +16,18 @@ export const meta = { requireCredential: false, allowGet: true, cacheSec: 60 * 3, + + res: { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'object', + }, + } + } + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts index 4fa65ac9aa..674f323734 100644 --- a/packages/backend/src/server/api/endpoints/flash/create.ts +++ b/packages/backend/src/server/api/endpoints/flash/create.ts @@ -27,6 +27,12 @@ export const meta = { errors: { }, + + res: { + type: 'object', + optional: false, nullable: false, + ref: 'Flash', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index 8a61168f25..737d637b7e 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -16,6 +16,16 @@ export const meta = { requireCredential: false, allowGet: true, cacheSec: 60 * 1, + res: { + type: 'object', + optional: false, nullable: false, + properties: { + count: { + type: 'number', + nullable: false, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index 6d530aba3b..a7be47fd0f 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -32,6 +32,16 @@ export const meta = { id: '798d6847-b1ed-4f9c-b1f9-163c42655995', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index c39005f2dd..0fac96d58f 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -36,6 +36,140 @@ export const meta = { id: 'bf32b864-449b-47b8-974e-f9a5468546f1', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + rp: { + type: 'object', + properties: { + id: { + type: 'string', + nullable: true, + }, + }, + }, + user: { + type: 'object', + properties: { + id: { + type: 'string', + }, + name: { + type: 'string', + }, + displayName: { + type: 'string', + }, + }, + }, + challenge: { + type: 'string', + }, + pubKeyCredParams: { + type: 'array', + items: { + type: 'object', + properties: { + type: { + type: 'string', + }, + alg: { + type: 'number', + }, + }, + }, + }, + timeout: { + type: 'number', + nullable: true, + }, + excludeCredentials: { + type: 'array', + nullable: true, + items: { + type: 'object', + properties: { + id: { + type: 'string', + }, + type: { + type: 'string', + }, + transports: { + type: 'array', + items: { + type: 'string', + enum: [ + "ble", + "cable", + "hybrid", + "internal", + "nfc", + "smart-card", + "usb", + ], + }, + }, + }, + }, + }, + authenticatorSelection: { + type: 'object', + nullable: true, + properties: { + authenticatorAttachment: { + type: 'string', + enum: [ + "cross-platform", + "platform", + ], + }, + requireResidentKey: { + type: 'boolean', + }, + userVerification: { + type: 'string', + enum: [ + "discouraged", + "preferred", + "required", + ], + }, + }, + }, + attestation: { + type: 'string', + nullable: true, + enum: [ + "direct", + "enterprise", + "indirect", + "none", + ], + }, + extensions: { + type: 'object', + nullable: true, + properties: { + appid: { + type: 'string', + nullable: true, + }, + credProps: { + type: 'boolean', + nullable: true, + }, + hmacCreateSecret: { + type: 'boolean', + nullable: true, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index b358c812ee..cc083cbf7b 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -26,6 +26,19 @@ export const meta = { id: '78d6c839-20c9-4c66-b90a-fc0542168b48', }, }, + + res: { + type: 'object', + nullable: false, + optional: false, + properties: { + qr: { type: 'string' }, + url: { type: 'string' }, + secret: { type: 'string' }, + label: { type: 'string' }, + issuer: { type: 'string' }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index 09f6540a77..ef89f93181 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -13,6 +13,37 @@ export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + name: { + type: 'string', + }, + createdAt: { + type: 'string', + format: 'date-time', + }, + lastUsedAt: { + type: 'string', + format: 'date-time', + }, + permission: { + type: 'array', + uniqueItems: true, + items: { + type: 'string' + }, + } + }, + }, + }, } as const; export const paramDef = { @@ -50,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- id: token.id, name: token.name ?? token.app?.name, createdAt: this.idService.parse(token.id).date.toISOString(), - lastUsedAt: token.lastUsedAt, + lastUsedAt: token.lastUsedAt?.toISOString(), permission: token.permission, }))); }); diff --git a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts index 32061c2aa4..a0ed371fb8 100644 --- a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts +++ b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts @@ -14,6 +14,36 @@ export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + name: { + type: 'string', + }, + callbackUrl: { + type: 'string', + nullable: true, + }, + permission: { + type: 'array', + uniqueItems: true, + items: { + type: 'string' + }, + }, + isAuthorized: { + type: 'boolean', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index 86b726e054..f3ba720c2b 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -64,6 +64,10 @@ export const meta = { id: 'b234a14e-9ebe-4581-8000-074b3c215962', }, }, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts index 29fa0a29cc..bd6e85a074 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts @@ -9,6 +9,10 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts index 5b460b45d6..2352beb130 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts @@ -18,6 +18,10 @@ export const meta = { id: '97a1e8e7-c0f7-47d2-957a-92e61256e01a', }, }, + + res: { + type: 'object', + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/get.ts b/packages/backend/src/server/api/endpoints/i/registry/get.ts index e8c28298ef..4155a43e0d 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get.ts @@ -18,6 +18,10 @@ export const meta = { id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a', }, }, + + res: { + type: 'object', + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts index 8953ee5d3d..b411cdd3d9 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -9,6 +9,10 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, + + res: { + type: 'object', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts index 1ff994b82c..0aca2a26fe 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts @@ -10,6 +10,28 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, secure: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + scopes: { + type: 'array', + items: { + type: 'array', + items: { + type: 'string', + } + } + }, + domain: { + type: 'string', + nullable: true, + }, + }, + }, + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index a36b3a732b..52977f5a07 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -40,6 +40,11 @@ export const meta = { id: 'a2defefb-f220-8849-0af6-17f816099323', }, }, + + res: { + type: 'object', + ref: 'UserDetailed', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index b5fdc448ac..b258349148 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -177,7 +177,8 @@ export const paramDef = { receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, autoSensitive: { type: 'boolean' }, - ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, + followingVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, + followersVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true }, mutedWords: muteWords, hardMutedWords: muteWords, @@ -242,7 +243,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- if (ps.lang !== undefined) profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday; - if (ps.ffVisibility !== undefined) profileUpdates.ffVisibility = ps.ffVisibility; + if (ps.followingVisibility !== undefined) profileUpdates.followingVisibility = ps.followingVisibility; + if (ps.followersVisibility !== undefined) profileUpdates.followersVisibility = ps.followersVisibility; function checkMuteWordCount(mutedWords: (string[] | string)[], limit: number) { // TODO: ちゃんと数える diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index f00dba4a85..bdc9f9ea8b 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -27,6 +27,33 @@ export const meta = { id: '87a9bb19-111e-4e37-81d3-a3e7426453b0', }, }, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id' + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + } + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + }, } as const; export const paramDef = { @@ -73,7 +100,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- this.globalEventService.publishInternalEvent('webhookCreated', webhook); - return webhook; + return { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts index aa8921fe24..afb2d0509e 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts @@ -5,6 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import { webhookEventTypes } from '@/models/Webhook.js'; import type { WebhooksRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; @@ -14,6 +15,36 @@ export const meta = { requireCredential: true, kind: 'read:account', + + res: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id' + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + } + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + } + } } as const; export const paramDef = { @@ -33,7 +64,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- userId: me.id, }); - return webhooks; + return webhooks.map(webhook => ( + { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + } + )); }); } } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts index f1294bb5c8..5c6dd908b4 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts @@ -5,6 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import { webhookEventTypes } from '@/models/Webhook.js'; import type { WebhooksRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; @@ -23,6 +24,33 @@ export const meta = { id: '50f614d9-3047-4f7e-90d8-ad6b2d5fb098', }, }, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id' + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + name: { type: 'string' }, + on: { + type: 'array', + items: { + type: 'string', + enum: webhookEventTypes, + } + }, + url: { type: 'string' }, + secret: { type: 'string' }, + active: { type: 'boolean' }, + latestSentAt: { type: 'string', format: 'date-time', nullable: true }, + latestStatus: { type: 'integer', nullable: true }, + }, + }, } as const; export const paramDef = { @@ -49,7 +77,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- throw new ApiError(meta.errors.noSuchWebhook); } - return webhook; + return { + id: webhook.id, + userId: webhook.userId, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + active: webhook.active, + latestSentAt: webhook.latestSentAt?.toISOString(), + latestStatus: webhook.latestStatus, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index caaa3735e9..d304d075b2 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -24,6 +24,25 @@ export const meta = { id: '30aaaee3-4792-48dc-ab0d-cf501a575ac5', }, }, + + res: { + type: 'array', + items: { + type: 'object', + nullable: false, + properties: { + id: { + type: 'string', + format: 'misskey:id' + }, + user: { + type: 'object', + ref: 'User' + }, + }, + required: ['id', 'user'], + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index c8cb63e6b3..079f2d7f1d 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -15,6 +15,53 @@ export const meta = { cacheSec: 60 * 1, tags: ['meta'], + res: { + type: 'object', + optional: false, nullable: false, + properties: { + machine: { + type: 'string', + nullable: false, + }, + cpu: { + type: 'object', + nullable: false, + properties: { + model: { + type: 'string', + nullable: false, + }, + cores: { + type: 'number', + nullable: false, + }, + }, + }, + mem: { + type: 'object', + properties: { + total: { + type: 'number', + nullable: false, + }, + }, + }, + fs: { + type: 'object', + nullable: false, + properties: { + total: { + type: 'number', + nullable: false, + }, + used: { + type: 'number', + nullable: false, + }, + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/test.ts b/packages/backend/src/server/api/endpoints/test.ts index 6d6d44f752..949867c572 100644 --- a/packages/backend/src/server/api/endpoints/test.ts +++ b/packages/backend/src/server/api/endpoints/test.ts @@ -12,6 +12,30 @@ export const meta = { description: 'Endpoint for testing input validation.', requireCredential: false, + + res: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id' + }, + required: { + type: 'boolean', + }, + string: { + type: 'string', + }, + default: { + type: 'string', + }, + nullableDefault: { + type: 'string', + default: 'hello', + nullable: true, + }, + } + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/achievements.ts b/packages/backend/src/server/api/endpoints/users/achievements.ts index e4845d57bf..d6ad718dfa 100644 --- a/packages/backend/src/server/api/endpoints/users/achievements.ts +++ b/packages/backend/src/server/api/endpoints/users/achievements.ts @@ -10,6 +10,21 @@ import { DI } from '@/di-symbols.js'; export const meta = { requireCredential: true, + + res: { + type: 'array', + items: { + type: 'object', + properties: { + name: { + type: 'string', + }, + unlockedAt: { + type: 'number', + }, + }, + }, + } } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/featured-notes.ts b/packages/backend/src/server/api/endpoints/users/featured-notes.ts index f84148d727..7243aa3b3e 100644 --- a/packages/backend/src/server/api/endpoints/users/featured-notes.ts +++ b/packages/backend/src/server/api/endpoints/users/featured-notes.ts @@ -51,6 +51,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- private cacheService: CacheService, ) { super(meta, paramDef, async (ps, me) => { + const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set<string>(); + + // early return if me is blocked by requesting user + if (userIdsWhoBlockingMe.has(ps.userId)) { + return []; + } + let noteIds = await this.featuredService.getPerUserNotesRanking(ps.userId, 50); noteIds.sort((a, b) => a > b ? -1 : 1); @@ -65,11 +72,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- const [ userIdsWhoMeMuting, - userIdsWhoBlockingMe, ] = me ? await Promise.all([ this.cacheService.userMutingsCache.fetch(me.id), - this.cacheService.userBlockedCache.fetch(me.id), - ]) : [new Set<string>(), new Set<string>()]; + ]) : [new Set<string>()]; const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index b22fd2ff7a..5706e46b96 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -93,11 +93,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followersVisibility === 'private') { if (me == null || (me.id !== user.id)) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followersVisibility === 'followers') { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index ead7ba8c40..794fb04f10 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -101,11 +101,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - if (profile.ffVisibility === 'private') { + if (profile.followingVisibility === 'private') { if (me == null || (me.id !== user.id)) { throw new ApiError(meta.errors.forbidden); } - } else if (profile.ffVisibility === 'followers') { + } else if (profile.followingVisibility === 'followers') { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { diff --git a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts index ae8b4e9b81..985141515e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts @@ -25,6 +25,35 @@ export const meta = { id: '7bc05c21-1d7a-41ae-88f1-66820f4dc686', }, }, + + res: { + type: 'array', + items: { + type: 'object', + nullable: false, + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + createdAt: { + type: 'string', + format: 'date-time', + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + user: { + type: 'object', + ref: 'User', + }, + withReplies: { + type: 'boolean', + }, + }, + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index b32128a8aa..b485126ed8 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -86,6 +86,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- if (ps.withReplies && ps.withFiles) throw new ApiError(meta.errors.bothWithRepliesAndWithFiles); + // early return if me is blocked by requesting user + if (me != null) { + const userIdsWhoBlockingMe = await this.cacheService.userBlockedCache.fetch(me.id); + if (userIdsWhoBlockingMe.has(ps.userId)) { + return []; + } + } + if (!serverSettings.enableFanoutTimeline) { const timeline = await this.getFromDb({ untilId, diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index dd4304e6ef..dfda85aac9 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -60,7 +60,7 @@ export class FeedService { title: `${author.name} (@${user.username}@${this.config.host})`, updated: notes.length !== 0 ? this.idService.parse(notes[0].id).date : undefined, generator: 'Misskey', - description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, + description: `${user.notesCount} Notes, ${profile.followingVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.followersVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, link: author.link, image: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), feedLinks: { diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 6061d00ee1..03e755bcf9 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -22,18 +22,34 @@ import type { MiScheduledNote } from '@/models/ScheduledNote.js'; * pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した * receiveFollowRequest - フォローリクエストされた * followRequestAccepted - 自分の送ったフォローリクエストが承認された + * roleAssigned - ロールが付与された * achievementEarned - 実績を獲得 * app - アプリ通知 * test - テスト通知(サーバー側) */ -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app', 'test'] as const; +export const notificationTypes = [ + 'note', + 'follow', + 'mention', + 'reply', + 'renote', + 'quote', + 'reaction', + 'pollEnded', + 'receiveFollowRequest', + 'followRequestAccepted', + 'roleAssigned', + 'achievementEarned', + 'app', + 'test'] as const; export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const; -export const ffVisibility = ['public', 'followers', 'private'] as const; +export const followingVisibilities = ['public', 'followers', 'private'] as const; +export const followersVisibilities = ['public', 'followers', 'private'] as const; export const moderationLogTypes = [ 'updateServerSettings', diff --git a/packages/backend/test/docker-compose.yml b/packages/backend/test/docker-compose.yml index da6c01dda1..f2d8990758 100644 --- a/packages/backend/test/docker-compose.yml +++ b/packages/backend/test/docker-compose.yml @@ -7,7 +7,7 @@ services: - "127.0.0.1:56312:6379" dbtest: - image: postgres:13 + image: postgres:15 ports: - "127.0.0.1:54312:5432" environment: diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts index 7841e057bf..1fbd45c741 100644 --- a/packages/backend/test/e2e/ff-visibility.ts +++ b/packages/backend/test/e2e/ff-visibility.ts @@ -26,9 +26,10 @@ describe('FF visibility', () => { await app.close(); }); - test('ffVisibility が public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { + test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { await api('/i/update', { - ffVisibility: 'public', + followingVisibility: 'public', + followersVisibility: 'public', }, alice); const followingRes = await api('/users/following', { @@ -44,9 +45,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーを自分で見れる', async () => { + test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); const followingRes = await api('/users/following', { @@ -62,9 +142,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); const followingRes = await api('/users/following', { @@ -78,9 +237,82 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 400); }); - test('ffVisibility が followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + }); + + test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => { await api('/i/update', { - ffVisibility: 'followers', + followingVisibility: 'followers', + followersVisibility: 'followers', }, alice); await api('/following/create', { @@ -100,9 +332,106 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が private なユーザーのフォロー/フォロワーを自分で見れる', async () => { + test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'public', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + await api('/following/create', { + userId: alice.id, + }, bob); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => { await api('/i/update', { - ffVisibility: 'private', + followingVisibility: 'private', + followersVisibility: 'private', }, alice); const followingRes = await api('/users/following', { @@ -118,9 +447,88 @@ describe('FF visibility', () => { assert.strictEqual(Array.isArray(followersRes.body), true); }); - test('ffVisibility が private なユーザーのフォロー/フォロワーを他人が見れない', async () => { + test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, alice); + assert.strictEqual(followingRes.status, 200); + assert.strictEqual(Array.isArray(followingRes.body), true); + } + }); + + test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, alice); + assert.strictEqual(followersRes.status, 200); + assert.strictEqual(Array.isArray(followersRes.body), true); + } + }); + + test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => { await api('/i/update', { - ffVisibility: 'private', + followingVisibility: 'private', + followersVisibility: 'private', }, alice); const followingRes = await api('/users/following', { @@ -134,36 +542,129 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 400); }); + test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'public', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'followers', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followingRes = await api('/users/following', { + userId: alice.id, + }, bob); + assert.strictEqual(followingRes.status, 400); + } + }); + + test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => { + { + await api('/i/update', { + followingVisibility: 'public', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'followers', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + { + await api('/i/update', { + followingVisibility: 'private', + followersVisibility: 'private', + }, alice); + + const followersRes = await api('/users/followers', { + userId: alice.id, + }, bob); + assert.strictEqual(followersRes.status, 400); + } + }); + describe('AP', () => { - test('ffVisibility が public 以外ならばAPからは取得できない', async () => { + test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => { { await api('/i/update', { - ffVisibility: 'public', + followingVisibility: 'public', }, alice); const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); - const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followingRes.status, 200); + } + { + await api('/i/update', { + followingVisibility: 'followers', + }, alice); + + const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); + assert.strictEqual(followingRes.status, 403); + } + { + await api('/i/update', { + followingVisibility: 'private', + }, alice); + + const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); + assert.strictEqual(followingRes.status, 403); + } + }); + + test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => { + { + await api('/i/update', { + followersVisibility: 'public', + }, alice); + + const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); assert.strictEqual(followersRes.status, 200); } { await api('/i/update', { - ffVisibility: 'followers', + followersVisibility: 'followers', }, alice); - const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); - assert.strictEqual(followingRes.status, 403); assert.strictEqual(followersRes.status, 403); } { await api('/i/update', { - ffVisibility: 'private', + followersVisibility: 'private', }, alice); - const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json'); const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json'); - assert.strictEqual(followingRes.status, 403); assert.strictEqual(followersRes.status, 403); } }); diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 73c446444b..cb9558b416 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -10,9 +10,8 @@ process.env.NODE_ENV = 'test'; process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING = 'true'; import * as assert from 'assert'; -import { signup, api, post, react, startServer, waitFire, sleep, uploadUrl, randomString } from '../utils.js'; +import { api, post, randomString, signup, sleep, startServer, uploadUrl } from '../utils.js'; import type { INestApplicationContext } from '@nestjs/common'; -import type * as misskey from 'misskey-js'; function genHost() { return randomString() + '.example.com'; @@ -366,8 +365,8 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await sleep(1000); const [bobFile, carolFile] = await Promise.all([ - uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), - uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), + uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), + uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), ]); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [bobFile.id] }); @@ -666,7 +665,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -804,7 +803,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -999,7 +998,7 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); @@ -1158,7 +1157,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 2ce8fbc129..9c4cbac368 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -112,7 +112,8 @@ describe('ユーザー', () => { pinnedPageId: user.pinnedPageId, pinnedPage: user.pinnedPage, publicReactions: user.publicReactions, - ffVisibility: user.ffVisibility, + followingVisibility: user.followingVisibility, + followersVisibility: user.followersVisibility, twoFactorEnabled: user.twoFactorEnabled, usePasswordLessLogin: user.usePasswordLessLogin, securityKeys: user.securityKeys, @@ -386,7 +387,8 @@ describe('ユーザー', () => { assert.strictEqual(response.pinnedPageId, null); assert.strictEqual(response.pinnedPage, null); assert.strictEqual(response.publicReactions, true); - assert.strictEqual(response.ffVisibility, 'public'); + assert.strictEqual(response.followingVisibility, 'public'); + assert.strictEqual(response.followersVisibility, 'public'); assert.strictEqual(response.twoFactorEnabled, false); assert.strictEqual(response.usePasswordLessLogin, false); assert.strictEqual(response.securityKeys, false); @@ -495,9 +497,12 @@ describe('ユーザー', () => { { parameters: (): object => ({ alwaysMarkNsfw: false }) }, { parameters: (): object => ({ autoSensitive: true }) }, { parameters: (): object => ({ autoSensitive: false }) }, - { parameters: (): object => ({ ffVisibility: 'private' }) }, - { parameters: (): object => ({ ffVisibility: 'followers' }) }, - { parameters: (): object => ({ ffVisibility: 'public' }) }, + { parameters: (): object => ({ followingVisibility: 'private' }) }, + { parameters: (): object => ({ followingVisibility: 'followers' }) }, + { parameters: (): object => ({ followingVisibility: 'public' }) }, + { parameters: (): object => ({ followersVisibility: 'private' }) }, + { parameters: (): object => ({ followersVisibility: 'followers' }) }, + { parameters: (): object => ({ followersVisibility: 'public' }) }, { parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) }, { parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) }, { parameters: (): object => ({ mutedWords: [] }) }, diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index f644312bc9..9879eb8e3e 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -19,6 +19,7 @@ import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; +import { NotificationService } from '@/core/NotificationService.js'; import { sleep } from '../utils.js'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; @@ -32,6 +33,7 @@ describe('RoleService', () => { let rolesRepository: RolesRepository; let roleAssignmentsRepository: RoleAssignmentsRepository; let metaService: jest.Mocked<MetaService>; + let notificationService: jest.Mocked<NotificationService>; let clock: lolex.InstalledClock; function createUser(data: Partial<MiUser> = {}) { @@ -71,6 +73,16 @@ describe('RoleService', () => { CacheService, IdService, GlobalEventService, + { + provide: NotificationService, + useFactory: () => ({ + createNotification: jest.fn(), + }), + }, + { + provide: NotificationService.name, + useExisting: NotificationService, + }, ], }) .useMocker((token) => { @@ -93,6 +105,9 @@ describe('RoleService', () => { roleAssignmentsRepository = app.get<RoleAssignmentsRepository>(DI.roleAssignmentsRepository); metaService = app.get<MetaService>(MetaService) as jest.Mocked<MetaService>; + notificationService = app.get<NotificationService>(NotificationService) as jest.Mocked<NotificationService>; + + await roleService.onModuleInit(); }); afterEach(async () => { @@ -273,4 +288,57 @@ describe('RoleService', () => { expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true); }); }); + + describe('assign', () => { + test('公開ロールの場合は通知される', async () => { + const user = await createUser(); + const role = await createRole({ + isPublic: true, + name: 'a', + }); + + await roleService.assign(user.id, role.id); + + clock.uninstall(); + await sleep(100); + + const assignments = await roleAssignmentsRepository.find({ + where: { + userId: user.id, + roleId: role.id, + }, + }); + expect(assignments).toHaveLength(1); + + expect(notificationService.createNotification).toHaveBeenCalled(); + expect(notificationService.createNotification.mock.lastCall![0]).toBe(user.id); + expect(notificationService.createNotification.mock.lastCall![1]).toBe('roleAssigned'); + expect(notificationService.createNotification.mock.lastCall![2]).toEqual({ + roleId: role.id, + }); + }); + + test('非公開ロールの場合は通知されない', async () => { + const user = await createUser(); + const role = await createRole({ + isPublic: false, + name: 'a', + }); + + await roleService.assign(user.id, role.id); + + clock.uninstall(); + await sleep(100); + + const assignments = await roleAssignmentsRepository.find({ + where: { + userId: user.id, + roleId: role.id, + }, + }); + expect(assignments).toHaveLength(1); + + expect(notificationService.createNotification).not.toHaveBeenCalled(); + }); + }); }); diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index c2e6ee52f3..2960489c77 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -82,7 +82,8 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi birthday: '2014-06-20', createdAt: '2016-12-28T22:49:51.000Z', description: 'I am a cool user!', - ffVisibility: 'public', + followingVisibility: 'public', + followersVisibility: 'public', roles: [], fields: [ { diff --git a/packages/frontend/.storybook/mocks.ts b/packages/frontend/.storybook/mocks.ts index b60755feea..80e5157c5a 100644 --- a/packages/frontend/.storybook/mocks.ts +++ b/packages/frontend/.storybook/mocks.ts @@ -25,7 +25,7 @@ export const commonHandlers = [ }), rest.get('/twemoji/:codepoints.svg', async (req, res, ctx) => { const { codepoints } = req.params; - const value = await fetch(`https://unpkg.com/@discordapp/twemoji@14.1.2/dist/svg/${codepoints}.svg`).then((response) => response.blob()); + const value = await fetch(`https://unpkg.com/@discordapp/twemoji@15.0.2/dist/svg/${codepoints}.svg`).then((response) => response.blob()); return res(ctx.set('Content-Type', 'image/svg+xml'), ctx.body(value)); }), ]; diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 4cf4779563..523fc281b3 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -17,18 +17,19 @@ "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { - "@discordapp/twemoji": "14.1.2", + "@discordapp/twemoji": "15.0.2", "@github/webauthn-json": "2.1.1", "@rollup/plugin-json": "6.1.0", "@rollup/plugin-replace": "5.0.5", "@rollup/pluginutils": "5.1.0", "@syuilo/aiscript": "0.16.0", "@tabler/icons-webfont": "2.44.0", + "@twemoji/parser": "15.0.0", "@vitejs/plugin-vue": "4.5.2", - "@vue/compiler-sfc": "3.3.11", - "astring": "1.8.6", + "@vue/compiler-sfc": "3.3.12", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.0.6", - "broadcast-channel": "6.0.0", + "astring": "1.8.6", + "broadcast-channel": "7.0.0", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", "buraha": "0.0.1", "canvas-confetti": "1.6.1", @@ -44,20 +45,20 @@ "escape-regexp": "0.0.1", "estree-walker": "3.0.3", "eventemitter3": "5.0.1", - "gsap": "3.12.3", + "gsap": "3.12.4", "idb-keyval": "6.2.1", "insert-text-at-cursor": "0.3.0", "is-file-animated": "1.0.2", "json5": "2.2.3", "matter-js": "0.19.0", - "mfm-js": "0.23.3", + "mfm-js": "0.24.0", "misskey-js": "workspace:*", "photoswipe": "5.4.3", "punycode": "2.3.1", - "rollup": "4.9.0", + "rollup": "4.9.1", "sanitize-html": "2.11.0", - "shiki": "0.14.6", "sass": "1.69.5", + "shiki": "0.14.7", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", "three": "0.159.0", @@ -65,39 +66,38 @@ "tinycolor2": "1.6.0", "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", - "twemoji-parser": "14.0.0", "typescript": "5.3.3", "uuid": "9.0.1", "v-code-diff": "1.7.2", - "vite": "5.0.8", - "vue": "3.3.11", + "vite": "5.0.10", + "vue": "3.3.12", "vuedraggable": "next" }, "devDependencies": { - "@storybook/addon-actions": "7.6.4", - "@storybook/addon-essentials": "7.6.4", - "@storybook/addon-interactions": "7.6.4", - "@storybook/addon-links": "7.6.4", - "@storybook/addon-storysource": "7.6.4", - "@storybook/addons": "7.6.4", - "@storybook/blocks": "7.6.4", - "@storybook/core-events": "7.6.4", + "@storybook/addon-actions": "7.6.5", + "@storybook/addon-essentials": "7.6.5", + "@storybook/addon-interactions": "7.6.5", + "@storybook/addon-links": "7.6.5", + "@storybook/addon-storysource": "7.6.5", + "@storybook/addons": "7.6.5", + "@storybook/blocks": "7.6.5", + "@storybook/core-events": "7.6.5", "@storybook/jest": "0.2.3", - "@storybook/manager-api": "7.6.4", - "@storybook/preview-api": "7.6.4", - "@storybook/react": "7.6.4", - "@storybook/react-vite": "7.6.4", + "@storybook/manager-api": "7.6.5", + "@storybook/preview-api": "7.6.5", + "@storybook/react": "7.6.5", + "@storybook/react-vite": "7.6.5", "@storybook/testing-library": "0.2.2", - "@storybook/theming": "7.6.4", - "@storybook/types": "7.6.4", - "@storybook/vue3": "7.6.4", - "@storybook/vue3-vite": "7.6.4", + "@storybook/theming": "7.6.5", + "@storybook/types": "7.6.5", + "@storybook/vue3": "7.6.5", + "@storybook/vue3-vite": "7.6.5", "@testing-library/vue": "8.0.1", "@types/escape-regexp": "0.0.3", "@types/estree": "1.0.5", "@types/matter-js": "0.19.5", "@types/micromatch": "4.0.6", - "@types/node": "20.10.4", + "@types/node": "20.10.5", "@types/punycode": "2.1.3", "@types/sanitize-html": "2.9.5", "@types/throttle-debounce": "5.0.2", @@ -107,15 +107,16 @@ "@typescript-eslint/eslint-plugin": "6.14.0", "@typescript-eslint/parser": "6.14.0", "@vitest/coverage-v8": "0.34.6", - "@vue/runtime-core": "3.3.11", + "@vue/runtime-core": "3.3.12", "acorn": "8.11.2", "cross-env": "7.0.3", "cypress": "13.6.1", - "eslint": "8.55.0", - "eslint-plugin-import": "2.29.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1", "eslint-plugin-vue": "9.19.2", "fast-glob": "3.3.2", "happy-dom": "10.0.3", + "intersection-observer": "0.12.2", "micromatch": "4.0.5", "msw": "1.3.2", "msw-storybook-addon": "1.10.0", @@ -124,7 +125,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.3", - "storybook": "7.6.4", + "storybook": "7.6.5", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.3", diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 728f39962b..ef69eff764 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -3,28 +3,25 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent, App } from 'vue'; +import { computed, watch, version as vueVersion, App } from 'vue'; import { compareVersions } from 'compare-versions'; import widgets from '@/widgets/index.js'; import directives from '@/directives/index.js'; import components from '@/components/index.js'; -import { version, ui, lang, updateLocale, locale } from '@/config.js'; +import { version, lang, updateLocale, locale } from '@/config.js'; import { applyTheme } from '@/scripts/theme.js'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js'; -import { i18n, updateI18n } from '@/i18n.js'; -import { confirm, alert, post, popup, toast } from '@/os.js'; -import { $i, refreshAccount, login, updateAccount, signout } from '@/account.js'; +import { updateI18n } from '@/i18n.js'; +import { $i, refreshAccount, login } from '@/account.js'; import { defaultStore, ColdDeviceStorage } from '@/store.js'; import { fetchInstance, instance } from '@/instance.js'; import { deviceKind } from '@/scripts/device-kind.js'; import { reloadChannel } from '@/scripts/unison-reload.js'; -import { reactionPicker } from '@/scripts/reaction-picker.js'; import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { miLocalStorage } from '@/local-storage.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; -import { mainRouter } from '@/router.js'; export async function common(createVue: () => App<Element>) { console.info(`Misskey v${version}`); diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 88e2f83895..0159d0c032 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -3,14 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent } from 'vue'; +import { createApp, markRaw, defineAsyncComponent } from 'vue'; import { common } from './common.js'; -import { version, ui, lang, updateLocale } from '@/config.js'; -import { i18n, updateI18n } from '@/i18n.js'; +import { ui } from '@/config.js'; +import { i18n } from '@/i18n.js'; import { confirm, alert, post, popup, toast } from '@/os.js'; import { useStream } from '@/stream.js'; import * as sound from '@/scripts/sound.js'; -import { $i, refreshAccount, login, updateAccount, signout } from '@/account.js'; +import { $i, updateAccount, signout } from '@/account.js'; import { defaultStore, ColdDeviceStorage } from '@/store.js'; import { makeHotkey } from '@/scripts/hotkey.js'; import { reactionPicker } from '@/scripts/reaction-picker.js'; @@ -75,6 +75,14 @@ export async function mainBoot() { }, }; + if (defaultStore.state.enableSeasonalScreenEffect) { + const month = new Date().getMonth() + 1; + if (month === 12 || month === 1) { + const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; + new SnowfallEffect().render(); + } + } + if ($i) { // only add post shortcuts if logged in hotkeys['p|n'] = post; diff --git a/packages/frontend/src/boot/sub-boot.ts b/packages/frontend/src/boot/sub-boot.ts index 9b4670e130..92ee074afb 100644 --- a/packages/frontend/src/boot/sub-boot.ts +++ b/packages/frontend/src/boot/sub-boot.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent } from 'vue'; +import { createApp, defineAsyncComponent } from 'vue'; import { common } from './common.js'; export async function subBoot() { diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 0e3927dba4..4353ba4ac1 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -363,12 +363,25 @@ function onKeydown(event: KeyboardEvent) { } break; - case 'Tab': case 'ArrowDown': cancel(); selectNext(); break; + case 'Tab': + if (event.shiftKey) { + if (select.value !== -1) { + cancel(); + selectPrev(); + } else { + props.close(); + } + } else { + cancel(); + selectNext(); + } + break; + default: event.stopPropagation(); props.textarea.focus(); diff --git a/packages/frontend/src/components/MkChannelPreview.vue b/packages/frontend/src/components/MkChannelPreview.vue index 4512f2dd60..bf6504d6bf 100644 --- a/packages/frontend/src/components/MkChannelPreview.vue +++ b/packages/frontend/src/components/MkChannelPreview.vue @@ -4,49 +4,70 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1"> - <div class="banner" :style="bannerStyle"> - <div class="fade"></div> - <div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div> - <div v-if="channel.isSensitive" class="sensitiveIndicator">{{ i18n.ts.sensitive }}</div> - <div class="status"> - <div> - <i class="ti ti-users ti-fw"></i> - <I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"> - <template #n> - <b>{{ channel.usersCount }}</b> - </template> - </I18n> - </div> - <div> - <i class="ti ti-pencil ti-fw"></i> - <I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"> - <template #n> - <b>{{ channel.notesCount }}</b> - </template> - </I18n> +<div style="position: relative;"> + <MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1" @click="updateLastReadedAt"> + <div class="banner" :style="bannerStyle"> + <div class="fade"></div> + <div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div> + <div v-if="channel.isSensitive" class="sensitiveIndicator">{{ i18n.ts.sensitive }}</div> + <div class="status"> + <div> + <i class="ti ti-users ti-fw"></i> + <I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"> + <template #n> + <b>{{ channel.usersCount }}</b> + </template> + </I18n> + </div> + <div> + <i class="ti ti-pencil ti-fw"></i> + <I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"> + <template #n> + <b>{{ channel.notesCount }}</b> + </template> + </I18n> + </div> </div> </div> - </div> - <article v-if="channel.description"> - <p :title="channel.description">{{ channel.description.length > 85 ? channel.description.slice(0, 85) + '…' : channel.description }}</p> - </article> - <footer> - <span v-if="channel.lastNotedAt"> - {{ i18n.ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/> - </span> - </footer> -</MkA> + <article v-if="channel.description"> + <p :title="channel.description">{{ channel.description.length > 85 ? channel.description.slice(0, 85) + '…' : channel.description }}</p> + </article> + <footer> + <span v-if="channel.lastNotedAt"> + {{ i18n.ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/> + </span> + </footer> + </MkA> + <div + v-if="channel.lastNotedAt && (channel.isFavorited || channel.isFollowing) && (!lastReadedAt || Date.parse(channel.lastNotedAt) > lastReadedAt)" + class="indicator" + ></div> +</div> </template> <script lang="ts" setup> -import { computed } from 'vue'; +import { computed, ref, watch } from 'vue'; import { i18n } from '@/i18n.js'; +import { miLocalStorage } from '@/local-storage.js'; const props = defineProps<{ channel: Record<string, any>; }>(); +const getLastReadedAt = (): number | null => { + return miLocalStorage.getItemAsJson(`channelLastReadedAt:${props.channel.id}`) ?? null; +}; + +const lastReadedAt = ref(getLastReadedAt()); + +watch(() => props.channel.id, () => { + lastReadedAt.value = getLastReadedAt(); +}); + +const updateLastReadedAt = () => { + lastReadedAt.value = props.channel.lastNotedAt ? Date.parse(props.channel.lastNotedAt) : Date.now(); +}; + const bannerStyle = computed(() => { if (props.channel.bannerUrl) { return { backgroundImage: `url(${props.channel.bannerUrl})` }; @@ -170,4 +191,17 @@ const bannerStyle = computed(() => { } } +.indicator { + position: absolute; + top: 0; + right: 0; + transform: translate(25%, -25%); + background-color: var(--accent); + border: solid var(--bg) 4px; + border-radius: 100%; + width: 1.5rem; + height: 1.5rem; + aspect-ratio: 1 / 1; +} + </style> diff --git a/packages/frontend/src/components/MkCode.vue b/packages/frontend/src/components/MkCode.vue index cb0eef0549..2c016e4d7c 100644 --- a/packages/frontend/src/components/MkCode.vue +++ b/packages/frontend/src/components/MkCode.vue @@ -9,7 +9,8 @@ SPDX-License-Identifier: AGPL-3.0-only <MkLoading v-if="!inline ?? true"/> </template> <code v-if="inline" :class="$style.codeInlineRoot">{{ code }}</code> - <XCode v-else-if="show" :code="code" :lang="lang"/> + <XCode v-else-if="show && lang" :code="code" :lang="lang"/> + <pre v-else-if="show" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre> <button v-else :class="$style.codePlaceholderRoot" @click="show = true"> <div :class="$style.codePlaceholderContainer"> <div><i class="ti ti-code"></i> {{ i18n.ts.code }}</div> @@ -47,6 +48,21 @@ const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue')) border-radius: .3em; } +.codeBlockFallbackRoot { + display: block; + overflow-wrap: anywhere; + color: #D4D4D4; + background: #1E1E1E; + padding: 1em; + margin: .5em 0; + overflow: auto; + border-radius: 8px; +} + +.codeBlockFallbackCode { + font-family: Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace; +} + .codePlaceholderRoot { display: block; width: 100%; diff --git a/packages/frontend/src/components/MkCodeEditor.vue b/packages/frontend/src/components/MkCodeEditor.vue index 60f16f285f..6341c454ae 100644 --- a/packages/frontend/src/components/MkCodeEditor.vue +++ b/packages/frontend/src/components/MkCodeEditor.vue @@ -4,30 +4,38 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div :class="[$style.codeEditorRoot, { [$style.focused]: focused }]"> - <div :class="$style.codeEditorScroller"> - <textarea - ref="inputEl" - v-model="vModel" - :class="[$style.textarea]" - :disabled="disabled" - :required="required" - :readonly="readonly" - autocomplete="off" - wrap="off" - spellcheck="false" - @focus="focused = true" - @blur="focused = false" - @keydown="onKeydown($event)" - @input="onInput" - ></textarea> - <XCode :class="$style.codeEditorHighlighter" :codeEditor="true" :code="v" :lang="lang"/> +<div> + <div :class="$style.label" @click="focus"><slot name="label"></slot></div> + <div :class="[$style.codeEditorRoot, { [$style.focused]: focused }]"> + <div :class="$style.codeEditorScroller"> + <textarea + ref="inputEl" + v-model="vModel" + :class="[$style.textarea]" + :disabled="disabled" + :required="required" + :readonly="readonly" + autocomplete="off" + wrap="off" + spellcheck="false" + @focus="focused = true" + @blur="focused = false" + @keydown="onKeydown($event)" + @input="onInput" + ></textarea> + <XCode :class="$style.codeEditorHighlighter" :codeEditor="true" :code="v" :lang="lang"/> + </div> </div> + <div :class="$style.caption"><slot name="caption"></slot></div> + <MkButton v-if="manualSave && changed" primary :class="$style.save" @click="updated"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> </div> </template> <script lang="ts" setup> import { ref, watch, toRefs, shallowRef, nextTick } from 'vue'; +import { debounce } from 'throttle-debounce'; +import MkButton from '@/components/MkButton.vue'; +import { i18n } from '@/i18n.js'; import XCode from '@/components/MkCode.core.vue'; const props = withDefaults(defineProps<{ @@ -36,6 +44,8 @@ const props = withDefaults(defineProps<{ required?: boolean; readonly?: boolean; disabled?: boolean; + debounce?: boolean; + manualSave?: boolean; }>(), { lang: 'js', }); @@ -54,6 +64,8 @@ const focused = ref(false); const changed = ref(false); const inputEl = shallowRef<HTMLTextAreaElement>(); +const focus = () => inputEl.value?.focus(); + const onInput = (ev) => { v.value = ev.target?.value ?? v.value; changed.value = true; @@ -100,16 +112,48 @@ const updated = () => { emit('update:modelValue', v.value); }; +const debouncedUpdated = debounce(1000, updated); + watch(modelValue, newValue => { v.value = newValue ?? ''; }); -watch(v, () => { - updated(); +watch(v, newValue => { + if (!props.manualSave) { + if (props.debounce) { + debouncedUpdated(); + } else { + updated(); + } + } }); </script> <style lang="scss" module> +.label { + font-size: 0.85em; + padding: 0 0 8px 0; + user-select: none; + + &:empty { + display: none; + } +} + +.caption { + font-size: 0.85em; + padding: 8px 0 0 0; + color: var(--fgTransparentWeak); + + &:empty { + display: none; + } +} + +.save { + margin: 8px 0 0 0; +} + .codeEditorRoot { min-width: 100%; max-width: 100%; @@ -117,6 +161,7 @@ watch(v, () => { overflow-y: hidden; box-sizing: border-box; margin: 0; + border-radius: 6px; padding: 0; color: var(--fg); border: solid 1px var(--panel); @@ -157,9 +202,10 @@ watch(v, () => { caret-color: rgb(225, 228, 232); background-color: transparent; border: 0; + border-radius: 6px; outline: 0; min-width: calc(100% - 24px); - height: calc(100% - 24px); + height: 100%; padding: 12px; line-height: 1.5em; font-size: 1em; diff --git a/packages/frontend/src/components/MkColorInput.vue b/packages/frontend/src/components/MkColorInput.vue index 983a35103c..a7a3eff5af 100644 --- a/packages/frontend/src/components/MkColorInput.vue +++ b/packages/frontend/src/components/MkColorInput.vue @@ -24,8 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onMounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue'; -import { i18n } from '@/i18n.js'; +import { ref, shallowRef, toRefs } from 'vue'; const props = defineProps<{ modelValue: string | null; diff --git a/packages/frontend/src/components/MkCwButton.vue b/packages/frontend/src/components/MkCwButton.vue index 70b7bc8295..4a6d2dfba2 100644 --- a/packages/frontend/src/components/MkCwButton.vue +++ b/packages/frontend/src/components/MkCwButton.vue @@ -17,6 +17,7 @@ import MkButton from '@/components/MkButton.vue'; const props = defineProps<{ modelValue: boolean; text: string | null; + renote: Misskey.entities.Note | null; files: Misskey.entities.DriveFile[]; poll?: { expiresAt: string | null; @@ -41,6 +42,7 @@ const emit = defineEmits<{ const label = computed(() => { return concat([ props.text ? [i18n.t('_cw.chars', { count: props.text.length })] : [], + props.renote ? [i18n.ts.quote] : [], props.files.length !== 0 ? [i18n.t('_cw.files', { count: props.files.length })] : [], props.poll != null ? [i18n.ts.poll] : [], ] as string[][]).join(' / '); diff --git a/packages/frontend/src/components/MkDonation.vue b/packages/frontend/src/components/MkDonation.vue index a2a0b6023b..3a1bab5f98 100644 --- a/packages/frontend/src/components/MkDonation.vue +++ b/packages/frontend/src/components/MkDonation.vue @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </I18n> <div style="margin-top: 0.2em;"> - <MkLink target="_blank" url="https://misskey-hub.net/docs/donate.html">{{ i18n.ts.learnMore }}</MkLink> + <MkLink target="_blank" url="https://misskey-hub.net/docs/for-users/resources/donate/">{{ i18n.ts.learnMore }}</MkLink> </div> </div> <div class="_buttons"> diff --git a/packages/frontend/src/components/MkEmojiEditDialog.vue b/packages/frontend/src/components/MkEmojiEditDialog.vue index 4413ef3650..7b8fa801d3 100644 --- a/packages/frontend/src/components/MkEmojiEditDialog.vue +++ b/packages/frontend/src/components/MkEmojiEditDialog.vue @@ -99,7 +99,7 @@ import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { customEmojiCategories } from '@/custom-emojis.js'; import MkSwitch from '@/components/MkSwitch.vue'; -import { selectFile, selectFiles } from '@/scripts/select-file.js'; +import { selectFile } from '@/scripts/select-file.js'; import MkRolePreview from '@/components/MkRolePreview.vue'; const props = defineProps<{ diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index 92b5388c34..3f8fef6632 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -32,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onMounted, shallowRef, watch, ref } from 'vue'; +import { shallowRef, watch, ref } from 'vue'; import * as Misskey from 'misskey-js'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index b154eb0202..c5be2a2f62 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div ref="root"> +<div> <XBanner v-for="media in mediaList.filter(media => !previewable(media))" :key="media.id" :media="media"/> <div v-if="mediaList.filter(media => previewable(media)).length > 0" :class="$style.container"> <div @@ -27,41 +27,6 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </template> -<script lang="ts"> -/** - * アスペクト比算出のためにHTMLElement.clientWidthを使うが、 - * 大変重たいのでコンテナ要素とメディアリスト幅のペアをキャッシュする - * (タイムラインごとにスクロールコンテナが存在する前提だが……) - */ -const widthCache = new Map<Element, number>(); - -/** - * コンテナ要素がリサイズされたらキャッシュを削除する - */ -const ro = new ResizeObserver(entries => { - for (const entry of entries) { - widthCache.delete(entry.target); - } -}); - -async function getClientWidthWithCache(targetEl: HTMLElement, containerEl: HTMLElement, count = 0) { - if (_DEV_) console.log('getClientWidthWithCache', { targetEl, containerEl, count, cache: widthCache.get(containerEl) }); - if (widthCache.has(containerEl)) return widthCache.get(containerEl)!; - - const width = targetEl.clientWidth; - - if (count <= 10 && width < 64) { - // widthが64未満はおかしいのでリトライする - await new Promise(resolve => setTimeout(resolve, 50)); - return getClientWidthWithCache(targetEl, containerEl, count + 1); - } - - widthCache.set(containerEl, width); - ro.observe(containerEl); - return width; -} -</script> - <script lang="ts" setup> import { computed, onMounted, onUnmounted, shallowRef } from 'vue'; import * as Misskey from 'misskey-js'; @@ -74,15 +39,12 @@ import XVideo from '@/components/MkMediaVideo.vue'; import * as os from '@/os.js'; import { FILE_TYPE_BROWSERSAFE } from '@/const'; import { defaultStore } from '@/store.js'; -import { getScrollContainer, getBodyScrollHeight } from '@/scripts/scroll.js'; const props = defineProps<{ mediaList: Misskey.entities.DriveFile[]; raw?: boolean; }>(); -const root = shallowRef<HTMLDivElement>(); -const container = shallowRef<HTMLElement | null | undefined>(undefined); const gallery = shallowRef<HTMLDivElement>(); const pswpZIndex = os.claimZIndex('middle'); document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); @@ -95,12 +57,8 @@ const popstateHandler = (): void => { } }; -/** - * アスペクト比をmediaListWithOneImageAppearanceに基づいていい感じに調整する - * aspect-ratioではなくheightを使う - */ async function calcAspectRatio() { - if (!gallery.value || !root.value) return; + if (!gallery.value) return; let img = props.mediaList[0]; @@ -109,41 +67,22 @@ async function calcAspectRatio() { return; } - if (!container.value) container.value = getScrollContainer(root.value); - const width = container.value ? await getClientWidthWithCache(root.value, container.value) : root.value.clientWidth; - - const heightMin = (ratio: number) => { - const imgResizeRatio = width / img.properties.width; - const imgDrawHeight = img.properties.height * imgResizeRatio; - const maxHeight = width * ratio; - const height = Math.min(imgDrawHeight, maxHeight); - if (_DEV_) console.log('Image height calculated:', { width, properties: img.properties, imgResizeRatio, imgDrawHeight, maxHeight, height }); - return `${height}px`; - }; + const ratioMax = (ratio: number) => `${Math.max(ratio, img.properties.width / img.properties.height).toString()} / 1`; switch (defaultStore.state.mediaListWithOneImageAppearance) { case '16_9': - gallery.value.style.height = heightMin(9 / 16); + gallery.value.style.aspectRatio = ratioMax(16 / 9); break; case '1_1': - gallery.value.style.height = heightMin(1); + gallery.value.style.aspectRatio = ratioMax(1 / 1); break; case '2_3': - gallery.value.style.height = heightMin(3 / 2); + gallery.value.style.aspectRatio = ratioMax(2 / 3); break; - default: { - const maxHeight = Math.max(64, (container.value ? container.value.clientHeight : getBodyScrollHeight()) * 0.5 || 360); - if (width === 0 || !maxHeight) return; - const imgResizeRatio = width / img.properties.width; - const imgDrawHeight = img.properties.height * imgResizeRatio; - gallery.value.style.height = `${Math.max(64, Math.min(imgDrawHeight, maxHeight))}px`; - gallery.value.style.minHeight = 'initial'; - gallery.value.style.maxHeight = 'initial'; + default: + gallery.value.style.aspectRatio = ''; break; - } } - - gallery.value.style.aspectRatio = 'initial'; } onMounted(() => { diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index c378af6ee6..02add03c40 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-for="(item, i) in items2"> <div v-if="item.type === 'divider'" role="separator" :class="$style.divider"></div> <span v-else-if="item.type === 'label'" role="menuitem" :class="[$style.label, $style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"> - <span>{{ item.text }}</span> + <span style="opacity: 0.7;">{{ item.text }}</span> </span> <span v-else-if="item.type === 'pending'" role="menuitem" :tabindex="i" :class="[$style.pending, $style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"> <span><MkEllipsis/></span> @@ -23,32 +23,44 @@ SPDX-License-Identifier: AGPL-3.0-only <MkA v-else-if="item.type === 'link'" role="menuitem" :to="item.to" :tabindex="i" class="_button" :class="[$style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" @click.passive="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)"> <i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i> <MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/> - <span>{{ item.text }}</span> - <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + <div :class="$style.item_content"> + <span :class="$style.item_content_text">{{ item.text }}</span> + <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + </div> </MkA> <a v-else-if="item.type === 'a'" role="menuitem" :href="item.href" :target="item.target" :download="item.download" :tabindex="i" class="_button" :class="[$style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" @click="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)"> <i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i> - <span>{{ item.text }}</span> - <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + <div :class="$style.item_content"> + <span :class="$style.item_content_text">{{ item.text }}</span> + <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + </div> </a> <button v-else-if="item.type === 'user'" role="menuitem" :tabindex="i" class="_button" :class="[$style.item, { [$style.active]: item.active },{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)"> <MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/> - <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + <div v-if="item.indicate" :class="$style.item_content"> + <span :class="$style.indicator"><i class="_indicatorCircle"></i></span> + </div> </button> <button v-else-if="item.type === 'switch'" role="menuitemcheckbox" :tabindex="i" class="_button" :class="[$style.item, $style.switch, { [$style.switchDisabled]: item.disabled } , { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" @click="switchItem(item)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)"> <MkSwitchButton :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)" model-value/> - <span :class="$style.switchText">{{ item.text }}</span> + <div :class="$style.item_content"> + <span :class="[$style.item_content_text, $style.switchText]">{{ item.text }}</span> + </div> </button> <button v-else-if="item.type === 'parent'" class="_button" role="menuitem" :tabindex="i" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item } , { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" @mouseenter="preferClick ? null : showChildren(item, $event)" @click="!preferClick ? null : showChildren(item, $event)"> <i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i> - <span style="pointer-events: none;">{{ item.text }}</span> - <span :class="$style.caret" style="pointer-events: none;"><i class="ti ti-chevron-right ti-fw"></i></span> + <div :class="$style.item_content"> + <span :class="$style.item_content_text" style="pointer-events: none;">{{ item.text }}</span> + <span :class="$style.caret" style="pointer-events: none;"><i class="ti ti-chevron-right ti-fw"></i></span> + </div> </button> <button v-else :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.danger]: item.danger, [$style.active]: item.active }, { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)"> <i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon, { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"></i> <MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/> - <span>{{ item.text }}</span> - <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + <div :class="$style.item_content"> + <span :class="$style.item_content_text">{{ item.text }}</span> + <span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span> + </div> </button> </template> <span v-if="items2.length === 0" :class="[$style.none, $style.item]"> @@ -230,6 +242,7 @@ onBeforeUnmount(() => { .root { padding: 8px 0; box-sizing: border-box; + max-width: 100vw; min-width: 200px; overflow: auto; overscroll-behavior: contain; @@ -269,7 +282,8 @@ onBeforeUnmount(() => { } .item { - display: block; + display: flex; + align-items: center; position: relative; padding: 5px 16px; width: 100%; @@ -384,10 +398,6 @@ onBeforeUnmount(() => { pointer-events: none; font-size: 0.7em; padding-bottom: 4px; - - > span { - opacity: 0.7; - } } &.pending { @@ -440,6 +450,22 @@ onBeforeUnmount(() => { } } +.item_content { + width: 100%; + max-width: 100vw; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + text-overflow: ellipsis; +} + +.item_content_text { + max-width: calc(100vw - 4rem); + text-overflow: ellipsis; + overflow: hidden; +} + .switch { position: relative; display: flex; @@ -473,6 +499,7 @@ onBeforeUnmount(() => { .icon { margin-right: 8px; + line-height: 1; } .caret { diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index c6c16a9fc6..bde3b8770e 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div style="container-type: inline-size;"> <p v-if="appearNote.cw != null" :class="$style.cw"> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/> - <MkCwButton v-model="showContent" :text="appearNote.text" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;"/> + <MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;"/> </p> <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div :class="$style.text"> @@ -159,7 +159,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import {computed, inject, onMounted, ref, shallowRef, Ref, defineAsyncComponent, watch, provide } from 'vue'; +import {computed, inject, onMounted, ref, shallowRef, Ref, watch, provide } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; import MkNoteSub from '@/components/MkNoteSub.vue'; @@ -236,6 +236,7 @@ if (noteViewInterruptors.length > 0) { const isRenote = ( note.value.renote != null && note.value.text == null && + note.value.cw == null && note.value.fileIds.length === 0 && note.value.poll == null ); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 4decb29cfb..6f671b7310 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -215,11 +215,10 @@ import { useNoteCapture } from '@/scripts/use-note-capture.js'; import { deepClone } from '@/scripts/clone.js'; import { useTooltip } from '@/scripts/use-tooltip.js'; import { claimAchievement } from '@/scripts/achievements.js'; -import { MenuItem } from '@/types/menu.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { showMovedDialog } from '@/scripts/show-moved-dialog.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; -import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import MkPagination from '@/components/MkPagination.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkButton from '@/components/MkButton.vue'; diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 63ab125bb3..ef84aa3393 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -43,7 +43,6 @@ import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; import { userPage } from '@/filters/user.js'; import { checkWordMute } from '@/scripts/check-word-mute.js'; -import { defaultStore } from '@/store.js'; const props = withDefaults(defineProps<{ note: Misskey.entities.Note; diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index fcf4791240..4d422c10ae 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.head"> <MkAvatar v-if="notification.type === 'pollEnded'" :class="$style.icon" :user="notification.note.user" link preview/> <MkAvatar v-else-if="notification.type === 'note'" :class="$style.icon" :user="notification.note.user" link preview/> + <MkAvatar v-else-if="notification.type === 'roleAssigned'" :class="$style.icon" :user="$i" link preview/> <MkAvatar v-else-if="notification.type === 'achievementEarned'" :class="$style.icon" :user="$i" link preview/> <div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div> <div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div> @@ -36,6 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only <i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i> <i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i> <i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i> + <img v-else-if="notification.type === 'roleAssigned'" :src="notification.role.iconUrl" alt=""/> <!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 --> <MkReactionIcon v-else-if="notification.type === 'reaction'" @@ -50,6 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only <header :class="$style.header"> <span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span> <span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span> + <span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span> <span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span> <span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span> <MkA v-else-if="notification.user" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA> @@ -86,6 +89,9 @@ SPDX-License-Identifier: AGPL-3.0-only <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <i class="ti ti-quote" :class="$style.quote"></i> </MkA> + <div v-else-if="notification.type === 'roleAssigned'" :class="$style.text"> + {{ notification.role.name }} + </div> <MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements"> {{ i18n.ts._achievements._types['_' + notification.achievement].title }} </MkA> @@ -130,7 +136,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref, shallowRef } from 'vue'; +import { ref } from 'vue'; import * as Misskey from 'misskey-js'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkFollowButton from '@/components/MkFollowButton.vue'; diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index e560545f92..d8107397e6 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -24,13 +24,12 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, onActivated, watch } from 'vue'; -import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, onActivated } from 'vue'; +import MkPagination from '@/components/MkPagination.vue'; import XNotification from '@/components/MkNotification.vue'; import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; import MkNote from '@/components/MkNote.vue'; import { useStream } from '@/stream.js'; -import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; import { notificationTypes } from '@/const.js'; import { infoImageUrl } from '@/instance.js'; diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 8a15d024ad..8bd9f0af59 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -63,7 +63,8 @@ SPDX-License-Identifier: AGPL-3.0-only <MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo> <input v-show="useCw" ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown"> <div :class="[$style.textOuter, { [$style.withCw]: useCw }]"> - <textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/> + <div v-if="channel" :class="$style.colorBar" :style="{ background: channel.color }"></div> + <textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/> <div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div> </div> <input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags"> @@ -1114,6 +1115,16 @@ defineExpose({ } } +.colorBar { + position: absolute; + top: 0px; + left: 12px; + width: 5px; + height: 100% ; + border-radius: 999px; + pointer-events: none; +} + .submitInner { padding: 0 12px; line-height: 34px; diff --git a/packages/frontend/src/components/MkPullToRefresh.vue b/packages/frontend/src/components/MkPullToRefresh.vue index 44555f2c13..54ef117d77 100644 --- a/packages/frontend/src/components/MkPullToRefresh.vue +++ b/packages/frontend/src/components/MkPullToRefresh.vue @@ -23,8 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onMounted, onUnmounted, watch, ref, shallowRef } from 'vue'; -import { deviceKind } from '@/scripts/device-kind.js'; +import { onMounted, onUnmounted, ref, shallowRef } from 'vue'; import { i18n } from '@/i18n.js'; import { getScrollContainer } from '@/scripts/scroll.js'; diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 8515d7b1c7..24d78d4511 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -115,7 +115,6 @@ import { computed, ref, watch } from 'vue'; import { toUnicode } from 'punycode/'; import MkButton from './MkButton.vue'; import MkInput from './MkInput.vue'; -import MkSwitch from './MkSwitch.vue'; import MkCaptcha, {type Captcha} from '@/components/MkCaptcha.vue'; import * as config from '@/config.js'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue index 6e8ef6389b..61fa30c178 100644 --- a/packages/frontend/src/components/MkSignupDialog.rules.vue +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.basicNotesBeforeCreateAccount }}</template> <template #suffix><i v-if="agreeNote" class="ti ti-check" style="color: var(--success)"></i></template> - <a href="https://misskey-hub.net/docs/notes.html" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }} <i class="ti ti-external-link"></i></a> + <a href="https://misskey-hub.net/docs/for-users/onboarding/warning/" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }} <i class="ti ti-external-link"></i></a> <MkSwitch :modelValue="agreeNote" style="margin-top: 16px;" data-cy-signup-rules-notes-agree @update:modelValue="updateAgreeNote">{{ i18n.ts.agree }}</MkSwitch> </MkFolder> @@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, onMounted, ref, watch } from 'vue'; +import { computed, ref } from 'vue'; import { instance } from '@/instance.js'; import { i18n } from '@/i18n.js'; import MkButton from '@/components/MkButton.vue'; diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 1467049e25..b4fba114a6 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -39,7 +39,6 @@ import XSignup from '@/components/MkSignupDialog.form.vue'; import XServerRules from '@/components/MkSignupDialog.rules.vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import { i18n } from '@/i18n.js'; -import { instance } from '@/instance.js'; const props = withDefaults(defineProps<{ autoSet?: boolean; diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 370894d4f4..438140649e 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -35,7 +35,6 @@ import * as Misskey from 'misskey-js'; import MkMediaList from '@/components/MkMediaList.vue'; import MkPoll from '@/components/MkPoll.vue'; import { i18n } from '@/i18n.js'; -import { $i } from '@/account.js'; import { shouldCollapsed } from '@/scripts/collapsed.js'; const props = defineProps<{ diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue index 23fdd5bfe1..3ee374300a 100644 --- a/packages/frontend/src/components/MkTextarea.vue +++ b/packages/frontend/src/components/MkTextarea.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only :readonly="readonly" :placeholder="placeholder" :pattern="pattern" - :autocomplete="autocomplete" + :autocomplete="props.autocomplete" :spellcheck="spellcheck" @focus="focused = true" @blur="focused = false" @@ -26,8 +26,8 @@ SPDX-License-Identifier: AGPL-3.0-only ></textarea> </div> <div :class="$style.caption"><slot name="caption"></slot></div> - <button style="font-size: 0.85em;" class="_textButton" type="button" @click="preview = !preview">{{ i18n.ts.preview }}</button> - <div v-show="preview" v-panel :class="$style.mfmPreview"> + <button v-if="mfmPreview" style="font-size: 0.85em;" class="_textButton" type="button" @click="preview = !preview">{{ i18n.ts.preview }}</button> + <div v-if="mfmPreview" v-show="preview" v-panel :class="$style.mfmPreview"> <Mfm :text="v"/> </div> @@ -91,6 +91,16 @@ const onKeydown = (ev: KeyboardEvent) => { if (ev.code === 'Enter') { emit('enter'); } + + if (props.code && ev.key === 'Tab') { + const pos = inputEl.value?.selectionStart ?? 0; + const posEnd = inputEl.value?.selectionEnd ?? v.value.length; + v.value = v.value.slice(0, pos) + '\t' + v.value.slice(posEnd); + nextTick(() => { + inputEl.value?.setSelectionRange(pos + 1, pos + 1); + }); + ev.preventDefault(); + } }; const updated = () => { diff --git a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue index 75b917f33c..93181cf2b1 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.divider"></div> <I18n :src="i18n.ts._initialTutorial._timeline.description3" tag="div" style="padding: 0 16px;"> <template #link> - <a href="https://misskey-hub.net/docs/features/timeline.html" target="_blank" class="_link">{{ i18n.ts.help }}</a> + <a href="https://misskey-hub.net/docs/for-users/features/timeline/" target="_blank" class="_link">{{ i18n.ts.help }}</a> </template> </I18n> diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue index e28838425f..963e78a1ff 100644 --- a/packages/frontend/src/components/MkTutorialDialog.vue +++ b/packages/frontend/src/components/MkTutorialDialog.vue @@ -130,7 +130,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div style="font-size: 120%;">{{ i18n.ts._initialTutorial._done.title }}</div> <I18n :src="i18n.ts._initialTutorial._done.description" tag="div" style="padding: 0 16px;"> <template #link> - <a href="https://misskey-hub.net/help.html" target="_blank" class="_link">{{ i18n.ts.help }}</a> + <a href="https://misskey-hub.net/docs/for-users/" target="_blank" class="_link">{{ i18n.ts.help }}</a> </template> </I18n> <div>{{ i18n.t('_initialAccountSetting.haveFun', { name: instance.name ?? host }) }}</div> diff --git a/packages/frontend/src/components/MkUpdated.vue b/packages/frontend/src/components/MkUpdated.vue index 699d7af33e..391733931a 100644 --- a/packages/frontend/src/components/MkUpdated.vue +++ b/packages/frontend/src/components/MkUpdated.vue @@ -27,7 +27,7 @@ const modal = shallowRef<InstanceType<typeof MkModal>>(); const whatIsNew = () => { modal.value.close(); - window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank'); + window.open(`https://misskey-hub.net/docs/releases/#_${version.replace(/\./g, '')}`, '_blank'); }; onMounted(() => { diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue index eaebbf03e7..762b9b4316 100644 --- a/packages/frontend/src/components/MkUserInfo.vue +++ b/packages/frontend/src/components/MkUserInfo.vue @@ -22,10 +22,10 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.statusItem"> <p :class="$style.statusItemLabel">{{ i18n.ts.notes }}</p><span :class="$style.statusItemValue">{{ number(user.notesCount) }}</span> </div> - <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem"> + <div v-if="isFollowingVisibleForMe(user)" :class="$style.statusItem"> <p :class="$style.statusItemLabel">{{ i18n.ts.following }}</p><span :class="$style.statusItemValue">{{ number(user.followingCount) }}</span> </div> - <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem"> + <div v-if="isFollowersVisibleForMe(user)" :class="$style.statusItem"> <p :class="$style.statusItemLabel">{{ i18n.ts.followers }}</p><span :class="$style.statusItemValue">{{ number(user.followersCount) }}</span> </div> </div> @@ -40,7 +40,7 @@ import number from '@/filters/number.js'; import { userPage } from '@/filters/user.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; -import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; +import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; defineProps<{ user: Misskey.entities.UserDetailed; diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index b703369433..df8252fb14 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -35,11 +35,11 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.statusItemLabel">{{ i18n.ts.notes }}</div> <div>{{ number(user.notesCount) }}</div> </div> - <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem"> + <div v-if="isFollowingVisibleForMe(user)" :class="$style.statusItem"> <div :class="$style.statusItemLabel">{{ i18n.ts.following }}</div> <div>{{ number(user.followingCount) }}</div> </div> - <div v-if="isFfVisibleForMe(user)" :class="$style.statusItem"> + <div v-if="isFollowersVisibleForMe(user)" :class="$style.statusItem"> <div :class="$style.statusItemLabel">{{ i18n.ts.followers }}</div> <div>{{ number(user.followersCount) }}</div> </div> @@ -65,7 +65,7 @@ import number from '@/filters/number.js'; import { i18n } from '@/i18n.js'; import { defaultStore } from '@/store.js'; import { $i } from '@/account.js'; -import { isFfVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; +import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; const props = defineProps<{ showing: boolean; diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue index 4ecca7334c..5f3f5b81dd 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue @@ -34,15 +34,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, ref, watch } from 'vue'; -import { instance } from '@/instance.js'; import { i18n } from '@/i18n.js'; -import MkButton from '@/components/MkButton.vue'; import MkFolder from '@/components/MkFolder.vue'; import XUser from '@/components/MkUserSetupDialog.User.vue'; -import MkInfo from '@/components/MkInfo.vue'; -import * as os from '@/os.js'; -import { $i } from '@/account.js'; import MkPagination from '@/components/MkPagination.vue'; const pinnedUsers = { endpoint: 'pinned-users', noPaging: true }; diff --git a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue index 4bca72511d..ecdfbb4969 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue @@ -44,14 +44,12 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, ref, watch } from 'vue'; -import { instance } from '@/instance.js'; +import { ref, watch } from 'vue'; import { i18n } from '@/i18n.js'; import MkSwitch from '@/components/MkSwitch.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkFolder from '@/components/MkFolder.vue'; import * as os from '@/os.js'; -import { $i } from '@/account.js'; const isLocked = ref(false); const hideOnlineStatus = ref(false); diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index 8de9bbdbb1..37aa677b44 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -30,8 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, ref, watch } from 'vue'; -import { instance } from '@/instance.js'; +import { ref, watch } from 'vue'; import { i18n } from '@/i18n.js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; diff --git a/packages/frontend/src/components/MkUserSetupDialog.User.vue b/packages/frontend/src/components/MkUserSetupDialog.User.vue index 4fbaf75454..49476c7364 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.User.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.User.vue @@ -29,7 +29,6 @@ import * as Misskey from 'misskey-js'; import { ref } from 'vue'; import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n.js'; -import { $i } from '@/account.js'; import * as os from '@/os.js'; const props = defineProps<{ diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index 26f50b4738..b8e659aa3e 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -53,7 +53,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import * as Misskey from 'misskey-js'; -import XTimeline from './welcome.timeline.vue'; import XSigninDialog from '@/components/MkSigninDialog.vue'; import XSignupDialog from '@/components/MkSignupDialog.vue'; import MkButton from '@/components/MkButton.vue'; @@ -63,7 +62,6 @@ import { instanceName } from '@/config.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; -import number from '@/filters/number.js'; import MkNumber from '@/components/MkNumber.vue'; import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue'; @@ -125,13 +123,13 @@ function showMenu(ev) { text: i18n.ts.help, icon: 'ti ti-help-circle', action: () => { - window.open('https://misskey-hub.net/help.md', '_blank', 'noopener'); + window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener'); }, }], ev.currentTarget ?? ev.target); } function exploreOtherServers() { - window.open('https://join.misskey.page/instances', '_blank', 'noopener'); + window.open('https://misskey-hub.net/servers/', '_blank', 'noopener'); } </script> diff --git a/packages/frontend/src/components/form/suspense.vue b/packages/frontend/src/components/form/suspense.vue index e3db639ff0..bfddac7523 100644 --- a/packages/frontend/src/components/form/suspense.vue +++ b/packages/frontend/src/components/form/suspense.vue @@ -21,7 +21,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch } from 'vue'; import MkButton from '@/components/MkButton.vue'; -import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; const props = defineProps<{ diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue index 5552e96ee0..d34f47a68a 100644 --- a/packages/frontend/src/components/global/MkA.vue +++ b/packages/frontend/src/components/global/MkA.vue @@ -14,7 +14,6 @@ import { computed } from 'vue'; import * as os from '@/os.js'; import copyToClipboard from '@/scripts/copy-to-clipboard.js'; import { url } from '@/config.js'; -import { popout as popout_ } from '@/scripts/popout.js'; import { i18n } from '@/i18n.js'; import { useRouter } from '@/router.js'; diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts index 360bc88b4a..5ae45ec58f 100644 --- a/packages/frontend/src/components/global/MkAd.stories.impl.ts +++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts @@ -4,11 +4,8 @@ */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ -import { expect } from '@storybook/jest'; -import { userEvent, waitFor, within } from '@storybook/testing-library'; import { StoryObj } from '@storybook/vue3'; import MkAd from './MkAd.vue'; -import { i18n } from '@/i18n.js'; let lock: Promise<undefined> | undefined; diff --git a/packages/frontend/src/components/global/MkLazy.vue b/packages/frontend/src/components/global/MkLazy.vue new file mode 100644 index 0000000000..6d7ff4ca49 --- /dev/null +++ b/packages/frontend/src/components/global/MkLazy.vue @@ -0,0 +1,53 @@ +<!-- +SPDX-FileCopyrightText: syuilo and other misskey contributors +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div ref="rootEl" :class="$style.root"> + <div v-if="!showing" :class="$style.placeholder"></div> + <slot v-else></slot> +</div> +</template> + +<script lang="ts" setup> +import { nextTick, onMounted, onActivated, onBeforeUnmount, ref, shallowRef } from 'vue'; + +const rootEl = shallowRef<HTMLDivElement>(); +const showing = ref(false); + +const observer = new IntersectionObserver( + (entries) => { + if (entries.some((entry) => entry.isIntersecting)) { + showing.value = true; + } + }, +); + +onMounted(() => { + nextTick(() => { + observer.observe(rootEl.value!); + }); +}); + +onActivated(() => { + nextTick(() => { + observer.observe(rootEl.value!); + }); +}); + +onBeforeUnmount(() => { + observer.disconnect(); +}); +</script> + +<style lang="scss" module> +.root { + display: block; +} + +.placeholder { + display: block; + min-height: 150px; +} +</style> diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 301e691fa0..8624aebdcf 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -53,7 +53,7 @@ import { PageHeaderItem } from '@/types/page-header.js'; const props = withDefaults(defineProps<{ tabs?: Tab[]; tab?: string; - actions?: PageHeaderItem[]; + actions?: PageHeaderItem[] | null; thin?: boolean; displayMyAvatar?: boolean; }>(), { diff --git a/packages/frontend/src/components/global/MkUserName.stories.impl.ts b/packages/frontend/src/components/global/MkUserName.stories.impl.ts index 8c24a4819f..01455e492d 100644 --- a/packages/frontend/src/components/global/MkUserName.stories.impl.ts +++ b/packages/frontend/src/components/global/MkUserName.stories.impl.ts @@ -5,7 +5,6 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { expect } from '@storybook/jest'; -import { userEvent, within } from '@storybook/testing-library'; import { StoryObj } from '@storybook/vue3'; import { userDetailed } from '../../../.storybook/fakes'; import MkUserName from './MkUserName.vue'; diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 48af4754d7..517b00dfbb 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -24,6 +24,7 @@ import MkAd from './global/MkAd.vue'; import MkPageHeader from './global/MkPageHeader.vue'; import MkSpacer from './global/MkSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; +import MkLazy from './global/MkLazy.vue'; export default function(app: App) { for (const [key, value] of Object.entries(components)) { @@ -51,6 +52,7 @@ export const components = { MkPageHeader: MkPageHeader, MkSpacer: MkSpacer, MkStickyContainer: MkStickyContainer, + MkLazy: MkLazy, }; declare module '@vue/runtime-core' { @@ -74,5 +76,6 @@ declare module '@vue/runtime-core' { MkPageHeader: typeof MkPageHeader; MkSpacer: typeof MkSpacer; MkStickyContainer: typeof MkStickyContainer; + MkLazy: typeof MkLazy; } } diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue index e0f1a4af90..1ab2c0f3c3 100644 --- a/packages/frontend/src/components/page/page.text.vue +++ b/packages/frontend/src/components/page/page.text.vue @@ -16,7 +16,6 @@ import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; import { TextBlock } from './block.type'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; -import { $i } from '@/account.js'; const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue')); diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index ab37ca69ad..94ca7bdf04 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -10,7 +10,6 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onMounted, nextTick } from 'vue'; import * as Misskey from 'misskey-js'; import XBlock from './page.block.vue'; diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index 7409f1f604..b2b6c663d5 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -54,7 +54,21 @@ https://github.com/sindresorhus/file-type/blob/main/core.js https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers */ -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app'] as const; +export const notificationTypes = [ + 'note', + 'follow', + 'mention', + 'reply', + 'renote', + 'quote', + 'reaction', + 'pollEnded', + 'receiveFollowRequest', + 'followRequestAccepted', + 'roleAssigned', + 'achievementEarned', + 'app', +] as const; export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const; export const ROLE_POLICIES = [ diff --git a/packages/frontend/src/emojilist.json b/packages/frontend/src/emojilist.json index fe1d884ebe..75d5c34d71 100644 --- a/packages/frontend/src/emojilist.json +++ b/packages/frontend/src/emojilist.json @@ -103,6 +103,7 @@ ["🫥", "dotted_line_face", 0], ["🫤", "face_with_diagonal_mouth", 0], ["🥹", "face_holding_back_tears", 0], + ["🫨", "shaking_face", 0], ["💩", "poop", 0], ["😈", "smiling_imp", 0], ["👿", "imp", 0], @@ -132,6 +133,8 @@ ["✊", "fist", 1], ["🤛", "fist_left", 1], ["🤜", "fist_right", 1], + ["🫷", "leftwards_pushing_hand", 1], + ["🫸", "rightwards_pushing_hand", 1], ["✌", "v", 1], ["👌", "ok_hand", 1], ["✋", "raised_hand", 1], @@ -453,6 +456,7 @@ ["🐸", "frog", 2], ["🦑", "squid", 2], ["🐙", "octopus", 2], + ["🪼", "jellyfish", 2], ["🦐", "shrimp", 2], ["🐵", "monkey_face", 2], ["🦍", "gorilla", 2], @@ -466,7 +470,9 @@ ["🐤", "baby_chick", 2], ["🐣", "hatching_chick", 2], ["🐥", "hatched_chick", 2], + ["🪿", "goose", 2], ["🦆", "duck", 2], + ["🐦⬛", "black_bird", 2], ["🦅", "eagle", 2], ["🦉", "owl", 2], ["🦇", "bat", 2], @@ -474,6 +480,7 @@ ["🐗", "boar", 2], ["🐴", "horse", 2], ["🦄", "unicorn", 2], + ["🫎", "moose", 2], ["🐝", "honeybee", 2], ["🐛", "bug", 2], ["🦋", "butterfly", 2], @@ -516,6 +523,7 @@ ["🐐", "goat", 2], ["🐏", "ram", 2], ["🐑", "sheep", 2], + ["🫏", "donkey", 2], ["🐎", "racehorse", 2], ["🐖", "pig2", 2], ["🐀", "rat", 2], @@ -546,6 +554,7 @@ ["🐻❄️", "polar_bear", 2], ["🦤", "dodo", 2], ["🪶", "feather", 2], + ["🪽", "wing", 2], ["🦭", "seal", 2], ["🐾", "paw_prints", 2], ["🐉", "dragon", 2], @@ -576,6 +585,7 @@ ["🌻", "sunflower", 2], ["🌹", "rose", 2], ["🥀", "wilted_flower", 2], + ["🪻", "hyacinth", 2], ["🌷", "tulip", 2], ["🌼", "blossom", 2], ["🌸", "cherry_blossom", 2], @@ -655,6 +665,7 @@ ["🥝", "kiwi_fruit", 3], ["🥭", "mango", 3], ["🥑", "avocado", 3], + ["🫛", "pea_pod", 3], ["🥦", "broccoli", 3], ["🍅", "tomato", 3], ["🍆", "eggplant", 3], @@ -668,6 +679,7 @@ ["🌽", "corn", 3], ["🥬", "leafy_greens", 3], ["🍠", "sweet_potato", 3], + ["🫚", "ginger_root", 3], ["🥜", "peanuts", 3], ["🧄", "garlic", 3], ["🧅", "onion", 3], @@ -850,9 +862,11 @@ ["🎧", "headphones", 4], ["🎼", "musical_score", 4], ["🎹", "musical_keyboard", 4], + ["🪇", "maracas", 4], ["🥁", "drum", 4], ["🎷", "saxophone", 4], ["🎺", "trumpet", 4], + ["🪈", "flute", 4], ["🎸", "guitar", 4], ["🎻", "violin", 4], ["🪕", "banjo", 4], @@ -1108,6 +1122,7 @@ ["🩹", "adhesive_bandage", 6], ["🩺", "stethoscope", 6], ["🪒", "razor", 6], + ["🪮", "hair_pick", 6], ["🩻", "xray", 6], ["🩼", "crutch", 6], ["🧬", "dna", 6], @@ -1156,6 +1171,7 @@ ["🎊", "confetti_ball", 6], ["🎉", "tada", 6], ["🎎", "dolls", 6], + ["🪭", "folding_hand_fan", 6], ["🎐", "wind_chime", 6], ["🎌", "crossed_flags", 6], ["🏮", "izakaya_lantern", 6], @@ -1237,14 +1253,17 @@ ["🪧", "placard", 6], ["💯", "100", 7], ["🔢", "1234", 7], + ["🩷", "pink_heart", 7], ["❤️", "heart", 7], ["🧡", "orange_heart", 7], ["💛", "yellow_heart", 7], ["💚", "green_heart", 7], + ["🩵", "light_blue_heart", 7], ["💙", "blue_heart", 7], ["💜", "purple_heart", 7], ["🤎", "brown_heart", 7], ["🖤", "black_heart", 7], + ["🩶", "grey_heart", 7], ["🤍", "white_heart", 7], ["💔", "broken_heart", 7], ["❣", "heavy_heart_exclamation", 7], @@ -1263,6 +1282,7 @@ ["☪", "star_and_crescent", 7], ["🕉", "om", 7], ["☸", "wheel_of_dharma", 7], + ["🪯", "khanda", 7], ["✡", "star_of_david", 7], ["🔯", "six_pointed_star", 7], ["🕎", "menorah", 7], @@ -1358,6 +1378,7 @@ ["🛃", "customs", 7], ["🛄", "baggage_claim", 7], ["🛅", "left_luggage", 7], + ["🛜", "wireless", 7], ["♿", "wheelchair", 7], ["🚭", "no_smoking", 7], ["🚾", "wc", 7], diff --git a/packages/frontend/src/index.html b/packages/frontend/src/index.html index 49189914a0..8de01e4802 100644 --- a/packages/frontend/src/index.html +++ b/packages/frontend/src/index.html @@ -12,16 +12,17 @@ <html> <head> <meta charset="UTF-8" /> - <title>misskey</title> + <title>[DEV] Loading...</title> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; worker-src 'self'; - script-src 'self'; + script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000; - media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;" + media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000; + connect-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;" /> <meta property="og:site_name" content="[DEV BUILD] Misskey" /> <meta name="viewport" content="width=device-width, initial-scale=1"> diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts index 0d73885b68..1ef115978e 100644 --- a/packages/frontend/src/local-storage.ts +++ b/packages/frontend/src/local-storage.ts @@ -35,7 +35,8 @@ type Keys = `themes:${string}` | `aiscript:${string}` | 'lastEmojisFetchedAt' | // DEPRECATED, stored in indexeddb (13.9.0~) - 'emojis' // DEPRECATED, stored in indexeddb (13.9.0~); + 'emojis' | // DEPRECATED, stored in indexeddb (13.9.0~); + `channelLastReadedAt:${string}` export const miLocalStorage = { getItem: (key: Keys): string | null => window.localStorage.getItem(key), diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index c245b9b6cb..20c65f4541 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button> </div> <div style="text-align: center;"> - {{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a> + {{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/about-misskey/" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a> </div> <div v-if="$i != null" style="text-align: center;"> <MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Misskey</MkButton> @@ -139,73 +139,73 @@ import { $i } from '@/account.js'; const patronsWithIcon = [{ name: 'カイヤン', - icon: 'https://misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg', + icon: 'https://assets.misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg', }, { name: 'だれかさん', - icon: 'https://misskey-hub.net/patrons/f7409b5e5a88477a9b9d740c408de125.jpg', + icon: 'https://assets.misskey-hub.net/patrons/f7409b5e5a88477a9b9d740c408de125.jpg', }, { name: 'narazaka', - icon: 'https://misskey-hub.net/patrons/e3affff31ffb4877b1196c7360abc3e5.jpg', + icon: 'https://assets.misskey-hub.net/patrons/e3affff31ffb4877b1196c7360abc3e5.jpg', }, { name: 'ひとぅ', - icon: 'https://misskey-hub.net/patrons/8cc0d0a0a6d84c88bca1aedabf6ed5ab.jpg', + icon: 'https://assets.misskey-hub.net/patrons/8cc0d0a0a6d84c88bca1aedabf6ed5ab.jpg', }, { name: 'ぱーこ', - icon: 'https://misskey-hub.net/patrons/79c6602ffade489e8df2fcf2c2bc5d9d.jpg', + icon: 'https://assets.misskey-hub.net/patrons/79c6602ffade489e8df2fcf2c2bc5d9d.jpg', }, { name: 'わっほー☆', - icon: 'https://misskey-hub.net/patrons/d31d5d13924443a082f3da7966318a0a.jpg', + icon: 'https://assets.misskey-hub.net/patrons/d31d5d13924443a082f3da7966318a0a.jpg', }, { name: 'mollinaca', - icon: 'https://misskey-hub.net/patrons/ceb36b8f66e549bdadb3b90d5da62314.jpg', + icon: 'https://assets.misskey-hub.net/patrons/ceb36b8f66e549bdadb3b90d5da62314.jpg', }, { name: '坂本龍', - icon: 'https://misskey-hub.net/patrons/a631cf8b490145cf8dbbe4e7508cfbc2.jpg', + icon: 'https://assets.misskey-hub.net/patrons/a631cf8b490145cf8dbbe4e7508cfbc2.jpg', }, { name: 'takke', - icon: 'https://misskey-hub.net/patrons/6c3327e626c046f2914fbcd9f7557935.jpg', + icon: 'https://assets.misskey-hub.net/patrons/6c3327e626c046f2914fbcd9f7557935.jpg', }, { name: 'ぺんぎん', - icon: 'https://misskey-hub.net/patrons/6a652e0534ff4cb1836e7ce4968d76a7.jpg', + icon: 'https://assets.misskey-hub.net/patrons/6a652e0534ff4cb1836e7ce4968d76a7.jpg', }, { name: 'かみらえっと', - icon: 'https://misskey-hub.net/patrons/be1326bda7d940a482f3758ffd9ffaf6.jpg', + icon: 'https://assets.misskey-hub.net/patrons/be1326bda7d940a482f3758ffd9ffaf6.jpg', }, { name: 'へてて', - icon: 'https://misskey-hub.net/patrons/0431eacd7c6843d09de8ea9984307e86.jpg', + icon: 'https://assets.misskey-hub.net/patrons/0431eacd7c6843d09de8ea9984307e86.jpg', }, { name: 'spinlock', - icon: 'https://misskey-hub.net/patrons/6a1cebc819d540a78bf20e9e3115baa8.jpg', + icon: 'https://assets.misskey-hub.net/patrons/6a1cebc819d540a78bf20e9e3115baa8.jpg', }, { name: 'じゅくま', - icon: 'https://misskey-hub.net/patrons/3e56bdac69dd42f7a06e0f12cf2fc895.jpg', + icon: 'https://assets.misskey-hub.net/patrons/3e56bdac69dd42f7a06e0f12cf2fc895.jpg', }, { name: '清遊あみ', - icon: 'https://misskey-hub.net/patrons/de25195b88e940a388388bea2e7637d8.jpg', + icon: 'https://assets.misskey-hub.net/patrons/de25195b88e940a388388bea2e7637d8.jpg', }, { name: 'Nagi8410', - icon: 'https://misskey-hub.net/patrons/31b102ab4fc540ed806b0461575d38be.jpg', + icon: 'https://assets.misskey-hub.net/patrons/31b102ab4fc540ed806b0461575d38be.jpg', }, { name: '山岡士郎', - icon: 'https://misskey-hub.net/patrons/84b9056341684266bb1eda3e680d094d.jpg', + icon: 'https://assets.misskey-hub.net/patrons/84b9056341684266bb1eda3e680d094d.jpg', }, { name: 'よもやまたろう', - icon: 'https://misskey-hub.net/patrons/4273c9cce50d445f8f7d0f16113d6d7f.jpg', + icon: 'https://assets.misskey-hub.net/patrons/4273c9cce50d445f8f7d0f16113d6d7f.jpg', }, { name: '花咲ももか', - icon: 'https://misskey-hub.net/patrons/8c9b2b9128cb4fee99f04bb4f86f2efa.jpg', + icon: 'https://assets.misskey-hub.net/patrons/8c9b2b9128cb4fee99f04bb4f86f2efa.jpg', }, { name: 'カガミ', - icon: 'https://misskey-hub.net/patrons/226ea3a4617749548580ec2d9a263e24.jpg', + icon: 'https://assets.misskey-hub.net/patrons/226ea3a4617749548580ec2d9a263e24.jpg', }, { name: 'フランギ・シュウ', - icon: 'https://misskey-hub.net/patrons/3016d37e35f3430b90420176c912d304.jpg', + icon: 'https://assets.misskey-hub.net/patrons/3016d37e35f3430b90420176c912d304.jpg', }, { name: '百日紅', - icon: 'https://misskey-hub.net/patrons/302dce2898dd457ba03c3f7dc037900b.jpg', + icon: 'https://assets.misskey-hub.net/patrons/302dce2898dd457ba03c3f7dc037900b.jpg', }, { name: 'taichan', - icon: 'https://misskey-hub.net/patrons/f981ab0159fb4e2c998e05f7263e1cd9.png', + icon: 'https://assets.misskey-hub.net/patrons/f981ab0159fb4e2c998e05f7263e1cd9.png', }]; const patrons = [ diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 4ad8cc58c5..a614ba73d2 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -220,12 +220,12 @@ import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue'; import MkInfo from '@/components/MkInfo.vue'; import * as os from '@/os.js'; import { url } from '@/config.js'; -import { userPage, acct } from '@/filters/user.js'; +import { acct } from '@/filters/user.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { i18n } from '@/i18n.js'; import { iAmAdmin, $i } from '@/account.js'; import MkRolePreview from '@/components/MkRolePreview.vue'; -import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import MkPagination from '@/components/MkPagination.vue'; const props = withDefaults(defineProps<{ userId: string; diff --git a/packages/frontend/src/pages/admin/branding.vue b/packages/frontend/src/pages/admin/branding.vue index 28109cfd2d..e09f68f6e4 100644 --- a/packages/frontend/src/pages/admin/branding.vue +++ b/packages/frontend/src/pages/admin/branding.vue @@ -97,11 +97,8 @@ SPDX-License-Identifier: AGPL-3.0-only import { ref, computed } from 'vue'; import JSON5 from 'json5'; import XHeader from './_header_.vue'; -import MkSwitch from '@/components/MkSwitch.vue'; import MkInput from '@/components/MkInput.vue'; import MkTextarea from '@/components/MkTextarea.vue'; -import FormSection from '@/components/form/section.vue'; -import FormSplit from '@/components/form/split.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os.js'; import { instance, fetchInstance } from '@/instance.js'; diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index a64dad3164..f6c0b29403 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -64,8 +64,6 @@ import XHeader from './_header_.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkInput from '@/components/MkInput.vue'; import MkTextarea from '@/components/MkTextarea.vue'; -import FormSection from '@/components/form/section.vue'; -import FormSplit from '@/components/form/split.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os.js'; import { fetchInstance } from '@/instance.js'; diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index fe825613fa..699b3c425a 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -123,9 +123,7 @@ SPDX-License-Identifier: AGPL-3.0-only import * as Misskey from 'misskey-js'; import { CodeDiff } from 'v-code-diff'; import JSON5 from 'json5'; -import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; -import { dateString } from '@/filters/date.js'; import MkFolder from '@/components/MkFolder.vue'; const props = defineProps<{ diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index c11cc24b4f..9aa7d8dd3c 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -73,7 +73,7 @@ import { useRouter } from '@/router.js'; import MkButton from '@/components/MkButton.vue'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkInfo from '@/components/MkInfo.vue'; -import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import MkPagination from '@/components/MkPagination.vue'; import { infoImageUrl } from '@/instance.js'; const router = useRouter(); diff --git a/packages/frontend/src/pages/ads.vue b/packages/frontend/src/pages/ads.vue index ee58049554..9e85e81f19 100644 --- a/packages/frontend/src/pages/ads.vue +++ b/packages/frontend/src/pages/ads.vue @@ -16,8 +16,6 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, watch } from 'vue'; -import * as os from '@/os.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; diff --git a/packages/frontend/src/pages/avatar-decorations.vue b/packages/frontend/src/pages/avatar-decorations.vue index b9edb18d10..9dedbccedc 100644 --- a/packages/frontend/src/pages/avatar-decorations.vue +++ b/packages/frontend/src/pages/avatar-decorations.vue @@ -38,9 +38,6 @@ import { ref, computed } from 'vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkTextarea from '@/components/MkTextarea.vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkRadios from '@/components/MkRadios.vue'; -import MkInfo from '@/components/MkInfo.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 698f7fa383..421895ea6c 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only <XChannelFollowButton :channel="channel" :full="true" :class="$style.subscribe"/> <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton> <MkButton v-else v-tooltip="i18n.ts.favorite" asLike class="button" rounded :class="$style.favorite" @click="favorite()"><i class="ti ti-star"></i></MkButton> - <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" :class="$style.banner"> + <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : undefined }" :class="$style.banner"> <div :class="$style.bannerStatus"> <div><i class="ti ti-users ti-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> <div><i class="ti ti-pencil ti-fw"></i><I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> @@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkFoldableSection> <template #header><i class="ti ti-pin ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedNotes }}</template> - <div v-if="channel.pinnedNotes.length > 0" class="_gaps"> + <div v-if="channel.pinnedNotes && channel.pinnedNotes.length > 0" class="_gaps"> <MkNote v-for="note in channel.pinnedNotes" :key="note.id" class="_panel" :note="note"/> </div> </MkFoldableSection> @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only <!-- スマホ・タブレットの場合、キーボードが表示されると投稿が見づらくなるので、デスクトップ場合のみ自動でフォーカスを当てる --> <MkPostForm v-if="$i && defaultStore.reactiveState.showFixedPostFormInChannel.value" :channel="channel" class="post-form _panel" fixed :autofocus="deviceKind === 'desktop'"/> - <MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after"/> + <MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/> </div> <div v-else-if="tab === 'featured'"> <MkNotes :pagination="featuredPagination"/> @@ -69,6 +69,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, watch, ref } from 'vue'; +import * as Misskey from 'misskey-js'; import MkPostForm from '@/components/MkPostForm.vue'; import MkTimeline from '@/components/MkTimeline.vue'; import XChannelFollowButton from '@/components/MkChannelFollowButton.vue'; @@ -89,6 +90,7 @@ import MkFoldableSection from '@/components/MkFoldableSection.vue'; import { PageHeaderItem } from '@/types/page-header.js'; import { isSupportShare } from '@/scripts/navigator.js'; import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { miLocalStorage } from '@/local-storage.js'; const router = useRouter(); @@ -97,7 +99,7 @@ const props = defineProps<{ }>(); const tab = ref('overview'); -const channel = ref(null); +const channel = ref<Misskey.entities.Channel | null>(null); const favorited = ref(false); const searchQuery = ref(''); const searchPagination = ref(); @@ -114,14 +116,23 @@ watch(() => props.channelId, async () => { channel.value = await os.api('channels/show', { channelId: props.channelId, }); - favorited.value = channel.value.isFavorited; + favorited.value = channel.value.isFavorited ?? false; if (favorited.value || channel.value.isFollowing) { tab.value = 'timeline'; } + + if ((favorited.value || channel.value.isFollowing) && channel.value.lastNotedAt) { + const lastReadedAt: number = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.value.id}`) ?? 0; + const lastNotedAt = Date.parse(channel.value.lastNotedAt); + + if (lastNotedAt > lastReadedAt) { + miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.value.id}`, lastNotedAt); + } + } }, { immediate: true }); function edit() { - router.push(`/channels/${channel.value.id}/edit`); + router.push(`/channels/${channel.value?.id}/edit`); } function openPostForm() { @@ -131,6 +142,8 @@ function openPostForm() { } function favorite() { + if (!channel.value) return; + os.apiWithDialog('channels/favorite', { channelId: channel.value.id, }).then(() => { @@ -139,6 +152,8 @@ function favorite() { } async function unfavorite() { + if (!channel.value) return; + const confirm = await os.confirm({ type: 'warning', text: i18n.ts.unfavoriteConfirm, @@ -152,6 +167,8 @@ async function unfavorite() { } async function search() { + if (!channel.value) return; + const query = searchQuery.value.toString().trim(); if (query == null) return; @@ -176,6 +193,10 @@ const headerActions = computed(() => { icon: 'ti ti-link', text: i18n.ts.copyUrl, handler: async (): Promise<void> => { + if (!channel.value) { + console.warn('failed to copy channel URL. channel.value is null.'); + return; + } copyToClipboard(`${url}/channels/${channel.value.id}`); os.success(); }, @@ -186,9 +207,14 @@ const headerActions = computed(() => { icon: 'ti ti-share', text: i18n.ts.share, handler: async (): Promise<void> => { + if (!channel.value) { + console.warn('failed to share channel. channel.value is null.'); + return; + } + navigator.share({ title: channel.value.name, - text: channel.value.description, + text: channel.value.description ?? undefined, url: `${url}/channels/${channel.value.id}`, }); }, diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue index 75d1fad212..f6d7468a1e 100644 --- a/packages/frontend/src/pages/custom-emojis-manager.vue +++ b/packages/frontend/src/pages/custom-emojis-manager.vue @@ -40,11 +40,9 @@ const add = async (ev: MouseEvent) => { os.popup(defineAsyncComponent(() => import('@/components/MkEmojiEditDialog.vue')), { }, { done: result => { - //TODO: emitにして追加を反映 - // if (result.created) { - // emojisPaginationComponent.value.prepend(result.created); - // emojisPaginationComponent.value.reload(); - // } + if (result.created) { + emojisPaginationComponent.value.prepend(result.created); + } }, }, 'closed'); }; diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index cfda4d6556..67a655b677 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -15,9 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts._play.summary }}</template> </MkTextarea> <MkButton primary @click="selectPreset">{{ i18n.ts.selectFromPresets }}<i class="ti ti-chevron-down"></i></MkButton> - <MkTextarea v-model="script" class="_monospace" tall spellcheck="false"> + <MkCodeEditor v-model="script" lang="is"> <template #label>{{ i18n.ts._play.script }}</template> - </MkTextarea> + </MkCodeEditor> <div class="_buttons"> <MkButton primary @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> <MkButton @click="show"><i class="ti ti-eye"></i> {{ i18n.ts.show }}</MkButton> @@ -40,6 +40,7 @@ import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkTextarea from '@/components/MkTextarea.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import MkInput from '@/components/MkInput.vue'; import MkSelect from '@/components/MkSelect.vue'; import { useRouter } from '@/router.js'; diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue index 0ac95ca282..8c5188a1e9 100644 --- a/packages/frontend/src/pages/flash/flash.vue +++ b/packages/frontend/src/pages/flash/flash.vue @@ -165,12 +165,8 @@ async function run() { return new Promise(ok => { os.inputText({ title: q, - }).then(({ canceled, result: a }) => { - if (canceled) { - ok(''); - } else { - ok(a); - } + }).then(({ result: a }) => { + ok(a ?? ''); }); }); }, diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue index 3c6b0750de..cf9da02868 100644 --- a/packages/frontend/src/pages/my-lists/list.vue +++ b/packages/frontend/src/pages/my-lists/list.vue @@ -68,7 +68,7 @@ import MkInput from '@/components/MkInput.vue'; import { userListsCache } from '@/cache.js'; import { $i } from '@/account.js'; import { defaultStore } from '@/store.js'; -import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import MkPagination from '@/components/MkPagination.vue'; const { enableInfiniteScroll, diff --git a/packages/frontend/src/pages/page-editor/page-editor.container.vue b/packages/frontend/src/pages/page-editor/page-editor.container.vue index c1bc0c61c9..9b0dce820c 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.container.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.container.vue @@ -29,7 +29,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { i18n } from '@/i18n.js'; const props = withDefaults(defineProps<{ expanded?: boolean; diff --git a/packages/frontend/src/pages/registry.value.vue b/packages/frontend/src/pages/registry.value.vue index 29406ec83c..8efc0e0504 100644 --- a/packages/frontend/src/pages/registry.value.vue +++ b/packages/frontend/src/pages/registry.value.vue @@ -26,9 +26,9 @@ SPDX-License-Identifier: AGPL-3.0-only </MkKeyValue> </FormSplit> - <MkTextarea v-model="valueForEditor" tall class="_monospace"> + <MkCodeEditor v-model="valueForEditor" lang="json5"> <template #label>{{ i18n.ts.value }} (JSON)</template> - </MkTextarea> + </MkCodeEditor> <MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> @@ -52,7 +52,7 @@ import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkButton from '@/components/MkButton.vue'; import MkKeyValue from '@/components/MkKeyValue.vue'; -import MkTextarea from '@/components/MkTextarea.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import FormSplit from '@/components/form/split.vue'; import FormInfo from '@/components/MkInfo.vue'; diff --git a/packages/frontend/src/pages/search.note.vue b/packages/frontend/src/pages/search.note.vue index 3e74a6f591..38692c4de3 100644 --- a/packages/frontend/src/pages/search.note.vue +++ b/packages/frontend/src/pages/search.note.vue @@ -42,18 +42,14 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, onMounted, ref } from 'vue'; +import { ref } from 'vue'; import MkNotes from '@/components/MkNotes.vue'; import MkInput from '@/components/MkInput.vue'; -import MkRadios from '@/components/MkRadios.vue'; import MkButton from '@/components/MkButton.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; -import { $i } from '@/account.js'; -import { instance } from '@/instance.js'; -import MkInfo from '@/components/MkInfo.vue'; import { useRouter } from '@/router.js'; import MkFolder from '@/components/MkFolder.vue'; diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue index 39707e634c..0d978e4107 100644 --- a/packages/frontend/src/pages/search.user.vue +++ b/packages/frontend/src/pages/search.user.vue @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, defineAsyncComponent, onMounted, ref } from 'vue'; +import { ref } from 'vue'; import MkUserList from '@/components/MkUserList.vue'; import MkInput from '@/components/MkInput.vue'; import MkRadios from '@/components/MkRadios.vue'; @@ -33,9 +33,6 @@ import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; -import { $i } from '@/account.js'; -import { instance } from '@/instance.js'; -import MkInfo from '@/components/MkInfo.vue'; import { useRouter } from '@/router.js'; const router = useRouter(); diff --git a/packages/frontend/src/pages/search.vue b/packages/frontend/src/pages/search.vue index c47414e573..9d5e5697ce 100644 --- a/packages/frontend/src/pages/search.vue +++ b/packages/frontend/src/pages/search.vue @@ -23,10 +23,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, defineAsyncComponent, onMounted, ref } from 'vue'; +import { computed, defineAsyncComponent, ref } from 'vue'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; -import * as os from '@/os.js'; import { $i } from '@/account.js'; import { instance } from '@/instance.js'; import MkInfo from '@/components/MkInfo.vue'; diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue index d9a59cdc35..4c165ef4ee 100644 --- a/packages/frontend/src/pages/settings/2fa.vue +++ b/packages/frontend/src/pages/settings/2fa.vue @@ -72,7 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref, defineAsyncComponent, computed } from 'vue'; +import { defineAsyncComponent, computed } from 'vue'; import { supported as webAuthnSupported, create as webAuthnCreate, parseCreationOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill'; import MkButton from '@/components/MkButton.vue'; import MkInfo from '@/components/MkInfo.vue'; diff --git a/packages/frontend/src/pages/settings/profile.avatar-decoration.decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.decoration.vue similarity index 100% rename from packages/frontend/src/pages/settings/profile.avatar-decoration.decoration.vue rename to packages/frontend/src/pages/settings/avatar-decoration.decoration.vue diff --git a/packages/frontend/src/pages/settings/profile.avatar-decoration.dialog.vue b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue similarity index 97% rename from packages/frontend/src/pages/settings/profile.avatar-decoration.dialog.vue rename to packages/frontend/src/pages/settings/avatar-decoration.dialog.vue index 77e6b28fad..329ab4d47a 100644 --- a/packages/frontend/src/pages/settings/profile.avatar-decoration.dialog.vue +++ b/packages/frontend/src/pages/settings/avatar-decoration.dialog.vue @@ -50,9 +50,6 @@ import MkButton from '@/components/MkButton.vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import { i18n } from '@/i18n.js'; -import * as os from '@/os.js'; -import MkFolder from '@/components/MkFolder.vue'; -import MkInfo from '@/components/MkInfo.vue'; import MkRange from '@/components/MkRange.vue'; import { $i } from '@/account.js'; diff --git a/packages/frontend/src/pages/settings/profile.avatar-decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.vue similarity index 58% rename from packages/frontend/src/pages/settings/profile.avatar-decoration.vue rename to packages/frontend/src/pages/settings/avatar-decoration.vue index 8579acfed8..6551fc917e 100644 --- a/packages/frontend/src/pages/settings/profile.avatar-decoration.vue +++ b/packages/frontend/src/pages/settings/avatar-decoration.vue @@ -4,51 +4,56 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div v-if="!loading" class="_gaps"> - <MkInfo>{{ i18n.t('_profile.avatarDecorationMax', { max: $i.policies.avatarDecorationLimit }) }} ({{ i18n.t('remainingN', { n: $i.policies.avatarDecorationLimit - $i.avatarDecorations.length }) }})</MkInfo> +<div> + <div v-if="!loading" class="_gaps"> + <MkInfo>{{ i18n.t('_profile.avatarDecorationMax', { max: $i.policies.avatarDecorationLimit }) }} ({{ i18n.t('remainingN', { n: $i.policies.avatarDecorationLimit - $i.avatarDecorations.length }) }})</MkInfo> - <div v-if="$i.avatarDecorations.length > 0" v-panel :class="$style.current" class="_gaps_s"> - <div>{{ i18n.ts.inUse }}</div> + <MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration/> + + <div v-if="$i.avatarDecorations.length > 0" v-panel :class="$style.current" class="_gaps_s"> + <div>{{ i18n.ts.inUse }}</div> + + <div :class="$style.decorations"> + <XDecoration + v-for="(avatarDecoration, i) in $i.avatarDecorations" + :decoration="avatarDecorations.find(d => d.id === avatarDecoration.id)" + :angle="avatarDecoration.angle" + :flipH="avatarDecoration.flipH" + :offsetX="avatarDecoration.offsetX" + :offsetY="avatarDecoration.offsetY" + :active="true" + @click="openDecoration(avatarDecoration, i)" + /> + </div> + + <MkButton danger @click="detachAllDecorations">{{ i18n.ts.detachAll }}</MkButton> + </div> <div :class="$style.decorations"> <XDecoration - v-for="(avatarDecoration, i) in $i.avatarDecorations" - :decoration="avatarDecorations.find(d => d.id === avatarDecoration.id)" - :angle="avatarDecoration.angle" - :flipH="avatarDecoration.flipH" - :offsetX="avatarDecoration.offsetX" - :offsetY="avatarDecoration.offsetY" - :active="true" - @click="openDecoration(avatarDecoration, i)" + v-for="avatarDecoration in avatarDecorations" + :key="avatarDecoration.id" + :decoration="avatarDecoration" + @click="openDecoration(avatarDecoration)" /> </div> - - <MkButton danger @click="detachAllDecorations">{{ i18n.ts.detachAll }}</MkButton> </div> - - <div :class="$style.decorations"> - <XDecoration - v-for="avatarDecoration in avatarDecorations" - :key="avatarDecoration.id" - :decoration="avatarDecoration" - @click="openDecoration(avatarDecoration)" - /> + <div v-else> + <MkLoading/> </div> </div> -<div v-else> - <MkLoading/> -</div> </template> <script lang="ts" setup> -import { ref, defineAsyncComponent } from 'vue'; +import { ref, defineAsyncComponent, computed } from 'vue'; import * as Misskey from 'misskey-js'; -import XDecoration from './profile.avatar-decoration.decoration.vue'; +import XDecoration from './avatar-decoration.decoration.vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; import MkInfo from '@/components/MkInfo.vue'; +import { definePageMetadata } from '@/scripts/page-metadata.js'; const loading = ref(true); const avatarDecorations = ref<Misskey.entities.GetAvatarDecorationsResponse>([]); @@ -59,7 +64,7 @@ os.api('get-avatar-decorations').then(_avatarDecorations => { }); function openDecoration(avatarDecoration, index?: number) { - os.popup(defineAsyncComponent(() => import('./profile.avatar-decoration.dialog.vue')), { + os.popup(defineAsyncComponent(() => import('./avatar-decoration.dialog.vue')), { decoration: avatarDecoration, usingIndex: index, }, { @@ -115,9 +120,25 @@ function detachAllDecorations() { $i.avatarDecorations = []; }); } + +const headerActions = computed(() => []); + +const headerTabs = computed(() => []); + +definePageMetadata({ + title: i18n.ts.avatarDecorations, + icon: 'ti ti-sparkles', +}); </script> <style lang="scss" module> +.avatar { + display: inline-block; + width: 72px; + height: 72px; + margin: 16px auto; +} + .current { padding: 16px; border-radius: var(--radius); diff --git a/packages/frontend/src/pages/settings/custom-css.vue b/packages/frontend/src/pages/settings/custom-css.vue index e33e778246..2564562089 100644 --- a/packages/frontend/src/pages/settings/custom-css.vue +++ b/packages/frontend/src/pages/settings/custom-css.vue @@ -7,15 +7,15 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_m"> <FormInfo warn>{{ i18n.ts.customCssWarn }}</FormInfo> - <MkTextarea v-model="localCustomCss" manualSave tall class="_monospace" style="tab-size: 2;"> + <MkCodeEditor v-model="localCustomCss" manualSave lang="css"> <template #label>CSS</template> - </MkTextarea> + </MkCodeEditor> </div> </template> <script lang="ts" setup> import { ref, watch, computed } from 'vue'; -import MkTextarea from '@/components/MkTextarea.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import FormInfo from '@/components/MkInfo.vue'; import * as os from '@/os.js'; import { unisonReload } from '@/scripts/unison-reload.js'; diff --git a/packages/frontend/src/pages/settings/drive-cleaner.vue b/packages/frontend/src/pages/settings/drive-cleaner.vue index 8da60ef504..4efcdb31da 100644 --- a/packages/frontend/src/pages/settings/drive-cleaner.vue +++ b/packages/frontend/src/pages/settings/drive-cleaner.vue @@ -55,7 +55,6 @@ import MkPagination from '@/components/MkPagination.vue'; import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue'; import { i18n } from '@/i18n.js'; import bytes from '@/filters/bytes.js'; -import { dateString } from '@/filters/date.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkSelect from '@/components/MkSelect.vue'; import { getDriveFileMenu } from '@/scripts/get-drive-file-menu.js'; diff --git a/packages/frontend/src/pages/settings/emoji-picker.vue b/packages/frontend/src/pages/settings/emoji-picker.vue index 7e7bf9bd1f..61f3332122 100644 --- a/packages/frontend/src/pages/settings/emoji-picker.vue +++ b/packages/frontend/src/pages/settings/emoji-picker.vue @@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_buttons"> <MkButton inline @click="previewReaction"><i class="ti ti-eye"></i> {{ i18n.ts.preview }}</MkButton> <MkButton inline danger @click="setDefaultReaction"><i class="ti ti-reload"></i> {{ i18n.ts.default }}</MkButton> - <MkButton inline danger @click="copyFromPinnedEmojis"><i class="ti ti-copy"></i> {{ i18n.ts.copyFromPinnedEmojis }}</MkButton> + <MkButton inline danger @click="overwriteFromPinnedEmojis"><i class="ti ti-copy"></i> {{ i18n.ts.overwriteFromPinnedEmojis }}</MkButton> </div> </div> </MkFolder> @@ -80,7 +80,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_buttons"> <MkButton inline @click="previewEmoji"><i class="ti ti-eye"></i> {{ i18n.ts.preview }}</MkButton> <MkButton inline danger @click="setDefaultEmoji"><i class="ti ti-reload"></i> {{ i18n.ts.default }}</MkButton> - <MkButton inline danger @click="copyFromPinnedEmojisForReaction"><i class="ti ti-copy"></i> {{ i18n.ts.copyFromPinnedEmojisForReaction }}</MkButton> + <MkButton inline danger @click="overwriteFromPinnedEmojisForReaction"><i class="ti ti-copy"></i> {{ i18n.ts.overwriteFromPinnedEmojisForReaction }}</MkButton> </div> </div> </MkFolder> @@ -164,7 +164,7 @@ function previewEmoji(ev: MouseEvent) { emojiPicker.show(getHTMLElement(ev)); } -async function copyFromPinnedEmojis() { +async function overwriteFromPinnedEmojis() { const { canceled } = await os.confirm({ type: 'warning', text: i18n.ts.overwriteContentConfirm, @@ -177,7 +177,7 @@ async function copyFromPinnedEmojis() { pinnedEmojisForReaction.value = [...pinnedEmojis.value]; } -async function copyFromPinnedEmojisForReaction() { +async function overwriteFromPinnedEmojisForReaction() { const { canceled } = await os.confirm({ type: 'warning', text: i18n.ts.overwriteContentConfirm, diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 9460de0752..e10eab00ed 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -141,8 +141,8 @@ SPDX-License-Identifier: AGPL-3.0-only <MkSwitch v-model="enableGamingMode">{{ i18n.ts.gamingMode }} <template #caption>{{ i18n.ts.gamingModeInfo }} </template></MkSwitch> <MkSwitch v-model="enableonlyAndWithSave">{{ i18n.ts.onlyAndWithSave}}<template #caption>{{ i18n.ts.onlyAndWithSaveInfo }} </template></MkSwitch> <MkSwitch v-model="enablehanntenn">{{ i18n.ts.hanntenn }}<template #caption>{{ i18n.ts.hanntennInfo }} </template></MkSwitch> - <MkSwitch v-model="indicatorCounterToggle">{{ i18n.ts.notificationIndicator }}</MkSwitch> - </div> + <MkSwitch v-model="enableSeasonalScreenEffect">{{ i18n.ts.seasonalScreenEffect }}</MkSwitch> + </div> <div> <MkRadios v-model="emojiStyle"> <template #label>{{ i18n.ts.emojiStyle }}</template> @@ -326,8 +326,7 @@ const showVisibilityColor = computed(defaultStore.makeGetterSetter('showVisibili const FeaturedOrNote = computed(defaultStore.makeGetterSetter('FeaturedOrNote')) const disableStreamingTimeline = computed(defaultStore.makeGetterSetter('disableStreamingTimeline')); const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroupedNotifications')); -const indicatorCounterToggle = computed(defaultStore.makeGetterSetter('indicatorCounterToggle')); - +const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); miLocalStorage.removeItem('locale'); @@ -394,6 +393,7 @@ watch([ FeaturedOrNote, showGlobalTimeline, disableStreamingTimeline, + enableSeasonalScreenEffect, ], async () => { await reloadAsk(); }); diff --git a/packages/frontend/src/pages/settings/navbar.vue b/packages/frontend/src/pages/settings/navbar.vue index 66477a86ca..5fe7209a0a 100644 --- a/packages/frontend/src/pages/settings/navbar.vue +++ b/packages/frontend/src/pages/settings/navbar.vue @@ -57,7 +57,6 @@ import { defaultStore } from '@/store.js'; import { unisonReload } from '@/scripts/unison-reload.js'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; -import { deepClone } from '@/scripts/clone.js'; const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index 58261c3cc9..09ff5beaf5 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -55,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { defineAsyncComponent, shallowRef, computed } from 'vue'; +import { shallowRef, computed } from 'vue'; import XNotificationConfig from './notifications.notification-config.vue'; import FormLink from '@/components/form/link.vue'; import FormSection from '@/components/form/section.vue'; @@ -68,7 +68,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue'; import { notificationTypes } from '@/const.js'; -const nonConfigurableNotificationTypes = ['note']; +const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'achievementEarned']; const allowButton = shallowRef<InstanceType<typeof MkPushNotificationAllowButton>>(); const pushRegistrationInServer = computed(() => allowButton.value?.pushRegistrationInServer); diff --git a/packages/frontend/src/pages/settings/plugin.install.vue b/packages/frontend/src/pages/settings/plugin.install.vue index f304d777a5..c174ba176f 100644 --- a/packages/frontend/src/pages/settings/plugin.install.vue +++ b/packages/frontend/src/pages/settings/plugin.install.vue @@ -7,9 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_m"> <FormInfo warn>{{ i18n.ts._plugin.installWarn }}</FormInfo> - <MkTextarea v-model="code" tall> + <MkCodeEditor v-model="code" lang="is"> <template #label>{{ i18n.ts.code }}</template> - </MkTextarea> + </MkCodeEditor> <div> <MkButton :disabled="code == null" primary inline @click="install"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton> @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { nextTick, ref, computed } from 'vue'; -import MkTextarea from '@/components/MkTextarea.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import MkButton from '@/components/MkButton.vue'; import FormInfo from '@/components/MkInfo.vue'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index 971881ea24..67a2f2cb40 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -13,12 +13,18 @@ SPDX-License-Identifier: AGPL-3.0-only <template #caption>{{ i18n.ts.makeReactionsPublicDescription }}</template> </MkSwitch> - <MkSelect v-model="ffVisibility" @update:modelValue="save()"> - <template #label>{{ i18n.ts.ffVisibility }}</template> + <MkSelect v-model="followingVisibility" @update:modelValue="save()"> + <template #label>{{ i18n.ts.followingVisibility }}</template> + <option value="public">{{ i18n.ts._ffVisibility.public }}</option> + <option value="followers">{{ i18n.ts._ffVisibility.followers }}</option> + <option value="private">{{ i18n.ts._ffVisibility.private }}</option> + </MkSelect> + + <MkSelect v-model="followersVisibility" @update:modelValue="save()"> + <template #label>{{ i18n.ts.followersVisibility }}</template> <option value="public">{{ i18n.ts._ffVisibility.public }}</option> <option value="followers">{{ i18n.ts._ffVisibility.followers }}</option> <option value="private">{{ i18n.ts._ffVisibility.private }}</option> - <template #caption>{{ i18n.ts.ffVisibilityDescription }}</template> </MkSelect> <MkSwitch v-model="hideOnlineStatus" @update:modelValue="save()"> @@ -84,7 +90,8 @@ const preventAiLearning = ref($i.preventAiLearning); const isExplorable = ref($i.isExplorable); const hideOnlineStatus = ref($i.hideOnlineStatus); const publicReactions = ref($i.publicReactions); -const ffVisibility = ref($i.ffVisibility); +const followingVisibility = ref($i?.followingVisibility); +const followersVisibility = ref($i?.followersVisibility); const defaultNoteVisibility = computed(defaultStore.makeGetterSetter('defaultNoteVisibility')); const defaultNoteLocalOnly = computed(defaultStore.makeGetterSetter('defaultNoteLocalOnly')); @@ -100,7 +107,8 @@ function save() { isExplorable: !!isExplorable.value, hideOnlineStatus: !!hideOnlineStatus.value, publicReactions: !!publicReactions.value, - ffVisibility: ffVisibility.value, + followingVisibility: followingVisibility.value, + followersVisibility: followersVisibility.value, }); } diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 8da0ba9cba..2e5a0617b0 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -5,19 +5,24 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div class="_gaps_m"> - <div :class="$style.avatarAndBanner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> + <div class="_panel"> + <div :class="$style.banner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> + <MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> + </div> <div :class="$style.avatarContainer"> <MkAvatar :class="$style.avatar" :user="$i" forceShowDecoration @click="changeAvatar"/> - <MkButton primary rounded @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> + <div class="_buttonsCenter"> + <MkButton primary rounded @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> + <MkButton primary rounded link to="/settings/avatar-decoration">{{ i18n.ts.decorate }} <i class="ti ti-sparkles"></i></MkButton> + </div> </div> - <MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> </div> <MkInput v-model="profile.name" :max="30" manualSave :mfmAutocomplete="['emoji']"> <template #label>{{ i18n.ts._profile.name }}</template> </MkInput> - <MkTextarea v-model="profile.description" :max="500" tall manualSave mfmAutocomplete :mfmPreview="true" :nyaize="$i?.isCat ? 'respect' : undefined" :author="($i as Misskey.entities.UserLite)"> + <MkTextarea v-model="profile.description" :max="500" tall manualSave mfmAutocomplete :mfmPreview="true"> <template #label>{{ i18n.ts._profile.description }}</template> <template #caption>{{ i18n.ts._profile.youCanIncludeHashtags }}</template> </MkTextarea> @@ -83,13 +88,6 @@ SPDX-License-Identifier: AGPL-3.0-only <template #caption>{{ i18n.ts._profile.metadataDescription }}</template> </FormSlot> - <MkFolder> - <template #icon><i class="ti ti-sparkles"></i></template> - <template #label>{{ i18n.ts.avatarDecorations }}</template> - - <XAvatarDecoration/> - </MkFolder> - <MkFolder> <template #label>{{ i18n.ts.advancedSettings }}</template> @@ -113,8 +111,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, reactive, ref, watch, defineAsyncComponent } from 'vue'; -import Misskey from 'misskey-js'; -import XAvatarDecoration from './profile.avatar-decoration.vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -270,19 +266,19 @@ definePageMetadata({ </script> <style lang="scss" module> -.avatarAndBanner { +.banner { position: relative; + height: 130px; background-size: cover; background-position: center; - border: solid 1px var(--divider); - border-radius: 10px; + border-bottom: solid 1px var(--divider); overflow: clip; } .avatarContainer { - display: inline-block; + margin-top: -50px; + padding-bottom: 16px; text-align: center; - padding: 16px; } .avatar { diff --git a/packages/frontend/src/pages/settings/roles.vue b/packages/frontend/src/pages/settings/roles.vue index 0f6c30dae9..40671f7132 100644 --- a/packages/frontend/src/pages/settings/roles.vue +++ b/packages/frontend/src/pages/settings/roles.vue @@ -23,21 +23,12 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, reactive, watch } from 'vue'; -import MkButton from '@/components/MkButton.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkTextarea from '@/components/MkTextarea.vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkSelect from '@/components/MkSelect.vue'; -import FormSplit from '@/components/form/split.vue'; -import MkFolder from '@/components/MkFolder.vue'; -import FormSlot from '@/components/form/slot.vue'; +import { computed } from 'vue'; import FormSection from '@/components/form/section.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; -import { defaultStore } from '@/store.js'; import MkRolePreview from '@/components/MkRolePreview.vue'; function save() { diff --git a/packages/frontend/src/pages/settings/theme.install.vue b/packages/frontend/src/pages/settings/theme.install.vue index c2ca53c743..f9be5720e0 100644 --- a/packages/frontend/src/pages/settings/theme.install.vue +++ b/packages/frontend/src/pages/settings/theme.install.vue @@ -5,9 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div class="_gaps_m"> - <MkTextarea v-model="installThemeCode"> + <MkCodeEditor v-model="installThemeCode" lang="json5"> <template #label>{{ i18n.ts._theme.code }}</template> - </MkTextarea> + </MkCodeEditor> <div class="_buttons"> <MkButton :disabled="installThemeCode == null" inline @click="() => previewTheme(installThemeCode)"><i class="ti ti-eye"></i> {{ i18n.ts.preview }}</MkButton> @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, computed } from 'vue'; -import MkTextarea from '@/components/MkTextarea.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import MkButton from '@/components/MkButton.vue'; import { parseThemeCode, previewTheme, installTheme } from '@/scripts/install-theme.js'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/pages/share.vue b/packages/frontend/src/pages/share.vue index 3e9cac9858..cb5acf3afa 100644 --- a/packages/frontend/src/pages/share.vue +++ b/packages/frontend/src/pages/share.vue @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -// SPECIFICATION: https://misskey-hub.net/docs/features/share-form.html +// SPECIFICATION: https://misskey-hub.net/docs/for-users/features/share-form/ import { ref, computed } from 'vue'; import * as Misskey from 'misskey-js'; diff --git a/packages/frontend/src/pages/theme-editor.vue b/packages/frontend/src/pages/theme-editor.vue index 0d137137fc..eee3e49db1 100644 --- a/packages/frontend/src/pages/theme-editor.vue +++ b/packages/frontend/src/pages/theme-editor.vue @@ -51,9 +51,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.editCode }}</template> <div class="_gaps_m"> - <MkTextarea v-model="themeCode" tall> + <MkCodeEditor v-model="themeCode" lang="json5"> <template #label>{{ i18n.ts._theme.code }}</template> - </MkTextarea> + </MkCodeEditor> <MkButton primary @click="applyThemeCode">{{ i18n.ts.apply }}</MkButton> </div> </MkFolder> @@ -80,6 +80,7 @@ import { v4 as uuid } from 'uuid'; import JSON5 from 'json5'; import MkButton from '@/components/MkButton.vue'; +import MkCodeEditor from '@/components/MkCodeEditor.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkFolder from '@/components/MkFolder.vue'; diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index de21e98380..1ffa8aaa15 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -45,10 +45,10 @@ import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import { $i } from '@/account.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; -import { miLocalStorage } from '@/local-storage.js'; import { antennasCache, userListsCache } from '@/cache.js'; import { deviceKind } from '@/scripts/device-kind.js'; import { MenuItem } from '@/types/menu.js'; +import { miLocalStorage } from '@/local-storage.js'; provide('shouldOmitHeaderTitle', true); @@ -125,11 +125,15 @@ async function chooseChannel(ev: MouseEvent): Promise<void> { limit: 100, }); const items: MenuItem[] = [ - ...channels.map(channel => ({ - type: 'link' as const, + ...channels.map(channel => { + const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null; + const hasUnreadNote = (lastReadedAt && channel.lastNotedAt) ? Date.parse(channel.lastNotedAt) > lastReadedAt : !!(!lastReadedAt && channel.lastNotedAt); + + return {type: 'link' as const, text: channel.name, - indicate: channel.hasUnreadNote, - to: `/channels/${channel.id}`,})), + indicate: hasUnreadNote, + to: `/channels/${channel.id}`,}; + }), (channels.length === 0 ? undefined : { type: 'divider' }), { type: 'link' as const, diff --git a/packages/frontend/src/pages/user-tag.vue b/packages/frontend/src/pages/user-tag.vue index 06269ec9a9..5d83efc1a9 100644 --- a/packages/frontend/src/pages/user-tag.vue +++ b/packages/frontend/src/pages/user-tag.vue @@ -16,8 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, watch } from 'vue'; -import * as os from '@/os.js'; +import { computed } from 'vue'; import MkUserList from '@/components/MkUserList.vue'; import { definePageMetadata } from '@/scripts/page-metadata.js'; diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 4eada13bc5..aa88473dfc 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -123,11 +123,11 @@ SPDX-License-Identifier: AGPL-3.0-only <b>{{ number(user.notesCount) }}</b> <span>{{ i18n.ts.notes }}</span> </MkA> - <MkA v-if="isFfVisibleForMe(user)" :to="userPage(user, 'following')"> + <MkA v-if="isFollowingVisibleForMe(user)" :to="userPage(user, 'following')"> <b>{{ number(user.followingCount) }}</b> <span>{{ i18n.ts.following }}</span> </MkA> - <MkA v-if="isFfVisibleForMe(user)" :to="userPage(user, 'followers')"> + <MkA v-if="isFollowersVisibleForMe(user)" :to="userPage(user, 'followers')"> <b>{{ number(user.followersCount) }}</b> <span>{{ i18n.ts.followers }}</span> </MkA> @@ -141,13 +141,18 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> <template v-if="narrow"> - <XFiles :key="user.id" :user="user"/> - <XActivity :key="user.id" :user="user"/> - </template> + <MkLazy> + <XFiles :key="user.id" :user="user"/> + </MkLazy> + <MkLazy> + <XActivity :key="user.id" :user="user"/> + </MkLazy> + </template> <div v-if="!defaultStore.state.FeaturedOrNote"> <div v-if="!disableNotes"> - <div style="margin-bottom: 8px;">{{ i18n.ts.featured }}</div> - <MkNotes :class="$style.tl" :noGap="true" :pagination="pagination"/> + <MkLazy> + <XTimeline :user="user"/> + </MkLazy> </div> </div> <div v-else> @@ -185,9 +190,8 @@ import {i18n} from '@/i18n.js'; import {$i, iAmModerator} from '@/account.js'; import {dateString} from '@/filters/date.js'; import {confetti} from '@/scripts/confetti.js'; -import MkNotes from '@/components/MkNotes.vue'; -import {api} from '@/os.js'; -import {isFfVisibleForMe} from '@/scripts/isFfVisibleForMe.js'; +import {api} from '@/os.js'; +import {isFollowingVisibleForMe, isFollowersVisibleForMe} from '@/scripts/isFfVisibleForMe.js'; import MkNotifyButton from "@/components/MkNotifyButton.vue"; import MkRemoteInfoUpdate from "@/components/MkRemoteInfoUpdate.vue"; import {defaultStore} from '@/store.js'; @@ -209,6 +213,7 @@ function calcAge(birthdate: string): number { const XFiles = defineAsyncComponent(() => import('./index.files.vue')); const XActivity = defineAsyncComponent(() => import('./index.activity.vue')); +const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue')); const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed; diff --git a/packages/frontend/src/pages/user/index.timeline.vue b/packages/frontend/src/pages/user/index.timeline.vue index 6cf5bcf91f..e5a0f49e3d 100644 --- a/packages/frontend/src/pages/user/index.timeline.vue +++ b/packages/frontend/src/pages/user/index.timeline.vue @@ -4,18 +4,17 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkSpacer :contentMax="800" style="padding-top: 0"> - <MkStickyContainer> - <template #header> - <MkTab v-model="include" :class="$style.tab"> - <option :value="null">{{ i18n.ts.notes }}</option> - <option value="all">{{ i18n.ts.all }}</option> - <option value="files">{{ i18n.ts.withFiles }}</option> - </MkTab> - </template> - <MkNotes :noGap="true" :pagination="pagination" :class="$style.tl"/> - </MkStickyContainer> -</MkSpacer> +<MkStickyContainer> + <template #header> + <MkTab v-model="tab" :class="$style.tab"> + <option value="featured">{{ i18n.ts.featured }}</option> + <option :value="null">{{ i18n.ts.notes }}</option> + <option value="all">{{ i18n.ts.all }}</option> + <option value="files">{{ i18n.ts.withFiles }}</option> + </MkTab> + </template> + <MkNotes :noGap="true" :pagination="pagination" :class="$style.tl"/> +</MkStickyContainer> </template> <script lang="ts" setup> @@ -29,24 +28,29 @@ const props = defineProps<{ user: Misskey.entities.UserDetailed; }>(); -const include = ref<string | null>('all'); +const tab = ref<string | null>('all'); -const pagination = { +const pagination = computed(() => tab.value === 'featured' ? { + endpoint: 'users/featured-notes' as const, + limit: 10, + params: { + userId: props.user.id, + }, +} : { endpoint: 'users/notes' as const, limit: 10, - params: computed(() => ({ + params: { userId: props.user.id, - withRenotes: include.value === 'all', - withReplies: include.value === 'all', - withChannelNotes: include.value === 'all', - withFiles: include.value === 'files', - })), -}; + withRenotes: tab.value === 'all', + withReplies: tab.value === 'all', + withChannelNotes: tab.value === 'all', + withFiles: tab.value === 'files', + }, +}); </script> <style lang="scss" module> .tab { - margin: calc(var(--margin) / 2) 0; padding: calc(var(--margin) / 2) 0; background: var(--bg); } diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index 4725aedeee..4efa834d14 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -9,7 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only <div> <div v-if="user"> <XHome v-if="tab === 'home'" :user="user"/> - <XTimeline v-else-if="tab === 'notes'" :user="user"/> + <MkSpacer v-else-if="tab === 'notes'" :contentMax="800" style="padding-top: 0"> + <XTimeline :user="user"/> + </MkSpacer> <XActivity v-else-if="tab === 'activity'" :user="user"/> <XAchievements v-else-if="tab === 'achievements'" :user="user"/> <XReactions v-else-if="tab === 'reactions'" :user="user"/> diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue index fef5f23bcd..068de4ca8a 100644 --- a/packages/frontend/src/pages/welcome.entrance.a.vue +++ b/packages/frontend/src/pages/welcome.entrance.a.vue @@ -39,13 +39,7 @@ import XTimeline from './welcome.timeline.vue'; import MarqueeText from '@/components/MkMarquee.vue'; import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue'; import misskeysvg from '/client-assets/misskey.svg'; -import MkInfo from '@/components/MkInfo.vue'; -import { instanceName } from '@/config.js'; import * as os from '@/os.js'; -import { i18n } from '@/i18n.js'; -import { instance } from '@/instance.js'; -import number from '@/filters/number.js'; -import MkNumber from '@/components/MkNumber.vue'; import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue'; import { getProxiedImageUrl } from '@/scripts/media-proxy.js'; diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue index 129131ce4a..92be80228a 100644 --- a/packages/frontend/src/pages/welcome.timeline.vue +++ b/packages/frontend/src/pages/welcome.timeline.vue @@ -34,7 +34,6 @@ import MkMediaList from '@/components/MkMediaList.vue'; import MkPoll from '@/components/MkPoll.vue'; import * as os from '@/os.js'; import { getScrollContainer } from '@/scripts/scroll.js'; -import { $i } from '@/account.js'; const notes = ref<Misskey.entities.Note[]>([]); const isScrolling = ref(false); diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index ea5a6569d4..d626bfcdb6 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -54,6 +54,10 @@ export const routes = [{ path: '/profile', name: 'profile', component: page(() => import('./pages/settings/profile.vue')), + }, { + path: '/avatar-decoration', + name: 'avatarDecoration', + component: page(() => import('./pages/settings/avatar-decoration.vue')), }, { path: '/roles', name: 'roles', diff --git a/packages/frontend/src/scripts/emoji-picker.ts b/packages/frontend/src/scripts/emoji-picker.ts index 3cf653ea1b..f87c3f6fb2 100644 --- a/packages/frontend/src/scripts/emoji-picker.ts +++ b/packages/frontend/src/scripts/emoji-picker.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { defineAsyncComponent, Ref, ref, computed, ComputedRef } from 'vue'; +import { defineAsyncComponent, Ref, ref } from 'vue'; import { popup } from '@/os.js'; import { defaultStore } from '@/store.js'; diff --git a/packages/frontend/src/scripts/isFfVisibleForMe.ts b/packages/frontend/src/scripts/isFfVisibleForMe.ts index 0567f3b34a..dc0e90d20a 100644 --- a/packages/frontend/src/scripts/isFfVisibleForMe.ts +++ b/packages/frontend/src/scripts/isFfVisibleForMe.ts @@ -6,11 +6,19 @@ import * as Misskey from 'misskey-js'; import { $i } from '@/account.js'; -export function isFfVisibleForMe(user: Misskey.entities.UserDetailed): boolean { +export function isFollowingVisibleForMe(user: Misskey.entities.UserDetailed): boolean { if ($i && $i.id === user.id) return true; - if (user.ffVisibility === 'private') return false; - if (user.ffVisibility === 'followers' && !user.isFollowing) return false; + if (user.followingVisibility === 'private') return false; + if (user.followingVisibility === 'followers' && !user.isFollowing) return false; + + return true; +} +export function isFollowersVisibleForMe(user: Misskey.entities.UserDetailed): boolean { + if ($i && $i.id === user.id) return true; + + if (user.followersVisibility === 'private') return false; + if (user.followersVisibility === 'followers' && !user.isFollowing) return false; return true; } diff --git a/packages/frontend/src/scripts/snowfall-effect.ts b/packages/frontend/src/scripts/snowfall-effect.ts new file mode 100644 index 0000000000..a09f02cec0 --- /dev/null +++ b/packages/frontend/src/scripts/snowfall-effect.ts @@ -0,0 +1,476 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SnowfallEffect { + private VERTEX_SOURCE = `#version 300 es + in vec4 a_position; + in vec4 a_color; + in vec3 a_rotation; + in vec3 a_speed; + in float a_size; + out vec4 v_color; + out float v_rotation; + uniform float u_time; + uniform mat4 u_projection; + uniform vec3 u_worldSize; + uniform float u_gravity; + uniform float u_wind; + + void main() { + v_color = a_color; + v_rotation = a_rotation.x + u_time * a_rotation.y; + + vec3 pos = a_position.xyz; + + float turbulence = 1.0; + + pos.x = mod(pos.x + u_time + u_wind * a_speed.x, u_worldSize.x * 2.0) - u_worldSize.x; + pos.y = mod(pos.y - u_time * a_speed.y * u_gravity, u_worldSize.y * 2.0) - u_worldSize.y; + + pos.x += sin(u_time * a_speed.z * turbulence) * a_rotation.z; + pos.z += cos(u_time * a_speed.z * turbulence) * a_rotation.z; + + gl_Position = u_projection * vec4(pos.xyz, a_position.w); + gl_PointSize = (a_size / gl_Position.w) * 100.0; + } + `; + + private FRAGMENT_SOURCE = `#version 300 es + precision highp float; + + in vec4 v_color; + in float v_rotation; + uniform sampler2D u_texture; + out vec4 out_color; + + void main() { + vec2 rotated = vec2( + cos(v_rotation) * (gl_PointCoord.x - 0.5) + sin(v_rotation) * (gl_PointCoord.y - 0.5) + 0.5, + cos(v_rotation) * (gl_PointCoord.y - 0.5) - sin(v_rotation) * (gl_PointCoord.x - 0.5) + 0.5 + ); + + vec4 snowflake = texture(u_texture, rotated); + + out_color = vec4(snowflake.rgb * v_color.xyz, snowflake.a * v_color.a); + } + `; + + private gl: WebGLRenderingContext; + private program: WebGLProgram; + private canvas: HTMLCanvasElement; + private buffers: Record<string, { + size: number; + value: number[] | Float32Array; + location: number; + ref: WebGLBuffer; + }>; + private uniforms: Record<string, { + type: string; + value: number[] | Float32Array; + location: WebGLUniformLocation; + }>; + private texture: WebGLTexture; + private camera: { + fov: number; + near: number; + far: number; + aspect: number; + z: number; + }; + private wind: { + current: number; + force: number; + target: number; + min: number; + max: number; + easing: number; + }; + private time: { + start: number; + previous: number; + } = { + start: 0, + previous: 0, + }; + private raf = 0; + + private density: number = 1 / 90; + private depth = 100; + private count = 1000; + private gravity = 100; + private speed: number = 1 / 10000; + private color: number[] = [1, 1, 1]; + private opacity = 1; + private size = 4; + private snowflake = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAErRJREFUeAHdmgnYlmPax5MShaxRKRElPmXJXpaSsRxDU0bTZ+kt65RloiRDltEMQsxYKmS+zzYjxCCamCzV2LchResMIxFRQ1G93+93Pdf5dL9v7zuf4/hm0fc/jt9znddy3/e1nNd53c/7vHXq/AtVWVnZA/bzkaQjoWG298DeMdvrmP6/EIOqC4fBsbAx7Arz4TaYBPXgWVDnO2jSBrB2T0IMIA9mCmmoE8aonPkR6WPZHlp9xSlfeyeBzq9bHBD5feEdUGfDXBgBqnde+a2wvw/dYdNctvZNAp1PnTaFttA6JgP7eVgBM0CNzgO9HNvy0AcYDda6SaDTdXOnz8X+IkZDugAGQmOYA+ob6Ah/MIOMDRPhJjgJ6uV7pXtWt81/50SnY/Wvwn4ZDHAvwJ9ATYcxyaqsnEnqZCyCPaE80BgYZXG/5A3VyyP/b08LHa11z9KmFUwA5eqruRBHYX1s8WSI1Xcbme8Mt8PWUCU+kF8XbFN+dtH+p06OD4IU8EjD/VOZ5bnezq0XHcHuC2oV7BDlkVIWq56uIX8UjAO31GRIMYW0Vo/xXtSXJyTuXVO6xk1qalRTmQ9AfqzEvog2XYpllnsd6Qr4unCPT7NtByu0uU7vuAaOoy1JuvfXpJdTvSX0gI1gCXwGZdFmEFxoQb7Wid8s7lNu+I8wuHGsTqz2zpQ9DAa5R6HC55A2gvCMXthvwi25bjx26H0M9/9f4Rnok9s0zulFlC2HzzP9cnld8nH/p7DVrbmuIfYs6JLz9U3/z+KGadDeCDsmwre7GyEifn/su8HVSsL2HeBn8CK8AW+B7u9R5yrPgyOjvSn5DWAaXAG2UU7CE9Ayt4k4sR1lX4LaLdd9gn2ftsL+Vtuh1Dp/elH1C8lvCdUj8kDK3gbP8XdhCnSC86rcsNSR9pQvhc/gVlB9bUfqoFNAy/mLrUROrpMwCtpBxBbTtLqkF4K6IF9rf57I9pnYekx5AS0P1VhopXso9pR5buC7+kewU86nFcB+BT4EXdIvNO73sRBubGTXLZtTtgp+DEb++bACdqBuJOlAaMMzLVM3whegNznQDtCb+pW5b8YY76euB5+7pxm0IbzCfS8m3Zf2q4T8/+4JNArXGoptpxz8LqDmQJq0Qnostt/sfIn5GygD4/Zeq7B7wljQO2yjB/QGj0Pjxz4wGdqXrkjXtCT/ISyDa6EPpHrSraFjvnecFpMoMx40Br3xSlD262rYObevddHTs2kYwWUG9uP5It/f1eU5Xw9btwoXPALbwYXcg+unG/KB3Rq8n9ddAOpn4Kr8BAaBcltcDo9D7Ouavig1o34x7F94xqPk74eLQH0MH8HvwS3SLPe9iheEG6f70KiuLpZv6sxG/Va5bFJOabaO7ucAvGEbeAH+AN1hV7iDOidQFz4A2oJb6D1YDhXZHkTqpL8EbqHDYRtwW20AsdIb8syl5N2e6dTAPB2mWYa+hE4Qk7I59iMwFZ70GlJlfyuTVfygs7Hyw7HbwI0w3Tak14BqEtdg7wVdIx8pZbtBUbrjZeA3vUPBANkU+sEehev8O4Db6QpwYm+D8II0KPKHwUFeQ3oLDIMN4WgID1yOPQ+MAXMhNAtju3ztmtuAypiAw7EXwo/Am+0NfUG5mknYc6GfGVIjsoFNuyuoh8COuDcd2LmwA9jWE8bB3Q7N4XrwWAz5XOXR+Tx4n6FgdHeB6sF/w2QwhlSXdXvl/jixx4NH8GW5LDzb7GrR4ES4F5QddB99CieAwStOAPegdUZ2B71F3AXbQSn3vJ1bYaYWrayh3NUPTcbYFExVW3CfXwlvgfoavMbnDAY9dxGo6dCt0LeaB54H4UydDEPA2R4PDlrFLB9XuNmTlO+Xr7X9ZNBr9J4+EN8AMcv6ButpMND9FM6EnTOHkLrSnvtzwbbq3vwMB2ow/qWFSC8ZC++ZQaldbquH2afQWbl8TdcvVtC6LtipifAuOKt6gA9Tzqgzb5R2gP1hX3DVtZVHVvdklY5DA5beIkVPuZn8LOgAnWEfeAaUkxCan/voBNkfF+U5cFu5z5XlxZU20OmZtgm1K45VO4naNCukrcBZVk/CD+E/YBjoYjXJY8Zg9DxsDrbbBHTRotxOrug4eBs+hHgWZtKzfHrdXHBi9gDvqzxFHNA5KVfyBCf0ExgB7nkXStLLEKkniNf0AzUs5+ublkVFKiC9FBZAvGxshT0NnN3zoSUYSJQPcjAvm0HmjcIPemNS96F6E36drFLwugx7EEzNZV/l9IjoEPkW4B7eFtYH9QKcBcfA/aCWgpPQOT+zMbb9fS3nDbYR2MdgV0S5aVlUhLs0w45IHi7sqnnGJ2E7CXqHWgZXgJ1y8KqpDUmfSLmSV5yB/XrpDqVP8ofmehNdOv7I0ShfP4yyJdl2a4SchI1gCXgkHgljYfvc1i3cs/SU1A9jQRpfri/b0Sal1RrtSj4ULyHprY5C6+6E1+EBULq0E+DK7A96iwqX0z4td8B3dCdob5gD3UB3j9fUcNuDKFOvgc+bZAZFf4Zgu/q/AGPMgfm+5ShPWay+k6I31BwAvVDRYL2cuqfUVTkfnTqvVFx5ai7/MXn3tp1UrtRkDWRsaAMjzaD08uJ1irz7+8ps/6ZYj90V3FKrQBkvmubULbN7vs7tZRyJV9w0ePLbQ4PcJspqXnkbhbgoGk/AVptZRxpB0hU7Mpc1x34cdgKPm1dzeTts9XPwlFAO5Au4BDbO7ZycO7J9A/Zh2b4A2+ucALefWpTrflDKVq4kHQBOoi9PO1qvsDeGd6AxXAJbQ5VxlFrW8EnDcJlTsOPcjElxL7WNy7AduC4f2+A/rSN/Hyg7YMBTxgqPUT3F2HAqtIb58GvQW86GqyG+ff4UWz0FBuH4UhaTal1vmAGfg98dfP4d4HPGwmwYAg+D2/J7uU0ap/YaolHZVbBj5d1DaSK8ADsmqiH2JIhgNRhbPZrbhSdZ5heVJGw7477VfYuaagMK2sM8iMloga1HXAt/AeWELgQnR/0Z7k3W6pe3xTn/JamTFPGnPMZSj6p90rA8YOziwHcnH/EgTovJlJ0LPSHkyrTKmZNJ+8KrYKBsCQeB0pWdBFNleieMgzjL44jejTK1CPSY0CiMdyOT09g6ni5O3Ceg51U4VNLaPSA3SDNEwwiKFdgHgANNrpjb7UVejYTYCuZ92DR42HYh8gfDJfAMqBi4dqxk+RrKGkD0YXNsA6AT5qCUXhBe5CR0gPCC4dhqKFwI1m1qX0hr94CotDE4aAd3PCyBX4Jyn+sNL5tBDsRAp3S7b5KVYwa2A0nHaO5AXBeDtnlMxizsW+HomLh8zX9R5sTeBSEn/cqc2Tvak9eDXCyP2PgbYWzn2gefHxT7+0Qu/h18DO7XmPWYcYqSXuHz2myb6G7RNs7meLgeMxXugbiPA3clQx0xtgNPGN819L7+oCzvm6zSx+EkI+Du3Pe0LbOd/jqc7dhG9Wib+mJ5jaJBuL8e4B5aAMpAomKlb8d+KZWUVnw+dgzKSdDtvKaLDyJ1ReZB7O0J2EV5Xwd8OsTJExNpu7Q1SJ8zgy7K93UCX4P4mr4udoyhPGDKygOP+tomIFarMw2d+cfgF2DnDVAGoBvzw33YTHgPDoXQ7Fx/Wy6YkdMrcrmrehO4Pz3WvP90cIVPgonwITg4973yu0XTZK0+ZQaQd+K816twVAwKO71ZRj9zeg7lcVzXHghpVN4n2G3BAHQ1NILx4MBjoppgLwL3Ww8IHZsf6vGk3O8fwx9heK7rhD0o2zdg75JtT6GzQQ8KzcZwElSr3M5J85ktYCzEG+Gx2NNzm/Cm5pSp+K2gfLrZbg3RcB2IQcZN1qPM3+l06SjbAltX/TiXe1wtg7+AdR+AcgIs7xUPw94XxuTrnOD4E1bEoe9Rptw+DWGOGeQi7JOs1SfKKfk+epcakPNxbI8uFVdem8vT6aJdq7jASYjOFPdQDP4Q6t+Em8HVutmbkbYH9Tv4LcQW+H6ujy9Wrtxc6A7vQnznb5TbHUPZ0mw7CeoaOBAegmfBIKw8WZzs34M/oNiPGPzB2KHdrVMUlD29VFLLpw2jMWmnaIbdDNxXur+dWgVumTMglI4zMgbUEV5LmjqW7XnRkDS9qhbu/xZlZ8LWuc3UfM22Of80aVcYDJ/lstdIWxXu0TGXm/TO19vveHWuOglUxOo6iMfyBe7JOEp01ech9puuuBCMA8pVcUUNUB5lqgMYwJyE1oXOGTh9v1gO6kmogKEwHtREMHYofz5zAl3lJ2AWqJfgfohJiKB8HWWfg54YA9Zr1fn5Xmm80SdvHhNwVmq2umF8vWxA+WRwwE9BPNhOulrq0nxz97j6Go6DF8HYcBfYyer6MwWuoINeDG6roq4iE97QCtsJuxWc2JrkCeKEbgX7waOgnLiavxdQEWfohtgRwCrygIoxoQv1K0FNgR7gAKPTB+dr5lAWMliqmbAb7AzbgCs42vYK21NmOiwHJ9atpdxqDlhdA75QdYJT4XUYDfbBiVRe5ySoZTAbBpeekp6T4lo5uFnBz0fpJ6P8E9SJufEdXHipdRA/mw2hzmvfhrfgfjCKPwJnwn2g3igldb4hNaD5a6/fz7eHVuAb2wPwPs+4DB7E/hTagd64BbgoC6Ab9IAfgn+OX0p/ppAaGxZjnw6+Ep8DK8Cj0IDrmHw3GaeN9EZ/AlxFfk1RuVGUYu8K00D9Fa6EvrAUVKzO29gXg9vC1VW3g540w0xBcU2hKJnz+FxYvTCXWaduK/StuTZlLcD6JjnfEvsb6A56m32z78q4FMGw1gA4lEa60WmwMeiSnsljIBSDmEOBE3RdfvggbMuMIbNhItgJtbyUpE9ddjA0Bid1sderXDaQ1OdPAO9zH6hDcpuG2Ml7SQfArHRx6Xpf3JTluySrsrIP6Seg9/iMqsEvF6YZoXIDeAZCRmpneAHEnnLQnaEuXATX53schR3n/e7YyuvOT1bpnyV107Io3xZ6QWs4EirAyXkEqqvK3xa9CQ0c5C5xQ+zN8kWjcr2xZxTsBHfmsipbP671ZmW3wHYA58DdEPobhtwVF2HfBE9H3pT8xjkdja3iiDK4PQBO8Dx4B9wiH8JKeANcKTUW9IITwKNMeYrcArfDhVDsb1pVyty26le5D97/zWzrzVUGXyVjI0WjHUgq4CjoAuGiRuuJkN7mSJX7cn+uaZNyfBBgDHZqXvqsU2cZ6aPwChgE/ap8M9wLbSH+0DKOaw18z8N12GPAyf4BfADbwBmwCbxAHY9NvxQXx2GgVLZXPvurZDE0rqk5+NmAm8U2aIbdH9yDalgpSS80ltlB29fPqW9c8XLUHnsIuGquqt8gN7edwtazrOsAn4MysLryX8BD4Ap3y+0dZROIwPsl9h/hHjgit4lXdrdvHN8dc91wyk7JdvIS7VpF46Jb2ZGz4WJIRyBpBKQW3oR8lZuSvwQMhKtAfQUpYuf27cgbNx6EEeDAzgMHPwYMYi2gEcSfxC7B9qicDMoo/1vQI8p9IG88WAY/yeVpYrJdHpf5vytu4Ky7X46xIamrvjDb52OrG3K+HrZt4xq9wYEZPGPVfp7bhsdE2os2ylV6J1n5mbYPUX4S7AkGX+OAk2t6mm1Iw3PtQ+O4LuooK26RYvW3s7nBLZDiAGlbUHYiRV/S5AWk28DTEFqB4eo+B+n1M55Ivhu4kspj92uYCm6Px0Gv61lor0fcDQNBrQQnOr71lVeYsm894L/bkBuFe/u93eBngJtJMlwTDIDKyfDt6n3se8Dt8jHoNU0o70waq34obZ8lPx4coG+LbifrP6Pt0aQvwn65LFzcAHY8ZUtgAnwExp2WoMpeQLvaA12p7bf/pLPFmS3a/ajr750cfE43wX4YYmU9wi7IddHBCsrc69vm8uuwQydYVhQVvmsUn7s+ebfD0GhXrI+yf2jqA4oPKdo+iHxMwHbYRmgjta4cUTqCWXkg0UHatIR4SxxWKK9PeXhgKiZfxWOthzXuGff4p6b54bH3Y3W3pNxJcK8ebgdI44iys0G0N/8qKGOAGg9Ni50n3yjy2GkxSKtMRtT/21I7Fg/H9lRIX6qK5YX6zSjvDL4BGiBfBnUNmFdzwfKX4Ct40OtJv1sDj0Hlzrk6xbM3tob7uCf4amyk96VHvQg7gltGzQG9wpcwX6BCesfJ3/kJiMmgs+Gm4errUeZqF+Up4IoOzoWLcmqETyLve/2BsKkFpGUvK7VYCz6j06RbQx+ogHhN3Qdb3QF+a/wVKF94OhSHR77sWcXytcKm82usHGW9QE2B3skq/QB7APaqnJ9NuvaufnF1GIhxYH3LSAeA+hM0hMfgNzATdHvjgDHDv+qkP8gW77XW2gwmYsJe2F3zZDgxI7NteTo+/1WD/B9Au3Zjh2RyrgAAAABJRU5ErkJggg=='; + + private INITIAL_BUFFERS = () => ({ + position: { size: 3, value: [] }, + color: { size: 4, value: [] }, + size: { size: 1, value: [] }, + rotation: { size: 3, value: [] }, + speed: { size: 3, value: [] }, + }); + + private INITIAL_UNIFORMS = () => ({ + time: { type: 'float', value: 0 }, + worldSize: { type: 'vec3', value: [0, 0, 0] }, + gravity: { type: 'float', value: this.gravity }, + wind: { type: 'float', value: 0 }, + projection: { + type: 'mat4', + value: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], + }, + }); + + private UNIFORM_SETTERS = { + int: 'uniform1i', + float: 'uniform1f', + vec2: 'uniform2fv', + vec3: 'uniform3fv', + vec4: 'uniform4fv', + mat2: 'uniformMatrix2fv', + mat3: 'uniformMatrix3fv', + mat4: 'uniformMatrix4fv', + }; + + private CAMERA = { + fov: 60, + near: 5, + far: 10000, + aspect: 1, + z: 100, + }; + + private WIND = { + current: 0, + force: 0.01, + target: 0.01, + min: 0, + max: 0.125, + easing: 0.0005, + }; + + constructor() { + const canvas = this.initCanvas(); + const gl = canvas.getContext('webgl2', { antialias: true }); + if (gl == null) throw new Error('Failed to get WebGL context'); + + document.body.append(canvas); + + this.canvas = canvas; + this.gl = gl; + this.program = this.initProgram(); + this.buffers = this.initBuffers(); + this.uniforms = this.initUniforms(); + this.texture = this.initTexture(); + this.camera = this.initCamera(); + this.wind = this.initWind(); + + this.resize = this.resize.bind(this); + this.update = this.update.bind(this); + + window.addEventListener('resize', () => this.resize()); + } + + private initCanvas(): HTMLCanvasElement { + const canvas = document.createElement('canvas'); + + Object.assign(canvas.style, { + position: 'fixed', + top: 0, + left: 0, + width: '100vw', + height: '100vh', + background: 'transparent', + 'pointer-events': 'none', + 'z-index': 2147483647, + }); + + return canvas; + } + + private initCamera() { + return { ...this.CAMERA }; + } + + private initWind() { + return { ...this.WIND }; + } + + private initShader(type, source): WebGLShader { + const { gl } = this; + const shader = gl.createShader(type); + if (shader == null) throw new Error('Failed to create shader'); + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + + private initProgram(): WebGLProgram { + const { gl } = this; + const vertex = this.initShader(gl.VERTEX_SHADER, this.VERTEX_SOURCE); + const fragment = this.initShader(gl.FRAGMENT_SHADER, this.FRAGMENT_SOURCE); + const program = gl.createProgram(); + if (program == null) throw new Error('Failed to create program'); + + gl.attachShader(program, vertex); + gl.attachShader(program, fragment); + gl.linkProgram(program); + gl.useProgram(program); + + return program; + } + + private initBuffers(): SnowfallEffect['buffers'] { + const { gl, program } = this; + const buffers = this.INITIAL_BUFFERS() as unknown as SnowfallEffect['buffers']; + + for (const [name, buffer] of Object.entries(buffers)) { + buffer.location = gl.getAttribLocation(program, `a_${name}`); + buffer.ref = gl.createBuffer()!; + + gl.bindBuffer(gl.ARRAY_BUFFER, buffer.ref); + gl.enableVertexAttribArray(buffer.location); + gl.vertexAttribPointer( + buffer.location, + buffer.size, + gl.FLOAT, + false, + 0, + 0, + ); + } + + return buffers; + } + + private updateBuffers() { + const { buffers } = this; + + for (const name of Object.keys(buffers)) { + this.setBuffer(name); + } + } + + private setBuffer(name: string, value?) { + const { gl, buffers } = this; + const buffer = buffers[name]; + + buffer.value = new Float32Array(value ?? buffer.value); + + gl.bindBuffer(gl.ARRAY_BUFFER, buffer.ref); + gl.bufferData(gl.ARRAY_BUFFER, buffer.value, gl.STATIC_DRAW); + } + + private initUniforms(): SnowfallEffect['uniforms'] { + const { gl, program } = this; + const uniforms = this.INITIAL_UNIFORMS() as unknown as SnowfallEffect['uniforms']; + + for (const [name, uniform] of Object.entries(uniforms)) { + uniform.location = gl.getUniformLocation(program, `u_${name}`)!; + } + + return uniforms; + } + + private updateUniforms() { + const { uniforms } = this; + + for (const name of Object.keys(uniforms)) { + this.setUniform(name); + } + } + + private setUniform(name: string, value?) { + const { gl, uniforms } = this; + const uniform = uniforms[name]; + const setter = this.UNIFORM_SETTERS[uniform.type]; + const isMatrix = /^mat[2-4]$/i.test(uniform.type); + + uniform.value = value ?? uniform.value; + + if (isMatrix) { + gl[setter](uniform.location, false, uniform.value); + } else { + gl[setter](uniform.location, uniform.value); + } + } + + private initTexture() { + const { gl } = this; + const texture = gl.createTexture(); + if (texture == null) throw new Error('Failed to create texture'); + const image = new Image(); + + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + 1, + 1, + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + new Uint8Array([0, 0, 0, 0]), + ); + + image.onload = () => { + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + gl.RGBA, + gl.UNSIGNED_BYTE, + image, + ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + }; + + image.src = this.snowflake; + + return texture; + } + + private initSnowflakes(vw: number, vh: number, dpi: number) { + const position: number[] = []; + const color: number[] = []; + const size: number[] = []; + const rotation: number[] = []; + const speed: number[] = []; + + const height = 1 / this.density; + const width = (vw / vh) * height; + const depth = this.depth; + const count = this.count; + const length = (vw / vh) * count; + + for (let i = 0; i < length; ++i) { + position.push( + -width + Math.random() * width * 2, + -height + Math.random() * height * 2, + Math.random() * depth * 2, + ); + + speed.push(1 + Math.random(), 1 + Math.random(), Math.random() * 10); + + rotation.push( + Math.random() * 2 * Math.PI, + Math.random() * 20, + Math.random() * 10, + ); + + color.push(...this.color, 0.1 + Math.random() * this.opacity); + //size.push((this.size * Math.random() * this.size * vh * dpi) / 1000); + size.push((this.size * vh * dpi) / 1000); + } + + this.setUniform('worldSize', [width, height, depth]); + + this.setBuffer('position', position); + this.setBuffer('color', color); + this.setBuffer('rotation', rotation); + this.setBuffer('size', size); + this.setBuffer('speed', speed); + } + + private setProjection(aspect: number) { + const { camera } = this; + + camera.aspect = aspect; + + const fovRad = (camera.fov * Math.PI) / 180; + const f = Math.tan(Math.PI * 0.5 - 0.5 * fovRad); + const rangeInv = 1.0 / (camera.near - camera.far); + + const m0 = f / camera.aspect; + const m5 = f; + const m10 = (camera.near + camera.far) * rangeInv; + const m11 = -1; + const m14 = camera.near * camera.far * rangeInv * 2 + camera.z; + const m15 = camera.z; + + return [m0, 0, 0, 0, 0, m5, 0, 0, 0, 0, m10, m11, 0, 0, m14, m15]; + } + + public render() { + const { gl } = this; + + gl.enable(gl.BLEND); + gl.enable(gl.CULL_FACE); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE); + gl.disable(gl.DEPTH_TEST); + + this.updateBuffers(); + this.updateUniforms(); + this.resize(true); + + this.time = { + start: window.performance.now(), + previous: window.performance.now(), + }; + + if (this.raf) window.cancelAnimationFrame(this.raf); + this.raf = window.requestAnimationFrame(this.update); + + return this; + } + + private resize(updateSnowflakes = false) { + const { canvas, gl } = this; + const vw = canvas.offsetWidth; + const vh = canvas.offsetHeight; + const aspect = vw / vh; + const dpi = window.devicePixelRatio; + + canvas.width = vw * dpi; + canvas.height = vh * dpi; + + gl.viewport(0, 0, vw * dpi, vh * dpi); + gl.clearColor(0, 0, 0, 0); + + if (updateSnowflakes === true) { + this.initSnowflakes(vw, vh, dpi); + } + + this.setUniform('projection', this.setProjection(aspect)); + } + + private update(timestamp: number) { + const { gl, buffers, wind } = this; + const elapsed = (timestamp - this.time.start) * this.speed; + const delta = timestamp - this.time.previous; + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays( + gl.POINTS, + 0, + buffers.position.value.length / buffers.position.size, + ); + + if (Math.random() > 0.995) { + wind.target = + (wind.min + Math.random() * (wind.max - wind.min)) * + (Math.random() > 0.5 ? -1 : 1); + } + + wind.force += (wind.target - wind.force) * wind.easing; + wind.current += wind.force * (delta * 0.2); + + this.setUniform('wind', wind.current); + this.setUniform('time', elapsed); + + this.time.previous = timestamp; + + this.raf = window.requestAnimationFrame(this.update); + } +} diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 7cdc036708..59d2b39250 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -507,6 +507,10 @@ export const defaultStore = markRaw(new Storage('base', { code: false, } as Record<string, boolean>, }, + enableSeasonalScreenEffect: { + where: 'device', + default: false, + }, sound_masterVolume: { where: 'device', diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts index 3fc7990888..5251ef5787 100644 --- a/packages/frontend/src/ui/_common_/common.ts +++ b/packages/frontend/src/ui/_common_/common.ts @@ -101,7 +101,7 @@ export function openInstanceMenu(ev: MouseEvent) { text: i18n.ts.help, icon: 'ti ti-help-circle', action: () => { - window.open('https://misskey-hub.net/help.html', '_blank', 'noopener'); + window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener'); }, }, ($i) ? { text: i18n.ts._initialTutorial.launchTutorial, diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue index 9d3308c470..0f27f29319 100644 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ b/packages/frontend/src/ui/classic.sidebar.vue @@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { defineAsyncComponent, onMounted, computed, watch, nextTick, ref, shallowRef } from 'vue'; +import { defineAsyncComponent, computed, watch, ref, shallowRef } from 'vue'; import { openInstanceMenu } from './_common_/common.js'; // import { host } from '@/config.js'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index b5381396cd..c8d15630ba 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { defineAsyncComponent, ComputedRef, onMounted, provide, ref, computed, shallowRef } from 'vue'; +import { defineAsyncComponent, onMounted, provide, ref, computed, shallowRef } from 'vue'; import XSidebar from './classic.sidebar.vue'; import XCommon from './_common_/common.vue'; import { instanceName } from '@/config.js'; diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 5cf9b2f45b..0a5f43a13f 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -99,7 +99,6 @@ import { deckStore, addColumn as addColumnToStore, loadDeck, getProfiles, delete import XSidebar from '@/ui/_common_/navbar.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import MkButton from '@/components/MkButton.vue'; -import { getScrollContainer } from '@/scripts/scroll.js'; import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { $i } from '@/account.js'; diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 8bf3a28d55..e0d54614b6 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ComputedRef, onMounted, provide, ref, computed } from 'vue'; import XCommon from './_common_/common.vue'; -import { host, instanceName } from '@/config.js'; +import { instanceName } from '@/config.js'; import * as os from '@/os.js'; import { instance } from '@/instance.js'; import XSigninDialog from '@/components/MkSigninDialog.vue'; diff --git a/packages/frontend/src/unicode-emoji-indexes/en-US.json b/packages/frontend/src/unicode-emoji-indexes/en-US.json index 567125c4c7..4d8b040ad2 100644 --- a/packages/frontend/src/unicode-emoji-indexes/en-US.json +++ b/packages/frontend/src/unicode-emoji-indexes/en-US.json @@ -103,6 +103,7 @@ "🫥": ["depressed", "disappear", "hide", "introvert", "invisible", "tensen"], "🫤": ["disappointed", "meh", "skeptical", "unsure"], "🥹": ["angry", "cry", "proud", "resist", "sad"], + "🫨": ["earthquake", "face", "shaking", "shock", "vibrate"], "💩": ["hankey", "shitface", "fail", "turd", "shit"], "😈": ["devil", "horns"], "👿": ["devil", "angry", "horns"], @@ -132,6 +133,8 @@ "✊": ["fingers", "hand", "grasp"], "🤛": ["hand", "fistbump"], "🤜": ["hand", "fistbump"], + "🫷": ["hand", "high_five", "leftward", "push", "refuse", "stop", "wait"], + "🫸": ["hand", "high_five", "push", "refuse", "rightward", "stop", "wait"], "✌": ["fingers", "ohyeah", "hand", "peace", "victory", "two"], "👌": ["fingers", "limbs", "perfect", "ok", "okay"], "✋": ["fingers", "stop", "highfive", "palm", "ban"], @@ -453,6 +456,7 @@ "🐸": ["animal", "nature", "croak", "toad"], "🦑": ["animal", "nature", "ocean", "sea"], "🐙": ["animal", "creature", "ocean", "sea", "nature", "beach"], + "🪼": ["animal", "creature", "ocean", "sea", "nature", "beach"], "🦐": ["animal", "ocean", "nature", "seafood"], "🐵": ["animal", "nature", "circus"], "🦍": ["animal", "nature", "circus"], @@ -466,7 +470,9 @@ "🐤": ["animal", "chicken", "bird"], "🐣": ["animal", "chicken", "egg", "born", "baby", "bird"], "🐥": ["animal", "chicken", "baby", "bird"], + "🪿": ["animal", "nature", "bird", "fowl", "goose", "honk", "silly"], "🦆": ["animal", "nature", "bird", "mallard"], + "🐦⬛": ["animal", "nature", "bird", "black", "crow", "raven", "rook"], "🦅": ["animal", "nature", "bird"], "🦉": ["animal", "nature", "bird", "hoot"], "🦇": ["animal", "nature", "blind", "vampire"], @@ -474,9 +480,11 @@ "🐗": ["animal", "nature"], "🐴": ["animal", "brown", "nature"], "🦄": ["animal", "nature", "mystical"], + "🫎": ["animal", "nature", "antlers", "elk", "mammal"], "🐝": ["animal", "insect", "nature", "bug", "spring", "honey"], "🐛": ["animal", "insect", "nature", "worm"], "🦋": ["animal", "insect", "nature", "caterpillar"], + "🫏": ["animal", "ass", "burro", "mammal", "mule", "stubborn"], "🐌": ["slow", "animal", "shell"], "🐞": ["animal", "insect", "nature", "ladybug"], "🐜": ["animal", "insect", "nature", "bug"], @@ -546,6 +554,7 @@ "🐻❄️": ["animal", "nature"], "🦤": ["animal", "nature"], "🪶": ["animal", "nature"], + "🪽": ["angelic", "aviation", "bird", "flying", "mythology"], "🦭": ["animal", "nature"], "🐾": ["animal", "tracking", "footprints", "dog", "cat", "pet", "feet"], "🐉": ["animal", "myth", "nature", "chinese", "green"], @@ -576,6 +585,7 @@ "🌻": ["nature", "plant", "fall"], "🌹": ["flowers", "valentines", "love", "spring"], "🥀": ["plant", "nature", "flower"], + "🪻": ["plant", "nature", "flower", "bluebonnet", "lavender", "lupine", "snapdragon"], "🌷": ["flowers", "plant", "nature", "summer", "spring"], "🌼": ["nature", "flowers", "yellow"], "🌸": ["nature", "plant", "spring", "flower"], @@ -655,6 +665,7 @@ "🥝": ["fruit", "food"], "🥭": ["fruit", "food", "tropical"], "🥑": ["fruit", "food"], + "🫛": ["beans", "edamame", "legume", "pea", "pod", "vegetable", "food"], "🥦": ["fruit", "food", "vegetable"], "🍅": ["fruit", "vegetable", "nature", "food"], "🍆": ["vegetable", "nature", "food", "aubergine"], @@ -668,6 +679,7 @@ "🌽": ["food", "vegetable", "plant"], "🥬": ["food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce"], "🍠": ["food", "nature"], + "🫚": ["food", "nature", "beer", "root", "spice"], "🥜": ["food", "nut"], "🧄": ["food"], "🧅": ["food"], @@ -850,9 +862,11 @@ "🎧": ["music", "score", "gadgets"], "🎼": ["treble", "clef", "compose"], "🎹": ["piano", "instrument", "compose"], + "🪇": ["instrument", "music", "percussion", "rattle", "shake"], "🥁": ["music", "instrument", "drumsticks", "snare"], "🎷": ["music", "instrument", "jazz", "blues"], "🎺": ["music", "brass"], + "🪈": ["music", "fife", "pipe", "recorder", "woodwind"], "🎸": ["music", "instrument"], "🎻": ["music", "instrument", "orchestra", "symphony"], "🪕": ["music", "instrument"], @@ -1108,6 +1122,7 @@ "🩹": ["health", "hospital", "medicine", "needle", "doctor", "nurse"], "🩺": ["health", "hospital", "medicine", "needle", "doctor", "nurse"], "🪒": ["health"], + "🪮": ["afro", "comb", "hair", "pick"], "🩻": [], "🩼": [], "🧬": ["biologist", "genetics", "life"], @@ -1156,6 +1171,7 @@ "🎊": ["festival", "party", "birthday", "circus"], "🎉": ["party", "congratulations", "birthday", "magic", "circus", "celebration"], "🎎": ["japanese", "toy", "kimono"], + "🪭": ["cooling", "dance", "fan", "flutter", "hot", "shy"], "🎐": ["nature", "ding", "spring", "bell"], "🎌": ["japanese", "nation", "country", "border"], "🏮": ["light", "paper", "halloween", "spooky"], @@ -1237,14 +1253,17 @@ "🪧": [], "💯": ["score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred"], "🔢": ["numbers", "blue-square"], + "🩷": ["love", "like", "affection", "valentines"], "❤️": ["love", "like", "affection", "valentines"], "🧡": ["love", "like", "affection", "valentines"], "💛": ["love", "like", "affection", "valentines"], "💚": ["love", "like", "affection", "valentines"], + "🩵": ["love", "like", "affection", "valentines"], "💙": ["love", "like", "affection", "valentines"], "💜": ["love", "like", "affection", "valentines"], "🤎": ["love", "like", "affection", "valentines"], "🖤": ["love", "like", "affection", "valentines"], + "🩶": ["love", "like", "affection", "valentines"], "🤍": ["love", "like", "affection", "valentines"], "💔": ["sad", "sorry", "break", "heart", "heartbreak"], "❣": ["decoration", "love"], @@ -1263,6 +1282,7 @@ "☪": ["islam"], "🕉": ["hinduism", "buddhism", "sikhism", "jainism"], "☸": ["hinduism", "buddhism", "sikhism", "jainism"], + "🪯": ["religion", "sikh"], "✡": ["judaism"], "🔯": ["purple-square", "religion", "jewish", "hexagram"], "🕎": ["hanukkah", "candles", "jewish"], @@ -1358,6 +1378,7 @@ "🛃": ["passport", "border", "blue-square"], "🛄": ["blue-square", "airport", "transport"], "🛅": ["blue-square", "travel"], + "🛜": ["blue-square", "computer", "internet", "network"], "♿": ["blue-square", "disabled", "a11y", "accessibility"], "🚭": ["cigarette", "blue-square", "smell", "smoke"], "🚾": ["toilet", "restroom", "blue-square"], @@ -1527,258 +1548,258 @@ "🕥": ["time", "late", "early", "schedule"], "🕦": ["time", "late", "early", "schedule"], "🕧": ["time", "late", "early", "schedule"], - "🇦🇫": ["af", "flag", "nation", "country", "banner"], - "🇦🇽": ["Åland", "islands", "flag", "nation", "country", "banner"], - "🇦🇱": ["al", "flag", "nation", "country", "banner"], - "🇩🇿": ["dz", "flag", "nation", "country", "banner"], - "🇦🇸": ["american", "ws", "flag", "nation", "country", "banner"], + "🇦🇫": ["af", "afghanistan", "flag", "nation", "country", "banner"], + "🇦🇽": ["ax", "Åland", "aland", "islands", "flag", "nation", "country", "banner"], + "🇦🇱": ["al", "albania", "flag", "nation", "country", "banner"], + "🇩🇿": ["dz", "algeria", "flag", "nation", "country", "banner"], + "🇦🇸": ["as", "american", "samoa", "flag", "nation", "country", "banner"], "🇦🇩": ["ad", "flag", "nation", "country", "banner"], - "🇦🇴": ["ao", "flag", "nation", "country", "banner"], - "🇦🇮": ["ai", "flag", "nation", "country", "banner"], - "🇦🇶": ["aq", "flag", "nation", "country", "banner"], - "🇦🇬": ["antigua", "barbuda", "flag", "nation", "country", "banner"], - "🇦🇷": ["ar", "flag", "nation", "country", "banner"], - "🇦🇲": ["am", "flag", "nation", "country", "banner"], - "🇦🇼": ["aw", "flag", "nation", "country", "banner"], - "🇦🇨": ["flag", "nation", "country", "banner"], - "🇦🇺": ["au", "flag", "nation", "country", "banner"], - "🇦🇹": ["at", "flag", "nation", "country", "banner"], - "🇦🇿": ["az", "flag", "nation", "country", "banner"], - "🇧🇸": ["bs", "flag", "nation", "country", "banner"], - "🇧🇭": ["bh", "flag", "nation", "country", "banner"], - "🇧🇩": ["bd", "flag", "nation", "country", "banner"], - "🇧🇧": ["bb", "flag", "nation", "country", "banner"], - "🇧🇾": ["by", "flag", "nation", "country", "banner"], - "🇧🇪": ["be", "flag", "nation", "country", "banner"], - "🇧🇿": ["bz", "flag", "nation", "country", "banner"], - "🇧🇯": ["bj", "flag", "nation", "country", "banner"], - "🇧🇲": ["bm", "flag", "nation", "country", "banner"], - "🇧🇹": ["bt", "flag", "nation", "country", "banner"], - "🇧🇴": ["bo", "flag", "nation", "country", "banner"], - "🇧🇶": ["bonaire", "flag", "nation", "country", "banner"], - "🇧🇦": ["bosnia", "herzegovina", "flag", "nation", "country", "banner"], - "🇧🇼": ["bw", "flag", "nation", "country", "banner"], - "🇧🇷": ["br", "flag", "nation", "country", "banner"], - "🇮🇴": ["british", "indian", "ocean", "territory", "flag", "nation", "country", "banner"], - "🇻🇬": ["british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner"], - "🇧🇳": ["bn", "darussalam", "flag", "nation", "country", "banner"], - "🇧🇬": ["bg", "flag", "nation", "country", "banner"], - "🇧🇫": ["burkina", "faso", "flag", "nation", "country", "banner"], - "🇧🇮": ["bi", "flag", "nation", "country", "banner"], - "🇨🇻": ["cabo", "verde", "flag", "nation", "country", "banner"], - "🇰🇭": ["kh", "flag", "nation", "country", "banner"], - "🇨🇲": ["cm", "flag", "nation", "country", "banner"], - "🇨🇦": ["ca", "flag", "nation", "country", "banner"], - "🇮🇨": ["canary", "islands", "flag", "nation", "country", "banner"], - "🇰🇾": ["cayman", "islands", "flag", "nation", "country", "banner"], - "🇨🇫": ["central", "african", "republic", "flag", "nation", "country", "banner"], - "🇹🇩": ["td", "flag", "nation", "country", "banner"], - "🇨🇱": ["flag", "nation", "country", "banner"], - "🇨🇳": ["china", "chinese", "prc", "flag", "country", "nation", "banner"], - "🇨🇽": ["christmas", "island", "flag", "nation", "country", "banner"], - "🇨🇨": ["cocos", "keeling", "islands", "flag", "nation", "country", "banner"], - "🇨🇴": ["co", "flag", "nation", "country", "banner"], - "🇰🇲": ["km", "flag", "nation", "country", "banner"], - "🇨🇬": ["congo", "flag", "nation", "country", "banner"], - "🇨🇩": ["congo", "democratic", "republic", "flag", "nation", "country", "banner"], - "🇨🇰": ["cook", "islands", "flag", "nation", "country", "banner"], - "🇨🇷": ["costa", "rica", "flag", "nation", "country", "banner"], - "🇭🇷": ["hr", "flag", "nation", "country", "banner"], - "🇨🇺": ["cu", "flag", "nation", "country", "banner"], - "🇨🇼": ["curaçao", "flag", "nation", "country", "banner"], - "🇨🇾": ["cy", "flag", "nation", "country", "banner"], - "🇨🇿": ["cz", "flag", "nation", "country", "banner"], - "🇩🇰": ["dk", "flag", "nation", "country", "banner"], - "🇩🇯": ["dj", "flag", "nation", "country", "banner"], - "🇩🇲": ["dm", "flag", "nation", "country", "banner"], - "🇩🇴": ["dominican", "republic", "flag", "nation", "country", "banner"], - "🇪🇨": ["ec", "flag", "nation", "country", "banner"], - "🇪🇬": ["eg", "flag", "nation", "country", "banner"], - "🇸🇻": ["el", "salvador", "flag", "nation", "country", "banner"], - "🇬🇶": ["equatorial", "gn", "flag", "nation", "country", "banner"], - "🇪🇷": ["er", "flag", "nation", "country", "banner"], - "🇪🇪": ["ee", "flag", "nation", "country", "banner"], - "🇪🇹": ["et", "flag", "nation", "country", "banner"], - "🇪🇺": ["european", "union", "flag", "banner"], - "🇫🇰": ["falkland", "islands", "malvinas", "flag", "nation", "country", "banner"], - "🇫🇴": ["faroe", "islands", "flag", "nation", "country", "banner"], - "🇫🇯": ["fj", "flag", "nation", "country", "banner"], - "🇫🇮": ["fi", "flag", "nation", "country", "banner"], - "🇫🇷": ["banner", "flag", "nation", "france", "french", "country"], - "🇬🇫": ["french", "guiana", "flag", "nation", "country", "banner"], - "🇵🇫": ["french", "polynesia", "flag", "nation", "country", "banner"], - "🇹🇫": ["french", "southern", "territories", "flag", "nation", "country", "banner"], - "🇬🇦": ["ga", "flag", "nation", "country", "banner"], - "🇬🇲": ["gm", "flag", "nation", "country", "banner"], - "🇬🇪": ["ge", "flag", "nation", "country", "banner"], - "🇩🇪": ["german", "nation", "flag", "country", "banner"], - "🇬🇭": ["gh", "flag", "nation", "country", "banner"], - "🇬🇮": ["gi", "flag", "nation", "country", "banner"], - "🇬🇷": ["gr", "flag", "nation", "country", "banner"], - "🇬🇱": ["gl", "flag", "nation", "country", "banner"], - "🇬🇩": ["gd", "flag", "nation", "country", "banner"], - "🇬🇵": ["gp", "flag", "nation", "country", "banner"], - "🇬🇺": ["gu", "flag", "nation", "country", "banner"], - "🇬🇹": ["gt", "flag", "nation", "country", "banner"], - "🇬🇬": ["gg", "flag", "nation", "country", "banner"], - "🇬🇳": ["gn", "flag", "nation", "country", "banner"], - "🇬🇼": ["gw", "bissau", "flag", "nation", "country", "banner"], - "🇬🇾": ["gy", "flag", "nation", "country", "banner"], - "🇭🇹": ["ht", "flag", "nation", "country", "banner"], - "🇭🇳": ["hn", "flag", "nation", "country", "banner"], - "🇭🇰": ["hong", "kong", "flag", "nation", "country", "banner"], - "🇭🇺": ["hu", "flag", "nation", "country", "banner"], - "🇮🇸": ["is", "flag", "nation", "country", "banner"], - "🇮🇳": ["in", "flag", "nation", "country", "banner"], - "🇮🇩": ["flag", "nation", "country", "banner"], - "🇮🇷": ["iran, ", "islamic", "republic", "flag", "nation", "country", "banner"], - "🇮🇶": ["iq", "flag", "nation", "country", "banner"], - "🇮🇪": ["ie", "flag", "nation", "country", "banner"], - "🇮🇲": ["isle", "man", "flag", "nation", "country", "banner"], - "🇮🇱": ["il", "flag", "nation", "country", "banner"], - "🇮🇹": ["italy", "flag", "nation", "country", "banner"], - "🇨🇮": ["ivory", "coast", "flag", "nation", "country", "banner"], - "🇯🇲": ["jm", "flag", "nation", "country", "banner"], - "🇯🇵": ["japanese", "nation", "flag", "country", "banner"], - "🇯🇪": ["je", "flag", "nation", "country", "banner"], - "🇯🇴": ["jo", "flag", "nation", "country", "banner"], - "🇰🇿": ["kz", "flag", "nation", "country", "banner"], - "🇰🇪": ["ke", "flag", "nation", "country", "banner"], - "🇰🇮": ["ki", "flag", "nation", "country", "banner"], - "🇽🇰": ["xk", "flag", "nation", "country", "banner"], - "🇰🇼": ["kw", "flag", "nation", "country", "banner"], - "🇰🇬": ["kg", "flag", "nation", "country", "banner"], - "🇱🇦": ["lao", "democratic", "republic", "flag", "nation", "country", "banner"], - "🇱🇻": ["lv", "flag", "nation", "country", "banner"], - "🇱🇧": ["lb", "flag", "nation", "country", "banner"], - "🇱🇸": ["ls", "flag", "nation", "country", "banner"], - "🇱🇷": ["lr", "flag", "nation", "country", "banner"], - "🇱🇾": ["ly", "flag", "nation", "country", "banner"], - "🇱🇮": ["li", "flag", "nation", "country", "banner"], - "🇱🇹": ["lt", "flag", "nation", "country", "banner"], - "🇱🇺": ["lu", "flag", "nation", "country", "banner"], - "🇲🇴": ["macao", "flag", "nation", "country", "banner"], - "🇲🇰": ["macedonia, ", "flag", "nation", "country", "banner"], - "🇲🇬": ["mg", "flag", "nation", "country", "banner"], - "🇲🇼": ["mw", "flag", "nation", "country", "banner"], - "🇲🇾": ["my", "flag", "nation", "country", "banner"], - "🇲🇻": ["mv", "flag", "nation", "country", "banner"], - "🇲🇱": ["ml", "flag", "nation", "country", "banner"], - "🇲🇹": ["mt", "flag", "nation", "country", "banner"], - "🇲🇭": ["marshall", "islands", "flag", "nation", "country", "banner"], - "🇲🇶": ["mq", "flag", "nation", "country", "banner"], - "🇲🇷": ["mr", "flag", "nation", "country", "banner"], - "🇲🇺": ["mu", "flag", "nation", "country", "banner"], - "🇾🇹": ["yt", "flag", "nation", "country", "banner"], - "🇲🇽": ["mx", "flag", "nation", "country", "banner"], - "🇫🇲": ["micronesia, ", "federated", "states", "flag", "nation", "country", "banner"], - "🇲🇩": ["moldova, ", "republic", "flag", "nation", "country", "banner"], - "🇲🇨": ["mc", "flag", "nation", "country", "banner"], - "🇲🇳": ["mn", "flag", "nation", "country", "banner"], - "🇲🇪": ["me", "flag", "nation", "country", "banner"], - "🇲🇸": ["ms", "flag", "nation", "country", "banner"], - "🇲🇦": ["ma", "flag", "nation", "country", "banner"], - "🇲🇿": ["mz", "flag", "nation", "country", "banner"], - "🇲🇲": ["mm", "flag", "nation", "country", "banner"], - "🇳🇦": ["na", "flag", "nation", "country", "banner"], - "🇳🇷": ["nr", "flag", "nation", "country", "banner"], - "🇳🇵": ["np", "flag", "nation", "country", "banner"], - "🇳🇱": ["nl", "flag", "nation", "country", "banner"], - "🇳🇨": ["new", "caledonia", "flag", "nation", "country", "banner"], - "🇳🇿": ["new", "zealand", "flag", "nation", "country", "banner"], - "🇳🇮": ["ni", "flag", "nation", "country", "banner"], - "🇳🇪": ["ne", "flag", "nation", "country", "banner"], - "🇳🇬": ["flag", "nation", "country", "banner"], - "🇳🇺": ["nu", "flag", "nation", "country", "banner"], - "🇳🇫": ["norfolk", "island", "flag", "nation", "country", "banner"], - "🇲🇵": ["northern", "mariana", "islands", "flag", "nation", "country", "banner"], - "🇰🇵": ["north", "korea", "nation", "flag", "country", "banner"], - "🇳🇴": ["no", "flag", "nation", "country", "banner"], - "🇴🇲": ["om_symbol", "flag", "nation", "country", "banner"], - "🇵🇰": ["pk", "flag", "nation", "country", "banner"], - "🇵🇼": ["pw", "flag", "nation", "country", "banner"], - "🇵🇸": ["palestine", "palestinian", "territories", "flag", "nation", "country", "banner"], - "🇵🇦": ["pa", "flag", "nation", "country", "banner"], - "🇵🇬": ["papua", "new", "guinea", "flag", "nation", "country", "banner"], - "🇵🇾": ["py", "flag", "nation", "country", "banner"], - "🇵🇪": ["pe", "flag", "nation", "country", "banner"], - "🇵🇭": ["ph", "flag", "nation", "country", "banner"], - "🇵🇳": ["pitcairn", "flag", "nation", "country", "banner"], - "🇵🇱": ["pl", "flag", "nation", "country", "banner"], - "🇵🇹": ["pt", "flag", "nation", "country", "banner"], - "🇵🇷": ["puerto", "rico", "flag", "nation", "country", "banner"], - "🇶🇦": ["qa", "flag", "nation", "country", "banner"], - "🇷🇪": ["réunion", "flag", "nation", "country", "banner"], - "🇷🇴": ["ro", "flag", "nation", "country", "banner"], - "🇷🇺": ["russian", "federation", "flag", "nation", "country", "banner"], - "🇷🇼": ["rw", "flag", "nation", "country", "banner"], - "🇧🇱": ["saint", "barthélemy", "flag", "nation", "country", "banner"], - "🇸🇭": ["saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner"], - "🇰🇳": ["saint", "kitts", "nevis", "flag", "nation", "country", "banner"], - "🇱🇨": ["saint", "lucia", "flag", "nation", "country", "banner"], - "🇵🇲": ["saint", "pierre", "miquelon", "flag", "nation", "country", "banner"], - "🇻🇨": ["saint", "vincent", "grenadines", "flag", "nation", "country", "banner"], - "🇼🇸": ["ws", "flag", "nation", "country", "banner"], - "🇸🇲": ["san", "marino", "flag", "nation", "country", "banner"], - "🇸🇹": ["sao", "tome", "principe", "flag", "nation", "country", "banner"], - "🇸🇦": ["flag", "nation", "country", "banner"], - "🇸🇳": ["sn", "flag", "nation", "country", "banner"], - "🇷🇸": ["rs", "flag", "nation", "country", "banner"], - "🇸🇨": ["sc", "flag", "nation", "country", "banner"], - "🇸🇱": ["sierra", "leone", "flag", "nation", "country", "banner"], - "🇸🇬": ["sg", "flag", "nation", "country", "banner"], - "🇸🇽": ["sint", "maarten", "dutch", "flag", "nation", "country", "banner"], - "🇸🇰": ["sk", "flag", "nation", "country", "banner"], - "🇸🇮": ["si", "flag", "nation", "country", "banner"], - "🇸🇧": ["solomon", "islands", "flag", "nation", "country", "banner"], - "🇸🇴": ["so", "flag", "nation", "country", "banner"], - "🇿🇦": ["south", "africa", "flag", "nation", "country", "banner"], - "🇬🇸": ["south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner"], - "🇰🇷": ["south", "korea", "nation", "flag", "country", "banner"], - "🇸🇸": ["south", "sd", "flag", "nation", "country", "banner"], - "🇪🇸": ["spain", "flag", "nation", "country", "banner"], - "🇱🇰": ["sri", "lanka", "flag", "nation", "country", "banner"], - "🇸🇩": ["sd", "flag", "nation", "country", "banner"], - "🇸🇷": ["sr", "flag", "nation", "country", "banner"], - "🇸🇿": ["sz", "flag", "nation", "country", "banner"], - "🇸🇪": ["se", "flag", "nation", "country", "banner"], - "🇨🇭": ["ch", "flag", "nation", "country", "banner"], - "🇸🇾": ["syrian", "arab", "republic", "flag", "nation", "country", "banner"], - "🇹🇼": ["tw", "flag", "nation", "country", "banner"], - "🇹🇯": ["tj", "flag", "nation", "country", "banner"], - "🇹🇿": ["tanzania, ", "united", "republic", "flag", "nation", "country", "banner"], - "🇹🇭": ["th", "flag", "nation", "country", "banner"], - "🇹🇱": ["timor", "leste", "flag", "nation", "country", "banner"], - "🇹🇬": ["tg", "flag", "nation", "country", "banner"], - "🇹🇰": ["tk", "flag", "nation", "country", "banner"], - "🇹🇴": ["to", "flag", "nation", "country", "banner"], - "🇹🇹": ["trinidad", "tobago", "flag", "nation", "country", "banner"], - "🇹🇦": ["flag", "nation", "country", "banner"], - "🇹🇳": ["tn", "flag", "nation", "country", "banner"], - "🇹🇷": ["turkey", "flag", "nation", "country", "banner"], - "🇹🇲": ["flag", "nation", "country", "banner"], - "🇹🇨": ["turks", "caicos", "islands", "flag", "nation", "country", "banner"], - "🇹🇻": ["flag", "nation", "country", "banner"], - "🇺🇬": ["ug", "flag", "nation", "country", "banner"], - "🇺🇦": ["ua", "flag", "nation", "country", "banner"], - "🇦🇪": ["united", "arab", "emirates", "flag", "nation", "country", "banner"], - "🇬🇧": ["united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack"], + "🇦🇴": ["ao", "angola", "flag", "nation", "country", "banner"], + "🇦🇮": ["ai", "anguilla", "flag", "nation", "country", "banner"], + "🇦🇶": ["aq", "antarctique", "flag", "nation", "country", "banner"], + "🇦🇬": ["ag", "antigua", "barbuda", "flag", "nation", "country", "banner"], + "🇦🇷": ["ar", "argentina", "flag", "nation", "country", "banner"], + "🇦🇲": ["am", "armenia", "flag", "nation", "country", "banner"], + "🇦🇼": ["aw", "aruba", "flag", "nation", "country", "banner"], + "🇦🇨": ["ac", "ascension", "island", "flag", "nation", "country", "banner"], + "🇦🇺": ["au", "australia", "flag", "nation", "country", "banner"], + "🇦🇹": ["at", "austria", "flag", "nation", "country", "banner"], + "🇦🇿": ["az", "azerbaijan", "flag", "nation", "country", "banner"], + "🇧🇸": ["bs", "bahamas", "flag", "nation", "country", "banner"], + "🇧🇭": ["bh", "bahrain", "flag", "nation", "country", "banner"], + "🇧🇩": ["bd", "bangladesh", "flag", "nation", "country", "banner"], + "🇧🇧": ["bb", "barbados", "flag", "nation", "country", "banner"], + "🇧🇾": ["by", "belarus", "flag", "nation", "country", "banner"], + "🇧🇪": ["be", "belgium", "flag", "nation", "country", "banner"], + "🇧🇿": ["bz", "belize", "flag", "nation", "country", "banner"], + "🇧🇯": ["bj", "benin", "flag", "nation", "country", "banner"], + "🇧🇲": ["bm", "bermuda", "flag", "nation", "country", "banner"], + "🇧🇹": ["bt", "bhutan", "flag", "nation", "country", "banner"], + "🇧🇴": ["bo", "bolivia", "flag", "nation", "country", "banner"], + "🇧🇶": ["bq", "bonaire", "flag", "nation", "country", "banner"], + "🇧🇦": ["ba", "bosnia", "herzegovina", "flag", "nation", "country", "banner"], + "🇧🇼": ["bw", "botswana", "flag", "nation", "country", "banner"], + "🇧🇷": ["br", "brazil", "flag", "nation", "country", "banner"], + "🇮🇴": ["io", "british", "indian", "ocean", "territory", "flag", "nation", "country", "banner"], + "🇻🇬": ["vg", "british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner"], + "🇧🇳": ["bn", "brunei", "darussalam", "flag", "nation", "country", "banner"], + "🇧🇬": ["bg", "bulgaria", "flag", "nation", "country", "banner"], + "🇧🇫": ["bf", "burkina", "faso", "flag", "nation", "country", "banner"], + "🇧🇮": ["bi", "burundi", "flag", "nation", "country", "banner"], + "🇨🇻": ["cv", "cabo", "verde", "flag", "nation", "country", "banner"], + "🇰🇭": ["kh", "cambodia", "flag", "nation", "country", "banner"], + "🇨🇲": ["cm", "cameroon", "flag", "nation", "country", "banner"], + "🇨🇦": ["ca", "canada", "flag", "nation", "country", "banner"], + "🇮🇨": ["ic", "canary", "islands", "flag", "nation", "country", "banner"], + "🇰🇾": ["ky", "cayman", "islands", "flag", "nation", "country", "banner"], + "🇨🇫": ["cf", "central", "african", "republic", "flag", "nation", "country", "banner"], + "🇹🇩": ["td", "chad", "flag", "nation", "country", "banner"], + "🇨🇱": ["cl", "chile", "flag", "nation", "country", "banner"], + "🇨🇳": ["cn", "china", "chinese", "prc", "flag", "country", "nation", "banner"], + "🇨🇽": ["cx", "christmas", "island", "flag", "nation", "country", "banner"], + "🇨🇨": ["cc", "cocos", "keeling", "islands", "flag", "nation", "country", "banner"], + "🇨🇴": ["co", "colombia", "flag", "nation", "country", "banner"], + "🇰🇲": ["km", "comoros", "flag", "nation", "country", "banner"], + "🇨🇬": ["cg", "republic", "congo", "flag", "nation", "country", "banner"], + "🇨🇩": ["cd", "democratic", "republic", "congo", "flag", "nation", "country", "banner"], + "🇨🇰": ["ck", "cook", "islands", "flag", "nation", "country", "banner"], + "🇨🇷": ["cr", "costa", "rica", "flag", "nation", "country", "banner"], + "🇭🇷": ["hr", "croatia", "flag", "nation", "country", "banner"], + "🇨🇺": ["cu", "cuba", "flag", "nation", "country", "banner"], + "🇨🇼": ["cw", "curacao", "curaçao", "flag", "nation", "country", "banner"], + "🇨🇾": ["cy", "cyprus", "flag", "nation", "country", "banner"], + "🇨🇿": ["cz", "czech", "republic", "flag", "nation", "country", "banner"], + "🇩🇰": ["dk", "denmark", "flag", "nation", "country", "banner"], + "🇩🇯": ["dj", "djibouti", "flag", "nation", "country", "banner"], + "🇩🇲": ["dm", "dominica", "flag", "nation", "country", "banner"], + "🇩🇴": ["do", "dominican", "republic", "flag", "nation", "country", "banner"], + "🇪🇨": ["ec", "ecuador", "flag", "nation", "country", "banner"], + "🇪🇬": ["eg", "egypt", "flag", "nation", "country", "banner"], + "🇸🇻": ["sv", "el", "salvador", "flag", "nation", "country", "banner"], + "🇬🇶": ["gq", "equatorial", "guinea", "flag", "nation", "country", "banner"], + "🇪🇷": ["er", "eritrea", "flag", "nation", "country", "banner"], + "🇪🇪": ["ee", "estonia", "flag", "nation", "country", "banner"], + "🇪🇹": ["et", "ethiopia", "flag", "nation", "country", "banner"], + "🇪🇺": ["eu", "european", "union", "flag", "banner"], + "🇫🇰": ["fk", "falkland", "islands", "malvinas", "flag", "nation", "country", "banner"], + "🇫🇴": ["fo", "faroe", "islands", "flag", "nation", "country", "banner"], + "🇫🇯": ["fj", "fiji", "flag", "nation", "country", "banner"], + "🇫🇮": ["fi", "finland", "flag", "nation", "country", "banner"], + "🇫🇷": ["fr", "banner", "flag", "nation", "france", "french", "country"], + "🇬🇫": ["gf", "french", "guiana", "flag", "nation", "country", "banner"], + "🇵🇫": ["pf", "french", "polynesia", "flag", "nation", "country", "banner"], + "🇹🇫": ["tf", "french", "southern", "territories", "flag", "nation", "country", "banner"], + "🇬🇦": ["ga", "gabon", "flag", "nation", "country", "banner"], + "🇬🇲": ["gm", "gambia", "flag", "nation", "country", "banner"], + "🇬🇪": ["ge", "georgia", "flag", "nation", "country", "banner"], + "🇩🇪": ["de", "deutschland", "german", "nation", "flag", "country", "banner"], + "🇬🇭": ["gh", "ghana", "flag", "nation", "country", "banner"], + "🇬🇮": ["gi", "gibraltar", "flag", "nation", "country", "banner"], + "🇬🇷": ["gr", "greece", "flag", "nation", "country", "banner"], + "🇬🇱": ["gl", "green", "land", "flag", "nation", "country", "banner"], + "🇬🇩": ["gd", "grenada", "flag", "nation", "country", "banner"], + "🇬🇵": ["gp", "guadeloupe", "flag", "nation", "country", "banner"], + "🇬🇺": ["gu", "guam", "flag", "nation", "country", "banner"], + "🇬🇹": ["gt", "guatemala", "flag", "nation", "country", "banner"], + "🇬🇬": ["gg", "guernsey", "flag", "nation", "country", "banner"], + "🇬🇳": ["gn", "guinea", "flag", "nation", "country", "banner"], + "🇬🇼": ["gw", "guiana", "bissau", "flag", "nation", "country", "banner"], + "🇬🇾": ["gy", "guyana", "flag", "nation", "country", "banner"], + "🇭🇹": ["ht", "haiti", "flag", "nation", "country", "banner"], + "🇭🇳": ["hn", "honduras", "flag", "nation", "country", "banner"], + "🇭🇰": ["hk", "hong", "kong", "flag", "nation", "country", "banner"], + "🇭🇺": ["hu", "hungary", "flag", "nation", "country", "banner"], + "🇮🇸": ["is", "iceland", "Ísland", "flag", "nation", "country", "banner"], + "🇮🇳": ["in", "india", "flag", "nation", "country", "banner"], + "🇮🇩": ["id", "indonesia", "flag", "nation", "country", "banner"], + "🇮🇷": ["ir", "iran", "islamic", "republic", "flag", "nation", "country", "banner"], + "🇮🇶": ["iq", "iraq", "flag", "nation", "country", "banner"], + "🇮🇪": ["ie", "ireland", "flag", "nation", "country", "banner"], + "🇮🇲": ["im", "isle", "man", "flag", "nation", "country", "banner"], + "🇮🇱": ["il", "israel", "flag", "nation", "country", "banner"], + "🇮🇹": ["it", "italy", "flag", "nation", "country", "banner"], + "🇨🇮": ["ci", "cote", "divoire", "Côte", "d'Ivoire", "ivory", "coast", "flag", "nation", "country", "banner"], + "🇯🇲": ["jm", "jamaica", "flag", "nation", "country", "banner"], + "🇯🇵": ["jp", "japan", "japanese", "nation", "flag", "country", "banner"], + "🇯🇪": ["je", "jersey", "flag", "nation", "country", "banner"], + "🇯🇴": ["jo", "jordan", "flag", "nation", "country", "banner"], + "🇰🇿": ["kz", "kazakhstan", "flag", "nation", "country", "banner"], + "🇰🇪": ["ke", "kenya", "flag", "nation", "country", "banner"], + "🇰🇮": ["ki", "kiribati", "flag", "nation", "country", "banner"], + "🇽🇰": ["xk", "kosovo", "flag", "nation", "country", "banner"], + "🇰🇼": ["kw", "kuwait", "flag", "nation", "country", "banner"], + "🇰🇬": ["kg", "kyrgyzstan", "kyrgyz", "flag", "nation", "country", "banner"], + "🇱🇦": ["la", "laos", "lao", "democratic", "republic", "flag", "nation", "country", "banner"], + "🇱🇻": ["lv", "latvia", "flag", "nation", "country", "banner"], + "🇱🇧": ["lb", "lebanon", "flag", "nation", "country", "banner"], + "🇱🇸": ["ls", "lesotho", "flag", "nation", "country", "banner"], + "🇱🇷": ["lr", "liberia", "flag", "nation", "country", "banner"], + "🇱🇾": ["ly", "libya", "flag", "nation", "country", "banner"], + "🇱🇮": ["li", "liechtenstein", "flag", "nation", "country", "banner"], + "🇱🇹": ["lt", "lithuania", "flag", "nation", "country", "banner"], + "🇱🇺": ["lu", "luxembourg", "flag", "nation", "country", "banner"], + "🇲🇴": ["mo", "macao", "macau", "flag", "nation", "country", "banner"], + "🇲🇰": ["mk", "north", "macedonia", "flag", "nation", "country", "banner"], + "🇲🇬": ["mg", "madagascar", "flag", "nation", "country", "banner"], + "🇲🇼": ["mw", "malawi", "flag", "nation", "country", "banner"], + "🇲🇾": ["my", "malaysia", "flag", "nation", "country", "banner"], + "🇲🇻": ["mv", "maldives", "republic", "flag", "nation", "country", "banner"], + "🇲🇱": ["ml", "mali", "flag", "nation", "country", "banner"], + "🇲🇹": ["mt", "malta", "flag", "nation", "country", "banner"], + "🇲🇭": ["mh", "marshall", "islands", "flag", "nation", "country", "banner"], + "🇲🇶": ["mq", "martinique", "flag", "nation", "country", "banner"], + "🇲🇷": ["mr", "mauritania", "flag", "nation", "country", "banner"], + "🇲🇺": ["mu", "mauritius", "flag", "nation", "country", "banner"], + "🇾🇹": ["yt", "mayotte", "flag", "nation", "country", "banner"], + "🇲🇽": ["mx", "mexico", "flag", "nation", "country", "banner"], + "🇫🇲": ["fm", "micronesia", "federated", "states", "flag", "nation", "country", "banner"], + "🇲🇩": ["md", "moldova", "republic", "flag", "nation", "country", "banner"], + "🇲🇨": ["mc", "monaco", "flag", "nation", "country", "banner"], + "🇲🇳": ["mn", "mongolia", "flag", "nation", "country", "banner"], + "🇲🇪": ["me", "montenegro", "flag", "nation", "country", "banner"], + "🇲🇸": ["ms", "montserrat", "flag", "nation", "country", "banner"], + "🇲🇦": ["ma", "morocco", "flag", "nation", "country", "banner"], + "🇲🇿": ["mz", "mozambique", "flag", "nation", "country", "banner"], + "🇲🇲": ["mm", "myanmar", "flag", "nation", "country", "banner"], + "🇳🇦": ["na", "namibia", "flag", "nation", "country", "banner"], + "🇳🇷": ["nr", "nauru", "flag", "nation", "country", "banner"], + "🇳🇵": ["np", "nepal", "flag", "nation", "country", "banner"], + "🇳🇱": ["nl", "netherlands", "flag", "nation", "country", "banner"], + "🇳🇨": ["nc", "new", "caledonia", "flag", "nation", "country", "banner"], + "🇳🇿": ["nz", "new", "zealand", "flag", "nation", "country", "banner"], + "🇳🇮": ["ni", "nicaragua", "flag", "nation", "country", "banner"], + "🇳🇪": ["ne", "niger", "flag", "nation", "country", "banner"], + "🇳🇬": ["ng", "nigeria", "flag", "nation", "country", "banner"], + "🇳🇺": ["nu", "niue", "flag", "nation", "country", "banner"], + "🇳🇫": ["nf", "norfolk", "island", "flag", "nation", "country", "banner"], + "🇲🇵": ["mp", "northern", "mariana", "islands", "flag", "nation", "country", "banner"], + "🇰🇵": ["kp", "democratic", "people", "republic", "north", "korea", "nation", "flag", "country", "banner"], + "🇳🇴": ["no", "norway", "flag", "nation", "country", "banner"], + "🇴🇲": ["om", "oman", "flag", "nation", "country", "banner"], + "🇵🇰": ["pk", "pakistan", "flag", "nation", "country", "banner"], + "🇵🇼": ["pw", "palau", "flag", "nation", "country", "banner"], + "🇵🇸": ["ps", "palestine", "palestinian", "territories", "flag", "nation", "country", "banner"], + "🇵🇦": ["pa", "panama", "flag", "nation", "country", "banner"], + "🇵🇬": ["pg", "papua", "new", "guinea", "flag", "nation", "country", "banner"], + "🇵🇾": ["py", "paraguay", "flag", "nation", "country", "banner"], + "🇵🇪": ["pe", "peru", "flag", "nation", "country", "banner"], + "🇵🇭": ["ph", "philippines", "flag", "nation", "country", "banner"], + "🇵🇳": ["pn", "pitcairn", "flag", "nation", "country", "banner"], + "🇵🇱": ["pl", "poland", "flag", "nation", "country", "banner"], + "🇵🇹": ["pt", "portugal", "flag", "nation", "country", "banner"], + "🇵🇷": ["pr", "puerto", "rico", "flag", "nation", "country", "banner"], + "🇶🇦": ["qa", "qatar", "flag", "nation", "country", "banner"], + "🇷🇪": ["re", "reunion", "réunion", "flag", "nation", "country", "banner"], + "🇷🇴": ["ro", "romania", "flag", "nation", "country", "banner"], + "🇷🇺": ["ru", "russian", "federation", "flag", "nation", "country", "banner"], + "🇷🇼": ["rw", "rwanda", "flag", "nation", "country", "banner"], + "🇧🇱": ["bl", "saint", "barthélemy", "flag", "nation", "country", "banner"], + "🇸🇭": ["sh", "saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner"], + "🇰🇳": ["kn", "saint", "kitts", "nevis", "flag", "nation", "country", "banner"], + "🇱🇨": ["lc", "saint", "lucia", "flag", "nation", "country", "banner"], + "🇵🇲": ["pm", "saint", "pierre", "miquelon", "flag", "nation", "country", "banner"], + "🇻🇨": ["vc", "saint", "vincent", "grenadines", "flag", "nation", "country", "banner"], + "🇼🇸": ["ws", "western", "samoa", "flag", "nation", "country", "banner"], + "🇸🇲": ["sm", "san", "marino", "flag", "nation", "country", "banner"], + "🇸🇹": ["st", "sao", "tome", "principe", "flag", "nation", "country", "banner"], + "🇸🇦": ["saudi", "arabia", "flag", "nation", "country", "banner"], + "🇸🇳": ["sn", "senegal", "flag", "nation", "country", "banner"], + "🇷🇸": ["rs", "serbia", "flag", "nation", "country", "banner"], + "🇸🇨": ["sc", "seychelles", "flag", "nation", "country", "banner"], + "🇸🇱": ["sl", "sierra", "leone", "flag", "nation", "country", "banner"], + "🇸🇬": ["sg", "singapore", "flag", "nation", "country", "banner"], + "🇸🇽": ["sx", "sint", "maarten", "dutch", "flag", "nation", "country", "banner"], + "🇸🇰": ["sk", "slovakia", "flag", "nation", "country", "banner"], + "🇸🇮": ["si", "slovenia", "flag", "nation", "country", "banner"], + "🇸🇧": ["sb", "solomon", "islands", "flag", "nation", "country", "banner"], + "🇸🇴": ["so", "somalia", "flag", "nation", "country", "banner"], + "🇿🇦": ["za", "south", "africa", "flag", "nation", "country", "banner"], + "🇬🇸": ["gs", "south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner"], + "🇰🇷": ["kr", "south", "korea", "nation", "flag", "country", "banner"], + "🇸🇸": ["ss", "south", "sudan", "flag", "nation", "country", "banner"], + "🇪🇸": ["es", "spain", "españa", "flag", "nation", "country", "banner"], + "🇱🇰": ["lk", "sri", "lanka", "flag", "nation", "country", "banner"], + "🇸🇩": ["sd", "sudan", "flag", "nation", "country", "banner"], + "🇸🇷": ["sr", "suriname", "flag", "nation", "country", "banner"], + "🇸🇿": ["sz", "eswatini", "flag", "nation", "country", "banner"], + "🇸🇪": ["se", "sweden", "flag", "nation", "country", "banner"], + "🇨🇭": ["ch", "switzerland", "confoederatio", "helvetica", "flag", "nation", "country", "banner"], + "🇸🇾": ["sy", "syrian", "arab", "republic", "flag", "nation", "country", "banner"], + "🇹🇼": ["tw", "taiwan", "flag", "nation", "country", "banner"], + "🇹🇯": ["tj", "tajikistan", "flag", "nation", "country", "banner"], + "🇹🇿": ["tz", "tanzania", "united", "republic", "flag", "nation", "country", "banner"], + "🇹🇭": ["th", "thailand", "flag", "nation", "country", "banner"], + "🇹🇱": ["tl", "timor", "leste", "flag", "nation", "country", "banner"], + "🇹🇬": ["tg", "togo", "flag", "nation", "country", "banner"], + "🇹🇰": ["tk", "tokelau", "flag", "nation", "country", "banner"], + "🇹🇴": ["to", "tonga", "flag", "nation", "country", "banner"], + "🇹🇹": ["tt", "trinidad", "tobago", "flag", "nation", "country", "banner"], + "🇹🇦": ["ta", "tristan", "da", "cunha", "flag", "nation", "country", "banner"], + "🇹🇳": ["tn", "tunisia", "flag", "nation", "country", "banner"], + "🇹🇷": ["tr", "turkey", "türkiye", "flag", "nation", "country", "banner"], + "🇹🇲": ["tm", "turkmenistan", "flag", "nation", "country", "banner"], + "🇹🇨": ["tc", "turks", "caicos", "islands", "flag", "nation", "country", "banner"], + "🇹🇻": ["tv", "tuvalu", "flag", "nation", "country", "banner"], + "🇺🇬": ["ug", "uganda", "flag", "nation", "country", "banner"], + "🇺🇦": ["ua", "ukraine", "flag", "nation", "country", "banner"], + "🇦🇪": ["ae", "united", "arab", "emirates", "flag", "nation", "country", "banner"], + "🇬🇧": ["gb", "united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "uk", "english", "england", "union jack"], "🏴": ["flag", "english"], "🏴": ["flag", "scottish"], "🏴": ["flag", "welsh"], - "🇺🇸": ["united", "states", "america", "flag", "nation", "country", "banner"], - "🇻🇮": ["virgin", "islands", "us", "flag", "nation", "country", "banner"], - "🇺🇾": ["uy", "flag", "nation", "country", "banner"], - "🇺🇿": ["uz", "flag", "nation", "country", "banner"], - "🇻🇺": ["vu", "flag", "nation", "country", "banner"], - "🇻🇦": ["vatican", "city", "flag", "nation", "country", "banner"], - "🇻🇪": ["ve", "bolivarian", "republic", "flag", "nation", "country", "banner"], - "🇻🇳": ["viet", "nam", "flag", "nation", "country", "banner"], - "🇼🇫": ["wallis", "futuna", "flag", "nation", "country", "banner"], - "🇪🇭": ["western", "sahara", "flag", "nation", "country", "banner"], - "🇾🇪": ["ye", "flag", "nation", "country", "banner"], - "🇿🇲": ["zm", "flag", "nation", "country", "banner"], - "🇿🇼": ["zw", "flag", "nation", "country", "banner"], - "🇺🇳": ["un", "flag", "banner"], + "🇺🇸": ["us", "usa", "united", "states", "america", "flag", "nation", "country", "banner"], + "🇻🇮": ["vi", "virgin", "islands", "us", "flag", "nation", "country", "banner"], + "🇺🇾": ["uy", "uruguay", "flag", "nation", "country", "banner"], + "🇺🇿": ["uz", "uzbekistan", "flag", "nation", "country", "banner"], + "🇻🇺": ["vu", "vanuatu", "flag", "nation", "country", "banner"], + "🇻🇦": ["va", "vatican", "city", "flag", "nation", "country", "banner"], + "🇻🇪": ["ve", "venezuela", "flag", "nation", "country", "banner"], + "🇻🇳": ["vn", "viet", "nam", "flag", "nation", "country", "banner"], + "🇼🇫": ["wf", "wallis", "futuna", "flag", "nation", "country", "banner"], + "🇪🇭": ["eh", "western", "sahara", "flag", "nation", "country", "banner"], + "🇾🇪": ["ye", "yemen", "flag", "nation", "country", "banner"], + "🇿🇲": ["zm", "zambia", "flag", "nation", "country", "banner"], + "🇿🇼": ["zw", "zimbabwe", "flag", "nation", "country", "banner"], + "🇺🇳": ["un", "united", "nation", "flag", "banner"], "🏴☠️": ["skull", "crossbones", "flag", "banner"] } diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue index 6b890d41a8..db89265bff 100644 --- a/packages/frontend/src/widgets/WidgetActivity.vue +++ b/packages/frontend/src/widgets/WidgetActivity.vue @@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import XCalendar from './WidgetActivity.calendar.vue'; import XChart from './WidgetActivity.chart.vue'; import { GetFormResultType } from '@/scripts/form.js'; diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue index cf2012b74d..fef026244c 100644 --- a/packages/frontend/src/widgets/WidgetAichan.vue +++ b/packages/frontend/src/widgets/WidgetAichan.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, onUnmounted, shallowRef } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; const name = 'ai'; diff --git a/packages/frontend/src/widgets/WidgetAiscript.vue b/packages/frontend/src/widgets/WidgetAiscript.vue index 1b8c8ad9bc..5968b54626 100644 --- a/packages/frontend/src/widgets/WidgetAiscript.vue +++ b/packages/frontend/src/widgets/WidgetAiscript.vue @@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import { Interpreter, Parser, utils } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import MkContainer from '@/components/MkContainer.vue'; diff --git a/packages/frontend/src/widgets/WidgetAiscriptApp.vue b/packages/frontend/src/widgets/WidgetAiscriptApp.vue index 08037222d0..10248a840a 100644 --- a/packages/frontend/src/widgets/WidgetAiscriptApp.vue +++ b/packages/frontend/src/widgets/WidgetAiscriptApp.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, Ref, ref, watch } from 'vue'; import { Interpreter, Parser } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import { createAiScriptEnv } from '@/scripts/aiscript/api.js'; diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue index a7bdd4c49c..11082c1e3f 100644 --- a/packages/frontend/src/widgets/WidgetButton.vue +++ b/packages/frontend/src/widgets/WidgetButton.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { Interpreter, Parser } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import { createAiScriptEnv } from '@/scripts/aiscript/api.js'; diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue index 7fabd09a24..c78e291a2e 100644 --- a/packages/frontend/src/widgets/WidgetCalendar.vue +++ b/packages/frontend/src/widgets/WidgetCalendar.vue @@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import { i18n } from '@/i18n.js'; import { useInterval } from '@/scripts/use-interval.js'; diff --git a/packages/frontend/src/widgets/WidgetClicker.vue b/packages/frontend/src/widgets/WidgetClicker.vue index 8ab62d416e..56a9f2933d 100644 --- a/packages/frontend/src/widgets/WidgetClicker.vue +++ b/packages/frontend/src/widgets/WidgetClicker.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import MkClickerGame from '@/components/MkClickerGame.vue'; diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue index ca115cfcf7..22f053db59 100644 --- a/packages/frontend/src/widgets/WidgetClock.vue +++ b/packages/frontend/src/widgets/WidgetClock.vue @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import MkAnalogClock from '@/components/MkAnalogClock.vue'; diff --git a/packages/frontend/src/widgets/WidgetDigitalClock.vue b/packages/frontend/src/widgets/WidgetDigitalClock.vue index ba7b82aad5..a4b90c49d3 100644 --- a/packages/frontend/src/widgets/WidgetDigitalClock.vue +++ b/packages/frontend/src/widgets/WidgetDigitalClock.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import { timezones } from '@/scripts/timezones.js'; import MkDigitalClock from '@/components/MkDigitalClock.vue'; diff --git a/packages/frontend/src/widgets/WidgetFederation.vue b/packages/frontend/src/widgets/WidgetFederation.vue index 47f94402fb..d32a4e836b 100644 --- a/packages/frontend/src/widgets/WidgetFederation.vue +++ b/packages/frontend/src/widgets/WidgetFederation.vue @@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import MkMiniChart from '@/components/MkMiniChart.vue'; diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue index 16e1a42da2..0fc96c0d35 100644 --- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue +++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { shallowRef } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import MkTagCloud from '@/components/MkTagCloud.vue'; diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue index 469df109f4..72cfe2822d 100644 --- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue +++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue @@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form'; import { host } from '@/config'; import { instance } from '@/instance'; diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue index cca368ec8f..10bc257e12 100644 --- a/packages/frontend/src/widgets/WidgetJobQueue.vue +++ b/packages/frontend/src/widgets/WidgetJobQueue.vue @@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onUnmounted, reactive, ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import { useStream } from '@/stream.js'; import number from '@/filters/number.js'; diff --git a/packages/frontend/src/widgets/WidgetMemo.vue b/packages/frontend/src/widgets/WidgetMemo.vue index 1f5666b3ef..167014270a 100644 --- a/packages/frontend/src/widgets/WidgetMemo.vue +++ b/packages/frontend/src/widgets/WidgetMemo.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import { defaultStore } from '@/store.js'; diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue index 796578395f..506fc6b4d4 100644 --- a/packages/frontend/src/widgets/WidgetNotifications.vue +++ b/packages/frontend/src/widgets/WidgetNotifications.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import XNotifications from '@/components/MkNotifications.vue'; diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue index 46fe991f37..0a6fec7f2e 100644 --- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue +++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import { useInterval } from '@/scripts/use-interval.js'; diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue index 9af4f80873..b1c62caf4d 100644 --- a/packages/frontend/src/widgets/WidgetPhotos.vue +++ b/packages/frontend/src/widgets/WidgetPhotos.vue @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onUnmounted, ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import { useStream } from '@/stream.js'; import { getStaticImageUrl } from '@/scripts/media-proxy.js'; diff --git a/packages/frontend/src/widgets/WidgetPostForm.vue b/packages/frontend/src/widgets/WidgetPostForm.vue index 320b47a4ff..9979ae256e 100644 --- a/packages/frontend/src/widgets/WidgetPostForm.vue +++ b/packages/frontend/src/widgets/WidgetPostForm.vue @@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkPostForm from '@/components/MkPostForm.vue'; diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue index fc54af2d71..3ff57bab86 100644 --- a/packages/frontend/src/widgets/WidgetProfile.vue +++ b/packages/frontend/src/widgets/WidgetProfile.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import { $i } from '@/account.js'; import { userPage } from '@/filters/user.js'; diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index be662e0ed1..78678920c7 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch, computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import { url as base } from '@/config.js'; diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index 07f922bfec..34b4b8f884 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch, computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import MarqueeText from '@/components/MkMarquee.vue'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; diff --git a/packages/frontend/src/widgets/WidgetSlideshow.vue b/packages/frontend/src/widgets/WidgetSlideshow.vue index 82b6246add..eccb9a00bf 100644 --- a/packages/frontend/src/widgets/WidgetSlideshow.vue +++ b/packages/frontend/src/widgets/WidgetSlideshow.vue @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, ref, shallowRef } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import { useInterval } from '@/scripts/use-interval.js'; diff --git a/packages/frontend/src/widgets/WidgetTimeline.vue b/packages/frontend/src/widgets/WidgetTimeline.vue index 2d1d5873d3..ea40471fa8 100644 --- a/packages/frontend/src/widgets/WidgetTimeline.vue +++ b/packages/frontend/src/widgets/WidgetTimeline.vue @@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import * as os from '@/os.js'; import MkContainer from '@/components/MkContainer.vue'; diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue index 0d4df28a95..51de02d308 100644 --- a/packages/frontend/src/widgets/WidgetTrends.vue +++ b/packages/frontend/src/widgets/WidgetTrends.vue @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import MkMiniChart from '@/components/MkMiniChart.vue'; diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue index 33585cd721..35f29b5e21 100644 --- a/packages/frontend/src/widgets/WidgetUnixClock.vue +++ b/packages/frontend/src/widgets/WidgetUnixClock.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onUnmounted, ref, watch } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; const name = 'unixClock'; diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue index 4f3ce1c8c5..81b14fde3f 100644 --- a/packages/frontend/src/widgets/WidgetUserList.vue +++ b/packages/frontend/src/widgets/WidgetUserList.vue @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; +import { useWidgetPropsManager, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import { GetFormResultType } from '@/scripts/form.js'; import MkContainer from '@/components/MkContainer.vue'; import * as os from '@/os.js'; diff --git a/packages/frontend/test/home.test.ts b/packages/frontend/test/home.test.ts index 6d38b7e526..094ea071b9 100644 --- a/packages/frontend/test/home.test.ts +++ b/packages/frontend/test/home.test.ts @@ -3,13 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { describe, test, assert, afterEach } from 'vitest'; -import { render, cleanup, type RenderResult } from '@testing-library/vue'; +import { afterEach, assert, describe, test } from 'vitest'; +import { cleanup, render, type RenderResult } from '@testing-library/vue'; import './init'; import type * as Misskey from 'misskey-js'; import { directives } from '@/directives/index.js'; import { components } from '@/components/index.js'; import XHome from '@/pages/user/home.vue'; +import 'intersection-observer'; describe('XHome', () => { const renderHome = (user: Partial<Misskey.entities.UserDetailed>): RenderResult => { diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index abb3cae4b1..ea4e0c4163 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1635,9 +1635,6 @@ type FetchLike = (input: string, init?: { // @public (undocumented) type FetchRssRequest = operations['fetch-rss']['requestBody']['content']['application/json']; -// @public (undocumented) -export const ffVisibility: readonly ["public", "followers", "private"]; - // @public (undocumented) type Flash = components['schemas']['Flash']; @@ -1677,6 +1674,9 @@ type FlashUnlikeRequest = operations['flash/unlike']['requestBody']['content'][' // @public (undocumented) type FlashUpdateRequest = operations['flash/update']['requestBody']['content']['application/json']; +// @public (undocumented) +export const followersVisibilities: readonly ["public", "followers", "private"]; + // @public (undocumented) type Following = components['schemas']['Following']; @@ -1725,6 +1725,9 @@ type FollowingUpdateRequest = operations['following/update']['requestBody']['con // @public (undocumented) type FollowingUpdateResponse = operations['following/update']['responses']['200']['content']['application/json']; +// @public (undocumented) +export const followingVisibilities: readonly ["public", "followers", "private"]; + // @public (undocumented) type GalleryFeaturedRequest = operations['gallery/featured']['requestBody']['content']['application/json']; @@ -2337,7 +2340,7 @@ type Notification_2 = components['schemas']['Notification']; type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json']; // @public (undocumented) -export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "achievementEarned"]; +export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned"]; // @public (undocumented) type Page = components['schemas']['Page']; diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 0b54c6a59c..53d5044d68 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -25,17 +25,17 @@ "@microsoft/api-extractor": "7.38.5", "@swc/jest": "0.2.29", "@types/jest": "29.5.11", - "@types/node": "20.10.4", + "@types/node": "20.10.5", "@typescript-eslint/eslint-plugin": "6.14.0", "@typescript-eslint/parser": "6.14.0", - "eslint": "8.55.0", + "eslint": "8.56.0", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", "ncp": "2.0.0", "nodemon": "3.0.2", - "tsd": "0.29.0", + "tsd": "0.30.0", "typescript": "5.3.3" }, "files": [ diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index a8f0b96d5d..e769bb9e6d 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -1,10 +1,12 @@ -export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'achievementEarned'] as const; +export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const; -export const ffVisibility = ['public', 'followers', 'private'] as const; +export const followingVisibilities = ['public', 'followers', 'private'] as const; + +export const followersVisibilities = ['public', 'followers', 'private'] as const; export const permissions = [ 'read:account', diff --git a/packages/misskey-js/src/index.ts b/packages/misskey-js/src/index.ts index e78501fdfd..54cae8ec03 100644 --- a/packages/misskey-js/src/index.ts +++ b/packages/misskey-js/src/index.ts @@ -16,7 +16,8 @@ export const permissions = consts.permissions; export const notificationTypes = consts.notificationTypes; export const noteVisibilities = consts.noteVisibilities; export const mutedNoteReasons = consts.mutedNoteReasons; -export const ffVisibility = consts.ffVisibility; +export const followingVisibilities = consts.followingVisibilities; +export const followersVisibilities = consts.followersVisibilities; export const moderationLogTypes = consts.moderationLogTypes; // api extractor not supported yet diff --git a/packages/sw/package.json b/packages/sw/package.json index 990e991966..c48efd6ea6 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -9,15 +9,15 @@ "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { - "esbuild": "0.19.8", + "esbuild": "0.19.9", "idb-keyval": "6.2.1", "misskey-js": "workspace:*" }, "devDependencies": { "@typescript-eslint/parser": "6.14.0", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", - "eslint": "8.55.0", - "eslint-plugin-import": "2.29.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1", "nodemon": "3.0.2", "typescript": "5.3.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c0bc470b0..278109f12d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,8 +13,8 @@ importers: .: dependencies: cssnano: - specifier: 6.0.1 - version: 6.0.1(postcss@8.4.32) + specifier: 6.0.2 + version: 6.0.2(postcss@8.4.32) execa: specifier: 8.0.1 version: 8.0.1 @@ -25,8 +25,8 @@ importers: specifier: 8.4.32 version: 8.4.32 terser: - specifier: 5.24.0 - version: 5.24.0 + specifier: 5.26.0 + version: 5.26.0 typescript: specifier: 5.3.3 version: 5.3.3 @@ -37,10 +37,10 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: 6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(eslint@8.56.0)(typescript@5.3.3) cross-env: specifier: 7.0.3 version: 7.0.3 @@ -48,8 +48,8 @@ importers: specifier: 13.6.1 version: 13.6.1 eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 ncp: specifier: 2.0.0 version: 2.0.0 @@ -75,8 +75,8 @@ importers: specifier: 5.10.2 version: 5.10.2 '@discordapp/twemoji': - specifier: 14.1.2 - version: 14.1.2 + specifier: 15.0.2 + version: 15.0.2 '@fastify/accepts': specifier: 4.3.0 version: 4.3.0 @@ -128,6 +128,9 @@ importers: '@swc/core': specifier: 1.3.100 version: 1.3.100 + '@twemoji/parser': + specifier: 15.0.0 + version: 15.0.0 accepts: specifier: 1.3.8 version: 1.3.8 @@ -150,8 +153,8 @@ importers: specifier: 1.20.2 version: 1.20.2 bullmq: - specifier: 4.15.3 - version: 4.15.3 + specifier: 4.15.4 + version: 4.15.4 cacheable-lookup: specifier: 7.0.0 version: 7.0.0 @@ -201,8 +204,8 @@ importers: specifier: 4.0.0 version: 4.0.0 got: - specifier: 13.0.0 - version: 13.0.0 + specifier: 14.0.0 + version: 14.0.0 happy-dom: specifier: 10.0.3 version: 10.0.3 @@ -243,11 +246,11 @@ importers: specifier: 0.36.0 version: 0.36.0 mfm-js: - specifier: 0.23.3 - version: 0.23.3 + specifier: 0.24.0 + version: 0.24.0 microformats-parser: - specifier: 1.5.2 - version: 1.5.2 + specifier: 2.0.2 + version: 2.0.2 mime-types: specifier: 2.1.35 version: 2.1.35 @@ -377,9 +380,6 @@ importers: tsconfig-paths: specifier: 4.2.0 version: 4.2.0 - twemoji-parser: - specifier: 14.0.0 - version: 14.0.0 typeorm: specifier: 0.3.17 version: 0.3.17(ioredis@5.3.2)(pg@8.11.3) @@ -548,8 +548,8 @@ importers: specifier: 0.7.34 version: 0.7.34 '@types/node': - specifier: 20.10.4 - version: 20.10.4 + specifier: 20.10.5 + version: 20.10.5 '@types/node-fetch': specifier: 3.0.3 version: 3.0.3 @@ -618,10 +618,10 @@ importers: version: 8.5.10 '@typescript-eslint/eslint-plugin': specifier: 6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(eslint@8.56.0)(typescript@5.3.3) aws-sdk-client-mock: specifier: 3.0.0 version: 3.0.0 @@ -629,17 +629,17 @@ importers: specifier: 7.0.3 version: 7.0.3 eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 eslint-plugin-import: - specifier: 2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0) + specifier: 2.29.1 + version: 2.29.1(@typescript-eslint/parser@6.14.0)(eslint@8.56.0) execa: specifier: 8.0.1 version: 8.0.1 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.10.4) + version: 29.7.0(@types/node@20.10.5) jest-mock: specifier: 29.7.0 version: 29.7.0 @@ -653,32 +653,35 @@ importers: packages/frontend: dependencies: '@discordapp/twemoji': - specifier: 14.1.2 - version: 14.1.2 + specifier: 15.0.2 + version: 15.0.2 '@github/webauthn-json': specifier: 2.1.1 version: 2.1.1 '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.9.0) + version: 6.1.0(rollup@4.9.1) '@rollup/plugin-replace': specifier: 5.0.5 - version: 5.0.5(rollup@4.9.0) + version: 5.0.5(rollup@4.9.1) '@rollup/pluginutils': specifier: 5.1.0 - version: 5.1.0(rollup@4.9.0) + version: 5.1.0(rollup@4.9.1) '@syuilo/aiscript': specifier: 0.16.0 version: 0.16.0 '@tabler/icons-webfont': specifier: 2.44.0 version: 2.44.0 + '@twemoji/parser': + specifier: 15.0.0 + version: 15.0.0 '@vitejs/plugin-vue': specifier: 4.5.2 - version: 4.5.2(vite@5.0.8)(vue@3.3.11) + version: 4.5.2(vite@5.0.10)(vue@3.3.12) '@vue/compiler-sfc': - specifier: 3.3.11 - version: 3.3.11 + specifier: 3.3.12 + version: 3.3.12 aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.0.6 version: github.com/aiscript-dev/aiscript-vscode/b5a8aa0ad927831a0b867d1c183460a14e6c48cd @@ -686,8 +689,8 @@ importers: specifier: 1.8.6 version: 1.8.6 broadcast-channel: - specifier: 6.0.0 - version: 6.0.0 + specifier: 7.0.0 + version: 7.0.0 browser-image-resizer: specifier: github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3 version: github.com/misskey-dev/browser-image-resizer/0227e860621e55cbed0aabe6dc601096a7748c4a @@ -734,8 +737,8 @@ importers: specifier: 5.0.1 version: 5.0.1 gsap: - specifier: 3.12.3 - version: 3.12.3 + specifier: 3.12.4 + version: 3.12.4 idb-keyval: specifier: 6.2.1 version: 6.2.1 @@ -752,8 +755,8 @@ importers: specifier: 0.19.0 version: 0.19.0 mfm-js: - specifier: 0.23.3 - version: 0.23.3 + specifier: 0.24.0 + version: 0.24.0 misskey-js: specifier: workspace:* version: link:../misskey-js @@ -764,8 +767,8 @@ importers: specifier: 2.3.1 version: 2.3.1 rollup: - specifier: 4.9.0 - version: 4.9.0 + specifier: 4.9.1 + version: 4.9.1 sanitize-html: specifier: 2.11.0 version: 2.11.0 @@ -773,8 +776,8 @@ importers: specifier: 1.69.5 version: 1.69.5 shiki: - specifier: 0.14.6 - version: 0.14.6 + specifier: 0.14.7 + version: 0.14.7 strict-event-emitter-types: specifier: 2.0.0 version: 2.0.0 @@ -796,9 +799,6 @@ importers: tsconfig-paths: specifier: 4.2.0 version: 4.2.0 - twemoji-parser: - specifier: 14.0.0 - version: 14.0.0 typescript: specifier: 5.3.3 version: 5.3.3 @@ -807,74 +807,74 @@ importers: version: 9.0.1 v-code-diff: specifier: 1.7.2 - version: 1.7.2(vue@3.3.11) + version: 1.7.2(vue@3.3.12) vite: - specifier: 5.0.8 - version: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + specifier: 5.0.10 + version: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) vue: - specifier: 3.3.11 - version: 3.3.11(typescript@5.3.3) + specifier: 3.3.12 + version: 3.3.12(typescript@5.3.3) vuedraggable: specifier: next - version: 4.1.0(vue@3.3.11) + version: 4.1.0(vue@3.3.12) devDependencies: '@storybook/addon-actions': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/addon-essentials': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/addon-links': - specifier: 7.6.4 - version: 7.6.4(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react@18.2.0) '@storybook/addon-storysource': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/addons': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/jest': specifier: 0.2.3 version: 0.2.3(vitest@0.34.6) '@storybook/manager-api': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/react': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3) '@storybook/react-vite': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0)(rollup@4.9.0)(typescript@5.3.3)(vite@5.0.8) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0)(rollup@4.9.1)(typescript@5.3.3)(vite@5.0.10) '@storybook/testing-library': specifier: 0.2.2 version: 0.2.2 '@storybook/theming': - specifier: 7.6.4 - version: 7.6.4(react-dom@18.2.0)(react@18.2.0) + specifier: 7.6.5 + version: 7.6.5(react-dom@18.2.0)(react@18.2.0) '@storybook/types': - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 '@storybook/vue3': - specifier: 7.6.4 - version: 7.6.4(@vue/compiler-core@3.3.11)(vue@3.3.11) + specifier: 7.6.5 + version: 7.6.5(@vue/compiler-core@3.3.12)(vue@3.3.12) '@storybook/vue3-vite': - specifier: 7.6.4 - version: 7.6.4(@vue/compiler-core@3.3.11)(typescript@5.3.3)(vite@5.0.8)(vue@3.3.11) + specifier: 7.6.5 + version: 7.6.5(@vue/compiler-core@3.3.12)(typescript@5.3.3)(vite@5.0.10)(vue@3.3.12) '@testing-library/vue': specifier: 8.0.1 - version: 8.0.1(@vue/compiler-sfc@3.3.11)(vue@3.3.11) + version: 8.0.1(@vue/compiler-sfc@3.3.12)(vue@3.3.12) '@types/escape-regexp': specifier: 0.0.3 version: 0.0.3 @@ -888,8 +888,8 @@ importers: specifier: 4.0.6 version: 4.0.6 '@types/node': - specifier: 20.10.4 - version: 20.10.4 + specifier: 20.10.5 + version: 20.10.5 '@types/punycode': specifier: 2.1.3 version: 2.1.3 @@ -910,16 +910,16 @@ importers: version: 8.5.10 '@typescript-eslint/eslint-plugin': specifier: 6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(eslint@8.56.0)(typescript@5.3.3) '@vitest/coverage-v8': specifier: 0.34.6 version: 0.34.6(vitest@0.34.6) '@vue/runtime-core': - specifier: 3.3.11 - version: 3.3.11 + specifier: 3.3.12 + version: 3.3.12 acorn: specifier: 8.11.2 version: 8.11.2 @@ -930,20 +930,23 @@ importers: specifier: 13.6.1 version: 13.6.1 eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 eslint-plugin-import: - specifier: 2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0) + specifier: 2.29.1 + version: 2.29.1(@typescript-eslint/parser@6.14.0)(eslint@8.56.0) eslint-plugin-vue: specifier: 9.19.2 - version: 9.19.2(eslint@8.55.0) + version: 9.19.2(eslint@8.56.0) fast-glob: specifier: 3.3.2 version: 3.3.2 happy-dom: specifier: 10.0.3 version: 10.0.3 + intersection-observer: + specifier: 0.12.2 + version: 0.12.2 micromatch: specifier: 4.0.5 version: 4.0.5 @@ -969,11 +972,11 @@ importers: specifier: 2.0.3 version: 2.0.3 storybook: - specifier: 7.6.4 - version: 7.6.4 + specifier: 7.6.5 + version: 7.6.5 storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.6.4)(@storybook/components@7.6.4)(@storybook/core-events@7.6.4)(@storybook/manager-api@7.6.4)(@storybook/preview-api@7.6.4)(@storybook/theming@7.6.4)(@storybook/types@7.6.4)(react-dom@18.2.0)(react@18.2.0) + version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.6.5)(@storybook/components@7.6.5)(@storybook/core-events@7.6.5)(@storybook/manager-api@7.6.5)(@storybook/preview-api@7.6.5)(@storybook/theming@7.6.5)(@storybook/types@7.6.5)(react-dom@18.2.0)(react@18.2.0) summaly: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/d2a3e07205c3c9769bc5a7b42031c8884b5a25c8 @@ -982,13 +985,13 @@ importers: version: 1.0.3 vitest: specifier: 0.34.6 - version: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.24.0) + version: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.26.0) vitest-fetch-mock: specifier: 0.2.2 version: 0.2.2(vitest@0.34.6) vue-eslint-parser: specifier: 9.3.2 - version: 9.3.2(eslint@8.55.0) + version: 9.3.2(eslint@8.56.0) vue-tsc: specifier: 1.8.25 version: 1.8.25(typescript@5.3.3) @@ -1010,7 +1013,7 @@ importers: devDependencies: '@microsoft/api-extractor': specifier: 7.38.5 - version: 7.38.5(@types/node@20.10.4) + version: 7.38.5(@types/node@20.10.5) '@swc/jest': specifier: 0.2.29 version: 0.2.29(@swc/core@1.3.100) @@ -1018,20 +1021,20 @@ importers: specifier: 29.5.11 version: 29.5.11 '@types/node': - specifier: 20.10.4 - version: 20.10.4 + specifier: 20.10.5 + version: 20.10.5 '@typescript-eslint/eslint-plugin': specifier: 6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(eslint@8.56.0)(typescript@5.3.3) eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.10.4) + version: 29.7.0(@types/node@20.10.5) jest-fetch-mock: specifier: 3.0.3 version: 3.0.3 @@ -1048,8 +1051,8 @@ importers: specifier: 3.0.2 version: 3.0.2 tsd: - specifier: 0.29.0 - version: 0.29.0 + specifier: 0.30.0 + version: 0.30.0 typescript: specifier: 5.3.3 version: 5.3.3 @@ -1090,8 +1093,8 @@ importers: packages/sw: dependencies: esbuild: - specifier: 0.19.8 - version: 0.19.8 + specifier: 0.19.9 + version: 0.19.9 idb-keyval: specifier: 6.2.1 version: 6.2.1 @@ -1101,16 +1104,16 @@ importers: devDependencies: '@typescript-eslint/parser': specifier: 6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) + version: 6.14.0(eslint@8.56.0)(typescript@5.3.3) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.67 version: /@types/serviceworker@0.0.67 eslint: - specifier: 8.55.0 - version: 8.55.0 + specifier: 8.56.0 + version: 8.56.0 eslint-plugin-import: - specifier: 2.29.0 - version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0) + specifier: 2.29.1 + version: 2.29.1(@typescript-eslint/parser@6.14.0)(eslint@8.56.0) nodemon: specifier: 3.0.2 version: 3.0.2 @@ -2172,14 +2175,6 @@ packages: dependencies: '@babel/types': 7.22.17 - /@babel/parser@7.23.3: - resolution: {integrity: sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.22.17 - dev: true - /@babel/parser@7.23.5: resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} engines: {node: '>=6.0.0'} @@ -3284,12 +3279,21 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 + dev: false /@babel/runtime@7.23.2: resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 + dev: true + + /@babel/runtime@7.23.4: + resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false /@babel/template@7.22.15: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} @@ -3305,7 +3309,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.22.13 - '@babel/parser': 7.23.3 + '@babel/parser': 7.23.5 '@babel/types': 7.22.17 dev: true @@ -3319,7 +3323,7 @@ packages: '@babel/helper-function-name': 7.22.5 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.3 + '@babel/parser': 7.23.5 '@babel/types': 7.22.17 debug: 4.3.4(supports-color@5.5.0) globals: 11.12.0 @@ -3594,12 +3598,12 @@ packages: - web-streams-polyfill dev: false - /@discordapp/twemoji@14.1.2: - resolution: {integrity: sha512-Rkuu30/biwy8Zss0r5qfFvQzoQGPTHXzA7Y/MPMkCQqFd0WskoYvjfJRTz0iuZwUpMfrgbM8eakSsptCxmOqog==} + /@discordapp/twemoji@15.0.2: + resolution: {integrity: sha512-SrWKcv3SrGfrLQ/vfUnA+bAG73Q6Yjys01UuoY5SzUlc9iS03amQ6DxLhzVsjW/aTdgiMQdUatLidD+YPfYMCw==} dependencies: + '@twemoji/parser': 15.0.0 fs-extra: 8.1.0 jsonfile: 5.0.0 - twemoji-parser: 14.0.0 universalify: 0.1.2 dev: false @@ -3633,6 +3637,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm64@0.19.9: + resolution: {integrity: sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -3650,6 +3663,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm@0.19.9: + resolution: {integrity: sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -3667,6 +3689,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-x64@0.19.9: + resolution: {integrity: sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -3684,6 +3715,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-arm64@0.19.9: + resolution: {integrity: sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -3701,6 +3741,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-x64@0.19.9: + resolution: {integrity: sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -3718,6 +3767,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-arm64@0.19.9: + resolution: {integrity: sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -3735,6 +3793,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-x64@0.19.9: + resolution: {integrity: sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -3752,6 +3819,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm64@0.19.9: + resolution: {integrity: sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm@0.18.20: resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -3769,6 +3845,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm@0.19.9: + resolution: {integrity: sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ia32@0.18.20: resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -3786,6 +3871,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ia32@0.19.9: + resolution: {integrity: sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -3803,6 +3897,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-loong64@0.19.9: + resolution: {integrity: sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -3820,6 +3923,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-mips64el@0.19.9: + resolution: {integrity: sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -3837,6 +3949,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ppc64@0.19.9: + resolution: {integrity: sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -3854,6 +3975,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-riscv64@0.19.9: + resolution: {integrity: sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -3871,6 +4001,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-s390x@0.19.9: + resolution: {integrity: sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -3888,6 +4027,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-x64@0.19.9: + resolution: {integrity: sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -3905,6 +4053,15 @@ packages: requiresBuild: true optional: true + /@esbuild/netbsd-x64@0.19.9: + resolution: {integrity: sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -3922,6 +4079,15 @@ packages: requiresBuild: true optional: true + /@esbuild/openbsd-x64@0.19.9: + resolution: {integrity: sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -3939,6 +4105,15 @@ packages: requiresBuild: true optional: true + /@esbuild/sunos-x64@0.19.9: + resolution: {integrity: sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -3956,6 +4131,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-arm64@0.19.9: + resolution: {integrity: sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -3973,6 +4157,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-ia32@0.19.9: + resolution: {integrity: sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -3990,6 +4183,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-x64@0.19.9: + resolution: {integrity: sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4000,13 +4202,13 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.55.0 + eslint: 8.56.0 eslint-visitor-keys: 3.4.3 dev: true @@ -4054,8 +4256,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@eslint/js@8.55.0: - resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} + /@eslint/js@8.56.0: + resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -4353,7 +4555,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -4374,14 +4576,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.10.4) + jest-config: 29.7.0(@types/node@20.10.5) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -4416,7 +4618,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 jest-mock: 29.7.0 dev: true @@ -4443,7 +4645,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.10.4 + '@types/node': 20.10.5 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -4476,7 +4678,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4570,7 +4772,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -4582,12 +4784,12 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@types/yargs': 17.0.19 chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.3)(vite@5.0.8): + /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.3.3)(vite@5.0.10): resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} peerDependencies: typescript: '>= 4.3.x' @@ -4601,7 +4803,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.3.3) typescript: 5.3.3 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) dev: true /@jridgewell/gen-mapping@0.3.2: @@ -4690,24 +4892,24 @@ packages: react: 18.2.0 dev: true - /@microsoft/api-extractor-model@7.28.3(@types/node@20.10.4): + /@microsoft/api-extractor-model@7.28.3(@types/node@20.10.5): resolution: {integrity: sha512-wT/kB2oDbdZXITyDh2SQLzaWwTOFbV326fP0pUwNW00WeliARs0qjmXBWmGWardEzp2U3/axkO3Lboqun6vrig==} dependencies: '@microsoft/tsdoc': 0.14.2 '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.62.0(@types/node@20.10.4) + '@rushstack/node-core-library': 3.62.0(@types/node@20.10.5) transitivePeerDependencies: - '@types/node' dev: true - /@microsoft/api-extractor@7.38.5(@types/node@20.10.4): + /@microsoft/api-extractor@7.38.5(@types/node@20.10.5): resolution: {integrity: sha512-c/w2zfqBcBJxaCzpJNvFoouWewcYrUOfeu5ZkWCCIXTF9a/gXM85RGevEzlMAIEGM/kssAAZSXRJIZ3Q5vLFow==} hasBin: true dependencies: - '@microsoft/api-extractor-model': 7.28.3(@types/node@20.10.4) + '@microsoft/api-extractor-model': 7.28.3(@types/node@20.10.5) '@microsoft/tsdoc': 0.14.2 '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.62.0(@types/node@20.10.4) + '@rushstack/node-core-library': 3.62.0(@types/node@20.10.5) '@rushstack/rig-package': 0.5.1 '@rushstack/ts-command-line': 4.17.1 colors: 1.2.5 @@ -5550,7 +5752,7 @@ packages: '@babel/runtime': 7.23.2 dev: true - /@rollup/plugin-json@6.1.0(rollup@4.9.0): + /@rollup/plugin-json@6.1.0(rollup@4.9.1): resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5559,11 +5761,11 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.9.0) - rollup: 4.9.0 + '@rollup/pluginutils': 5.1.0(rollup@4.9.1) + rollup: 4.9.1 dev: false - /@rollup/plugin-replace@5.0.5(rollup@4.9.0): + /@rollup/plugin-replace@5.0.5(rollup@4.9.1): resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5572,12 +5774,12 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.9.0) + '@rollup/pluginutils': 5.1.0(rollup@4.9.1) magic-string: 0.30.5 - rollup: 4.9.0 + rollup: 4.9.1 dev: false - /@rollup/pluginutils@5.1.0(rollup@4.9.0): + /@rollup/pluginutils@5.1.0(rollup@4.9.1): resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5589,100 +5791,100 @@ packages: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 4.9.0 + rollup: 4.9.1 - /@rollup/rollup-android-arm-eabi@4.9.0: - resolution: {integrity: sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==} + /@rollup/rollup-android-arm-eabi@4.9.1: + resolution: {integrity: sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==} cpu: [arm] os: [android] requiresBuild: true optional: true - /@rollup/rollup-android-arm64@4.9.0: - resolution: {integrity: sha512-im6hUEyQ7ZfoZdNvtwgEJvBWZYauC9KVKq1w58LG2Zfz6zMd8gRrbN+xCVoqA2hv/v6fm9lp5LFGJ3za8EQH3A==} + /@rollup/rollup-android-arm64@4.9.1: + resolution: {integrity: sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==} cpu: [arm64] os: [android] requiresBuild: true optional: true - /@rollup/rollup-darwin-arm64@4.9.0: - resolution: {integrity: sha512-u7aTMskN6Dmg1lCT0QJ+tINRt+ntUrvVkhbPfFz4bCwRZvjItx2nJtwJnJRlKMMaQCHRjrNqHRDYvE4mBm3DlQ==} + /@rollup/rollup-darwin-arm64@4.9.1: + resolution: {integrity: sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==} cpu: [arm64] os: [darwin] requiresBuild: true optional: true - /@rollup/rollup-darwin-x64@4.9.0: - resolution: {integrity: sha512-8FvEl3w2ExmpcOmX5RJD0yqXcVSOqAJJUJ29Lca29Ik+3zPS1yFimr2fr5JSZ4Z5gt8/d7WqycpgkX9nocijSw==} + /@rollup/rollup-darwin-x64@4.9.1: + resolution: {integrity: sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==} cpu: [x64] os: [darwin] requiresBuild: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.9.0: - resolution: {integrity: sha512-lHoKYaRwd4gge+IpqJHCY+8Vc3hhdJfU6ukFnnrJasEBUvVlydP8PuwndbWfGkdgSvZhHfSEw6urrlBj0TSSfg==} + /@rollup/rollup-linux-arm-gnueabihf@4.9.1: + resolution: {integrity: sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==} cpu: [arm] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.9.0: - resolution: {integrity: sha512-JbEPfhndYeWHfOSeh4DOFvNXrj7ls9S/2omijVsao+LBPTPayT1uKcK3dHW3MwDJ7KO11t9m2cVTqXnTKpeaiw==} + /@rollup/rollup-linux-arm64-gnu@4.9.1: + resolution: {integrity: sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==} cpu: [arm64] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-linux-arm64-musl@4.9.0: - resolution: {integrity: sha512-ahqcSXLlcV2XUBM3/f/C6cRoh7NxYA/W7Yzuv4bDU1YscTFw7ay4LmD7l6OS8EMhTNvcrWGkEettL1Bhjf+B+w==} + /@rollup/rollup-linux-arm64-musl@4.9.1: + resolution: {integrity: sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==} cpu: [arm64] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.9.0: - resolution: {integrity: sha512-uwvOYNtLw8gVtrExKhdFsYHA/kotURUmZYlinH2VcQxNCQJeJXnkmWgw2hI9Xgzhgu7J9QvWiq9TtTVwWMDa+w==} + /@rollup/rollup-linux-riscv64-gnu@4.9.1: + resolution: {integrity: sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==} cpu: [riscv64] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-linux-x64-gnu@4.9.0: - resolution: {integrity: sha512-m6pkSwcZZD2LCFHZX/zW2aLIISyzWLU3hrLLzQKMI12+OLEzgruTovAxY5sCZJkipklaZqPy/2bEEBNjp+Y7xg==} + /@rollup/rollup-linux-x64-gnu@4.9.1: + resolution: {integrity: sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==} cpu: [x64] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-linux-x64-musl@4.9.0: - resolution: {integrity: sha512-VFAC1RDRSbU3iOF98X42KaVicAfKf0m0OvIu8dbnqhTe26Kh6Ym9JrDulz7Hbk7/9zGc41JkV02g+p3BivOdAg==} + /@rollup/rollup-linux-x64-musl@4.9.1: + resolution: {integrity: sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==} cpu: [x64] os: [linux] requiresBuild: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.9.0: - resolution: {integrity: sha512-9jPgMvTKXARz4inw6jezMLA2ihDBvgIU9Ml01hjdVpOcMKyxFBJrn83KVQINnbeqDv0+HdO1c09hgZ8N0s820Q==} + /@rollup/rollup-win32-arm64-msvc@4.9.1: + resolution: {integrity: sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==} cpu: [arm64] os: [win32] requiresBuild: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.9.0: - resolution: {integrity: sha512-WE4pT2kTXQN2bAv40Uog0AsV7/s9nT9HBWXAou8+++MBCnY51QS02KYtm6dQxxosKi1VIz/wZIrTQO5UP2EW+Q==} + /@rollup/rollup-win32-ia32-msvc@4.9.1: + resolution: {integrity: sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==} cpu: [ia32] os: [win32] requiresBuild: true optional: true - /@rollup/rollup-win32-x64-msvc@4.9.0: - resolution: {integrity: sha512-aPP5Q5AqNGuT0tnuEkK/g4mnt3ZhheiXrDIiSVIHN9mcN21OyXDVbEMqmXPE7e2OplNLDkcvV+ZoGJa2ZImFgw==} + /@rollup/rollup-win32-x64-msvc@4.9.1: + resolution: {integrity: sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==} cpu: [x64] os: [win32] requiresBuild: true optional: true - /@rushstack/node-core-library@3.62.0(@types/node@20.10.4): + /@rushstack/node-core-library@3.62.0(@types/node@20.10.5): resolution: {integrity: sha512-88aJn2h8UpSvdwuDXBv1/v1heM6GnBf3RjEy6ZPP7UnzHNCqOHA2Ut+ScYUbXcqIdfew9JlTAe3g+cnX9xQ/Aw==} peerDependencies: '@types/node': '*' @@ -5690,7 +5892,7 @@ packages: '@types/node': optional: true dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 colors: 1.2.5 fs-extra: 7.0.1 import-lazy: 4.0.0 @@ -5767,6 +5969,11 @@ packages: resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==} engines: {node: '>=14.16'} + /@sindresorhus/is@6.1.0: + resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==} + engines: {node: '>=16'} + dev: false + /@sinonjs/commons@1.8.6: resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} dependencies: @@ -6277,10 +6484,10 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@storybook/addon-actions@7.6.4: - resolution: {integrity: sha512-91UD5KPDik74VKVioPMcbwwvDXN/non8p1wArYAHCHCmd/Pts5MJRiFueSdfomSpNjUtjtn6eSXtwpIL3XVOfQ==} + /@storybook/addon-actions@7.6.5: + resolution: {integrity: sha512-lW/m9YcaNfBZk+TZLxyzHdd563mBWpsUIveOKYjcPdl/q0FblWWZrRsFHqwLK1ldZ4AZXs8J/47G8CBr6Ew2uQ==} dependencies: - '@storybook/core-events': 7.6.4 + '@storybook/core-events': 7.6.5 '@storybook/global': 5.0.0 '@types/uuid': 9.0.7 dequal: 2.0.3 @@ -6288,18 +6495,18 @@ packages: uuid: 9.0.1 dev: true - /@storybook/addon-backgrounds@7.6.4: - resolution: {integrity: sha512-gNy3kIkHSr+Lg/jVDHwbZjIe1po5SDGZNVe39vrJwnqGz8T1clWes9WHCL6zk/uaCDA3yUna2Nt/KlOFAWDSoQ==} + /@storybook/addon-backgrounds@7.6.5: + resolution: {integrity: sha512-wZZOL19vg4TTRtOTl71XKqPe5hQx3XUh9Fle0wOi91FiFrBdqusrppnyS89wPS8RQG5lXEOFEUvYcMmdCcdZfw==} dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 ts-dedent: 2.2.0 dev: true - /@storybook/addon-controls@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-k4AtZfazmD/nL3JAtLGAB7raPhkhUo0jWnaZWrahd9h1Fm13mBU/RW+JzTRhCw3Mp2HPERD7NI5Qcd2fUP6WDA==} + /@storybook/addon-controls@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-EdSZ2pYf74mOXZGGJ22lrDvdvL0YKc95iWv9FFEhUFOloMy/0OZPB2ybYmd2KVCy3SeIE4Zfeiw8pDXdCUniOQ==} dependencies: - '@storybook/blocks': 7.6.4(react-dom@18.2.0)(react@18.2.0) + '@storybook/blocks': 7.6.5(react-dom@18.2.0)(react@18.2.0) lodash: 4.17.21 ts-dedent: 2.2.0 transitivePeerDependencies: @@ -6311,27 +6518,27 @@ packages: - supports-color dev: true - /@storybook/addon-docs@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-PbFMbvC9sK3sGdMhwmagXs9TqopTp9FySji+L8O7W9SHRC6wSmdwoWWPWybkOYxr/z/wXi7EM0azSAX7yQxLbw==} + /@storybook/addon-docs@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D9tZyD41IujCHiPYdfS2bKtZRJPNwO4EydzyqODXppomluhFbY3uTEaf0H1UFnJLQxWNXZ7rr3aS0V3O6yu8pA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@jest/transform': 29.7.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.6.4 - '@storybook/components': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/csf-plugin': 7.6.4 - '@storybook/csf-tools': 7.6.4 + '@storybook/blocks': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.6.5 + '@storybook/components': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/csf-plugin': 7.6.5 + '@storybook/csf-tools': 7.6.5 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.6.4 - '@storybook/postinstall': 7.6.4 - '@storybook/preview-api': 7.6.4 - '@storybook/react-dom-shim': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/node-logger': 7.6.5 + '@storybook/postinstall': 7.6.5 + '@storybook/preview-api': 7.6.5 + '@storybook/react-dom-shim': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 fs-extra: 11.1.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -6345,25 +6552,25 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-J+zPmP4pbuuFxQ3pjLRYQRnxEtp7jF3xRXGFO8brVnEqtqoxwJ6j3euUrRLe0rpGAU3AD7dYfaaFjd3xkENgTw==} + /@storybook/addon-essentials@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-VCLj1JAEpGoqF5iFJOo1CZFFck/tg4m/98DLdQuNuXvxT6jqaF0NI9UUQuJLIGteDCR7NKRbTFc1hV3/Ev+Ziw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addon-actions': 7.6.4 - '@storybook/addon-backgrounds': 7.6.4 - '@storybook/addon-controls': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-highlight': 7.6.4 - '@storybook/addon-measure': 7.6.4 - '@storybook/addon-outline': 7.6.4 - '@storybook/addon-toolbars': 7.6.4 - '@storybook/addon-viewport': 7.6.4 - '@storybook/core-common': 7.6.4 - '@storybook/manager-api': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.6.4 - '@storybook/preview-api': 7.6.4 + '@storybook/addon-actions': 7.6.5 + '@storybook/addon-backgrounds': 7.6.5 + '@storybook/addon-controls': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-docs': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-highlight': 7.6.5 + '@storybook/addon-measure': 7.6.5 + '@storybook/addon-outline': 7.6.5 + '@storybook/addon-toolbars': 7.6.5 + '@storybook/addon-viewport': 7.6.5 + '@storybook/core-common': 7.6.5 + '@storybook/manager-api': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.6.5 + '@storybook/preview-api': 7.6.5 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -6374,24 +6581,24 @@ packages: - supports-color dev: true - /@storybook/addon-highlight@7.6.4: - resolution: {integrity: sha512-0kvjDzquoPwWWU61QYmEtcSGWXufnV7Z/bfBTYh132uxvV/X9YzDFcXXrxGL7sBJkK32gNUUBDuiTOxs5NxyOQ==} + /@storybook/addon-highlight@7.6.5: + resolution: {integrity: sha512-CxzmIb30F9nLPQwT0lCPYhOAwGlGF4IkgkO8hYA7VfGCGUkJZEyyN/YkP/ZCUSdCIRChDBouR3KiFFd4mDFKzg==} dependencies: '@storybook/global': 5.0.0 dev: true - /@storybook/addon-interactions@7.6.4: - resolution: {integrity: sha512-LjK9uhkgnbGyDwwa7pQhLptDEHeTIFmy+KurfJs9T08DpvRFfuuzyW4mj/hA63R1W5yjFSAhRiZj26+D7kBIyw==} + /@storybook/addon-interactions@7.6.5: + resolution: {integrity: sha512-8Hzt9u1DQzFvtGER/hCGIvGpCoVwzVoqpM98f2KAIVx/NMFmRW7UyKihXzw1j2t4q2ZaF2jZDYWCBqlP+iwILA==} dependencies: '@storybook/global': 5.0.0 - '@storybook/types': 7.6.4 + '@storybook/types': 7.6.5 jest-mock: 27.5.1 polished: 4.2.2 ts-dedent: 2.2.0 dev: true - /@storybook/addon-links@7.6.4(react@18.2.0): - resolution: {integrity: sha512-TEhxYdMhJO28gD84ej1FCwLv9oLuCPt77bRXip9ndaNPRTdHYdWv6IP94dhbuDi8eHux7Z4A/mllciFuDFrnCw==} + /@storybook/addon-links@7.6.5(react@18.2.0): + resolution: {integrity: sha512-Lx4Ng+iXt0YpIrKGr+nOZlpN9ypOoEDoP/7bZ6m7GXuVAkDm3JrRCBp7e2ZKSKcTxPdjPuO9HVKkIjtqjINlpw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: @@ -6404,66 +6611,66 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure@7.6.4: - resolution: {integrity: sha512-73wsJ8PALsgWniR3MA/cmxcFuU6cRruWdIyYzOMgM8ife2Jm3xSkV7cTTXAqXt2H9Uuki4PGnuMHWWFLpPeyVA==} + /@storybook/addon-measure@7.6.5: + resolution: {integrity: sha512-tlUudVQSrA+bwI4dhO8J7nYHtYdylcBZ86ybnqMmdTthsnyc7jnaFVQwbb6bbQJpPxvEvoNds5bVGUFocuvymQ==} dependencies: '@storybook/global': 5.0.0 tiny-invariant: 1.3.1 dev: true - /@storybook/addon-outline@7.6.4: - resolution: {integrity: sha512-CFxGASRse/qeFocetDKFNeWZ3Aa2wapVtRciDNa4Zx7k1wCnTjEsPIm54waOuCaNVcrvO+nJUAZG5WyiorQvcg==} + /@storybook/addon-outline@7.6.5: + resolution: {integrity: sha512-P7X4+Z9L/l/RZW9UvvM+iuK2SUHD22KPc+dbYOifRXDovUqhfmcKVh1CUqTDMyZrg2ZAbropehMz1eI9BlQfxg==} dependencies: '@storybook/global': 5.0.0 ts-dedent: 2.2.0 dev: true - /@storybook/addon-storysource@7.6.4: - resolution: {integrity: sha512-D63IB8bkqn5ZDq4yjvkcLVfGz3OcAQUohlxSFR1e7COo8jMSTiQWjN7xaVPNOnVJRCj6GrlRlto/hqGl+F+WiQ==} + /@storybook/addon-storysource@7.6.5: + resolution: {integrity: sha512-mlGReftuGxfyfLXsnw4GF03G79w3rKKRclNasOVPuAR2vlSTRyltoglZ8TcXfxNQ+RzywtEZkjD7SeJZsuvBbQ==} dependencies: - '@storybook/source-loader': 7.6.4 + '@storybook/source-loader': 7.6.5 estraverse: 5.3.0 tiny-invariant: 1.3.1 dev: true - /@storybook/addon-toolbars@7.6.4: - resolution: {integrity: sha512-ENMQJgU4sRCLLDVXYfa+P3cQVV9PC0ZxwVAKeM3NPYPNH/ODoryGNtq+Q68LwHlM4ObCE2oc9MzaQqPxloFcCw==} + /@storybook/addon-toolbars@7.6.5: + resolution: {integrity: sha512-/zqWbVNE/SHc8I5Prnd2Q8U57RGEIYvHfeXjfkuLcE2Quc4Iss4x/9eU7SKu4jm+IOO2s0wlN6HcqI3XEf2XxA==} dev: true - /@storybook/addon-viewport@7.6.4: - resolution: {integrity: sha512-SoTcHIoqybhYD28v7QExF1EZnl7FfxuP74VDhtze5LyMd2CbqmVnUfwewLCz/3IvCNce0GqdNyg1m6QJ7Eq1uw==} + /@storybook/addon-viewport@7.6.5: + resolution: {integrity: sha512-9ghKTaduIUvQ6oShmWLuwMeTjtMR4RgKeKHrTJ7THMqvE/ydDPCYeL7ugF65ocXZSEz/QmxdK7uL686ZMKsqNA==} dependencies: memoizerific: 1.11.3 dev: true - /@storybook/addons@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-YnmLyR/ciALtzoi9HEu+Y+NJWeOVEBo9PRgQaG7zGiNDvOrLY69uU3Ej0+TZlrTqBqce42bRCrDINJfnk0Mfsg==} + /@storybook/addons@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-v+d8io1MsgTd7rruYInfKXY0c1uXn+ADLxAppUI0PUwPFYwg9tLn3cvwgt5SVum9E5IkVQwXoW6JNkDC5fC8XQ==} dependencies: - '@storybook/manager-api': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/manager-api': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.6.5 + '@storybook/types': 7.6.5 transitivePeerDependencies: - react - react-dom dev: true - /@storybook/blocks@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-iXinXXhTUBtReREP1Jifpu35DnGg7FidehjvCM8sM4E4aymfb8czdg9DdvG46T2UFUPUct36nnjIdMLWOya8Bw==} + /@storybook/blocks@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/NjuYkPks5w9lKn47KLgVC5cBkwfc+ERAp0CY0Xe//BQJkP+bcI8lE8d9Qc9IXFbOTvYEULeQrFgCkesk5BmLg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.6.4 - '@storybook/client-logger': 7.6.4 - '@storybook/components': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.6.4 + '@storybook/channels': 7.6.5 + '@storybook/client-logger': 7.6.5 + '@storybook/components': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.6.5 '@storybook/csf': 0.1.2 - '@storybook/docs-tools': 7.6.4 + '@storybook/docs-tools': 7.6.5 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.6.4 - '@storybook/theming': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/manager-api': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.6.5 + '@storybook/theming': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -6485,13 +6692,13 @@ packages: - supports-color dev: true - /@storybook/builder-manager@7.6.4: - resolution: {integrity: sha512-k5+D3fXw7LdMOWd5tF7cIq8L3irrdW6/vmcEHLaJj1EXZ+DvsNCH9xSsLS+6zfrUcxug4oSfRqvF87w6Oz3DtA==} + /@storybook/builder-manager@7.6.5: + resolution: {integrity: sha512-FQyI+tfzMam2XKXq7k921YVafIJs9Vqvos5qx8vyRnRffo55UU8tgunwjGn0PswtbMm6sThVqE0C0ZzVr7RG8A==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.6.4 - '@storybook/manager': 7.6.4 - '@storybook/node-logger': 7.6.4 + '@storybook/core-common': 7.6.5 + '@storybook/manager': 7.6.5 + '@storybook/node-logger': 7.6.5 '@types/ejs': 3.1.2 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.18.20) @@ -6509,8 +6716,8 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.6.4(typescript@5.3.3)(vite@5.0.8): - resolution: {integrity: sha512-eqb3mLUfuXd4a7+46cWevQ9qH81FvHy1lrAbZGwp4bQ/Tj0YF8Ej7lKBbg7zoIwiu2zDci+BbMiaDOY1kPtILw==} + /@storybook/builder-vite@7.6.5(typescript@5.3.3)(vite@5.0.10): + resolution: {integrity: sha512-VbAYTGr92lgCWTwO2Z7NgSW3f5/K4Vr0Qxa2IlTgMCymWdDbWdIQiREcmCP0vjAGM2ftq1+vxngohVgx/r7pUw==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' @@ -6524,14 +6731,14 @@ packages: vite-plugin-glimmerx: optional: true dependencies: - '@storybook/channels': 7.6.4 - '@storybook/client-logger': 7.6.4 - '@storybook/core-common': 7.6.4 - '@storybook/csf-plugin': 7.6.4 - '@storybook/node-logger': 7.6.4 - '@storybook/preview': 7.6.4 - '@storybook/preview-api': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/channels': 7.6.5 + '@storybook/client-logger': 7.6.5 + '@storybook/core-common': 7.6.5 + '@storybook/csf-plugin': 7.6.5 + '@storybook/node-logger': 7.6.5 + '@storybook/preview': 7.6.5 + '@storybook/preview-api': 7.6.5 + '@storybook/types': 7.6.5 '@types/find-cache-dir': 3.2.1 browser-assert: 1.2.1 es-module-lexer: 0.9.3 @@ -6541,39 +6748,39 @@ packages: magic-string: 0.30.5 rollup: 3.29.4 typescript: 5.3.3 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - encoding - supports-color dev: true - /@storybook/channels@7.6.4: - resolution: {integrity: sha512-Z4PY09/Czl70ap4ObmZ4bgin+EQhPaA3HdrEDNwpnH7A9ttfEO5u5KThytIjMq6kApCCihmEPDaYltoVrfYJJA==} + /@storybook/channels@7.6.5: + resolution: {integrity: sha512-FIlNkyfQy9uHoJfAFL2/wO3ASGJELFvBzURBE2rcEF/TS7GcUiqWnBfiDxAbwSEjSOm2F0eEq3UXhaZEjpJHDw==} dependencies: - '@storybook/client-logger': 7.6.4 - '@storybook/core-events': 7.6.4 + '@storybook/client-logger': 7.6.5 + '@storybook/core-events': 7.6.5 '@storybook/global': 5.0.0 qs: 6.11.1 telejson: 7.2.0 tiny-invariant: 1.3.1 dev: true - /@storybook/cli@7.6.4: - resolution: {integrity: sha512-GqvaFdkkBMJOdnrVe82XY0V3b+qFMhRNyVoTv2nqB87iMUXZHqh4Pu4LqwaJBsBpuNregvCvVOPe9LGgoOzy4A==} + /@storybook/cli@7.6.5: + resolution: {integrity: sha512-w+Y8dx5oCLQVESOVmpsQuFksr/ewARKrnSKl9kwnVMN4sMgjOgoZ3zmV66J7SKexvwyuwlOjf840pmEglGdPPg==} hasBin: true dependencies: '@babel/core': 7.23.5 '@babel/preset-env': 7.23.5(@babel/core@7.23.5) '@babel/types': 7.23.5 '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 7.6.4 - '@storybook/core-common': 7.6.4 - '@storybook/core-events': 7.6.4 - '@storybook/core-server': 7.6.4 - '@storybook/csf-tools': 7.6.4 - '@storybook/node-logger': 7.6.4 - '@storybook/telemetry': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/codemod': 7.6.5 + '@storybook/core-common': 7.6.5 + '@storybook/core-events': 7.6.5 + '@storybook/core-server': 7.6.5 + '@storybook/csf-tools': 7.6.5 + '@storybook/node-logger': 7.6.5 + '@storybook/telemetry': 7.6.5 + '@storybook/types': 7.6.5 '@types/semver': 7.5.6 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 @@ -6610,22 +6817,22 @@ packages: - utf-8-validate dev: true - /@storybook/client-logger@7.6.4: - resolution: {integrity: sha512-vJwMShC98tcoFruRVQ4FphmFqvAZX1FqZqjFyk6IxtFumPKTVSnXJjlU1SnUIkSK2x97rgdUMqkdI+wAv/tugQ==} + /@storybook/client-logger@7.6.5: + resolution: {integrity: sha512-S5aROWgssqg7tcs9lgW5wmCAz4SxMAtioiyVj5oFecmPCbQtFVIAREYzeoxE4GfJL+plrfRkum4BzziANn8EhQ==} dependencies: '@storybook/global': 5.0.0 dev: true - /@storybook/codemod@7.6.4: - resolution: {integrity: sha512-q4rZVOfozxzbDRH/LzuFDoIGBdXs+orAm18fi6iAx8PeMHe8J/MOXKccNV1zdkm/h7mTQowuRo45KwJHw8vX+g==} + /@storybook/codemod@7.6.5: + resolution: {integrity: sha512-K5C9ltBClZ0aSyujGt3RJFtRicrUZy8nzhHrcADUj27rrQD26jH/p+Y05jWKj9JcI8SyMg978GN5X/1aw2Y31A==} dependencies: '@babel/core': 7.23.5 '@babel/preset-env': 7.23.5(@babel/core@7.23.5) '@babel/types': 7.23.5 '@storybook/csf': 0.1.2 - '@storybook/csf-tools': 7.6.4 - '@storybook/node-logger': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/csf-tools': 7.6.5 + '@storybook/node-logger': 7.6.5 + '@storybook/types': 7.6.5 '@types/cross-spawn': 6.0.2 cross-spawn: 7.0.3 globby: 11.1.0 @@ -6637,19 +6844,19 @@ packages: - supports-color dev: true - /@storybook/components@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-K5RvEObJAnX+SbGJbkM1qrZEk+VR2cUhRCSrFnlfMwsn8/60T3qoH7U8bCXf8krDgbquhMwqev5WzDB+T1VV8g==} + /@storybook/components@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-w4ZucbBBZ+NKMWlJKVj2I/bMBBq7gzDp9lzc4+8QaQ3vUPXKqc1ilIPYo/7UR5oxwDVMZocmMSgl9L8lvf7+Mw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@radix-ui/react-select': 1.2.2(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-toolbar': 1.0.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.6.4 + '@storybook/client-logger': 7.6.5 '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 - '@storybook/theming': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/theming': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -6660,19 +6867,19 @@ packages: - '@types/react-dom' dev: true - /@storybook/core-client@7.6.4: - resolution: {integrity: sha512-0msqdGd+VYD1dRgAJ2StTu4d543Wveb7LVVujX3PwD/QCxmCaVUHuAoZrekM/H7jZLw546ZIbLZo0xWrADAUMw==} + /@storybook/core-client@7.6.5: + resolution: {integrity: sha512-6FtyJcz8MSl+JYwNJZ53FM6rkT27pFHWcJPdtw/9229Ec8as9RpkNeZ/NBZjRTeDkn9Ki0VOiVAefNie9tZ/8Q==} dependencies: - '@storybook/client-logger': 7.6.4 - '@storybook/preview-api': 7.6.4 + '@storybook/client-logger': 7.6.5 + '@storybook/preview-api': 7.6.5 dev: true - /@storybook/core-common@7.6.4: - resolution: {integrity: sha512-qes4+mXqINu0kCgSMFjk++GZokmYjb71esId0zyJsk0pcIPkAiEjnhbSEQkMhbUfcvO1lztoaQTBW2P7Rd1tag==} + /@storybook/core-common@7.6.5: + resolution: {integrity: sha512-z4EgzZSIVbID6Ib0jhh3jimKeaDWU8OOhoZYfn3galFmgQWowWOv1oMgipWiXfRLWw9DaLFQiCHIdLANH+VO2g==} dependencies: - '@storybook/core-events': 7.6.4 - '@storybook/node-logger': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/core-events': 7.6.5 + '@storybook/node-logger': 7.6.5 + '@storybook/types': 7.6.5 '@types/find-cache-dir': 3.2.1 '@types/node': 18.17.15 '@types/node-fetch': 2.6.4 @@ -6698,30 +6905,30 @@ packages: - supports-color dev: true - /@storybook/core-events@7.6.4: - resolution: {integrity: sha512-i3xzcJ19ILSy4oJL5Dz9y0IlyApynn5RsGhAMIsW+mcfri+hGfeakq1stNCo0o7jW4Y3A7oluFTtIoK8DOxQdQ==} + /@storybook/core-events@7.6.5: + resolution: {integrity: sha512-zk2q/qicYXAzHA4oV3GDbIql+Kd4TOHUgDE8e4jPCOPp856z2ScqEKUAbiJizs6eEJOH4nW9Db1kuzgrBVEykQ==} dependencies: ts-dedent: 2.2.0 dev: true - /@storybook/core-server@7.6.4: - resolution: {integrity: sha512-mXxZMpCwOhjEPPRjqrTHdiCpFdkc47f46vlgTj02SX+9xKHxslmZ2D3JG/8O4Ab9tG+bBl6lBm3RIrIzaiCu9Q==} + /@storybook/core-server@7.6.5: + resolution: {integrity: sha512-BfKzK/ObTjUcPvE5/r1pogCifM/4nLRhOUYJl7XekwHkOQwn19e6H3/ku1W3jDoYXBu642Dc9X7l/ERjKTqxFg==} dependencies: '@aw-web-design/x-default-browser': 1.4.126 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.6.4 - '@storybook/channels': 7.6.4 - '@storybook/core-common': 7.6.4 - '@storybook/core-events': 7.6.4 + '@storybook/builder-manager': 7.6.5 + '@storybook/channels': 7.6.5 + '@storybook/core-common': 7.6.5 + '@storybook/core-events': 7.6.5 '@storybook/csf': 0.1.2 - '@storybook/csf-tools': 7.6.4 + '@storybook/csf-tools': 7.6.5 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.6.4 - '@storybook/node-logger': 7.6.4 - '@storybook/preview-api': 7.6.4 - '@storybook/telemetry': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/manager': 7.6.5 + '@storybook/node-logger': 7.6.5 + '@storybook/preview-api': 7.6.5 + '@storybook/telemetry': 7.6.5 + '@storybook/types': 7.6.5 '@types/detect-port': 1.3.2 '@types/node': 18.17.15 '@types/pretty-hrtime': 1.0.1 @@ -6755,24 +6962,24 @@ packages: - utf-8-validate dev: true - /@storybook/csf-plugin@7.6.4: - resolution: {integrity: sha512-7g9p8s2ITX+Z9iThK5CehPhJOcusVN7JcUEEW+gVF5PlYT+uk/x+66gmQno+scQuNkV9+8UJD6RLFjP+zg2uCA==} + /@storybook/csf-plugin@7.6.5: + resolution: {integrity: sha512-iQ8Y/Qq1IUhHRddjDVicWJA2sM7OZA1FR97OvWUT2240WjCuQSCfy32JD8TQlYjqXgEolJeLPv3zW4qH5om4LQ==} dependencies: - '@storybook/csf-tools': 7.6.4 + '@storybook/csf-tools': 7.6.5 unplugin: 1.4.0 transitivePeerDependencies: - supports-color dev: true - /@storybook/csf-tools@7.6.4: - resolution: {integrity: sha512-6sLayuhgReIK3/QauNj5BW4o4ZfEMJmKf+EWANPEM/xEOXXqrog6Un8sjtBuJS9N1DwyhHY6xfkEiPAwdttwqw==} + /@storybook/csf-tools@7.6.5: + resolution: {integrity: sha512-1iaCh7nt+WE7Q5UwRhLLc5flMNoAV/vBr0tvDSCKiHaO+D3dZzlZOe/U+S6wegdyN2QNcvT2xs179CcrX6Qp6w==} dependencies: '@babel/generator': 7.23.5 '@babel/parser': 7.23.5 '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 '@storybook/csf': 0.1.2 - '@storybook/types': 7.6.4 + '@storybook/types': 7.6.5 fs-extra: 11.1.1 recast: 0.23.4 ts-dedent: 2.2.0 @@ -6790,12 +6997,12 @@ packages: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} dev: true - /@storybook/docs-tools@7.6.4: - resolution: {integrity: sha512-2eGam43aD7O3cocA72Z63kRi7t/ziMSpst0qB218QwBWAeZjT4EYDh8V6j/Xhv6zVQL3msW7AglrQP5kCKPvPA==} + /@storybook/docs-tools@7.6.5: + resolution: {integrity: sha512-UyHkHu5Af6jMpYsR4lZ69D32GQGeA0pLAn7jaBbQndgAjBdK1ykZcifiUC7Wz1hG7+YpuYspEGuDEddOh+X8FQ==} dependencies: - '@storybook/core-common': 7.6.4 - '@storybook/preview-api': 7.6.4 - '@storybook/types': 7.6.4 + '@storybook/core-common': 7.6.5 + '@storybook/preview-api': 7.6.5 + '@storybook/types': 7.6.5 '@types/doctrine': 0.0.3 assert: 2.1.0 doctrine: 3.0.0 @@ -6828,17 +7035,17 @@ packages: - vitest dev: true - /@storybook/manager-api@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-RFb/iaBJfXygSgXkINPRq8dXu7AxBicTGX7MxqKXbz5FU7ANwV7abH6ONBYURkSDOH9//TQhRlVkF5u8zWg3bw==} + /@storybook/manager-api@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tE3OShOcs6A3XtI3NJd6hYQOZLaP++Fn0dCtowBwYh/vS1EN/AyroVmL97tsxn1DZTyoRt0GidwbB6dvLMBOwA==} dependencies: - '@storybook/channels': 7.6.4 - '@storybook/client-logger': 7.6.4 - '@storybook/core-events': 7.6.4 + '@storybook/channels': 7.6.5 + '@storybook/client-logger': 7.6.5 + '@storybook/core-events': 7.6.5 '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 - '@storybook/router': 7.6.4 - '@storybook/theming': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/router': 7.6.5 + '@storybook/theming': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -6851,31 +7058,31 @@ packages: - react-dom dev: true - /@storybook/manager@7.6.4: - resolution: {integrity: sha512-Ug2ejfKgKre8h/RJbkumukwAA44TbvTPEjDcJmyFdAI+kHYhOYdKPEC2UNmVYz8/4HjwMTJQ3M7t/esK8HHY4A==} + /@storybook/manager@7.6.5: + resolution: {integrity: sha512-y1KLH0O1PGPyMxGMvOhppzFSO7r4ibjTve5iqsI0JZwxUjNuBKRLYbrhXdAyC2iacvxYNrHgevae1k9XdD+FQw==} dev: true /@storybook/mdx2-csf@1.0.0: resolution: {integrity: sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw==} dev: true - /@storybook/node-logger@7.6.4: - resolution: {integrity: sha512-GDkEnnDj4Op+PExs8ZY/P6ox3wg453CdEIaR8PR9TxF/H/T2fBL6puzma3hN2CMam6yzfAL8U+VeIIDLQ5BZdQ==} + /@storybook/node-logger@7.6.5: + resolution: {integrity: sha512-xKw6IH1wLkIssekdBv3bd13xYKUF1t8EwqDR8BYcN8AVjZlqJMTifssqG4bYV+G/B7J3tz4ugJ5nmtWg6RQ0Qw==} dev: true - /@storybook/postinstall@7.6.4: - resolution: {integrity: sha512-7uoB82hSzlFSdDMS3hKQD+AaeSvPit/fAMvXCBxn0/D0UGJUZcq4M9JcKBwEHkZJcbuDROgOTJ6TUeXi/FWO0w==} + /@storybook/postinstall@7.6.5: + resolution: {integrity: sha512-12WxfpqGKsk7GQ3KWiZSbamsYK8vtRmhOTkavZ9IQkcJ/zuVfmqK80/Mds+njJMudUPzuREuSFGWACczo17EDA==} dev: true - /@storybook/preview-api@7.6.4: - resolution: {integrity: sha512-KhisNdQX5NdfAln+spLU4B82d804GJQp/CnI5M1mm/taTnjvMgs/wTH9AmR89OPoq+tFZVW0vhy2zgPS3ar71A==} + /@storybook/preview-api@7.6.5: + resolution: {integrity: sha512-9XzuDXXgNuA6dDZ3DXsUwEG6ElxeTbzLuYuzcjtS1FusSICZ2iYmxfS0GfSud9MjPPYOJYoSOvMdIHjorjgByA==} dependencies: - '@storybook/channels': 7.6.4 - '@storybook/client-logger': 7.6.4 - '@storybook/core-events': 7.6.4 + '@storybook/channels': 7.6.5 + '@storybook/client-logger': 7.6.5 + '@storybook/core-events': 7.6.5 '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 - '@storybook/types': 7.6.4 + '@storybook/types': 7.6.5 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -6886,12 +7093,12 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview@7.6.4: - resolution: {integrity: sha512-p9xIvNkgXgTpSRphOMV9KpIiNdkymH61jBg3B0XyoF6IfM1S2/mQGvC89lCVz1dMGk2SrH4g87/WcOapkU5ArA==} + /@storybook/preview@7.6.5: + resolution: {integrity: sha512-zmLa7C7yFGTYhgGZXoecdww9rx0Z5HpNi/GDBRWoNSK+FEdE8Jj2jF5NJ2ncldtYIyegz9ku29JFMKbhMj9K5Q==} dev: true - /@storybook/react-dom-shim@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-wGJfomlDEBnowNmhmumWDu/AcUInxSoPqUUJPgk2f5oL0EW17fR9fDP/juG3XOEdieMDM0jDX48GML7lyvL2fg==} + /@storybook/react-dom-shim@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Qp3N3zENdvx20ikHmz5yI03z+mAWF8bUAwUofqXarVtZUkBNtvfTfUwgAezOAF0eClClH+ktIziIKd976tLSPw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6900,24 +7107,24 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.6.4(react-dom@18.2.0)(react@18.2.0)(rollup@4.9.0)(typescript@5.3.3)(vite@5.0.8): - resolution: {integrity: sha512-1NYzCJRO6k/ZyoMzpu1FQiaUaiLNjAvTAB1x3HE7oY/tEIT8kGpzXGYH++LJVWvyP/5dSWlUnRSy2rJvySraiw==} + /@storybook/react-vite@7.6.5(react-dom@18.2.0)(react@18.2.0)(rollup@4.9.1)(typescript@5.3.3)(vite@5.0.10): + resolution: {integrity: sha512-fIoSBbou3rQdOo6qX/nD5givb3qIOSwXeZWjAqRB6560cqmeSQFlRGtKUJ0nzQYADwJ0/iNHz3nOvJOOSnPepA==} engines: {node: '>=16'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.3)(vite@5.0.8) - '@rollup/pluginutils': 5.1.0(rollup@4.9.0) - '@storybook/builder-vite': 7.6.4(typescript@5.3.3)(vite@5.0.8) - '@storybook/react': 7.6.4(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3) - '@vitejs/plugin-react': 3.1.0(vite@5.0.8) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.3.3)(vite@5.0.10) + '@rollup/pluginutils': 5.1.0(rollup@4.9.1) + '@storybook/builder-vite': 7.6.5(typescript@5.3.3)(vite@5.0.10) + '@storybook/react': 7.6.5(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3) + '@vitejs/plugin-react': 3.1.0(vite@5.0.10) magic-string: 0.30.5 react: 18.2.0 react-docgen: 7.0.1 react-dom: 18.2.0(react@18.2.0) - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -6927,8 +7134,8 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.6.4(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3): - resolution: {integrity: sha512-XYRP+eylH3JqkCuziwtQGY5vOCeDreOibRYJmj5na6k4QbURjGVB44WCIW04gWVlmBXM9SqLAmserUi3HP890Q==} + /@storybook/react@7.6.5(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3): + resolution: {integrity: sha512-z0l5T+gL//VekMXnHi+lW5qr7OQ8X7WoeIRMk38e62ppSpGUZRfoxRmmhU/9YcIFAlCgMaoLSYmhOceKGRZuVw==} engines: {node: '>=16.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6938,13 +7145,13 @@ packages: typescript: optional: true dependencies: - '@storybook/client-logger': 7.6.4 - '@storybook/core-client': 7.6.4 - '@storybook/docs-tools': 7.6.4 + '@storybook/client-logger': 7.6.5 + '@storybook/core-client': 7.6.5 + '@storybook/docs-tools': 7.6.5 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.6.4 - '@storybook/react-dom-shim': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/preview-api': 7.6.5 + '@storybook/react-dom-shim': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 18.17.15 @@ -6967,30 +7174,30 @@ packages: - supports-color dev: true - /@storybook/router@7.6.4: - resolution: {integrity: sha512-5MQ7Z4D7XNPN2yhFgjey7hXOYd6s8CggUqeAwhzGTex90SMCkKHSz1hfkcXn1ZqBPaall2b53uK553OvPLp9KQ==} + /@storybook/router@7.6.5: + resolution: {integrity: sha512-QiTC86gRuoepzzmS6HNJZTwfz/n27NcqtaVEIxJi1Yvsx2/kLa9NkRhylNkfTuZ1gEry9stAlKWanMsB2aKyjQ==} dependencies: - '@storybook/client-logger': 7.6.4 + '@storybook/client-logger': 7.6.5 memoizerific: 1.11.3 qs: 6.11.1 dev: true - /@storybook/source-loader@7.6.4: - resolution: {integrity: sha512-1wb/3bVpJZ/3r3qUrLK8jb0kLuvwjNi5T1kci5huREdc1TrIxZXoPw9EiyjcMCZzCURkoj7euNLrLHGyzdBTLg==} + /@storybook/source-loader@7.6.5: + resolution: {integrity: sha512-3GpXJY9GUOOl3Uq/xcsJ12XWLBNZJwUWzwkBm4Eev1xl5eg/ygeyJflwM5egsA1NfkV77hNxtjQcbfw4cBtqdg==} dependencies: '@storybook/csf': 0.1.2 - '@storybook/types': 7.6.4 + '@storybook/types': 7.6.5 estraverse: 5.3.0 lodash: 4.17.21 prettier: 2.8.8 dev: true - /@storybook/telemetry@7.6.4: - resolution: {integrity: sha512-Q4QpvcgloHUEqC9PGo7tgqkUH91/PjX+74/0Hi9orLo8QmLMgdYS5fweFwgSKoTwDGNg2PaHp/jqvhhw7UmnJA==} + /@storybook/telemetry@7.6.5: + resolution: {integrity: sha512-FiLRh9k9LoGphqgBqPYySWdGqplihiZyDwqdo+Qs19RcQ/eiKg0W7fdA09nStcdcsHmDl/1cMfRhz9KUiMtwOw==} dependencies: - '@storybook/client-logger': 7.6.4 - '@storybook/core-common': 7.6.4 - '@storybook/csf-tools': 7.6.4 + '@storybook/client-logger': 7.6.5 + '@storybook/core-common': 7.6.5 + '@storybook/csf-tools': 7.6.5 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -7009,42 +7216,42 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/theming@7.6.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Z/dcC5EpkIXelYCkt9ojnX6D7qGOng8YHxV/OWlVE9TrEGYVGPOEfwQryR0RhmGpDha1TYESLYrsDb4A8nJ1EA==} + /@storybook/theming@7.6.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-RpcWT0YEgiobO41McVPDfQQHHFnjyr1sJnNTPJIvOUgSfURdgSj17mQVxtD5xcXcPWUdle5UhIOrCixHbL/NNw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@storybook/client-logger': 7.6.4 + '@storybook/client-logger': 7.6.5 '@storybook/global': 5.0.0 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/types@7.6.4: - resolution: {integrity: sha512-qyiiXPCvol5uVgfubcIMzJBA0awAyFPU+TyUP1mkPYyiTHnsHYel/mKlSdPjc8a97N3SlJXHOCx41Hde4IyJgg==} + /@storybook/types@7.6.5: + resolution: {integrity: sha512-Q757v+fYZZSaEpks/zDL5YgXRozxkgKakXFc+BoQHK5q5sVhJ+0jvpLJiAQAniIIaMIkqY/G24Kd6Uo6UdKBCg==} dependencies: - '@storybook/channels': 7.6.4 + '@storybook/channels': 7.6.5 '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.3.0 dev: true - /@storybook/vue3-vite@7.6.4(@vue/compiler-core@3.3.11)(typescript@5.3.3)(vite@5.0.8)(vue@3.3.11): - resolution: {integrity: sha512-M1cT6lZsRqwws+H+pv2K/jJGiXUfGHAz7nc0DwK/YYT/w0OOVp5hinh/IvNwIYW5zUmwIyQVEoGrrxQEi0S79w==} + /@storybook/vue3-vite@7.6.5(@vue/compiler-core@3.3.12)(typescript@5.3.3)(vite@5.0.10)(vue@3.3.12): + resolution: {integrity: sha512-7wUCq2Lrjlekftd5ha3hG0GSGbbzuc370cKkBqSmwFuOfI38z5+VeYt7nDtAlncxcpVSH7DejTGRuKTlC7NyYg==} engines: {node: ^14.18 || >=16} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 dependencies: - '@storybook/builder-vite': 7.6.4(typescript@5.3.3)(vite@5.0.8) - '@storybook/core-server': 7.6.4 - '@storybook/vue3': 7.6.4(@vue/compiler-core@3.3.11)(vue@3.3.11) - '@vitejs/plugin-vue': 4.5.2(vite@5.0.8)(vue@3.3.11) + '@storybook/builder-vite': 7.6.5(typescript@5.3.3)(vite@5.0.10) + '@storybook/core-server': 7.6.5 + '@storybook/vue3': 7.6.5(@vue/compiler-core@3.3.12)(vue@3.3.12) + '@vitejs/plugin-vue': 4.5.2(vite@5.0.10)(vue@3.3.12) magic-string: 0.30.5 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) - vue-docgen-api: 4.64.1(vue@3.3.11) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) + vue-docgen-api: 4.64.1(vue@3.3.12) transitivePeerDependencies: - '@preact/preset-vite' - '@vue/compiler-core' @@ -7057,23 +7264,23 @@ packages: - vue dev: true - /@storybook/vue3@7.6.4(@vue/compiler-core@3.3.11)(vue@3.3.11): - resolution: {integrity: sha512-9BYxqj9C30/7UBspP4sE0UE/4fgE17jymJHWkxFbEE95MfbLkDFRnJ3Y09VPK0OnmbsBW5xBciMyjGV9Lq2pmg==} + /@storybook/vue3@7.6.5(@vue/compiler-core@3.3.12)(vue@3.3.12): + resolution: {integrity: sha512-tv/9rVc3XXDOJu5hfZtKhrhM8x4GTLKon62Rmaxlq06weqkGlfBi/V/g1EZ7OE71Pi+woKS/TX7p9qbRrvgahg==} engines: {node: '>=16.0.0'} peerDependencies: '@vue/compiler-core': ^3.0.0 vue: ^3.0.0 dependencies: - '@storybook/core-client': 7.6.4 - '@storybook/docs-tools': 7.6.4 + '@storybook/core-client': 7.6.5 + '@storybook/docs-tools': 7.6.5 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.6.4 - '@storybook/types': 7.6.4 - '@vue/compiler-core': 3.3.11 + '@storybook/preview-api': 7.6.5 + '@storybook/types': 7.6.5 + '@vue/compiler-core': 3.3.12 lodash: 4.17.21 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.3.11(typescript@5.3.3) + vue: 3.3.12(typescript@5.3.3) vue-component-type-helpers: 1.8.25 transitivePeerDependencies: - encoding @@ -7486,7 +7693,7 @@ packages: engines: {node: '>=14'} dependencies: '@babel/code-frame': 7.21.4 - '@babel/runtime': 7.21.0 + '@babel/runtime': 7.23.2 '@types/aria-query': 5.0.1 aria-query: 5.1.3 chalk: 4.1.2 @@ -7536,7 +7743,7 @@ packages: dom-accessibility-api: 0.5.16 lodash: 4.17.21 redent: 3.0.0 - vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.24.0) + vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.26.0) dev: true /@testing-library/user-event@14.4.3(@testing-library/dom@9.2.0): @@ -7548,7 +7755,7 @@ packages: '@testing-library/dom': 9.2.0 dev: true - /@testing-library/vue@8.0.1(@vue/compiler-sfc@3.3.11)(vue@3.3.11): + /@testing-library/vue@8.0.1(@vue/compiler-sfc@3.3.12)(vue@3.3.12): resolution: {integrity: sha512-l51ZEpjTQ6glq3wM+asQ1GbKJMGcxwgHEygETx0aCRN4TjFEGvMZy4YdWKs/y7bu4bmLrxcxhbEPP7iPSW/2OQ==} engines: {node: '>=14'} peerDependencies: @@ -7557,9 +7764,9 @@ packages: dependencies: '@babel/runtime': 7.23.2 '@testing-library/dom': 9.3.3 - '@vue/compiler-sfc': 3.3.11 - '@vue/test-utils': 2.4.1(vue@3.3.11) - vue: 3.3.11(typescript@5.3.3) + '@vue/compiler-sfc': 3.3.12 + '@vue/test-utils': 2.4.1(vue@3.3.12) + vue: 3.3.12(typescript@5.3.3) transitivePeerDependencies: - '@vue/server-renderer' dev: true @@ -7573,15 +7780,19 @@ packages: engines: {node: '>=10.13.0'} dev: false - /@tsd/typescript@5.2.2: - resolution: {integrity: sha512-VtjHPAKJqLJoHHKBDNofzvQB2+ZVxjXU/Gw6INAS9aINLQYVsxfzrQ2s84huCeYWZRTtrr7R0J7XgpZHjNwBCw==} + /@tsd/typescript@5.3.3: + resolution: {integrity: sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==} engines: {node: '>=14.17'} dev: true + /@twemoji/parser@15.0.0: + resolution: {integrity: sha512-lh9515BNsvKSNvyUqbj5yFu83iIDQ77SwVcsN/SnEGawczhsKU6qWuogewN1GweTi5Imo5ToQ9s+nNTf97IXvg==} + dev: false + /@types/accepts@1.3.7: resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/archiver@6.0.2: @@ -7635,7 +7846,7 @@ packages: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/braces@3.0.1: @@ -7647,7 +7858,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@types/responselike': 1.0.0 dev: false @@ -7680,7 +7891,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/content-disposition@0.5.8: @@ -7694,7 +7905,7 @@ packages: /@types/cross-spawn@6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/debug@4.1.7: @@ -7752,7 +7963,7 @@ packages: /@types/express-serve-static-core@4.17.33: resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -7773,29 +7984,33 @@ packages: /@types/fluent-ffmpeg@2.1.24: resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/http-cache-semantics@4.0.1: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} + /@types/http-cache-semantics@4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + dev: false + /@types/http-link-header@1.0.5: resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/istanbul-lib-coverage@2.0.4: @@ -7839,7 +8054,7 @@ packages: /@types/jsdom@21.1.6: resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -7863,7 +8078,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: false /@types/lodash@4.14.191: @@ -7912,7 +8127,7 @@ packages: /@types/node-fetch@2.6.4: resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 form-data: 3.0.1 /@types/node-fetch@3.0.3: @@ -7925,8 +8140,8 @@ packages: resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} dev: true - /@types/node@20.10.4: - resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} + /@types/node@20.10.5: + resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==} dependencies: undici-types: 5.26.5 @@ -7939,7 +8154,7 @@ packages: /@types/nodemailer@6.4.14: resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/normalize-package-data@2.4.1: @@ -7956,13 +8171,13 @@ packages: resolution: {integrity: sha512-Ali0fUUn+zgr4Yy/pCTFbuiaiJpq7l7OQwFnxYVchNbNGIx0c4Wkcdje6WO89I91RAaYF+gVc1pOaizA4YKZmA==} dependencies: '@types/express': 4.17.17 - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/oauth@0.9.4: resolution: {integrity: sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/offscreencanvas@2019.3.0: @@ -7978,7 +8193,7 @@ packages: /@types/pg@8.10.9: resolution: {integrity: sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 pg-protocol: 1.6.0 pg-types: 4.0.1 dev: true @@ -8002,7 +8217,7 @@ packages: /@types/qrcode@1.5.5: resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/qs@6.9.7: @@ -8032,7 +8247,7 @@ packages: /@types/readdir-glob@1.1.1: resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/rename@1.0.7: @@ -8046,7 +8261,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: false /@types/sanitize-html@2.9.5: @@ -8072,7 +8287,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 3.0.1 - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/serviceworker@0.0.67: @@ -8082,7 +8297,7 @@ packages: /@types/set-cookie-parser@2.4.3: resolution: {integrity: sha512-7QhnH7bi+6KAhBB+Auejz1uV9DHiopZqu7LfR/5gZZTkejJV5nYeZZpgfFoE0N8aDsXuiYpfKyfyMatCwQhyTQ==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/sharp@0.32.0: @@ -8145,13 +8360,13 @@ packages: /@types/vary@1.1.3: resolution: {integrity: sha512-XJT8/ZQCL7NUut9QDLf6l24JfAEl7bnNdgxfj50cHIpEPRJLHHDDFOAq6i+GsEmeFfH7NamhBE4c4Thtb2egWg==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/web-push@3.6.3: resolution: {integrity: sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/webgl-ext@0.0.30: @@ -8162,7 +8377,7 @@ packages: /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /@types/yargs-parser@21.0.0: @@ -8185,7 +8400,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true optional: true @@ -8218,7 +8433,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8230,13 +8445,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.14.0(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/type-utils': 6.14.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4(supports-color@5.5.0) - eslint: 8.55.0 + eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -8268,7 +8483,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/parser@6.14.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8283,7 +8498,7 @@ packages: '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4(supports-color@5.5.0) - eslint: 8.55.0 + eslint: 8.56.0 typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -8325,7 +8540,7 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/type-utils@6.14.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8336,9 +8551,9 @@ packages: optional: true dependencies: '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.56.0)(typescript@5.3.3) debug: 4.3.4(supports-color@5.5.0) - eslint: 8.55.0 + eslint: 8.56.0 ts-api-utils: 1.0.1(typescript@5.3.3) typescript: 5.3.3 transitivePeerDependencies: @@ -8416,19 +8631,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + /@typescript-eslint/utils@6.14.0(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 6.14.0 '@typescript-eslint/types': 6.14.0 '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) - eslint: 8.55.0 + eslint: 8.56.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -8455,7 +8670,7 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@vitejs/plugin-react@3.1.0(vite@5.0.8): + /@vitejs/plugin-react@3.1.0(vite@5.0.10): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -8466,20 +8681,20 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.23.5) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - supports-color dev: true - /@vitejs/plugin-vue@4.5.2(vite@5.0.8)(vue@3.3.11): + /@vitejs/plugin-vue@4.5.2(vite@5.0.10)(vue@3.3.12): resolution: {integrity: sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 || ^5.0.0 vue: ^3.2.25 dependencies: - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) - vue: 3.3.11(typescript@5.3.3) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) + vue: 3.3.12(typescript@5.3.3) /@vitest/coverage-v8@0.34.6(vitest@0.34.6): resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} @@ -8497,7 +8712,7 @@ packages: std-env: 3.3.3 test-exclude: 6.0.0 v8-to-istanbul: 9.1.0 - vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.24.0) + vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - supports-color dev: true @@ -8566,11 +8781,20 @@ packages: '@vue/shared': 3.3.11 estree-walker: 2.0.2 source-map-js: 1.0.2 + dev: true + + /@vue/compiler-core@3.3.12: + resolution: {integrity: sha512-qAtjyG3GBLG0chzp5xGCyRLLe6wFCHmjI82aGzwuGKyznNP+GJJMxjc0wOYWDB2YKfho7niJFdoFpo0CZZQg9w==} + dependencies: + '@babel/parser': 7.23.5 + '@vue/shared': 3.3.12 + estree-walker: 2.0.2 + source-map-js: 1.0.2 /@vue/compiler-core@3.3.9: resolution: {integrity: sha512-+/Lf68Vr/nFBA6ol4xOtJrW+BQWv3QWKfRwGSm70jtXwfhZNF4R/eRgyVJYoxFRhdCTk/F6g99BP0ffPgZihfQ==} dependencies: - '@babel/parser': 7.23.3 + '@babel/parser': 7.23.5 '@vue/shared': 3.3.9 estree-walker: 2.0.2 source-map-js: 1.0.2 @@ -8581,6 +8805,13 @@ packages: dependencies: '@vue/compiler-core': 3.3.11 '@vue/shared': 3.3.11 + dev: true + + /@vue/compiler-dom@3.3.12: + resolution: {integrity: sha512-RdJU9oEYaoPKUdGXCy0l+i4clesdDeLmbvRlszoc9iagsnBnMmQtYfCPVQ5BHB6o7K4SCucDdJM2Dh3oXB0D6g==} + dependencies: + '@vue/compiler-core': 3.3.12 + '@vue/shared': 3.3.12 /@vue/compiler-dom@3.3.9: resolution: {integrity: sha512-nfWubTtLXuT4iBeDSZ5J3m218MjOy42Vp2pmKVuBKo2/BLcrFUX8nCSr/bKRFiJ32R8qbdnnnBgRn9AdU5v0Sg==} @@ -8589,25 +8820,25 @@ packages: '@vue/shared': 3.3.9 dev: true - /@vue/compiler-sfc@3.3.11: - resolution: {integrity: sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==} + /@vue/compiler-sfc@3.3.12: + resolution: {integrity: sha512-yy5b9e7b79dsGbMmglCe/YnhCQgBkHO7Uf6JfjWPSf2/5XH+MKn18LhzhHyxbHdJgnA4lZCqtXzLaJz8Pd8lMw==} dependencies: '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.3.11 - '@vue/compiler-dom': 3.3.11 - '@vue/compiler-ssr': 3.3.11 - '@vue/reactivity-transform': 3.3.11 - '@vue/shared': 3.3.11 + '@vue/compiler-core': 3.3.12 + '@vue/compiler-dom': 3.3.12 + '@vue/compiler-ssr': 3.3.12 + '@vue/reactivity-transform': 3.3.12 + '@vue/shared': 3.3.12 estree-walker: 2.0.2 magic-string: 0.30.5 postcss: 8.4.32 source-map-js: 1.0.2 - /@vue/compiler-ssr@3.3.11: - resolution: {integrity: sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==} + /@vue/compiler-ssr@3.3.12: + resolution: {integrity: sha512-adCiMJPznfWcQyk/9HSuXGja859IaMV+b8UNSVzDatqv7h0PvT9BEeS22+gjkWofDiSg5d78/ZLls3sLA+cn3A==} dependencies: - '@vue/compiler-dom': 3.3.11 - '@vue/shared': 3.3.11 + '@vue/compiler-dom': 3.3.12 + '@vue/shared': 3.3.12 /@vue/language-core@1.8.25(typescript@5.3.3): resolution: {integrity: sha512-NJk/5DnAZlpvXX8BdWmHI45bWGLViUaS3R/RMrmFSvFMSbJKuEODpM4kR0F0Ofv5SFzCWuNiMhxameWpVdQsnA==} @@ -8629,50 +8860,54 @@ packages: vue-template-compiler: 2.7.14 dev: true - /@vue/reactivity-transform@3.3.11: - resolution: {integrity: sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==} + /@vue/reactivity-transform@3.3.12: + resolution: {integrity: sha512-g5TijmML7FyKkLt6QnpqNmA4KD7K/T5SbXa88Bhq+hydNQEkzA8veVXWAQuNqg9rjaFYD0rPf0a9NofKA0ENgg==} dependencies: '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.3.11 - '@vue/shared': 3.3.11 + '@vue/compiler-core': 3.3.12 + '@vue/shared': 3.3.12 estree-walker: 2.0.2 magic-string: 0.30.5 - /@vue/reactivity@3.3.11: - resolution: {integrity: sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==} + /@vue/reactivity@3.3.12: + resolution: {integrity: sha512-vOJORzO8DlIx88cgTnMLIf2GlLYpoXAKsuoQsK6SGdaqODjxO129pVPTd2s/N/Mb6KKZEFIHIEwWGmtN4YPs+g==} dependencies: - '@vue/shared': 3.3.11 + '@vue/shared': 3.3.12 - /@vue/runtime-core@3.3.11: - resolution: {integrity: sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==} + /@vue/runtime-core@3.3.12: + resolution: {integrity: sha512-5iL4w7MZrSGKEZU2wFAYhDZdZmgn+s//73EfgDXW1M+ZUOl36md7tlWp1QFK/ladiq4FvQ82shVjo0KiPDPr0A==} dependencies: - '@vue/reactivity': 3.3.11 - '@vue/shared': 3.3.11 + '@vue/reactivity': 3.3.12 + '@vue/shared': 3.3.12 - /@vue/runtime-dom@3.3.11: - resolution: {integrity: sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==} + /@vue/runtime-dom@3.3.12: + resolution: {integrity: sha512-8mMzqiIdl+IYa/OXwKwk6/4ebLq7cYV1pUcwCSwBK2KerUa6cwGosen5xrCL9f8o2DJ9TfPFwbPEvH7OXzUpoA==} dependencies: - '@vue/runtime-core': 3.3.11 - '@vue/shared': 3.3.11 - csstype: 3.1.2 + '@vue/runtime-core': 3.3.12 + '@vue/shared': 3.3.12 + csstype: 3.1.3 - /@vue/server-renderer@3.3.11(vue@3.3.11): - resolution: {integrity: sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==} + /@vue/server-renderer@3.3.12(vue@3.3.12): + resolution: {integrity: sha512-OZ0IEK5TU5GXb5J8/wSplyxvGGdIcwEmS8EIO302Vz8K6fGSgSJTU54X0Sb6PaefzZdiN3vHsLXO8XIeF8crQQ==} peerDependencies: - vue: 3.3.11 + vue: 3.3.12 dependencies: - '@vue/compiler-ssr': 3.3.11 - '@vue/shared': 3.3.11 - vue: 3.3.11(typescript@5.3.3) + '@vue/compiler-ssr': 3.3.12 + '@vue/shared': 3.3.12 + vue: 3.3.12(typescript@5.3.3) /@vue/shared@3.3.11: resolution: {integrity: sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==} + dev: true + + /@vue/shared@3.3.12: + resolution: {integrity: sha512-6p0Yin0pclvnER7BLNOQuod9Z+cxSYh8pSh7CzHnWNjAIP6zrTlCdHRvSCb1aYEx6i3Q3kvfuWU7nG16CgG1ag==} /@vue/shared@3.3.9: resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==} dev: true - /@vue/test-utils@2.4.1(vue@3.3.11): + /@vue/test-utils@2.4.1(vue@3.3.12): resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==} peerDependencies: '@vue/server-renderer': ^3.0.1 @@ -8682,7 +8917,7 @@ packages: optional: true dependencies: js-beautify: 1.14.9 - vue: 3.3.11(typescript@5.3.3) + vue: 3.3.12(typescript@5.3.3) vue-component-type-helpers: 1.8.4 dev: true @@ -9516,10 +9751,10 @@ packages: dependencies: fill-range: 7.0.1 - /broadcast-channel@6.0.0: - resolution: {integrity: sha512-h8ki6RYXq502Eb+zAt4Kni2ahL/lulh0ip+mpnvsMSRC2biBo6AkSBfO6JFTelT+FX88VL0SDd3RKpqlPNw4ng==} + /broadcast-channel@7.0.0: + resolution: {integrity: sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==} dependencies: - '@babel/runtime': 7.23.2 + '@babel/runtime': 7.23.4 oblivious-set: 1.4.0 p-queue: 6.6.2 unload: 2.4.1 @@ -9544,6 +9779,7 @@ packages: electron-to-chromium: 1.4.463 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.9) + dev: true /browserslist@4.22.2: resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} @@ -9554,7 +9790,6 @@ packages: electron-to-chromium: 1.4.601 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) - dev: true /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -9604,8 +9839,8 @@ packages: dependencies: node-gyp-build: 4.6.0 - /bullmq@4.15.3: - resolution: {integrity: sha512-UvvM61cGGoT6Ish+gjmPYzCoqOnkmdC9OMufcO41ijya8Evk6zqXm3PNYK8CLCkvb3jrWieDo1SFag9Tg3RiPQ==} + /bullmq@4.15.4: + resolution: {integrity: sha512-lrEtiERjYPPfb0OEXva5G8cF6kbtJFy/BmIL0yjmO+kj2eSVjCpAVVeYikxoqKtaYyEnNFal7ERVLanEvp+1Lw==} dependencies: cron-parser: 4.8.1 glob: 8.1.0 @@ -9672,6 +9907,19 @@ packages: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} + /cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.0 + responselike: 3.0.0 + dev: false + /cacheable-request@10.2.8: resolution: {integrity: sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==} engines: {node: '>=14.16'} @@ -9738,18 +9986,18 @@ packages: /caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: - browserslist: 4.21.9 - caniuse-lite: 1.0.30001516 + browserslist: 4.22.2 + caniuse-lite: 1.0.30001566 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 dev: false /caniuse-lite@1.0.30001516: resolution: {integrity: sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==} + dev: true /caniuse-lite@1.0.30001566: resolution: {integrity: sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==} - dev: true /canonicalize@1.0.8: resolution: {integrity: sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==} @@ -10302,7 +10550,7 @@ packages: readable-stream: 3.6.0 dev: false - /create-jest@29.7.0(@types/node@20.10.4): + /create-jest@29.7.0(@types/node@20.10.5): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10311,7 +10559,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.10.4) + jest-config: 29.7.0(@types/node@20.10.5) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -10387,9 +10635,9 @@ packages: engines: {node: '>=8'} dev: true - /css-declaration-sorter@6.4.1(postcss@8.4.32): - resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} - engines: {node: ^10 || ^12 || >=14} + /css-declaration-sorter@7.1.1(postcss@8.4.32): + resolution: {integrity: sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==} + engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.0.9 dependencies: @@ -10433,61 +10681,61 @@ packages: engines: {node: '>=4'} hasBin: true - /cssnano-preset-default@6.0.1(postcss@8.4.32): - resolution: {integrity: sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==} + /cssnano-preset-default@6.0.2(postcss@8.4.32): + resolution: {integrity: sha512-VnZybFeZ63AiVqIUNlxqMxpj9VU8B5j0oKgP7WyVt/7mkyf97KsYkNzsPTV/RVmy54Pg7cBhOK4WATbdCB44gw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - css-declaration-sorter: 6.4.1(postcss@8.4.32) - cssnano-utils: 4.0.0(postcss@8.4.32) + css-declaration-sorter: 7.1.1(postcss@8.4.32) + cssnano-utils: 4.0.1(postcss@8.4.32) postcss: 8.4.32 postcss-calc: 9.0.1(postcss@8.4.32) - postcss-colormin: 6.0.0(postcss@8.4.32) - postcss-convert-values: 6.0.0(postcss@8.4.32) - postcss-discard-comments: 6.0.0(postcss@8.4.32) - postcss-discard-duplicates: 6.0.0(postcss@8.4.32) - postcss-discard-empty: 6.0.0(postcss@8.4.32) - postcss-discard-overridden: 6.0.0(postcss@8.4.32) - postcss-merge-longhand: 6.0.0(postcss@8.4.32) - postcss-merge-rules: 6.0.1(postcss@8.4.32) - postcss-minify-font-values: 6.0.0(postcss@8.4.32) - postcss-minify-gradients: 6.0.0(postcss@8.4.32) - postcss-minify-params: 6.0.0(postcss@8.4.32) - postcss-minify-selectors: 6.0.0(postcss@8.4.32) - postcss-normalize-charset: 6.0.0(postcss@8.4.32) - postcss-normalize-display-values: 6.0.0(postcss@8.4.32) - postcss-normalize-positions: 6.0.0(postcss@8.4.32) - postcss-normalize-repeat-style: 6.0.0(postcss@8.4.32) - postcss-normalize-string: 6.0.0(postcss@8.4.32) - postcss-normalize-timing-functions: 6.0.0(postcss@8.4.32) - postcss-normalize-unicode: 6.0.0(postcss@8.4.32) - postcss-normalize-url: 6.0.0(postcss@8.4.32) - postcss-normalize-whitespace: 6.0.0(postcss@8.4.32) - postcss-ordered-values: 6.0.0(postcss@8.4.32) - postcss-reduce-initial: 6.0.0(postcss@8.4.32) - postcss-reduce-transforms: 6.0.0(postcss@8.4.32) - postcss-svgo: 6.0.0(postcss@8.4.32) - postcss-unique-selectors: 6.0.0(postcss@8.4.32) + postcss-colormin: 6.0.1(postcss@8.4.32) + postcss-convert-values: 6.0.1(postcss@8.4.32) + postcss-discard-comments: 6.0.1(postcss@8.4.32) + postcss-discard-duplicates: 6.0.1(postcss@8.4.32) + postcss-discard-empty: 6.0.1(postcss@8.4.32) + postcss-discard-overridden: 6.0.1(postcss@8.4.32) + postcss-merge-longhand: 6.0.1(postcss@8.4.32) + postcss-merge-rules: 6.0.2(postcss@8.4.32) + postcss-minify-font-values: 6.0.1(postcss@8.4.32) + postcss-minify-gradients: 6.0.1(postcss@8.4.32) + postcss-minify-params: 6.0.1(postcss@8.4.32) + postcss-minify-selectors: 6.0.1(postcss@8.4.32) + postcss-normalize-charset: 6.0.1(postcss@8.4.32) + postcss-normalize-display-values: 6.0.1(postcss@8.4.32) + postcss-normalize-positions: 6.0.1(postcss@8.4.32) + postcss-normalize-repeat-style: 6.0.1(postcss@8.4.32) + postcss-normalize-string: 6.0.1(postcss@8.4.32) + postcss-normalize-timing-functions: 6.0.1(postcss@8.4.32) + postcss-normalize-unicode: 6.0.1(postcss@8.4.32) + postcss-normalize-url: 6.0.1(postcss@8.4.32) + postcss-normalize-whitespace: 6.0.1(postcss@8.4.32) + postcss-ordered-values: 6.0.1(postcss@8.4.32) + postcss-reduce-initial: 6.0.1(postcss@8.4.32) + postcss-reduce-transforms: 6.0.1(postcss@8.4.32) + postcss-svgo: 6.0.1(postcss@8.4.32) + postcss-unique-selectors: 6.0.1(postcss@8.4.32) dev: false - /cssnano-utils@4.0.0(postcss@8.4.32): - resolution: {integrity: sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==} + /cssnano-utils@4.0.1(postcss@8.4.32): + resolution: {integrity: sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /cssnano@6.0.1(postcss@8.4.32): - resolution: {integrity: sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==} + /cssnano@6.0.2(postcss@8.4.32): + resolution: {integrity: sha512-Tu9wv8UdN6CoiQnIVkCNvi+0rw/BwFWOJBlg2bVfEyKaadSuE3Gq/DD8tniVvggTJGwK88UjqZp7zL5sv6t1aA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - cssnano-preset-default: 6.0.1(postcss@8.4.32) - lilconfig: 2.1.0 + cssnano-preset-default: 6.0.2(postcss@8.4.32) + lilconfig: 3.0.0 postcss: 8.4.32 dev: false @@ -10507,6 +10755,10 @@ packages: /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} /cwise-compiler@1.1.3: resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} @@ -11004,10 +11256,10 @@ packages: /electron-to-chromium@1.4.463: resolution: {integrity: sha512-fT3hvdUWLjDbaTGzyOjng/CQhQJSQP8ThO3XZAoaxHvHo2kUXiRQVMj9M235l8uDFiNPsPa6KHT1p3RaR6ugRw==} + dev: true /electron-to-chromium@1.4.601: resolution: {integrity: sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==} - dev: true /emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -11252,6 +11504,36 @@ packages: '@esbuild/win32-ia32': 0.19.8 '@esbuild/win32-x64': 0.19.8 + /esbuild@0.19.9: + resolution: {integrity: sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.9 + '@esbuild/android-arm64': 0.19.9 + '@esbuild/android-x64': 0.19.9 + '@esbuild/darwin-arm64': 0.19.9 + '@esbuild/darwin-x64': 0.19.9 + '@esbuild/freebsd-arm64': 0.19.9 + '@esbuild/freebsd-x64': 0.19.9 + '@esbuild/linux-arm': 0.19.9 + '@esbuild/linux-arm64': 0.19.9 + '@esbuild/linux-ia32': 0.19.9 + '@esbuild/linux-loong64': 0.19.9 + '@esbuild/linux-mips64el': 0.19.9 + '@esbuild/linux-ppc64': 0.19.9 + '@esbuild/linux-riscv64': 0.19.9 + '@esbuild/linux-s390x': 0.19.9 + '@esbuild/linux-x64': 0.19.9 + '@esbuild/netbsd-x64': 0.19.9 + '@esbuild/openbsd-x64': 0.19.9 + '@esbuild/sunos-x64': 0.19.9 + '@esbuild/win32-arm64': 0.19.9 + '@esbuild/win32-ia32': 0.19.9 + '@esbuild/win32-x64': 0.19.9 + dev: false + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -11317,7 +11599,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint@8.56.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -11338,16 +11620,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.14.0(eslint@8.56.0)(typescript@5.3.3) debug: 3.2.7(supports-color@8.1.1) - eslint: 8.55.0 + eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0): - resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==} + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.14.0)(eslint@8.56.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -11356,16 +11638,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.14.0(eslint@8.56.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 - eslint: 8.55.0 + eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint@8.56.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -11374,26 +11656,26 @@ packages: object.groupby: 1.0.1 object.values: 1.1.7 semver: 6.3.1 - tsconfig-paths: 3.14.2 + tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true - /eslint-plugin-vue@9.19.2(eslint@8.55.0): + /eslint-plugin-vue@9.19.2(eslint@8.56.0): resolution: {integrity: sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) - eslint: 8.55.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + eslint: 8.56.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.13 semver: 7.5.4 - vue-eslint-parser: 9.3.2(eslint@8.55.0) + vue-eslint-parser: 9.3.2(eslint@8.56.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -11463,15 +11745,15 @@ packages: - supports-color dev: true - /eslint@8.55.0: - resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} + /eslint@8.56.0: + resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) '@eslint-community/regexpp': 4.6.2 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.55.0 + '@eslint/js': 8.56.0 '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -12105,6 +12387,11 @@ packages: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} + /form-data-encoder@4.0.2: + resolution: {integrity: sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==} + engines: {node: '>= 18'} + dev: false + /form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} @@ -12536,20 +12823,20 @@ packages: p-cancelable: 3.0.0 responselike: 3.0.0 - /got@13.0.0: - resolution: {integrity: sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==} - engines: {node: '>=16'} + /got@14.0.0: + resolution: {integrity: sha512-X01vTgaX9SwaMq5DfImvS+3GMQFFs5HtrrlS9CuzUSzkxAf/tWGEyynuI+Qy7BjciMczZGjyVSmawYbP4eYhYA==} + engines: {node: '>=20'} dependencies: - '@sindresorhus/is': 5.3.0 + '@sindresorhus/is': 6.1.0 '@szmarczak/http-timer': 5.0.1 cacheable-lookup: 7.0.0 - cacheable-request: 10.2.8 + cacheable-request: 10.2.14 decompress-response: 6.0.0 - form-data-encoder: 2.1.4 - get-stream: 6.0.1 - http2-wrapper: 2.2.0 + form-data-encoder: 4.0.2 + get-stream: 8.0.1 + http2-wrapper: 2.2.1 lowercase-keys: 3.0.0 - p-cancelable: 3.0.0 + p-cancelable: 4.0.1 responselike: 3.0.0 dev: false @@ -12565,8 +12852,8 @@ packages: engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} dev: true - /gsap@3.12.3: - resolution: {integrity: sha512-TySXTE+ABiAVa61W+h5wv2p5GkJT1Uj//4nWpK8EjmhcDqwH++35IvtbQlVVFj+rdcJdFCdCt0SKgb+SwdPq/A==} + /gsap@3.12.4: + resolution: {integrity: sha512-1ByAq8dD0W4aBZ/JArgaQvc0gyUfkGkP8mgAQa0qZGdpOKlSOhOf+WNXjoLimKaKG3Z4Iu6DKZtnyszqQeyqWQ==} dev: false /gunzip-maybe@1.4.2: @@ -12809,6 +13096,14 @@ packages: quick-lru: 5.1.1 resolve-alpn: 1.2.1 + /http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: false + /http_ece@1.1.0: resolution: {integrity: sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA==} engines: {node: '>=4'} @@ -12996,6 +13291,10 @@ packages: side-channel: 1.0.4 dev: true + /intersection-observer@0.12.2: + resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} + dev: true + /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -13134,12 +13433,6 @@ packages: has: 1.0.3 dev: true - /is-core-module@2.13.0: - resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} - dependencies: - has: 1.0.3 - dev: true - /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: @@ -13510,7 +13803,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 co: 4.6.0 dedent: 1.3.0 @@ -13531,7 +13824,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.10.4): + /jest-cli@29.7.0(@types/node@20.10.5): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13545,10 +13838,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.10.4) + create-jest: 29.7.0(@types/node@20.10.5) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.10.4) + jest-config: 29.7.0(@types/node@20.10.5) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.6.2 @@ -13559,7 +13852,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.10.4): + /jest-config@29.7.0(@types/node@20.10.5): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -13574,7 +13867,7 @@ packages: '@babel/core': 7.22.11 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 babel-jest: 29.7.0(@babel/core@7.22.11) chalk: 4.1.2 ci-info: 3.7.1 @@ -13654,7 +13947,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -13684,7 +13977,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.6 - '@types/node': 20.10.4 + '@types/node': 20.10.5 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13745,7 +14038,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.10.4 + '@types/node': 20.10.5 dev: true /jest-mock@29.7.0: @@ -13753,7 +14046,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 jest-util: 29.7.0 dev: true @@ -13808,7 +14101,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13839,7 +14132,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -13891,7 +14184,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -13916,7 +14209,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13935,13 +14228,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@20.10.4): + /jest@29.7.0(@types/node@20.10.5): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13954,7 +14247,7 @@ packages: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.10.4) + jest-cli: 29.7.0(@types/node@20.10.5) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -14261,6 +14554,12 @@ packages: dependencies: json-buffer: 3.0.1 + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: false + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -14333,9 +14632,9 @@ packages: set-cookie-parser: 2.6.0 dev: false - /lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} + /lilconfig@3.0.0: + resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + engines: {node: '>=14'} dev: false /lines-and-columns@1.2.4: @@ -14680,17 +14979,17 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - /mfm-js@0.23.3: - resolution: {integrity: sha512-o8scYmbey6rMUmWAlT3k3ntt6khaCLdxlmHhAWV5wTTMj2OK1atQvZfRUq0SIVm1Jig08qlZg/ps71xUqrScNA==} + /mfm-js@0.24.0: + resolution: {integrity: sha512-6m8N0ElH9/4CA1izhVqmxTfLj5Z9RspdqM/lMew4xU/UTgm4Pf//VpDunpasxbRFjeJSVW+zoVwL4ZPfPtfiQg==} dependencies: - twemoji-parser: 14.0.0 + '@twemoji/parser': 15.0.0 dev: false - /microformats-parser@1.5.2: - resolution: {integrity: sha512-EcHm8zxEm3CggOLgILfxCo2wDiJEOnACzpV/FXWGLaRk24ECei+JkoWNdKdo2vzo/Pww9EvrQNeQsdv4JuHy7Q==} - engines: {node: '>=14'} + /microformats-parser@2.0.2: + resolution: {integrity: sha512-tUf9DmN4Jq/tGyp1YH2V6D/Cud+9Uc0WhjjUFirqVeHTRkkfLDacv6BQFT7h7HFsD0Z8wja5eKkRgzZU8bv0Fw==} + engines: {node: '>=18'} dependencies: - parse5: 6.0.1 + parse5: 7.1.2 dev: false /micromatch@4.0.5: @@ -15247,10 +15546,10 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true /nodemailer@6.9.7: resolution: {integrity: sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==} @@ -15325,7 +15624,7 @@ packages: engines: {node: '>=10'} dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.13.0 + is-core-module: 2.13.1 semver: 7.5.4 validate-npm-package-license: 3.0.4 dev: true @@ -15619,6 +15918,11 @@ packages: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} engines: {node: '>=12.20'} + /p-cancelable@4.0.1: + resolution: {integrity: sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==} + engines: {node: '>=14.16'} + dev: false + /p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -16061,251 +16365,251 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-colormin@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==} + /postcss-colormin@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-Tb9aR2wCJCzKuNjIeMzVNd0nXjQy25HDgFmmaRsHnP0eP/k8uQWE4S8voX5S2coO5CeKrp+USFs1Ayv9Tpxx6w==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-convert-values@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==} + /postcss-convert-values@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-zTd4Vh0HxGkhg5aHtfCogcRHzGkvblfdWlQ53lIh1cJhYcGyIxh2hgtKoVh40AMktRERet+JKdB04nNG19kjmA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-discard-comments@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==} + /postcss-discard-comments@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /postcss-discard-duplicates@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==} + /postcss-discard-duplicates@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-1hvUs76HLYR8zkScbwyJ8oJEugfPV+WchpnA+26fpJ7Smzs51CzGBHC32RS03psuX/2l0l0UKh2StzNxOrKCYg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /postcss-discard-empty@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==} + /postcss-discard-empty@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-yitcmKwmVWtNsrrRqGJ7/C0YRy53i0mjexBDQ9zYxDwTWVBgbU4+C9jIZLmQlTDT9zhml+u0OMFJh8+31krmOg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /postcss-discard-overridden@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==} + /postcss-discard-overridden@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /postcss-merge-longhand@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==} + /postcss-merge-longhand@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-vmr/HZQzaPXc45FRvSctqFTF05UaDnTn5ABX+UtQPJznDWT/QaFbVc/pJ5C2YPxx2J2XcfmWowlKwtCDwiQ5hA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 - stylehacks: 6.0.0(postcss@8.4.32) + stylehacks: 6.0.1(postcss@8.4.32) dev: false - /postcss-merge-rules@6.0.1(postcss@8.4.32): - resolution: {integrity: sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==} + /postcss-merge-rules@6.0.2(postcss@8.4.32): + resolution: {integrity: sha512-6lm8bl0UfriSfxI+F/cezrebqqP8w702UC6SjZlUlBYwuRVNbmgcJuQU7yePIvD4MNT53r/acQCUAyulrpgmeQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 caniuse-api: 3.0.0 - cssnano-utils: 4.0.0(postcss@8.4.32) + cssnano-utils: 4.0.1(postcss@8.4.32) postcss: 8.4.32 postcss-selector-parser: 6.0.13 dev: false - /postcss-minify-font-values@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==} + /postcss-minify-font-values@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-tIwmF1zUPoN6xOtA/2FgVk1ZKrLcCvE0dpZLtzyyte0j9zUeB8RTbCqrHZGjJlxOvNWKMYtunLrrl7HPOiR46w==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-gradients@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==} + /postcss-minify-gradients@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-M1RJWVjd6IOLPl1hYiOd5HQHgpp6cvJVLrieQYS9y07Yo8itAr6jaekzJphaJFR0tcg4kRewCk3kna9uHBxn/w==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: colord: 2.9.3 - cssnano-utils: 4.0.0(postcss@8.4.32) + cssnano-utils: 4.0.1(postcss@8.4.32) postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-params@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==} + /postcss-minify-params@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-eFvGWArqh4khPIgPDu6SZNcaLctx97nO7c59OXnRtGntAp5/VS4gjMhhW9qUFsK6mQ27pEZGt2kR+mPizI+Z9g==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 - cssnano-utils: 4.0.0(postcss@8.4.32) + browserslist: 4.22.2 + cssnano-utils: 4.0.1(postcss@8.4.32) postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-selectors@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==} + /postcss-minify-selectors@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-mfReq5wrS6vkunxvJp6GDuOk+Ak6JV7134gp8L+ANRnV9VwqzTvBtX6lpohooVU750AR0D3pVx2Zn6uCCwOAfQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-selector-parser: 6.0.13 dev: false - /postcss-normalize-charset@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==} + /postcss-normalize-charset@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 dev: false - /postcss-normalize-display-values@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==} + /postcss-normalize-display-values@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-positions@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==} + /postcss-normalize-positions@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-repeat-style@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==} + /postcss-normalize-repeat-style@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-string@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==} + /postcss-normalize-string@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-timing-functions@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==} + /postcss-normalize-timing-functions@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-unicode@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==} + /postcss-normalize-unicode@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-ok9DsI94nEF79MkvmLfHfn8ddnKXA7w+8YuUoz5m7b6TOdoaRCpvu/QMHXQs9+DwUbvp+ytzz04J55CPy77PuQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-url@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==} + /postcss-normalize-url@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-whitespace@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==} + /postcss-normalize-whitespace@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-ordered-values@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==} + /postcss-ordered-values@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - cssnano-utils: 4.0.0(postcss@8.4.32) + cssnano-utils: 4.0.1(postcss@8.4.32) postcss: 8.4.32 postcss-value-parser: 4.2.0 dev: false - /postcss-reduce-initial@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==} + /postcss-reduce-initial@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-cgzsI2ThG1PMSdSyM9A+bVxiiVgPIVz9f5c6H+TqEv0CA89iCOO81mwLWRWLgOKFtQkKob9nNpnkxG/1RlgFcA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 caniuse-api: 3.0.0 postcss: 8.4.32 dev: false - /postcss-reduce-transforms@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==} + /postcss-reduce-transforms@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 @@ -16318,22 +16622,22 @@ packages: cssesc: 3.0.0 util-deprecate: 1.0.2 - /postcss-svgo@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==} + /postcss-svgo@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-eWV4Rrqa06LzTgqirOv5Ln6WTGyU7Pbeqj9WEyKo9tpnWixNATVJMeaEcOHOW1ZYyjcG8wSJwX/28DvU3oy3HA==} engines: {node: ^14 || ^16 || >= 18} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-value-parser: 4.2.0 - svgo: 3.0.2 + svgo: 3.1.0 dev: false - /postcss-unique-selectors@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==} + /postcss-unique-selectors@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-/KCCEpNNR7oXVJ38/Id7GC9Nt0zxO1T3zVbhVaq6F6LSG+3gU3B7+QuTHfD0v8NPEHlzewAout29S0InmB78EQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: postcss: 8.4.32 postcss-selector-parser: 6.0.13 @@ -17151,6 +17455,7 @@ packages: /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} @@ -17397,24 +17702,24 @@ packages: fsevents: 2.3.3 dev: true - /rollup@4.9.0: - resolution: {integrity: sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==} + /rollup@4.9.1: + resolution: {integrity: sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.9.0 - '@rollup/rollup-android-arm64': 4.9.0 - '@rollup/rollup-darwin-arm64': 4.9.0 - '@rollup/rollup-darwin-x64': 4.9.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.9.0 - '@rollup/rollup-linux-arm64-gnu': 4.9.0 - '@rollup/rollup-linux-arm64-musl': 4.9.0 - '@rollup/rollup-linux-riscv64-gnu': 4.9.0 - '@rollup/rollup-linux-x64-gnu': 4.9.0 - '@rollup/rollup-linux-x64-musl': 4.9.0 - '@rollup/rollup-win32-arm64-msvc': 4.9.0 - '@rollup/rollup-win32-ia32-msvc': 4.9.0 - '@rollup/rollup-win32-x64-msvc': 4.9.0 + '@rollup/rollup-android-arm-eabi': 4.9.1 + '@rollup/rollup-android-arm64': 4.9.1 + '@rollup/rollup-darwin-arm64': 4.9.1 + '@rollup/rollup-darwin-x64': 4.9.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.9.1 + '@rollup/rollup-linux-arm64-gnu': 4.9.1 + '@rollup/rollup-linux-arm64-musl': 4.9.1 + '@rollup/rollup-linux-riscv64-gnu': 4.9.1 + '@rollup/rollup-linux-x64-gnu': 4.9.1 + '@rollup/rollup-linux-x64-musl': 4.9.1 + '@rollup/rollup-win32-arm64-msvc': 4.9.1 + '@rollup/rollup-win32-ia32-msvc': 4.9.1 + '@rollup/rollup-win32-x64-msvc': 4.9.1 fsevents: 2.3.3 /rrweb-cssom@0.6.0: @@ -17665,8 +17970,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - /shiki@0.14.6: - resolution: {integrity: sha512-R4koBBlQP33cC8cpzX0hAoOURBHJILp4Aaduh2eYi+Vj8ZBqtK/5SWNEHBS3qwUMu8dqOtI/ftno3ESfNeVW9g==} + /shiki@0.14.7: + resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==} dependencies: ansi-sequence-parser: 1.1.1 jsonc-parser: 3.2.0 @@ -18088,11 +18393,11 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true - /storybook@7.6.4: - resolution: {integrity: sha512-nQhs9XkrroxjqMoBnnToyc6M8ndbmpkOb1qmULO4chtfMy4k0p9Un3K4TJvDaP8c3wPUFGd4ZaJ1hZNVmIl56Q==} + /storybook@7.6.5: + resolution: {integrity: sha512-uHPrL+g/0v6iIVtDA8J0uWd3jDZcdr51lCR/vPXTkrCY1uVaFjswzl8EMy5PR05I7jMpKUzkJWZtFbgbh9e1Bw==} hasBin: true dependencies: - '@storybook/cli': 7.6.4 + '@storybook/cli': 7.6.5 transitivePeerDependencies: - bufferutil - encoding @@ -18309,13 +18614,13 @@ packages: peek-readable: 5.0.0 dev: false - /stylehacks@6.0.0(postcss@8.4.32): - resolution: {integrity: sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==} + /stylehacks@6.0.1(postcss@8.4.32): + resolution: {integrity: sha512-jTqG2aIoX2fYg0YsGvqE4ooE/e75WmaEjnNiP6Ag7irLtHxML8NJRxRxS0HyDpde8DRGuEXTFVHVfR5Tmbxqzg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: ^8.2.15 + postcss: ^8.4.31 dependencies: - browserslist: 4.21.9 + browserslist: 4.22.2 postcss: 8.4.32 postcss-selector-parser: 6.0.13 dev: false @@ -18355,8 +18660,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /svgo@3.0.2: - resolution: {integrity: sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==} + /svgo@3.1.0: + resolution: {integrity: sha512-R5SnNA89w1dYgNv570591F66v34b3eQShpIBcQtZtM5trJwm1VvxbIoMpRYY3ybTAutcKTLEmTsdnaknOHbiQA==} engines: {node: '>=14.0.0'} hasBin: true dependencies: @@ -18364,6 +18669,7 @@ packages: commander: 7.2.0 css-select: 5.1.0 css-tree: 2.3.1 + css-what: 6.1.0 csso: 5.0.5 picocolors: 1.0.0 dev: false @@ -18470,8 +18776,8 @@ packages: unique-string: 2.0.0 dev: true - /terser@5.24.0: - resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==} + /terser@5.26.0: + resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==} engines: {node: '>=10'} hasBin: true dependencies: @@ -18714,8 +19020,8 @@ packages: plimit-lit: 1.5.0 dev: false - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -18732,15 +19038,15 @@ packages: strip-bom: 3.0.0 dev: false - /tsd@0.29.0: - resolution: {integrity: sha512-5B7jbTj+XLMg6rb9sXRBGwzv7h8KJlGOkTHxY63eWpZJiQ5vJbXEjL0u7JkIxwi5EsrRE1kRVUWmy6buK/ii8A==} + /tsd@0.30.0: + resolution: {integrity: sha512-aHL4rEuf3wwRzKCH8yqsE1oMAJYn7SAQ2JfWSgjr1e5/fqr+ggohQazECMpSoRAqSQeM/iIFugoyL/0eFwdTcA==} engines: {node: '>=14.16'} hasBin: true dependencies: - '@tsd/typescript': 5.2.2 + '@tsd/typescript': 5.3.3 eslint-formatter-pretty: 4.1.0 globby: 11.1.0 - jest-diff: 29.6.4 + jest-diff: 29.7.0 meow: 9.0.0 path-exists: 4.0.0 read-pkg-up: 7.0.1 @@ -19137,6 +19443,7 @@ packages: browserslist: 4.21.9 escalade: 3.1.1 picocolors: 1.0.0 + dev: true /update-browserslist-db@1.0.13(browserslist@4.22.2): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} @@ -19147,7 +19454,6 @@ packages: browserslist: 4.22.2 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -19246,7 +19552,7 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - /v-code-diff@1.7.2(vue@3.3.11): + /v-code-diff@1.7.2(vue@3.3.12): resolution: {integrity: sha512-y+q8ZHf8GfphYLhcZbjAKcId/h6vZujS71Ryq5u+dI6Jg4ZLTdLrBNVSzYpHywHSSFFfBMdilm6XvVryEaH4+A==} requiresBuild: true peerDependencies: @@ -19259,8 +19565,8 @@ packages: diff: 5.1.0 diff-match-patch: 1.0.5 highlight.js: 11.8.0 - vue: 3.3.11(typescript@5.3.3) - vue-demi: 0.13.11(vue@3.3.11) + vue: 3.3.12(typescript@5.3.3) + vue-demi: 0.13.11(vue@3.3.12) dev: false /v8-to-istanbul@9.1.0: @@ -19296,7 +19602,7 @@ packages: core-util-is: 1.0.2 extsprintf: 1.3.0 - /vite-node@0.34.6(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0): + /vite-node@0.34.6(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0): resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19306,7 +19612,7 @@ packages: mlly: 1.4.0 pathe: 1.1.1 picocolors: 1.0.0 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - '@types/node' - less @@ -19322,8 +19628,8 @@ packages: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} dev: true - /vite@5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0): - resolution: {integrity: sha512-jYMALd8aeqR3yS9xlHd0OzQJndS9fH5ylVgWdB+pxTwxLKdO1pgC5Dlb398BUxpfaBxa4M9oT7j1g503Gaj5IQ==} + /vite@5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0): + resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -19350,12 +19656,12 @@ packages: terser: optional: true dependencies: - '@types/node': 20.10.4 + '@types/node': 20.10.5 esbuild: 0.19.8 postcss: 8.4.32 - rollup: 4.9.0 + rollup: 4.9.1 sass: 1.69.5 - terser: 5.24.0 + terser: 5.26.0 optionalDependencies: fsevents: 2.3.3 @@ -19366,12 +19672,12 @@ packages: vitest: '>=0.16.0' dependencies: cross-fetch: 3.1.5 - vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.24.0) + vitest: 0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.26.0) transitivePeerDependencies: - encoding dev: true - /vitest@0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.24.0): + /vitest@0.34.6(happy-dom@10.0.3)(sass@1.69.5)(terser@5.26.0): resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19404,7 +19710,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 20.10.4 + '@types/node': 20.10.5 '@vitest/expect': 0.34.6 '@vitest/runner': 0.34.6 '@vitest/snapshot': 0.34.6 @@ -19424,8 +19730,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.5.0 tinypool: 0.7.0 - vite: 5.0.8(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) - vite-node: 0.34.6(@types/node@20.10.4)(sass@1.69.5)(terser@5.24.0) + vite: 5.0.10(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) + vite-node: 0.34.6(@types/node@20.10.5)(sass@1.69.5)(terser@5.26.0) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -19457,7 +19763,7 @@ packages: resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==} dev: true - /vue-demi@0.13.11(vue@3.3.11): + /vue-demi@0.13.11(vue@3.3.12): resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} engines: {node: '>=12'} hasBin: true @@ -19469,35 +19775,35 @@ packages: '@vue/composition-api': optional: true dependencies: - vue: 3.3.11(typescript@5.3.3) + vue: 3.3.12(typescript@5.3.3) dev: false - /vue-docgen-api@4.64.1(vue@3.3.11): + /vue-docgen-api@4.64.1(vue@3.3.12): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: '@babel/parser': 7.23.5 '@babel/types': 7.23.5 - '@vue/compiler-dom': 3.3.9 - '@vue/compiler-sfc': 3.3.11 + '@vue/compiler-dom': 3.3.11 + '@vue/compiler-sfc': 3.3.12 ast-types: 0.14.2 hash-sum: 2.0.0 lru-cache: 8.0.4 pug: 3.0.2 recast: 0.22.0 ts-map: 1.0.3 - vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.11) + vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.12) transitivePeerDependencies: - vue dev: true - /vue-eslint-parser@9.3.2(eslint@8.55.0): + /vue-eslint-parser@9.3.2(eslint@8.56.0): resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@5.5.0) - eslint: 8.55.0 + eslint: 8.56.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -19508,12 +19814,12 @@ packages: - supports-color dev: true - /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.11): + /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.12): resolution: {integrity: sha512-Hn32n07XZ8j9W8+fmOXPQL+i+W2e/8i6mkH4Ju3H6nR0+cfvmWM95GhczYi5B27+Y8JlCKgAo04IUiYce4mKAw==} peerDependencies: vue: '>=2' dependencies: - vue: 3.3.11(typescript@5.3.3) + vue: 3.3.12(typescript@5.3.3) dev: true /vue-template-compiler@2.7.14: @@ -19535,28 +19841,28 @@ packages: typescript: 5.3.3 dev: true - /vue@3.3.11(typescript@5.3.3): - resolution: {integrity: sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==} + /vue@3.3.12(typescript@5.3.3): + resolution: {integrity: sha512-jYNv2QmET2OTHsFzfWHMnqgCfqL4zfo97QwofdET+GBRCHhSCHuMTTvNIgeSn0/xF3JRT5OGah6MDwUFN7MPlg==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@vue/compiler-dom': 3.3.11 - '@vue/compiler-sfc': 3.3.11 - '@vue/runtime-dom': 3.3.11 - '@vue/server-renderer': 3.3.11(vue@3.3.11) - '@vue/shared': 3.3.11 + '@vue/compiler-dom': 3.3.12 + '@vue/compiler-sfc': 3.3.12 + '@vue/runtime-dom': 3.3.12 + '@vue/server-renderer': 3.3.12(vue@3.3.12) + '@vue/shared': 3.3.12 typescript: 5.3.3 - /vuedraggable@4.1.0(vue@3.3.11): + /vuedraggable@4.1.0(vue@3.3.12): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} peerDependencies: vue: ^3.0.1 dependencies: sortablejs: 1.14.0 - vue: 3.3.11(typescript@5.3.3) + vue: 3.3.12(typescript@5.3.3) dev: false /w3c-xmlserializer@5.0.0: @@ -20031,7 +20337,7 @@ packages: sharp: 0.31.3 dev: false - github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.6.4)(@storybook/components@7.6.4)(@storybook/core-events@7.6.4)(@storybook/manager-api@7.6.4)(@storybook/preview-api@7.6.4)(@storybook/theming@7.6.4)(@storybook/types@7.6.4)(react-dom@18.2.0)(react@18.2.0): + github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.6.5)(@storybook/components@7.6.5)(@storybook/core-events@7.6.5)(@storybook/manager-api@7.6.5)(@storybook/preview-api@7.6.5)(@storybook/theming@7.6.5)(@storybook/types@7.6.5)(react-dom@18.2.0)(react@18.2.0): resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 name: storybook-addon-misskey-theme @@ -20052,13 +20358,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/components': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.6.4 - '@storybook/manager-api': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.6.4 - '@storybook/theming': 7.6.4(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.6.4 + '@storybook/blocks': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.6.5 + '@storybook/manager-api': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.6.5 + '@storybook/theming': 7.6.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.6.5 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true