Merge remote-tracking branch 'misskey-original/develop' into develop

# Conflicts:
#	package.json
#	packages/frontend/src/components/MkDrive.file.vue
#	packages/frontend/src/components/MkNote.vue
This commit is contained in:
mattyatea 2023-10-10 18:32:52 +09:00
commit d691a130e2
31 changed files with 688 additions and 254 deletions

View file

@ -38,11 +38,15 @@
- Fix: ユーザーリストTLにチャンネル投稿が含まれる問題を修正 - Fix: ユーザーリストTLにチャンネル投稿が含まれる問題を修正
### Client ### Client
- Feat: 「ファイルの詳細」ページを追加
- ドライブのファイルの拡大プレビューができるように
- ファイルが添付されたノートの一覧が表示できるように
- Enhance: 二要素認証のバックアップコード一覧をテキストファイルでダウンロード可能に - Enhance: 二要素認証のバックアップコード一覧をテキストファイルでダウンロード可能に
- Enhance: 動画再生時のデフォルトボリュームを30%に - Enhance: 動画再生時のデフォルトボリュームを30%に
- Fix: リアクションしたユーザ一覧のUIが稀に左上に残ってしまう不具合を修正 - Fix: リアクションしたユーザ一覧のUIが稀に左上に残ってしまう不具合を修正
### Server ### Server
- Enhance: drive/files/attached-notes がページネーションに対応しました
- Enhance: タイムライン取得時のパフォーマンスを大幅に向上 - Enhance: タイムライン取得時のパフォーマンスを大幅に向上
- Enhance: ハイライト取得時のパフォーマンスを大幅に向上 - Enhance: ハイライト取得時のパフォーマンスを大幅に向上
- Enhance: トレンドハッシュタグ取得時のパフォーマンスを大幅に向上 - Enhance: トレンドハッシュタグ取得時のパフォーマンスを大幅に向上

View file

@ -2144,3 +2144,11 @@ _moderationLogTypes:
createAd: "Werbung erstellt" createAd: "Werbung erstellt"
deleteAd: "Werbung gelöscht" deleteAd: "Werbung gelöscht"
updateAd: "Werbung aktualisiert" updateAd: "Werbung aktualisiert"
_fileViewer:
title: "Dateiinformationen"
type: "Dateityp"
size: "Dateigröße"
url: "URL"
uploadedAt: "Hochgeladen am"
attachedNotes: "Zugehörige Notizen"
thisPageCanBeSeenFromTheAuthor: "Nur der Benutzer, der diese Datei hochgeladen hat, kann diese Seite sehen."

View file

@ -2154,3 +2154,11 @@ _moderationLogTypes:
createAd: "Ad created" createAd: "Ad created"
deleteAd: "Ad deleted" deleteAd: "Ad deleted"
updateAd: "Ad updated" updateAd: "Ad updated"
_fileViewer:
title: "File details"
type: "File type"
size: "Filesize"
url: "URL"
uploadedAt: "Uploaded at"
attachedNotes: "Attached notes"
thisPageCanBeSeenFromTheAuthor: "This page can only be seen by the user who uploaded this file."

View file

@ -45,6 +45,7 @@ pin: "Épingler sur le profil"
unpin: "Désépingler" unpin: "Désépingler"
copyContent: "Copier le contenu" copyContent: "Copier le contenu"
copyLink: "Copier le lien" copyLink: "Copier le lien"
copyLinkRenote: "Copier le lien de la renote"
delete: "Supprimer" delete: "Supprimer"
deleteAndEdit: "Supprimer et réécrire" deleteAndEdit: "Supprimer et réécrire"
deleteAndEditConfirm: "Êtes-vous sûr de vouloir effacer cette note et la modifier ? Vous perdrez toutes les réactions, renotes et réponses." deleteAndEditConfirm: "Êtes-vous sûr de vouloir effacer cette note et la modifier ? Vous perdrez toutes les réactions, renotes et réponses."
@ -129,6 +130,8 @@ unmarkAsSensitive: "Supprimer le marquage comme sensible"
enterFileName: "Entrer le nom du fichier" enterFileName: "Entrer le nom du fichier"
mute: "Masquer" mute: "Masquer"
unmute: "Ne plus masquer" unmute: "Ne plus masquer"
renoteMute: "Masquer les renotes"
renoteUnmute: "Ne plus masquer les renotes"
block: "Bloquer" block: "Bloquer"
unblock: "Débloquer" unblock: "Débloquer"
suspend: "Suspendre" suspend: "Suspendre"
@ -414,6 +417,7 @@ moderator: "Modérateur·rice·s"
moderation: "Modérations" moderation: "Modérations"
moderationNote: "Note de modération" moderationNote: "Note de modération"
addModerationNote: "Ajouter une note de modération" addModerationNote: "Ajouter une note de modération"
moderationLogs: "Journal de modération"
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s" nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
securityKeyAndPasskey: "Sécurité et clés de sécurité" securityKeyAndPasskey: "Sécurité et clés de sécurité"
securityKey: "Clé de sécurité" securityKey: "Clé de sécurité"
@ -472,6 +476,7 @@ aboutX: "À propos de {x}"
emojiStyle: "Style des émojis" emojiStyle: "Style des émojis"
native: "Natif" native: "Natif"
disableDrawer: "Les menus ne s'affichent pas dans le tiroir" disableDrawer: "Les menus ne s'affichent pas dans le tiroir"
showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
noHistory: "Pas d'historique" noHistory: "Pas d'historique"
signinHistory: "Historique de connexion" signinHistory: "Historique de connexion"
enableAdvancedMfm: "Activer la MFM avancée" enableAdvancedMfm: "Activer la MFM avancée"
@ -647,6 +652,7 @@ behavior: "Comportement"
sample: "Exemple" sample: "Exemple"
abuseReports: "Signalements" abuseReports: "Signalements"
reportAbuse: "Signaler" reportAbuse: "Signaler"
reportAbuseRenote: "Signaler la renote"
reportAbuseOf: "Signaler {name}" reportAbuseOf: "Signaler {name}"
fillAbuseReportDescription: "Veuillez expliquer les raisons du signalement. S'il s'agit d'une note précise, veuillez en donner le lien." fillAbuseReportDescription: "Veuillez expliquer les raisons du signalement. S'il s'agit d'une note précise, veuillez en donner le lien."
abuseReported: "Le rapport est envoyé. Merci." abuseReported: "Le rapport est envoyé. Merci."
@ -671,6 +677,8 @@ clip: "Clip"
createNew: "Créer nouveau" createNew: "Créer nouveau"
optional: "Facultatif" optional: "Facultatif"
createNewClip: "Créer un nouveau clip" createNewClip: "Créer un nouveau clip"
unclip: "Supprimer le clip"
confirmToUnclipAlreadyClippedNote: "Cette note fait déjà partie du clip « {name} ». Souhaitez-vous la supprimer de ce clip ?"
public: "Public" public: "Public"
private: "Privé" private: "Privé"
i18nInfo: "Misskey est traduit dans différentes langues par des bénévoles. Vous pouvez contribuer à {link}." i18nInfo: "Misskey est traduit dans différentes langues par des bénévoles. Vous pouvez contribuer à {link}."
@ -933,12 +941,15 @@ unsubscribePushNotification: "Désactiver les notifications push"
pushNotificationAlreadySubscribed: "Les notifications push sont déjà activées" pushNotificationAlreadySubscribed: "Les notifications push sont déjà activées"
pushNotificationNotSupported: "Votre navigateur ou votre instance ne prend pas en charge les notifications push" pushNotificationNotSupported: "Votre navigateur ou votre instance ne prend pas en charge les notifications push"
sendPushNotificationReadMessage: "Supprimer les notifications push une fois que les notifications ou messages pertinents ont été lus." sendPushNotificationReadMessage: "Supprimer les notifications push une fois que les notifications ou messages pertinents ont été lus."
windowMaximize: "Maximiser"
windowMinimize: "Minimaliser"
windowRestore: "Restaurer" windowRestore: "Restaurer"
caption: "Libellé" caption: "Libellé"
loggedInAsBot: "Connecté actuellement en tant que bot" loggedInAsBot: "Connecté actuellement en tant que bot"
tools: "Outils" tools: "Outils"
cannotLoad: "Chargement impossible" cannotLoad: "Chargement impossible"
like: "J'aime" like: "J'aime"
unlike: "Ne plus aimer"
numberOfLikes: "Favoris" numberOfLikes: "Favoris"
show: "Affichage" show: "Affichage"
neverShow: "Ne plus afficher" neverShow: "Ne plus afficher"
@ -949,6 +960,7 @@ noRole: "Aucun rôle"
normalUser: "Simple utilisateur·rice" normalUser: "Simple utilisateur·rice"
undefined: "Non défini" undefined: "Non défini"
assign: "Attribuer" assign: "Attribuer"
unassign: "Retirer"
color: "Couleur" color: "Couleur"
manageCustomEmojis: "Gestion des émojis personnalisés" manageCustomEmojis: "Gestion des émojis personnalisés"
preset: "Préréglage" preset: "Préréglage"
@ -958,12 +970,16 @@ thisPostMayBeAnnoying: "Cette note peut gêner d'autres personnes."
thisPostMayBeAnnoyingHome: "Publier vers le fil principal" thisPostMayBeAnnoyingHome: "Publier vers le fil principal"
thisPostMayBeAnnoyingCancel: "Annuler" thisPostMayBeAnnoyingCancel: "Annuler"
thisPostMayBeAnnoyingIgnore: "Publier quand-même" thisPostMayBeAnnoyingIgnore: "Publier quand-même"
collapseRenotes: "Réduire les renotes déjà vues"
internalServerError: "Erreur interne du serveur" internalServerError: "Erreur interne du serveur"
copyErrorInfo: "Copier les détails de lerreur" copyErrorInfo: "Copier les détails de lerreur"
exploreOtherServers: "Trouver une autre instance" exploreOtherServers: "Trouver une autre instance"
disableFederationOk: "Désactiver" disableFederationOk: "Désactiver"
likeOnly: "Les favoris uniquement" likeOnly: "Les favoris uniquement"
sensitiveWords: "Mots sensibles"
notesSearchNotAvailable: "La recherche de notes n'est pas disponible."
license: "Licence" license: "Licence"
myClips: "Mes clips"
video: "Vidéo" video: "Vidéo"
videos: "Vidéos" videos: "Vidéos"
dataSaver: "Économiseur de données" dataSaver: "Économiseur de données"
@ -973,6 +989,7 @@ accountMovedShort: "Ce compte a migré"
operationForbidden: "Opération non autorisée" operationForbidden: "Opération non autorisée"
addMemo: "Ajouter un mémo" addMemo: "Ajouter un mémo"
reactionsList: "Réactions" reactionsList: "Réactions"
renotesList: "Liste de renotes"
notificationDisplay: "Style des notifications" notificationDisplay: "Style des notifications"
leftTop: "En haut à gauche" leftTop: "En haut à gauche"
rightTop: "En haut à droite" rightTop: "En haut à droite"
@ -982,6 +999,7 @@ vertical: "Vertical"
horizontal: "Latéral" horizontal: "Latéral"
serverRules: "Règles du serveur" serverRules: "Règles du serveur"
archive: "Archive" archive: "Archive"
displayOfNote: "Affichage de la note"
youFollowing: "Abonné·e" youFollowing: "Abonné·e"
options: "Options" options: "Options"
later: "Plus tard" later: "Plus tard"
@ -1001,6 +1019,7 @@ pinnedList: "Liste épinglée"
notifyNotes: "Notifier à propos des nouvelles notes" notifyNotes: "Notifier à propos des nouvelles notes"
authentication: "Authentification" authentication: "Authentification"
authenticationRequiredToContinue: "Veuillez vous authentifier pour continuer" authenticationRequiredToContinue: "Veuillez vous authentifier pour continuer"
showRenotes: "Afficher les renotes"
_announcement: _announcement:
readConfirmTitle: "Marquer comme lu ?" readConfirmTitle: "Marquer comme lu ?"
_initialAccountSetting: _initialAccountSetting:
@ -1082,12 +1101,20 @@ _achievements:
title: "Beaucoup d'amis" title: "Beaucoup d'amis"
_followers10: _followers10:
title: "Abonnez-moi !" title: "Abonnez-moi !"
description: "Obtenir plus de 10 abonné·e·s"
_followers50:
description: "Obtenir plus de 50 abonné·e·s"
_followers100: _followers100:
title: "Populaire" title: "Populaire"
description: "Obtenir plus de 100 abonné·e·s"
_followers300:
description: "Obtenir plus de 300 abonné·e·s"
_followers500: _followers500:
title: "Tour radio" title: "Tour radio"
description: "Obtenir plus de 500 abonné·e·s"
_followers1000: _followers1000:
title: "Influenceur·euse" title: "Influenceur·euse"
description: "Obtenir plus de 1000 abonné·e·s"
_iLoveMisskey: _iLoveMisskey:
title: "Jadore Misskey" title: "Jadore Misskey"
description: "Publication « J❤ #Misskey »" description: "Publication « J❤ #Misskey »"
@ -1151,6 +1178,7 @@ _role:
high: "Haute" high: "Haute"
_options: _options:
canManageCustomEmojis: "Gestion des émojis personnalisés" canManageCustomEmojis: "Gestion des émojis personnalisés"
wordMuteMax: "Nombre maximal de caractères dans le filtre de mots"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement." description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
sensitivity: "Sensibilité de la détection" sensitivity: "Sensibilité de la détection"

12
locales/index.d.ts vendored
View file

@ -1818,9 +1818,6 @@ export interface Locale {
"infoFg": string; "infoFg": string;
"infoWarnBg": string; "infoWarnBg": string;
"infoWarnFg": string; "infoWarnFg": string;
"cwBg": string;
"cwFg": string;
"cwHoverBg": string;
"toastBg": string; "toastBg": string;
"toastFg": string; "toastFg": string;
"buttonBg": string; "buttonBg": string;
@ -2319,6 +2316,15 @@ export interface Locale {
"deleteAd": string; "deleteAd": string;
"updateAd": string; "updateAd": string;
}; };
"_fileViewer": {
"title": string;
"type": string;
"size": string;
"url": string;
"uploadedAt": string;
"attachedNotes": string;
"thisPageCanBeSeenFromTheAuthor": string;
};
} }
declare const locales: { declare const locales: {
[lang: string]: Locale; [lang: string]: Locale;

View file

@ -113,7 +113,7 @@ cantReRenote: "È impossibile rinotare una Rinota."
quote: "Cita" quote: "Cita"
inChannelRenote: "Rinota nel canale" inChannelRenote: "Rinota nel canale"
inChannelQuote: "Cita nel canale" inChannelQuote: "Cita nel canale"
pinnedNote: "Nota fissata" pinnedNote: "Nota in primo piano"
pinned: "Fissa sul profilo" pinned: "Fissa sul profilo"
you: "Tu" you: "Tu"
clickToShow: "Clicca per visualizzare" clickToShow: "Clicca per visualizzare"
@ -364,7 +364,7 @@ pinnedUsersDescription: "Elenca gli/le utenti che vuoi fissare in cima alla pagi
pinnedPages: "Pagine in evidenza" pinnedPages: "Pagine in evidenza"
pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima alla pagina dell'istanza. Una pagina per riga." pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima alla pagina dell'istanza. Una pagina per riga."
pinnedClipId: "ID della Clip in evidenza" pinnedClipId: "ID della Clip in evidenza"
pinnedNotes: "Nota fissata" pinnedNotes: "Note in primo piano"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
enableHcaptcha: "Abilita hCaptcha" enableHcaptcha: "Abilita hCaptcha"
hcaptchaSiteKey: "Chiave del sito" hcaptchaSiteKey: "Chiave del sito"
@ -384,7 +384,7 @@ name: "Nome"
antennaSource: "Fonte dell'antenna" antennaSource: "Fonte dell'antenna"
antennaKeywords: "Parole chiavi da ricevere" antennaKeywords: "Parole chiavi da ricevere"
antennaExcludeKeywords: "Parole chiavi da escludere" antennaExcludeKeywords: "Parole chiavi da escludere"
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"." antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
notifyAntenna: "Invia notifiche delle nuove note" notifyAntenna: "Invia notifiche delle nuove note"
withFileAntenna: "Solo note con file in allegato" withFileAntenna: "Solo note con file in allegato"
enableServiceworker: "Abilita ServiceWorker" enableServiceworker: "Abilita ServiceWorker"
@ -393,7 +393,7 @@ caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
withReplies: "Includere le risposte" withReplies: "Includere le risposte"
connectedTo: "Connessione ai seguenti profili:" connectedTo: "Connessione ai seguenti profili:"
notesAndReplies: "Note e risposte" notesAndReplies: "Note e risposte"
withFiles: "Con file in allegato" withFiles: "Con allegati"
silence: "Silenzia" silence: "Silenzia"
silenceConfirm: "Vuoi davvero silenziare questo profilo?" silenceConfirm: "Vuoi davvero silenziare questo profilo?"
unsilence: "Riattiva" unsilence: "Riattiva"
@ -1121,11 +1121,11 @@ unnotifyNotes: "Interrompi le notifiche di nuove Note"
authentication: "Autenticazione" authentication: "Autenticazione"
authenticationRequiredToContinue: "Per procedere, è richiesta l'autenticazione" authenticationRequiredToContinue: "Per procedere, è richiesta l'autenticazione"
dateAndTime: "Data e Ora" dateAndTime: "Data e Ora"
showRenotes: "Leggi le Rinota" showRenotes: "Includi le Rinota"
edited: "Modificato" edited: "Modificato"
notificationRecieveConfig: "Preferenze di notifica" notificationRecieveConfig: "Preferenze di notifica"
mutualFollow: "Follow reciproco" mutualFollow: "Follow reciproco"
fileAttachedOnly: "Con file in allegato" fileAttachedOnly: "Solo con allegati"
showRepliesToOthersInTimeline: "Risposte altrui nella TL" showRepliesToOthersInTimeline: "Risposte altrui nella TL"
hideRepliesToOthersInTimeline: "Nascondi Riposte altrui nella TL" hideRepliesToOthersInTimeline: "Nascondi Riposte altrui nella TL"
externalServices: "Servizi esterni" externalServices: "Servizi esterni"
@ -1533,6 +1533,10 @@ _ad:
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso" reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
hide: "Nascondi" hide: "Nascondi"
timezoneinfo: "Il giorno della settimana è determinato in base al fuso orario del server." timezoneinfo: "Il giorno della settimana è determinato in base al fuso orario del server."
adsSettings: "Impostazioni banner"
notesPerOneAd: "Quantità di Note tra i banner"
setZeroToDisable: "Imposta 0 (zero) per disattivare la distribuzione dei banner durante gli aggiornamenti in tempo reale"
adsTooClose: "Attenzione, l'intervallo di pubblicazione dei banner è molto breve, potrebbe infastidire significativamente la fruizione"
_forgotPassword: _forgotPassword:
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo profilo. Il collegamento necessario per ripristinare la password verrà inviato a questo indirizzo." enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo profilo. Il collegamento necessario per ripristinare la password verrà inviato a questo indirizzo."
ifNoEmail: "Se il tuo indirizzo email non risulta registrato, contatta l'amministrazione dell'istanza." ifNoEmail: "Se il tuo indirizzo email non risulta registrato, contatta l'amministrazione dell'istanza."
@ -1616,7 +1620,7 @@ _menuDisplay:
hide: "Nascondere" hide: "Nascondere"
_wordMute: _wordMute:
muteWords: "Parole da filtrare" muteWords: "Parole da filtrare"
muteWordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con una interruzione di riga, indica la condizione \"O\"" muteWordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
muteWordsDescription2: "Se vuoi indicare delle Espressioni Regolari (regexp), metti la condizione all'interno di due slash (/)" muteWordsDescription2: "Se vuoi indicare delle Espressioni Regolari (regexp), metti la condizione all'interno di due slash (/)"
_instanceMute: _instanceMute:
instanceMuteDescription: "Disattiva tutte le note, le note di rinvio (condivisione) dell'istanza configurata, comprese le risposte agli utenti dell'istanza." instanceMuteDescription: "Disattiva tutte le note, le note di rinvio (condivisione) dell'istanza configurata, comprese le risposte agli utenti dell'istanza."
@ -1626,7 +1630,7 @@ _instanceMute:
_theme: _theme:
explore: "Esplora temi" explore: "Esplora temi"
install: "Installa un tema" install: "Installa un tema"
manage: "Gerisci temi" manage: "Gestione temi"
code: "Codice tema" code: "Codice tema"
description: "Descrizione" description: "Descrizione"
installed: "{name} è installato" installed: "{name} è installato"
@ -1885,7 +1889,7 @@ _visibility:
followersDescription: "Visibile solo ai tuoi follower" followersDescription: "Visibile solo ai tuoi follower"
specified: "Nota diretta" specified: "Nota diretta"
specifiedDescription: "Visibile solo ai profili menzionati" specifiedDescription: "Visibile solo ai profili menzionati"
disableFederation: "Non federare" disableFederation: "Senza federazione"
disableFederationDescription: "Non spedire attività alle altre istanze remote" disableFederationDescription: "Non spedire attività alle altre istanze remote"
_postForm: _postForm:
replyPlaceholder: "Rispondi a questa nota..." replyPlaceholder: "Rispondi a questa nota..."

View file

@ -1736,9 +1736,6 @@ _theme:
infoFg: "情報の文字" infoFg: "情報の文字"
infoWarnBg: "警告の背景" infoWarnBg: "警告の背景"
infoWarnFg: "警告の文字" infoWarnFg: "警告の文字"
cwBg: "CW ボタンの背景"
cwFg: "CW ボタンの文字"
cwHoverBg: "CW ボタンの背景 (ホバー)"
toastBg: "通知トーストの背景" toastBg: "通知トーストの背景"
toastFg: "通知トーストの文字" toastFg: "通知トーストの文字"
buttonBg: "ボタンの背景" buttonBg: "ボタンの背景"
@ -2231,3 +2228,12 @@ _moderationLogTypes:
createAd: "広告を作成" createAd: "広告を作成"
deleteAd: "広告を削除" deleteAd: "広告を削除"
updateAd: "広告を更新" updateAd: "広告を更新"
_fileViewer:
title: "ファイルの詳細"
type: "ファイルタイプ"
size: "ファイルサイズ"
url: "URL"
uploadedAt: "追加日"
attachedNotes: "添付されているノート"
thisPageCanBeSeenFromTheAuthor: "このページは、このファイルをアップロードしたユーザーしか閲覧できません。"

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2023.10.0-beta.15-prismisskey.4", "version": "2023.10.0",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",
@ -16,7 +16,6 @@
"scripts": { "scripts": {
"build-pre": "node ./scripts/build-pre.js", "build-pre": "node ./scripts/build-pre.js",
"build-assets": "node ./scripts/build-assets.mjs", "build-assets": "node ./scripts/build-assets.mjs",
"build-and-start": "pnpm build && pnpm start",
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"build-storybook": "pnpm --filter frontend build-storybook", "build-storybook": "pnpm --filter frontend build-storybook",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
@ -52,8 +51,8 @@
"typescript": "5.2.2" "typescript": "5.2.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "6.7.4", "@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.4", "@typescript-eslint/parser": "6.7.5",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "13.3.0", "cypress": "13.3.0",
"eslint": "8.51.0", "eslint": "8.51.0",

View file

@ -86,7 +86,7 @@
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "2.0.5", "blurhash": "2.0.5",
"body-parser": "1.20.2", "body-parser": "1.20.2",
"bullmq": "4.12.2", "bullmq": "4.12.3",
"cacheable-lookup": "7.0.0", "cacheable-lookup": "7.0.0",
"cbor": "9.0.1", "cbor": "9.0.1",
"chalk": "5.3.0", "chalk": "5.3.0",
@ -189,13 +189,13 @@
"@types/jsrsasign": "10.5.9", "@types/jsrsasign": "10.5.9",
"@types/mime-types": "2.1.2", "@types/mime-types": "2.1.2",
"@types/ms": "0.7.32", "@types/ms": "0.7.32",
"@types/node": "20.8.3", "@types/node": "20.8.4",
"@types/node-fetch": "3.0.3", "@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.11", "@types/nodemailer": "6.4.11",
"@types/oauth": "0.9.2", "@types/oauth": "0.9.2",
"@types/oauth2orize": "1.11.1", "@types/oauth2orize": "1.11.1",
"@types/oauth2orize-pkce": "0.1.0", "@types/oauth2orize-pkce": "0.1.0",
"@types/pg": "8.10.3", "@types/pg": "8.10.4",
"@types/pug": "2.0.7", "@types/pug": "2.0.7",
"@types/punycode": "2.1.0", "@types/punycode": "2.1.0",
"@types/qrcode": "1.5.2", "@types/qrcode": "1.5.2",
@ -212,8 +212,8 @@
"@types/vary": "1.1.1", "@types/vary": "1.1.1",
"@types/web-push": "3.6.1", "@types/web-push": "3.6.1",
"@types/ws": "8.5.6", "@types/ws": "8.5.6",
"@typescript-eslint/eslint-plugin": "6.7.4", "@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.4", "@typescript-eslint/parser": "6.7.5",
"aws-sdk-client-mock": "3.0.0", "aws-sdk-client-mock": "3.0.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "8.51.0", "eslint": "8.51.0",

View file

@ -109,7 +109,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.queryService.generateBlockedUserQuery(query, me); this.queryService.generateBlockedUserQuery(query, me);
const notes = await query.getMany(); const notes = await query.getMany();
notes.sort((a, b) => a.id > b.id ? -1 : 1); if (sinceId != null && untilId == null) {
notes.sort((a, b) => a.id < b.id ? -1 : 1);
} else {
notes.sort((a, b) => a.id > b.id ? -1 : 1);
}
if (notes.length > 0) { if (notes.length > 0) {
this.noteReadService.read(me.id, notes); this.noteReadService.read(me.id, notes);

View file

@ -6,6 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { NotesRepository, DriveFilesRepository } from '@/models/_.js'; import type { NotesRepository, DriveFilesRepository } from '@/models/_.js';
import { QueryService } from '@/core/QueryService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js'; import { ApiError } from '../../../error.js';
@ -41,6 +42,9 @@ export const meta = {
export const paramDef = { export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
fileId: { type: 'string', format: 'misskey:id' }, fileId: { type: 'string', format: 'misskey:id' },
}, },
required: ['fileId'], required: ['fileId'],
@ -56,6 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private notesRepository: NotesRepository, private notesRepository: NotesRepository,
private noteEntityService: NoteEntityService, private noteEntityService: NoteEntityService,
private queryService: QueryService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
// Fetch file // Fetch file
@ -68,9 +73,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchFile); throw new ApiError(meta.errors.noSuchFile);
} }
const notes = await this.notesRepository.createQueryBuilder('note') const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId);
.where(':file = ANY(note.fileIds)', { file: file.id }) query.andWhere(':file = ANY(note.fileIds)', { file: file.id });
.getMany();
const notes = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(notes, me, { return await this.noteEntityService.packMany(notes, me, {
detail: true, detail: true,

View file

@ -457,6 +457,7 @@ export async function testPaginationConsistency<Entity extends { id: string, cre
}; };
for (const limit of [1, 5, 10, 100, undefined]) { for (const limit of [1, 5, 10, 100, undefined]) {
/*
// 1. sinceId/DateとuntilId/Dateで両端を指定して取得した結果が期待通りになっていること // 1. sinceId/DateとuntilId/Dateで両端を指定して取得した結果が期待通りになっていること
if (ordering === 'desc') { if (ordering === 'desc') {
const end = expected.at(-1)!; const end = expected.at(-1)!;
@ -485,6 +486,7 @@ export async function testPaginationConsistency<Entity extends { id: string, cre
actual.map(({ id, createdAt }) => id + ':' + createdAt), actual.map(({ id, createdAt }) => id + ':' + createdAt),
expected.map(({ id, createdAt }) => id + ':' + createdAt)); expected.map(({ id, createdAt }) => id + ':' + createdAt));
} }
*/
// 3. untilId指定+limitで取得してつなぎ合わせた結果が期待通りになっていること // 3. untilId指定+limitで取得してつなぎ合わせた結果が期待通りになっていること
if (ordering === 'desc') { if (ordering === 'desc') {

View file

@ -60,7 +60,7 @@
"querystring": "0.2.1", "querystring": "0.2.1",
"rollup": "4.0.2", "rollup": "4.0.2",
"sanitize-html": "2.11.0", "sanitize-html": "2.11.0",
"sass": "1.69.0", "sass": "1.69.1",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.157.0", "three": "0.157.0",
@ -103,7 +103,7 @@
"@types/estree": "1.0.2", "@types/estree": "1.0.2",
"@types/matter-js": "0.19.1", "@types/matter-js": "0.19.1",
"@types/micromatch": "4.0.3", "@types/micromatch": "4.0.3",
"@types/node": "20.8.3", "@types/node": "20.8.4",
"@types/punycode": "2.1.0", "@types/punycode": "2.1.0",
"@types/sanitize-html": "2.9.1", "@types/sanitize-html": "2.9.1",
"@types/throttle-debounce": "5.0.0", "@types/throttle-debounce": "5.0.0",
@ -111,8 +111,8 @@
"@types/uuid": "9.0.5", "@types/uuid": "9.0.5",
"@types/websocket": "1.0.7", "@types/websocket": "1.0.7",
"@types/ws": "8.5.6", "@types/ws": "8.5.6",
"@typescript-eslint/eslint-plugin": "6.7.4", "@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.4", "@typescript-eslint/parser": "6.7.5",
"@vitest/coverage-v8": "0.34.6", "@vitest/coverage-v8": "0.34.6",
"@vue/runtime-core": "3.3.4", "@vue/runtime-core": "3.3.4",
"acorn": "8.10.0", "acorn": "8.10.0",

View file

@ -4,10 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<button class="_button" :class="$style.root" @mousedown="toggle"> <MkButton rounded full small @click="toggle"><b>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}</b><span v-if="!modelValue" :class="$style.label">{{ label }}</span></MkButton>
<b>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}</b>
<span v-if="!modelValue" :class="$style.label">{{ label }}</span>
</button>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -15,6 +12,7 @@ import { computed } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { concat } from '@/scripts/array.js'; import { concat } from '@/scripts/array.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import MkButton from '@/components/MkButton.vue';
const props = defineProps<{ const props = defineProps<{
modelValue: boolean; modelValue: boolean;
@ -33,25 +31,12 @@ const label = computed(() => {
] as string[][]).join(' / '); ] as string[][]).join(' / ');
}); });
const toggle = () => { function toggle() {
emit('update:modelValue', !props.modelValue); emit('update:modelValue', !props.modelValue);
}; }
</script> </script>
<style lang="scss" module> <style lang="scss" module>
.root {
display: inline-block;
padding: 4px 8px;
font-size: 0.7em;
color: var(--cwFg);
background: var(--cwBg);
border-radius: 2px;
&:hover {
background: var(--cwHoverBg);
}
}
.label { .label {
margin-left: 4px; margin-left: 4px;

View file

@ -45,9 +45,12 @@ import bytes from '@/filters/bytes.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { useRouter } from '@/router.js';
import { getDriveFileMenu, getDriveMultiFileMenu } from '@/scripts/get-drive-file-menu.js'; import { getDriveFileMenu, getDriveMultiFileMenu } from '@/scripts/get-drive-file-menu.js';
import { isTouchUsing } from '@/scripts/touch.js'; import { isTouchUsing } from '@/scripts/touch.js';
const router = useRouter();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
file: Misskey.entities.DriveFile; file: Misskey.entities.DriveFile;
folder: Misskey.entities.DriveFolder | null; folder: Misskey.entities.DriveFolder | null;
@ -84,6 +87,8 @@ function onClick(ev: MouseEvent) {
os.popupMenu(getDriveMultiFileMenu(props.SelectFiles), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); os.popupMenu(getDriveMultiFileMenu(props.SelectFiles), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
} else if (isTouchUsing && !isSelectedFile.value && props.SelectFiles.length === 0) { } else if (isTouchUsing && !isSelectedFile.value && props.SelectFiles.length === 0) {
os.popupMenu(getDriveFileMenu(props.file, props.folder), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); os.popupMenu(getDriveFileMenu(props.file, props.folder), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
}else {
router.push(`/my/drive/file/${props.file.id}`);
} }
} }

View file

@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<p v-if="appearNote.cw != null" :class="$style.cw"> <p v-if="appearNote.cw != null" :class="$style.cw">
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user"
:i="$i"/> :i="$i"/>
<MkCwButton v-model="showContent" :note="appearNote"/> <MkCwButton v-model="showContent" :note="appearNote" style="margin: 4px 0;"/>
</p> </p>
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
<div :class="$style.text"> <div :class="$style.text">
@ -190,7 +190,6 @@ const props = defineProps<{
const inChannel = inject('inChannel', null); const inChannel = inject('inChannel', null);
const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null); const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null);
;
let note = $ref(deepClone(props.note)); let note = $ref(deepClone(props.note));
// plugin // plugin

View file

@ -0,0 +1,302 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div class="_gaps">
<MkInfo>{{ i18n.ts._fileViewer.thisPageCanBeSeenFromTheAuthor }}</MkInfo>
<MkLoading v-if="fetching"/>
<div v-else-if="file" class="_gaps">
<div :class="$style.filePreviewRoot">
<MkMediaList :mediaList="[file]"></MkMediaList>
</div>
<div :class="$style.fileQuickActionsRoot">
<button class="_button" :class="$style.fileNameEditBtn" @click="rename()">
<h2 class="_nowrap" :class="$style.fileName">{{ file.name }}</h2>
<i class="ti ti-pencil" :class="$style.fileNameEditIcon"></i>
</button>
<div :class="$style.fileQuickActionsOthers">
<button v-tooltip="i18n.ts.createNoteFromTheFile" class="_button" :class="$style.fileQuickActionsOthersButton" @click="postThis()">
<i class="ti ti-pencil"></i>
</button>
<button v-if="isImage" v-tooltip="i18n.ts.cropImage" class="_button" :class="$style.fileQuickActionsOthersButton" @click="crop()">
<i class="ti ti-crop"></i>
</button>
<button v-if="file.isSensitive" v-tooltip="i18n.ts.unmarkAsSensitive" class="_button" :class="$style.fileQuickActionsOthersButton" @click="toggleSensitive()">
<i class="ti ti-eye"></i>
</button>
<button v-else v-tooltip="i18n.ts.markAsSensitive" class="_button" :class="$style.fileQuickActionsOthersButton" @click="toggleSensitive()">
<i class="ti ti-eye-exclamation"></i>
</button>
<a v-tooltip="i18n.ts.download" :href="file.url" :download="file.name" class="_button" :class="$style.fileQuickActionsOthersButton">
<i class="ti ti-download"></i>
</a>
<button v-tooltip="i18n.ts.delete" class="_button" :class="[$style.fileQuickActionsOthersButton, $style.danger]" @click="deleteFile()">
<i class="ti ti-trash"></i>
</button>
</div>
</div>
<div>
<button class="_button" :class="$style.fileAltEditBtn" @click="describe()">
<MkKeyValue>
<template #key>{{ i18n.ts.description }}</template>
<template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.fileAltEditIcon"></i></template>
</MkKeyValue>
</button>
<MkKeyValue :class="$style.fileMetaDataChildren">
<template #key>{{ i18n.ts._fileViewer.uploadedAt }}</template>
<template #value><MkTime :time="file.createdAt" mode="detail"/></template>
</MkKeyValue>
<MkKeyValue :class="$style.fileMetaDataChildren">
<template #key>{{ i18n.ts._fileViewer.type }}</template>
<template #value>{{ file.type }}</template>
</MkKeyValue>
<MkKeyValue :class="$style.fileMetaDataChildren">
<template #key>{{ i18n.ts._fileViewer.size }}</template>
<template #value>{{ bytes(file.size) }}</template>
</MkKeyValue>
</div>
</div>
<div v-else class="_fullinfo">
<img :src="infoImageUrl" class="_ghost"/>
<div>{{ i18n.ts.nothing }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, defineAsyncComponent, onMounted } from 'vue';
import * as Misskey from 'misskey-js';
import MkInfo from '@/components/MkInfo.vue';
import MkMediaList from '@/components/MkMediaList.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import bytes from '@/filters/bytes.js';
import { infoImageUrl } from '@/instance.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { useRouter } from '@/router.js';
const router = useRouter();
const props = defineProps<{
fileId: string;
}>();
const fetching = ref(true);
const file = ref<Misskey.entities.DriveFile>();
const isImage = computed(() => file.value?.type.startsWith('image/'));
async function fetch() {
fetching.value = true;
file.value = await os.api('drive/files/show', {
fileId: props.fileId,
}).catch((err) => {
console.error(err);
return undefined;
});
fetching.value = false;
}
function postThis() {
if (!file.value) return;
os.post({
initialFiles: [file.value],
});
}
function crop() {
if (!file.value) return;
os.cropImage(file.value, {
aspectRatio: NaN,
uploadFolder: file.value.folderId ?? null,
});
}
function toggleSensitive() {
if (!file.value) return;
os.apiWithDialog('drive/files/update', {
fileId: file.value.id,
isSensitive: !file.value.isSensitive,
}).then(async () => {
await fetch();
}).catch(err => {
os.alert({
type: 'error',
title: i18n.ts.error,
text: err.message,
});
});
}
function rename() {
if (!file.value) return;
os.inputText({
title: i18n.ts.renameFile,
placeholder: i18n.ts.inputNewFileName,
default: file.value.name,
}).then(({ canceled, result: name }) => {
if (canceled) return;
os.apiWithDialog('drive/files/update', {
fileId: file.value.id,
name: name,
}).then(async () => {
await fetch();
});
});
}
function describe() {
if (!file.value) return;
os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
default: file.value.comment ?? '',
file: file.value,
}, {
done: caption => {
os.apiWithDialog('drive/files/update', {
fileId: file.value.id,
comment: caption.length === 0 ? null : caption,
}).then(async () => {
await fetch();
});
},
}, 'closed');
}
async function deleteFile() {
if (!file.value) return;
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.t('driveFileDeleteConfirm', { name: file.value.name }),
});
if (canceled) return;
await os.apiWithDialog('drive/files/delete', {
fileId: file.value.id,
});
router.push('/my/drive');
}
onMounted(async () => {
await fetch();
});
</script>
<style lang="scss" module>
.filePreviewRoot {
background: var(--panel);
border-radius: var(--radius);
// MkMediaList 4px
padding: calc(1rem - 4px) 1rem 1rem;
}
.fileQuickActionsRoot {
display: flex;
flex-direction: column;
gap: 8px;
}
@container (min-width: 500px) {
.fileQuickActionsRoot {
flex-direction: row;
align-items: center;
}
}
.fileQuickActionsOthers {
margin-left: auto;
margin-right: 1rem;
display: flex;
gap: 8px;
.fileQuickActionsOthersButton {
padding: .5rem;
border-radius: 99rem;
&:hover,
&:focus-visible {
background-color: var(--accentedBg);
color: var(--accent);
text-decoration: none;
}
&.danger {
color: #ff2a2a;
}
&.danger:hover,
&.danger:focus-visible {
background-color: rgba(255, 42, 42, .15);
}
}
}
.fileNameEditBtn {
padding: .5rem 1rem;
display: flex;
align-items: center;
min-width: 0;
font-weight: 700;
border-radius: var(--radius);
font-size: .8rem;
>.fileNameEditIcon {
color: transparent;
visibility: hidden;
padding-left: .5rem;
}
>.fileName {
margin: 0;
}
&:hover {
background-color: var(--accentedBg);
>.fileName,
>.fileNameEditIcon {
visibility: visible;
color: var(--accent);
}
}
}
.fileMetaDataChildren {
padding: .5rem 1rem;
}
.fileAltEditBtn {
text-align: start;
display: block;
width: 100%;
padding: .5rem 1rem;
border-radius: var(--radius);
.fileAltEditIcon {
display: inline-block;
color: transparent;
visibility: hidden;
padding-left: .5rem;
}
&:hover {
color: var(--accent);
background-color: var(--accentedBg);
.fileAltEditIcon {
color: var(--accent);
visibility: visible;
}
}
}
</style>

View file

@ -0,0 +1,33 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div class="_gaps">
<MkInfo>{{ i18n.ts._fileViewer.thisPageCanBeSeenFromTheAuthor }}</MkInfo>
<MkNotes ref="tlComponent" :pagination="pagination"/>
</div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { i18n } from '@/i18n.js';
import { Paging } from '@/components/MkPagination.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkNotes from '@/components/MkNotes.vue';
const props = defineProps<{
fileId: string;
}>();
const realFileId = computed(() => props.fileId);
const pagination = ref<Paging>({
endpoint: 'drive/files/attached-notes',
limit: 10,
params: {
fileId: realFileId.value,
},
});
</script>

View file

@ -0,0 +1,52 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header>
<MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/>
</template>
<MkSpacer v-if="tab === 'info'" :contentMax="800">
<XFileInfo :fileId="fileId"/>
</MkSpacer>
<MkSpacer v-else-if="tab === 'notes'" :contentMax="800">
<XNotes :fileId="fileId"/>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { computed, ref, defineAsyncComponent } from 'vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const props = defineProps<{
fileId: string;
}>();
const XFileInfo = defineAsyncComponent(() => import('./drive.file.info.vue'));
const XNotes = defineAsyncComponent(() => import('./drive.file.notes.vue'));
const tab = ref('info');
const headerActions = computed(() => []);
const headerTabs = computed(() => [{
key: 'info',
title: i18n.ts.info,
icon: 'ti ti-info-circle',
}, {
key: 'notes',
title: i18n.ts._fileViewer.attachedNotes,
icon: 'ti ti-pencil',
}]);
definePageMetadata(computed(() => ({
title: i18n.ts._fileViewer.title,
icon: 'ti ti-file',
})));
</script>

View file

@ -61,20 +61,7 @@ function settings() {
router.push(`/my/lists/${props.listId}`); router.push(`/my/lists/${props.listId}`);
} }
async function timetravel() {
const { canceled, result: date } = await os.inputDate({
title: i18n.ts.date,
});
if (canceled) return;
tlEl.timetravel(date);
}
const headerActions = $computed(() => list ? [{ const headerActions = $computed(() => list ? [{
icon: 'ti ti-calendar-time',
text: i18n.ts.jumpToSpecifiedDate,
handler: timetravel,
}, {
icon: 'ti ti-settings', icon: 'ti ti-settings',
text: i18n.ts.settings, text: i18n.ts.settings,
handler: settings, handler: settings,

View file

@ -467,6 +467,10 @@ export const routes = [{
path: '/my/drive', path: '/my/drive',
component: page(() => import('./pages/drive.vue')), component: page(() => import('./pages/drive.vue')),
loginRequired: true, loginRequired: true,
}, {
path: '/my/drive/file/:fileId',
component: page(() => import('./pages/drive.file.vue')),
loginRequired: true,
}, { }, {
path: '/my/follow-requests', path: '/my/follow-requests',
component: page(() => import('./pages/follow-requests.vue')), component: page(() => import('./pages/follow-requests.vue')),

View file

@ -27,7 +27,7 @@ function rename(file: Misskey.entities.DriveFile) {
function describe(file: Misskey.entities.DriveFile) { function describe(file: Misskey.entities.DriveFile) {
os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), {
default: file.comment != null ? file.comment : '', default: file.comment ?? '',
file: file, file: file,
}, { }, {
done: caption => { done: caption => {
@ -139,6 +139,11 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
text: i18n.ts.download, text: i18n.ts.download,
icon: 'ti ti-download', icon: 'ti ti-download',
download: file.name, download: file.name,
}, null, {
type: 'link',
to: `/my/drive/file/${file.id}`,
text: i18n.ts._fileViewer.title,
icon: 'ti ti-file',
}, null, { }, null, {
text: i18n.ts.delete, text: i18n.ts.delete,
icon: 'ti ti-trash', icon: 'ti ti-trash',

View file

@ -54,9 +54,6 @@
infoWarnBg: '#42321c', infoWarnBg: '#42321c',
infoWarnFg: '#ffbd3e', infoWarnFg: '#ffbd3e',
switchBg: 'rgba(255, 255, 255, 0.15)', switchBg: 'rgba(255, 255, 255, 0.15)',
cwBg: '#687390',
cwFg: '#393f4f',
cwHoverBg: '#707b97',
buttonBg: 'rgba(255, 255, 255, 0.05)', buttonBg: 'rgba(255, 255, 255, 0.05)',
buttonHoverBg: 'rgba(255, 255, 255, 0.1)', buttonHoverBg: 'rgba(255, 255, 255, 0.1)',
buttonGradateA: '@accent', buttonGradateA: '@accent',

View file

@ -54,9 +54,6 @@
infoWarnBg: '#fff0db', infoWarnBg: '#fff0db',
infoWarnFg: '#8f6e31', infoWarnFg: '#8f6e31',
switchBg: 'rgba(0, 0, 0, 0.15)', switchBg: 'rgba(0, 0, 0, 0.15)',
cwBg: '#b1b9c1',
cwFg: '#fff',
cwHoverBg: '#bbc4ce',
buttonBg: 'rgba(0, 0, 0, 0.05)', buttonBg: 'rgba(0, 0, 0, 0.05)',
buttonHoverBg: 'rgba(0, 0, 0, 0.1)', buttonHoverBg: 'rgba(0, 0, 0, 0.1)',
buttonGradateA: '@accent', buttonGradateA: '@accent',

View file

@ -6,8 +6,6 @@
props: { props: {
bg: '#232125', bg: '#232125',
fg: '#efdab9', fg: '#efdab9',
cwBg: '#687390',
cwFg: '#393f4f',
link: '#78b0a0', link: '#78b0a0',
warn: '#ecb637', warn: '#ecb637',
badge: '#31b1ce', badge: '#31b1ce',
@ -29,7 +27,6 @@
success: '#86b300', success: '#86b300',
buttonBg: 'rgba(255, 255, 255, 0.05)', buttonBg: 'rgba(255, 255, 255, 0.05)',
acrylicBg: ':alpha<0.5<@bg', acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#707b97',
indicator: '@accent', indicator: '@accent',
mentionMe: '#fb5d38', mentionMe: '#fb5d38',
messageBg: '@bg', messageBg: '@bg',

View file

@ -21,8 +21,6 @@
X15: ':alpha<0<@panel', X15: ':alpha<0<@panel',
X16: ':alpha<0.7<@panel', X16: ':alpha<0.7<@panel',
X17: ':alpha<0.8<@bg', X17: ':alpha<0.8<@bg',
cwBg: '#687390',
cwFg: '#393f4f',
link: '@accent', link: '@accent',
warn: '#ecb637', warn: '#ecb637',
badge: '#31b1ce', badge: '#31b1ce',
@ -46,7 +44,6 @@
buttonBg: 'rgba(255, 255, 255, 0.05)', buttonBg: 'rgba(255, 255, 255, 0.05)',
switchBg: 'rgba(255, 255, 255, 0.15)', switchBg: 'rgba(255, 255, 255, 0.15)',
acrylicBg: ':alpha<0.5<@bg', acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#707b97',
indicator: '@accent', indicator: '@accent',
mentionMe: '@mention', mentionMe: '@mention',
messageBg: '@bg', messageBg: '@bg',

View file

@ -21,8 +21,6 @@
X15: ':alpha<0<@panel', X15: ':alpha<0<@panel',
X16: ':alpha<0.7<@panel', X16: ':alpha<0.7<@panel',
X17: ':alpha<0.8<@bg', X17: ':alpha<0.8<@bg',
cwBg: '#687390',
cwFg: '#393f4f',
link: '@accent', link: '@accent',
warn: '#ecb637', warn: '#ecb637',
badge: '#31b1ce', badge: '#31b1ce',
@ -46,7 +44,6 @@
buttonBg: '#0000000d', buttonBg: '#0000000d',
switchBg: 'rgba(255, 255, 255, 0.15)', switchBg: 'rgba(255, 255, 255, 0.15)',
acrylicBg: ':alpha<0.5<@bg', acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#707b97',
indicator: '@accent', indicator: '@accent',
mentionMe: '@mention', mentionMe: '@mention',
messageBg: '@bg', messageBg: '@bg',

View file

@ -9,8 +9,6 @@
props: { props: {
bg: '#fafafa', bg: '#fafafa',
fg: '#444', fg: '#444',
cwBg: '#b1b9c1',
cwFg: '#fff',
link: '#ff9400', link: '#ff9400',
warn: '#ecb637', warn: '#ecb637',
badge: '#31b1ce', badge: '#31b1ce',
@ -32,7 +30,6 @@
success: '#86b300', success: '#86b300',
buttonBg: 'rgba(0, 0, 0, 0.05)', buttonBg: 'rgba(0, 0, 0, 0.05)',
acrylicBg: ':alpha<0.5<@bg', acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#bbc4ce',
indicator: '@accent', indicator: '@accent',
mentionMe: '@mention', mentionMe: '@mention',
messageBg: '@bg', messageBg: '@bg',

View file

@ -23,9 +23,9 @@
"@microsoft/api-extractor": "7.38.0", "@microsoft/api-extractor": "7.38.0",
"@swc/jest": "0.2.29", "@swc/jest": "0.2.29",
"@types/jest": "29.5.5", "@types/jest": "29.5.5",
"@types/node": "20.8.3", "@types/node": "20.8.4",
"@typescript-eslint/eslint-plugin": "6.7.4", "@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.4", "@typescript-eslint/parser": "6.7.5",
"eslint": "8.51.0", "eslint": "8.51.0",
"jest": "29.7.0", "jest": "29.7.0",
"jest-fetch-mock": "3.0.3", "jest-fetch-mock": "3.0.3",

View file

@ -14,7 +14,7 @@
"misskey-js": "workspace:*" "misskey-js": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/parser": "6.7.4", "@typescript-eslint/parser": "6.7.5",
"@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67",
"eslint": "8.51.0", "eslint": "8.51.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.28.1",

File diff suppressed because it is too large Load diff