Merge remote-tracking branch 'msky/develop' into enh-15290
This commit is contained in:
commit
25f719a5ec
|
@ -50,8 +50,8 @@ jobs:
|
||||||
- run: pnpm i --frozen-lockfile
|
- run: pnpm i --frozen-lockfile
|
||||||
- name: Check pnpm-lock.yaml
|
- name: Check pnpm-lock.yaml
|
||||||
run: git diff --exit-code pnpm-lock.yaml
|
run: git diff --exit-code pnpm-lock.yaml
|
||||||
- name: Build misskey-js
|
- name: Build dependent packages
|
||||||
run: pnpm --filter misskey-js build
|
run: pnpm -F misskey-js -F misskey-bubble-game -F misskey-reversi build
|
||||||
- name: Build storybook
|
- name: Build storybook
|
||||||
run: pnpm --filter frontend build-storybook
|
run: pnpm --filter frontend build-storybook
|
||||||
- name: Publish to Chromatic
|
- name: Publish to Chromatic
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
- Feat: 設定の管理が強化されました
|
- Feat: 設定の管理が強化されました
|
||||||
- 自動でバックアップされるように
|
- 自動でバックアップされるように
|
||||||
- 任意の設定項目をデバイス間で同期できるように
|
- 任意の設定項目をデバイス間で同期できるように
|
||||||
|
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
||||||
- Enhance: プラグインの管理が強化されました
|
- Enhance: プラグインの管理が強化されました
|
||||||
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
||||||
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
- Enhance: 投稿フォームの設定メニューを改良
|
- Enhance: 投稿フォームの設定メニューを改良
|
||||||
- 投稿フォームをリセットできるように
|
- 投稿フォームをリセットできるように
|
||||||
- 文字数カウントを復活
|
- 文字数カウントを復活
|
||||||
|
- Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように
|
||||||
- Enhance: 投稿フォームの絵文字ピッカーに独立したウィンドウを使用できるように
|
- Enhance: 投稿フォームの絵文字ピッカーに独立したウィンドウを使用できるように
|
||||||
- リアクションピッカーと絵文字ピッカーで表示スタイルの設定が分離しました。絵文字ピッカーでのみウィンドウスタイルを使用可能です。
|
- リアクションピッカーと絵文字ピッカーで表示スタイルの設定が分離しました。絵文字ピッカーでのみウィンドウスタイルを使用可能です。
|
||||||
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
||||||
|
@ -24,6 +26,8 @@
|
||||||
### Server
|
### Server
|
||||||
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正
|
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正
|
||||||
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
||||||
|
- Fix: 連合無しモードでも外部から照会可能だった問題を修正
|
||||||
|
- Fix: テスト用WebHookのペイロードの`emojis`パラメータが実際のものと異なる問題を修正
|
||||||
|
|
||||||
## 2025.3.1
|
## 2025.3.1
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,6 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
|
||||||
query?: Record<string, string>;
|
query?: Record<string, string>;
|
||||||
loginRequired?: boolean;
|
loginRequired?: boolean;
|
||||||
hash?: string;
|
hash?: string;
|
||||||
globalCacheKey?: string;
|
|
||||||
children?: RouteDef[];
|
children?: RouteDef[];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1013,6 +1013,7 @@ flip: "اقلب"
|
||||||
lastNDays: "آخر {n} أيام"
|
lastNDays: "آخر {n} أيام"
|
||||||
surrender: "ألغِ"
|
surrender: "ألغِ"
|
||||||
postForm: "أنشئ ملاحظة"
|
postForm: "أنشئ ملاحظة"
|
||||||
|
information: "عن"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "مُعلّق"
|
stop: "مُعلّق"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
|
|
|
@ -853,6 +853,7 @@ renotes: "রিনোট"
|
||||||
sourceCode: "সোর্স কোড"
|
sourceCode: "সোর্স কোড"
|
||||||
flip: "উল্টান"
|
flip: "উল্টান"
|
||||||
postForm: "নোট লিখুন"
|
postForm: "নোট লিখুন"
|
||||||
|
information: "আপনার সম্পর্কে"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "স্থগিত করা হয়েছে"
|
stop: "স্থগিত করা হয়েছে"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} està parlant sobre \"{word}\""
|
||||||
makeActive: "Activar"
|
makeActive: "Activar"
|
||||||
display: "Veure"
|
display: "Veure"
|
||||||
copy: "Copiar"
|
copy: "Copiar"
|
||||||
|
copiedToClipboard: "Copiat al porta papers"
|
||||||
metrics: "Mètriques"
|
metrics: "Mètriques"
|
||||||
overview: "Visió General"
|
overview: "Visió General"
|
||||||
logs: "Registres"
|
logs: "Registres"
|
||||||
|
@ -1139,7 +1140,7 @@ channelArchiveConfirmDescription: "Un Canal arxivat no apareixerà a la llista d
|
||||||
thisChannelArchived: "Aquest Canal ha sigut arxivat."
|
thisChannelArchived: "Aquest Canal ha sigut arxivat."
|
||||||
displayOfNote: "Mostrar notes"
|
displayOfNote: "Mostrar notes"
|
||||||
initialAccountSetting: "Configuració del perfil"
|
initialAccountSetting: "Configuració del perfil"
|
||||||
youFollowing: "Seguint"
|
youFollowing: "Segueixes "
|
||||||
preventAiLearning: "Descartar l'ús d'aprenentatge automàtic (IA Generativa)"
|
preventAiLearning: "Descartar l'ús d'aprenentatge automàtic (IA Generativa)"
|
||||||
preventAiLearningDescription: "Demanar els indexadors no fer servir els texts, imatges, etc. en cap conjunt de dades per alimentar l'aprenentatge automàtic (IA Predictiva/ Generativa). Això s'aconsegueix afegint la etiqueta \"noai\" com a resposta HTML al contingut corresponent. Prevenir aquest ús totalment pot ser que no sigui aconseguit, ja que molts indexadors poden obviar aquesta etiqueta."
|
preventAiLearningDescription: "Demanar els indexadors no fer servir els texts, imatges, etc. en cap conjunt de dades per alimentar l'aprenentatge automàtic (IA Predictiva/ Generativa). Això s'aconsegueix afegint la etiqueta \"noai\" com a resposta HTML al contingut corresponent. Prevenir aquest ús totalment pot ser que no sigui aconseguit, ja que molts indexadors poden obviar aquesta etiqueta."
|
||||||
options: "Opcions"
|
options: "Opcions"
|
||||||
|
@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "Cancel·lar l'activació de la sincronitzac
|
||||||
paste: "Pegar"
|
paste: "Pegar"
|
||||||
emojiPalette: "Calaix d'emojis"
|
emojiPalette: "Calaix d'emojis"
|
||||||
postForm: "Formulari de publicació"
|
postForm: "Formulari de publicació"
|
||||||
|
textCount: "Nombre de caràcters "
|
||||||
|
information: "Informació"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "Calaixos d'emojis"
|
palettes: "Calaixos d'emojis"
|
||||||
enableSyncBetweenDevicesForPalettes: "Activa la sincronització dels calaixos d'emojis entre dispositius"
|
enableSyncBetweenDevicesForPalettes: "Activa la sincronització dels calaixos d'emojis entre dispositius"
|
||||||
|
@ -1355,6 +1358,8 @@ _settings:
|
||||||
appearanceBanner: "Pots configurar les preferències relacionades amb la visualització i l'aspecte del client segons el teu parer."
|
appearanceBanner: "Pots configurar les preferències relacionades amb la visualització i l'aspecte del client segons el teu parer."
|
||||||
soundsBanner: "Configuració dels sons que reproduirà el client."
|
soundsBanner: "Configuració dels sons que reproduirà el client."
|
||||||
timelineAndNote: "Línia de temps i nota"
|
timelineAndNote: "Línia de temps i nota"
|
||||||
|
makeEveryTextElementsSelectable: "Fes que tots els elements del text siguin seleccionables"
|
||||||
|
makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions."
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "Nom del perfil"
|
profileName: "Nom del perfil"
|
||||||
profileNameDescription: "Estableix un nom que identifiqui aquest dispositiu."
|
profileNameDescription: "Estableix un nom que identifiqui aquest dispositiu."
|
||||||
|
@ -2519,6 +2524,7 @@ _notification:
|
||||||
achievementEarned: "Assoliment desbloquejat"
|
achievementEarned: "Assoliment desbloquejat"
|
||||||
exportCompleted: "Exportació completada"
|
exportCompleted: "Exportació completada"
|
||||||
login: "Iniciar sessió"
|
login: "Iniciar sessió"
|
||||||
|
createToken: "Creació de tokens d'accés "
|
||||||
test: "Prova la notificació"
|
test: "Prova la notificació"
|
||||||
app: "Notificacions d'aplicacions"
|
app: "Notificacions d'aplicacions"
|
||||||
_actions:
|
_actions:
|
||||||
|
@ -2668,10 +2674,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Assegura't que qui distribueix aquest recurs és fiable abans d'instal·lar-ho."
|
checkVendorBeforeInstall: "Assegura't que qui distribueix aquest recurs és fiable abans d'instal·lar-ho."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Vols instal·lar aquest afegit?"
|
title: "Vols instal·lar aquest afegit?"
|
||||||
metaTitle: "Informació de l'afegit "
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Vols instal·lar aquest tema?"
|
title: "Vols instal·lar aquest tema?"
|
||||||
metaTitle: "Informació del tema"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Paleta de colors base"
|
base: "Paleta de colors base"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -169,6 +169,9 @@ addAccount: "Přidat účet"
|
||||||
reloadAccountsList: "Obnovit list účtů"
|
reloadAccountsList: "Obnovit list účtů"
|
||||||
loginFailed: "Přihlášení se nezdařilo."
|
loginFailed: "Přihlášení se nezdařilo."
|
||||||
showOnRemote: "Více na původním profilu"
|
showOnRemote: "Více na původním profilu"
|
||||||
|
continueOnRemote: "Pokračujte na původní profil"
|
||||||
|
chooseServerOnMisskeyHub: "Vyberete si server z Misskey Hubu"
|
||||||
|
inputHostName: "Zadejte doménu"
|
||||||
general: "Obecně"
|
general: "Obecně"
|
||||||
wallpaper: "Obrázek na pozadí"
|
wallpaper: "Obrázek na pozadí"
|
||||||
setWallpaper: "Nastavení obrázku na pozadí"
|
setWallpaper: "Nastavení obrázku na pozadí"
|
||||||
|
@ -193,6 +196,7 @@ perHour: "za hodinu"
|
||||||
perDay: "za den"
|
perDay: "za den"
|
||||||
stopActivityDelivery: "Přestat zasílat aktivitu"
|
stopActivityDelivery: "Přestat zasílat aktivitu"
|
||||||
blockThisInstance: "Blokovat tuto instanci"
|
blockThisInstance: "Blokovat tuto instanci"
|
||||||
|
silenceThisInstance: "Utišit tuto instanci"
|
||||||
operations: "Operace"
|
operations: "Operace"
|
||||||
software: "Software"
|
software: "Software"
|
||||||
version: "Verze"
|
version: "Verze"
|
||||||
|
@ -1099,6 +1103,7 @@ flip: "Otočit"
|
||||||
lastNDays: "Posledních {n} dnů"
|
lastNDays: "Posledních {n} dnů"
|
||||||
surrender: "Zrušit"
|
surrender: "Zrušit"
|
||||||
postForm: "Formulář pro odeslání"
|
postForm: "Formulář pro odeslání"
|
||||||
|
information: "Informace"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspendováno"
|
stop: "Suspendováno"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1309,6 +1309,7 @@ availableRoles: "Verfügbare Rollen"
|
||||||
federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren."
|
federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren."
|
||||||
federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren."
|
federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren."
|
||||||
postForm: "Notizfenster"
|
postForm: "Notizfenster"
|
||||||
|
information: "Über"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
|
@ -2524,10 +2525,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Überprüfe vor Installation die Vertrauenswürdigkeit des Vertreibers."
|
checkVendorBeforeInstall: "Überprüfe vor Installation die Vertrauenswürdigkeit des Vertreibers."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Möchtest du dieses Plugin installieren?"
|
title: "Möchtest du dieses Plugin installieren?"
|
||||||
metaTitle: "Plugininformation"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Möchten du dieses Farbschema installieren?"
|
title: "Möchten du dieses Farbschema installieren?"
|
||||||
metaTitle: "Farbschemainfo"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Farbschemavorlage"
|
base: "Farbschemavorlage"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -289,6 +289,7 @@ icon: "Εικονίδιο"
|
||||||
replies: "Απάντηση"
|
replies: "Απάντηση"
|
||||||
renotes: "Κοινοποίηση σημειώματος"
|
renotes: "Κοινοποίηση σημειώματος"
|
||||||
postForm: "Φόρμα δημοσίευσης"
|
postForm: "Φόρμα δημοσίευσης"
|
||||||
|
information: "Πληροφορίες"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "Έχετε ένα νέο ακόλουθο"
|
title: "Έχετε ένα νέο ακόλουθο"
|
||||||
|
|
|
@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} said something about \"{word}\""
|
||||||
makeActive: "Activate"
|
makeActive: "Activate"
|
||||||
display: "Display"
|
display: "Display"
|
||||||
copy: "Copy"
|
copy: "Copy"
|
||||||
|
copiedToClipboard: "Copied to clipboard"
|
||||||
metrics: "Metrics"
|
metrics: "Metrics"
|
||||||
overview: "Overview"
|
overview: "Overview"
|
||||||
logs: "Logs"
|
logs: "Logs"
|
||||||
|
@ -1316,14 +1317,29 @@ unmarkAsSensitiveConfirm: "Do you want to remove the sensitive designation for t
|
||||||
preferences: "Preferences"
|
preferences: "Preferences"
|
||||||
accessibility: "Accessibility"
|
accessibility: "Accessibility"
|
||||||
preferencesProfile: "Preferences profile"
|
preferencesProfile: "Preferences profile"
|
||||||
copyPreferenceId: "Copy the proference ID"
|
copyPreferenceId: "Copy the preference ID"
|
||||||
resetToDefaultValue: "Revert to default"
|
resetToDefaultValue: "Revert to default"
|
||||||
overrideByAccount: "Override by the account"
|
overrideByAccount: "Override by the account"
|
||||||
untitled: "Untitled"
|
untitled: "Untitled"
|
||||||
noName: "No name"
|
noName: "No name"
|
||||||
skip: "Skip"
|
skip: "Skip"
|
||||||
restore: "Restore"
|
restore: "Restore"
|
||||||
|
syncBetweenDevices: "Sync between devices"
|
||||||
|
preferenceSyncConflictTitle: "The configured value exists on the server."
|
||||||
|
preferenceSyncConflictText: "The sync enabled settings will save their values to the server. However, there are existing values on the server. Which set of values would you like to overwrite?"
|
||||||
|
preferenceSyncConflictChoiceServer: "Configured value on server"
|
||||||
|
preferenceSyncConflictChoiceDevice: "Configured value on device"
|
||||||
|
preferenceSyncConflictChoiceCancel: "Cancel enabling sync"
|
||||||
|
paste: "Paste"
|
||||||
|
emojiPalette: "Emoji palette"
|
||||||
postForm: "Posting form"
|
postForm: "Posting form"
|
||||||
|
textCount: "Character count"
|
||||||
|
information: "About"
|
||||||
|
_emojiPalette:
|
||||||
|
palettes: "Palette"
|
||||||
|
enableSyncBetweenDevicesForPalettes: "Enable palette sync between devices"
|
||||||
|
paletteForMain: "Main palette"
|
||||||
|
paletteForReaction: "Reaction palette"
|
||||||
_settings:
|
_settings:
|
||||||
driveBanner: "You can manage and configure the drive, check usage, and configure file upload settings."
|
driveBanner: "You can manage and configure the drive, check usage, and configure file upload settings."
|
||||||
pluginBanner: "You can extend client features with plugins. You can install plugins, configure and manage individually."
|
pluginBanner: "You can extend client features with plugins. You can install plugins, configure and manage individually."
|
||||||
|
@ -1341,6 +1357,9 @@ _settings:
|
||||||
preferencesBanner: "You can configure the overall behavior of the client according to your preferences."
|
preferencesBanner: "You can configure the overall behavior of the client according to your preferences."
|
||||||
appearanceBanner: "You can configure the appearance and display settings for the client according to your preferences."
|
appearanceBanner: "You can configure the appearance and display settings for the client according to your preferences."
|
||||||
soundsBanner: "You can configure the sound settings for playback in the client."
|
soundsBanner: "You can configure the sound settings for playback in the client."
|
||||||
|
timelineAndNote: "Timeline and note"
|
||||||
|
makeEveryTextElementsSelectable: "Make all text elements selectable"
|
||||||
|
makeEveryTextElementsSelectable_description: "Enabling this may reduce usability in some situations."
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "Profile name"
|
profileName: "Profile name"
|
||||||
profileNameDescription: "Set a name that identifies this device."
|
profileNameDescription: "Set a name that identifies this device."
|
||||||
|
@ -2505,6 +2524,7 @@ _notification:
|
||||||
achievementEarned: "Achievement unlocked"
|
achievementEarned: "Achievement unlocked"
|
||||||
exportCompleted: "The export has been completed"
|
exportCompleted: "The export has been completed"
|
||||||
login: "Sign In"
|
login: "Sign In"
|
||||||
|
createToken: "Create access token"
|
||||||
test: "Notification test"
|
test: "Notification test"
|
||||||
app: "Notifications from linked apps"
|
app: "Notifications from linked apps"
|
||||||
_actions:
|
_actions:
|
||||||
|
@ -2532,6 +2552,7 @@ _deck:
|
||||||
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
|
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
|
||||||
usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled"
|
usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled"
|
||||||
flexible: "Auto-adjust width"
|
flexible: "Auto-adjust width"
|
||||||
|
enableSyncBetweenDevicesForProfiles: "Enable profile information sync between devices"
|
||||||
_columns:
|
_columns:
|
||||||
main: "Main"
|
main: "Main"
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
|
@ -2653,10 +2674,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Make sure the distributor of this resource is trustworthy before installation."
|
checkVendorBeforeInstall: "Make sure the distributor of this resource is trustworthy before installation."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Do you want to install this plugin?"
|
title: "Do you want to install this plugin?"
|
||||||
metaTitle: "Plugin information"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Do you want to install this theme?"
|
title: "Do you want to install this theme?"
|
||||||
metaTitle: "Theme information"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Base color scheme"
|
base: "Base color scheme"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
@ -2857,8 +2876,8 @@ _selfXssPrevention:
|
||||||
description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window."
|
description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window."
|
||||||
description3: "For more information, please refer to this. {link}"
|
description3: "For more information, please refer to this. {link}"
|
||||||
_followRequest:
|
_followRequest:
|
||||||
recieved: "Received application"
|
recieved: "Received request"
|
||||||
sent: "Sent application"
|
sent: "Sent request"
|
||||||
_remoteLookupErrors:
|
_remoteLookupErrors:
|
||||||
_federationNotAllowed:
|
_federationNotAllowed:
|
||||||
title: "Unable to communicate with this server"
|
title: "Unable to communicate with this server"
|
||||||
|
|
|
@ -1300,6 +1300,7 @@ target: "Para"
|
||||||
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
||||||
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
||||||
postForm: "Formulario"
|
postForm: "Formulario"
|
||||||
|
information: "Información"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
|
@ -2521,10 +2522,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Asegúrate de que el distribuidor de este recurso es de confianza antes de proceder a la instalación."
|
checkVendorBeforeInstall: "Asegúrate de que el distribuidor de este recurso es de confianza antes de proceder a la instalación."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "¿Quieres instalar este plugin?"
|
title: "¿Quieres instalar este plugin?"
|
||||||
metaTitle: "Información del plugin"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "¿Quieres instalar este tema?"
|
title: "¿Quieres instalar este tema?"
|
||||||
metaTitle: "Información del tema"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Esquema de color base"
|
base: "Esquema de color base"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -1278,6 +1278,7 @@ lockdown: "Verrouiller"
|
||||||
pleaseSelectAccount: "Sélectionner un compte"
|
pleaseSelectAccount: "Sélectionner un compte"
|
||||||
availableRoles: "Rôles disponibles"
|
availableRoles: "Rôles disponibles"
|
||||||
postForm: "Formulaire de publication"
|
postForm: "Formulaire de publication"
|
||||||
|
information: "Informations"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Transférer"
|
forward: "Transférer"
|
||||||
forwardDescription: "Transférer le signalement vers une instance distante en tant qu'anonyme."
|
forwardDescription: "Transférer le signalement vers une instance distante en tant qu'anonyme."
|
||||||
|
@ -2295,10 +2296,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Veuillez confirmer que le distributeur est fiable avant l'installation."
|
checkVendorBeforeInstall: "Veuillez confirmer que le distributeur est fiable avant l'installation."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Voulez-vous installer cette extension ?"
|
title: "Voulez-vous installer cette extension ?"
|
||||||
metaTitle: "Informations sur l'extension"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Voulez-vous installer ce thème ?"
|
title: "Voulez-vous installer ce thème ?"
|
||||||
metaTitle: "Informations sur le thème"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Palette de couleurs de base"
|
base: "Palette de couleurs de base"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -1262,6 +1262,7 @@ modified: "Diubah"
|
||||||
thereAreNChanges: "Ada {n} perubahan"
|
thereAreNChanges: "Ada {n} perubahan"
|
||||||
prohibitedWordsForNameOfUser: "Kata yang dilarang untuk nama pengguna"
|
prohibitedWordsForNameOfUser: "Kata yang dilarang untuk nama pengguna"
|
||||||
postForm: "Buat catatan"
|
postForm: "Buat catatan"
|
||||||
|
information: "Informasi"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
|
@ -2492,10 +2493,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Pastikan sumber dari sumber daya ini terpercaya sebelum melakukan pemasangan."
|
checkVendorBeforeInstall: "Pastikan sumber dari sumber daya ini terpercaya sebelum melakukan pemasangan."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Apakah kamu ingin memasang plugin ini?"
|
title: "Apakah kamu ingin memasang plugin ini?"
|
||||||
metaTitle: "Informasi plugin"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Apakah kamu ingin memasang tema ini?"
|
title: "Apakah kamu ingin memasang tema ini?"
|
||||||
metaTitle: "Informasi tema"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Skema warna dasar"
|
base: "Skema warna dasar"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -2818,6 +2818,10 @@ export interface Locale extends ILocale {
|
||||||
* コピー
|
* コピー
|
||||||
*/
|
*/
|
||||||
"copy": string;
|
"copy": string;
|
||||||
|
/**
|
||||||
|
* クリップボードにコピーされました
|
||||||
|
*/
|
||||||
|
"copiedToClipboard": string;
|
||||||
/**
|
/**
|
||||||
* メトリクス
|
* メトリクス
|
||||||
*/
|
*/
|
||||||
|
@ -5354,6 +5358,10 @@ export interface Locale extends ILocale {
|
||||||
* 文字数
|
* 文字数
|
||||||
*/
|
*/
|
||||||
"textCount": string;
|
"textCount": string;
|
||||||
|
/**
|
||||||
|
* 情報
|
||||||
|
*/
|
||||||
|
"information": string;
|
||||||
"_emojiPalette": {
|
"_emojiPalette": {
|
||||||
/**
|
/**
|
||||||
* パレット
|
* パレット
|
||||||
|
@ -10359,20 +10367,12 @@ export interface Locale extends ILocale {
|
||||||
* このプラグインをインストールしますか?
|
* このプラグインをインストールしますか?
|
||||||
*/
|
*/
|
||||||
"title": string;
|
"title": string;
|
||||||
/**
|
|
||||||
* プラグイン情報
|
|
||||||
*/
|
|
||||||
"metaTitle": string;
|
|
||||||
};
|
};
|
||||||
"_theme": {
|
"_theme": {
|
||||||
/**
|
/**
|
||||||
* このテーマをインストールしますか?
|
* このテーマをインストールしますか?
|
||||||
*/
|
*/
|
||||||
"title": string;
|
"title": string;
|
||||||
/**
|
|
||||||
* テーマ情報
|
|
||||||
*/
|
|
||||||
"metaTitle": string;
|
|
||||||
};
|
};
|
||||||
"_meta": {
|
"_meta": {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} ha Notato a riguardo di \"{word}\""
|
||||||
makeActive: "Attiva"
|
makeActive: "Attiva"
|
||||||
display: "Visualizza"
|
display: "Visualizza"
|
||||||
copy: "Copia"
|
copy: "Copia"
|
||||||
|
copiedToClipboard: "Copiato negli appunti"
|
||||||
metrics: "Statistiche"
|
metrics: "Statistiche"
|
||||||
overview: "Anteprima"
|
overview: "Anteprima"
|
||||||
logs: "Log"
|
logs: "Log"
|
||||||
|
@ -973,7 +974,7 @@ check: "Verifica"
|
||||||
driveCapOverrideLabel: "Modificare la capienza del Drive per questo profilo"
|
driveCapOverrideLabel: "Modificare la capienza del Drive per questo profilo"
|
||||||
driveCapOverrideCaption: "Se viene specificato meno di 0, viene annullato."
|
driveCapOverrideCaption: "Se viene specificato meno di 0, viene annullato."
|
||||||
requireAdminForView: "Per visualizzarli, è necessario aver effettuato l'accesso con un profilo amministratore."
|
requireAdminForView: "Per visualizzarli, è necessario aver effettuato l'accesso con un profilo amministratore."
|
||||||
isSystemAccount: "Questi profili vengono creati e gestiti automaticamente dal sistema"
|
isSystemAccount: "Si tratta di un profilo creato e gestito automaticamente dal sistema."
|
||||||
typeToConfirm: "Digita {x} per continuare"
|
typeToConfirm: "Digita {x} per continuare"
|
||||||
deleteAccount: "Eliminazione profilo"
|
deleteAccount: "Eliminazione profilo"
|
||||||
document: "Documentazione"
|
document: "Documentazione"
|
||||||
|
@ -1323,7 +1324,22 @@ untitled: "Senza titolo"
|
||||||
noName: "Senza nome"
|
noName: "Senza nome"
|
||||||
skip: "Salta"
|
skip: "Salta"
|
||||||
restore: "Ripristina"
|
restore: "Ripristina"
|
||||||
|
syncBetweenDevices: "Sincronizzazione tra i dispositivi"
|
||||||
|
preferenceSyncConflictTitle: "Sul server esiste già il valore impostato"
|
||||||
|
preferenceSyncConflictText: "Le impostazione sincronizzata salverà il valore sul server. Però, bada che esiste già un valore sul server. Quale vorresti sovrascrivere?"
|
||||||
|
preferenceSyncConflictChoiceServer: "Valore del server"
|
||||||
|
preferenceSyncConflictChoiceDevice: "Valore del dispositivo"
|
||||||
|
preferenceSyncConflictChoiceCancel: "Annulla la sincronizzazione"
|
||||||
|
paste: "Incolla"
|
||||||
|
emojiPalette: "Tavolozza emoji"
|
||||||
postForm: "Finestra di pubblicazione"
|
postForm: "Finestra di pubblicazione"
|
||||||
|
textCount: "Il numero di caratteri"
|
||||||
|
information: "Informazioni"
|
||||||
|
_emojiPalette:
|
||||||
|
palettes: "Tavolozza"
|
||||||
|
enableSyncBetweenDevicesForPalettes: "Attiva la sincronizzazione tra dispositivi"
|
||||||
|
paletteForMain: "Tavolozza principale"
|
||||||
|
paletteForReaction: "Tavolozza per reazioni"
|
||||||
_settings:
|
_settings:
|
||||||
driveBanner: "Permette di gestire e configurare il Drive, controllare il consumo di spazio e configurare il caricamento dei file."
|
driveBanner: "Permette di gestire e configurare il Drive, controllare il consumo di spazio e configurare il caricamento dei file."
|
||||||
pluginBanner: "Consentono di migliorare le funzionalità. Le estensioni si possono configurare e gestire singolarmente."
|
pluginBanner: "Consentono di migliorare le funzionalità. Le estensioni si possono configurare e gestire singolarmente."
|
||||||
|
@ -1341,6 +1357,9 @@ _settings:
|
||||||
preferencesBanner: "Puoi personalizzare il comportamento del tuo dispositivo."
|
preferencesBanner: "Puoi personalizzare il comportamento del tuo dispositivo."
|
||||||
appearanceBanner: "Puoi personalizzare l'aspetto nel dispositivo, in base alle tue preferenze."
|
appearanceBanner: "Puoi personalizzare l'aspetto nel dispositivo, in base alle tue preferenze."
|
||||||
soundsBanner: "Puoi personalizzare i suoni emessi dagli eventi sul tuo dispositivo."
|
soundsBanner: "Puoi personalizzare i suoni emessi dagli eventi sul tuo dispositivo."
|
||||||
|
timelineAndNote: "Note e Timeline"
|
||||||
|
makeEveryTextElementsSelectable: "Imposta ogni elemento come selezionabile"
|
||||||
|
makeEveryTextElementsSelectable_description: "Potrebbe ridurre l'usabilità in alcune situazioni."
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "Nome del profilo"
|
profileName: "Nome del profilo"
|
||||||
profileNameDescription: "Impostare il nome che indentifica questo dispositivo."
|
profileNameDescription: "Impostare il nome che indentifica questo dispositivo."
|
||||||
|
@ -2505,6 +2524,7 @@ _notification:
|
||||||
achievementEarned: "Risultato raggiunto"
|
achievementEarned: "Risultato raggiunto"
|
||||||
exportCompleted: "Esportazione completata"
|
exportCompleted: "Esportazione completata"
|
||||||
login: "Accessi"
|
login: "Accessi"
|
||||||
|
createToken: "Creare un token di accesso"
|
||||||
test: "Notifiche di test"
|
test: "Notifiche di test"
|
||||||
app: "Notifiche da applicazioni"
|
app: "Notifiche da applicazioni"
|
||||||
_actions:
|
_actions:
|
||||||
|
@ -2532,6 +2552,7 @@ _deck:
|
||||||
useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice"
|
useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice"
|
||||||
usedAsMinWidthWhenFlexible: "Se \"larghezza flessibile\" è abilitato, questa diventa la larghezza minima"
|
usedAsMinWidthWhenFlexible: "Se \"larghezza flessibile\" è abilitato, questa diventa la larghezza minima"
|
||||||
flexible: "Larghezza flessibile"
|
flexible: "Larghezza flessibile"
|
||||||
|
enableSyncBetweenDevicesForProfiles: "Abilita la sincronizzazione delle informazioni profilo tra dispositivi"
|
||||||
_columns:
|
_columns:
|
||||||
main: "Principale"
|
main: "Principale"
|
||||||
widgets: "Riquadri"
|
widgets: "Riquadri"
|
||||||
|
@ -2653,10 +2674,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Prima di installare, assicurati che la fonte sia affidabile."
|
checkVendorBeforeInstall: "Prima di installare, assicurati che la fonte sia affidabile."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Vuoi davvero installare questo componente aggiuntivo?"
|
title: "Vuoi davvero installare questo componente aggiuntivo?"
|
||||||
metaTitle: "Informazioni sul componente aggiuntivo"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Vuoi davvero installare questa variazione grafica?"
|
title: "Vuoi davvero installare questa variazione grafica?"
|
||||||
metaTitle: "Informazioni sulla variazione grafica"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Combinazione base di colori"
|
base: "Combinazione base di colori"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -700,6 +700,7 @@ userSaysSomethingAbout: "{name}が「{word}」について何かを言いまし
|
||||||
makeActive: "アクティブにする"
|
makeActive: "アクティブにする"
|
||||||
display: "表示"
|
display: "表示"
|
||||||
copy: "コピー"
|
copy: "コピー"
|
||||||
|
copiedToClipboard: "クリップボードにコピーされました"
|
||||||
metrics: "メトリクス"
|
metrics: "メトリクス"
|
||||||
overview: "概要"
|
overview: "概要"
|
||||||
logs: "ログ"
|
logs: "ログ"
|
||||||
|
@ -1334,6 +1335,7 @@ paste: "ペースト"
|
||||||
emojiPalette: "絵文字パレット"
|
emojiPalette: "絵文字パレット"
|
||||||
postForm: "投稿フォーム"
|
postForm: "投稿フォーム"
|
||||||
textCount: "文字数"
|
textCount: "文字数"
|
||||||
|
information: "情報"
|
||||||
|
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "パレット"
|
palettes: "パレット"
|
||||||
|
@ -2749,10 +2751,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "配布元が信頼できるかを確認した上でインストールしてください。"
|
checkVendorBeforeInstall: "配布元が信頼できるかを確認した上でインストールしてください。"
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "このプラグインをインストールしますか?"
|
title: "このプラグインをインストールしますか?"
|
||||||
metaTitle: "プラグイン情報"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "このテーマをインストールしますか?"
|
title: "このテーマをインストールしますか?"
|
||||||
metaTitle: "テーマ情報"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "基本のカラースキーム"
|
base: "基本のカラースキーム"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -1312,6 +1312,7 @@ federationDisabled: "このサーバーは連合が無効化されてるで。
|
||||||
confirmOnReact: "ツッコむときに確認とる"
|
confirmOnReact: "ツッコむときに確認とる"
|
||||||
reactAreYouSure: "\" {emoji} \" でツッコむ?"
|
reactAreYouSure: "\" {emoji} \" でツッコむ?"
|
||||||
postForm: "投稿フォーム"
|
postForm: "投稿フォーム"
|
||||||
|
information: "情報"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
|
@ -2610,10 +2611,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "配ってるとこが信頼できるか確認した上でインストールしてな。"
|
checkVendorBeforeInstall: "配ってるとこが信頼できるか確認した上でインストールしてな。"
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "このプラグイン、インストールする?"
|
title: "このプラグイン、インストールする?"
|
||||||
metaTitle: "プラグイン情報"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "このテーマインストールする?"
|
title: "このテーマインストールする?"
|
||||||
metaTitle: "テーマ情報"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: ""
|
base: ""
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -655,6 +655,7 @@ replies: "답하기"
|
||||||
renotes: "리노트"
|
renotes: "리노트"
|
||||||
attach: "옇기"
|
attach: "옇기"
|
||||||
surrender: "아이예"
|
surrender: "아이예"
|
||||||
|
information: "정보"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "고만 보내예"
|
stop: "고만 보내예"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1330,6 +1330,7 @@ preferenceSyncConflictChoiceDevice: "장치 설정값"
|
||||||
paste: "붙여넣기"
|
paste: "붙여넣기"
|
||||||
emojiPalette: "이모지 팔레트"
|
emojiPalette: "이모지 팔레트"
|
||||||
postForm: "글 입력란"
|
postForm: "글 입력란"
|
||||||
|
information: "정보"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "팔레트"
|
palettes: "팔레트"
|
||||||
paletteForMain: "메인으로 사용할 팔레트"
|
paletteForMain: "메인으로 사용할 팔레트"
|
||||||
|
@ -2650,10 +2651,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "제공자를 신뢰할 수 있는 경우에만 설치하십시오."
|
checkVendorBeforeInstall: "제공자를 신뢰할 수 있는 경우에만 설치하십시오."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "이 플러그인을 설치하시겠습니까?"
|
title: "이 플러그인을 설치하시겠습니까?"
|
||||||
metaTitle: "플러그인 정보"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "이 테마를 설치하시겠습니까?"
|
title: "이 테마를 설치하시겠습니까?"
|
||||||
metaTitle: "테마 정보"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "기본 컬러 스키마"
|
base: "기본 컬러 스키마"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -394,6 +394,7 @@ searchByGoogle: "ຄົ້ນຫາ"
|
||||||
file: "ໄຟລ໌"
|
file: "ໄຟລ໌"
|
||||||
replies: "ຕອບກັບ"
|
replies: "ຕອບກັບ"
|
||||||
renotes: "Renote"
|
renotes: "Renote"
|
||||||
|
information: "ກ່ຽວກັບ"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "ໂຈະ"
|
stop: "ໂຈະ"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -462,6 +462,7 @@ loggedInAsBot: "Momenteel als bot ingelogd"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "Antwoord"
|
replies: "Antwoord"
|
||||||
renotes: "Herdelen"
|
renotes: "Herdelen"
|
||||||
|
information: "Over"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Opgeschort"
|
stop: "Opgeschort"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -463,6 +463,7 @@ icon: "Avatar"
|
||||||
replies: "Svar"
|
replies: "Svar"
|
||||||
renotes: "Renote"
|
renotes: "Renote"
|
||||||
surrender: "Avbryt"
|
surrender: "Avbryt"
|
||||||
|
information: "Informasjon"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspendert"
|
stop: "Suspendert"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
|
|
|
@ -1045,6 +1045,7 @@ lastNDays: "W ciągu ostatnich {n} dni"
|
||||||
surrender: "Odrzuć"
|
surrender: "Odrzuć"
|
||||||
gameRetry: "Spróbuj ponownie"
|
gameRetry: "Spróbuj ponownie"
|
||||||
postForm: "Formularz tworzenia wpisu"
|
postForm: "Formularz tworzenia wpisu"
|
||||||
|
information: "Informacje"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Zawieszono"
|
stop: "Zawieszono"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1302,6 +1302,7 @@ pleaseSelectAccount: "Selecione uma conta"
|
||||||
availableRoles: "Cargos disponíveis"
|
availableRoles: "Cargos disponíveis"
|
||||||
acknowledgeNotesAndEnable: "Ative após compreender as precauções."
|
acknowledgeNotesAndEnable: "Ative após compreender as precauções."
|
||||||
postForm: "Campo de postagem"
|
postForm: "Campo de postagem"
|
||||||
|
information: "Informações"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
|
@ -2598,10 +2599,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "Tenha certeza de que o distribuidor desse recurso é confiável antes da instalação."
|
checkVendorBeforeInstall: "Tenha certeza de que o distribuidor desse recurso é confiável antes da instalação."
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "Deseja instalar esse plugin?"
|
title: "Deseja instalar esse plugin?"
|
||||||
metaTitle: "Informações do plugin"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "Deseja instalar esse tema?"
|
title: "Deseja instalar esse tema?"
|
||||||
metaTitle: "Informações do tema"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "Paleta de cores base"
|
base: "Paleta de cores base"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -646,6 +646,7 @@ show: "Arată"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "Răspunde"
|
replies: "Răspunde"
|
||||||
renotes: "Re-notează"
|
renotes: "Re-notează"
|
||||||
|
information: "Despre"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspendat"
|
stop: "Suspendat"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1182,6 +1182,7 @@ alwaysConfirmFollow: "Всегда подтверждать подписку"
|
||||||
inquiry: "Связаться"
|
inquiry: "Связаться"
|
||||||
messageToFollower: "Сообщение подписчикам"
|
messageToFollower: "Сообщение подписчикам"
|
||||||
postForm: "Форма отправки"
|
postForm: "Форма отправки"
|
||||||
|
information: "Описание"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Вебхук"
|
webhook: "Вебхук"
|
||||||
_delivery:
|
_delivery:
|
||||||
|
|
|
@ -918,6 +918,7 @@ sourceCode: "Zdrojový kód"
|
||||||
flip: "Preklopiť"
|
flip: "Preklopiť"
|
||||||
lastNDays: "Posledných {n} dní"
|
lastNDays: "Posledných {n} dní"
|
||||||
postForm: "Napísať poznámku"
|
postForm: "Napísať poznámku"
|
||||||
|
information: "Informácie"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Zmrazené"
|
stop: "Zmrazené"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -562,6 +562,7 @@ inquiry: "Kontakt"
|
||||||
tryAgain: "Försök igen senare"
|
tryAgain: "Försök igen senare"
|
||||||
signinWithPasskey: "Logga in med nyckel"
|
signinWithPasskey: "Logga in med nyckel"
|
||||||
unknownWebAuthnKey: "Okänd nyckel"
|
unknownWebAuthnKey: "Okänd nyckel"
|
||||||
|
information: "Om"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspenderad"
|
stop: "Suspenderad"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1293,6 +1293,7 @@ prohibitedWordsForNameOfUserDescription: "หากมีสตริงใด
|
||||||
yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม"
|
yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม"
|
||||||
yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ"
|
yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ"
|
||||||
postForm: "แบบฟอร์มการโพสต์"
|
postForm: "แบบฟอร์มการโพสต์"
|
||||||
|
information: "เกี่ยวกับ"
|
||||||
_settings:
|
_settings:
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
|
@ -2572,10 +2573,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "โปรดตรวจสอบให้แน่ใจว่าแหล่งแจกหน่ายมีความน่าเชื่อถือก่อนทำการติดตั้ง"
|
checkVendorBeforeInstall: "โปรดตรวจสอบให้แน่ใจว่าแหล่งแจกหน่ายมีความน่าเชื่อถือก่อนทำการติดตั้ง"
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "ต้องการติดตั้งปลั๊กอินนี้ใช่ไหม?"
|
title: "ต้องการติดตั้งปลั๊กอินนี้ใช่ไหม?"
|
||||||
metaTitle: "ข้อมูลส่วนเสริม"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "ต้องการติดตั้งธีมนี้ใช่ไหม?"
|
title: "ต้องการติดตั้งธีมนี้ใช่ไหม?"
|
||||||
metaTitle: "ข้อมูลธีม"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "โทนสีพื้นฐาน"
|
base: "โทนสีพื้นฐาน"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -910,6 +910,7 @@ sourceCode: "Вихідний код"
|
||||||
flip: "Перевернути"
|
flip: "Перевернути"
|
||||||
lastNDays: "Останні {n} днів"
|
lastNDays: "Останні {n} днів"
|
||||||
postForm: "Створення нотатки"
|
postForm: "Створення нотатки"
|
||||||
|
information: "Інформація"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Призупинено"
|
stop: "Призупинено"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -841,6 +841,7 @@ icon: "Avatar"
|
||||||
replies: "Javob berish"
|
replies: "Javob berish"
|
||||||
renotes: "Qayta qayd etish"
|
renotes: "Qayta qayd etish"
|
||||||
flip: "Teskari"
|
flip: "Teskari"
|
||||||
|
information: "Haqida"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "To'xtatilgan"
|
stop: "To'xtatilgan"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -1120,6 +1120,7 @@ cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải
|
||||||
lastNDays: "{n} ngày trước"
|
lastNDays: "{n} ngày trước"
|
||||||
surrender: "Từ chối"
|
surrender: "Từ chối"
|
||||||
postForm: "Mẫu đăng"
|
postForm: "Mẫu đăng"
|
||||||
|
information: "Giới thiệu"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Đã vô hiệu hóa"
|
stop: "Đã vô hiệu hóa"
|
||||||
_type:
|
_type:
|
||||||
|
|
|
@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} 说了关于「{word}」的什么"
|
||||||
makeActive: "启用"
|
makeActive: "启用"
|
||||||
display: "显示"
|
display: "显示"
|
||||||
copy: "复制"
|
copy: "复制"
|
||||||
|
copiedToClipboard: "已复制到剪贴板"
|
||||||
metrics: "指标"
|
metrics: "指标"
|
||||||
overview: "概览"
|
overview: "概览"
|
||||||
logs: "日志"
|
logs: "日志"
|
||||||
|
@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "取消同步"
|
||||||
paste: "粘贴"
|
paste: "粘贴"
|
||||||
emojiPalette: "表情符号调色板"
|
emojiPalette: "表情符号调色板"
|
||||||
postForm: "投稿窗口"
|
postForm: "投稿窗口"
|
||||||
|
textCount: "字数"
|
||||||
|
information: "关于"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "调色板"
|
palettes: "调色板"
|
||||||
enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步"
|
enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步"
|
||||||
|
@ -2671,10 +2674,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "请在安装前确保来源可靠"
|
checkVendorBeforeInstall: "请在安装前确保来源可靠"
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "要安装此插件吗?"
|
title: "要安装此插件吗?"
|
||||||
metaTitle: "插件信息"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "要安装此主题吗?"
|
title: "要安装此主题吗?"
|
||||||
metaTitle: "主题信息"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "基本配色方案"
|
base: "基本配色方案"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name} 說了一些關於「{word}」的話"
|
||||||
makeActive: "啟用"
|
makeActive: "啟用"
|
||||||
display: "檢視"
|
display: "檢視"
|
||||||
copy: "複製"
|
copy: "複製"
|
||||||
|
copiedToClipboard: "已複製到剪貼簿"
|
||||||
metrics: "指標"
|
metrics: "指標"
|
||||||
overview: "概覽"
|
overview: "概覽"
|
||||||
logs: "日誌"
|
logs: "日誌"
|
||||||
|
@ -1332,6 +1333,8 @@ preferenceSyncConflictChoiceCancel: "取消啟用同步"
|
||||||
paste: "貼上"
|
paste: "貼上"
|
||||||
emojiPalette: "表情符號調色盤"
|
emojiPalette: "表情符號調色盤"
|
||||||
postForm: "發文視窗"
|
postForm: "發文視窗"
|
||||||
|
textCount: "字數"
|
||||||
|
information: "關於"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "調色盤"
|
palettes: "調色盤"
|
||||||
enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化"
|
enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化"
|
||||||
|
@ -1355,6 +1358,8 @@ _settings:
|
||||||
appearanceBanner: "您可以根據喜好設定與用戶端外觀和顯示方式相關的設定。"
|
appearanceBanner: "您可以根據喜好設定與用戶端外觀和顯示方式相關的設定。"
|
||||||
soundsBanner: "您可以調整用戶端播放的聲音設定。"
|
soundsBanner: "您可以調整用戶端播放的聲音設定。"
|
||||||
timelineAndNote: "時間軸及貼文"
|
timelineAndNote: "時間軸及貼文"
|
||||||
|
makeEveryTextElementsSelectable: "允許選取所有文字"
|
||||||
|
makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。"
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "設定檔案名稱"
|
profileName: "設定檔案名稱"
|
||||||
profileNameDescription: "設定一個名稱來識別此裝置。"
|
profileNameDescription: "設定一個名稱來識別此裝置。"
|
||||||
|
@ -2519,6 +2524,7 @@ _notification:
|
||||||
achievementEarned: "獲得成就"
|
achievementEarned: "獲得成就"
|
||||||
exportCompleted: "已完成匯出。"
|
exportCompleted: "已完成匯出。"
|
||||||
login: "登入"
|
login: "登入"
|
||||||
|
createToken: "建立存取權杖"
|
||||||
test: "通知測試"
|
test: "通知測試"
|
||||||
app: "應用程式通知"
|
app: "應用程式通知"
|
||||||
_actions:
|
_actions:
|
||||||
|
@ -2668,10 +2674,8 @@ _externalResourceInstaller:
|
||||||
checkVendorBeforeInstall: "安裝前請確認提供者是可信賴的。"
|
checkVendorBeforeInstall: "安裝前請確認提供者是可信賴的。"
|
||||||
_plugin:
|
_plugin:
|
||||||
title: "要安裝此外掛嘛?"
|
title: "要安裝此外掛嘛?"
|
||||||
metaTitle: "外掛資訊"
|
|
||||||
_theme:
|
_theme:
|
||||||
title: "要安裝此佈景主題嗎?"
|
title: "要安裝此佈景主題嗎?"
|
||||||
metaTitle: "佈景主題資訊"
|
|
||||||
_meta:
|
_meta:
|
||||||
base: "基本配色方案"
|
base: "基本配色方案"
|
||||||
_vendorInfo:
|
_vendorInfo:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.3.2-beta.1",
|
"version": "2025.3.2-beta.6",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -7,42 +7,16 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
||||||
import { AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { type AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { type Packed } from '@/misc/json-schema.js';
|
||||||
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
|
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||||
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||||
|
|
||||||
const oneDayMillis = 24 * 60 * 60 * 1000;
|
const oneDayMillis = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseReportPayload {
|
|
||||||
const result: MiAbuseUserReport = {
|
|
||||||
id: 'dummy-abuse-report1',
|
|
||||||
targetUserId: 'dummy-target-user',
|
|
||||||
targetUser: null,
|
|
||||||
reporterId: 'dummy-reporter-user',
|
|
||||||
reporter: null,
|
|
||||||
assigneeId: null,
|
|
||||||
assignee: null,
|
|
||||||
resolved: false,
|
|
||||||
forwarded: false,
|
|
||||||
comment: 'This is a dummy report for testing purposes.',
|
|
||||||
targetUserHost: null,
|
|
||||||
reporterHost: null,
|
|
||||||
resolvedAs: null,
|
|
||||||
moderationNote: 'foo',
|
|
||||||
...override,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...result,
|
|
||||||
targetUser: result.targetUser ? toPackedUserLite(result.targetUser) : null,
|
|
||||||
reporter: result.reporter ? toPackedUserLite(result.reporter) : null,
|
|
||||||
assignee: result.assignee ? toPackedUserLite(result.assignee) : null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
||||||
return {
|
return {
|
||||||
id: 'dummy-user-1',
|
id: 'dummy-user-1',
|
||||||
|
@ -134,124 +108,6 @@ function generateDummyNote(override?: Partial<MiNote>): MiNote {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPackedNote(note: MiNote, detail = true, override?: Packed<'Note'>): Packed<'Note'> {
|
|
||||||
return {
|
|
||||||
id: note.id,
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
deletedAt: null,
|
|
||||||
text: note.text,
|
|
||||||
cw: note.cw,
|
|
||||||
userId: note.userId,
|
|
||||||
user: toPackedUserLite(note.user ?? generateDummyUser()),
|
|
||||||
replyId: note.replyId,
|
|
||||||
renoteId: note.renoteId,
|
|
||||||
isHidden: false,
|
|
||||||
visibility: note.visibility,
|
|
||||||
mentions: note.mentions,
|
|
||||||
visibleUserIds: note.visibleUserIds,
|
|
||||||
fileIds: note.fileIds,
|
|
||||||
files: [],
|
|
||||||
tags: note.tags,
|
|
||||||
poll: null,
|
|
||||||
emojis: note.emojis,
|
|
||||||
channelId: note.channelId,
|
|
||||||
channel: note.channel,
|
|
||||||
localOnly: note.localOnly,
|
|
||||||
reactionAcceptance: note.reactionAcceptance,
|
|
||||||
reactionEmojis: {},
|
|
||||||
reactions: {},
|
|
||||||
reactionCount: 0,
|
|
||||||
renoteCount: note.renoteCount,
|
|
||||||
repliesCount: note.repliesCount,
|
|
||||||
uri: note.uri ?? undefined,
|
|
||||||
url: note.url ?? undefined,
|
|
||||||
reactionAndUserPairCache: note.reactionAndUserPairCache,
|
|
||||||
...(detail ? {
|
|
||||||
clippedCount: note.clippedCount,
|
|
||||||
reply: note.reply ? toPackedNote(note.reply, false) : null,
|
|
||||||
renote: note.renote ? toPackedNote(note.renote, true) : null,
|
|
||||||
myReaction: null,
|
|
||||||
} : {}),
|
|
||||||
...override,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function toPackedUserLite(user: MiUser, override?: Packed<'UserLite'>): Packed<'UserLite'> {
|
|
||||||
return {
|
|
||||||
id: user.id,
|
|
||||||
name: user.name,
|
|
||||||
username: user.username,
|
|
||||||
host: user.host,
|
|
||||||
avatarUrl: user.avatarUrl,
|
|
||||||
avatarBlurhash: user.avatarBlurhash,
|
|
||||||
avatarDecorations: user.avatarDecorations.map(it => ({
|
|
||||||
id: it.id,
|
|
||||||
angle: it.angle,
|
|
||||||
flipH: it.flipH,
|
|
||||||
url: 'https://example.com/dummy-image001.png',
|
|
||||||
offsetX: it.offsetX,
|
|
||||||
offsetY: it.offsetY,
|
|
||||||
})),
|
|
||||||
isBot: user.isBot,
|
|
||||||
isCat: user.isCat,
|
|
||||||
emojis: user.emojis,
|
|
||||||
onlineStatus: 'active',
|
|
||||||
badgeRoles: [],
|
|
||||||
...override,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function toPackedUserDetailedNotMe(user: MiUser, override?: Packed<'UserDetailedNotMe'>): Packed<'UserDetailedNotMe'> {
|
|
||||||
return {
|
|
||||||
...toPackedUserLite(user),
|
|
||||||
url: null,
|
|
||||||
uri: null,
|
|
||||||
movedTo: null,
|
|
||||||
alsoKnownAs: [],
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
updatedAt: user.updatedAt?.toISOString() ?? null,
|
|
||||||
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
|
|
||||||
bannerUrl: user.bannerUrl,
|
|
||||||
bannerBlurhash: user.bannerBlurhash,
|
|
||||||
isLocked: user.isLocked,
|
|
||||||
isSilenced: false,
|
|
||||||
isSuspended: user.isSuspended,
|
|
||||||
description: null,
|
|
||||||
location: null,
|
|
||||||
birthday: null,
|
|
||||||
lang: null,
|
|
||||||
fields: [],
|
|
||||||
verifiedLinks: [],
|
|
||||||
followersCount: user.followersCount,
|
|
||||||
followingCount: user.followingCount,
|
|
||||||
notesCount: user.notesCount,
|
|
||||||
pinnedNoteIds: [],
|
|
||||||
pinnedNotes: [],
|
|
||||||
pinnedPageId: null,
|
|
||||||
pinnedPage: null,
|
|
||||||
publicReactions: true,
|
|
||||||
followersVisibility: 'public',
|
|
||||||
followingVisibility: 'public',
|
|
||||||
twoFactorEnabled: false,
|
|
||||||
usePasswordLessLogin: false,
|
|
||||||
securityKeys: false,
|
|
||||||
roles: [],
|
|
||||||
memo: null,
|
|
||||||
moderationNote: undefined,
|
|
||||||
isFollowing: false,
|
|
||||||
isFollowed: false,
|
|
||||||
hasPendingFollowRequestFromYou: false,
|
|
||||||
hasPendingFollowRequestToYou: false,
|
|
||||||
isBlocking: false,
|
|
||||||
isBlocked: false,
|
|
||||||
isMuted: false,
|
|
||||||
isRenoteMuted: false,
|
|
||||||
notify: 'none',
|
|
||||||
withReplies: true,
|
|
||||||
...override,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const dummyUser1 = generateDummyUser();
|
const dummyUser1 = generateDummyUser();
|
||||||
const dummyUser2 = generateDummyUser({
|
const dummyUser2 = generateDummyUser({
|
||||||
id: 'dummy-user-2',
|
id: 'dummy-user-2',
|
||||||
|
@ -284,6 +140,7 @@ export class WebhookTestService {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private customEmojiService: CustomEmojiService,
|
||||||
private userWebhookService: UserWebhookService,
|
private userWebhookService: UserWebhookService,
|
||||||
private systemWebhookService: SystemWebhookService,
|
private systemWebhookService: SystemWebhookService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
|
@ -354,31 +211,31 @@ export class WebhookTestService {
|
||||||
|
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'note': {
|
case 'note': {
|
||||||
send('note', { note: toPackedNote(dummyNote1) });
|
send('note', { note: await this.toPackedNote(dummyNote1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'reply': {
|
case 'reply': {
|
||||||
send('reply', { note: toPackedNote(dummyReply1) });
|
send('reply', { note: await this.toPackedNote(dummyReply1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'renote': {
|
case 'renote': {
|
||||||
send('renote', { note: toPackedNote(dummyRenote1) });
|
send('renote', { note: await this.toPackedNote(dummyRenote1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'mention': {
|
case 'mention': {
|
||||||
send('mention', { note: toPackedNote(dummyMention1) });
|
send('mention', { note: await this.toPackedNote(dummyMention1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'follow': {
|
case 'follow': {
|
||||||
send('follow', { user: toPackedUserDetailedNotMe(dummyUser1) });
|
send('follow', { user: await this.toPackedUserDetailedNotMe(dummyUser1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'followed': {
|
case 'followed': {
|
||||||
send('followed', { user: toPackedUserLite(dummyUser2) });
|
send('followed', { user: await this.toPackedUserLite(dummyUser2) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'unfollow': {
|
case 'unfollow': {
|
||||||
send('unfollow', { user: toPackedUserDetailedNotMe(dummyUser3) });
|
send('unfollow', { user: await this.toPackedUserDetailedNotMe(dummyUser3) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// まだ実装されていない (#9485)
|
// まだ実装されていない (#9485)
|
||||||
|
@ -427,7 +284,7 @@ export class WebhookTestService {
|
||||||
|
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'abuseReport': {
|
case 'abuseReport': {
|
||||||
send('abuseReport', generateAbuseReport({
|
send('abuseReport', await this.generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -436,7 +293,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'abuseReportResolved': {
|
case 'abuseReportResolved': {
|
||||||
send('abuseReportResolved', generateAbuseReport({
|
send('abuseReportResolved', await this.generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -448,7 +305,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'userCreated': {
|
case 'userCreated': {
|
||||||
send('userCreated', toPackedUserLite(dummyUser1));
|
send('userCreated', await this.toPackedUserLite(dummyUser1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inactiveModeratorsWarning': {
|
case 'inactiveModeratorsWarning': {
|
||||||
|
@ -474,4 +331,153 @@ export class WebhookTestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async generateAbuseReport(override?: Partial<MiAbuseUserReport>): Promise<AbuseReportPayload> {
|
||||||
|
const result: MiAbuseUserReport = {
|
||||||
|
id: 'dummy-abuse-report1',
|
||||||
|
targetUserId: 'dummy-target-user',
|
||||||
|
targetUser: null,
|
||||||
|
reporterId: 'dummy-reporter-user',
|
||||||
|
reporter: null,
|
||||||
|
assigneeId: null,
|
||||||
|
assignee: null,
|
||||||
|
resolved: false,
|
||||||
|
forwarded: false,
|
||||||
|
comment: 'This is a dummy report for testing purposes.',
|
||||||
|
targetUserHost: null,
|
||||||
|
reporterHost: null,
|
||||||
|
resolvedAs: null,
|
||||||
|
moderationNote: 'foo',
|
||||||
|
...override,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
targetUser: result.targetUser ? await this.toPackedUserLite(result.targetUser) : null,
|
||||||
|
reporter: result.reporter ? await this.toPackedUserLite(result.reporter) : null,
|
||||||
|
assignee: result.assignee ? await this.toPackedUserLite(result.assignee) : null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async toPackedNote(note: MiNote, detail = true, override?: Packed<'Note'>): Promise<Packed<'Note'>> {
|
||||||
|
return {
|
||||||
|
id: note.id,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
deletedAt: null,
|
||||||
|
text: note.text,
|
||||||
|
cw: note.cw,
|
||||||
|
userId: note.userId,
|
||||||
|
user: await this.toPackedUserLite(note.user ?? generateDummyUser()),
|
||||||
|
replyId: note.replyId,
|
||||||
|
renoteId: note.renoteId,
|
||||||
|
isHidden: false,
|
||||||
|
visibility: note.visibility,
|
||||||
|
mentions: note.mentions,
|
||||||
|
visibleUserIds: note.visibleUserIds,
|
||||||
|
fileIds: note.fileIds,
|
||||||
|
files: [],
|
||||||
|
tags: note.tags,
|
||||||
|
poll: null,
|
||||||
|
emojis: await this.customEmojiService.populateEmojis(note.emojis, note.userHost),
|
||||||
|
channelId: note.channelId,
|
||||||
|
channel: note.channel,
|
||||||
|
localOnly: note.localOnly,
|
||||||
|
reactionAcceptance: note.reactionAcceptance,
|
||||||
|
reactionEmojis: {},
|
||||||
|
reactions: {},
|
||||||
|
reactionCount: 0,
|
||||||
|
renoteCount: note.renoteCount,
|
||||||
|
repliesCount: note.repliesCount,
|
||||||
|
uri: note.uri ?? undefined,
|
||||||
|
url: note.url ?? undefined,
|
||||||
|
reactionAndUserPairCache: note.reactionAndUserPairCache,
|
||||||
|
...(detail ? {
|
||||||
|
clippedCount: note.clippedCount,
|
||||||
|
reply: note.reply ? await this.toPackedNote(note.reply, false) : null,
|
||||||
|
renote: note.renote ? await this.toPackedNote(note.renote, true) : null,
|
||||||
|
myReaction: null,
|
||||||
|
} : {}),
|
||||||
|
...override,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async toPackedUserLite(user: MiUser, override?: Packed<'UserLite'>): Promise<Packed<'UserLite'>> {
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
username: user.username,
|
||||||
|
host: user.host,
|
||||||
|
avatarUrl: user.avatarUrl,
|
||||||
|
avatarBlurhash: user.avatarBlurhash,
|
||||||
|
avatarDecorations: user.avatarDecorations.map(it => ({
|
||||||
|
id: it.id,
|
||||||
|
angle: it.angle,
|
||||||
|
flipH: it.flipH,
|
||||||
|
url: 'https://example.com/dummy-image001.png',
|
||||||
|
offsetX: it.offsetX,
|
||||||
|
offsetY: it.offsetY,
|
||||||
|
})),
|
||||||
|
isBot: user.isBot,
|
||||||
|
isCat: user.isCat,
|
||||||
|
emojis: await this.customEmojiService.populateEmojis(user.emojis, user.host),
|
||||||
|
onlineStatus: 'active',
|
||||||
|
badgeRoles: [],
|
||||||
|
...override,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async toPackedUserDetailedNotMe(user: MiUser, override?: Packed<'UserDetailedNotMe'>): Promise<Packed<'UserDetailedNotMe'>> {
|
||||||
|
return {
|
||||||
|
...await this.toPackedUserLite(user),
|
||||||
|
url: null,
|
||||||
|
uri: null,
|
||||||
|
movedTo: null,
|
||||||
|
alsoKnownAs: [],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
updatedAt: user.updatedAt?.toISOString() ?? null,
|
||||||
|
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
|
||||||
|
bannerUrl: user.bannerUrl,
|
||||||
|
bannerBlurhash: user.bannerBlurhash,
|
||||||
|
isLocked: user.isLocked,
|
||||||
|
isSilenced: false,
|
||||||
|
isSuspended: user.isSuspended,
|
||||||
|
description: null,
|
||||||
|
location: null,
|
||||||
|
birthday: null,
|
||||||
|
lang: null,
|
||||||
|
fields: [],
|
||||||
|
verifiedLinks: [],
|
||||||
|
followersCount: user.followersCount,
|
||||||
|
followingCount: user.followingCount,
|
||||||
|
notesCount: user.notesCount,
|
||||||
|
pinnedNoteIds: [],
|
||||||
|
pinnedNotes: [],
|
||||||
|
pinnedPageId: null,
|
||||||
|
pinnedPage: null,
|
||||||
|
publicReactions: true,
|
||||||
|
followersVisibility: 'public',
|
||||||
|
followingVisibility: 'public',
|
||||||
|
twoFactorEnabled: false,
|
||||||
|
usePasswordLessLogin: false,
|
||||||
|
securityKeys: false,
|
||||||
|
roles: [],
|
||||||
|
memo: null,
|
||||||
|
moderationNote: undefined,
|
||||||
|
isFollowing: false,
|
||||||
|
isFollowed: false,
|
||||||
|
hasPendingFollowRequestFromYou: false,
|
||||||
|
hasPendingFollowRequestToYou: false,
|
||||||
|
isBlocking: false,
|
||||||
|
isBlocked: false,
|
||||||
|
isMuted: false,
|
||||||
|
isRenoteMuted: false,
|
||||||
|
notify: 'none',
|
||||||
|
withReplies: true,
|
||||||
|
...override,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,7 @@ export interface Schema extends OfSchema {
|
||||||
readonly maximum?: number;
|
readonly maximum?: number;
|
||||||
readonly minimum?: number;
|
readonly minimum?: number;
|
||||||
readonly pattern?: string;
|
readonly pattern?: string;
|
||||||
|
readonly additionalProperties?: Schema | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequiredPropertyNames<s extends Obj> = {
|
type RequiredPropertyNames<s extends Obj> = {
|
||||||
|
@ -217,6 +218,13 @@ type ObjectSchemaTypeDef<p extends Schema> =
|
||||||
:
|
:
|
||||||
p['anyOf'] extends ReadonlyArray<Schema> ? never : // see CONTRIBUTING.md
|
p['anyOf'] extends ReadonlyArray<Schema> ? never : // see CONTRIBUTING.md
|
||||||
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
||||||
|
p['additionalProperties'] extends true ? Record<string, any> :
|
||||||
|
p['additionalProperties'] extends Schema ?
|
||||||
|
p['additionalProperties'] extends infer AdditionalProperties ?
|
||||||
|
AdditionalProperties extends Schema ?
|
||||||
|
Record<string, SchemaType<AdditionalProperties>> :
|
||||||
|
never :
|
||||||
|
never :
|
||||||
any;
|
any;
|
||||||
|
|
||||||
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
|
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ZipReader } from 'slacc';
|
import { ZipReader } from 'slacc';
|
||||||
|
import { IsNull } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { EmojisRepository, DriveFilesRepository } from '@/models/_.js';
|
import type { EmojisRepository, DriveFilesRepository } from '@/models/_.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
@ -86,6 +87,7 @@ export class ImportCustomEmojisProcessorService {
|
||||||
const emojiPath = outputPath + '/' + record.fileName;
|
const emojiPath = outputPath + '/' + record.fileName;
|
||||||
await this.emojisRepository.delete({
|
await this.emojisRepository.delete({
|
||||||
name: emojiInfo.name,
|
name: emojiInfo.name,
|
||||||
|
host: IsNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import accepts from 'accepts';
|
||||||
import vary from 'vary';
|
import vary from 'vary';
|
||||||
import secureJson from 'secure-json-parse';
|
import secureJson from 'secure-json-parse';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js';
|
import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js';
|
||||||
import * as url from '@/misc/prelude/url.js';
|
import * as url from '@/misc/prelude/url.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
|
@ -42,6 +42,9 @@ export class ActivityPubServerService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.meta)
|
||||||
|
private meta: MiMeta,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@ -102,6 +105,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private inbox(request: FastifyRequest, reply: FastifyReply) {
|
private inbox(request: FastifyRequest, reply: FastifyReply) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let signature;
|
let signature;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -173,6 +181,11 @@ export class ActivityPubServerService {
|
||||||
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
||||||
reply: FastifyReply,
|
reply: FastifyReply,
|
||||||
) {
|
) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const cursor = request.query.cursor;
|
const cursor = request.query.cursor;
|
||||||
|
@ -265,6 +278,11 @@ export class ActivityPubServerService {
|
||||||
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
||||||
reply: FastifyReply,
|
reply: FastifyReply,
|
||||||
) {
|
) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const cursor = request.query.cursor;
|
const cursor = request.query.cursor;
|
||||||
|
@ -354,6 +372,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) {
|
private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
|
@ -398,6 +421,11 @@ export class ActivityPubServerService {
|
||||||
}>,
|
}>,
|
||||||
reply: FastifyReply,
|
reply: FastifyReply,
|
||||||
) {
|
) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const sinceId = request.query.since_id;
|
const sinceId = request.query.since_id;
|
||||||
|
@ -482,6 +510,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) {
|
private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
reply.code(404);
|
reply.code(404);
|
||||||
return;
|
return;
|
||||||
|
@ -564,6 +597,11 @@ export class ActivityPubServerService {
|
||||||
fastify.get<{ Params: { note: string; } }>('/notes/:note', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
fastify.get<{ Params: { note: string; } }>('/notes/:note', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||||
vary(reply.raw, 'Accept');
|
vary(reply.raw, 'Accept');
|
||||||
|
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const note = await this.notesRepository.findOneBy({
|
const note = await this.notesRepository.findOneBy({
|
||||||
id: request.params.note,
|
id: request.params.note,
|
||||||
visibility: In(['public', 'home']),
|
visibility: In(['public', 'home']),
|
||||||
|
@ -594,6 +632,11 @@ export class ActivityPubServerService {
|
||||||
fastify.get<{ Params: { note: string; } }>('/notes/:note/activity', async (request, reply) => {
|
fastify.get<{ Params: { note: string; } }>('/notes/:note/activity', async (request, reply) => {
|
||||||
vary(reply.raw, 'Accept');
|
vary(reply.raw, 'Accept');
|
||||||
|
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const note = await this.notesRepository.findOneBy({
|
const note = await this.notesRepository.findOneBy({
|
||||||
id: request.params.note,
|
id: request.params.note,
|
||||||
userHost: IsNull(),
|
userHost: IsNull(),
|
||||||
|
@ -634,6 +677,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
// publickey
|
// publickey
|
||||||
fastify.get<{ Params: { user: string; } }>('/users/:user/publickey', async (request, reply) => {
|
fastify.get<{ Params: { user: string; } }>('/users/:user/publickey', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
|
@ -661,6 +709,11 @@ export class ActivityPubServerService {
|
||||||
fastify.get<{ Params: { user: string; } }>('/users/:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
fastify.get<{ Params: { user: string; } }>('/users/:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||||
vary(reply.raw, 'Accept');
|
vary(reply.raw, 'Accept');
|
||||||
|
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
|
@ -674,6 +727,11 @@ export class ActivityPubServerService {
|
||||||
fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||||
vary(reply.raw, 'Accept');
|
vary(reply.raw, 'Accept');
|
||||||
|
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const acct = Acct.parse(request.params.acct);
|
const acct = Acct.parse(request.params.acct);
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
|
@ -688,6 +746,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
// emoji
|
// emoji
|
||||||
fastify.get<{ Params: { emoji: string; } }>('/emojis/:emoji', async (request, reply) => {
|
fastify.get<{ Params: { emoji: string; } }>('/emojis/:emoji', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const emoji = await this.emojisRepository.findOneBy({
|
const emoji = await this.emojisRepository.findOneBy({
|
||||||
host: IsNull(),
|
host: IsNull(),
|
||||||
name: request.params.emoji,
|
name: request.params.emoji,
|
||||||
|
@ -705,6 +768,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
// like
|
// like
|
||||||
fastify.get<{ Params: { like: string; } }>('/likes/:like', async (request, reply) => {
|
fastify.get<{ Params: { like: string; } }>('/likes/:like', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const reaction = await this.noteReactionsRepository.findOneBy({ id: request.params.like });
|
const reaction = await this.noteReactionsRepository.findOneBy({ id: request.params.like });
|
||||||
|
|
||||||
if (reaction == null) {
|
if (reaction == null) {
|
||||||
|
@ -726,6 +794,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
// follow
|
// follow
|
||||||
fastify.get<{ Params: { follower: string; followee: string; } }>('/follows/:follower/:followee', async (request, reply) => {
|
fastify.get<{ Params: { follower: string; followee: string; } }>('/follows/:follower/:followee', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This may be used before the follow is completed, so we do not
|
// This may be used before the follow is completed, so we do not
|
||||||
// check if the following exists.
|
// check if the following exists.
|
||||||
|
|
||||||
|
@ -752,6 +825,11 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
// follow
|
// follow
|
||||||
fastify.get<{ Params: { followRequestId: string; } }>('/follows/:followRequestId', async (request, reply) => {
|
fastify.get<{ Params: { followRequestId: string; } }>('/follows/:followRequestId', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This may be used before the follow is completed, so we do not
|
// This may be used before the follow is completed, so we do not
|
||||||
// check if the following exists and only check if the follow request exists.
|
// check if the following exists and only check if the follow request exists.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { IsNull } from 'typeorm';
|
||||||
import vary from 'vary';
|
import vary from 'vary';
|
||||||
import fastifyAccepts from '@fastify/accepts';
|
import fastifyAccepts from '@fastify/accepts';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository } from '@/models/_.js';
|
import type { MiMeta, UsersRepository } from '@/models/_.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js';
|
import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
|
@ -26,6 +26,9 @@ export class WellKnownServerService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.meta)
|
||||||
|
private meta: MiMeta,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@ -66,6 +69,11 @@ export class WellKnownServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get('/.well-known/host-meta', async (request, reply) => {
|
fastify.get('/.well-known/host-meta', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reply.header('Content-Type', xrd);
|
reply.header('Content-Type', xrd);
|
||||||
return XRD({ element: 'Link', attributes: {
|
return XRD({ element: 'Link', attributes: {
|
||||||
rel: 'lrdd',
|
rel: 'lrdd',
|
||||||
|
@ -75,6 +83,11 @@ export class WellKnownServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get('/.well-known/host-meta.json', async (request, reply) => {
|
fastify.get('/.well-known/host-meta.json', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reply.header('Content-Type', 'application/json');
|
reply.header('Content-Type', 'application/json');
|
||||||
return {
|
return {
|
||||||
links: [{
|
links: [{
|
||||||
|
@ -86,6 +99,11 @@ export class WellKnownServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get('/.well-known/nodeinfo', async (request, reply) => {
|
fastify.get('/.well-known/nodeinfo', async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return { links: this.nodeinfoServerService.getLinks() };
|
return { links: this.nodeinfoServerService.getLinks() };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,6 +117,11 @@ fastify.get('/.well-known/change-password', async (request, reply) => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fastify.get<{ Querystring: { resource: string } }>(webFingerPath, async (request, reply) => {
|
fastify.get<{ Querystring: { resource: string } }>(webFingerPath, async (request, reply) => {
|
||||||
|
if (this.meta.federation === 'none') {
|
||||||
|
reply.code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const fromId = (id: MiUser['id']): FindOptionsWhere<MiUser> => ({
|
const fromId = (id: MiUser['id']): FindOptionsWhere<MiUser> => ({
|
||||||
id,
|
id,
|
||||||
host: IsNull(),
|
host: IsNull(),
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersReposi
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
|
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||||
|
|
||||||
describe('WebhookTestService', () => {
|
describe('WebhookTestService', () => {
|
||||||
let app: TestingModule;
|
let app: TestingModule;
|
||||||
|
@ -56,6 +57,11 @@ describe('WebhookTestService', () => {
|
||||||
providers: [
|
providers: [
|
||||||
WebhookTestService,
|
WebhookTestService,
|
||||||
IdService,
|
IdService,
|
||||||
|
{
|
||||||
|
provide: CustomEmojiService, useFactory: () => ({
|
||||||
|
populateEmojis: jest.fn(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: QueueService, useFactory: () => ({
|
provide: QueueService, useFactory: () => ({
|
||||||
systemWebhookDeliver: jest.fn(),
|
systemWebhookDeliver: jest.fn(),
|
||||||
|
|
|
@ -33,13 +33,11 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
||||||
Math.min(navigator.hardwareConcurrency - 1, 4),
|
Math.min(navigator.hardwareConcurrency - 1, 4),
|
||||||
);
|
);
|
||||||
resolve(workers);
|
resolve(workers);
|
||||||
if (_DEV_) console.log('WebGL2 in worker is supported!');
|
|
||||||
} else {
|
} else {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 64;
|
canvas.width = 64;
|
||||||
canvas.height = 64;
|
canvas.height = 64;
|
||||||
resolve(canvas);
|
resolve(canvas);
|
||||||
if (_DEV_) console.log('WebGL2 in worker is not supported...');
|
|
||||||
}
|
}
|
||||||
testWorker.terminate();
|
testWorker.terminate();
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,7 @@ const siteName = document.querySelector<HTMLMetaElement>('meta[property="og:site
|
||||||
export const host = address.host;
|
export const host = address.host;
|
||||||
export const hostname = address.hostname;
|
export const hostname = address.hostname;
|
||||||
export const url = address.origin;
|
export const url = address.origin;
|
||||||
|
export const port = address.port;
|
||||||
export const apiUrl = location.origin + '/api';
|
export const apiUrl = location.origin + '/api';
|
||||||
export const wsOrigin = location.origin;
|
export const wsOrigin = location.origin;
|
||||||
export const lang = localStorage.getItem('lang') ?? 'en-US';
|
export const lang = localStorage.getItem('lang') ?? 'en-US';
|
||||||
|
|
|
@ -64,12 +64,12 @@ initialize({
|
||||||
initLocalStorage();
|
initLocalStorage();
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
import('../src/components'),
|
import('../src/components/index.js'),
|
||||||
import('../src/directives'),
|
import('../src/directives/index.js'),
|
||||||
import('../src/widgets'),
|
import('../src/widgets/index.js'),
|
||||||
import('../src/theme'),
|
import('../src/theme.js'),
|
||||||
import('../src/preferences'),
|
import('../src/preferences.js'),
|
||||||
import('../src/os'),
|
import('../src/os.js'),
|
||||||
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => {
|
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => {
|
||||||
setup((app) => {
|
setup((app) => {
|
||||||
moduleInitialized = true;
|
moduleInitialized = true;
|
||||||
|
|
|
@ -52,7 +52,11 @@ export default [
|
||||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||||
// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
|
// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
|
||||||
// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
|
// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
|
||||||
'id-denylist': ['error', 'window', 'e'],
|
// close ... window.closeと衝突 or 紛らわしい
|
||||||
|
// open ... window.openと衝突 or 紛らわしい
|
||||||
|
// fetch ... window.fetchと衝突 or 紛らわしい
|
||||||
|
// location ... window.locationと衝突 or 紛らわしい
|
||||||
|
'id-denylist': ['error', 'window', 'e', 'close', 'open', 'fetch', 'location'],
|
||||||
'no-shadow': ['warn'],
|
'no-shadow': ['warn'],
|
||||||
'vue/attributes-order': ['error', {
|
'vue/attributes-order': ['error', {
|
||||||
alphabetical: false,
|
alphabetical: false,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import '@/style.scss';
|
||||||
import { mainBoot } from '@/boot/main-boot.js';
|
import { mainBoot } from '@/boot/main-boot.js';
|
||||||
import { subBoot } from '@/boot/sub-boot.js';
|
import { subBoot } from '@/boot/sub-boot.js';
|
||||||
|
|
||||||
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete'];
|
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions'];
|
||||||
|
|
||||||
if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) {
|
if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) {
|
||||||
subBoot();
|
subBoot();
|
||||||
|
|
|
@ -26,8 +26,6 @@ import { deckStore } from '@/ui/deck/deck-store.js';
|
||||||
import { analytics, initAnalytics } from '@/analytics.js';
|
import { analytics, initAnalytics } from '@/analytics.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { setupRouter } from '@/router/main.js';
|
|
||||||
import { createMainRouter } from '@/router/definition.js';
|
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
|
@ -267,8 +265,6 @@ export async function common(createVue: () => App<Element>) {
|
||||||
|
|
||||||
const app = createVue();
|
const app = createVue();
|
||||||
|
|
||||||
setupRouter(app, createMainRouter);
|
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
app.config.performance = true;
|
app.config.performance = true;
|
||||||
}
|
}
|
||||||
|
@ -304,24 +300,26 @@ export async function common(createVue: () => App<Element>) {
|
||||||
removeSplash();
|
removeSplash();
|
||||||
|
|
||||||
//#region Self-XSS 対策メッセージ
|
//#region Self-XSS 対策メッセージ
|
||||||
console.log(
|
if (!_DEV_) {
|
||||||
`%c${i18n.ts._selfXssPrevention.warning}`,
|
console.log(
|
||||||
'color: #f00; background-color: #ff0; font-size: 36px; padding: 4px;',
|
`%c${i18n.ts._selfXssPrevention.warning}`,
|
||||||
);
|
'color: #f00; background-color: #ff0; font-size: 36px; padding: 4px;',
|
||||||
console.log(
|
);
|
||||||
`%c${i18n.ts._selfXssPrevention.title}`,
|
console.log(
|
||||||
'color: #f00; font-weight: 900; font-family: "Hiragino Sans W9", "Hiragino Kaku Gothic ProN", sans-serif; font-size: 24px;',
|
`%c${i18n.ts._selfXssPrevention.title}`,
|
||||||
);
|
'color: #f00; font-weight: 900; font-family: "Hiragino Sans W9", "Hiragino Kaku Gothic ProN", sans-serif; font-size: 24px;',
|
||||||
console.log(
|
);
|
||||||
`%c${i18n.ts._selfXssPrevention.description1}`,
|
console.log(
|
||||||
'font-size: 16px; font-weight: 700;',
|
`%c${i18n.ts._selfXssPrevention.description1}`,
|
||||||
);
|
'font-size: 16px; font-weight: 700;',
|
||||||
console.log(
|
);
|
||||||
`%c${i18n.ts._selfXssPrevention.description2}`,
|
console.log(
|
||||||
'font-size: 16px;',
|
`%c${i18n.ts._selfXssPrevention.description2}`,
|
||||||
'font-size: 20px; font-weight: 700; color: #f00;',
|
'font-size: 16px;',
|
||||||
);
|
'font-size: 20px; font-weight: 700; color: #f00;',
|
||||||
console.log(i18n.tsx._selfXssPrevention.description3({ link: 'https://misskey-hub.net/docs/for-users/resources/self-xss/' }));
|
);
|
||||||
|
console.log(i18n.tsx._selfXssPrevention.description3({ link: 'https://misskey-hub.net/docs/for-users/resources/self-xss/' }));
|
||||||
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
|
import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
|
||||||
import { initializeSw } from '@/utility/initialize-sw.js';
|
import { initializeSw } from '@/utility/initialize-sw.js';
|
||||||
import { emojiPicker } from '@/utility/emoji-picker.js';
|
import { emojiPicker } from '@/utility/emoji-picker.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router.js';
|
||||||
import { makeHotkey } from '@/utility/hotkey.js';
|
import { makeHotkey } from '@/utility/hotkey.js';
|
||||||
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
@ -201,6 +201,8 @@ export async function mainBoot() {
|
||||||
prefer.commit('sound.on.noteMy', store.s.sound_noteMy as any);
|
prefer.commit('sound.on.noteMy', store.s.sound_noteMy as any);
|
||||||
prefer.commit('sound.on.notification', store.s.sound_notification as any);
|
prefer.commit('sound.on.notification', store.s.sound_notification as any);
|
||||||
prefer.commit('sound.on.reaction', store.s.sound_reaction as any);
|
prefer.commit('sound.on.reaction', store.s.sound_reaction as any);
|
||||||
|
prefer.commit('defaultNoteVisibility', store.s.defaultNoteVisibility);
|
||||||
|
prefer.commit('defaultNoteLocalOnly', store.s.defaultNoteLocalOnly);
|
||||||
|
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
unisonReload();
|
unisonReload();
|
||||||
|
|
|
@ -88,9 +88,9 @@ import { i18n } from '@/i18n.js';
|
||||||
import { dateString } from '@/filters/date.js';
|
import { dateString } from '@/filters/date.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import RouterView from '@/components/global/RouterView.vue';
|
import RouterView from '@/components/global/RouterView.vue';
|
||||||
import { useRouterFactory } from '@/router/supplier';
|
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
|
import { createRouter } from '@/router.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
report: Misskey.entities.AdminAbuseUserReportsResponse[number];
|
report: Misskey.entities.AdminAbuseUserReportsResponse[number];
|
||||||
|
@ -100,10 +100,9 @@ const emit = defineEmits<{
|
||||||
(ev: 'resolved', reportId: string): void;
|
(ev: 'resolved', reportId: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const routerFactory = useRouterFactory();
|
const targetRouter = createRouter(`/admin/user/${props.report.targetUserId}`);
|
||||||
const targetRouter = routerFactory(`/admin/user/${props.report.targetUserId}`);
|
|
||||||
targetRouter.init();
|
targetRouter.init();
|
||||||
const reporterRouter = routerFactory(`/admin/user/${props.report.reporterId}`);
|
const reporterRouter = createRouter(`/admin/user/${props.report.reporterId}`);
|
||||||
reporterRouter.init();
|
reporterRouter.init();
|
||||||
|
|
||||||
const moderationNote = ref(props.report.moderationNote ?? '');
|
const moderationNote = ref(props.report.moderationNote ?? '');
|
||||||
|
@ -135,7 +134,7 @@ function forward() {
|
||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-hash',
|
||||||
text: 'Copy ID',
|
text: 'Copy ID',
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(props.report.id);
|
copyToClipboard(props.report.id);
|
||||||
|
|
|
@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, shallowRef } from 'vue';
|
import { ref, useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkWindow from '@/components/MkWindow.vue';
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
@ -47,7 +47,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const uiWindow = shallowRef<InstanceType<typeof MkWindow>>();
|
const uiWindow = useTemplateRef('uiWindow');
|
||||||
const comment = ref(props.initialComment ?? '');
|
const comment = ref(props.initialComment ?? '');
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
|
|
|
@ -4,14 +4,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<canvas ref="canvasEl" style="width: 100%; height: 100%; pointer-events: none;"></canvas>
|
<canvas ref="canvasEl" style="display: block; width: 100%; height: 100%; pointer-events: none;"></canvas>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, shallowRef } from 'vue';
|
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
|
||||||
import isChromatic from 'chromatic/isChromatic';
|
import isChromatic from 'chromatic/isChromatic';
|
||||||
|
|
||||||
const canvasEl = shallowRef<HTMLCanvasElement>();
|
const canvasEl = useTemplateRef('canvasEl');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
scale?: number;
|
scale?: number;
|
||||||
|
|
|
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
|
@ -37,8 +37,8 @@ const props = withDefaults(defineProps<{
|
||||||
}>(), {
|
}>(), {
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = useTemplateRef('modal');
|
||||||
|
|
||||||
async function ok() {
|
async function ok() {
|
||||||
if (props.announcement.needConfirmationToRead) {
|
if (props.announcement.needConfirmationToRead) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import XAntennaEditor from '@/components/MkAntennaEditor.vue';
|
import XAntennaEditor from '@/components/MkAntennaEditor.vue';
|
||||||
|
@ -40,7 +40,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void,
|
(ev: 'closed'): void,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
function onAntennaCreated(newAntenna: Misskey.entities.Antenna) {
|
function onAntennaCreated(newAntenna: Misskey.entities.Antenna) {
|
||||||
emit('created', newAntenna);
|
emit('created', newAntenna);
|
||||||
|
|
|
@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { markRaw, ref, shallowRef, computed, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
import { markRaw, ref, useTemplateRef, computed, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import { emojilist, getEmojiName } from '@@/js/emojilist.js';
|
import { emojilist, getEmojiName } from '@@/js/emojilist.js';
|
||||||
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js';
|
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js';
|
||||||
|
@ -139,7 +139,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const suggests = ref<Element>();
|
const suggests = ref<Element>();
|
||||||
const rootEl = shallowRef<HTMLDivElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
|
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
const users = ref<any[]>([]);
|
const users = ref<any[]>([]);
|
||||||
|
|
|
@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, shallowRef } from 'vue';
|
import { nextTick, onMounted, useTemplateRef } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
type?: 'button' | 'submit' | 'reset';
|
type?: 'button' | 'submit' | 'reset';
|
||||||
|
@ -64,8 +64,8 @@ const emit = defineEmits<{
|
||||||
(ev: 'click', payload: MouseEvent): void;
|
(ev: 'click', payload: MouseEvent): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const el = shallowRef<HTMLElement | null>(null);
|
const el = useTemplateRef('el');
|
||||||
const ripples = shallowRef<HTMLElement | null>(null);
|
const ripples = useTemplateRef('ripples');
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autofocus) {
|
if (props.autofocus) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
|
import { ref, useTemplateRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
// APIs provided by Captcha services
|
// APIs provided by Captcha services
|
||||||
|
@ -69,7 +69,7 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const available = ref(false);
|
const available = ref(false);
|
||||||
|
|
||||||
const captchaEl = shallowRef<HTMLDivElement | undefined>();
|
const captchaEl = useTemplateRef('captchaEl');
|
||||||
const captchaWidgetId = ref<string | undefined>(undefined);
|
const captchaWidgetId = ref<string | undefined>(undefined);
|
||||||
const testcaptchaInput = ref('');
|
const testcaptchaInput = ref('');
|
||||||
const testcaptchaPassed = ref(false);
|
const testcaptchaPassed = ref(false);
|
||||||
|
|
|
@ -45,12 +45,8 @@ export type ChartSrc =
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/* eslint-disable id-denylist --
|
|
||||||
Chart.js has a `data` attribute in most chart definitions, which triggers the
|
import { onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
id-denylist violation when setting it. This is causing about 60+ lint issues.
|
|
||||||
As this is part of Chart.js's API it makes sense to disable the check here.
|
|
||||||
*/
|
|
||||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApiGet } from '@/utility/misskey-api.js';
|
import { misskeyApiGet } from '@/utility/misskey-api.js';
|
||||||
|
@ -96,7 +92,7 @@ const props = withDefaults(defineProps<{
|
||||||
nowForChromatic: undefined,
|
nowForChromatic: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const legendEl = shallowRef<InstanceType<typeof MkChartLegend>>();
|
const legendEl = useTemplateRef('legendEl');
|
||||||
|
|
||||||
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
|
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
|
||||||
const negate = arr => arr.map(x => -x);
|
const negate = arr => arr.map(x => -x);
|
||||||
|
@ -134,7 +130,7 @@ let chartData: {
|
||||||
bytes?: boolean;
|
bytes?: boolean;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
||||||
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
const chartEl = useTemplateRef('chartEl');
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
const getDate = (ago: number) => {
|
const getDate = (ago: number) => {
|
||||||
|
@ -849,7 +845,7 @@ watch(() => [props.src, props.span], fetchAndRender);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchAndRender();
|
fetchAndRender();
|
||||||
});
|
});
|
||||||
/* eslint-enable id-denylist */
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -48,7 +48,6 @@ const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue'))
|
||||||
|
|
||||||
function copy() {
|
function copy() {
|
||||||
copyToClipboard(props.code);
|
copyToClipboard(props.code);
|
||||||
os.success();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch, toRefs, shallowRef, nextTick } from 'vue';
|
import { ref, watch, toRefs, useTemplateRef, nextTick } from 'vue';
|
||||||
import { debounce } from 'throttle-debounce';
|
import { debounce } from 'throttle-debounce';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
@ -61,7 +61,7 @@ const { modelValue } = toRefs(props);
|
||||||
const v = ref<string>(modelValue.value ?? '');
|
const v = ref<string>(modelValue.value ?? '');
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
const changed = ref(false);
|
const changed = ref(false);
|
||||||
const inputEl = shallowRef<HTMLTextAreaElement>();
|
const inputEl = useTemplateRef('inputEl');
|
||||||
|
|
||||||
const focus = () => inputEl.value?.focus();
|
const focus = () => inputEl.value?.focus();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, toRefs } from 'vue';
|
import { ref, useTemplateRef, toRefs } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: string | null;
|
modelValue: string | null;
|
||||||
|
@ -39,7 +39,7 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const { modelValue } = toRefs(props);
|
const { modelValue } = toRefs(props);
|
||||||
const v = ref(modelValue.value);
|
const v = ref(modelValue.value);
|
||||||
const inputEl = shallowRef<HTMLElement>();
|
const inputEl = useTemplateRef('inputEl');
|
||||||
|
|
||||||
const onInput = () => {
|
const onInput = () => {
|
||||||
emit('update:modelValue', v.value ?? '');
|
emit('update:modelValue', v.value ?? '');
|
||||||
|
|
|
@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
import { onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
@ -58,9 +58,9 @@ const props = withDefaults(defineProps<{
|
||||||
maxHeight: null,
|
maxHeight: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const contentEl = shallowRef<HTMLElement>();
|
const contentEl = useTemplateRef('contentEl');
|
||||||
const headerEl = shallowRef<HTMLElement>();
|
const headerEl = useTemplateRef('headerEl');
|
||||||
const showBody = ref(props.expanded);
|
const showBody = ref(props.expanded);
|
||||||
const ignoreOmit = ref(false);
|
const ignoreOmit = ref(false);
|
||||||
const omitted = ref(false);
|
const omitted = ref(false);
|
||||||
|
|
|
@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
|
import { onMounted, onBeforeUnmount, useTemplateRef, ref } from 'vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import contains from '@/utility/contains.js';
|
import contains from '@/utility/contains.js';
|
||||||
|
@ -34,7 +34,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
|
|
||||||
const zIndex = ref<number>(os.claimZIndex('high'));
|
const zIndex = ref<number>(os.claimZIndex('high'));
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef, ref } from 'vue';
|
import { onMounted, useTemplateRef, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
@ -56,8 +56,8 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const imgUrl = getProxiedImageUrl(props.file.url, undefined, true);
|
const imgUrl = getProxiedImageUrl(props.file.url, undefined, true);
|
||||||
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialogEl = useTemplateRef('dialogEl');
|
||||||
const imgEl = shallowRef<HTMLImageElement>();
|
const imgEl = useTemplateRef('imgEl');
|
||||||
let cropper: Cropper | null = null;
|
let cropper: Cropper | null = null;
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
|
|
||||||
|
|
|
@ -57,14 +57,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { shallowRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
emoji: Misskey.entities.EmojiDetailed,
|
emoji: Misskey.entities.EmojiDetailed,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -73,7 +73,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialogEl = useTemplateRef('dialogEl');
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
|
|
|
@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed } from 'vue';
|
import { ref, useTemplateRef, computed } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
@ -117,7 +117,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = useTemplateRef('modal');
|
||||||
|
|
||||||
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
||||||
const selectedValue = ref(props.select?.default ?? null);
|
const selectedValue = ref(props.select?.default ?? null);
|
||||||
|
|
|
@ -47,7 +47,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
|
||||||
import { deviceKind } from '@/utility/device-kind.js';
|
import { deviceKind } from '@/utility/device-kind.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ function onContextmenu(ev: MouseEvent) {
|
||||||
}];
|
}];
|
||||||
if (prefer.s.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menu = menu.concat([{ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-hash',
|
||||||
text: i18n.ts.copyFolderId,
|
text: i18n.ts.copyFolderId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(props.folder.id);
|
copyToClipboard(props.folder.id);
|
||||||
|
|
|
@ -96,7 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onActivated, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
|
import { nextTick, onActivated, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkButton from './MkButton.vue';
|
import MkButton from './MkButton.vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
@ -129,8 +129,8 @@ const emit = defineEmits<{
|
||||||
(ev: 'open-folder', v: Misskey.entities.DriveFolder): void;
|
(ev: 'open-folder', v: Misskey.entities.DriveFolder): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const loadMoreFiles = shallowRef<InstanceType<typeof MkButton>>();
|
const loadMoreFiles = useTemplateRef('loadMoreFiles');
|
||||||
const fileInput = shallowRef<HTMLInputElement>();
|
const fileInput = useTemplateRef('fileInput');
|
||||||
|
|
||||||
const folder = ref<Misskey.entities.DriveFolder | null>(null);
|
const folder = ref<Misskey.entities.DriveFolder | null>(null);
|
||||||
const files = ref<Misskey.entities.DriveFile[]>([]);
|
const files = ref<Misskey.entities.DriveFile[]>([]);
|
||||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef } from 'vue';
|
import { ref, useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XDrive from '@/components/MkDrive.vue';
|
import XDrive from '@/components/MkDrive.vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
|
@ -43,7 +43,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
const selected = ref<Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[]>([]);
|
const selected = ref<Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[]>([]);
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { shallowRef, ref, computed, nextTick, onMounted, onDeactivated, onUnmounted } from 'vue';
|
import { useTemplateRef, ref, computed, nextTick, onMounted, onDeactivated, onUnmounted } from 'vue';
|
||||||
import { url } from '@@/js/config.js';
|
import { url } from '@@/js/config.js';
|
||||||
import { embedRouteWithScrollbar } from '@@/js/embed-page.js';
|
import { embedRouteWithScrollbar } from '@@/js/embed-page.js';
|
||||||
import type { EmbeddableEntity, EmbedParams } from '@@/js/embed-page.js';
|
import type { EmbeddableEntity, EmbedParams } from '@@/js/embed-page.js';
|
||||||
|
@ -121,7 +121,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
//#region Modalの制御
|
//#region Modalの制御
|
||||||
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialogEl = useTemplateRef('dialogEl');
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
|
@ -194,14 +194,13 @@ function generate() {
|
||||||
|
|
||||||
function doCopy() {
|
function doCopy() {
|
||||||
copyToClipboard(result.value);
|
copyToClipboard(result.value);
|
||||||
os.success();
|
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region プレビューのリサイズ
|
//#region プレビューのリサイズ
|
||||||
const resizerRootEl = shallowRef<HTMLDivElement>();
|
const resizerRootEl = useTemplateRef('resizerRootEl');
|
||||||
const iframeLoading = ref(true);
|
const iframeLoading = ref(true);
|
||||||
const iframeEl = shallowRef<HTMLIFrameElement>();
|
const iframeEl = useTemplateRef('iframeEl');
|
||||||
const iframeHeight = ref(0);
|
const iframeHeight = ref(0);
|
||||||
const iframeScale = ref(1);
|
const iframeScale = ref(1);
|
||||||
const iframeStyle = computed(() => {
|
const iframeStyle = computed(() => {
|
||||||
|
|
|
@ -115,7 +115,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, watch, onMounted } from 'vue';
|
import { ref, useTemplateRef, computed, watch, onMounted } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import {
|
import {
|
||||||
emojilist,
|
emojilist,
|
||||||
|
@ -157,8 +157,8 @@ const emit = defineEmits<{
|
||||||
(ev: 'esc'): void;
|
(ev: 'esc'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const searchEl = shallowRef<HTMLInputElement>();
|
const searchEl = useTemplateRef('searchEl');
|
||||||
const emojisEl = shallowRef<HTMLDivElement>();
|
const emojisEl = useTemplateRef('emojisEl');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
emojiPickerScale,
|
emojiPickerScale,
|
||||||
|
|
|
@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { shallowRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
|
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
@ -64,8 +64,8 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = useTemplateRef('modal');
|
||||||
const picker = shallowRef<InstanceType<typeof MkEmojiPicker>>();
|
const picker = useTemplateRef('picker');
|
||||||
|
|
||||||
function chosen(emoji: string) {
|
function chosen(emoji: string) {
|
||||||
emit('done', emoji);
|
emit('done', emoji);
|
||||||
|
|
|
@ -11,54 +11,91 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<!-- 拡張用? -->
|
<!-- 拡張用? -->
|
||||||
<i v-else class="ti ti-download"></i>
|
<i v-else class="ti ti-download"></i>
|
||||||
</div>
|
</div>
|
||||||
<h2 :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].title }}</h2>
|
|
||||||
<div :class="$style.extInstallerNormDesc">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</div>
|
|
||||||
<MkInfo v-if="isPlugin" :warn="true">{{ i18n.ts._plugin.installWarn }}</MkInfo>
|
|
||||||
<FormSection>
|
|
||||||
<template #label>{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].metaTitle }}</template>
|
|
||||||
<div class="_gaps_s">
|
|
||||||
<FormSplit>
|
|
||||||
<MkKeyValue>
|
|
||||||
<template #key>{{ i18n.ts.name }}</template>
|
|
||||||
<template #value>{{ extension.meta.name }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue>
|
|
||||||
<template #key>{{ i18n.ts.author }}</template>
|
|
||||||
<template #value>{{ extension.meta.author }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
</FormSplit>
|
|
||||||
<MkKeyValue v-if="isPlugin">
|
|
||||||
<template #key>{{ i18n.ts.description }}</template>
|
|
||||||
<template #value>{{ extension.meta.description ?? i18n.ts.none }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue v-if="isPlugin">
|
|
||||||
<template #key>{{ i18n.ts.version }}</template>
|
|
||||||
<template #value>{{ extension.meta.version }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue v-if="isPlugin">
|
|
||||||
<template #key>{{ i18n.ts.permission }}</template>
|
|
||||||
<template #value>
|
|
||||||
<ul v-if="extension.meta.permissions && extension.meta.permissions.length > 0" :class="$style.extInstallerKVList">
|
|
||||||
<li v-for="permission in extension.meta.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
|
|
||||||
</ul>
|
|
||||||
<template v-else>{{ i18n.ts.none }}</template>
|
|
||||||
</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue v-if="isTheme">
|
|
||||||
<template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template>
|
|
||||||
<template #value>{{ i18n.ts[extension.meta.base ?? 'none'] }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkFolder>
|
|
||||||
<template #icon><i class="ti ti-code"></i></template>
|
|
||||||
<template #label>{{ i18n.ts._plugin.viewSource }}</template>
|
|
||||||
|
|
||||||
<MkCode :code="extension.raw"/>
|
<h2 v-if="isPlugin" :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller._plugin.title }}</h2>
|
||||||
</MkFolder>
|
<h2 v-else-if="isTheme" :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller._theme.title }}</h2>
|
||||||
</div>
|
|
||||||
</FormSection>
|
<MkInfo :warn="true">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</MkInfo>
|
||||||
|
|
||||||
|
<div v-if="isPlugin" class="_gaps_s">
|
||||||
|
<MkFolder :defaultOpen="true">
|
||||||
|
<template #icon><i class="ti ti-info-circle"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.metadata }}</template>
|
||||||
|
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<FormSplit>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.name }}</template>
|
||||||
|
<template #value>{{ extension.meta.name }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.author }}</template>
|
||||||
|
<template #value>{{ extension.meta.author }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</FormSplit>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.description }}</template>
|
||||||
|
<template #value>{{ extension.meta.description ?? i18n.ts.none }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.version }}</template>
|
||||||
|
<template #value>{{ extension.meta.version }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.permission }}</template>
|
||||||
|
<template #value>
|
||||||
|
<ul v-if="extension.meta.permissions && extension.meta.permissions.length > 0" :class="$style.extInstallerKVList">
|
||||||
|
<li v-for="permission in extension.meta.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
|
||||||
|
</ul>
|
||||||
|
<template v-else>{{ i18n.ts.none }}</template>
|
||||||
|
</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder :withSpacer="false">
|
||||||
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
|
<template #label>{{ i18n.ts._plugin.viewSource }}</template>
|
||||||
|
|
||||||
|
<MkCode :code="extension.raw"/>
|
||||||
|
</MkFolder>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="isTheme" class="_gaps_s">
|
||||||
|
<MkFolder :defaultOpen="true">
|
||||||
|
<template #icon><i class="ti ti-info-circle"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.metadata }}</template>
|
||||||
|
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<FormSplit>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.name }}</template>
|
||||||
|
<template #value>{{ extension.meta.name }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts.author }}</template>
|
||||||
|
<template #value>{{ extension.meta.author }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</FormSplit>
|
||||||
|
<MkKeyValue>
|
||||||
|
<template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template>
|
||||||
|
<template #value>{{ i18n.ts[extension.meta.base ?? 'none'] }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder :withSpacer="false">
|
||||||
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
|
<template #label>{{ i18n.ts._theme.code }}</template>
|
||||||
|
|
||||||
|
<MkCode :code="extension.raw"/>
|
||||||
|
</MkFolder>
|
||||||
|
</div>
|
||||||
|
|
||||||
<slot name="additionalInfo"/>
|
<slot name="additionalInfo"/>
|
||||||
|
|
||||||
<div class="_buttonsCenter">
|
<div class="_buttonsCenter">
|
||||||
<MkButton primary @click="emits('confirm')"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton>
|
<MkButton danger rounded large @click="emits('cancel')"><i class="ti ti-x"></i> {{ i18n.ts.cancel }}</MkButton>
|
||||||
|
<MkButton gradate rounded large @click="emits('confirm')"><i class="ti ti-download"></i> {{ i18n.ts.install }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -105,6 +142,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
(ev: 'confirm'): void;
|
(ev: 'confirm'): void;
|
||||||
|
(ev: 'cancel'): void;
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -112,13 +150,13 @@ const emits = defineEmits<{
|
||||||
.extInstallerRoot {
|
.extInstallerRoot {
|
||||||
border-radius: var(--MI-radius);
|
border-radius: var(--MI-radius);
|
||||||
background: var(--MI_THEME-panel);
|
background: var(--MI_THEME-panel);
|
||||||
padding: 1.5rem;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extInstallerIconWrapper {
|
.extInstallerIconWrapper {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
font-size: 24px;
|
font-size: 20px;
|
||||||
line-height: 48px;
|
line-height: 48px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
@ -135,10 +173,6 @@ const emits = defineEmits<{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extInstallerNormDesc {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.extInstallerKVList {
|
.extInstallerKVList {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef, ref } from 'vue';
|
import { useTemplateRef, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
@ -42,7 +42,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
const caption = ref(props.default);
|
const caption = ref(props.default);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
import { onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||||
|
@ -46,7 +46,7 @@ const props = withDefaults(defineProps<{
|
||||||
persistKey: null,
|
persistKey: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const parentBg = ref<string | null>(null);
|
const parentBg = ref<string | null>(null);
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
||||||
|
|
|
@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, ref, shallowRef } from 'vue';
|
import { nextTick, onMounted, ref, useTemplateRef } from 'vue';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ const props = withDefaults(defineProps<{
|
||||||
spacerMax: 22,
|
spacerMax: 22,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const bgSame = ref(false);
|
const bgSame = ref(false);
|
||||||
const opened = ref(props.defaultOpen);
|
const opened = ref(props.defaultOpen);
|
||||||
const openedAtLeastOnce = ref(props.defaultOpen);
|
const openedAtLeastOnce = ref(props.defaultOpen);
|
||||||
|
|
|
@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, shallowRef } from 'vue';
|
import { reactive, useTemplateRef } from 'vue';
|
||||||
import MkInput from './MkInput.vue';
|
import MkInput from './MkInput.vue';
|
||||||
import MkTextarea from './MkTextarea.vue';
|
import MkTextarea from './MkTextarea.vue';
|
||||||
import MkSwitch from './MkSwitch.vue';
|
import MkSwitch from './MkSwitch.vue';
|
||||||
|
@ -99,7 +99,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = useTemplateRef('dialog');
|
||||||
const values = reactive({});
|
const values = reactive({});
|
||||||
|
|
||||||
for (const item in props.form) {
|
for (const item in props.form) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, nextTick, watch, shallowRef, ref } from 'vue';
|
import { onMounted, nextTick, watch, useTemplateRef, ref } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
|
@ -35,8 +35,8 @@ const props = withDefaults(defineProps<{
|
||||||
label: '',
|
label: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement | null>(null);
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
const chartEl = useTemplateRef('chartEl');
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let chartInstance: Chart | null = null;
|
let chartInstance: Chart | null = null;
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
|
@ -26,12 +26,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, nextTick, watch } from 'vue';
|
import { ref, useTemplateRef, computed, nextTick, watch } from 'vue';
|
||||||
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
||||||
import { isHorizontalSwipeSwiping as isSwiping } from '@/utility/touch.js';
|
import { isHorizontalSwipeSwiping as isSwiping } from '@/utility/touch.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
|
|
||||||
const tabModel = defineModel<string>('tab');
|
const tabModel = defineModel<string>('tab');
|
||||||
|
|
||||||
|
|
|
@ -69,13 +69,11 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
||||||
Math.min(navigator.hardwareConcurrency - 1, 4),
|
Math.min(navigator.hardwareConcurrency - 1, 4),
|
||||||
);
|
);
|
||||||
resolve(workers);
|
resolve(workers);
|
||||||
if (_DEV_) console.log('WebGL2 in worker is supported!');
|
|
||||||
} else {
|
} else {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 64;
|
canvas.width = 64;
|
||||||
canvas.height = 64;
|
canvas.height = 64;
|
||||||
resolve(canvas);
|
resolve(canvas);
|
||||||
if (_DEV_) console.log('WebGL2 in worker is not supported...');
|
|
||||||
}
|
}
|
||||||
testWorker.terminate();
|
testWorker.terminate();
|
||||||
});
|
});
|
||||||
|
@ -83,7 +81,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch, ref } from 'vue';
|
import { computed, nextTick, onMounted, onUnmounted, useTemplateRef, watch, ref } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { render } from 'buraha';
|
import { render } from 'buraha';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
@ -120,9 +118,9 @@ const props = withDefaults(defineProps<{
|
||||||
});
|
});
|
||||||
|
|
||||||
const viewId = uuid();
|
const viewId = uuid();
|
||||||
const canvas = shallowRef<HTMLCanvasElement>();
|
const canvas = useTemplateRef('canvas');
|
||||||
const root = shallowRef<HTMLDivElement>();
|
const root = useTemplateRef('root');
|
||||||
const img = shallowRef<HTMLImageElement>();
|
const img = useTemplateRef('img');
|
||||||
const loaded = ref(false);
|
const loaded = ref(false);
|
||||||
const canvasWidth = ref(64);
|
const canvasWidth = ref(64);
|
||||||
const canvasHeight = ref(64);
|
const canvasHeight = ref(64);
|
||||||
|
|
|
@ -44,7 +44,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue';
|
import { onMounted, onUnmounted, nextTick, ref, useTemplateRef, watch, computed, toRefs } from 'vue';
|
||||||
import { debounce } from 'throttle-debounce';
|
import { debounce } from 'throttle-debounce';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
import type { InputHTMLAttributes } from 'vue';
|
import type { InputHTMLAttributes } from 'vue';
|
||||||
|
@ -92,9 +92,9 @@ const focused = ref(false);
|
||||||
const changed = ref(false);
|
const changed = ref(false);
|
||||||
const invalid = ref(false);
|
const invalid = ref(false);
|
||||||
const filled = computed(() => v.value !== '' && v.value != null);
|
const filled = computed(() => v.value !== '' && v.value != null);
|
||||||
const inputEl = shallowRef<HTMLInputElement>();
|
const inputEl = useTemplateRef('inputEl');
|
||||||
const prefixEl = shallowRef<HTMLElement>();
|
const prefixEl = useTemplateRef('prefixEl');
|
||||||
const suffixEl = shallowRef<HTMLElement>();
|
const suffixEl = useTemplateRef('suffixEl');
|
||||||
const height =
|
const height =
|
||||||
props.small ? 33 :
|
props.small ? 33 :
|
||||||
props.large ? 39 :
|
props.large ? 39 :
|
||||||
|
|
|
@ -84,8 +84,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, computed, shallowRef } from 'vue';
|
import { onMounted, ref, computed, useTemplateRef } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
|
import type { HeatmapSource } from '@/components/MkHeatmap.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkChart from '@/components/MkChart.vue';
|
import MkChart from '@/components/MkChart.vue';
|
||||||
import { useChartTooltip } from '@/use/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/use/use-chart-tooltip.js';
|
||||||
|
@ -95,7 +96,6 @@ import { misskeyApiGet } from '@/utility/misskey-api.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkHeatmap from '@/components/MkHeatmap.vue';
|
import MkHeatmap from '@/components/MkHeatmap.vue';
|
||||||
import type { HeatmapSource } from '@/components/MkHeatmap.vue';
|
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue';
|
import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue';
|
||||||
import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue';
|
import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue';
|
||||||
|
@ -109,8 +109,8 @@ const chartLimit = 500;
|
||||||
const chartSpan = ref<'hour' | 'day'>('hour');
|
const chartSpan = ref<'hour' | 'day'>('hour');
|
||||||
const chartSrc = ref('active-users');
|
const chartSrc = ref('active-users');
|
||||||
const heatmapSrc = ref<HeatmapSource>('active-users');
|
const heatmapSrc = ref<HeatmapSource>('active-users');
|
||||||
const subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
const subDoughnutEl = useTemplateRef('subDoughnutEl');
|
||||||
const pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
const pubDoughnutEl = useTemplateRef('pubDoughnutEl');
|
||||||
|
|
||||||
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
||||||
position: 'middle',
|
position: 'middle',
|
||||||
|
|
|
@ -90,7 +90,6 @@ function deleteCode() {
|
||||||
|
|
||||||
function copyInviteCode() {
|
function copyInviteCode() {
|
||||||
copyToClipboard(props.invite.code);
|
copyToClipboard(props.invite.code);
|
||||||
os.success();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ const props = withDefaults(defineProps<{
|
||||||
|
|
||||||
const copy_ = () => {
|
const copy_ = () => {
|
||||||
copyToClipboard(props.copy);
|
copyToClipboard(props.copy);
|
||||||
os.success();
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import { navbarItemDef } from '@/navbar.js';
|
import { navbarItemDef } from '@/navbar.js';
|
||||||
import { deviceKind } from '@/utility/device-kind.js';
|
import { deviceKind } from '@/utility/device-kind.js';
|
||||||
|
@ -48,7 +48,7 @@ const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'pop
|
||||||
deviceKind === 'smartphone' ? 'drawer' :
|
deviceKind === 'smartphone' ? 'drawer' :
|
||||||
'dialog';
|
'dialog';
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = useTemplateRef('modal');
|
||||||
|
|
||||||
const menu = prefer.s.menu;
|
const menu = prefer.s.menu;
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef, watch, computed, ref, onDeactivated, onActivated, onMounted } from 'vue';
|
import { useTemplateRef, watch, computed, ref, onDeactivated, onActivated, onMounted } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import type { Keymap } from '@/utility/hotkey.js';
|
import type { Keymap } from '@/utility/hotkey.js';
|
||||||
|
@ -151,8 +151,8 @@ function hasFocus() {
|
||||||
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
|
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
const playerEl = shallowRef<HTMLDivElement>();
|
const playerEl = useTemplateRef('playerEl');
|
||||||
const audioEl = shallowRef<HTMLAudioElement>();
|
const audioEl = useTemplateRef('audioEl');
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore'));
|
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore'));
|
||||||
|
@ -242,7 +242,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
|
|
||||||
if (prefer.s.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu.push({ type: 'divider' }, {
|
menu.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-hash',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(props.audio.id);
|
copyToClipboard(props.audio.id);
|
||||||
|
|
|
@ -168,7 +168,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
|
|
||||||
if (prefer.s.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menuItems.push({ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-hash',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(props.image.id);
|
copyToClipboard(props.image.id);
|
||||||
|
|
|
@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted, shallowRef } from 'vue';
|
import { computed, onMounted, onUnmounted, useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
||||||
import PhotoSwipe from 'photoswipe';
|
import PhotoSwipe from 'photoswipe';
|
||||||
|
@ -46,7 +46,7 @@ const props = defineProps<{
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const gallery = shallowRef<HTMLDivElement>();
|
const gallery = useTemplateRef('gallery');
|
||||||
const pswpZIndex = os.claimZIndex('middle');
|
const pswpZIndex = os.claimZIndex('middle');
|
||||||
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
|
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
|
||||||
const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
|
const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
|
||||||
|
|
|
@ -109,7 +109,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
|
import { ref, useTemplateRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import type { Keymap } from '@/utility/hotkey.js';
|
import type { Keymap } from '@/utility/hotkey.js';
|
||||||
|
@ -267,7 +267,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
|
|
||||||
if (prefer.s.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu.push({ type: 'divider' }, {
|
menu.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-hash',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(props.video.id);
|
copyToClipboard(props.video.id);
|
||||||
|
@ -299,8 +299,8 @@ async function toggleSensitive(file: Misskey.entities.DriveFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaControl: Video State
|
// MediaControl: Video State
|
||||||
const videoEl = shallowRef<HTMLVideoElement>();
|
const videoEl = useTemplateRef('videoEl');
|
||||||
const playerEl = shallowRef<HTMLDivElement>();
|
const playerEl = useTemplateRef('playerEl');
|
||||||
const isHoverring = ref(false);
|
const isHoverring = ref(false);
|
||||||
const controlsShowing = computed(() => {
|
const controlsShowing = computed(() => {
|
||||||
if (!oncePlayed.value) return true;
|
if (!oncePlayed.value) return true;
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, onUnmounted, provide, shallowRef, watch } from 'vue';
|
import { nextTick, onMounted, onUnmounted, provide, useTemplateRef, watch } from 'vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
provide('isNestingMenu', true);
|
provide('isNestingMenu', true);
|
||||||
|
|
||||||
const el = shallowRef<HTMLElement>();
|
const el = useTemplateRef('el');
|
||||||
const align = 'left';
|
const align = 'left';
|
||||||
|
|
||||||
const SCROLLBAR_THICKNESS = 16;
|
const SCROLLBAR_THICKNESS = 16;
|
||||||
|
|
|
@ -15,6 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@focusin.passive.stop="() => {}"
|
@focusin.passive.stop="() => {}"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
ref="itemsEl"
|
||||||
|
v-hotkey="keymap"
|
||||||
|
tabindex="0"
|
||||||
class="_popup _shadow"
|
class="_popup _shadow"
|
||||||
:class="$style.menu"
|
:class="$style.menu"
|
||||||
:style="{
|
:style="{
|
||||||
|
@ -24,156 +27,150 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@keydown.stop="() => {}"
|
@keydown.stop="() => {}"
|
||||||
@contextmenu.self.prevent="() => {}"
|
@contextmenu.self.prevent="() => {}"
|
||||||
>
|
>
|
||||||
<slot name="header"></slot>
|
<template v-for="item in (items2 ?? [])">
|
||||||
<div
|
<div v-if="item.type === 'divider'" role="separator" tabindex="-1" :class="$style.divider"></div>
|
||||||
ref="itemsEl"
|
<span v-else-if="item.type === 'label'" role="menuitem" tabindex="-1" :class="[$style.label, $style.item]">
|
||||||
v-hotkey="keymap"
|
<span style="opacity: 0.7;">{{ item.text }}</span>
|
||||||
tabindex="0"
|
|
||||||
:class="$style.menuItems"
|
|
||||||
>
|
|
||||||
<template v-for="item in (items2 ?? [])">
|
|
||||||
<div v-if="item.type === 'divider'" role="separator" tabindex="-1" :class="$style.divider"></div>
|
|
||||||
<span v-else-if="item.type === 'label'" role="menuitem" tabindex="-1" :class="[$style.label, $style.item]">
|
|
||||||
<span style="opacity: 0.7;">{{ item.text }}</span>
|
|
||||||
</span>
|
|
||||||
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item]">
|
|
||||||
<span><MkEllipsis/></span>
|
|
||||||
</span>
|
|
||||||
<MkA
|
|
||||||
v-else-if="item.type === 'link'"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item]"
|
|
||||||
:to="item.to"
|
|
||||||
@click.passive="close(true)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<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"/>
|
|
||||||
<div :class="$style.item_content">
|
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
|
||||||
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
|
||||||
</div>
|
|
||||||
</MkA>
|
|
||||||
<a
|
|
||||||
v-else-if="item.type === 'a'"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item]"
|
|
||||||
:href="item.href"
|
|
||||||
:target="item.target"
|
|
||||||
:rel="item.target === '_blank' ? 'noopener noreferrer' : undefined"
|
|
||||||
:download="item.download"
|
|
||||||
@click.passive="close(true)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
|
||||||
<div :class="$style.item_content">
|
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
|
||||||
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
v-else-if="item.type === 'user'"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item, { [$style.active]: item.active }]"
|
|
||||||
@click.prevent="item.active ? close(false) : clicked(item.action, $event)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/>
|
|
||||||
<div v-if="item.indicate" :class="$style.item_content">
|
|
||||||
<span :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-else-if="item.type === 'switch'"
|
|
||||||
role="menuitemcheckbox"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item]"
|
|
||||||
:disabled="unref(item.disabled)"
|
|
||||||
@click.prevent="switchItem(item)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
|
||||||
<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
|
||||||
<div :class="$style.item_content">
|
|
||||||
<span :class="[$style.item_content_text, { [$style.switchText]: !item.icon }]">{{ item.text }}</span>
|
|
||||||
<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-else-if="item.type === 'radio'"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
|
|
||||||
:disabled="unref(item.disabled)"
|
|
||||||
@mouseenter.prevent="preferClick ? null : showRadioOptions(item, $event)"
|
|
||||||
@keydown.enter.prevent="preferClick ? null : showRadioOptions(item, $event)"
|
|
||||||
@click.prevent="!preferClick ? null : showRadioOptions(item, $event)"
|
|
||||||
>
|
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
|
|
||||||
<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-if="item.type === 'radioOption'"
|
|
||||||
role="menuitemradio"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item, $style.radio, { [$style.active]: unref(item.active) }]"
|
|
||||||
@click.prevent="unref(item.active) ? null : clicked(item.action, $event, false)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<div :class="$style.icon">
|
|
||||||
<span :class="[$style.radioIcon, { [$style.radioChecked]: unref(item.active) }]"></span>
|
|
||||||
</div>
|
|
||||||
<div :class="$style.item_content">
|
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-else-if="item.type === 'parent'"
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
|
|
||||||
@mouseenter.prevent="preferClick ? null : showChildren(item, $event)"
|
|
||||||
@keydown.enter.prevent="preferClick ? null : showChildren(item, $event)"
|
|
||||||
@click.prevent="!preferClick ? null : showChildren(item, $event)"
|
|
||||||
>
|
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
|
|
||||||
<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 role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
:class="['_button', $style.item, { [$style.danger]: item.danger, [$style.active]: unref(item.active) }]"
|
|
||||||
@click.prevent="unref(item.active) ? close(false) : clicked(item.action, $event)"
|
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
|
||||||
>
|
|
||||||
<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"/>
|
|
||||||
<div :class="$style.item_content">
|
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
|
||||||
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<span v-if="items2 == null || items2.length === 0" tabindex="-1" :class="[$style.none, $style.item]">
|
|
||||||
<span>{{ i18n.ts.none }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item]">
|
||||||
<slot name="footer"></slot>
|
<span><MkEllipsis/></span>
|
||||||
|
</span>
|
||||||
|
<div v-else-if="item.type === 'component'" role="menuitem" tabindex="-1" :class="[$style.componentItem]">
|
||||||
|
<component :is="item.component" v-bind="item.props"/>
|
||||||
|
</div>
|
||||||
|
<MkA
|
||||||
|
v-else-if="item.type === 'link'"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item]"
|
||||||
|
:to="item.to"
|
||||||
|
@click.passive="close(true)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<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"/>
|
||||||
|
<div :class="$style.item_content">
|
||||||
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
||||||
|
</div>
|
||||||
|
</MkA>
|
||||||
|
<a
|
||||||
|
v-else-if="item.type === 'a'"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item]"
|
||||||
|
:href="item.href"
|
||||||
|
:target="item.target"
|
||||||
|
:rel="item.target === '_blank' ? 'noopener noreferrer' : undefined"
|
||||||
|
:download="item.download"
|
||||||
|
@click.passive="close(true)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
|
<div :class="$style.item_content">
|
||||||
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
v-else-if="item.type === 'user'"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item, { [$style.active]: item.active }]"
|
||||||
|
@click.prevent="item.active ? close(false) : clicked(item.action, $event)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/>
|
||||||
|
<div v-if="item.indicate" :class="$style.item_content">
|
||||||
|
<span :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="item.type === 'switch'"
|
||||||
|
role="menuitemcheckbox"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item]"
|
||||||
|
:disabled="unref(item.disabled)"
|
||||||
|
@click.prevent="switchItem(item)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
|
<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
||||||
|
<div :class="$style.item_content">
|
||||||
|
<span :class="[$style.item_content_text, { [$style.switchText]: !item.icon }]">{{ item.text }}</span>
|
||||||
|
<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="item.type === 'radio'"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
|
||||||
|
:disabled="unref(item.disabled)"
|
||||||
|
@mouseenter.prevent="preferClick ? null : showRadioOptions(item, $event)"
|
||||||
|
@keydown.enter.prevent="preferClick ? null : showRadioOptions(item, $event)"
|
||||||
|
@click.prevent="!preferClick ? null : showRadioOptions(item, $event)"
|
||||||
|
>
|
||||||
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
|
||||||
|
<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-if="item.type === 'radioOption'"
|
||||||
|
role="menuitemradio"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item, $style.radio, { [$style.active]: unref(item.active) }]"
|
||||||
|
@click.prevent="unref(item.active) ? null : clicked(item.action, $event, false)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<div :class="$style.icon">
|
||||||
|
<span :class="[$style.radioIcon, { [$style.radioChecked]: unref(item.active) }]"></span>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.item_content">
|
||||||
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="item.type === 'parent'"
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item }]"
|
||||||
|
@mouseenter.prevent="preferClick ? null : showChildren(item, $event)"
|
||||||
|
@keydown.enter.prevent="preferClick ? null : showChildren(item, $event)"
|
||||||
|
@click.prevent="!preferClick ? null : showChildren(item, $event)"
|
||||||
|
>
|
||||||
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]" style="pointer-events: none;"></i>
|
||||||
|
<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 role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item, { [$style.danger]: item.danger, [$style.active]: unref(item.active) }]"
|
||||||
|
@click.prevent="unref(item.active) ? close(false) : clicked(item.action, $event)"
|
||||||
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
|
<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"/>
|
||||||
|
<div :class="$style.item_content">
|
||||||
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
<span v-if="item.indicate" :class="$style.indicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<span v-if="items2 == null || items2.length === 0" tabindex="-1" :class="[$style.none, $style.item]">
|
||||||
|
<span>{{ i18n.ts.none }}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="childMenu">
|
<div v-if="childMenu">
|
||||||
<XChild ref="child" :items="childMenu" :targetElement="childTarget!" :rootElement="itemsEl!" @actioned="childActioned" @closed="closeChild"/>
|
<XChild ref="child" :items="childMenu" :targetElement="childTarget!" :rootElement="itemsEl!" @actioned="childActioned" @closed="closeChild"/>
|
||||||
|
@ -182,7 +179,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, unref, watch } from 'vue';
|
import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, unref, watch, shallowRef } from 'vue';
|
||||||
import type { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
|
import type { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
|
||||||
import type { Keymap } from '@/utility/hotkey.js';
|
import type { Keymap } from '@/utility/hotkey.js';
|
||||||
import MkSwitchButton from '@/components/MkSwitch.button.vue';
|
import MkSwitchButton from '@/components/MkSwitch.button.vue';
|
||||||
|
@ -215,11 +212,11 @@ const big = isTouchUsing;
|
||||||
|
|
||||||
const isNestingMenu = inject<boolean>('isNestingMenu', false);
|
const isNestingMenu = inject<boolean>('isNestingMenu', false);
|
||||||
|
|
||||||
const itemsEl = shallowRef<HTMLElement>();
|
const itemsEl = useTemplateRef('itemsEl');
|
||||||
|
|
||||||
const items2 = ref<InnerMenuItem[]>();
|
const items2 = ref<InnerMenuItem[]>();
|
||||||
|
|
||||||
const child = shallowRef<InstanceType<typeof XChild>>();
|
const child = useTemplateRef('child');
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'up|k|shift+tab': {
|
'up|k|shift+tab': {
|
||||||
|
@ -260,7 +257,7 @@ watch(() => props.items, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const childMenu = ref<MenuItem[] | null>();
|
const childMenu = ref<MenuItem[] | null>();
|
||||||
const childTarget = shallowRef<HTMLElement | null>();
|
const childTarget = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
function closeChild() {
|
function closeChild() {
|
||||||
childMenu.value = null;
|
childMenu.value = null;
|
||||||
|
@ -435,7 +432,7 @@ onBeforeUnmount(() => {
|
||||||
.root {
|
.root {
|
||||||
&.center {
|
&.center {
|
||||||
> .menu {
|
> .menu {
|
||||||
.item {
|
> .item {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,7 +442,7 @@ onBeforeUnmount(() => {
|
||||||
> .menu {
|
> .menu {
|
||||||
min-width: 230px;
|
min-width: 230px;
|
||||||
|
|
||||||
.item {
|
> .item {
|
||||||
padding: 6px 20px;
|
padding: 6px 20px;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
@ -458,38 +455,36 @@ onBeforeUnmount(() => {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
> .menu {
|
> .menu {
|
||||||
|
padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
|
|
||||||
> .menuItems {
|
> .item {
|
||||||
padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0;
|
font-size: 1em;
|
||||||
|
padding: 12px 24px;
|
||||||
|
|
||||||
> .item {
|
&::before {
|
||||||
font-size: 1em;
|
width: calc(100% - 24px);
|
||||||
padding: 12px 24px;
|
border-radius: 12px;
|
||||||
|
|
||||||
&::before {
|
|
||||||
width: calc(100% - 24px);
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .icon {
|
|
||||||
margin-right: 14px;
|
|
||||||
width: 24px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .divider {
|
> .icon {
|
||||||
margin: 12px 0;
|
margin-right: 14px;
|
||||||
|
width: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .divider {
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
|
padding: 8px 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
@ -501,11 +496,6 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuItems {
|
|
||||||
padding: 8px 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch, ref, shallowRef, computed } from 'vue';
|
import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch, ref, useTemplateRef, computed } from 'vue';
|
||||||
import type { Keymap } from '@/utility/hotkey.js';
|
import type { Keymap } from '@/utility/hotkey.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { isTouchUsing } from '@/utility/touch.js';
|
import { isTouchUsing } from '@/utility/touch.js';
|
||||||
|
@ -100,8 +100,8 @@ const maxHeight = ref<number>();
|
||||||
const fixed = ref(false);
|
const fixed = ref(false);
|
||||||
const transformOrigin = ref('center');
|
const transformOrigin = ref('center');
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
const modalRootEl = shallowRef<HTMLElement>();
|
const modalRootEl = useTemplateRef('modalRootEl');
|
||||||
const content = shallowRef<HTMLElement>();
|
const content = useTemplateRef('content');
|
||||||
const zIndex = os.claimZIndex(props.zPriority);
|
const zIndex = os.claimZIndex(props.zPriority);
|
||||||
const useSendAnime = ref(false);
|
const useSendAnime = ref(false);
|
||||||
const type = computed<ModalTypes>(() => {
|
const type = computed<ModalTypes>(() => {
|
||||||
|
|
|
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, shallowRef, ref } from 'vue';
|
import { onMounted, onUnmounted, useTemplateRef, ref } from 'vue';
|
||||||
import MkModal from './MkModal.vue';
|
import MkModal from './MkModal.vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
@ -47,9 +47,9 @@ const emit = defineEmits<{
|
||||||
(event: 'esc'): void;
|
(event: 'esc'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = useTemplateRef('modal');
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const headerEl = shallowRef<HTMLElement>();
|
const headerEl = useTemplateRef('headerEl');
|
||||||
const bodyWidth = ref(0);
|
const bodyWidth = ref(0);
|
||||||
const bodyHeight = ref(0);
|
const bodyHeight = ref(0);
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, ref, shallowRef, watch, provide } from 'vue';
|
import { computed, inject, onMounted, ref, useTemplateRef, watch, provide } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { isLink } from '@@/js/is-link.js';
|
import { isLink } from '@@/js/is-link.js';
|
||||||
|
@ -271,14 +271,14 @@ if (noteViewInterruptors.length > 0) {
|
||||||
|
|
||||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const menuButton = shallowRef<HTMLElement>();
|
const menuButton = useTemplateRef('menuButton');
|
||||||
const renoteButton = shallowRef<HTMLElement>();
|
const renoteButton = useTemplateRef('renoteButton');
|
||||||
const renoteTime = shallowRef<HTMLElement>();
|
const renoteTime = useTemplateRef('renoteTime');
|
||||||
const reactButton = shallowRef<HTMLElement>();
|
const reactButton = useTemplateRef('reactButton');
|
||||||
const clipButton = shallowRef<HTMLElement>();
|
const clipButton = useTemplateRef('clipButton');
|
||||||
const appearNote = computed(() => getAppearNote(note.value));
|
const appearNote = computed(() => getAppearNote(note.value));
|
||||||
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
const galleryEl = useTemplateRef('galleryEl');
|
||||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value.text) : null);
|
||||||
|
|
|
@ -211,7 +211,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue';
|
import { computed, inject, onMounted, provide, ref, useTemplateRef } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { isLink } from '@@/js/is-link.js';
|
import { isLink } from '@@/js/is-link.js';
|
||||||
|
@ -290,14 +290,14 @@ if (noteViewInterruptors.length > 0) {
|
||||||
|
|
||||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLElement>();
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const menuButton = shallowRef<HTMLElement>();
|
const menuButton = useTemplateRef('menuButton');
|
||||||
const renoteButton = shallowRef<HTMLElement>();
|
const renoteButton = useTemplateRef('renoteButton');
|
||||||
const renoteTime = shallowRef<HTMLElement>();
|
const renoteTime = useTemplateRef('renoteTime');
|
||||||
const reactButton = shallowRef<HTMLElement>();
|
const reactButton = useTemplateRef('reactButton');
|
||||||
const clipButton = shallowRef<HTMLElement>();
|
const clipButton = useTemplateRef('clipButton');
|
||||||
const appearNote = computed(() => getAppearNote(note.value));
|
const appearNote = computed(() => getAppearNote(note.value));
|
||||||
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
const galleryEl = useTemplateRef('galleryEl');
|
||||||
const isMyRenote = $i && ($i.id === note.value.userId);
|
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
|
|
|
@ -32,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
|
@ -46,7 +46,7 @@ const props = defineProps<{
|
||||||
disableAutoLoad?: boolean;
|
disableAutoLoad?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const pagingComponent = useTemplateRef('pagingComponent');
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
pagingComponent,
|
pagingComponent,
|
||||||
|
|
|
@ -169,10 +169,10 @@ import { notePage } from '@/filters/note.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { signinRequired } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
notification: Misskey.entities.Notification;
|
notification: Misskey.entities.Notification;
|
||||||
|
|
|
@ -30,13 +30,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef } from 'vue';
|
import { ref, useTemplateRef } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import { notificationTypes } from '@@/js/const.js';
|
||||||
import MkSwitch from './MkSwitch.vue';
|
import MkSwitch from './MkSwitch.vue';
|
||||||
import MkInfo from './MkInfo.vue';
|
import MkInfo from './MkInfo.vue';
|
||||||
import MkButton from './MkButton.vue';
|
import MkButton from './MkButton.vue';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import { notificationTypes } from '@@/js/const.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
type TypesMap = Record<typeof notificationTypes[number], Ref<boolean>>;
|
type TypesMap = Record<typeof notificationTypes[number], Ref<boolean>>;
|
||||||
|
@ -52,7 +52,7 @@ const props = withDefaults(defineProps<{
|
||||||
excludeTypes: () => [],
|
excludeTypes: () => [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
const typesMap = notificationTypes.reduce((p, t) => ({ ...p, [t]: ref<boolean>(!props.excludeTypes.includes(t)) }), {} as TypesMap);
|
const typesMap = notificationTypes.reduce((p, t) => ({ ...p, [t]: ref<boolean>(!props.excludeTypes.includes(t)) }), {} as TypesMap);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, onActivated } from 'vue';
|
import { onUnmounted, onDeactivated, onMounted, computed, useTemplateRef, onActivated } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { notificationTypes } from '@@/js/const.js';
|
import type { notificationTypes } from '@@/js/const.js';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
|
@ -41,7 +41,7 @@ const props = defineProps<{
|
||||||
excludeTypes?: typeof notificationTypes[number][];
|
excludeTypes?: typeof notificationTypes[number][];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const pagingComponent = useTemplateRef('pagingComponent');
|
||||||
|
|
||||||
const pagination = computed(() => prefer.r.useGroupedNotifications.value ? {
|
const pagination = computed(() => prefer.r.useGroupedNotifications.value ? {
|
||||||
endpoint: 'i/notifications-grouped' as const,
|
endpoint: 'i/notifications-grouped' as const,
|
||||||
|
|
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, shallowRef, ref } from 'vue';
|
import { onMounted, onUnmounted, useTemplateRef, ref } from 'vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
@ -22,7 +22,7 @@ const props = withDefaults(defineProps<{
|
||||||
maxHeight: 200,
|
maxHeight: 200,
|
||||||
});
|
});
|
||||||
|
|
||||||
const content = shallowRef<HTMLElement>();
|
const content = useTemplateRef('content');
|
||||||
const omitted = ref(false);
|
const omitted = ref(false);
|
||||||
const ignoreOmit = ref(false);
|
const ignoreOmit = ref(false);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue