Compare commits
12 Commits
2025.3.2-b
...
view-trans
Author | SHA1 | Date | |
---|---|---|---|
![]() |
76dc7affe0 | ||
![]() |
1c9d9923f4 | ||
![]() |
c8db2043b5 | ||
![]() |
f40c5f27dd | ||
![]() |
386494dd6c | ||
![]() |
f5c946b44d | ||
![]() |
5fe23d3f69 | ||
![]() |
7d86efd087 | ||
![]() |
361f810da8 | ||
![]() |
be16622de2 | ||
![]() |
f930cd7842 | ||
![]() |
f1014bc7f7 |
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
@@ -24,6 +24,9 @@ updates:
|
|||||||
aws-sdk:
|
aws-sdk:
|
||||||
patterns:
|
patterns:
|
||||||
- "@aws-sdk/*"
|
- "@aws-sdk/*"
|
||||||
|
bull-board:
|
||||||
|
patterns:
|
||||||
|
- "@bull-board/*"
|
||||||
nestjs:
|
nestjs:
|
||||||
patterns:
|
patterns:
|
||||||
- "@nestjs/*"
|
- "@nestjs/*"
|
||||||
|
@@ -1,29 +1,23 @@
|
|||||||
## 2025.3.2
|
## 2025.3.2
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- セキュリティを強化するため、ジョブキューのダッシュボード(bull-board)統合が削除されました。
|
-
|
||||||
- Misskeyネイティブでダッシュボードを実装予定です
|
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: 設定の管理が強化されました
|
- Feat: 設定の管理が強化されました
|
||||||
- 自動でバックアップされるように
|
- 自動でバックアップされるように
|
||||||
- 任意の設定項目をデバイス間で同期できるように
|
- 任意の設定項目をデバイス間で同期できるように
|
||||||
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
|
||||||
- Enhance: プラグインの管理が強化されました
|
- Enhance: プラグインの管理が強化されました
|
||||||
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
||||||
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
||||||
- Enhance: CWの注釈テキストが入力されていない場合, Postボタンを非アクティブに
|
- Enhance: CWの注釈テキストが入力されていない場合, Postボタンを非アクティブに
|
||||||
- Enhance: CWを無効にした場合, 注釈テキストが最大入力文字数を超えていても投稿できるように
|
- Enhance: CWを無効にした場合, 注釈テキストが最大入力文字数を超えていても投稿できるように
|
||||||
- Enhance: テーマ設定画面のデザインを改善
|
- Enhance: テーマ設定画面のデザインを改善
|
||||||
- Enhance: 投稿フォームの設定メニューを改良
|
|
||||||
- 投稿フォームをリセットできるように
|
|
||||||
- 文字数カウントを復活
|
|
||||||
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正
|
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正
|
||||||
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
||||||
- Fix: 連合無しモードでも外部から照会可能だった問題を修正
|
|
||||||
|
|
||||||
## 2025.3.1
|
## 2025.3.1
|
||||||
|
|
||||||
|
@@ -273,6 +273,7 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド
|
|||||||
query?: Record<string, string>;
|
query?: Record<string, string>;
|
||||||
loginRequired?: boolean;
|
loginRequired?: boolean;
|
||||||
hash?: string;
|
hash?: string;
|
||||||
|
globalCacheKey?: string;
|
||||||
children?: RouteDef[];
|
children?: RouteDef[];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -698,7 +698,6 @@ 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"
|
||||||
@@ -1140,7 +1139,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: "Segueixes "
|
youFollowing: "Seguint"
|
||||||
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"
|
||||||
@@ -1191,7 +1190,7 @@ pastAnnouncements: "Informes passats"
|
|||||||
youHaveUnreadAnnouncements: "Tens informes per llegir."
|
youHaveUnreadAnnouncements: "Tens informes per llegir."
|
||||||
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
|
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
|
||||||
replies: "Respostes"
|
replies: "Respostes"
|
||||||
renotes: "Impulsos"
|
renotes: "Impulsar"
|
||||||
loadReplies: "Mostrar les respostes"
|
loadReplies: "Mostrar les respostes"
|
||||||
loadConversation: "Mostrar la conversació "
|
loadConversation: "Mostrar la conversació "
|
||||||
pinnedList: "Llista fixada"
|
pinnedList: "Llista fixada"
|
||||||
@@ -1327,18 +1326,7 @@ restore: "Restaurar "
|
|||||||
syncBetweenDevices: "Sincronització entre dispositius"
|
syncBetweenDevices: "Sincronització entre dispositius"
|
||||||
preferenceSyncConflictTitle: "Els valors de la configuració ja existeixen al dispositiu"
|
preferenceSyncConflictTitle: "Els valors de la configuració ja existeixen al dispositiu"
|
||||||
preferenceSyncConflictText: "Un element de la configuració amb sincronització activada desa els seus valors al servidor, però s'ha trobat un valor a la configuració desat al servidor per aquest element de la configuració. Quin valor us sobreescriure?"
|
preferenceSyncConflictText: "Un element de la configuració amb sincronització activada desa els seus valors al servidor, però s'ha trobat un valor a la configuració desat al servidor per aquest element de la configuració. Quin valor us sobreescriure?"
|
||||||
preferenceSyncConflictChoiceServer: "Valors de configuració del servidor"
|
|
||||||
preferenceSyncConflictChoiceDevice: "Punts d'ajustos del dispositiu "
|
|
||||||
preferenceSyncConflictChoiceCancel: "Cancel·lar l'activació de la sincronització "
|
|
||||||
paste: "Pegar"
|
|
||||||
emojiPalette: "Calaix d'emojis"
|
|
||||||
postForm: "Formulari de publicació"
|
postForm: "Formulari de publicació"
|
||||||
textCount: "Nombre de caràcters "
|
|
||||||
_emojiPalette:
|
|
||||||
palettes: "Calaixos d'emojis"
|
|
||||||
enableSyncBetweenDevicesForPalettes: "Activa la sincronització dels calaixos d'emojis entre dispositius"
|
|
||||||
paletteForMain: "Calaix d'emojis principal"
|
|
||||||
paletteForReaction: "Calaix d'emojis per reaccions"
|
|
||||||
_settings:
|
_settings:
|
||||||
driveBanner: "Pots gestionar i configurar el Disc, comprovar el seu ús i establir una configuració per a la càrrega d'arxius."
|
driveBanner: "Pots gestionar i configurar el Disc, comprovar el seu ús i establir una configuració per a la càrrega d'arxius."
|
||||||
pluginBanner: "Els complements poden fer-se servir per ampliar les funcionalitats del client. Els complements poden instal·lar-se, configurar-se individualment i gestionar-se."
|
pluginBanner: "Els complements poden fer-se servir per ampliar les funcionalitats del client. Els complements poden instal·lar-se, configurar-se individualment i gestionar-se."
|
||||||
@@ -1356,9 +1344,6 @@ _settings:
|
|||||||
preferencesBanner: "Pots configurar el comportament general del client segons les teves preferències."
|
preferencesBanner: "Pots configurar el comportament general del client segons les teves preferències."
|
||||||
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"
|
|
||||||
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."
|
||||||
@@ -2071,7 +2056,7 @@ _theme:
|
|||||||
hashtag: "Etiqueta"
|
hashtag: "Etiqueta"
|
||||||
mention: "Menció"
|
mention: "Menció"
|
||||||
mentionMe: "Mencions (jo)"
|
mentionMe: "Mencions (jo)"
|
||||||
renote: "Impulsar"
|
renote: "Renotar"
|
||||||
modalBg: "Fons del modal"
|
modalBg: "Fons del modal"
|
||||||
divider: "Divisor"
|
divider: "Divisor"
|
||||||
scrollbarHandle: "Maneta de la barra de desplaçament"
|
scrollbarHandle: "Maneta de la barra de desplaçament"
|
||||||
@@ -2513,7 +2498,7 @@ _notification:
|
|||||||
follow: "Segueix-me"
|
follow: "Segueix-me"
|
||||||
mention: "Menció"
|
mention: "Menció"
|
||||||
reply: "Respostes"
|
reply: "Respostes"
|
||||||
renote: "Impulsos"
|
renote: "Impulsar"
|
||||||
quote: "Citar"
|
quote: "Citar"
|
||||||
reaction: "Reaccions"
|
reaction: "Reaccions"
|
||||||
pollEnded: "Enquesta terminada"
|
pollEnded: "Enquesta terminada"
|
||||||
@@ -2523,13 +2508,12 @@ _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:
|
||||||
followBack: "També et segueix"
|
followBack: "També et segueix"
|
||||||
reply: "Respondre"
|
reply: "Respondre"
|
||||||
renote: "Impulsar"
|
renote: "Impulsos"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Mostrar sempre la columna principal"
|
alwaysShowMainColumn: "Mostrar sempre la columna principal"
|
||||||
columnAlign: "Alinea les columnes"
|
columnAlign: "Alinea les columnes"
|
||||||
|
@@ -49,7 +49,7 @@ pin: "An dein Profil anheften"
|
|||||||
unpin: "Von deinem Profil lösen"
|
unpin: "Von deinem Profil lösen"
|
||||||
copyContent: "Inhalt kopieren"
|
copyContent: "Inhalt kopieren"
|
||||||
copyLink: "Link kopieren"
|
copyLink: "Link kopieren"
|
||||||
copyRemoteLink: "Remote-Link kopieren"
|
copyRemoteLink: "Renote-Link kopieren"
|
||||||
copyLinkRenote: "Renote-Link kopieren"
|
copyLinkRenote: "Renote-Link kopieren"
|
||||||
delete: "Löschen"
|
delete: "Löschen"
|
||||||
deleteAndEdit: "Löschen und Bearbeiten"
|
deleteAndEdit: "Löschen und Bearbeiten"
|
||||||
|
@@ -698,7 +698,6 @@ 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"
|
||||||
@@ -1324,21 +1323,7 @@ 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"
|
|
||||||
_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."
|
||||||
@@ -1356,9 +1341,6 @@ _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."
|
||||||
@@ -2523,7 +2505,6 @@ _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:
|
||||||
@@ -2551,7 +2532,6 @@ _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"
|
||||||
|
20
locales/index.d.ts
vendored
20
locales/index.d.ts
vendored
@@ -2810,10 +2810,6 @@ export interface Locale extends ILocale {
|
|||||||
* コピー
|
* コピー
|
||||||
*/
|
*/
|
||||||
"copy": string;
|
"copy": string;
|
||||||
/**
|
|
||||||
* クリップボードにコピーされました
|
|
||||||
*/
|
|
||||||
"copiedToClipboard": string;
|
|
||||||
/**
|
/**
|
||||||
* メトリクス
|
* メトリクス
|
||||||
*/
|
*/
|
||||||
@@ -5350,10 +5346,6 @@ export interface Locale extends ILocale {
|
|||||||
* 投稿フォーム
|
* 投稿フォーム
|
||||||
*/
|
*/
|
||||||
"postForm": string;
|
"postForm": string;
|
||||||
/**
|
|
||||||
* 文字数
|
|
||||||
*/
|
|
||||||
"textCount": string;
|
|
||||||
"_emojiPalette": {
|
"_emojiPalette": {
|
||||||
/**
|
/**
|
||||||
* パレット
|
* パレット
|
||||||
@@ -5441,14 +5433,6 @@ export interface Locale extends ILocale {
|
|||||||
* タイムラインとノート
|
* タイムラインとノート
|
||||||
*/
|
*/
|
||||||
"timelineAndNote": string;
|
"timelineAndNote": string;
|
||||||
/**
|
|
||||||
* 全てのテキスト要素を選択可能にする
|
|
||||||
*/
|
|
||||||
"makeEveryTextElementsSelectable": string;
|
|
||||||
/**
|
|
||||||
* 有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。
|
|
||||||
*/
|
|
||||||
"makeEveryTextElementsSelectable_description": string;
|
|
||||||
};
|
};
|
||||||
"_preferencesProfile": {
|
"_preferencesProfile": {
|
||||||
/**
|
/**
|
||||||
@@ -9793,10 +9777,6 @@ export interface Locale extends ILocale {
|
|||||||
* ログイン
|
* ログイン
|
||||||
*/
|
*/
|
||||||
"login": string;
|
"login": string;
|
||||||
/**
|
|
||||||
* アクセストークンの作成
|
|
||||||
*/
|
|
||||||
"createToken": string;
|
|
||||||
/**
|
/**
|
||||||
* 通知のテスト
|
* 通知のテスト
|
||||||
*/
|
*/
|
||||||
|
@@ -698,7 +698,6 @@ 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"
|
||||||
@@ -974,7 +973,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: "Si tratta di un profilo creato e gestito automaticamente dal sistema."
|
isSystemAccount: "Questi profili vengono creati e gestiti automaticamente dal sistema"
|
||||||
typeToConfirm: "Digita {x} per continuare"
|
typeToConfirm: "Digita {x} per continuare"
|
||||||
deleteAccount: "Eliminazione profilo"
|
deleteAccount: "Eliminazione profilo"
|
||||||
document: "Documentazione"
|
document: "Documentazione"
|
||||||
@@ -1324,21 +1323,7 @@ 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"
|
|
||||||
_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."
|
||||||
@@ -1356,9 +1341,6 @@ _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."
|
||||||
@@ -2523,7 +2505,6 @@ _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:
|
||||||
@@ -2551,7 +2532,6 @@ _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"
|
||||||
|
@@ -698,7 +698,6 @@ userSaysSomethingAbout: "{name}が「{word}」について何かを言いまし
|
|||||||
makeActive: "アクティブにする"
|
makeActive: "アクティブにする"
|
||||||
display: "表示"
|
display: "表示"
|
||||||
copy: "コピー"
|
copy: "コピー"
|
||||||
copiedToClipboard: "クリップボードにコピーされました"
|
|
||||||
metrics: "メトリクス"
|
metrics: "メトリクス"
|
||||||
overview: "概要"
|
overview: "概要"
|
||||||
logs: "ログ"
|
logs: "ログ"
|
||||||
@@ -1333,7 +1332,6 @@ preferenceSyncConflictChoiceCancel: "同期の有効化をキャンセル"
|
|||||||
paste: "ペースト"
|
paste: "ペースト"
|
||||||
emojiPalette: "絵文字パレット"
|
emojiPalette: "絵文字パレット"
|
||||||
postForm: "投稿フォーム"
|
postForm: "投稿フォーム"
|
||||||
textCount: "文字数"
|
|
||||||
|
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "パレット"
|
palettes: "パレット"
|
||||||
@@ -1359,8 +1357,6 @@ _settings:
|
|||||||
appearanceBanner: "好みに応じた、クライアントの見た目・表示方法に関する設定が行えます。"
|
appearanceBanner: "好みに応じた、クライアントの見た目・表示方法に関する設定が行えます。"
|
||||||
soundsBanner: "クライアントで再生するサウンドの設定が行えます。"
|
soundsBanner: "クライアントで再生するサウンドの設定が行えます。"
|
||||||
timelineAndNote: "タイムラインとノート"
|
timelineAndNote: "タイムラインとノート"
|
||||||
makeEveryTextElementsSelectable: "全てのテキスト要素を選択可能にする"
|
|
||||||
makeEveryTextElementsSelectable_description: "有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。"
|
|
||||||
|
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "プロファイル名"
|
profileName: "プロファイル名"
|
||||||
@@ -2588,7 +2584,6 @@ _notification:
|
|||||||
achievementEarned: "実績の獲得"
|
achievementEarned: "実績の獲得"
|
||||||
exportCompleted: "エクスポートが完了した"
|
exportCompleted: "エクスポートが完了した"
|
||||||
login: "ログイン"
|
login: "ログイン"
|
||||||
createToken: "アクセストークンの作成"
|
|
||||||
test: "通知のテスト"
|
test: "通知のテスト"
|
||||||
app: "連携アプリからの通知"
|
app: "連携アプリからの通知"
|
||||||
|
|
||||||
|
@@ -698,7 +698,6 @@ userSaysSomethingAbout: "{name} 说了关于「{word}」的什么"
|
|||||||
makeActive: "启用"
|
makeActive: "启用"
|
||||||
display: "显示"
|
display: "显示"
|
||||||
copy: "复制"
|
copy: "复制"
|
||||||
copiedToClipboard: "已复制到剪贴板"
|
|
||||||
metrics: "指标"
|
metrics: "指标"
|
||||||
overview: "概览"
|
overview: "概览"
|
||||||
logs: "日志"
|
logs: "日志"
|
||||||
@@ -747,7 +746,7 @@ confirmToUnclipAlreadyClippedNote: "本帖已包含在便签 \"{name}\" 里。
|
|||||||
public: "公开"
|
public: "公开"
|
||||||
private: "私密"
|
private: "私密"
|
||||||
i18nInfo: "Misskey 已经被志愿者们翻译成了各种语言。如果你也有兴趣,可以通过 {link} 帮助翻译。"
|
i18nInfo: "Misskey 已经被志愿者们翻译成了各种语言。如果你也有兴趣,可以通过 {link} 帮助翻译。"
|
||||||
manageAccessTokens: "管理访问令牌"
|
manageAccessTokens: "管理 Access Tokens"
|
||||||
accountInfo: "账户信息"
|
accountInfo: "账户信息"
|
||||||
notesCount: "帖子数量"
|
notesCount: "帖子数量"
|
||||||
repliesCount: "回复数量"
|
repliesCount: "回复数量"
|
||||||
@@ -1333,7 +1332,6 @@ preferenceSyncConflictChoiceCancel: "取消同步"
|
|||||||
paste: "粘贴"
|
paste: "粘贴"
|
||||||
emojiPalette: "表情符号调色板"
|
emojiPalette: "表情符号调色板"
|
||||||
postForm: "投稿窗口"
|
postForm: "投稿窗口"
|
||||||
textCount: "字数"
|
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "调色板"
|
palettes: "调色板"
|
||||||
enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步"
|
enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步"
|
||||||
@@ -1341,24 +1339,13 @@ _emojiPalette:
|
|||||||
paletteForReaction: "回应用调色板"
|
paletteForReaction: "回应用调色板"
|
||||||
_settings:
|
_settings:
|
||||||
driveBanner: "可在此管理和设置网盘、确认使用量及配置上传文件的设置。"
|
driveBanner: "可在此管理和设置网盘、确认使用量及配置上传文件的设置。"
|
||||||
pluginBanner: "使用插件可以扩展客户端的功能。可以在此安装、单独管理插件。"
|
|
||||||
notificationsBanner: "可在此设置从服务器接收的通知的种类和范围,以及推送通知的设置。"
|
|
||||||
api: "API"
|
api: "API"
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
serviceConnection: "连接服务"
|
|
||||||
serviceConnectionBanner: "可在此管理用于连接外部应用或服务的访问令牌及 Webhook。"
|
|
||||||
accountData: "账户数据"
|
|
||||||
accountDataBanner: "可在此导入或导出帐户数据的存档。"
|
|
||||||
muteAndBlockBanner: "可在此设置隐藏内容,或限制指定用户能进行的操作。"
|
|
||||||
accessibilityBanner: "可在此设置客户端的显示及动态效果等辅助设置。"
|
|
||||||
privacyBanner: "可在此设置如内容可见性、可发现性、批准关注请求等账户隐私设置。"
|
privacyBanner: "可在此设置如内容可见性、可发现性、批准关注请求等账户隐私设置。"
|
||||||
securityBanner: "可在此设置如密码、登入方式、验证器、Passkey 等账户安全性设置。"
|
securityBanner: "可在此设置如密码、登入方式、验证器、Passkey 等账户安全性设置。"
|
||||||
preferencesBanner: "可在此设置客户端的整体运作行为。"
|
preferencesBanner: "可在此设置客户端的整体运作行为。"
|
||||||
appearanceBanner: "可在此设置客户端的外观及显示方式。"
|
appearanceBanner: "可在此设置客户端的外观及显示方式。"
|
||||||
soundsBanner: "可在此设置客户端播放的声音。"
|
soundsBanner: "可在此设置客户端播放的声音。"
|
||||||
timelineAndNote: "时间线和帖子"
|
|
||||||
makeEveryTextElementsSelectable: "使所有的文字均可选择"
|
|
||||||
makeEveryTextElementsSelectable_description: "若开启,在某些情况下可能降低用户体验。"
|
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "配置名"
|
profileName: "配置名"
|
||||||
profileNameDescription: "请指定用于识别此设备的名称"
|
profileNameDescription: "请指定用于识别此设备的名称"
|
||||||
@@ -2523,7 +2510,6 @@ _notification:
|
|||||||
achievementEarned: "取得的成就"
|
achievementEarned: "取得的成就"
|
||||||
exportCompleted: "已完成导出"
|
exportCompleted: "已完成导出"
|
||||||
login: "登录"
|
login: "登录"
|
||||||
createToken: "创建访问令牌"
|
|
||||||
test: "测试通知"
|
test: "测试通知"
|
||||||
app: "关联应用的通知"
|
app: "关联应用的通知"
|
||||||
_actions:
|
_actions:
|
||||||
|
@@ -698,7 +698,6 @@ userSaysSomethingAbout: "{name} 說了一些關於「{word}」的話"
|
|||||||
makeActive: "啟用"
|
makeActive: "啟用"
|
||||||
display: "檢視"
|
display: "檢視"
|
||||||
copy: "複製"
|
copy: "複製"
|
||||||
copiedToClipboard: "已複製到剪貼簿"
|
|
||||||
metrics: "指標"
|
metrics: "指標"
|
||||||
overview: "概覽"
|
overview: "概覽"
|
||||||
logs: "日誌"
|
logs: "日誌"
|
||||||
@@ -1333,7 +1332,6 @@ preferenceSyncConflictChoiceCancel: "取消啟用同步"
|
|||||||
paste: "貼上"
|
paste: "貼上"
|
||||||
emojiPalette: "表情符號調色盤"
|
emojiPalette: "表情符號調色盤"
|
||||||
postForm: "發文視窗"
|
postForm: "發文視窗"
|
||||||
textCount: "字數"
|
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "調色盤"
|
palettes: "調色盤"
|
||||||
enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化"
|
enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化"
|
||||||
@@ -1357,8 +1355,6 @@ _settings:
|
|||||||
appearanceBanner: "您可以根據喜好設定與用戶端外觀和顯示方式相關的設定。"
|
appearanceBanner: "您可以根據喜好設定與用戶端外觀和顯示方式相關的設定。"
|
||||||
soundsBanner: "您可以調整用戶端播放的聲音設定。"
|
soundsBanner: "您可以調整用戶端播放的聲音設定。"
|
||||||
timelineAndNote: "時間軸及貼文"
|
timelineAndNote: "時間軸及貼文"
|
||||||
makeEveryTextElementsSelectable: "允許選取所有文字"
|
|
||||||
makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。"
|
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "設定檔案名稱"
|
profileName: "設定檔案名稱"
|
||||||
profileNameDescription: "設定一個名稱來識別此裝置。"
|
profileNameDescription: "設定一個名稱來識別此裝置。"
|
||||||
@@ -2523,7 +2519,6 @@ _notification:
|
|||||||
achievementEarned: "獲得成就"
|
achievementEarned: "獲得成就"
|
||||||
exportCompleted: "已完成匯出。"
|
exportCompleted: "已完成匯出。"
|
||||||
login: "登入"
|
login: "登入"
|
||||||
createToken: "建立存取權杖"
|
|
||||||
test: "通知測試"
|
test: "通知測試"
|
||||||
app: "應用程式通知"
|
app: "應用程式通知"
|
||||||
_actions:
|
_actions:
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.3.2-beta.4",
|
"version": "2025.3.2-beta.1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@@ -69,6 +69,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.749.0",
|
"@aws-sdk/client-s3": "3.749.0",
|
||||||
"@aws-sdk/lib-storage": "3.749.0",
|
"@aws-sdk/lib-storage": "3.749.0",
|
||||||
|
"@bull-board/api": "6.7.7",
|
||||||
|
"@bull-board/fastify": "6.7.7",
|
||||||
|
"@bull-board/ui": "6.7.7",
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@fastify/accepts": "5.0.2",
|
"@fastify/accepts": "5.0.2",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cookie": "11.0.2",
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
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';
|
||||||
@@ -87,7 +86,6 @@ 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, MiMeta } from '@/models/_.js';
|
import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository } 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,9 +42,6 @@ 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,
|
||||||
|
|
||||||
@@ -105,11 +102,6 @@ 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 {
|
||||||
@@ -181,11 +173,6 @@ 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;
|
||||||
@@ -278,11 +265,6 @@ 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;
|
||||||
@@ -372,11 +354,6 @@ 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({
|
||||||
@@ -421,11 +398,6 @@ 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;
|
||||||
@@ -510,11 +482,6 @@ 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;
|
||||||
@@ -597,11 +564,6 @@ 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']),
|
||||||
@@ -632,11 +594,6 @@ 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(),
|
||||||
@@ -677,11 +634,6 @@ 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({
|
||||||
@@ -709,11 +661,6 @@ 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({
|
||||||
@@ -727,11 +674,6 @@ 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({
|
||||||
@@ -746,11 +688,6 @@ 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,
|
||||||
@@ -768,11 +705,6 @@ 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) {
|
||||||
@@ -794,11 +726,6 @@ 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.
|
||||||
|
|
||||||
@@ -825,11 +752,6 @@ 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 { MiMeta, UsersRepository } from '@/models/_.js';
|
import type { 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,9 +26,6 @@ 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,
|
||||||
|
|
||||||
@@ -69,11 +66,6 @@ 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',
|
||||||
@@ -83,11 +75,6 @@ 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: [{
|
||||||
@@ -99,11 +86,6 @@ 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() };
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,11 +99,6 @@ 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(),
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import cors from '@fastify/cors';
|
import cors from '@fastify/cors';
|
||||||
import multipart from '@fastify/multipart';
|
import multipart from '@fastify/multipart';
|
||||||
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import { ModuleRef } from '@nestjs/core';
|
import { ModuleRef } from '@nestjs/core';
|
||||||
import { AuthenticationResponseJSON } from '@simplewebauthn/types';
|
import { AuthenticationResponseJSON } from '@simplewebauthn/types';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
@@ -56,6 +57,8 @@ export class ApiServerService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fastify.register(fastifyCookie, {});
|
||||||
|
|
||||||
// Prevent cache
|
// Prevent cache
|
||||||
fastify.addHook('onRequest', (request, reply, done) => {
|
fastify.addHook('onRequest', (request, reply, done) => {
|
||||||
reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
|
reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
|
||||||
|
@@ -7,12 +7,16 @@ import { randomUUID } from 'node:crypto';
|
|||||||
import { dirname } from 'node:path';
|
import { dirname } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { createBullBoard } from '@bull-board/api';
|
||||||
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter.js';
|
||||||
|
import { FastifyAdapter as BullBoardFastifyAdapter } from '@bull-board/fastify';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import pug from 'pug';
|
import pug from 'pug';
|
||||||
import { In, IsNull } from 'typeorm';
|
import { In, IsNull } from 'typeorm';
|
||||||
import fastifyStatic from '@fastify/static';
|
import fastifyStatic from '@fastify/static';
|
||||||
import fastifyView from '@fastify/view';
|
import fastifyView from '@fastify/view';
|
||||||
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import fastifyProxy from '@fastify/http-proxy';
|
import fastifyProxy from '@fastify/http-proxy';
|
||||||
import vary from 'vary';
|
import vary from 'vary';
|
||||||
import htmlSafeJsonStringify from 'htmlescape';
|
import htmlSafeJsonStringify from 'htmlescape';
|
||||||
@@ -217,6 +221,64 @@ export class ClientServerService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||||
|
fastify.register(fastifyCookie, {});
|
||||||
|
|
||||||
|
//#region Bull Dashboard
|
||||||
|
const bullBoardPath = '/queue';
|
||||||
|
|
||||||
|
// Authenticate
|
||||||
|
fastify.addHook('onRequest', async (request, reply) => {
|
||||||
|
if (request.routeOptions.url == null) {
|
||||||
|
reply.code(404).send('Not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %71ueueとかでリクエストされたら困るため
|
||||||
|
const url = decodeURI(request.routeOptions.url);
|
||||||
|
if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) {
|
||||||
|
if (!url.startsWith(bullBoardPath + '/static/')) {
|
||||||
|
reply.header('Cache-Control', 'private, max-age=0, must-revalidate');
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = request.cookies.token;
|
||||||
|
if (token == null) {
|
||||||
|
reply.code(401).send('Login required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const user = await this.usersRepository.findOneBy({ token });
|
||||||
|
if (user == null) {
|
||||||
|
reply.code(403).send('No such user');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isAdministrator = await this.roleService.isAdministrator(user);
|
||||||
|
if (!isAdministrator) {
|
||||||
|
reply.code(403).send('Access denied');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const bullBoardServerAdapter = new BullBoardFastifyAdapter();
|
||||||
|
|
||||||
|
createBullBoard({
|
||||||
|
queues: [
|
||||||
|
this.systemQueue,
|
||||||
|
this.endedPollNotificationQueue,
|
||||||
|
this.deliverQueue,
|
||||||
|
this.inboxQueue,
|
||||||
|
this.dbQueue,
|
||||||
|
this.relationshipQueue,
|
||||||
|
this.objectStorageQueue,
|
||||||
|
this.userWebhookDeliverQueue,
|
||||||
|
this.systemWebhookDeliverQueue,
|
||||||
|
].map(q => new BullMQAdapter(q)),
|
||||||
|
serverAdapter: bullBoardServerAdapter,
|
||||||
|
});
|
||||||
|
|
||||||
|
bullBoardServerAdapter.setBasePath(bullBoardPath);
|
||||||
|
(fastify.register as any)(bullBoardServerAdapter.registerPlugin(), { prefix: bullBoardPath });
|
||||||
|
//#endregion
|
||||||
|
|
||||||
fastify.register(fastifyView, {
|
fastify.register(fastifyView, {
|
||||||
root: _dirname + '/views',
|
root: _dirname + '/views',
|
||||||
engine: {
|
engine: {
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { channel, clip, galleryPost, page, play, post, signup, simpleGet, uploadFile } from '../utils.js';
|
import { channel, clip, cookie, galleryPost, page, play, post, signup, simpleGet, uploadFile } from '../utils.js';
|
||||||
import type { SimpleGetResponse } from '../utils.js';
|
import type { SimpleGetResponse } from '../utils.js';
|
||||||
import type * as misskey from 'misskey-js';
|
import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
@@ -156,20 +156,20 @@ describe('Webリソース', () => {
|
|||||||
|
|
||||||
describe(' has entry such ', () => {
|
describe(' has entry such ', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
post(alice, { text: '**a**' });
|
post(alice, { text: "**a**" })
|
||||||
});
|
});
|
||||||
|
|
||||||
test('MFMを含まない。', async () => {
|
test('MFMを含まない。', async () => {
|
||||||
const content = await simpleGet(path(alice.username), '*/*', undefined, res => res.text());
|
const content = await simpleGet(path(alice.username), "*/*", undefined, res => res.text());
|
||||||
const _body: unknown = content.body;
|
const _body: unknown = content.body;
|
||||||
// JSONフィードのときは改めて文字列化する
|
// JSONフィードのときは改めて文字列化する
|
||||||
const body: string = typeof (_body) === 'object' ? JSON.stringify(_body) : _body as string;
|
const body: string = typeof (_body) === "object" ? JSON.stringify(_body) : _body as string;
|
||||||
|
|
||||||
if (body.includes('**a**')) {
|
if (body.includes("**a**")) {
|
||||||
throw new Error('MFM shouldn\'t be included');
|
throw new Error("MFM shouldn't be included");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.each([{ path: '/api/foo' }])('$path', ({ path }) => {
|
describe.each([{ path: '/api/foo' }])('$path', ({ path }) => {
|
||||||
@@ -180,6 +180,24 @@ describe('Webリソース', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.each([{ path: '/queue' }])('$path', ({ path }) => {
|
||||||
|
test('はログインしないとGETできない。', async () => await notOk({
|
||||||
|
path,
|
||||||
|
status: 401,
|
||||||
|
}));
|
||||||
|
|
||||||
|
test('はadminでなければGETできない。', async () => await notOk({
|
||||||
|
path,
|
||||||
|
cookie: cookie(bob),
|
||||||
|
status: 403,
|
||||||
|
}));
|
||||||
|
|
||||||
|
test('はadminならGETできる。', async () => await ok({
|
||||||
|
path,
|
||||||
|
cookie: cookie(alice),
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe.each([{ path: '/streaming' }])('$path', ({ path }) => {
|
describe.each([{ path: '/streaming' }])('$path', ({ path }) => {
|
||||||
test('はGETできない。', async () => await notOk({
|
test('はGETできない。', async () => await notOk({
|
||||||
path,
|
path,
|
||||||
|
@@ -35,7 +35,7 @@ export type SystemWebhookPayload = {
|
|||||||
createdAt: string;
|
createdAt: string;
|
||||||
type: string;
|
type: string;
|
||||||
body: any;
|
body: any;
|
||||||
};
|
}
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
export const port = config.port;
|
export const port = config.port;
|
||||||
@@ -45,6 +45,10 @@ export const host = new URL(config.url).host;
|
|||||||
export const WEBHOOK_HOST = 'http://localhost:15080';
|
export const WEBHOOK_HOST = 'http://localhost:15080';
|
||||||
export const WEBHOOK_PORT = 15080;
|
export const WEBHOOK_PORT = 15080;
|
||||||
|
|
||||||
|
export const cookie = (me: UserToken): string => {
|
||||||
|
return `token=${me.token};`;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiRequest<E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req'] = misskey.Endpoints[E]['req']> = {
|
export type ApiRequest<E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req'] = misskey.Endpoints[E]['req']> = {
|
||||||
endpoint: E,
|
endpoint: E,
|
||||||
parameters: P,
|
parameters: P,
|
||||||
|
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="notFoundImageUrl" draggable="false"/>
|
<img :src="notFoundImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
<div>{{ i18n.ts.notFoundDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,5 +20,5 @@ import { i18n } from '@/i18n.js';
|
|||||||
|
|
||||||
const serverMetadata = inject(DI.serverMetadata)!;
|
const serverMetadata = inject(DI.serverMetadata)!;
|
||||||
|
|
||||||
const notFoundImageUrl = computed(() => serverMetadata.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
const notFoundImageUrl = computed(() => serverMetadata?.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
||||||
</script>
|
</script>
|
||||||
|
@@ -64,12 +64,12 @@ initialize({
|
|||||||
initLocalStorage();
|
initLocalStorage();
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
import('../src/components/index.js'),
|
import('../src/components'),
|
||||||
import('../src/directives/index.js'),
|
import('../src/directives'),
|
||||||
import('../src/widgets/index.js'),
|
import('../src/widgets'),
|
||||||
import('../src/theme.js'),
|
import('../src/theme'),
|
||||||
import('../src/preferences.js'),
|
import('../src/preferences'),
|
||||||
import('../src/os.js'),
|
import('../src/os'),
|
||||||
]).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;
|
||||||
|
@@ -26,6 +26,8 @@ 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';
|
||||||
|
|
||||||
@@ -232,10 +234,6 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefer.s.makeEveryTextElementsSelectable) {
|
|
||||||
document.documentElement.classList.add('forceSelectableAll');
|
|
||||||
}
|
|
||||||
|
|
||||||
//#region Fetch user
|
//#region Fetch user
|
||||||
if ($i && $i.token) {
|
if ($i && $i.token) {
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
@@ -265,6 +263,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
@@ -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.js';
|
import { mainRouter } from '@/router/main.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,8 +201,6 @@ 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,9 +100,10 @@ const emit = defineEmits<{
|
|||||||
(ev: 'resolved', reportId: string): void;
|
(ev: 'resolved', reportId: string): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const targetRouter = createRouter(`/admin/user/${props.report.targetUserId}`);
|
const routerFactory = useRouterFactory();
|
||||||
|
const targetRouter = routerFactory(`/admin/user/${props.report.targetUserId}`);
|
||||||
targetRouter.init();
|
targetRouter.init();
|
||||||
const reporterRouter = createRouter(`/admin/user/${props.report.reporterId}`);
|
const reporterRouter = routerFactory(`/admin/user/${props.report.reporterId}`);
|
||||||
reporterRouter.init();
|
reporterRouter.init();
|
||||||
|
|
||||||
const moderationNote = ref(props.report.moderationNote ?? '');
|
const moderationNote = ref(props.report.moderationNote ?? '');
|
||||||
@@ -134,7 +135,7 @@ function forward() {
|
|||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
icon: 'ti ti-hash',
|
icon: 'ti ti-id',
|
||||||
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, useTemplateRef } from 'vue';
|
import { ref, shallowRef } 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 = useTemplateRef('uiWindow');
|
const uiWindow = shallowRef<InstanceType<typeof MkWindow>>();
|
||||||
const comment = ref(props.initialComment ?? '');
|
const comment = ref(props.initialComment ?? '');
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
|
@@ -8,10 +8,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, shallowRef } from 'vue';
|
||||||
import isChromatic from 'chromatic/isChromatic';
|
import isChromatic from 'chromatic/isChromatic';
|
||||||
|
|
||||||
const canvasEl = useTemplateRef('canvasEl');
|
const canvasEl = shallowRef<HTMLCanvasElement>();
|
||||||
|
|
||||||
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, useTemplateRef } from 'vue';
|
import { onMounted, shallowRef } 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
const modal = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
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 { useTemplateRef } from 'vue';
|
import { shallowRef } 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 = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
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, useTemplateRef, computed, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
import { markRaw, ref, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
|
|
||||||
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, useTemplateRef } from 'vue';
|
import { nextTick, onMounted, shallowRef } 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 = useTemplateRef('el');
|
const el = shallowRef<HTMLElement | null>(null);
|
||||||
const ripples = useTemplateRef('ripples');
|
const ripples = shallowRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
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, useTemplateRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
|
import { ref, shallowRef, 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 = useTemplateRef('captchaEl');
|
const captchaEl = shallowRef<HTMLDivElement | undefined>();
|
||||||
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);
|
||||||
|
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFound }}</div>
|
<div>{{ i18n.ts.notFound }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -19,9 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
|
||||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
|
@@ -45,8 +45,12 @@ export type ChartSrc =
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
/* eslint-disable id-denylist --
|
||||||
import { onMounted, ref, useTemplateRef, watch } from 'vue';
|
Chart.js has a `data` attribute in most chart definitions, which triggers the
|
||||||
|
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';
|
||||||
@@ -92,7 +96,7 @@ const props = withDefaults(defineProps<{
|
|||||||
nowForChromatic: undefined,
|
nowForChromatic: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const legendEl = useTemplateRef('legendEl');
|
const legendEl = shallowRef<InstanceType<typeof MkChartLegend>>();
|
||||||
|
|
||||||
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);
|
||||||
@@ -130,7 +134,7 @@ let chartData: {
|
|||||||
bytes?: boolean;
|
bytes?: boolean;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
||||||
const chartEl = useTemplateRef('chartEl');
|
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
const getDate = (ago: number) => {
|
const getDate = (ago: number) => {
|
||||||
@@ -845,7 +849,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,6 +48,7 @@ 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, useTemplateRef, nextTick } from 'vue';
|
import { ref, watch, toRefs, shallowRef, 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 = useTemplateRef('inputEl');
|
const inputEl = shallowRef<HTMLTextAreaElement>();
|
||||||
|
|
||||||
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, useTemplateRef, toRefs } from 'vue';
|
import { ref, shallowRef, 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 = useTemplateRef('inputEl');
|
const inputEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
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, useTemplateRef, watch } from 'vue';
|
import { onMounted, onUnmounted, ref, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
const contentEl = useTemplateRef('contentEl');
|
const contentEl = shallowRef<HTMLElement>();
|
||||||
const headerEl = useTemplateRef('headerEl');
|
const headerEl = shallowRef<HTMLElement>();
|
||||||
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, useTemplateRef, ref } from 'vue';
|
import { onMounted, onBeforeUnmount, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
|
|
||||||
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, useTemplateRef, ref } from 'vue';
|
import { onMounted, shallowRef, 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 = useTemplateRef('dialogEl');
|
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
const imgEl = useTemplateRef('imgEl');
|
const imgEl = shallowRef<HTMLImageElement>();
|
||||||
let cropper: Cropper | null = null;
|
let cropper: Cropper | null = null;
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
|
|
||||||
|
@@ -57,7 +57,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 { useTemplateRef } from 'vue';
|
import { shallowRef } 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';
|
||||||
@@ -73,7 +73,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialogEl = useTemplateRef('dialogEl');
|
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
|
@@ -25,8 +25,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<i v-else-if="type === 'question'" :class="$style.iconInner" class="ti ti-help-circle"></i>
|
<i v-else-if="type === 'question'" :class="$style.iconInner" class="ti ti-help-circle"></i>
|
||||||
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
|
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
|
||||||
</div>
|
</div>
|
||||||
<header v-if="title" :class="$style.title" class="_selectable"><Mfm :text="title"/></header>
|
<header v-if="title" :class="$style.title"><Mfm :text="title"/></header>
|
||||||
<div v-if="text" :class="$style.text" class="_selectable"><Mfm :text="text"/></div>
|
<div v-if="text" :class="$style.text"><Mfm :text="text"/></div>
|
||||||
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown">
|
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" :autocomplete="input.autocomplete" @keydown="onInputKeydown">
|
||||||
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
|
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
|
||||||
<template #caption>
|
<template #caption>
|
||||||
@@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, useTemplateRef, computed } from 'vue';
|
import { ref, shallowRef, 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 = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
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.js';
|
import { useRouter } from '@/router/supplier.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-hash',
|
icon: 'ti ti-id',
|
||||||
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, useTemplateRef, watch } from 'vue';
|
import { nextTick, onActivated, onBeforeUnmount, onMounted, ref, shallowRef, 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 = useTemplateRef('loadMoreFiles');
|
const loadMoreFiles = shallowRef<InstanceType<typeof MkButton>>();
|
||||||
const fileInput = useTemplateRef('fileInput');
|
const fileInput = shallowRef<HTMLInputElement>();
|
||||||
|
|
||||||
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, useTemplateRef } from 'vue';
|
import { ref, shallowRef } 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 = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
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 { useTemplateRef, ref, computed, nextTick, onMounted, onDeactivated, onUnmounted } from 'vue';
|
import { shallowRef, 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 = useTemplateRef('dialogEl');
|
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
@@ -194,13 +194,14 @@ function generate() {
|
|||||||
|
|
||||||
function doCopy() {
|
function doCopy() {
|
||||||
copyToClipboard(result.value);
|
copyToClipboard(result.value);
|
||||||
|
os.success();
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region プレビューのリサイズ
|
//#region プレビューのリサイズ
|
||||||
const resizerRootEl = useTemplateRef('resizerRootEl');
|
const resizerRootEl = shallowRef<HTMLDivElement>();
|
||||||
const iframeLoading = ref(true);
|
const iframeLoading = ref(true);
|
||||||
const iframeEl = useTemplateRef('iframeEl');
|
const iframeEl = shallowRef<HTMLIFrameElement>();
|
||||||
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, useTemplateRef, computed, watch, onMounted } from 'vue';
|
import { ref, shallowRef, 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 = useTemplateRef('searchEl');
|
const searchEl = shallowRef<HTMLInputElement>();
|
||||||
const emojisEl = useTemplateRef('emojisEl');
|
const emojisEl = shallowRef<HTMLDivElement>();
|
||||||
|
|
||||||
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 { useTemplateRef } from 'vue';
|
import { shallowRef } 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 = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const picker = useTemplateRef('picker');
|
const picker = shallowRef<InstanceType<typeof MkEmojiPicker>>();
|
||||||
|
|
||||||
function chosen(emoji: string) {
|
function chosen(emoji: string) {
|
||||||
emit('done', emoji);
|
emit('done', emoji);
|
||||||
|
@@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef, ref } from 'vue';
|
import { shallowRef, 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 = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
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, useTemplateRef, watch } from 'vue';
|
import { onMounted, ref, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
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, useTemplateRef } from 'vue';
|
import { nextTick, onMounted, ref, shallowRef } 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
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);
|
||||||
|
@@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<div v-else class="_fullinfo">
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
@@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, useTemplateRef } from 'vue';
|
import { reactive, shallowRef } 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 = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
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, useTemplateRef, ref } from 'vue';
|
import { onMounted, nextTick, watch, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement | null>(null);
|
||||||
const chartEl = useTemplateRef('chartEl');
|
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
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);
|
||||||
|
@@ -11,27 +11,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
@touchmove.passive="touchMove"
|
@touchmove.passive="touchMove"
|
||||||
@touchend.passive="touchEnd"
|
@touchend.passive="touchEnd"
|
||||||
>
|
>
|
||||||
<Transition
|
|
||||||
:class="[$style.transitionChildren, { [$style.swiping]: isSwipingForClass }]"
|
|
||||||
:enterActiveClass="$style.swipeAnimation_enterActive"
|
|
||||||
:leaveActiveClass="$style.swipeAnimation_leaveActive"
|
|
||||||
:enterFromClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_enterFrom : $style.swipeAnimationRight_enterFrom"
|
|
||||||
:leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo"
|
|
||||||
:style="`--swipe: ${pullDistance}px;`"
|
|
||||||
>
|
|
||||||
<!-- 【注意】slot内の最上位要素に動的にkeyを設定すること -->
|
<!-- 【注意】slot内の最上位要素に動的にkeyを設定すること -->
|
||||||
<!-- 各最上位要素にユニークなkeyの指定がないとTransitionがうまく動きません -->
|
<!-- 各最上位要素にユニークなkeyの指定がないとTransitionがうまく動きません -->
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</Transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, useTemplateRef, computed, nextTick, watch } from 'vue';
|
import { ref, shallowRef, 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 = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
|
|
||||||
const tabModel = defineModel<string>('tab');
|
const tabModel = defineModel<string>('tab');
|
||||||
|
|
||||||
|
@@ -14,34 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
:enterToClass="prefer.s.animation && props.transition?.enterToClass || undefined"
|
:enterToClass="prefer.s.animation && props.transition?.enterToClass || undefined"
|
||||||
:leaveFromClass="prefer.s.animation && props.transition?.leaveFromClass || undefined"
|
:leaveFromClass="prefer.s.animation && props.transition?.leaveFromClass || undefined"
|
||||||
>
|
>
|
||||||
<canvas
|
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
|
||||||
v-show="hide"
|
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
|
||||||
key="canvas"
|
|
||||||
ref="canvas"
|
|
||||||
:class="$style.canvas"
|
|
||||||
:width="canvasWidth"
|
|
||||||
:height="canvasHeight"
|
|
||||||
:title="title ?? undefined"
|
|
||||||
draggable="false"
|
|
||||||
tabindex="-1"
|
|
||||||
style="-webkit-user-drag: none;"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
v-show="!hide"
|
|
||||||
key="img"
|
|
||||||
ref="img"
|
|
||||||
:height="imgHeight ?? undefined"
|
|
||||||
:width="imgWidth ?? undefined"
|
|
||||||
:class="$style.img"
|
|
||||||
:src="src ?? undefined"
|
|
||||||
:title="title ?? undefined"
|
|
||||||
:alt="alt ?? undefined"
|
|
||||||
loading="eager"
|
|
||||||
decoding="async"
|
|
||||||
draggable="false"
|
|
||||||
tabindex="-1"
|
|
||||||
style="-webkit-user-drag: none;"
|
|
||||||
/>
|
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -83,7 +57,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, nextTick, onMounted, onUnmounted, useTemplateRef, watch, ref } from 'vue';
|
import { computed, nextTick, onMounted, onUnmounted, shallowRef, 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 +94,9 @@ const props = withDefaults(defineProps<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
const viewId = uuid();
|
const viewId = uuid();
|
||||||
const canvas = useTemplateRef('canvas');
|
const canvas = shallowRef<HTMLCanvasElement>();
|
||||||
const root = useTemplateRef('root');
|
const root = shallowRef<HTMLDivElement>();
|
||||||
const img = useTemplateRef('img');
|
const img = shallowRef<HTMLImageElement>();
|
||||||
const loaded = ref(false);
|
const loaded = ref(false);
|
||||||
const canvasWidth = ref(64);
|
const canvasWidth = ref(64);
|
||||||
const canvasHeight = ref(64);
|
const canvasHeight = ref(64);
|
||||||
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.root, { [$style.warn]: warn }]" class="_selectable">
|
<div :class="[$style.root, { [$style.warn]: warn }]">
|
||||||
<i v-if="warn" class="ti ti-alert-triangle" :class="$style.i"></i>
|
<i v-if="warn" class="ti ti-alert-triangle" :class="$style.i"></i>
|
||||||
<i v-else class="ti ti-info-circle" :class="$style.i"></i>
|
<i v-else class="ti ti-info-circle" :class="$style.i"></i>
|
||||||
<div><slot></slot></div>
|
<div><slot></slot></div>
|
||||||
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_selectable">
|
<div>
|
||||||
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
|
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
|
||||||
<div :class="[$style.input, { [$style.inline]: inline, [$style.disabled]: disabled, [$style.focused]: focused }]">
|
<div :class="[$style.input, { [$style.inline]: inline, [$style.disabled]: disabled, [$style.focused]: focused }]">
|
||||||
<div ref="prefixEl" :class="$style.prefix"><slot name="prefix"></slot></div>
|
<div ref="prefixEl" :class="$style.prefix"><slot name="prefix"></slot></div>
|
||||||
@@ -44,14 +44,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, nextTick, ref, useTemplateRef, watch, computed, toRefs } from 'vue';
|
import { onMounted, onUnmounted, nextTick, ref, shallowRef, watch, computed, toRefs } from 'vue';
|
||||||
import { debounce } from 'throttle-debounce';
|
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
|
||||||
import type { InputHTMLAttributes } from 'vue';
|
import type { InputHTMLAttributes } from 'vue';
|
||||||
import type { SuggestionType } from '@/utility/autocomplete.js';
|
import { debounce } from 'throttle-debounce';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { Autocomplete } from '@/utility/autocomplete.js';
|
import { Autocomplete } from '@/utility/autocomplete.js';
|
||||||
|
import type { SuggestionType } from '@/utility/autocomplete.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: string | number | null;
|
modelValue: string | number | null;
|
||||||
@@ -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 = useTemplateRef('inputEl');
|
const inputEl = shallowRef<HTMLInputElement>();
|
||||||
const prefixEl = useTemplateRef('prefixEl');
|
const prefixEl = shallowRef<HTMLElement>();
|
||||||
const suffixEl = useTemplateRef('suffixEl');
|
const suffixEl = shallowRef<HTMLElement>();
|
||||||
const height =
|
const height =
|
||||||
props.small ? 33 :
|
props.small ? 33 :
|
||||||
props.large ? 39 :
|
props.large ? 39 :
|
||||||
|
@@ -84,9 +84,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, computed, useTemplateRef } from 'vue';
|
import { onMounted, ref, computed, shallowRef } 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';
|
||||||
@@ -96,6 +95,7 @@ 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 = useTemplateRef('subDoughnutEl');
|
const subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
const pubDoughnutEl = useTemplateRef('pubDoughnutEl');
|
const pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
|
|
||||||
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
||||||
position: 'middle',
|
position: 'middle',
|
||||||
|
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<div :class="$style.items">
|
<div :class="$style.items">
|
||||||
<div>
|
<div>
|
||||||
<div :class="$style.label">{{ i18n.ts.invitationCode }}</div>
|
<div :class="$style.label">{{ i18n.ts.invitationCode }}</div>
|
||||||
<div class="_selectableAtomic">{{ invite.code }}</div>
|
<div>{{ invite.code }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="moderator">
|
<div v-if="moderator">
|
||||||
<div :class="$style.label">{{ i18n.ts.inviteCodeCreator }}</div>
|
<div :class="$style.label">{{ i18n.ts.inviteCodeCreator }}</div>
|
||||||
@@ -90,6 +90,7 @@ function deleteCode() {
|
|||||||
|
|
||||||
function copyInviteCode() {
|
function copyInviteCode() {
|
||||||
copyToClipboard(props.invite.code);
|
copyToClipboard(props.invite.code);
|
||||||
|
os.success();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<div :class="$style.key">
|
<div :class="$style.key">
|
||||||
<slot name="key"></slot>
|
<slot name="key"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.value" class="_selectable">
|
<div :class="$style.value">
|
||||||
<slot name="value"></slot>
|
<slot name="value"></slot>
|
||||||
<button v-if="copy" v-tooltip="i18n.ts.copy" class="_textButton" style="margin-left: 0.5em;" @click="copy_"><i class="ti ti-copy"></i></button>
|
<button v-if="copy" v-tooltip="i18n.ts.copy" class="_textButton" style="margin-left: 0.5em;" @click="copy_"><i class="ti ti-copy"></i></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,6 +31,7 @@ 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 { useTemplateRef } from 'vue';
|
import { shallowRef } 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 = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
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 { useTemplateRef, watch, computed, ref, onDeactivated, onActivated, onMounted } from 'vue';
|
import { shallowRef, 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 = useTemplateRef('playerEl');
|
const playerEl = shallowRef<HTMLDivElement>();
|
||||||
const audioEl = useTemplateRef('audioEl');
|
const audioEl = shallowRef<HTMLAudioElement>();
|
||||||
|
|
||||||
// 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-hash',
|
icon: 'ti ti-id',
|
||||||
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-hash',
|
icon: 'ti ti-id',
|
||||||
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, useTemplateRef } from 'vue';
|
import { computed, onMounted, onUnmounted, shallowRef } 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 = useTemplateRef('gallery');
|
const gallery = shallowRef<HTMLDivElement>();
|
||||||
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, useTemplateRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue';
|
import { ref, shallowRef, 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-hash',
|
icon: 'ti ti-id',
|
||||||
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 = useTemplateRef('videoEl');
|
const videoEl = shallowRef<HTMLVideoElement>();
|
||||||
const playerEl = useTemplateRef('playerEl');
|
const playerEl = shallowRef<HTMLDivElement>();
|
||||||
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, useTemplateRef, watch } from 'vue';
|
import { nextTick, onMounted, onUnmounted, provide, shallowRef, 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 = useTemplateRef('el');
|
const el = shallowRef<HTMLElement>();
|
||||||
const align = 'left';
|
const align = 'left';
|
||||||
|
|
||||||
const SCROLLBAR_THICKNESS = 16;
|
const SCROLLBAR_THICKNESS = 16;
|
||||||
|
@@ -35,9 +35,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item]">
|
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item]">
|
||||||
<span><MkEllipsis/></span>
|
<span><MkEllipsis/></span>
|
||||||
</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
|
<MkA
|
||||||
v-else-if="item.type === 'link'"
|
v-else-if="item.type === 'link'"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
@@ -179,7 +176,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, unref, watch } from 'vue';
|
import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, unref, watch } 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';
|
||||||
@@ -212,11 +209,11 @@ const big = isTouchUsing;
|
|||||||
|
|
||||||
const isNestingMenu = inject<boolean>('isNestingMenu', false);
|
const isNestingMenu = inject<boolean>('isNestingMenu', false);
|
||||||
|
|
||||||
const itemsEl = useTemplateRef('itemsEl');
|
const itemsEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
const items2 = ref<InnerMenuItem[]>();
|
const items2 = ref<InnerMenuItem[]>();
|
||||||
|
|
||||||
const child = useTemplateRef('child');
|
const child = shallowRef<InstanceType<typeof XChild>>();
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'up|k|shift+tab': {
|
'up|k|shift+tab': {
|
||||||
@@ -257,7 +254,7 @@ watch(() => props.items, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const childMenu = ref<MenuItem[] | null>();
|
const childMenu = ref<MenuItem[] | null>();
|
||||||
const childTarget = useTemplateRef('childTarget');
|
const childTarget = shallowRef<HTMLElement | null>();
|
||||||
|
|
||||||
function closeChild() {
|
function closeChild() {
|
||||||
childMenu.value = null;
|
childMenu.value = null;
|
||||||
|
@@ -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, useTemplateRef, computed } from 'vue';
|
import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch, ref, shallowRef, 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 = useTemplateRef('modalRootEl');
|
const modalRootEl = shallowRef<HTMLElement>();
|
||||||
const content = useTemplateRef('content');
|
const content = shallowRef<HTMLElement>();
|
||||||
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, useTemplateRef, ref } from 'vue';
|
import { onMounted, onUnmounted, shallowRef, 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 = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
const headerEl = useTemplateRef('headerEl');
|
const headerEl = shallowRef<HTMLElement>();
|
||||||
const bodyWidth = ref(0);
|
const bodyWidth = ref(0);
|
||||||
const bodyHeight = ref(0);
|
const bodyHeight = ref(0);
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</div>
|
</div>
|
||||||
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
|
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
|
||||||
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
|
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
|
||||||
<MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!mock"/>
|
<MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!mock" :style="{ viewTransitionName: transitionName }"/>
|
||||||
<div :class="$style.main">
|
<div :class="$style.main">
|
||||||
<MkNoteHeader :note="appearNote" :mini="true"/>
|
<MkNoteHeader :note="appearNote" :mini="true"/>
|
||||||
<MkInstanceTicker v-if="showTicker" :host="appearNote.user.host" :instance="appearNote.user.instance"/>
|
<MkInstanceTicker v-if="showTicker" :host="appearNote.user.host" :instance="appearNote.user.instance"/>
|
||||||
@@ -76,13 +76,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
:emojiUrls="appearNote.emojis"
|
:emojiUrls="appearNote.emojis"
|
||||||
:enableEmojiMenu="true"
|
:enableEmojiMenu="true"
|
||||||
:enableEmojiMenuReaction="true"
|
:enableEmojiMenuReaction="true"
|
||||||
class="_selectable"
|
|
||||||
/>
|
/>
|
||||||
<div v-if="translating || translation" :class="$style.translation">
|
<div v-if="translating || translation" :class="$style.translation">
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
<div v-else-if="translation">
|
<div v-else-if="translation">
|
||||||
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
||||||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/>
|
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -178,7 +177,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, ref, useTemplateRef, watch, provide } from 'vue';
|
import { computed, inject, onMounted, ref, shallowRef, watch, provide, reactive, nextTick } 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';
|
||||||
@@ -224,6 +223,7 @@ import { focusPrev, focusNext } from '@/utility/focus.js';
|
|||||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
|
import { prepareViewTransition } from '@/page.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
@@ -235,7 +235,18 @@ const props = withDefaults(defineProps<{
|
|||||||
mock: false,
|
mock: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const transitionNames = reactive({
|
||||||
|
avatar: '',
|
||||||
|
});
|
||||||
|
|
||||||
provide(DI.mock, props.mock);
|
provide(DI.mock, props.mock);
|
||||||
|
provide(DI.navHook, (path, flag) => {
|
||||||
|
const names = prepareViewTransition(path);
|
||||||
|
transitionNames.avatar = names.avatar;
|
||||||
|
nextTick(() => {
|
||||||
|
router.push(path, flag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'reaction', emoji: string): void;
|
(ev: 'reaction', emoji: string): void;
|
||||||
@@ -271,14 +282,14 @@ if (noteViewInterruptors.length > 0) {
|
|||||||
|
|
||||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
const menuButton = useTemplateRef('menuButton');
|
const menuButton = shallowRef<HTMLElement>();
|
||||||
const renoteButton = useTemplateRef('renoteButton');
|
const renoteButton = shallowRef<HTMLElement>();
|
||||||
const renoteTime = useTemplateRef('renoteTime');
|
const renoteTime = shallowRef<HTMLElement>();
|
||||||
const reactButton = useTemplateRef('reactButton');
|
const reactButton = shallowRef<HTMLElement>();
|
||||||
const clipButton = useTemplateRef('clipButton');
|
const clipButton = shallowRef<HTMLElement>();
|
||||||
const appearNote = computed(() => getAppearNote(note.value));
|
const appearNote = computed(() => getAppearNote(note.value));
|
||||||
const galleryEl = useTemplateRef('galleryEl');
|
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
||||||
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);
|
||||||
@@ -854,6 +865,8 @@ function emitUpdReaction(emoji: string, delta: number) {
|
|||||||
position: sticky !important;
|
position: sticky !important;
|
||||||
top: calc(22px + var(--MI-stickyTop, 0px));
|
top: calc(22px + var(--MI-stickyTop, 0px));
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
|
contain: paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
|
@@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</div>
|
</div>
|
||||||
<article :class="$style.note" @contextmenu.stop="onContextmenu">
|
<article :class="$style.note" @contextmenu.stop="onContextmenu">
|
||||||
<header :class="$style.noteHeader">
|
<header :class="$style.noteHeader">
|
||||||
<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/>
|
<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview :style="{ viewTransitionName: transitionName }"/>
|
||||||
<div :class="$style.noteHeaderBody">
|
<div :class="$style.noteHeaderBody">
|
||||||
<div>
|
<div>
|
||||||
<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
|
<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
|
||||||
@@ -97,14 +97,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
:emojiUrls="appearNote.emojis"
|
:emojiUrls="appearNote.emojis"
|
||||||
:enableEmojiMenu="true"
|
:enableEmojiMenu="true"
|
||||||
:enableEmojiMenuReaction="true"
|
:enableEmojiMenuReaction="true"
|
||||||
class="_selectable"
|
|
||||||
/>
|
/>
|
||||||
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
|
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
|
||||||
<div v-if="translating || translation" :class="$style.translation">
|
<div v-if="translating || translation" :class="$style.translation">
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
<div v-else-if="translation">
|
<div v-else-if="translation">
|
||||||
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
||||||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/>
|
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="appearNote.files && appearNote.files.length > 0">
|
<div v-if="appearNote.files && appearNote.files.length > 0">
|
||||||
@@ -211,7 +210,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, provide, ref, useTemplateRef } from 'vue';
|
import { computed, inject, onMounted, provide, ref, shallowRef } 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';
|
||||||
@@ -256,6 +255,7 @@ import { isEnabledUrlPreview } from '@/instance.js';
|
|||||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
|
import { prepareViewTransition } from '@/page.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
@@ -264,6 +264,8 @@ const props = withDefaults(defineProps<{
|
|||||||
initialTab: 'replies',
|
initialTab: 'replies',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const transitionName = prepareViewTransition('note-noteDetailed', props.note.id).avatar;
|
||||||
|
|
||||||
const inChannel = inject('inChannel', null);
|
const inChannel = inject('inChannel', null);
|
||||||
|
|
||||||
const note = ref(deepClone(props.note));
|
const note = ref(deepClone(props.note));
|
||||||
@@ -290,14 +292,14 @@ if (noteViewInterruptors.length > 0) {
|
|||||||
|
|
||||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
const menuButton = useTemplateRef('menuButton');
|
const menuButton = shallowRef<HTMLElement>();
|
||||||
const renoteButton = useTemplateRef('renoteButton');
|
const renoteButton = shallowRef<HTMLElement>();
|
||||||
const renoteTime = useTemplateRef('renoteTime');
|
const renoteTime = shallowRef<HTMLElement>();
|
||||||
const reactButton = useTemplateRef('reactButton');
|
const reactButton = shallowRef<HTMLElement>();
|
||||||
const clipButton = useTemplateRef('clipButton');
|
const clipButton = shallowRef<HTMLElement>();
|
||||||
const appearNote = computed(() => getAppearNote(note.value));
|
const appearNote = computed(() => getAppearNote(note.value));
|
||||||
const galleryEl = useTemplateRef('galleryEl');
|
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
||||||
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);
|
||||||
@@ -670,6 +672,8 @@ function loadConversation() {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 58px;
|
width: 58px;
|
||||||
height: 58px;
|
height: 58px;
|
||||||
|
|
||||||
|
contain: paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
.noteHeaderBody {
|
.noteHeaderBody {
|
||||||
|
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
<MkPagination ref="pagingComponent" :pagination="pagination" :disableAutoLoad="disableAutoLoad">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
<div>{{ i18n.ts.noNotes }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -32,11 +32,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef } from 'vue';
|
import { shallowRef } from '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';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ const props = defineProps<{
|
|||||||
disableAutoLoad?: boolean;
|
disableAutoLoad?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const pagingComponent = useTemplateRef('pagingComponent');
|
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
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 { ensureSignin } from '@/i.js';
|
import { signinRequired } from '@/i.js';
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = signinRequired();
|
||||||
|
|
||||||
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, useTemplateRef } from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import { notificationTypes } from '@@/js/const.js';
|
import type { Ref } from 'vue';
|
||||||
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 = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotifications }}</div>
|
<div>{{ i18n.ts.noNotifications }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -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, useTemplateRef, onActivated } from 'vue';
|
import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, 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 = useTemplateRef('pagingComponent');
|
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
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, useTemplateRef, ref } from 'vue';
|
import { onMounted, onUnmounted, shallowRef, 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 = useTemplateRef('content');
|
const content = shallowRef<HTMLElement>();
|
||||||
const omitted = ref(false);
|
const omitted = ref(false);
|
||||||
const ignoreOmit = ref(false);
|
const ignoreOmit = ref(false);
|
||||||
|
|
||||||
|
@@ -22,29 +22,30 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div :class="$style.root">
|
<div ref="contents" :class="$style.root" style="container-type: inline-size;">
|
||||||
<StackingRouterView v-if="prefer.s['experimental.stackingRouterView']" :key="reloadCount" :router="windowRouter"/>
|
<RouterView :key="reloadCount" :router="windowRouter"/>
|
||||||
<RouterView v-else :key="reloadCount" :router="windowRouter"/>
|
|
||||||
</div>
|
</div>
|
||||||
</MkWindow>
|
</MkWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted, provide, ref, useTemplateRef } from 'vue';
|
import { computed, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue';
|
||||||
import { url } from '@@/js/config.js';
|
import { url } from '@@/js/config.js';
|
||||||
|
import { getScrollContainer } from '@@/js/scroll.js';
|
||||||
import type { PageMetadata } from '@/page.js';
|
import type { PageMetadata } from '@/page.js';
|
||||||
import RouterView from '@/components/global/RouterView.vue';
|
import RouterView from '@/components/global/RouterView.vue';
|
||||||
import MkWindow from '@/components/MkWindow.vue';
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
import { popout as _popout } from '@/utility/popout.js';
|
import { popout as _popout } from '@/utility/popout.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
|
import { useScrollPositionManager } from '@/nirax.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
import { provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
|
||||||
import { openingWindowsCount } from '@/os.js';
|
import { openingWindowsCount } from '@/os.js';
|
||||||
import { claimAchievement } from '@/utility/achievements.js';
|
import { claimAchievement } from '@/utility/achievements.js';
|
||||||
import { createRouter, mainRouter } from '@/router.js';
|
import { useRouterFactory } from '@/router/supplier.js';
|
||||||
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { analytics } from '@/analytics.js';
|
import { analytics } from '@/analytics.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
import { prefer } from '@/preferences.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
initialPath: string;
|
initialPath: string;
|
||||||
@@ -54,12 +55,15 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const windowRouter = createRouter(props.initialPath);
|
const routerFactory = useRouterFactory();
|
||||||
|
const windowRouter = routerFactory(props.initialPath);
|
||||||
|
|
||||||
|
const contents = shallowRef<HTMLElement | null>(null);
|
||||||
const pageMetadata = ref<null | PageMetadata>(null);
|
const pageMetadata = ref<null | PageMetadata>(null);
|
||||||
const windowEl = useTemplateRef('windowEl');
|
const windowEl = shallowRef<InstanceType<typeof MkWindow>>();
|
||||||
const history = ref<{ path: string; }[]>([{
|
const history = ref<{ path: string; key: string; }[]>([{
|
||||||
path: windowRouter.getCurrentFullPath(),
|
path: windowRouter.getCurrentPath(),
|
||||||
|
key: windowRouter.getCurrentKey(),
|
||||||
}]);
|
}]);
|
||||||
const buttonsLeft = computed(() => {
|
const buttonsLeft = computed(() => {
|
||||||
const buttons: Record<string, unknown>[] = [];
|
const buttons: Record<string, unknown>[] = [];
|
||||||
@@ -97,20 +101,20 @@ function getSearchMarker(path: string) {
|
|||||||
const searchMarkerId = ref<string | null>(getSearchMarker(props.initialPath));
|
const searchMarkerId = ref<string | null>(getSearchMarker(props.initialPath));
|
||||||
|
|
||||||
windowRouter.addListener('push', ctx => {
|
windowRouter.addListener('push', ctx => {
|
||||||
history.value.push({ path: ctx.fullPath });
|
history.value.push({ path: ctx.path, key: ctx.key });
|
||||||
});
|
});
|
||||||
|
|
||||||
windowRouter.addListener('replace', ctx => {
|
windowRouter.addListener('replace', ctx => {
|
||||||
history.value.pop();
|
history.value.pop();
|
||||||
history.value.push({ path: ctx.fullPath });
|
history.value.push({ path: ctx.path, key: ctx.key });
|
||||||
});
|
});
|
||||||
|
|
||||||
windowRouter.addListener('change', ctx => {
|
windowRouter.addListener('change', ctx => {
|
||||||
if (_DEV_) console.log('windowRouter: change', ctx.fullPath);
|
if (_DEV_) console.log('windowRouter: change', ctx.path);
|
||||||
searchMarkerId.value = getSearchMarker(ctx.fullPath);
|
searchMarkerId.value = getSearchMarker(ctx.path);
|
||||||
analytics.page({
|
analytics.page({
|
||||||
path: ctx.fullPath,
|
path: ctx.path,
|
||||||
title: ctx.fullPath,
|
title: ctx.path,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,20 +143,20 @@ const contextmenu = computed(() => ([{
|
|||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-external-link',
|
||||||
text: i18n.ts.openInNewTab,
|
text: i18n.ts.openInNewTab,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(url + windowRouter.getCurrentFullPath(), '_blank', 'noopener');
|
window.open(url + windowRouter.getCurrentPath(), '_blank', 'noopener');
|
||||||
windowEl.value?.close();
|
windowEl.value?.close();
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
icon: 'ti ti-link',
|
icon: 'ti ti-link',
|
||||||
text: i18n.ts.copyLink,
|
text: i18n.ts.copyLink,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(url + windowRouter.getCurrentFullPath());
|
copyToClipboard(url + windowRouter.getCurrentPath());
|
||||||
},
|
},
|
||||||
}]));
|
}]));
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
history.value.pop();
|
history.value.pop();
|
||||||
windowRouter.replace(history.value.at(-1)!.path);
|
windowRouter.replace(history.value.at(-1)!.path, history.value.at(-1)!.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
@@ -164,15 +168,17 @@ function close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function expand() {
|
function expand() {
|
||||||
mainRouter.push(windowRouter.getCurrentFullPath(), 'forcePage');
|
mainRouter.push(windowRouter.getCurrentPath(), 'forcePage');
|
||||||
windowEl.value?.close();
|
windowEl.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function popout() {
|
function popout() {
|
||||||
_popout(windowRouter.getCurrentFullPath(), windowEl.value?.$el);
|
_popout(windowRouter.getCurrentPath(), windowEl.value?.$el);
|
||||||
windowEl.value?.close();
|
windowEl.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useScrollPositionManager(() => getScrollContainer(contents.value), windowRouter);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
analytics.page({
|
analytics.page({
|
||||||
path: props.initialPath,
|
path: props.initialPath,
|
||||||
@@ -196,7 +202,9 @@ defineExpose({
|
|||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.root {
|
.root {
|
||||||
height: 100%;
|
overscroll-behavior: contain;
|
||||||
|
|
||||||
|
min-height: 100%;
|
||||||
background: var(--MI_THEME-bg);
|
background: var(--MI_THEME-bg);
|
||||||
|
|
||||||
--MI-margin: var(--MI-marginHalf);
|
--MI-margin: var(--MI-marginHalf);
|
||||||
|
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<div v-else-if="empty" key="_empty_" class="empty">
|
<div v-else-if="empty" key="_empty_" class="empty">
|
||||||
<slot name="empty">
|
<slot name="empty">
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img :src="infoImageUrl" draggable="false"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
@@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, useTemplateRef, watch } from 'vue';
|
import { computed, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, shallowRef, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { useDocumentVisibility } from '@@/js/use-document-visibility.js';
|
import { useDocumentVisibility } from '@@/js/use-document-visibility.js';
|
||||||
import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@@/js/scroll.js';
|
import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@@/js/scroll.js';
|
||||||
@@ -106,7 +106,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'status', error: boolean): void;
|
(ev: 'status', error: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
// 遡り中かどうか
|
// 遡り中かどうか
|
||||||
const backed = ref(false);
|
const backed = ref(false);
|
||||||
|
@@ -39,14 +39,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, useTemplateRef, ref } from 'vue';
|
import { onMounted, shallowRef, ref } from 'vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { signinRequired } from '@/i.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = signinRequired();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'done', v: { password: string; token: string | null; }): void;
|
(ev: 'done', v: { password: string; token: string | null; }): void;
|
||||||
@@ -54,8 +54,8 @@ const emit = defineEmits<{
|
|||||||
(ev: 'cancelled'): void;
|
(ev: 'cancelled'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
const passwordInput = useTemplateRef('passwordInput');
|
const passwordInput = shallowRef<InstanceType<typeof MkInput>>();
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
const isBackupCode = ref(false);
|
const isBackupCode = ref(false);
|
||||||
const token = ref<string | null>(null);
|
const token = ref<string | null>(null);
|
||||||
|
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, useTemplateRef } from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import MkModal from './MkModal.vue';
|
import MkModal from './MkModal.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<{
|
|||||||
(ev: 'closing'): void;
|
(ev: 'closing'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const manualShowing = ref(true);
|
const manualShowing = ref(true);
|
||||||
const hiding = ref(false);
|
const hiding = ref(false);
|
||||||
|
|
||||||
|
@@ -1,95 +0,0 @@
|
|||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="[$style.textCountRoot]">
|
|
||||||
<div :class="$style.textCountLabel">{{ i18n.ts.textCount }}</div>
|
|
||||||
<div
|
|
||||||
:class="[$style.textCount,
|
|
||||||
{ [$style.danger]: textCountPercentage > 100 },
|
|
||||||
{ [$style.warning]: textCountPercentage > 90 && textCountPercentage <= 100 },
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<div :class="$style.textCountGraph"></div>
|
|
||||||
<div><span :class="$style.textCountCurrent">{{ number(textLength) }}</span> / {{ number(maxTextLength) }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, useTemplateRef } from 'vue';
|
|
||||||
import { instance } from '@/instance.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
|
||||||
import number from '@/filters/number.js';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
textLength: number;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const maxTextLength = computed(() => {
|
|
||||||
return instance ? instance.maxNoteTextLength : 1000;
|
|
||||||
});
|
|
||||||
|
|
||||||
const textCountPercentage = computed(() => {
|
|
||||||
return props.textLength / maxTextLength.value * 100;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" module>
|
|
||||||
.textCountRoot {
|
|
||||||
padding: 4px 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textCountLabel {
|
|
||||||
font-size: 11px;
|
|
||||||
opacity: 0.8;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.textCount {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--MI-marginHalf);
|
|
||||||
align-items: center;
|
|
||||||
font-size: 12px;
|
|
||||||
--countColor: var(--MI_THEME-accent);
|
|
||||||
|
|
||||||
&.danger {
|
|
||||||
--countColor: var(--MI_THEME-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
--countColor: var(--MI_THEME-warn);
|
|
||||||
}
|
|
||||||
|
|
||||||
.textCountGraph {
|
|
||||||
position: relative;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-image: conic-gradient(
|
|
||||||
var(--countColor) 0% v-bind("Math.min(100, textCountPercentage) + '%'"),
|
|
||||||
rgba(0, 0, 0, .2) v-bind("Math.min(100, textCountPercentage) + '%'") 100%
|
|
||||||
);
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--MI_THEME-popup);
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.textCountCurrent {
|
|
||||||
color: var(--countColor);
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</div>
|
</div>
|
||||||
<div :class="$style.headerRight">
|
<div :class="$style.headerRight">
|
||||||
<template v-if="!(channel != null && fixed)">
|
<template v-if="!(channel != null && fixed)">
|
||||||
<button v-if="channel == null" ref="visibilityButton" v-tooltip="i18n.ts.visibility" :class="['_button', $style.headerRightItem, $style.visibility]" @click="setVisibility">
|
<button v-if="channel == null" ref="visibilityButton" v-click-anime v-tooltip="i18n.ts.visibility" :class="['_button', $style.headerRightItem, $style.visibility]" @click="setVisibility">
|
||||||
<span v-if="visibility === 'public'"><i class="ti ti-world"></i></span>
|
<span v-if="visibility === 'public'"><i class="ti ti-world"></i></span>
|
||||||
<span v-if="visibility === 'home'"><i class="ti ti-home"></i></span>
|
<span v-if="visibility === 'home'"><i class="ti ti-home"></i></span>
|
||||||
<span v-if="visibility === 'followers'"><i class="ti ti-lock"></i></span>
|
<span v-if="visibility === 'followers'"><i class="ti ti-lock"></i></span>
|
||||||
@@ -32,11 +32,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<span :class="$style.headerRightButtonText">{{ channel.name }}</span>
|
<span :class="$style.headerRightButtonText">{{ channel.name }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<button v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly">
|
<button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly">
|
||||||
<span v-if="!localOnly"><i class="ti ti-rocket"></i></span>
|
<span v-if="!localOnly"><i class="ti ti-rocket"></i></span>
|
||||||
<span v-else><i class="ti ti-rocket-off"></i></span>
|
<span v-else><i class="ti ti-rocket-off"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button ref="otherSettingsButton" v-tooltip="i18n.ts.other" class="_button" :class="$style.headerRightItem" @click="showOtherSettings"><i class="ti ti-dots"></i></button>
|
<button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance">
|
||||||
|
<span v-if="reactionAcceptance === 'likeOnly'"><i class="ti ti-heart"></i></span>
|
||||||
|
<span v-else-if="reactionAcceptance === 'likeOnlyForRemote'"><i class="ti ti-heart-plus"></i></span>
|
||||||
|
<span v-else><i class="ti ti-icons"></i></span>
|
||||||
|
</button>
|
||||||
<button v-click-anime class="_button" :class="$style.submit" :disabled="!canPost" data-cy-open-post-form-submit @click="post">
|
<button v-click-anime class="_button" :class="$style.submit" :disabled="!canPost" data-cy-open-post-form-submit @click="post">
|
||||||
<div :class="$style.submitInner">
|
<div :class="$style.submitInner">
|
||||||
<template v-if="posted"></template>
|
<template v-if="posted"></template>
|
||||||
@@ -99,7 +103,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed, useTemplateRef } from 'vue';
|
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed } 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 insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
@@ -107,11 +111,9 @@ import { toASCII } from 'punycode.js';
|
|||||||
import { host, url } from '@@/js/config.js';
|
import { host, url } from '@@/js/config.js';
|
||||||
import type { ShallowRef } from 'vue';
|
import type { ShallowRef } from 'vue';
|
||||||
import type { PostFormProps } from '@/types/post-form.js';
|
import type { PostFormProps } from '@/types/post-form.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
|
||||||
import type { PollEditorModelValue } from '@/components/MkPollEditor.vue';
|
import type { PollEditorModelValue } from '@/components/MkPollEditor.vue';
|
||||||
import MkNotePreview from '@/components/MkNotePreview.vue';
|
import MkNotePreview from '@/components/MkNotePreview.vue';
|
||||||
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
||||||
import XTextCounter from '@/components/MkPostForm.TextCounter.vue';
|
|
||||||
import MkPollEditor from '@/components/MkPollEditor.vue';
|
import MkPollEditor from '@/components/MkPollEditor.vue';
|
||||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||||
import { erase, unique } from '@/utility/array.js';
|
import { erase, unique } from '@/utility/array.js';
|
||||||
@@ -125,7 +127,7 @@ import { store } from '@/store.js';
|
|||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ensureSignin, notesCount, incNotesCount } from '@/i.js';
|
import { signinRequired, notesCount, incNotesCount } from '@/i.js';
|
||||||
import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
||||||
import { uploadFile } from '@/utility/upload.js';
|
import { uploadFile } from '@/utility/upload.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
@@ -138,7 +140,7 @@ import { prefer } from '@/preferences.js';
|
|||||||
import { getPluginHandlers } from '@/plugin.js';
|
import { getPluginHandlers } from '@/plugin.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = signinRequired();
|
||||||
|
|
||||||
const modal = inject('modal');
|
const modal = inject('modal');
|
||||||
|
|
||||||
@@ -165,11 +167,10 @@ const emit = defineEmits<{
|
|||||||
(ev: 'fileChangeSensitive', fileId: string, to: boolean): void;
|
(ev: 'fileChangeSensitive', fileId: string, to: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const textareaEl = useTemplateRef('textareaEl');
|
const textareaEl = shallowRef<HTMLTextAreaElement | null>(null);
|
||||||
const cwInputEl = useTemplateRef('cwInputEl');
|
const cwInputEl = shallowRef<HTMLInputElement | null>(null);
|
||||||
const hashtagsInputEl = useTemplateRef('hashtagsInputEl');
|
const hashtagsInputEl = shallowRef<HTMLInputElement | null>(null);
|
||||||
const visibilityButton = useTemplateRef('visibilityButton');
|
const visibilityButton = shallowRef<HTMLElement>();
|
||||||
const otherSettingsButton = useTemplateRef('otherSettingsButton');
|
|
||||||
|
|
||||||
const posting = ref(false);
|
const posting = ref(false);
|
||||||
const posted = ref(false);
|
const posted = ref(false);
|
||||||
@@ -555,47 +556,6 @@ async function toggleReactionAcceptance() {
|
|||||||
reactionAcceptance.value = select.result;
|
reactionAcceptance.value = select.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region その他の設定メニューpopup
|
|
||||||
function showOtherSettings() {
|
|
||||||
let reactionAcceptanceIcon = 'ti ti-icons';
|
|
||||||
|
|
||||||
if (reactionAcceptance.value === 'likeOnly') {
|
|
||||||
reactionAcceptanceIcon = 'ti ti-heart _love';
|
|
||||||
} else if (reactionAcceptance.value === 'likeOnlyForRemote') {
|
|
||||||
reactionAcceptanceIcon = 'ti ti-heart-plus';
|
|
||||||
}
|
|
||||||
|
|
||||||
const menuItems = [{
|
|
||||||
type: 'component',
|
|
||||||
component: XTextCounter,
|
|
||||||
props: {
|
|
||||||
textLength: textLength,
|
|
||||||
},
|
|
||||||
}, { type: 'divider' }, {
|
|
||||||
icon: reactionAcceptanceIcon,
|
|
||||||
text: i18n.ts.reactionAcceptance,
|
|
||||||
action: () => {
|
|
||||||
toggleReactionAcceptance();
|
|
||||||
},
|
|
||||||
}, { type: 'divider' }, {
|
|
||||||
icon: 'ti ti-trash',
|
|
||||||
text: i18n.ts.reset,
|
|
||||||
danger: true,
|
|
||||||
action: async () => {
|
|
||||||
if (props.mock) return;
|
|
||||||
const { canceled } = await os.confirm({
|
|
||||||
type: 'question',
|
|
||||||
text: i18n.ts.resetAreYouSure,
|
|
||||||
});
|
|
||||||
if (canceled) return;
|
|
||||||
clear();
|
|
||||||
},
|
|
||||||
}] satisfies MenuItem[];
|
|
||||||
|
|
||||||
os.popupMenu(menuItems, otherSettingsButton.value);
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
function pushVisibleUser(user: Misskey.entities.UserDetailed) {
|
function pushVisibleUser(user: Misskey.entities.UserDetailed) {
|
||||||
if (!visibleUsers.value.some(u => u.username === user.username && u.host === user.host)) {
|
if (!visibleUsers.value.some(u => u.username === user.username && u.host === user.host)) {
|
||||||
visibleUsers.value.push(user);
|
visibleUsers.value.push(user);
|
||||||
|
@@ -201,7 +201,7 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | Keyboar
|
|||||||
|
|
||||||
if (prefer.s.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menuItems.push({ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-hash',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(file.id);
|
copyToClipboard(file.id);
|
||||||
|
@@ -25,10 +25,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import type { PostFormProps } from '@/types/post-form.js';
|
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkPostForm from '@/components/MkPostForm.vue';
|
import MkPostForm from '@/components/MkPostForm.vue';
|
||||||
|
import type { PostFormProps } from '@/types/post-form.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<PostFormProps & {
|
const props = withDefaults(defineProps<PostFormProps & {
|
||||||
instant?: boolean;
|
instant?: boolean;
|
||||||
@@ -42,7 +42,8 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
const form = shallowRef<InstanceType<typeof MkPostForm>>();
|
||||||
|
|
||||||
function onPosted() {
|
function onPosted() {
|
||||||
modal.value?.close({
|
modal.value?.close({
|
||||||
|
@@ -23,9 +23,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||||
import { getScrollContainer } from '@@/js/scroll.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { getScrollContainer } from '@@/js/scroll.js';
|
||||||
import { isHorizontalSwipeSwiping } from '@/utility/touch.js';
|
import { isHorizontalSwipeSwiping } from '@/utility/touch.js';
|
||||||
|
|
||||||
const SCROLL_STOP = 10;
|
const SCROLL_STOP = 10;
|
||||||
@@ -43,7 +43,7 @@ const pullDistance = ref(0);
|
|||||||
let supportPointerDesktop = false;
|
let supportPointerDesktop = false;
|
||||||
let startScreenY: number | null = null;
|
let startScreenY: number | null = null;
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
let scrollEl: HTMLElement | null = null;
|
let scrollEl: HTMLElement | null = null;
|
||||||
|
|
||||||
let disabled = false;
|
let disabled = false;
|
||||||
|
@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { isTouchUsing } from '@/utility/touch.js';
|
import { isTouchUsing } from '@/utility/touch.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ const emit = defineEmits<{
|
|||||||
(ev: 'dragEnded', value: number): void;
|
(ev: 'dragEnded', value: number): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const containerEl = useTemplateRef('containerEl');
|
const containerEl = shallowRef<HTMLElement>();
|
||||||
const thumbEl = useTemplateRef('thumbEl');
|
const thumbEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
const rawValue = ref((props.modelValue - props.min) / (props.max - props.min));
|
const rawValue = ref((props.modelValue - props.min) / (props.max - props.min));
|
||||||
const steppedRawValue = computed(() => {
|
const steppedRawValue = computed(() => {
|
||||||
|
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, useTemplateRef } from 'vue';
|
import { defineAsyncComponent, shallowRef } from 'vue';
|
||||||
import { useTooltip } from '@/use/use-tooltip.js';
|
import { useTooltip } from '@/use/use-tooltip.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ const props = defineProps<{
|
|||||||
withTooltip?: boolean;
|
withTooltip?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const elRef = useTemplateRef('elRef');
|
const elRef = shallowRef();
|
||||||
|
|
||||||
if (props.withTooltip) {
|
if (props.withTooltip) {
|
||||||
useTooltip(elRef, (showing) => {
|
useTooltip(elRef, (showing) => {
|
||||||
|
@@ -12,13 +12,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
@click="toggleReaction()"
|
@click="toggleReaction()"
|
||||||
@contextmenu.prevent.stop="menu"
|
@contextmenu.prevent.stop="menu"
|
||||||
>
|
>
|
||||||
<MkReactionIcon style="pointer-events: none;" :class="prefer.s.limitWidthOfReaction ? $style.limitWidth : ''" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
|
<MkReactionIcon :class="prefer.s.limitWidthOfReaction ? $style.limitWidth : ''" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
|
||||||
<span :class="$style.count">{{ count }}</span>
|
<span :class="$style.count">{{ count }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, useTemplateRef, watch } from 'vue';
|
import { computed, inject, onMounted, shallowRef, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { getUnicodeEmoji } from '@@/js/emojilist.js';
|
import { getUnicodeEmoji } from '@@/js/emojilist.js';
|
||||||
import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
|
import MkCustomEmojiDetailedDialog from './MkCustomEmojiDetailedDialog.vue';
|
||||||
@@ -50,7 +50,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'reactionToggled', emoji: string, newCount: number): void;
|
(ev: 'reactionToggled', emoji: string, newCount: number): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const buttonEl = useTemplateRef('buttonEl');
|
const buttonEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
const emojiName = computed(() => props.reaction.replace(/:/g, '').replace(/@\./, ''));
|
const emojiName = computed(() => props.reaction.replace(/:/g, '').replace(/@\./, ''));
|
||||||
const emoji = computed(() => customEmojisMap.get(emojiName.value) ?? getUnicodeEmoji(props.reaction));
|
const emoji = computed(() => customEmojisMap.get(emojiName.value) ?? getUnicodeEmoji(props.reaction));
|
||||||
|
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, nextTick, useTemplateRef, ref } from 'vue';
|
import { onMounted, nextTick, shallowRef, ref } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
@@ -23,8 +23,8 @@ import { initChart } from '@/utility/init-chart.js';
|
|||||||
|
|
||||||
initChart();
|
initChart();
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLDivElement | null>(null);
|
||||||
const chartEl = useTemplateRef('chartEl');
|
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
let chartInstance: Chart | null = null;
|
let chartInstance: Chart | null = null;
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, useTemplateRef } from 'vue';
|
import { onMounted, shallowRef } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
@@ -20,7 +20,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||||||
|
|
||||||
initChart();
|
initChart();
|
||||||
|
|
||||||
const chartEl = useTemplateRef('chartEl');
|
const chartEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||||
|
|
||||||
|
@@ -24,7 +24,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 { useTemplateRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import type { OpenOnRemoteOptions } from '@/utility/please-login.js';
|
import type { OpenOnRemoteOptions } from '@/utility/please-login.js';
|
||||||
import MkSignin from '@/components/MkSignin.vue';
|
import MkSignin from '@/components/MkSignin.vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
@@ -46,7 +46,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'cancelled'): void;
|
(ev: 'cancelled'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const modal = useTemplateRef('modal');
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
function onClose() {
|
function onClose() {
|
||||||
emit('cancelled');
|
emit('cancelled');
|
||||||
|
@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef, ref } from 'vue';
|
import { shallowRef, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XSignup from '@/components/MkSignupDialog.form.vue';
|
import XSignup from '@/components/MkSignupDialog.form.vue';
|
||||||
import XServerRules from '@/components/MkSignupDialog.rules.vue';
|
import XServerRules from '@/components/MkSignupDialog.rules.vue';
|
||||||
@@ -52,7 +52,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
const isAcceptedServerRule = ref(false);
|
const isAcceptedServerRule = ref(false);
|
||||||
|
|
||||||
|
@@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
||||||
|
|
||||||
const particles = ref<{
|
const particles = ref<{
|
||||||
id: string,
|
id: string,
|
||||||
@@ -66,7 +66,7 @@ const particles = ref<{
|
|||||||
dur: number,
|
dur: number,
|
||||||
color: string
|
color: string
|
||||||
}[]>([]);
|
}[]>([]);
|
||||||
const el = useTemplateRef('el');
|
const el = shallowRef<HTMLElement>();
|
||||||
const width = ref(0);
|
const width = ref(0);
|
||||||
const height = ref(0);
|
const height = ref(0);
|
||||||
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
|
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
|
||||||
|
@@ -98,7 +98,7 @@ import type { SearchIndexItem } from '@/utility/autogen/settings-search-index.js
|
|||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { getScrollContainer } from '@@/js/scroll.js';
|
import { getScrollContainer } from '@@/js/scroll.js';
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import { initIntlString, compareStringIncludes } from '@/utility/intl-string.js';
|
import { initIntlString, compareStringIncludes } from '@/utility/intl-string.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@@ -92,15 +92,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref, useTemplateRef, toRefs } from 'vue';
|
import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import type {
|
import type {
|
||||||
MkSystemWebhookEditorProps,
|
MkSystemWebhookEditorProps,
|
||||||
MkSystemWebhookResult,
|
MkSystemWebhookResult,
|
||||||
SystemWebhookEventType,
|
SystemWebhookEventType,
|
||||||
} from '@/components/MkSystemWebhookEditor.impl.js';
|
} from '@/components/MkSystemWebhookEditor.impl.js';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
@@ -122,7 +122,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialogEl = useTemplateRef('dialogEl');
|
const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
const props = defineProps<MkSystemWebhookEditorProps>();
|
const props = defineProps<MkSystemWebhookEditorProps>();
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, watch, onBeforeUnmount, ref, useTemplateRef } from 'vue';
|
import { onMounted, watch, onBeforeUnmount, ref, shallowRef } from 'vue';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
const loaded = !!window.TagCanvas;
|
const loaded = !!window.TagCanvas;
|
||||||
@@ -24,9 +24,9 @@ const computedStyle = getComputedStyle(document.documentElement);
|
|||||||
const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
||||||
const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
||||||
const available = ref(false);
|
const available = ref(false);
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = shallowRef<HTMLElement | null>(null);
|
||||||
const canvasEl = useTemplateRef('canvasEl');
|
const canvasEl = shallowRef<HTMLCanvasElement | null>(null);
|
||||||
const tagsEl = useTemplateRef('tagsEl');
|
const tagsEl = shallowRef<HTMLElement | null>(null);
|
||||||
const width = ref(300);
|
const width = ref(300);
|
||||||
|
|
||||||
watch(available, () => {
|
watch(available, () => {
|
||||||
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_selectable">
|
<div>
|
||||||
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
|
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
|
||||||
<div :class="{ [$style.disabled]: disabled, [$style.focused]: focused, [$style.tall]: tall, [$style.pre]: pre }" style="position: relative;">
|
<div :class="{ [$style.disabled]: disabled, [$style.focused]: focused, [$style.tall]: tall, [$style.pre]: pre }" style="position: relative;">
|
||||||
<textarea
|
<textarea
|
||||||
@@ -36,12 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, shallowRef } from 'vue';
|
||||||
import { debounce } from 'throttle-debounce';
|
import { debounce } from 'throttle-debounce';
|
||||||
import type { SuggestionType } from '@/utility/autocomplete.js';
|
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { Autocomplete } from '@/utility/autocomplete.js';
|
import { Autocomplete } from '@/utility/autocomplete.js';
|
||||||
|
import type { SuggestionType } from '@/utility/autocomplete.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: string | null;
|
modelValue: string | null;
|
||||||
@@ -75,7 +75,7 @@ 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 = useTemplateRef('inputEl');
|
const inputEl = shallowRef<HTMLTextAreaElement>();
|
||||||
const preview = ref(false);
|
const preview = ref(false);
|
||||||
let autocompleteWorker: Autocomplete | null = null;
|
let autocompleteWorker: Autocomplete | null = null;
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, onUnmounted, provide, useTemplateRef } from 'vue';
|
import { computed, watch, onUnmounted, provide, ref, shallowRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { BasicTimelineType } from '@/timelines.js';
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
@@ -67,8 +67,8 @@ type TimelineQueryType = {
|
|||||||
roleId?: string
|
roleId?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
const prComponent = useTemplateRef('prComponent');
|
const prComponent = shallowRef<InstanceType<typeof MkPullToRefresh>>();
|
||||||
const tlComponent = useTemplateRef('tlComponent');
|
const tlComponent = shallowRef<InstanceType<typeof MkNotes>>();
|
||||||
|
|
||||||
let tlNotesCount = 0;
|
let tlNotesCount = 0;
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useTemplateRef, ref } from 'vue';
|
import { shallowRef, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkInput from './MkInput.vue';
|
import MkInput from './MkInput.vue';
|
||||||
import MkSwitch from './MkSwitch.vue';
|
import MkSwitch from './MkSwitch.vue';
|
||||||
@@ -77,7 +77,7 @@ const emit = defineEmits<{
|
|||||||
const defaultPermissions = Misskey.permissions.filter(p => !p.startsWith('read:admin') && !p.startsWith('write:admin'));
|
const defaultPermissions = Misskey.permissions.filter(p => !p.startsWith('read:admin') && !p.startsWith('write:admin'));
|
||||||
const adminPermissions = Misskey.permissions.filter(p => p.startsWith('read:admin') || p.startsWith('write:admin'));
|
const adminPermissions = Misskey.permissions.filter(p => p.startsWith('read:admin') || p.startsWith('write:admin'));
|
||||||
|
|
||||||
const dialog = useTemplateRef('dialog');
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
const name = ref(props.initialName);
|
const name = ref(props.initialName);
|
||||||
const permissionSwitches = ref({} as Record<(typeof Misskey.permissions)[number], boolean>);
|
const permissionSwitches = ref({} as Record<(typeof Misskey.permissions)[number], boolean>);
|
||||||
const permissionSwitchesForAdmin = ref({} as Record<(typeof Misskey.permissions)[number], boolean>);
|
const permissionSwitchesForAdmin = ref({} as Record<(typeof Misskey.permissions)[number], boolean>);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user