mirror of
https://github.com/misskey-dev/misskey
synced 2025-10-11 20:40:25 +02:00
Compare commits
No commits in common. "develop" and "2025.10.0-beta.1" have entirely different histories.
develop
...
2025.10.0-
69 changed files with 3282 additions and 3030 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -1,22 +1,7 @@
|
|||
## 2025.10.1
|
||||
|
||||
### General
|
||||
- 依存関係の更新
|
||||
|
||||
### Client
|
||||
- Fix: カスタム絵文字画面(beta)のaliasesで使用される区切り文字が一致していないのを修正 #15614
|
||||
- Fix: バナー画像の幅が表示領域と一致していない問題を修正
|
||||
- Fix: 一部のブラウザでバナー画像が上下中央に表示されない問題を修正
|
||||
|
||||
### Server
|
||||
-
|
||||
|
||||
## 2025.10.0
|
||||
|
||||
### NOTE
|
||||
- pnpm 10.16.0 が必要です
|
||||
- ロールのインポート機能の利用可否ポリシーのデフォルト値が「いいえ」に変わったため、デフォルトから変更していないサーバーでは適宜設定を変更してください。
|
||||
- ロールのアップロード可能なファイル種別ポリシーのデフォルト値に「text/*」が追加されたため、デフォルトから変更していないサーバーでは適宜設定を変更してください。
|
||||
|
||||
### General
|
||||
- Feat: 予約投稿ができるようになりました
|
||||
|
@ -35,12 +20,9 @@
|
|||
- Enhance: ウォーターマークにアカウントのQRコードを追加できるように
|
||||
- Enhance: テーマをドラッグ&ドロップできるように
|
||||
- Enhance: 絵文字ピッカーのサイズをより大きくできるように
|
||||
- Enhance: カスタム絵文字が多い場合にサーバーの絵文字一覧ページがフリーズしないように
|
||||
- Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上
|
||||
- Enhance: 「お問い合わせ」ページから、バグの調査等に役立つ情報(OSやブラウザのバージョン等)を取得・コピーできるように
|
||||
- Fix: iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正
|
||||
- Fix: アクティビティウィジェットのグラフモードが動作しない問題を修正
|
||||
- Fix: ユニコード絵文字の追加辞書をインストールするとユニコード絵文字が絵文字ピッカーで検索できなくなる絵文字があるバグを修正
|
||||
|
||||
### Server
|
||||
- Enhance: ユーザーIPを確実に取得できるために設定ファイルにFastifyOptions.trustProxyを追加しました
|
||||
|
|
|
@ -1010,7 +1010,6 @@ postForm: "أنشئ ملاحظة"
|
|||
information: "عن"
|
||||
inMinutes: "د"
|
||||
inDays: "ي"
|
||||
widgets: "التطبيقات المُصغّرة"
|
||||
_chat:
|
||||
invitations: "دعوة"
|
||||
noHistory: "السجل فارغ"
|
||||
|
|
|
@ -850,7 +850,6 @@ postForm: "নোট লিখুন"
|
|||
information: "আপনার সম্পর্কে"
|
||||
inMinutes: "মিনিট"
|
||||
inDays: "দিন"
|
||||
widgets: "উইজেটগুলি"
|
||||
_chat:
|
||||
invitations: "আমন্ত্রণ"
|
||||
noHistory: "কোনো ইতিহাস নেই"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "Nom del Fitxer"
|
|||
selectFile: "Selecciona un fitxer"
|
||||
selectFiles: "Selecciona fitxers"
|
||||
selectFolder: "Selecció de carpeta"
|
||||
unselectFolder: "Deixa de seleccionar la carpeta"
|
||||
selectFolders: "Selecció de carpetes"
|
||||
fileNotSelected: "Cap fitxer seleccionat"
|
||||
renameFile: "Canvia el nom del fitxer"
|
||||
|
@ -347,7 +346,6 @@ addFile: "Afegeix un fitxer"
|
|||
showFile: "Mostrar fitxer"
|
||||
emptyDrive: "El teu Disc és buit"
|
||||
emptyFolder: "La carpeta està buida"
|
||||
dropHereToUpload: "Arrossega els arxius fins aquí per pujar-los al servidor"
|
||||
unableToDelete: "No es pot eliminar"
|
||||
inputNewFileName: "Introduïu el nom de fitxer nou"
|
||||
inputNewDescription: "Escriu el peu de foto."
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "Programar una nota per {x}"
|
|||
scheduledToPostOnX: "S'ha programat la nota per {x}"
|
||||
schedule: "Programa"
|
||||
scheduled: "Programat"
|
||||
widgets: "Ginys"
|
||||
deviceInfo: "Informació del dispositiu"
|
||||
deviceInfoDescription: "En fer consultes tècniques influir la següent informació pot ajudar a resoldre'l més ràpidament."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Qualitat alta"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "Gestiona les decoracions dels avatars "
|
||||
driveCapacity: "Capacitat del disc"
|
||||
maxFileSize: "Mida màxima de l'arxiu que es pot carregar"
|
||||
maxFileSize_caption: "Pot haver-hi la possibilitat que existeixin altres opcions de configuració de l'etapa anterior, com podria ser el proxy invers i la CDN."
|
||||
alwaysMarkNsfw: "Marca sempre els fitxers com a sensibles"
|
||||
canUpdateBioMedia: "Permet l'edició d'una icona o un bàner"
|
||||
pinMax: "Nombre màxim de notes fixades"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "Opera com si fossis aquest usuari"
|
||||
pleaseLogin: "Si us plau, identificat per autoritzar l'aplicació."
|
||||
byClickingYouWillBeRedirectedToThisUrl: "Si es garanteix l'accés, seràs redirigit automàticament a la següent adreça URL"
|
||||
alreadyAuthorized: "Aquesta aplicació ja té accés."
|
||||
_antennaSources:
|
||||
all: "Totes les publicacions"
|
||||
homeTimeline: "Publicacions dels usuaris seguits"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "Citar"
|
||||
reaction: "Reaccions"
|
||||
pollEnded: "Enquesta terminada"
|
||||
scheduledNotePosted: "Nota programada amb èxit "
|
||||
scheduledNotePostFailed: "Ha fallat la programació de la nota"
|
||||
receiveFollowRequest: "Rebuda una petició de seguiment"
|
||||
followRequestAccepted: "Petició de seguiment acceptada"
|
||||
roleAssigned: "Rol donat"
|
||||
|
|
|
@ -1109,7 +1109,6 @@ postForm: "Formulář pro odeslání"
|
|||
information: "Informace"
|
||||
inMinutes: "Minut"
|
||||
inDays: "Dnů"
|
||||
widgets: "Widgety"
|
||||
_chat:
|
||||
invitations: "Pozvat"
|
||||
noHistory: "Žádná historie"
|
||||
|
|
|
@ -1370,7 +1370,6 @@ defaultImageCompressionLevel: "Standard-Bildkomprimierungsstufe"
|
|||
defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bildqualität, erhöht aber die Dateigröße. <br>Höhere Werte reduzieren die Dateigröße, verringern aber die Bildqualität."
|
||||
inMinutes: "Minute(n)"
|
||||
inDays: "Tag(en)"
|
||||
widgets: "Widgets"
|
||||
_order:
|
||||
newest: "Neueste zuerst"
|
||||
oldest: "Älteste zuerst"
|
||||
|
|
|
@ -288,7 +288,6 @@ replies: "Απάντηση"
|
|||
renotes: "Κοινοποίηση σημειώματος"
|
||||
postForm: "Φόρμα δημοσίευσης"
|
||||
information: "Πληροφορίες"
|
||||
widgets: "Μαραφέτια"
|
||||
_chat:
|
||||
members: "Μέλη"
|
||||
home: "Κεντρικό"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "Filename"
|
|||
selectFile: "Select a file"
|
||||
selectFiles: "Select files"
|
||||
selectFolder: "Select a folder"
|
||||
unselectFolder: "Deselect folder"
|
||||
selectFolders: "Select folders"
|
||||
fileNotSelected: "No file selected"
|
||||
renameFile: "Rename file"
|
||||
|
@ -347,7 +346,6 @@ addFile: "Add a file"
|
|||
showFile: "Show files"
|
||||
emptyDrive: "Your Drive is empty"
|
||||
emptyFolder: "This folder is empty"
|
||||
dropHereToUpload: "Drop files here to upload"
|
||||
unableToDelete: "Unable to delete"
|
||||
inputNewFileName: "Enter a new filename"
|
||||
inputNewDescription: "Enter new alt text"
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "Scheduled to note on {x}"
|
|||
scheduledToPostOnX: "Note is scheduled for {x}"
|
||||
schedule: "Schedule"
|
||||
scheduled: "Scheduled"
|
||||
widgets: "Widgets"
|
||||
deviceInfo: "Device information"
|
||||
deviceInfoDescription: "When making technical inquiries, including the following information may help resolve the issue."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "High quality"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "Manage avatar decorations"
|
||||
driveCapacity: "Drive capacity"
|
||||
maxFileSize: "Upload-able max file size"
|
||||
maxFileSize_caption: "Reverse proxies, CDNs, and other front-end components may have their own configuration settings."
|
||||
alwaysMarkNsfw: "Always mark files as NSFW"
|
||||
canUpdateBioMedia: "Can edit an icon or a banner image"
|
||||
pinMax: "Maximum number of pinned notes"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "Operate as the following user"
|
||||
pleaseLogin: "Please log in to authorize applications."
|
||||
byClickingYouWillBeRedirectedToThisUrl: "When access is granted, you will automatically be redirected to the following URL"
|
||||
alreadyAuthorized: "This application already has access permission."
|
||||
_antennaSources:
|
||||
all: "All notes"
|
||||
homeTimeline: "Notes from followed users"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "Quotes"
|
||||
reaction: "Reactions"
|
||||
pollEnded: "Polls ending"
|
||||
scheduledNotePosted: "Scheduled note was successful"
|
||||
scheduledNotePostFailed: "Scheduled note failed"
|
||||
receiveFollowRequest: "Received follow requests"
|
||||
followRequestAccepted: "Accepted follow requests"
|
||||
roleAssigned: "Role given"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "Nombre de archivo"
|
|||
selectFile: "Elegir archivo"
|
||||
selectFiles: "Elegir archivos"
|
||||
selectFolder: "Seleccione una carpeta"
|
||||
unselectFolder: "Deseleccionar carpeta"
|
||||
selectFolders: "Seleccione carpetas"
|
||||
fileNotSelected: "Archivo no seleccionado."
|
||||
renameFile: "Renombrar archivo"
|
||||
|
@ -347,7 +346,6 @@ addFile: "Agregar archivo"
|
|||
showFile: "Examinar archivos"
|
||||
emptyDrive: "El drive está vacío"
|
||||
emptyFolder: "La carpeta está vacía"
|
||||
dropHereToUpload: "Arrastra los archivos aquí para subirlos."
|
||||
unableToDelete: "No se puede borrar"
|
||||
inputNewFileName: "Ingrese un nuevo nombre de archivo"
|
||||
inputNewDescription: "Ingrese nueva descripción"
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "Programar una nota para {x}"
|
|||
scheduledToPostOnX: "La nota está programada para {x}."
|
||||
schedule: "Programado"
|
||||
scheduled: "Programado"
|
||||
widgets: "Widgets"
|
||||
deviceInfo: "Información del dispositivo"
|
||||
deviceInfoDescription: "Al realizar consultas técnicas, incluir la siguiente información puede ayudar a resolver el problema."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Calidad alta"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "Administrar decoraciones de avatar"
|
||||
driveCapacity: "Capacidad del drive"
|
||||
maxFileSize: "Tamaño máximo de archivo que se puede cargar."
|
||||
maxFileSize_caption: "Los proxies inversos o las CDN pueden tener diferentes valores de configuración aguas arriba."
|
||||
alwaysMarkNsfw: "Siempre marcar archivos como NSFW"
|
||||
canUpdateBioMedia: "Puede editar un icono o una imagen de fondo (banner)"
|
||||
pinMax: "Máximo de notas fijadas"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "Operar como el siguiente usuario"
|
||||
pleaseLogin: "Se requiere un inicio de sesión para darle permisos a la aplicación"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "Cuando el acceso es concedido, serás automáticamente redireccionado a la siguiente URL"
|
||||
alreadyAuthorized: "Esta aplicación ya ha obtenido acceso."
|
||||
_antennaSources:
|
||||
all: "Todas las notas"
|
||||
homeTimeline: "Notas de los usuarios que sigues"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "Citar"
|
||||
reaction: "Reacción"
|
||||
pollEnded: "La encuesta terminó"
|
||||
scheduledNotePosted: "Publicación programada con éxito"
|
||||
scheduledNotePostFailed: "Publicación programada fallida"
|
||||
receiveFollowRequest: "Recibió una solicitud de seguimiento"
|
||||
followRequestAccepted: "El seguimiento fue aceptado"
|
||||
roleAssigned: "Rol asignado"
|
||||
|
|
|
@ -1273,7 +1273,6 @@ postForm: "Formulaire de publication"
|
|||
information: "Informations"
|
||||
inMinutes: "min"
|
||||
inDays: "j"
|
||||
widgets: "Widgets"
|
||||
_chat:
|
||||
invitations: "Inviter"
|
||||
noHistory: "Pas d'historique"
|
||||
|
|
|
@ -1264,7 +1264,6 @@ postForm: "Buat catatan"
|
|||
information: "Informasi"
|
||||
inMinutes: "menit"
|
||||
inDays: "hari"
|
||||
widgets: "Widget"
|
||||
_chat:
|
||||
invitations: "Undang"
|
||||
noHistory: "Tidak ada riwayat"
|
||||
|
|
24
locales/index.d.ts
vendored
24
locales/index.d.ts
vendored
|
@ -1354,10 +1354,6 @@ export interface Locale extends ILocale {
|
|||
* フォルダーを選択
|
||||
*/
|
||||
"selectFolder": string;
|
||||
/**
|
||||
* フォルダーの選択を解除
|
||||
*/
|
||||
"unselectFolder": string;
|
||||
/**
|
||||
* フォルダーを選択
|
||||
*/
|
||||
|
@ -1406,10 +1402,6 @@ export interface Locale extends ILocale {
|
|||
* フォルダーは空です
|
||||
*/
|
||||
"emptyFolder": string;
|
||||
/**
|
||||
* ここにファイルをドロップしてアップロード
|
||||
*/
|
||||
"dropHereToUpload": string;
|
||||
/**
|
||||
* 削除できません
|
||||
*/
|
||||
|
@ -5589,14 +5581,6 @@ export interface Locale extends ILocale {
|
|||
* ウィジェット
|
||||
*/
|
||||
"widgets": string;
|
||||
/**
|
||||
* デバイス情報
|
||||
*/
|
||||
"deviceInfo": string;
|
||||
/**
|
||||
* 技術的なお問い合わせの際に、以下の情報を併記すると問題の解決に役立つことがあります。
|
||||
*/
|
||||
"deviceInfoDescription": string;
|
||||
"_compression": {
|
||||
"_quality": {
|
||||
/**
|
||||
|
@ -7869,10 +7853,6 @@ export interface Locale extends ILocale {
|
|||
* アップロード可能な最大ファイルサイズ
|
||||
*/
|
||||
"maxFileSize": string;
|
||||
/**
|
||||
* リバースプロキシやCDNなど、前段で別の設定値が存在する場合があります。
|
||||
*/
|
||||
"maxFileSize_caption": string;
|
||||
/**
|
||||
* ファイルにNSFWを常に付与
|
||||
*/
|
||||
|
@ -9480,10 +9460,6 @@ export interface Locale extends ILocale {
|
|||
* アクセスを許可すると、自動で以下のURLに遷移します
|
||||
*/
|
||||
"byClickingYouWillBeRedirectedToThisUrl": string;
|
||||
/**
|
||||
* このアプリケーションは既にアクセスが許可されています。
|
||||
*/
|
||||
"alreadyAuthorized": string;
|
||||
};
|
||||
"_antennaSources": {
|
||||
/**
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "Nome dell'allegato"
|
|||
selectFile: "Scelta allegato"
|
||||
selectFiles: "Scelta allegato"
|
||||
selectFolder: "Seleziona cartella"
|
||||
unselectFolder: "Deseleziona la cartella"
|
||||
selectFolders: "Seleziona cartella"
|
||||
fileNotSelected: "Nessun file selezionato"
|
||||
renameFile: "Rinomina file"
|
||||
|
@ -347,7 +346,6 @@ addFile: "Allega"
|
|||
showFile: "Visualizza file"
|
||||
emptyDrive: "Il Drive è vuoto"
|
||||
emptyFolder: "La cartella è vuota"
|
||||
dropHereToUpload: "Trascina qui il tuo file per caricarlo"
|
||||
unableToDelete: "Eliminazione impossibile"
|
||||
inputNewFileName: "Inserisci nome del nuovo file"
|
||||
inputNewDescription: "Inserisci una nuova descrizione"
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "Pianificare la pubblicazione {x}"
|
|||
scheduledToPostOnX: "Pubblicazione pianificata {x}"
|
||||
schedule: "Pianificare"
|
||||
scheduled: "Pianificata"
|
||||
widgets: "Riquadri"
|
||||
deviceInfo: "Informazioni sul dispositivo"
|
||||
deviceInfoDescription: "Se ci contatti per ricevere supporto tecnico, ti preghiamo di includere le seguenti informazioni per aiutarci a risolvere il tuo problema."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Alta qualità"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "Gestisce le decorazioni di immagini del profilo"
|
||||
driveCapacity: "Capienza del Drive"
|
||||
maxFileSize: "Dimensione massima del file caricabile"
|
||||
maxFileSize_caption: "Potrebbero esserci altre impostazioni nella fase precedente, come reverse proxy o CDN."
|
||||
alwaysMarkNsfw: "Impostare sempre come esplicito (NSFW)"
|
||||
canUpdateBioMedia: "Può aggiornare foto profilo e di testata"
|
||||
pinMax: "Quantità massima di Note in primo piano"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "Sto funzionando per il seguente profilo"
|
||||
pleaseLogin: "Per favore accedi al tuo account per cambiare i permessi dell'applicazione"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "Consentendo l'accesso, si verrà reindirizzati presso questo indirizzo URL"
|
||||
alreadyAuthorized: "Questa applicazione è già autorizzata ad accedere."
|
||||
_antennaSources:
|
||||
all: "Tutte le note"
|
||||
homeTimeline: "Note dai tuoi Following"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "Cita"
|
||||
reaction: "Reazioni"
|
||||
pollEnded: "Sondaggio terminato"
|
||||
scheduledNotePosted: "Nota pianificata correttamente"
|
||||
scheduledNotePostFailed: "La pianificazione della Nota è fallita"
|
||||
receiveFollowRequest: "Richieste di follow in arrivo"
|
||||
followRequestAccepted: "Richieste di follow accettate"
|
||||
roleAssigned: "Ruolo concesso"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "ファイル名"
|
|||
selectFile: "ファイルを選択"
|
||||
selectFiles: "ファイルを選択"
|
||||
selectFolder: "フォルダーを選択"
|
||||
unselectFolder: "フォルダーの選択を解除"
|
||||
selectFolders: "フォルダーを選択"
|
||||
fileNotSelected: "ファイルが選択されていません"
|
||||
renameFile: "ファイル名を変更"
|
||||
|
@ -347,7 +346,6 @@ addFile: "ファイルを追加"
|
|||
showFile: "ファイルを表示"
|
||||
emptyDrive: "ドライブは空です"
|
||||
emptyFolder: "フォルダーは空です"
|
||||
dropHereToUpload: "ここにファイルをドロップしてアップロード"
|
||||
unableToDelete: "削除できません"
|
||||
inputNewFileName: "新しいファイル名を入力してください"
|
||||
inputNewDescription: "新しいキャプションを入力してください"
|
||||
|
@ -1392,8 +1390,6 @@ scheduledToPostOnX: "{x}に投稿が予約されています"
|
|||
schedule: "予約"
|
||||
scheduled: "予約"
|
||||
widgets: "ウィジェット"
|
||||
deviceInfo: "デバイス情報"
|
||||
deviceInfoDescription: "技術的なお問い合わせの際に、以下の情報を併記すると問題の解決に役立つことがあります。"
|
||||
|
||||
_compression:
|
||||
_quality:
|
||||
|
@ -2040,7 +2036,6 @@ _role:
|
|||
canManageAvatarDecorations: "アバターデコレーションの管理"
|
||||
driveCapacity: "ドライブ容量"
|
||||
maxFileSize: "アップロード可能な最大ファイルサイズ"
|
||||
maxFileSize_caption: "リバースプロキシやCDNなど、前段で別の設定値が存在する場合があります。"
|
||||
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
|
||||
canUpdateBioMedia: "アイコンとバナーの更新を許可"
|
||||
pinMax: "ノートのピン留めの最大数"
|
||||
|
@ -2489,7 +2484,6 @@ _auth:
|
|||
scopeUser: "以下のユーザーとして操作しています"
|
||||
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "アクセスを許可すると、自動で以下のURLに遷移します"
|
||||
alreadyAuthorized: "このアプリケーションは既にアクセスが許可されています。"
|
||||
|
||||
_antennaSources:
|
||||
all: "全てのノート"
|
||||
|
|
|
@ -1337,7 +1337,6 @@ safeModeEnabled: "セーフモードがオンになってるで"
|
|||
pluginsAreDisabledBecauseSafeMode: "セーフモードがオンやから、プラグインは全部無効化されてるで。"
|
||||
customCssIsDisabledBecauseSafeMode: "セーフモードがオンやから、カスタムCSSは適用されてへんで。"
|
||||
themeIsDefaultBecauseSafeMode: "セーフモードがオンの間はデフォルトのテーマを使うで。セーフモードをオフにれば元に戻るで。"
|
||||
widgets: "ウィジェット"
|
||||
_chat:
|
||||
noMessagesYet: "まだメッセージはあらへんで"
|
||||
individualChat_description: "特定のユーザーと一対一でチャットができるで。"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "파일명"
|
|||
selectFile: "파일 선택"
|
||||
selectFiles: "파일 선택"
|
||||
selectFolder: "폴더 선택"
|
||||
unselectFolder: "폴더 선택 해제"
|
||||
selectFolders: "폴더 선택"
|
||||
fileNotSelected: "파일을 선택하지 않았습니다"
|
||||
renameFile: "파일 이름 변경"
|
||||
|
@ -347,7 +346,6 @@ addFile: "파일 추가"
|
|||
showFile: "파일 표시하기"
|
||||
emptyDrive: "드라이브가 비어 있습니다"
|
||||
emptyFolder: "폴더가 비어 있습니다"
|
||||
dropHereToUpload: "업로드할 파일을 여기로 드롭하십시오"
|
||||
unableToDelete: "삭제할 수 없습니다"
|
||||
inputNewFileName: "바꿀 파일명을 입력해 주세요"
|
||||
inputNewDescription: "새 캡션을 입력해 주세요"
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "{x}에 게시를 예약합니다."
|
|||
scheduledToPostOnX: "{x}에 게시가 예약돼있습니다."
|
||||
schedule: "예약"
|
||||
scheduled: "예약"
|
||||
widgets: "위젯"
|
||||
deviceInfo: "장치 정보"
|
||||
deviceInfoDescription: "기술적 문의의 경우 아래의 정보를 병기하면 문제의 해결에 도움이 됩니다."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "고품질"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "아바타 꾸미기 관리"
|
||||
driveCapacity: "드라이브 용량"
|
||||
maxFileSize: "업로드 가능한 최대 파일 크기"
|
||||
maxFileSize_caption: "리버스 프록시나 CDN 등 전단에서 다른 설정값이 존재하는 경우가 있습니다."
|
||||
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
|
||||
canUpdateBioMedia: "아바타 및 배너 이미지 변경 허용"
|
||||
pinMax: "고정할 수 있는 노트 수"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "다음 유저로 활동하고 있습니다."
|
||||
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
|
||||
byClickingYouWillBeRedirectedToThisUrl: "접근을 허용하면 자동으로 다음 URL로 이동합니다."
|
||||
alreadyAuthorized: "이 애플리케이션은 이미 접근이 허가돼있습니다."
|
||||
_antennaSources:
|
||||
all: "모든 노트"
|
||||
homeTimeline: "팔로우중인 유저의 노트"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "인용"
|
||||
reaction: "리액션"
|
||||
pollEnded: "투표가 종료됨"
|
||||
scheduledNotePosted: "예약 게시에 성공했습니다"
|
||||
scheduledNotePostFailed: "예약 게시에 실패했습니다"
|
||||
receiveFollowRequest: "팔로우 요청을 받았을 때"
|
||||
followRequestAccepted: "팔로우 요청이 승인되었을 때"
|
||||
roleAssigned: "역할이 부여됨"
|
||||
|
|
|
@ -1042,7 +1042,6 @@ postForm: "Formularz tworzenia wpisu"
|
|||
information: "Informacje"
|
||||
inMinutes: "minuta"
|
||||
inDays: "dzień"
|
||||
widgets: "Widżety"
|
||||
_chat:
|
||||
invitations: "Zaproś"
|
||||
noHistory: "Brak historii"
|
||||
|
|
|
@ -1389,7 +1389,6 @@ scheduleToPostOnX: "Agendar nota para {x}"
|
|||
scheduledToPostOnX: "A nota está agendada para {x}"
|
||||
schedule: "Agendar"
|
||||
scheduled: "Agendado"
|
||||
widgets: "Widgets"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Qualidade alta"
|
||||
|
|
|
@ -1277,7 +1277,6 @@ textCount: "Количество символов"
|
|||
information: "Описание"
|
||||
inMinutes: "мин"
|
||||
inDays: "сут"
|
||||
widgets: "Виджеты"
|
||||
_chat:
|
||||
invitations: "Пригласить"
|
||||
noHistory: "История пока пуста"
|
||||
|
|
|
@ -915,7 +915,6 @@ postForm: "Napísať poznámku"
|
|||
information: "Informácie"
|
||||
inMinutes: "min"
|
||||
inDays: "dní"
|
||||
widgets: "Widgety"
|
||||
_chat:
|
||||
invitations: "Pozvať"
|
||||
noHistory: "Žiadna história"
|
||||
|
|
|
@ -1389,7 +1389,6 @@ scheduleToPostOnX: "กำหนดเวลาให้โพสต์ไว้
|
|||
scheduledToPostOnX: "มีการกำหนดเวลาให้โพสต์ไว้ที่ {x}"
|
||||
schedule: "กำหนดเวลา"
|
||||
scheduled: "กำหนดเวลา"
|
||||
widgets: "วิดเจ็ต"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "คุณภาพสูง"
|
||||
|
|
|
@ -1378,7 +1378,6 @@ pluginsAreDisabledBecauseSafeMode: "Güvenli mod etkinleştirildiği için tüm
|
|||
customCssIsDisabledBecauseSafeMode: "Güvenli mod etkin olduğu için özel CSS uygulanmıyor."
|
||||
themeIsDefaultBecauseSafeMode: "Güvenli mod etkinken, varsayılan tema kullanılır. Güvenli modu devre dışı bırakmak bu değişiklikleri geri alır."
|
||||
thankYouForTestingBeta: "Beta sürümünü test ettiğin için teşekkür ederiz!"
|
||||
widgets: "Widget'lar"
|
||||
_order:
|
||||
newest: "Önce yeni"
|
||||
oldest: "Önce eski"
|
||||
|
|
|
@ -921,7 +921,6 @@ postForm: "Створення нотатки"
|
|||
information: "Інформація"
|
||||
inMinutes: "х"
|
||||
inDays: "д"
|
||||
widgets: "Віджети"
|
||||
_chat:
|
||||
invitations: "Запросити"
|
||||
noHistory: "Історія порожня"
|
||||
|
|
|
@ -1222,7 +1222,6 @@ migrateOldSettings: "Di chuyển cài đặt cũ"
|
|||
migrateOldSettings_description: "Thông thường, quá trình này diễn ra tự động, nhưng nếu vì lý do nào đó mà quá trình di chuyển không thành công, bạn có thể kích hoạt thủ công quy trình di chuyển, quá trình này sẽ ghi đè lên thông tin cấu hình hiện tại của bạn."
|
||||
inMinutes: "phút"
|
||||
inDays: "ngày"
|
||||
widgets: "Tiện ích"
|
||||
_chat:
|
||||
invitations: "Mời"
|
||||
noHistory: "Không có dữ liệu"
|
||||
|
|
|
@ -56,7 +56,7 @@ deleteAndEdit: "删除并编辑"
|
|||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
||||
addToList: "添加至列表"
|
||||
addToAntenna: "添加到天线"
|
||||
sendMessage: "发送消息"
|
||||
sendMessage: "发送"
|
||||
copyRSS: "复制RSS"
|
||||
copyUsername: "复制用户名"
|
||||
copyUserId: "复制用户 ID"
|
||||
|
@ -334,7 +334,6 @@ fileName: "文件名称"
|
|||
selectFile: "选择文件"
|
||||
selectFiles: "选择文件"
|
||||
selectFolder: "选择文件夹"
|
||||
unselectFolder: "取消全选文件夹"
|
||||
selectFolders: "选择多个文件夹"
|
||||
fileNotSelected: "未选择文件"
|
||||
renameFile: "重命名文件"
|
||||
|
@ -347,7 +346,6 @@ addFile: "添加文件"
|
|||
showFile: "显示文件"
|
||||
emptyDrive: "网盘中无文件"
|
||||
emptyFolder: "此文件夹中无文件"
|
||||
dropHereToUpload: "将文件拖动到这里来上传"
|
||||
unableToDelete: "无法删除"
|
||||
inputNewFileName: "请输入新文件名"
|
||||
inputNewDescription: "请输入新标题"
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "预定在 {x} 发出"
|
|||
scheduledToPostOnX: "已预定在 {x} 发出"
|
||||
schedule: "定时"
|
||||
scheduled: "定时"
|
||||
widgets: "小工具"
|
||||
deviceInfo: "设备信息"
|
||||
deviceInfoDescription: "咨询技术问题时,将以下信息一并发送有助于解决问题。"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "高质量"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "管理头像挂件"
|
||||
driveCapacity: "网盘容量"
|
||||
maxFileSize: "可上传的最大文件大小"
|
||||
maxFileSize_caption: "可能在反向代理或 CDN 等前端存在其它设定值。"
|
||||
alwaysMarkNsfw: "总是将文件标记为 NSFW"
|
||||
canUpdateBioMedia: "可以更新头像和横幅"
|
||||
pinMax: "帖子置顶数量限制"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "以下面的用户进行操作"
|
||||
pleaseLogin: "在对应用进行授权许可之前,请先登录"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "允许访问后将会自动重定向到以下 URL"
|
||||
alreadyAuthorized: "此应用已有访问许可。"
|
||||
_antennaSources:
|
||||
all: "所有帖子"
|
||||
homeTimeline: "已关注用户的帖子"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "引用"
|
||||
reaction: "回应"
|
||||
pollEnded: "问卷调查结束"
|
||||
scheduledNotePosted: "定时发送成功"
|
||||
scheduledNotePostFailed: "定时发送失败"
|
||||
receiveFollowRequest: "收到关注请求"
|
||||
followRequestAccepted: "关注请求已通过"
|
||||
roleAssigned: "授予的角色"
|
||||
|
|
|
@ -334,7 +334,6 @@ fileName: "檔案名稱"
|
|||
selectFile: "選擇檔案"
|
||||
selectFiles: "選擇檔案"
|
||||
selectFolder: "選擇資料夾"
|
||||
unselectFolder: "取消選擇資料夾"
|
||||
selectFolders: "選擇資料夾"
|
||||
fileNotSelected: "尚未選擇檔案"
|
||||
renameFile: "重新命名檔案"
|
||||
|
@ -347,7 +346,6 @@ addFile: "加入附件"
|
|||
showFile: "瀏覽文件"
|
||||
emptyDrive: "雲端硬碟為空"
|
||||
emptyFolder: "資料夾為空"
|
||||
dropHereToUpload: "將檔案拖放至此處即可上傳"
|
||||
unableToDelete: "無法刪除"
|
||||
inputNewFileName: "輸入檔案名稱"
|
||||
inputNewDescription: "請輸入新標題 "
|
||||
|
@ -1391,9 +1389,6 @@ scheduleToPostOnX: "排定在 {x} 發布"
|
|||
scheduledToPostOnX: "已排定在 {x} 發布貼文"
|
||||
schedule: "排定"
|
||||
scheduled: "排定"
|
||||
widgets: "小工具"
|
||||
deviceInfo: "硬體資訊"
|
||||
deviceInfoDescription: "在提出技術性諮詢時,若能同時提供以下資訊,將有助於解決問題。"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "高品質"
|
||||
|
@ -2018,7 +2013,6 @@ _role:
|
|||
canManageAvatarDecorations: "管理頭像裝飾"
|
||||
driveCapacity: "雲端硬碟容量"
|
||||
maxFileSize: "可上傳的最大檔案大小"
|
||||
maxFileSize_caption: "前端可能還有其他設定值,例如反向代理或 CDN。"
|
||||
alwaysMarkNsfw: "總是將檔案標記為NSFW"
|
||||
canUpdateBioMedia: "允許更新大頭貼和橫幅"
|
||||
pinMax: "置頂貼文的最大數量"
|
||||
|
@ -2437,7 +2431,6 @@ _auth:
|
|||
scopeUser: "以下列使用者身分操作"
|
||||
pleaseLogin: "必須登入以提供應用程式的存取權限。"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "如果授予存取權限,就會自動導向到以下的網址"
|
||||
alreadyAuthorized: "此應用程式已被授予存取權限。"
|
||||
_antennaSources:
|
||||
all: "全部貼文"
|
||||
homeTimeline: "來自已追隨使用者的貼文"
|
||||
|
@ -2704,8 +2697,6 @@ _notification:
|
|||
quote: "引用"
|
||||
reaction: "反應"
|
||||
pollEnded: "問卷調查結束"
|
||||
scheduledNotePosted: "預約發佈成功"
|
||||
scheduledNotePostFailed: "預約發佈失敗"
|
||||
receiveFollowRequest: "已收到追隨請求"
|
||||
followRequestAccepted: "追隨請求已接受"
|
||||
roleAssigned: "已授予角色"
|
||||
|
|
16
package.json
16
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"version": "2025.10.1-alpha.1",
|
||||
"version": "2025.10.0-beta.1",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -58,21 +58,21 @@
|
|||
"execa": "9.6.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"glob": "11.0.3",
|
||||
"ignore-walk": "8.0.0",
|
||||
"ignore-walk": "7.0.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"postcss": "8.5.6",
|
||||
"tar": "7.5.1",
|
||||
"terser": "5.44.0",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/eslint-plugin": "2.1.0",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"cross-env": "10.1.0",
|
||||
"cypress": "15.3.0",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "14.5.4",
|
||||
"eslint": "9.36.0",
|
||||
"globals": "16.4.0",
|
||||
"ncp": "2.0.0",
|
||||
|
|
|
@ -39,17 +39,17 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-android-arm64": "1.3.11",
|
||||
"@swc/core-darwin-arm64": "1.13.20",
|
||||
"@swc/core-darwin-x64": "1.13.20",
|
||||
"@swc/core-darwin-arm64": "1.13.19",
|
||||
"@swc/core-darwin-x64": "1.13.19",
|
||||
"@swc/core-freebsd-x64": "1.3.11",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.13.20",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.20",
|
||||
"@swc/core-linux-arm64-musl": "1.13.20",
|
||||
"@swc/core-linux-x64-gnu": "1.13.20",
|
||||
"@swc/core-linux-x64-musl": "1.13.20",
|
||||
"@swc/core-win32-arm64-msvc": "1.13.20",
|
||||
"@swc/core-win32-ia32-msvc": "1.13.20",
|
||||
"@swc/core-win32-x64-msvc": "1.13.20",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.13.19",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.19",
|
||||
"@swc/core-linux-arm64-musl": "1.13.19",
|
||||
"@swc/core-linux-x64-gnu": "1.13.19",
|
||||
"@swc/core-linux-x64-musl": "1.13.19",
|
||||
"@swc/core-win32-arm64-msvc": "1.13.19",
|
||||
"@swc/core-win32-ia32-msvc": "1.13.19",
|
||||
"@swc/core-win32-x64-msvc": "1.13.19",
|
||||
"@tensorflow/tfjs": "4.22.0",
|
||||
"@tensorflow/tfjs-node": "4.22.0",
|
||||
"bufferutil": "4.0.9",
|
||||
|
@ -69,10 +69,10 @@
|
|||
"utf-8-validate": "6.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.901.0",
|
||||
"@aws-sdk/lib-storage": "3.901.0",
|
||||
"@aws-sdk/client-s3": "3.896.0",
|
||||
"@aws-sdk/lib-storage": "3.895.0",
|
||||
"@discordapp/twemoji": "16.0.1",
|
||||
"@fastify/accepts": "5.0.3",
|
||||
"@fastify/accepts": "5.0.2",
|
||||
"@fastify/cookie": "11.0.2",
|
||||
"@fastify/cors": "10.1.0",
|
||||
"@fastify/express": "4.0.2",
|
||||
|
@ -81,7 +81,7 @@
|
|||
"@fastify/static": "8.2.0",
|
||||
"@fastify/view": "10.0.2",
|
||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@misskey-dev/summaly": "5.2.3",
|
||||
"@napi-rs/canvas": "0.1.80",
|
||||
"@nestjs/common": "11.1.6",
|
||||
"@nestjs/core": "11.1.6",
|
||||
|
@ -103,7 +103,7 @@
|
|||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"body-parser": "1.20.3",
|
||||
"bullmq": "5.59.0",
|
||||
"bullmq": "5.58.8",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "9.0.2",
|
||||
"chalk": "5.6.2",
|
||||
|
@ -134,7 +134,7 @@
|
|||
"json5": "2.2.3",
|
||||
"jsonld": "8.3.3",
|
||||
"jsrsasign": "11.1.0",
|
||||
"juice": "11.0.3",
|
||||
"juice": "11.0.1",
|
||||
"meilisearch": "0.53.0",
|
||||
"mfm-js": "0.25.0",
|
||||
"microformats-parser": "2.0.4",
|
||||
|
@ -181,7 +181,7 @@
|
|||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typeorm": "0.3.27",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"ulid": "2.4.0",
|
||||
"vary": "1.1.2",
|
||||
"web-push": "3.6.7",
|
||||
|
@ -210,8 +210,8 @@
|
|||
"@types/jsrsasign": "10.5.15",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/ms": "0.7.34",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/nodemailer": "6.4.20",
|
||||
"@types/node": "22.18.6",
|
||||
"@types/nodemailer": "6.4.19",
|
||||
"@types/oauth": "0.9.6",
|
||||
"@types/oauth2orize": "1.11.5",
|
||||
"@types/oauth2orize-pkce": "0.1.2",
|
||||
|
@ -231,8 +231,8 @@
|
|||
"@types/vary": "1.1.3",
|
||||
"@types/web-push": "3.6.4",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"aws-sdk-client-mock": "4.1.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
|
|
|
@ -172,14 +172,6 @@ export class NoteDraftService {
|
|||
me: MiLocalUser,
|
||||
data: Partial<NoteDraftOptions>,
|
||||
): Promise<void> {
|
||||
if (data.isActuallyScheduled) {
|
||||
if (data.scheduledAt == null) {
|
||||
throw new IdentifiableError('94a89a43-3591-400a-9c17-dd166e71fdfa', 'scheduledAt is required when isActuallyScheduled is true');
|
||||
} else if (data.scheduledAt.getTime() < Date.now()) {
|
||||
throw new IdentifiableError('b34d0c1b-996f-4e34-a428-c636d98df457', 'scheduledAt must be in the future');
|
||||
}
|
||||
}
|
||||
|
||||
if (data.pollExpiresAt != null) {
|
||||
if (data.pollExpiresAt.getTime() < Date.now()) {
|
||||
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
||||
|
@ -328,7 +320,6 @@ export class NoteDraftService {
|
|||
|
||||
@bindThis
|
||||
public async clearSchedule(draftId: MiNoteDraft['id']): Promise<void> {
|
||||
// TODO: 線形探索なのをどうにかする
|
||||
const jobs = await this.queueService.postScheduledNoteQueue.getJobs(['delayed', 'waiting', 'active']);
|
||||
for (const job of jobs) {
|
||||
if (job.data.noteDraftId === draftId) {
|
||||
|
|
|
@ -109,7 +109,8 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||
canImportUserLists: false,
|
||||
chatAvailability: 'available',
|
||||
uploadableFileTypes: [
|
||||
'text/*',
|
||||
'text/plain',
|
||||
'text/csv',
|
||||
'application/json',
|
||||
'image/*',
|
||||
'video/*',
|
||||
|
|
|
@ -153,14 +153,11 @@ export class MiNoteDraft {
|
|||
|
||||
//#endregion
|
||||
|
||||
// 予約日時
|
||||
// これがあるだけでは実際に予約されているかどうかはわからない
|
||||
@Column('timestamp with time zone', {
|
||||
nullable: true,
|
||||
})
|
||||
public scheduledAt: Date | null;
|
||||
|
||||
// scheduledAtに基づいて実際にスケジュールされているか
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
|
|
|
@ -192,7 +192,7 @@ export const paramDef = {
|
|||
scheduledAt: { type: 'integer', nullable: true },
|
||||
isActuallyScheduled: { type: 'boolean', default: false },
|
||||
},
|
||||
required: [],
|
||||
required: ['visibility', 'visibleUserIds', 'cw', 'hashtag', 'localOnly', 'reactionAcceptance', 'replyId', 'renoteId', 'channelId', 'text', 'fileIds', 'poll', 'scheduledAt', 'isActuallyScheduled'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
|
@ -203,22 +203,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const draft = await this.noteDraftService.create(me, {
|
||||
fileIds: ps.fileIds ?? [],
|
||||
fileIds: ps.fileIds,
|
||||
pollChoices: ps.poll?.choices ?? [],
|
||||
pollMultiple: ps.poll?.multiple ?? false,
|
||||
pollExpiresAt: ps.poll?.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
||||
pollExpiredAfter: ps.poll?.expiredAfter ?? null,
|
||||
hasPoll: ps.poll != null,
|
||||
text: ps.text ?? null,
|
||||
replyId: ps.replyId ?? null,
|
||||
renoteId: ps.renoteId ?? null,
|
||||
cw: ps.cw ?? null,
|
||||
hashtag: ps.hashtag ?? null,
|
||||
text: ps.text,
|
||||
replyId: ps.replyId,
|
||||
renoteId: ps.renoteId,
|
||||
cw: ps.cw,
|
||||
hashtag: ps.hashtag,
|
||||
localOnly: ps.localOnly,
|
||||
reactionAcceptance: ps.reactionAcceptance,
|
||||
visibility: ps.visibility,
|
||||
visibleUserIds: ps.visibleUserIds ?? [],
|
||||
channelId: ps.channelId ?? null,
|
||||
visibleUserIds: ps.visibleUserIds,
|
||||
channelId: ps.channelId,
|
||||
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
||||
isActuallyScheduled: ps.isActuallyScheduled,
|
||||
}).catch((err) => {
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"rollup": "4.52.3",
|
||||
"typescript": "5.9.3"
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"rollup": "4.52.2",
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"estree-walker": "3.0.3",
|
||||
|
|
|
@ -26,37 +26,37 @@
|
|||
"mfm-js": "0.25.0",
|
||||
"misskey-js": "workspace:*",
|
||||
"punycode.js": "2.3.1",
|
||||
"rollup": "4.52.3",
|
||||
"rollup": "4.52.2",
|
||||
"sass": "1.93.2",
|
||||
"shiki": "3.13.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"uuid": "13.0.0",
|
||||
"typescript": "5.9.2",
|
||||
"uuid": "11.1.0",
|
||||
"vite": "7.1.7",
|
||||
"vue": "3.5.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@misskey-dev/summaly": "5.2.3",
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/node": "22.18.6",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/runtime-core": "3.5.22",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.1.0",
|
||||
"cross-env": "10.0.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"happy-dom": "19.0.2",
|
||||
"happy-dom": "18.0.1",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"msw": "2.11.3",
|
||||
|
@ -65,8 +65,8 @@
|
|||
"start-server-and-test": "2.1.2",
|
||||
"tsx": "4.20.6",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vue-component-type-helpers": "3.1.0",
|
||||
"vue-component-type-helpers": "3.0.8",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
"vue-tsc": "3.1.0"
|
||||
"vue-tsc": "3.0.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"esbuild": "0.25.10",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"vue-eslint-parser": "10.2.0"
|
||||
},
|
||||
"files": [
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@sentry/vue": "10.17.0",
|
||||
"@sentry/vue": "10.15.0",
|
||||
"@syuilo/aiscript": "1.1.2",
|
||||
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
|
@ -41,7 +41,7 @@
|
|||
"chartjs-chart-matrix": "3.0.0",
|
||||
"chartjs-plugin-gradient": "0.6.1",
|
||||
"chartjs-plugin-zoom": "2.2.0",
|
||||
"chromatic": "13.3.0",
|
||||
"chromatic": "13.2.1",
|
||||
"compare-versions": "6.1.1",
|
||||
"cropperjs": "2.0.1",
|
||||
"date-fns": "4.1.0",
|
||||
|
@ -57,7 +57,7 @@
|
|||
"json5": "2.2.3",
|
||||
"magic-string": "0.30.19",
|
||||
"matter-js": "0.20.0",
|
||||
"mediabunny": "1.21.1",
|
||||
"mediabunny": "1.21.0",
|
||||
"mfm-js": "0.25.0",
|
||||
"misskey-bubble-game": "workspace:*",
|
||||
"misskey-js": "workspace:*",
|
||||
|
@ -66,7 +66,7 @@
|
|||
"punycode.js": "2.3.1",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qr-scanner": "1.4.2",
|
||||
"rollup": "4.52.3",
|
||||
"rollup": "4.52.2",
|
||||
"sanitize-html": "2.17.0",
|
||||
"sass": "1.93.2",
|
||||
"shiki": "3.13.0",
|
||||
|
@ -77,7 +77,7 @@
|
|||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"v-code-diff": "1.13.1",
|
||||
"vite": "7.1.7",
|
||||
"vue": "3.5.22",
|
||||
|
@ -85,10 +85,10 @@
|
|||
"wanakana": "5.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@misskey-dev/summaly": "5.2.3",
|
||||
"@storybook/addon-essentials": "8.6.14",
|
||||
"@storybook/addon-interactions": "8.6.14",
|
||||
"@storybook/addon-links": "9.1.10",
|
||||
"@storybook/addon-links": "9.1.8",
|
||||
"@storybook/addon-mdx-gfm": "8.6.14",
|
||||
"@storybook/addon-storysource": "8.6.14",
|
||||
"@storybook/blocks": "8.6.14",
|
||||
|
@ -96,38 +96,38 @@
|
|||
"@storybook/core-events": "8.6.14",
|
||||
"@storybook/manager-api": "8.6.14",
|
||||
"@storybook/preview-api": "8.6.14",
|
||||
"@storybook/react": "9.1.10",
|
||||
"@storybook/react-vite": "9.1.10",
|
||||
"@storybook/react": "9.1.8",
|
||||
"@storybook/react-vite": "9.1.8",
|
||||
"@storybook/test": "8.6.14",
|
||||
"@storybook/theming": "8.6.14",
|
||||
"@storybook/types": "8.6.14",
|
||||
"@storybook/vue3": "9.1.10",
|
||||
"@storybook/vue3-vite": "9.1.10",
|
||||
"@storybook/vue3": "9.1.8",
|
||||
"@storybook/vue3-vite": "9.1.8",
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/canvas-confetti": "1.9.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/matter-js": "0.20.2",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/node": "22.18.6",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/sanitize-html": "2.16.0",
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@types/throttle-debounce": "5.0.2",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/compiler-core": "3.5.22",
|
||||
"@vue/runtime-core": "3.5.22",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.1.0",
|
||||
"cypress": "15.3.0",
|
||||
"cross-env": "10.0.0",
|
||||
"cypress": "14.5.4",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"happy-dom": "19.0.2",
|
||||
"happy-dom": "18.0.1",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"minimatch": "10.0.3",
|
||||
|
@ -135,18 +135,18 @@
|
|||
"msw-storybook-addon": "2.0.5",
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.6.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"seedrandom": "3.0.5",
|
||||
"start-server-and-test": "2.1.2",
|
||||
"storybook": "9.1.10",
|
||||
"storybook": "9.1.8",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"tsx": "4.20.6",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vitest": "3.2.4",
|
||||
"vitest-fetch-mock": "0.4.5",
|
||||
"vue-component-type-helpers": "3.1.0",
|
||||
"vue-component-type-helpers": "3.0.8",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
"vue-tsc": "3.1.0"
|
||||
"vue-tsc": "3.0.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ export function createAiScriptEnv(opts: { storageKey: string, token?: string })
|
|||
});
|
||||
return confirm.canceled ? values.FALSE : values.TRUE;
|
||||
}),
|
||||
'Mk:toast': values.FN_NATIVE(([text]) => {
|
||||
'Mk:toast': values.FN_NATIVE(async ([text]) => {
|
||||
utils.assertString(text);
|
||||
os.toast(text.value);
|
||||
return values.NULL;
|
||||
|
|
|
@ -5,13 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<div
|
||||
:class="[$style.codeBlockRoot, {
|
||||
[$style.codeEditor]: codeEditor,
|
||||
[$style.outerStyle]: !codeEditor && withOuterStyle,
|
||||
[$style.dark]: darkMode,
|
||||
[$style.light]: !darkMode,
|
||||
}]" v-html="html"></div>
|
||||
<div :class="[$style.codeBlockRoot, { [$style.codeEditor]: codeEditor }, (darkMode ? $style.dark : $style.light)]" v-html="html"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
@ -21,15 +15,11 @@ import type { BundledLanguage } from 'shiki/langs';
|
|||
import { getHighlighter, getTheme } from '@/utility/code-highlighter.js';
|
||||
import { store } from '@/store.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const props = defineProps<{
|
||||
code: string;
|
||||
lang?: string;
|
||||
codeEditor?: boolean;
|
||||
withOuterStyle?: boolean;
|
||||
}>(), {
|
||||
codeEditor: false,
|
||||
withOuterStyle: true,
|
||||
});
|
||||
}>();
|
||||
|
||||
const highlighter = await getHighlighter();
|
||||
const darkMode = store.r.darkMode;
|
||||
|
@ -83,13 +73,17 @@ watch(() => props.lang, (to) => {
|
|||
|
||||
<style module lang="scss">
|
||||
.codeBlockRoot :global(.shiki) {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
font-family: Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace;
|
||||
|
||||
color: var(--shiki-fallback);
|
||||
background-color: var(--shiki-fallback-bg);
|
||||
|
||||
& span {
|
||||
color: var(--shiki-fallback);
|
||||
background-color: var(--shiki-fallback-bg);
|
||||
}
|
||||
|
||||
& pre,
|
||||
|
@ -98,39 +92,25 @@ watch(() => props.lang, (to) => {
|
|||
}
|
||||
}
|
||||
|
||||
.outerStyle.codeBlockRoot :global(.shiki) {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--MI_THEME-divider);
|
||||
background-color: var(--shiki-fallback-bg);
|
||||
}
|
||||
|
||||
.light.codeBlockRoot :global(.shiki) {
|
||||
color: var(--shiki-light);
|
||||
background-color: var(--shiki-light-bg);
|
||||
|
||||
& span {
|
||||
color: var(--shiki-light);
|
||||
}
|
||||
}
|
||||
|
||||
.light.outerStyle.codeBlockRoot :global(.shiki),
|
||||
.light.codeEditor.codeBlockRoot :global(.shiki) {
|
||||
background-color: var(--shiki-light-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.dark.codeBlockRoot :global(.shiki) {
|
||||
color: var(--shiki-dark);
|
||||
background-color: var(--shiki-dark-bg);
|
||||
|
||||
& span {
|
||||
color: var(--shiki-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.dark.outerStyle.codeBlockRoot :global(.shiki),
|
||||
.dark.codeEditor.codeBlockRoot :global(.shiki) {
|
||||
background-color: var(--shiki-dark-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.codeBlockRoot.codeEditor {
|
||||
min-width: 100%;
|
||||
|
|
|
@ -5,32 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div :class="$style.codeBlockRoot">
|
||||
<button v-if="copyButton" :class="[$style.codeBlockCopyButton, { [$style.withOuterStyle]: withOuterStyle }]" class="_button" @click="copy">
|
||||
<button v-if="copyButton" :class="$style.codeBlockCopyButton" class="_button" @click="copy">
|
||||
<i class="ti ti-copy"></i>
|
||||
</button>
|
||||
<Suspense>
|
||||
<template #fallback>
|
||||
<pre
|
||||
class="_selectable"
|
||||
:class="[$style.codeBlockFallbackRoot, {
|
||||
[$style.outerStyle]: withOuterStyle,
|
||||
}]"
|
||||
><code :class="$style.codeBlockFallbackCode">Loading...</code></pre>
|
||||
<MkLoading/>
|
||||
</template>
|
||||
<XCode
|
||||
v-if="show && lang"
|
||||
class="_selectable"
|
||||
:code="code"
|
||||
:lang="lang"
|
||||
:withOuterStyle="withOuterStyle"
|
||||
/>
|
||||
<pre
|
||||
v-else-if="show"
|
||||
class="_selectable"
|
||||
:class="[$style.codeBlockFallbackRoot, {
|
||||
[$style.outerStyle]: withOuterStyle,
|
||||
}]"
|
||||
><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre>
|
||||
<XCode v-if="show && lang" class="_selectable" :code="code" :lang="lang"/>
|
||||
<pre v-else-if="show" class="_selectable" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre>
|
||||
<button v-else :class="$style.codePlaceholderRoot" @click="show = true">
|
||||
<div :class="$style.codePlaceholderContainer">
|
||||
<div><i class="ti ti-code"></i> {{ i18n.ts.code }}</div>
|
||||
|
@ -43,6 +26,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
import MkLoading from '@/components/global/MkLoading.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
@ -51,12 +36,10 @@ const props = withDefaults(defineProps<{
|
|||
code: string;
|
||||
forceShow?: boolean;
|
||||
copyButton?: boolean;
|
||||
withOuterStyle?: boolean;
|
||||
lang?: string;
|
||||
}>(), {
|
||||
copyButton: true,
|
||||
forceShow: false,
|
||||
withOuterStyle: true,
|
||||
});
|
||||
|
||||
const show = ref(props.forceShow === true ? true : !prefer.s.dataSaver.code);
|
||||
|
@ -75,15 +58,9 @@ function copy() {
|
|||
|
||||
.codeBlockCopyButton {
|
||||
position: absolute;
|
||||
opacity: 0.5;
|
||||
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
&.withOuterStyle {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
|
@ -93,15 +70,9 @@ function copy() {
|
|||
.codeBlockFallbackRoot {
|
||||
display: block;
|
||||
overflow-wrap: anywhere;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.outerStyle.codeBlockFallbackRoot {
|
||||
background: var(--MI_THEME-bg);
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--MI_THEME-divider);
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.codeBlockFallbackCode {
|
||||
|
|
|
@ -35,18 +35,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div v-if="select === 'folder'">
|
||||
<template v-if="folder == null">
|
||||
<MkButton v-if="!isRootSelected" @click="isRootSelected = true">
|
||||
<i class="ti ti-square"></i> {{ i18n.ts.selectFolder }}
|
||||
<i class="ti ti-square"></i> {{ i18n.ts.selectThisFolder }}
|
||||
</MkButton>
|
||||
<MkButton v-else @click="isRootSelected = false">
|
||||
<i class="ti ti-checkbox"></i> {{ i18n.ts.unselectFolder }}
|
||||
<i class="ti ti-checkbox"></i> {{ i18n.ts.unselectThisFolder }}
|
||||
</MkButton>
|
||||
</template>
|
||||
<template v-else>
|
||||
<MkButton v-if="!selectedFolders.some(f => f.id === folder!.id)" @click="selectedFolders.push(folder)">
|
||||
<i class="ti ti-square"></i> {{ i18n.ts.selectFolder }}
|
||||
<i class="ti ti-square"></i> {{ i18n.ts.selectThisFolder }}
|
||||
</MkButton>
|
||||
<MkButton v-else @click="selectedFolders = selectedFolders.filter(f => f.id !== folder!.id)">
|
||||
<i class="ti ti-checkbox"></i> {{ i18n.ts.unselectFolder }}
|
||||
<i class="ti ti-checkbox"></i> {{ i18n.ts.unselectThisFolder }}
|
||||
</MkButton>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -112,7 +112,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkButton v-show="filesPaginator.canFetchOlder.value" :class="$style.loadMore" primary rounded @click="filesPaginator.fetchOlder()">{{ i18n.ts.loadMore }}</MkButton>
|
||||
|
||||
<div v-if="filesPaginator.items.value.length == 0 && foldersPaginator.items.value.length == 0 && !fetching" :class="$style.empty">
|
||||
<div v-if="draghover">{{ i18n.ts.dropHereToUpload }}</div>
|
||||
<div v-if="draghover">{{ i18n.ts['empty-draghover'] }}</div>
|
||||
<div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong></div>
|
||||
<div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div>
|
||||
</div>
|
||||
|
|
|
@ -326,7 +326,7 @@ watch(q, () => {
|
|||
|
||||
for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) {
|
||||
for (const emoji of emojis) {
|
||||
if (keywords.every(keyword => index[emoji.char]?.some(k => k.includes(keyword)))) {
|
||||
if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ watch(q, () => {
|
|||
|
||||
for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) {
|
||||
for (const emoji of emojis) {
|
||||
if (index[emoji.char]?.some(k => k.startsWith(newQ))) {
|
||||
if (index[emoji.char].some(k => k.startsWith(newQ))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ watch(q, () => {
|
|||
|
||||
for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) {
|
||||
for (const emoji of emojis) {
|
||||
if (index[emoji.char]?.some(k => k.includes(newQ))) {
|
||||
if (index[emoji.char].some(k => k.includes(newQ))) {
|
||||
matches.add(emoji);
|
||||
if (matches.size >= max) break;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||
import { nextTick, onMounted, ref, useTemplateRef } from 'vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||
import { pageFolderTeleportCount, popup } from '@/os.js';
|
||||
|
@ -119,11 +119,6 @@ const props = withDefaults(defineProps<{
|
|||
canPage: true,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'opened'): void;
|
||||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
const asPage = props.canPage && deviceKind === 'smartphone' && prefer.s['experimental.enableFolderPageView'];
|
||||
const bgSame = ref(false);
|
||||
|
@ -169,7 +164,7 @@ function afterLeave(el: Element) {
|
|||
let pageId = pageFolderTeleportCount.value;
|
||||
pageFolderTeleportCount.value += 1000;
|
||||
|
||||
async function toggle(ev: MouseEvent) {
|
||||
async function toggle() {
|
||||
if (asPage && !opened.value) {
|
||||
pageId++;
|
||||
const { dispose } = await popup(MkFolderPage, {
|
||||
|
@ -197,14 +192,6 @@ onMounted(() => {
|
|||
const myBg = computedStyle.getPropertyValue('--MI_THEME-panel');
|
||||
bgSame.value = parentBg === myBg;
|
||||
});
|
||||
|
||||
watch(opened, (isOpened) => {
|
||||
if (isOpened) {
|
||||
emit('opened');
|
||||
} else {
|
||||
emit('closed');
|
||||
}
|
||||
}, { flush: 'post' });
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
|
||||
<MkKeyValue>
|
||||
<template #key>{{ i18n.ts.name }}</template>
|
||||
<template #key>{{ i18n.ts.id }}</template>
|
||||
<template #value>{{ name }}</template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue>
|
||||
|
|
|
@ -68,7 +68,7 @@ export type GetMkSelectValueTypesFromDef<T extends MkSelectItem[]> = T[number] e
|
|||
</script>
|
||||
|
||||
<script lang="ts" setup generic="const ITEMS extends MkSelectItem[], MODELT extends OptionValue">
|
||||
import { onMounted, nextTick, ref, watch, computed, toRefs, useTemplateRef } from 'vue';
|
||||
import { onMounted, nextTick, ref, watch, computed, toRefs } from 'vue';
|
||||
import { useInterval } from '@@/js/use-interval.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import * as os from '@/os.js';
|
||||
|
@ -97,10 +97,10 @@ const { autofocus } = toRefs(props);
|
|||
const focused = ref(false);
|
||||
const opening = ref(false);
|
||||
const currentValueText = ref<string | null>(null);
|
||||
const inputEl = useTemplateRef('inputEl');
|
||||
const prefixEl = useTemplateRef('prefixEl');
|
||||
const suffixEl = useTemplateRef('suffixEl');
|
||||
const container = useTemplateRef('container');
|
||||
const inputEl = ref<HTMLObjectElement | null>(null);
|
||||
const prefixEl = ref<HTMLElement | null>(null);
|
||||
const suffixEl = ref<HTMLElement | null>(null);
|
||||
const container = ref<HTMLElement | null>(null);
|
||||
const height =
|
||||
props.small ? 33 :
|
||||
props.large ? 39 :
|
||||
|
|
|
@ -71,7 +71,7 @@ import {
|
|||
import * as os from '@/os.js';
|
||||
import { createColumn } from '@/components/grid/column.js';
|
||||
import { createRow, defaultGridRowSetting, resetRow } from '@/components/grid/row.js';
|
||||
import { makeHotkey } from '@/utility/hotkey.js';
|
||||
import { handleKeyEvent } from '@/utility/key-event.js';
|
||||
|
||||
type RowHolder = {
|
||||
row: GridRow,
|
||||
|
@ -289,8 +289,9 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
const max = availableBounds.value;
|
||||
const bounds = rangedBounds.value;
|
||||
|
||||
makeHotkey({
|
||||
'delete': () => {
|
||||
handleKeyEvent(ev, [
|
||||
{
|
||||
code: 'Delete', handler: () => {
|
||||
if (rangedRows.value.length > 0) {
|
||||
if (rowSetting.events.delete) {
|
||||
rowSetting.events.delete(rangedRows.value);
|
||||
|
@ -302,54 +303,56 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
});
|
||||
}
|
||||
},
|
||||
'ctrl+c|meta+c': () => {
|
||||
},
|
||||
{
|
||||
code: 'KeyC', modifiers: ['Control'], handler: () => {
|
||||
const context = createContext();
|
||||
copyGridDataToClipboard(data.value, context);
|
||||
},
|
||||
'ctrl+v|meta+v': async () => {
|
||||
},
|
||||
{
|
||||
code: 'KeyV', modifiers: ['Control'], handler: async () => {
|
||||
const _cells = cells.value;
|
||||
const context = createContext();
|
||||
await pasteToGridFromClipboard(context, (row, col, parsedValue) => {
|
||||
emitCellValue(_cells[row.index].cells[col.index], parsedValue);
|
||||
});
|
||||
},
|
||||
'ctrl+shift+right|meta+shift+right': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowRight', modifiers: ['Control', 'Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: { col: selectedCellAddress.col, row: bounds.leftTop.row },
|
||||
rightBottom: { col: max.rightBottom.col, row: bounds.rightBottom.row },
|
||||
});
|
||||
},
|
||||
'ctrl+shift+left|meta+shift+left': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowLeft', modifiers: ['Control', 'Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: { col: max.leftTop.col, row: bounds.leftTop.row },
|
||||
rightBottom: { col: selectedCellAddress.col, row: bounds.rightBottom.row },
|
||||
});
|
||||
},
|
||||
'ctrl+shift+up|meta+shift+up': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowUp', modifiers: ['Control', 'Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: { col: bounds.leftTop.col, row: max.leftTop.row },
|
||||
rightBottom: { col: bounds.rightBottom.col, row: selectedCellAddress.row },
|
||||
});
|
||||
},
|
||||
'ctrl+shift+down|meta+shift+down': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowDown', modifiers: ['Control', 'Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: { col: bounds.leftTop.col, row: selectedCellAddress.row },
|
||||
rightBottom: { col: bounds.rightBottom.col, row: max.rightBottom.row },
|
||||
});
|
||||
},
|
||||
'ctrl+right|meta+right': () => {
|
||||
selectionCell({ col: max.rightBottom.col, row: selectedCellAddress.row });
|
||||
},
|
||||
'ctrl+left|meta+left': () => {
|
||||
selectionCell({ col: max.leftTop.col, row: selectedCellAddress.row });
|
||||
},
|
||||
'ctrl+up|meta+up': () => {
|
||||
selectionCell({ col: selectedCellAddress.col, row: max.leftTop.row });
|
||||
},
|
||||
'ctrl+down|meta+down': () => {
|
||||
selectionCell({ col: selectedCellAddress.col, row: max.rightBottom.row });
|
||||
},
|
||||
'shift+right': () => {
|
||||
{
|
||||
code: 'ArrowRight', modifiers: ['Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: {
|
||||
col: bounds.leftTop.col < selectedCellAddress.col
|
||||
|
@ -365,7 +368,9 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
},
|
||||
});
|
||||
},
|
||||
'shift+left': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowLeft', modifiers: ['Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: {
|
||||
col: (bounds.leftTop.col < selectedCellAddress.col || bounds.rightBottom.col === selectedCellAddress.col)
|
||||
|
@ -381,7 +386,9 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
},
|
||||
});
|
||||
},
|
||||
'shift+up': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowUp', modifiers: ['Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: {
|
||||
col: bounds.leftTop.col,
|
||||
|
@ -397,7 +404,9 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
},
|
||||
});
|
||||
},
|
||||
'shift+down': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowDown', modifiers: ['Shift'], handler: () => {
|
||||
updateSelectionRange({
|
||||
leftTop: {
|
||||
col: bounds.leftTop.col,
|
||||
|
@ -413,19 +422,28 @@ function onKeyDown(ev: KeyboardEvent) {
|
|||
},
|
||||
});
|
||||
},
|
||||
'down': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowDown', handler: () => {
|
||||
selectionCell({ col: selectedCellAddress.col, row: selectedCellAddress.row + 1 });
|
||||
},
|
||||
'up': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowUp', handler: () => {
|
||||
selectionCell({ col: selectedCellAddress.col, row: selectedCellAddress.row - 1 });
|
||||
},
|
||||
'right': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowRight', handler: () => {
|
||||
selectionCell({ col: selectedCellAddress.col + 1, row: selectedCellAddress.row });
|
||||
},
|
||||
'left': () => {
|
||||
},
|
||||
{
|
||||
code: 'ArrowLeft', handler: () => {
|
||||
selectionCell({ col: selectedCellAddress.col - 1, row: selectedCellAddress.row });
|
||||
},
|
||||
}, [])(ev);
|
||||
},
|
||||
]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</MkFoldableSection>
|
||||
|
||||
<MkFoldableSection v-for="category in customEmojiCategories" v-once :key="category ?? '___root___'" :expanded="false">
|
||||
<MkFoldableSection v-for="category in customEmojiCategories" v-once :key="category ?? '___root___'">
|
||||
<template #header>{{ category || i18n.ts.other }}</template>
|
||||
<div :class="$style.emojis">
|
||||
<XEmoji v-for="emoji in customEmojis.filter(e => e.category === category)" :key="emoji.name" :emoji="emoji"/>
|
||||
|
|
|
@ -151,7 +151,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
|
||||
<div v-else-if="tab === 'announcements'" class="_gaps">
|
||||
<MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.createNew }}</MkButton>
|
||||
<MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.new }}</MkButton>
|
||||
|
||||
<MkSelect v-model="announcementsStatus" :items="announcementsStatusDef">
|
||||
<template #label>{{ i18n.ts.filter }}</template>
|
||||
|
|
|
@ -503,7 +503,7 @@ function refreshGridItems() {
|
|||
name: it.name,
|
||||
host: it.host ?? '',
|
||||
category: it.category ?? '',
|
||||
aliases: it.aliases.join(' '),
|
||||
aliases: it.aliases.join(','),
|
||||
license: it.license ?? '',
|
||||
isSensitive: it.isSensitive,
|
||||
localOnly: it.localOnly,
|
||||
|
|
|
@ -420,9 +420,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSwitch>
|
||||
<MkInput v-model="role.policies.maxFileSizeMb.value" :disabled="role.policies.maxFileSizeMb.useDefault" type="number" :readonly="readonly">
|
||||
<template #suffix>MB</template>
|
||||
<template #caption>
|
||||
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._role._options.maxFileSize_caption }}</div>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkRange v-model="role.policies.maxFileSizeMb.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
|
|
|
@ -155,9 +155,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #suffix>{{ policies.maxFileSizeMb }}MB</template>
|
||||
<MkInput v-model="policies.maxFileSizeMb" type="number">
|
||||
<template #suffix>MB</template>
|
||||
<template #caption>
|
||||
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._role._options.maxFileSize_caption }}</div>
|
||||
</template>
|
||||
</MkInput>
|
||||
</MkFolder>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<h1>{{ i18n.ts._auth.denied }}</h1>
|
||||
</div>
|
||||
<div v-if="state == 'accepted' && session">
|
||||
<h1>{{ session.app.isAuthorized ? i18n.ts._auth.alreadyAuthorized : i18n.ts._auth.accepted }}</h1>
|
||||
<h1>{{ session.app.isAuthorized ? i18n.ts['already-authorized'] : i18n.ts.allowed }}</h1>
|
||||
<p v-if="session.app.callbackUrl">
|
||||
{{ i18n.ts._auth.callback }}
|
||||
<MkEllipsis/>
|
||||
|
|
|
@ -28,37 +28,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<span v-else style="opacity: 0.7;">({{ i18n.ts.none }})</span>
|
||||
</template>
|
||||
</MkKeyValue>
|
||||
<MkFolder @opened="onOpened">
|
||||
<template #icon><i class="ti ti-report-search"></i></template>
|
||||
<template #label>{{ i18n.ts.deviceInfo }}</template>
|
||||
<template #caption>{{ i18n.ts.deviceInfoDescription }}</template>
|
||||
<MkLoading v-if="userEnv == null" />
|
||||
<MkCode v-else lang="json" :code="JSON.stringify(userEnv, null, 2)" style="max-height: 300px; overflow: auto;"/>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</div>
|
||||
</PageWithHeader>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { getUserEnvironment } from '@/utility/get-user-environment.js';
|
||||
import type { UserEnvironment } from '@/utility/get-user-environment.js';
|
||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkLink from '@/components/MkLink.vue';
|
||||
import MkCode from '@/components/MkCode.vue';
|
||||
|
||||
const userEnv = ref<UserEnvironment | null>(null);
|
||||
|
||||
async function onOpened() {
|
||||
if (userEnv.value == null) {
|
||||
userEnv.value = await getUserEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
definePage(() => ({
|
||||
title: i18n.ts.inquiry,
|
||||
|
|
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkButton primary @click="createKey">{{ i18n.ts._registry.createKey }}</MkButton>
|
||||
|
||||
<FormSection v-if="keys">
|
||||
<template #label>{{ i18n.ts._registry.keys }}</template>
|
||||
<template #label>{{ i18n.ts.keys }}</template>
|
||||
<div class="_gaps_s">
|
||||
<FormLink v-for="key in keys" :to="`/registry/value/${props.domain}/${scope.join('/')}/${key[0]}`" class="_monospace">{{ key[0] }}<template #suffix>{{ key[1].toUpperCase() }}</template></FormLink>
|
||||
</div>
|
||||
|
|
|
@ -159,7 +159,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, computed, onMounted, onUnmounted, onActivated, onDeactivated, nextTick, watch, ref, useTemplateRef } from 'vue';
|
||||
import { defineAsyncComponent, computed, onMounted, onUnmounted, onActivated, onDeactivated, nextTick, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { getScrollContainer } from '@@/js/scroll.js';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
|
@ -222,9 +222,9 @@ const router = useRouter();
|
|||
|
||||
const user = ref(props.user);
|
||||
const narrow = ref<null | boolean>(null);
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
const bannerEl = useTemplateRef('bannerEl');
|
||||
const memoTextareaEl = useTemplateRef('memoTextareaEl');
|
||||
const rootEl = ref<null | HTMLElement>(null);
|
||||
const bannerEl = ref<null | HTMLElement>(null);
|
||||
const memoTextareaEl = ref<null | HTMLElement>(null);
|
||||
const memoDraft = ref(props.user.memo);
|
||||
const isEditingMemo = ref(false);
|
||||
const moderationNote = ref(props.user.moderationNote ?? '');
|
||||
|
@ -372,6 +372,9 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
|||
overflow: clip;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
view-timeline-name: --bannerParallax;
|
||||
view-timeline-inset: var(--bannerParallaxInset, auto);
|
||||
view-timeline-axis: block;
|
||||
|
||||
> .banner {
|
||||
position: absolute;
|
||||
|
@ -379,12 +382,13 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 300%;
|
||||
background-size: 100% auto;
|
||||
background-color: #4c5e6d;
|
||||
background-repeat: repeat-y;
|
||||
background-position: center;
|
||||
will-change: transform;
|
||||
transform: translateY(-50%);
|
||||
animation: bannerParallaxKeyframes linear both;
|
||||
animation-timeline: --bannerParallax;
|
||||
animation-range: cover;
|
||||
}
|
||||
|
||||
> .fade {
|
||||
|
@ -741,26 +745,6 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
|||
}
|
||||
}
|
||||
|
||||
@supports (view-timeline-name: --name) {
|
||||
.ftskorzw {
|
||||
> .main {
|
||||
> .profile > .main {
|
||||
> .banner-container {
|
||||
view-timeline-name: --bannerParallax;
|
||||
view-timeline-inset: var(--bannerParallaxInset, auto);
|
||||
view-timeline-axis: block;
|
||||
|
||||
> .banner {
|
||||
animation: bannerParallaxKeyframes linear both;
|
||||
animation-timeline: --bannerParallax;
|
||||
animation-range: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bannerParallaxKeyframes {
|
||||
from {
|
||||
transform: translateY(-50%);
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export type UserEnvironment = {
|
||||
os: string;
|
||||
browser: string;
|
||||
userAgent: string;
|
||||
screenWidth: number;
|
||||
screenHeight: number;
|
||||
viaGetHighEntropyValues: true;
|
||||
} | {
|
||||
userAgent: string;
|
||||
screenWidth: number;
|
||||
screenHeight: number;
|
||||
viaGetHighEntropyValues: false;
|
||||
};
|
||||
|
||||
export async function getUserEnvironment(): Promise<UserEnvironment> {
|
||||
if ('userAgentData' in navigator && navigator.userAgentData != null) {
|
||||
try {
|
||||
const uaData: any = await navigator.userAgentData.getHighEntropyValues([
|
||||
'fullVersionList',
|
||||
'platformVersion',
|
||||
]);
|
||||
|
||||
let osVersion = 'v' + uaData.platformVersion;
|
||||
|
||||
if (uaData.platform === 'Windows' && uaData.platformVersion != null) {
|
||||
// https://learn.microsoft.com/ja-jp/microsoft-edge/web-platform/how-to-detect-win11
|
||||
const majorPlatformVersion = parseInt(uaData.platformVersion.split('.')[0]);
|
||||
if (majorPlatformVersion >= 13) {
|
||||
osVersion = '11 or later';
|
||||
} else if (majorPlatformVersion > 0) {
|
||||
osVersion = '10';
|
||||
} else {
|
||||
osVersion = '8.1 or earlier';
|
||||
}
|
||||
}
|
||||
|
||||
const browserData = uaData.fullVersionList.find((item) => !/^\s*not.+a.+brand\s*$/i.test(item.brand));
|
||||
return {
|
||||
os: `${uaData.platform} ${osVersion}`,
|
||||
browser: browserData ? `${browserData.brand} v${browserData.version}` : 'Unknown',
|
||||
userAgent: navigator.userAgent,
|
||||
screenWidth: window.innerWidth,
|
||||
screenHeight: window.innerHeight,
|
||||
viaGetHighEntropyValues: true,
|
||||
};
|
||||
} catch {
|
||||
return getViaUa();
|
||||
}
|
||||
} else {
|
||||
return getViaUa();
|
||||
}
|
||||
}
|
||||
|
||||
function getViaUa(): UserEnvironment {
|
||||
return {
|
||||
userAgent: navigator.userAgent,
|
||||
screenWidth: window.innerWidth,
|
||||
screenHeight: window.innerHeight,
|
||||
viaGetHighEntropyValues: false,
|
||||
};
|
||||
}
|
|
@ -50,12 +50,12 @@ let latestHotkey: Pattern & { callback: CallbackFunction } | null = null;
|
|||
//#endregion
|
||||
|
||||
//#region impl
|
||||
export const makeHotkey = (keymap: Keymap, ignoreElements = IGNORE_ELEMENTS) => {
|
||||
export const makeHotkey = (keymap: Keymap) => {
|
||||
const actions = parseKeymap(keymap);
|
||||
return (ev: KeyboardEvent) => {
|
||||
if ('pswp' in window && window.pswp != null) return;
|
||||
if (window.document.activeElement != null) {
|
||||
if (ignoreElements.includes(window.document.activeElement.tagName.toLowerCase())) return;
|
||||
if (IGNORE_ELEMENTS.includes(window.document.activeElement.tagName.toLowerCase())) return;
|
||||
if (getHTMLElementOrNull(window.document.activeElement)?.isContentEditable) return;
|
||||
}
|
||||
for (const action of actions) {
|
||||
|
|
153
packages/frontend/src/utility/key-event.ts
Normal file
153
packages/frontend/src/utility/key-event.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link KeyboardEvent.code} の値を表す文字列。不足分は適宜追加する
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values
|
||||
*/
|
||||
export type KeyCode = (
|
||||
| 'Backspace'
|
||||
| 'Tab'
|
||||
| 'Enter'
|
||||
| 'Shift'
|
||||
| 'Control'
|
||||
| 'Alt'
|
||||
| 'Pause'
|
||||
| 'CapsLock'
|
||||
| 'Escape'
|
||||
| 'Space'
|
||||
| 'PageUp'
|
||||
| 'PageDown'
|
||||
| 'End'
|
||||
| 'Home'
|
||||
| 'ArrowLeft'
|
||||
| 'ArrowUp'
|
||||
| 'ArrowRight'
|
||||
| 'ArrowDown'
|
||||
| 'Insert'
|
||||
| 'Delete'
|
||||
| 'Digit0'
|
||||
| 'Digit1'
|
||||
| 'Digit2'
|
||||
| 'Digit3'
|
||||
| 'Digit4'
|
||||
| 'Digit5'
|
||||
| 'Digit6'
|
||||
| 'Digit7'
|
||||
| 'Digit8'
|
||||
| 'Digit9'
|
||||
| 'KeyA'
|
||||
| 'KeyB'
|
||||
| 'KeyC'
|
||||
| 'KeyD'
|
||||
| 'KeyE'
|
||||
| 'KeyF'
|
||||
| 'KeyG'
|
||||
| 'KeyH'
|
||||
| 'KeyI'
|
||||
| 'KeyJ'
|
||||
| 'KeyK'
|
||||
| 'KeyL'
|
||||
| 'KeyM'
|
||||
| 'KeyN'
|
||||
| 'KeyO'
|
||||
| 'KeyP'
|
||||
| 'KeyQ'
|
||||
| 'KeyR'
|
||||
| 'KeyS'
|
||||
| 'KeyT'
|
||||
| 'KeyU'
|
||||
| 'KeyV'
|
||||
| 'KeyW'
|
||||
| 'KeyX'
|
||||
| 'KeyY'
|
||||
| 'KeyZ'
|
||||
| 'MetaLeft'
|
||||
| 'MetaRight'
|
||||
| 'ContextMenu'
|
||||
| 'F1'
|
||||
| 'F2'
|
||||
| 'F3'
|
||||
| 'F4'
|
||||
| 'F5'
|
||||
| 'F6'
|
||||
| 'F7'
|
||||
| 'F8'
|
||||
| 'F9'
|
||||
| 'F10'
|
||||
| 'F11'
|
||||
| 'F12'
|
||||
| 'NumLock'
|
||||
| 'ScrollLock'
|
||||
| 'Semicolon'
|
||||
| 'Equal'
|
||||
| 'Comma'
|
||||
| 'Minus'
|
||||
| 'Period'
|
||||
| 'Slash'
|
||||
| 'Backquote'
|
||||
| 'BracketLeft'
|
||||
| 'Backslash'
|
||||
| 'BracketRight'
|
||||
| 'Quote'
|
||||
| 'Meta'
|
||||
| 'AltGraph'
|
||||
);
|
||||
|
||||
/**
|
||||
* 修飾キーを表す文字列。不足分は適宜追加する。
|
||||
*/
|
||||
export type KeyModifier = (
|
||||
| 'Shift'
|
||||
| 'Control'
|
||||
| 'Alt'
|
||||
| 'Meta'
|
||||
);
|
||||
|
||||
/**
|
||||
* 押下されたキー以外の状態を表す文字列。不足分は適宜追加する。
|
||||
*/
|
||||
export type KeyState = (
|
||||
| 'composing'
|
||||
| 'repeat'
|
||||
);
|
||||
|
||||
export type KeyEventHandler = {
|
||||
modifiers?: KeyModifier[];
|
||||
states?: KeyState[];
|
||||
code: KeyCode | 'any';
|
||||
handler: (event: KeyboardEvent) => void;
|
||||
};
|
||||
|
||||
export function handleKeyEvent(event: KeyboardEvent, handlers: KeyEventHandler[]) {
|
||||
function checkModifier(ev: KeyboardEvent, modifiers? : KeyModifier[]) {
|
||||
if (modifiers) {
|
||||
return modifiers.every(modifier => ev.getModifierState(modifier));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkState(ev: KeyboardEvent, states?: KeyState[]) {
|
||||
if (states) {
|
||||
return states.every(state => ev.getModifierState(state));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let hit = false;
|
||||
for (const handler of handlers.filter(it => it.code === event.code)) {
|
||||
if (checkModifier(event, handler.modifiers) && checkState(event, handler.states)) {
|
||||
handler.handler(event);
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hit) {
|
||||
for (const handler of handlers.filter(it => it.code === 'any')) {
|
||||
handler.handler(event);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<p v-if="widgetProps.folderId == null">
|
||||
{{ i18n.ts.folder }}
|
||||
</p>
|
||||
<p v-if="widgetProps.folderId != null && images.length === 0 && !fetching">{{ i18n.ts.nothing }}</p>
|
||||
<p v-if="widgetProps.folderId != null && images.length === 0 && !fetching">{{ i18n.ts['no-image'] }}</p>
|
||||
<div ref="slideA" class="slide a"></div>
|
||||
<div ref="slideB" class="slide b"></div>
|
||||
</div>
|
||||
|
|
|
@ -11,17 +11,17 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.18.8",
|
||||
"@types/node": "22.18.6",
|
||||
"@types/wawoff2": "1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"harfbuzzjs": "0.4.13",
|
||||
"harfbuzzjs": "0.4.12",
|
||||
"tiny-glob": "0.2.9",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"wawoff2": "2.0.1"
|
||||
},
|
||||
"files": [
|
||||
|
|
|
@ -23,15 +23,15 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/matter-js": "0.20.2",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"esbuild": "0.25.10",
|
||||
"execa": "9.6.0",
|
||||
"glob": "11.0.3",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.3"
|
||||
"execa": "9.6.0",
|
||||
"typescript": "5.9.2",
|
||||
"esbuild": "0.25.10",
|
||||
"glob": "11.0.3"
|
||||
},
|
||||
"files": [
|
||||
"built"
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@readme/openapi-parser": "5.0.1",
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"openapi-types": "12.1.3",
|
||||
"openapi-typescript": "7.9.1",
|
||||
"ts-case-convert": "2.1.0",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"files": [
|
||||
"built"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2025.10.1-alpha.1",
|
||||
"version": "2025.10.0-beta.1",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"license": "MIT",
|
||||
"main": "./built/index.js",
|
||||
|
@ -35,10 +35,10 @@
|
|||
"directory": "packages/misskey-js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/api-extractor": "7.52.15",
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@microsoft/api-extractor": "7.52.13",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"esbuild": "0.25.10",
|
||||
"execa": "9.6.0",
|
||||
|
@ -46,7 +46,7 @@
|
|||
"ncp": "2.0.0",
|
||||
"nodemon": "3.1.10",
|
||||
"tsd": "0.33.0",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"vitest": "3.2.4",
|
||||
"vitest-websocket-mock": "0.5.0"
|
||||
},
|
||||
|
|
|
@ -29205,34 +29205,34 @@ export interface operations {
|
|||
* @default public
|
||||
* @enum {string}
|
||||
*/
|
||||
visibility?: 'public' | 'home' | 'followers' | 'specified';
|
||||
visibleUserIds?: string[];
|
||||
cw?: string | null;
|
||||
hashtag?: string | null;
|
||||
visibility: 'public' | 'home' | 'followers' | 'specified';
|
||||
visibleUserIds: string[];
|
||||
cw: string | null;
|
||||
hashtag: string | null;
|
||||
/** @default false */
|
||||
localOnly?: boolean;
|
||||
localOnly: boolean;
|
||||
/**
|
||||
* @default null
|
||||
* @enum {string|null}
|
||||
*/
|
||||
reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
||||
reactionAcceptance: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
||||
/** Format: misskey:id */
|
||||
replyId?: string | null;
|
||||
replyId: string | null;
|
||||
/** Format: misskey:id */
|
||||
renoteId?: string | null;
|
||||
renoteId: string | null;
|
||||
/** Format: misskey:id */
|
||||
channelId?: string | null;
|
||||
text?: string | null;
|
||||
fileIds?: string[];
|
||||
poll?: {
|
||||
channelId: string | null;
|
||||
text: string | null;
|
||||
fileIds: string[];
|
||||
poll: {
|
||||
choices: string[];
|
||||
multiple?: boolean;
|
||||
expiresAt?: number | null;
|
||||
expiredAfter?: number | null;
|
||||
} | null;
|
||||
scheduledAt?: number | null;
|
||||
scheduledAt: number | null;
|
||||
/** @default false */
|
||||
isActuallyScheduled?: boolean;
|
||||
isActuallyScheduled: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"esbuild": "0.25.10",
|
||||
"@types/node": "22.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.44.1",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"execa": "9.6.0",
|
||||
"glob": "11.0.3",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "5.9.2",
|
||||
"esbuild": "0.25.10",
|
||||
"glob": "11.0.3"
|
||||
},
|
||||
"files": [
|
||||
"built"
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
"misskey-js": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.44.1",
|
||||
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
|
5192
pnpm-lock.yaml
generated
5192
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -23,8 +23,7 @@
|
|||
'nsfwjs',
|
||||
// https://github.com/misskey-dev/misskey/issues/15920
|
||||
'sharp',
|
||||
'@misskey-dev/sharp-read-bmp',
|
||||
'@syuilo/aiscript-0-19-0',
|
||||
'@misskey-dev/sharp-read-bmp'
|
||||
],
|
||||
packageRules: [
|
||||
{
|
||||
|
|
20
scripts/changelog-checker/package-lock.json
generated
20
scripts/changelog-checker/package-lock.json
generated
|
@ -9,12 +9,12 @@
|
|||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@types/mdast": "4.0.4",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/node": "22.17.1",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"mdast-util-to-string": "4.0.0",
|
||||
"remark": "15.0.1",
|
||||
"remark-parse": "11.0.0",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"unified": "11.0.5",
|
||||
"vite": "6.3.6",
|
||||
"vite-node": "3.2.4",
|
||||
|
@ -940,12 +940,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.18.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.8.tgz",
|
||||
"integrity": "sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==",
|
||||
"version": "22.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.1.tgz",
|
||||
"integrity": "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
|
@ -2298,7 +2297,6 @@
|
|||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
@ -2714,9 +2712,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
@ -2844,7 +2842,6 @@
|
|||
"integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
|
@ -2943,7 +2940,6 @@
|
|||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/mdast": "4.0.4",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/node": "22.17.1",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"mdast-util-to-string": "4.0.0",
|
||||
"remark": "15.0.1",
|
||||
"remark-parse": "11.0.0",
|
||||
"typescript": "5.9.3",
|
||||
"typescript": "5.9.2",
|
||||
"unified": "11.0.5",
|
||||
"vite": "6.3.6",
|
||||
"vite-node": "3.2.4",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue