Merge branch 'develop' of https://codeberg.org/calckey/calckey into feat/module-player

This commit is contained in:
Essem 2023-07-06 13:23:21 -05:00
commit 672112ca65
No known key found for this signature in database
GPG key ID: 7D497397CC3A2A8C
387 changed files with 10201 additions and 1215 deletions

3
.gitignore vendored
View file

@ -48,6 +48,9 @@ packages/backend/assets/sounds/None.mp3
!packages/backend/src/db !packages/backend/src/db
packages/megalodon/lib
packages/megalodon/.idea
# blender backups # blender backups
*.blend1 *.blend1
*.blend2 *.blend2

View file

@ -1,10 +1,10 @@
_lang_: "Français" _lang_: "Français"
headlineMisskey: "Réseau relié par des notes" headlineMisskey: "Réseau relié par des notes"
introMisskey: "Bienvenue ! Calckey est un service de microblogage décentralisé, libre\ introMisskey: "Bienvenue ! Calckey est un service de microblogage décentralisé, libre
\ et ouvert.\nÉcrivez des « notes » et partagez ce qui se passe à linstant présent,\ et ouvert.\nÉcrivez des « notes » et partagez ce qui se passe à linstant présent,
\ autour de vous avec les autres \U0001F4E1\nLa fonction « réactions », vous permet\ autour de vous avec les autres 📡\nLa fonction « réactions », vous permet également
\ également dajouter une réaction rapide aux notes des autres utilisateur·rice·s\ dajouter une réaction rapide aux notes des autres utilisateur·rice·s 👍\nExplorons
\ \U0001F44D\nExplorons un nouveau monde \U0001F680" un nouveau monde 🚀"
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "Rechercher" search: "Rechercher"
notifications: "Notifications" notifications: "Notifications"
@ -26,8 +26,8 @@ otherSettings: "Paramètres avancés"
openInWindow: "Ouvrir dans une nouvelle fenêtre" openInWindow: "Ouvrir dans une nouvelle fenêtre"
profile: "Profil" profile: "Profil"
timeline: "Fil" timeline: "Fil"
noAccountDescription: "Lutilisateur·rice na pas encore renseigné de biographie de\ noAccountDescription: "Lutilisateur·rice na pas encore renseigné de biographie de
\ présentation sur son profil." présentation sur son profil."
login: "Se connecter" login: "Se connecter"
loggingIn: "Connexion en cours" loggingIn: "Connexion en cours"
logout: "Se déconnecter" logout: "Se déconnecter"
@ -48,8 +48,8 @@ copyContent: "Copier le contenu"
copyLink: "Copier le lien" copyLink: "Copier le lien"
delete: "Supprimer" delete: "Supprimer"
deleteAndEdit: "Supprimer et réécrire" deleteAndEdit: "Supprimer et réécrire"
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler\ deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler
\ ? Vous perdrez toutes les réactions, renotes et réponses y afférentes." ? Vous perdrez toutes les réactions, renotes et réponses y afférentes."
addToList: "Ajouter à une liste" addToList: "Ajouter à une liste"
sendMessage: "Envoyer un message" sendMessage: "Envoyer un message"
copyUsername: "Copier le nom dutilisateur·rice" copyUsername: "Copier le nom dutilisateur·rice"
@ -72,8 +72,8 @@ download: "Télécharger"
driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\"\ driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\"\
\ ? Il sera retiré de toutes ses notes liées." \ ? Il sera retiré de toutes ses notes liées."
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?" unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
exportRequested: "Vous avez demandé une exportation. Lopération pourrait prendre\ exportRequested: "Vous avez demandé une exportation. Lopération pourrait prendre
\ un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive." un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive."
importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps." importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps."
lists: "Listes" lists: "Listes"
noLists: "Vous navez aucune liste" noLists: "Vous navez aucune liste"
@ -88,12 +88,12 @@ error: "Erreur"
somethingHappened: "Une erreur est survenue" somethingHappened: "Une erreur est survenue"
retry: "Réessayer" retry: "Réessayer"
pageLoadError: "Le chargement de la page a échoué." pageLoadError: "Le chargement de la page a échoué."
pageLoadErrorDescription: "Cela est généralement causé par le cache du navigateur\ pageLoadErrorDescription: "Cela est généralement causé par le cache du navigateur
\ ou par un problème réseau. Veuillez vider votre cache ou attendre un peu et réessayer." ou par un problème réseau. Veuillez vider votre cache ou attendre un peu et réessayer."
serverIsDead: "Le serveur ne répond pas. Patientez quelques instants puis essayez\ serverIsDead: "Le serveur ne répond pas. Patientez quelques instants puis essayez
\ à nouveau." à nouveau."
youShouldUpgradeClient: "Si la page ne s'affiche pas correctement, rechargez-la pour\ youShouldUpgradeClient: "Si la page ne s'affiche pas correctement, rechargez-la pour
\ mettre votre client à jour." mettre votre client à jour."
enterListName: "Nom de la liste" enterListName: "Nom de la liste"
privacy: "Confidentialité" privacy: "Confidentialité"
makeFollowManuallyApprove: "Accepter manuellement les demandes dabonnement" makeFollowManuallyApprove: "Accepter manuellement les demandes dabonnement"
@ -118,11 +118,11 @@ sensitive: "Contenu sensible"
add: "Ajouter" add: "Ajouter"
reaction: "Réactions" reaction: "Réactions"
reactionSetting: "Réactions à afficher dans le sélecteur de réactions" reactionSetting: "Réactions à afficher dans le sélecteur de réactions"
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser\ reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser
\ « + » pour ajouter." « + » pour ajouter."
rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des notes\ rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des notes
\ \" vous permet de réutiliser automatiquement la visibilité utilisée lors de la\ \" vous permet de réutiliser automatiquement la visibilité utilisée lors de la publication
\ publication de votre note précédente." de votre note précédente."
attachCancel: "Supprimer le fichier attaché" attachCancel: "Supprimer le fichier attaché"
markAsSensitive: "Marquer comme sensible" markAsSensitive: "Marquer comme sensible"
unmarkAsSensitive: "Supprimer le marquage comme sensible" unmarkAsSensitive: "Supprimer le marquage comme sensible"
@ -150,20 +150,20 @@ emojiUrl: "URL de lémoji"
addEmoji: "Ajouter un émoji" addEmoji: "Ajouter un émoji"
settingGuide: "Configuration proposée" settingGuide: "Configuration proposée"
cacheRemoteFiles: "Mise en cache des fichiers distants" cacheRemoteFiles: "Mise en cache des fichiers distants"
cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants\ cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants
\ sont chargés directement depuis linstance distante. La désactiver diminuera certes\ sont chargés directement depuis linstance distante. La désactiver diminuera certes
\ lutilisation de lespace de stockage local mais augmentera le trafic réseau puisque\ lutilisation de lespace de stockage local mais augmentera le trafic réseau puisque
\ les miniatures ne seront plus générées." les miniatures ne seront plus générées."
flagAsBot: "Ce compte est un robot" flagAsBot: "Ce compte est un robot"
flagAsBotDescription: "Si ce compte est géré de manière automatisée, choisissez cette\ flagAsBotDescription: "Si ce compte est géré de manière automatisée, choisissez cette
\ option. Si elle est activée, elle agira comme un marqueur pour les autres développeurs\ option. Si elle est activée, elle agira comme un marqueur pour les autres développeurs
\ afin d'éviter des chaînes d'interaction sans fin avec d'autres robots et d'ajuster\ afin d'éviter des chaînes d'interaction sans fin avec d'autres robots et d'ajuster
\ les systèmes internes de Calckey pour traiter ce compte comme un robot." les systèmes internes de Calckey pour traiter ce compte comme un robot."
flagAsCat: "Ce compte est un chat" flagAsCat: "Ce compte est un chat"
flagAsCatDescription: "Activer l'option \" Je suis un chat \" pour ce compte." flagAsCatDescription: "Activer l'option \" Je suis un chat \" pour ce compte."
flagShowTimelineReplies: "Afficher les réponses dans le fil" flagShowTimelineReplies: "Afficher les réponses dans le fil"
autoAcceptFollowed: "Accepter automatiquement les demandes dabonnement venant dutilisateur·rice·s\ autoAcceptFollowed: "Accepter automatiquement les demandes dabonnement venant dutilisateur·rice·s
\ que vous suivez" que vous suivez"
addAccount: "Ajouter un compte" addAccount: "Ajouter un compte"
loginFailed: "Échec de la connexion" loginFailed: "Échec de la connexion"
showOnRemote: "Voir sur linstance distante" showOnRemote: "Voir sur linstance distante"
@ -175,12 +175,12 @@ searchWith: "Recherche : {q}"
youHaveNoLists: "Vous navez aucune liste" youHaveNoLists: "Vous navez aucune liste"
followConfirm: "Êtes-vous sûr·e de vouloir suivre {name} ?" followConfirm: "Êtes-vous sûr·e de vouloir suivre {name} ?"
proxyAccount: "Compte proxy" proxyAccount: "Compte proxy"
proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions,\ proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions,
\ comme un·e abonné·e distant·e pour les utilisateurs d'autres instances. Par exemple,\ comme un·e abonné·e distant·e pour les utilisateurs d'autres instances. Par exemple,
\ quand un·e utilisateur·rice ajoute un·e utilisateur·rice distant·e à une liste,\ quand un·e utilisateur·rice ajoute un·e utilisateur·rice distant·e à une liste,
\ ses notes ne seront pas visibles sur l'instance si personne ne suit cet·te utilisateur·rice.\ ses notes ne seront pas visibles sur l'instance si personne ne suit cet·te utilisateur·rice.
\ Le compte proxy va donc suivre cet·te utilisateur·rice pour que ses notes soient\ Le compte proxy va donc suivre cet·te utilisateur·rice pour que ses notes soient
\ acheminées." acheminées."
host: "Serveur distant" host: "Serveur distant"
selectUser: "Sélectionner un·e utilisateur·rice" selectUser: "Sélectionner un·e utilisateur·rice"
recipient: "Destinataire" recipient: "Destinataire"
@ -210,14 +210,14 @@ instanceInfo: "Informations sur linstance"
statistics: "Statistiques" statistics: "Statistiques"
clearQueue: "Vider la file dattente" clearQueue: "Vider la file dattente"
clearQueueConfirmTitle: "Êtes-vous sûr·e de vouloir vider la file dattente ?" clearQueueConfirmTitle: "Êtes-vous sûr·e de vouloir vider la file dattente ?"
clearQueueConfirmText: "Les notes non distribuées ne seront pas délivrées. Normalement,\ clearQueueConfirmText: "Les notes non distribuées ne seront pas délivrées. Normalement,
\ vous n'avez pas besoin d'effectuer cette opération." vous n'avez pas besoin d'effectuer cette opération."
clearCachedFiles: "Vider le cache" clearCachedFiles: "Vider le cache"
clearCachedFilesConfirm: "Êtes-vous sûr·e de vouloir vider tout le cache de fichiers\ clearCachedFilesConfirm: "Êtes-vous sûr·e de vouloir vider tout le cache de fichiers
\ distants ?" distants ?"
blockedInstances: "Instances bloquées" blockedInstances: "Instances bloquées"
blockedInstancesDescription: "Listez les instances que vous désirez bloquer, une par\ blockedInstancesDescription: "Listez les instances que vous désirez bloquer, une par
\ ligne. Ces instances ne seront plus en capacité d'interagir avec votre instance." ligne. Ces instances ne seront plus en capacité d'interagir avec votre instance."
muteAndBlock: "Masqué·e·s / Bloqué·e·s" muteAndBlock: "Masqué·e·s / Bloqué·e·s"
mutedUsers: "Utilisateur·rice·s en sourdine" mutedUsers: "Utilisateur·rice·s en sourdine"
blockedUsers: "Utilisateur·rice·s bloqué·e·s" blockedUsers: "Utilisateur·rice·s bloqué·e·s"
@ -270,8 +270,8 @@ fromUrl: "Depuis une URL"
uploadFromUrl: "Téléverser via une URL" uploadFromUrl: "Téléverser via une URL"
uploadFromUrlDescription: "URL du fichier que vous souhaitez téléverser" uploadFromUrlDescription: "URL du fichier que vous souhaitez téléverser"
uploadFromUrlRequested: "Téléversement demandé" uploadFromUrlRequested: "Téléversement demandé"
uploadFromUrlMayTakeTime: "Le téléversement de votre fichier peut prendre un certain\ uploadFromUrlMayTakeTime: "Le téléversement de votre fichier peut prendre un certain
\ temps." temps."
explore: "Découvrir" explore: "Découvrir"
messageRead: "Lu" messageRead: "Lu"
noMoreHistory: "Il ny a plus dhistorique" noMoreHistory: "Il ny a plus dhistorique"
@ -281,8 +281,8 @@ agreeTo: "Jaccepte {0}"
tos: "les conditions dutilisation" tos: "les conditions dutilisation"
start: "Commencer" start: "Commencer"
home: "Principal" home: "Principal"
remoteUserCaution: "Les informations de ce compte risqueraient dêtre incomplètes\ remoteUserCaution: "Les informations de ce compte risqueraient dêtre incomplètes
\ du fait que lutilisateur·rice provient dune instance distante." du fait que lutilisateur·rice provient dune instance distante."
activity: "Activité" activity: "Activité"
images: "Images" images: "Images"
birthday: "Date de naissance" birthday: "Date de naissance"
@ -315,8 +315,8 @@ unableToDelete: "Suppression impossible"
inputNewFileName: "Entrez un nouveau nom de fichier" inputNewFileName: "Entrez un nouveau nom de fichier"
inputNewDescription: "Veuillez entrer une nouvelle description" inputNewDescription: "Veuillez entrer une nouvelle description"
inputNewFolderName: "Entrez un nouveau nom de dossier" inputNewFolderName: "Entrez un nouveau nom de dossier"
circularReferenceFolder: "Le dossier de destination est un sous-dossier du dossier\ circularReferenceFolder: "Le dossier de destination est un sous-dossier du dossier
\ que vous souhaitez déplacer." que vous souhaitez déplacer."
hasChildFilesOrFolders: "Impossible de supprimer ce dossier car il n'est pas vide." hasChildFilesOrFolders: "Impossible de supprimer ce dossier car il n'est pas vide."
copyUrl: "Copier lURL" copyUrl: "Copier lURL"
rename: "Renommer" rename: "Renommer"
@ -350,8 +350,8 @@ connectService: "Connexion"
disconnectService: "Déconnexion" disconnectService: "Déconnexion"
enableLocalTimeline: "Activer le fil local" enableLocalTimeline: "Activer le fil local"
enableGlobalTimeline: "Activer le fil global" enableGlobalTimeline: "Activer le fil global"
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s\ disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s
\ et les modérateur·rice·s pourront toujours y accéder." et les modérateur·rice·s pourront toujours y accéder."
registration: "Sinscrire" registration: "Sinscrire"
enableRegistration: "Autoriser les nouvelles inscriptions" enableRegistration: "Autoriser les nouvelles inscriptions"
invite: "Inviter" invite: "Inviter"
@ -363,11 +363,11 @@ bannerUrl: "URL de limage de la bannière"
backgroundImageUrl: "URL de l'image d'arrière-plan" backgroundImageUrl: "URL de l'image d'arrière-plan"
basicInfo: "Informations basiques" basicInfo: "Informations basiques"
pinnedUsers: "Utilisateur·rice épinglé·e" pinnedUsers: "Utilisateur·rice épinglé·e"
pinnedUsersDescription: "Listez les utilisateur·rice·s que vous souhaitez voir épinglé·e·s\ pinnedUsersDescription: "Listez les utilisateur·rice·s que vous souhaitez voir épinglé·e·s
\ sur la page \"Découvrir\", un·e par ligne." sur la page \"Découvrir\", un·e par ligne."
pinnedPages: "Pages épinglées" pinnedPages: "Pages épinglées"
pinnedPagesDescription: "Inscrivez le chemin des pages que vous souhaitez épingler\ pinnedPagesDescription: "Inscrivez le chemin des pages que vous souhaitez épingler
\ en haut de la page de l'instance. Séparez les pages d'un retour à la ligne." en haut de la page de l'instance. Séparez les pages d'un retour à la ligne."
pinnedClipId: "Identifiant du clip épinglé" pinnedClipId: "Identifiant du clip épinglé"
pinnedNotes: "Note épinglée" pinnedNotes: "Note épinglée"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
@ -378,17 +378,17 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Activer reCAPTCHA" enableRecaptcha: "Activer reCAPTCHA"
recaptchaSiteKey: "Clé du site" recaptchaSiteKey: "Clé du site"
recaptchaSecretKey: "Clé secrète" recaptchaSecretKey: "Clé secrète"
avoidMultiCaptchaConfirm: "Lutilisation de plusieurs Captchas peut provoquer des\ avoidMultiCaptchaConfirm: "Lutilisation de plusieurs Captchas peut provoquer des
\ interférences. Souhaitez-vous désactiver lautre Captcha ? Vous pouvez laisser\ interférences. Souhaitez-vous désactiver lautre Captcha ? Vous pouvez laisser plusieurs
\ plusieurs Captcha activés en appuyant sur Annuler." Captcha activés en appuyant sur Annuler."
antennas: "Antennes" antennas: "Antennes"
manageAntennas: "Gestion des antennes" manageAntennas: "Gestion des antennes"
name: "Nom" name: "Nom"
antennaSource: "Source de lantenne" antennaSource: "Source de lantenne"
antennaKeywords: "Mots clés à recevoir" antennaKeywords: "Mots clés à recevoir"
antennaExcludeKeywords: "Mots clés à exclure" antennaExcludeKeywords: "Mots clés à exclure"
antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer\ antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer
\ avec un saut de ligne pour une condition OR." avec un saut de ligne pour une condition OR."
notifyAntenna: "Je souhaite recevoir les notifications des nouvelles notes" notifyAntenna: "Je souhaite recevoir les notifications des nouvelles notes"
withFileAntenna: "Notes ayant des attachements uniquement" withFileAntenna: "Notes ayant des attachements uniquement"
enableServiceworker: "Activer ServiceWorker" enableServiceworker: "Activer ServiceWorker"
@ -399,11 +399,11 @@ connectedTo: "Vous êtes connectés aux services suivants"
notesAndReplies: "Notes et Réponses" notesAndReplies: "Notes et Réponses"
withFiles: "Avec fichiers joints" withFiles: "Avec fichiers joints"
silence: "Mettre en sourdine" silence: "Mettre en sourdine"
silenceConfirm: "Êtes-vous sûr·e de vouloir mettre lutilisateur·rice en sourdine\ silenceConfirm: "Êtes-vous sûr·e de vouloir mettre lutilisateur·rice en sourdine
\ ?" ?"
unsilence: "Annuler la sourdine" unsilence: "Annuler la sourdine"
unsilenceConfirm: "Êtes-vous sûr·e de vouloir annuler la mise en sourdine de cet·te\ unsilenceConfirm: "Êtes-vous sûr·e de vouloir annuler la mise en sourdine de cet·te
\ utilisateur·rice ?" utilisateur·rice ?"
popularUsers: "Utilisateur·rice·s populaires" popularUsers: "Utilisateur·rice·s populaires"
recentlyUpdatedUsers: "Utilisateur·rice·s actif·ve·s récemment" recentlyUpdatedUsers: "Utilisateur·rice·s actif·ve·s récemment"
recentlyRegisteredUsers: "Utilisateur·rice·s récemment inscrit·e·s" recentlyRegisteredUsers: "Utilisateur·rice·s récemment inscrit·e·s"
@ -468,8 +468,8 @@ invitationCode: "Code dinvitation"
checking: "Vérification en cours..." checking: "Vérification en cours..."
available: "Disponible" available: "Disponible"
unavailable: "Non disponible" unavailable: "Non disponible"
usernameInvalidFormat: "Le nom d'utilisateur peut contenir uniquement des lettres\ usernameInvalidFormat: "Le nom d'utilisateur peut contenir uniquement des lettres
\ (minuscules et/ou majuscules), des chiffres et des _" (minuscules et/ou majuscules), des chiffres et des _"
tooShort: "Trop court" tooShort: "Trop court"
tooLong: "Trop long" tooLong: "Trop long"
weakPassword: "Mot de passe faible" weakPassword: "Mot de passe faible"
@ -478,8 +478,8 @@ strongPassword: "Mot de passe fort"
passwordMatched: "Les mots de passe correspondent" passwordMatched: "Les mots de passe correspondent"
passwordNotMatched: "Les mots de passe ne correspondent pas" passwordNotMatched: "Les mots de passe ne correspondent pas"
signinWith: "Se connecter avec {x}" signinWith: "Se connecter avec {x}"
signinFailed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur\ signinFailed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur
\ et mot de passe sont corrects." et mot de passe sont corrects."
tapSecurityKey: "Appuyez sur votre clé de sécurité" tapSecurityKey: "Appuyez sur votre clé de sécurité"
or: "OU" or: "OU"
language: "Langue" language: "Langue"
@ -488,8 +488,8 @@ groupInvited: "Invité au groupe"
aboutX: "À propos de {x}" aboutX: "À propos de {x}"
useOsNativeEmojis: "Utiliser les émojis natifs du système" useOsNativeEmojis: "Utiliser les émojis natifs du système"
youHaveNoGroups: "Vous navez aucun groupe" youHaveNoGroups: "Vous navez aucun groupe"
joinOrCreateGroup: "Vous pouvez être invité·e à rejoindre des groupes existants ou\ joinOrCreateGroup: "Vous pouvez être invité·e à rejoindre des groupes existants ou
\ créer votre propre nouveau groupe." créer votre propre nouveau groupe."
noHistory: "Pas d'historique" noHistory: "Pas d'historique"
signinHistory: "Historique de connexion" signinHistory: "Historique de connexion"
disableAnimatedMfm: "Désactiver MFM ayant des animations" disableAnimatedMfm: "Désactiver MFM ayant des animations"
@ -520,29 +520,29 @@ showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'act
objectStorage: "Stockage d'objets" objectStorage: "Stockage d'objets"
useObjectStorage: "Utiliser le stockage d'objets" useObjectStorage: "Utiliser le stockage d'objets"
objectStorageBaseUrl: "Base URL" objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "Préfixe dURL utilisé pour construire lURL vers le référencement\ objectStorageBaseUrlDesc: "Préfixe dURL utilisé pour construire lURL vers le référencement
\ dobjet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon\ dobjet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez
\ spécifiez ladresse accessible au public selon le guide de service que vous allez\ ladresse accessible au public selon le guide de service que vous allez utiliser.
\ utiliser. P.ex. 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>'\ P.ex. 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>'
\ pour GCS." pour GCS."
objectStorageBucket: "Bucket" objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le\ objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le
\ service configuré." service configuré."
objectStoragePrefix: "Prefix" objectStoragePrefix: "Prefix"
objectStoragePrefixDesc: "Les fichiers seront stockés sous le répertoire de ce préfixe." objectStoragePrefixDesc: "Les fichiers seront stockés sous le répertoire de ce préfixe."
objectStorageEndpoint: "Endpoint" objectStorageEndpoint: "Endpoint"
objectStorageEndpointDesc: "Laissez ce champ vide si vous utilisez AWS S3, sinon spécifiez\ objectStorageEndpointDesc: "Laissez ce champ vide si vous utilisez AWS S3, sinon spécifiez
\ le point de terminaison comme '<host>' ou '<host>: <port>' selon le guide de service\ le point de terminaison comme '<host>' ou '<host>: <port>' selon le guide de service
\ que vous allez utiliser." que vous allez utiliser."
objectStorageRegion: "Région" objectStorageRegion: "Région"
objectStorageRegionDesc: "Spécifiez une région comme 'xx-east-1'. Si votre service\ objectStorageRegionDesc: "Spécifiez une région comme 'xx-east-1'. Si votre service
\ ne fait pas de distinction entre les régions, laissez-le vide ou remplissez 'us-east-1'." ne fait pas de distinction entre les régions, laissez-le vide ou remplissez 'us-east-1'."
objectStorageUseSSL: "Utiliser SSL" objectStorageUseSSL: "Utiliser SSL"
objectStorageUseSSLDesc: "Désactivez cette option si vous n'utilisez pas HTTPS pour\ objectStorageUseSSLDesc: "Désactivez cette option si vous n'utilisez pas HTTPS pour
\ la connexion API" la connexion API"
objectStorageUseProxy: "Se connecter via proxy" objectStorageUseProxy: "Se connecter via proxy"
objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas de proxy\ objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas de proxy
\ pour la connexion API" pour la connexion API"
objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi" objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
serverLogs: "Journal du serveur" serverLogs: "Journal du serveur"
deleteAll: "Supprimer tout" deleteAll: "Supprimer tout"
@ -570,9 +570,9 @@ sort: "Trier"
ascendingOrder: "Ascendant" ascendingOrder: "Ascendant"
descendingOrder: "Descendant" descendingOrder: "Descendant"
scratchpad: "ScratchPad" scratchpad: "ScratchPad"
scratchpadDescription: "ScratchPad fournit un environnement expérimental pour AiScript.\ scratchpadDescription: "ScratchPad fournit un environnement expérimental pour AiScript.
\ Vous pouvez vérifier la rédaction de votre code, sa bonne exécution et le résultat\ Vous pouvez vérifier la rédaction de votre code, sa bonne exécution et le résultat
\ de son interaction avec Calckey." de son interaction avec Calckey."
output: "Sortie" output: "Sortie"
script: "Script" script: "Script"
disablePagesScript: "Désactiver AiScript sur les Pages" disablePagesScript: "Désactiver AiScript sur les Pages"
@ -580,15 +580,15 @@ updateRemoteUser: "Mettre à jour les informations de lutilisateur·rice dist
deleteAllFiles: "Supprimer tous les fichiers" deleteAllFiles: "Supprimer tous les fichiers"
deleteAllFilesConfirm: "Êtes-vous sûr·e de vouloir supprimer tous les fichiers ?" deleteAllFilesConfirm: "Êtes-vous sûr·e de vouloir supprimer tous les fichiers ?"
removeAllFollowing: "Retenir tous les abonnements" removeAllFollowing: "Retenir tous les abonnements"
removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Veuillez\ removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Veuillez
\ lancer cette action uniquement si linstance nexiste plus." lancer cette action uniquement si linstance nexiste plus."
userSuspended: "Cet·te utilisateur·rice a été suspendu·e." userSuspended: "Cet·te utilisateur·rice a été suspendu·e."
userSilenced: "Cette utilisateur·trice a été mis·e en sourdine." userSilenced: "Cette utilisateur·trice a été mis·e en sourdine."
yourAccountSuspendedTitle: "Ce compte est suspendu" yourAccountSuspendedTitle: "Ce compte est suspendu"
yourAccountSuspendedDescription: "Ce compte est suspendu car vous avez enfreint les\ yourAccountSuspendedDescription: "Ce compte est suspendu car vous avez enfreint les
\ conditions d'utilisation de l'instance, ou pour un motif similaire. Si vous souhaitez\ conditions d'utilisation de l'instance, ou pour un motif similaire. Si vous souhaitez
\ connaître en détail les raisons de cette suspension, renseignez-vous auprès de\ connaître en détail les raisons de cette suspension, renseignez-vous auprès de l'administrateur·rice
\ l'administrateur·rice de votre instance. Merci de ne pas créer de nouveau compte." de votre instance. Merci de ne pas créer de nouveau compte."
menu: "Menu" menu: "Menu"
divider: "Séparateur" divider: "Séparateur"
addItem: "Ajouter un élément" addItem: "Ajouter un élément"
@ -611,8 +611,8 @@ description: "Description"
describeFile: "Ajouter une description d'image" describeFile: "Ajouter une description d'image"
enterFileDescription: "Saisissez une description" enterFileDescription: "Saisissez une description"
author: "Auteur·rice" author: "Auteur·rice"
leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ignorer\ leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ignorer
\ ?" ?"
manage: "Gestion" manage: "Gestion"
plugins: "Extensions" plugins: "Extensions"
deck: "Deck" deck: "Deck"
@ -629,14 +629,14 @@ permission: "Autorisations"
enableAll: "Tout activer" enableAll: "Tout activer"
disableAll: "Tout désactiver" disableAll: "Tout désactiver"
tokenRequested: "Autoriser l'accès au compte" tokenRequested: "Autoriser l'accès au compte"
pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies\ pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies
\ ici." ici."
notificationType: "Type de notifications" notificationType: "Type de notifications"
edit: "Editer" edit: "Editer"
emailServer: "Serveur mail" emailServer: "Serveur mail"
enableEmail: "Activer la distribution de courriel" enableEmail: "Activer la distribution de courriel"
emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation\ emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation
\ de votre mot de passe en cas doubli." de votre mot de passe en cas doubli."
email: "E-mail " email: "E-mail "
emailAddress: "Adresses e-mail" emailAddress: "Adresses e-mail"
smtpConfig: "Paramètres du serveur SMTP" smtpConfig: "Paramètres du serveur SMTP"
@ -644,8 +644,8 @@ smtpHost: "Serveur distant"
smtpPort: "Port" smtpPort: "Port"
smtpUser: "Nom dutilisateur·rice" smtpUser: "Nom dutilisateur·rice"
smtpPass: "Mot de passe" smtpPass: "Mot de passe"
emptyToDisableSmtpAuth: "Laisser le nom dutilisateur et le mot de passe vides pour\ emptyToDisableSmtpAuth: "Laisser le nom dutilisateur et le mot de passe vides pour
\ désactiver la vérification SMTP" désactiver la vérification SMTP"
smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP" smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP"
smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé" smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé"
testEmail: "Tester la distribution de courriel" testEmail: "Tester la distribution de courriel"
@ -666,24 +666,24 @@ create: "Créer"
notificationSetting: "Paramètres des notifications " notificationSetting: "Paramètres des notifications "
notificationSettingDesc: "Sélectionnez le type de notification à afficher" notificationSettingDesc: "Sélectionnez le type de notification à afficher"
useGlobalSetting: "Utiliser paramètre général" useGlobalSetting: "Utiliser paramètre général"
useGlobalSettingDesc: "S'il est activé, les paramètres de notification de votre compte\ useGlobalSettingDesc: "S'il est activé, les paramètres de notification de votre compte
\ seront utilisés. S'il est désactivé, des configurations individuelles peuvent\ seront utilisés. S'il est désactivé, des configurations individuelles peuvent être
\ être effectuées." effectuées."
other: "Autre" other: "Autre"
regenerateLoginToken: "Régénérer le jeton de connexion" regenerateLoginToken: "Régénérer le jeton de connexion"
regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette\ regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette
\ opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau\ opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau jeton,
\ jeton, tous les appareils seront déconnectés. " tous les appareils seront déconnectés. "
setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant\ setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant
\ par des espaces." par des espaces."
fileIdOrUrl: "ID du fichier ou URL" fileIdOrUrl: "ID du fichier ou URL"
behavior: "Comportement" behavior: "Comportement"
sample: "Exemple" sample: "Exemple"
abuseReports: "Signalements" abuseReports: "Signalements"
reportAbuse: "Signaler" reportAbuse: "Signaler"
reportAbuseOf: "Signaler {name}" reportAbuseOf: "Signaler {name}"
fillAbuseReportDescription: "Veuillez expliquer les raisons du signalement. S'il s'agit\ fillAbuseReportDescription: "Veuillez expliquer les raisons du signalement. S'il s'agit
\ d'une note précise, veuillez en donner le lien." d'une note précise, veuillez en donner le lien."
abuseReported: "Le rapport est envoyé. Merci." abuseReported: "Le rapport est envoyé. Merci."
reporter: "Signalé par" reporter: "Signalé par"
reporteeOrigin: "Origine du signalement" reporteeOrigin: "Origine du signalement"
@ -694,8 +694,8 @@ abuseMarkAsResolved: "Marquer le signalement comme résolu"
openInNewTab: "Ouvrir dans un nouvel onglet" openInNewTab: "Ouvrir dans un nouvel onglet"
openInSideView: "Ouvrir en vue latérale" openInSideView: "Ouvrir en vue latérale"
defaultNavigationBehaviour: "Navigation par défaut" defaultNavigationBehaviour: "Navigation par défaut"
editTheseSettingsMayBreakAccount: "La modification de ces paramètres peut endommager\ editTheseSettingsMayBreakAccount: "La modification de ces paramètres peut endommager
\ votre compte." votre compte."
instanceTicker: "Nom de l'instance d'origine des notes" instanceTicker: "Nom de l'instance d'origine des notes"
waitingFor: "En attente de {x}" waitingFor: "En attente de {x}"
random: "Aléatoire" random: "Aléatoire"
@ -707,8 +707,8 @@ createNew: "Créer nouveau"
optional: "Facultatif" optional: "Facultatif"
createNewClip: "Créer un nouveau clip" createNewClip: "Créer un nouveau clip"
public: "Public" public: "Public"
i18nInfo: "Calckey est traduit dans différentes langues par des bénévoles. Vous pouvez\ i18nInfo: "Calckey est traduit dans différentes langues par des bénévoles. Vous pouvez
\ contribuer à {link}." contribuer à {link}."
manageAccessTokens: "Gérer les jetons d'accès" manageAccessTokens: "Gérer les jetons d'accès"
accountInfo: " Informations du compte " accountInfo: " Informations du compte "
notesCount: "Nombre de notes" notesCount: "Nombre de notes"
@ -727,16 +727,16 @@ no: "Non"
driveFilesCount: "Nombre de fichiers dans le Drive" driveFilesCount: "Nombre de fichiers dans le Drive"
driveUsage: "Utilisation du Drive" driveUsage: "Utilisation du Drive"
noCrawle: "Refuser l'indexation par les robots" noCrawle: "Refuser l'indexation par les robots"
noCrawleDescription: "Demandez aux moteurs de recherche de ne pas indexer votre page\ noCrawleDescription: "Demandez aux moteurs de recherche de ne pas indexer votre page
\ de profil, vos notes, vos pages, etc." de profil, vos notes, vos pages, etc."
lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre note sur\ lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre note sur
\ \"Abonné-e-s\", vos notes sont visibles par tous, même si vous exigez que les\ \"Abonné-e-s\", vos notes sont visibles par tous, même si vous exigez que les demandes
\ demandes d'abonnement soient approuvées manuellement." d'abonnement soient approuvées manuellement."
alwaysMarkSensitive: "Marquer les médias comme contenu sensible par défaut" alwaysMarkSensitive: "Marquer les médias comme contenu sensible par défaut"
loadRawImages: "Affichage complet des images jointes au lieu des vignettes" loadRawImages: "Affichage complet des images jointes au lieu des vignettes"
disableShowingAnimatedImages: "Désactiver l'animation des images" disableShowingAnimatedImages: "Désactiver l'animation des images"
verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez accéder au\ verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez accéder au
\ lien pour compléter la vérification." lien pour compléter la vérification."
notSet: "Non défini" notSet: "Non défini"
emailVerified: "Votre adresse e-mail a été vérifiée." emailVerified: "Votre adresse e-mail a été vérifiée."
noteFavoritesCount: "Nombre de notes dans les favoris" noteFavoritesCount: "Nombre de notes dans les favoris"
@ -748,16 +748,16 @@ clips: "Clips"
experimentalFeatures: "Fonctionnalités expérimentales" experimentalFeatures: "Fonctionnalités expérimentales"
developer: "Développeur" developer: "Développeur"
makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"." makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"."
makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra\ makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra
\ pas sur la page \"Découvrir\"." pas sur la page \"Découvrir\"."
showGapBetweenNotesInTimeline: "Afficher un écart entre les notes sur la Timeline" showGapBetweenNotesInTimeline: "Afficher un écart entre les notes sur la Timeline"
duplicate: "Duliquer" duplicate: "Duliquer"
left: "Gauche" left: "Gauche"
center: "Centrer" center: "Centrer"
wide: "Large" wide: "Large"
narrow: "Condensé" narrow: "Condensé"
reloadToApplySetting: "Vos paramètres seront appliqués lorsque vous rechargerez la\ reloadToApplySetting: "Vos paramètres seront appliqués lorsque vous rechargerez la
\ page. Souhaitez-vous recharger ?" page. Souhaitez-vous recharger ?"
needReloadToApply: "Ce paramètre s'appliquera après un rechargement." needReloadToApply: "Ce paramètre s'appliquera après un rechargement."
showTitlebar: "Afficher la barre de titre" showTitlebar: "Afficher la barre de titre"
clearCache: "Vider le cache" clearCache: "Vider le cache"
@ -765,11 +765,11 @@ onlineUsersCount: "{n} utilisateur(s) en ligne"
nUsers: "{n} utilisateur·rice·s" nUsers: "{n} utilisateur·rice·s"
nNotes: "{n} Notes" nNotes: "{n} Notes"
sendErrorReports: "Envoyer les rapports derreur" sendErrorReports: "Envoyer les rapports derreur"
sendErrorReportsDescription: "Si vous activez l'envoi des rapports d'erreur, vous\ sendErrorReportsDescription: "Si vous activez l'envoi des rapports d'erreur, vous
\ contribuerez à améliorer la qualité de Calckey grâce au partage d'informations\ contribuerez à améliorer la qualité de Calckey grâce au partage d'informations détaillées
\ détaillées sur les erreurs lorsqu'un problème survient.\nCela inclut des informations\ sur les erreurs lorsqu'un problème survient.\nCela inclut des informations telles
\ telles que la version de votre système d'exploitation, le type de navigateur que\ que la version de votre système d'exploitation, le type de navigateur que vous utilisez,
\ vous utilisez, votre historique d'activité, etc." votre historique d'activité, etc."
myTheme: "Mes thèmes" myTheme: "Mes thèmes"
backgroundColor: "Arrière-plan" backgroundColor: "Arrière-plan"
accentColor: "Accentuation" accentColor: "Accentuation"
@ -808,17 +808,17 @@ unlikeConfirm: "Êtes-vous sûr·e de ne plus vouloir aimer cette publication ?"
fullView: "Plein écran" fullView: "Plein écran"
quitFullView: "Quitter le plein écran" quitFullView: "Quitter le plein écran"
addDescription: "Ajouter une description" addDescription: "Ajouter une description"
userPagePinTip: "Vous pouvez afficher des notes ici en sélectionnant l'option « Épingler\ userPagePinTip: "Vous pouvez afficher des notes ici en sélectionnant l'option « Épingler
\ au profil » dans le menu de chaque note." au profil » dans le menu de chaque note."
notSpecifiedMentionWarning: "Vous avez mentionné des utilisateur·rice·s qui ne font\ notSpecifiedMentionWarning: "Vous avez mentionné des utilisateur·rice·s qui ne font
\ pas partie de la liste des destinataires" pas partie de la liste des destinataires"
info: "Informations" info: "Informations"
userInfo: "Informations sur l'utilisateur" userInfo: "Informations sur l'utilisateur"
unknown: "Inconnu" unknown: "Inconnu"
onlineStatus: "Statut" onlineStatus: "Statut"
hideOnlineStatus: "Se rendre invisible" hideOnlineStatus: "Se rendre invisible"
hideOnlineStatusDescription: "Rendre votre statut invisible peut diminuer les performances\ hideOnlineStatusDescription: "Rendre votre statut invisible peut diminuer les performances
\ de certaines fonctionnalités, telles que la Recherche." de certaines fonctionnalités, telles que la Recherche."
online: "En ligne" online: "En ligne"
active: "Actif·ve" active: "Actif·ve"
offline: "Hors ligne" offline: "Hors ligne"
@ -853,9 +853,9 @@ emailNotConfiguredWarning: "Vous n'avez pas configuré d'adresse e-mail."
ratio: "Ratio" ratio: "Ratio"
previewNoteText: "Voir l'aperçu" previewNoteText: "Voir l'aperçu"
customCss: "CSS personnalisé" customCss: "CSS personnalisé"
customCssWarn: "Utilisez cette fonctionnalité uniquement si vous savez exactement\ customCssWarn: "Utilisez cette fonctionnalité uniquement si vous savez exactement
\ ce que vous faites. Une configuration inadaptée peut empêcher le client de s'exécuter\ ce que vous faites. Une configuration inadaptée peut empêcher le client de s'exécuter
\ normalement." normalement."
global: "Global" global: "Global"
squareAvatars: "Avatars carrés" squareAvatars: "Avatars carrés"
sent: "Envoyer" sent: "Envoyer"
@ -870,10 +870,10 @@ whatIsNew: "Voir les derniers changements"
translate: "Traduire" translate: "Traduire"
translatedFrom: "Traduit depuis {x}" translatedFrom: "Traduit depuis {x}"
accountDeletionInProgress: "La suppression de votre compte est en cours" accountDeletionInProgress: "La suppression de votre compte est en cours"
usernameInfo: "C'est un nom qui identifie votre compte sur l'instance de manière unique.\ usernameInfo: "C'est un nom qui identifie votre compte sur l'instance de manière unique.
\ Vous pouvez utiliser des lettres de l'alphabet (minuscules et majuscules), des\ Vous pouvez utiliser des lettres de l'alphabet (minuscules et majuscules), des chiffres
\ chiffres (de 0 à 9), ou bien le tiret « _ ». Vous ne pourrez pas modifier votre\ (de 0 à 9), ou bien le tiret « _ ». Vous ne pourrez pas modifier votre nom d'utilisateur·rice
\ nom d'utilisateur·rice par la suite." par la suite."
aiChanMode: "Mode Ai" aiChanMode: "Mode Ai"
keepCw: "Garder le CW" keepCw: "Garder le CW"
pubSub: "Comptes Pub/Sub" pubSub: "Comptes Pub/Sub"
@ -889,14 +889,14 @@ filter: "Filtre"
controlPanel: "Panneau de contrôle" controlPanel: "Panneau de contrôle"
manageAccounts: "Gérer les comptes" manageAccounts: "Gérer les comptes"
makeReactionsPublic: "Rendre les réactions publiques" makeReactionsPublic: "Rendre les réactions publiques"
makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos réactions données\ makeReactionsPublicDescription: "Ceci rendra la liste de toutes vos réactions données
\ publique." publique."
classic: "Classique" classic: "Classique"
muteThread: "Masquer cette discussion" muteThread: "Masquer cette discussion"
unmuteThread: "Ne plus masquer le fil" unmuteThread: "Ne plus masquer le fil"
ffVisibility: "Visibilité des abonnés/abonnements" ffVisibility: "Visibilité des abonnés/abonnements"
ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu\ ffVisibilityDescription: "Permet de configurer qui peut voir les personnes que tu
\ suis et les personnes qui te suivent." suis et les personnes qui te suivent."
continueThread: "Afficher la suite du fil" continueThread: "Afficher la suite du fil"
deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?" deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?"
incorrectPassword: "Le mot de passe est incorrect." incorrectPassword: "Le mot de passe est incorrect."
@ -904,11 +904,11 @@ voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
hide: "Masquer" hide: "Masquer"
leaveGroup: "Quitter le groupe" leaveGroup: "Quitter le groupe"
leaveGroupConfirm: "Êtes vous sûr de vouloir quitter \"{name}\" ?" leaveGroupConfirm: "Êtes vous sûr de vouloir quitter \"{name}\" ?"
useDrawerReactionPickerForMobile: "Afficher le sélecteur de réactions en tant que\ useDrawerReactionPickerForMobile: "Afficher le sélecteur de réactions en tant que
\ panneau sur mobile" panneau sur mobile"
welcomeBackWithName: "Heureux de vous revoir, {name}" welcomeBackWithName: "Heureux de vous revoir, {name}"
clickToFinishEmailVerification: "Veuillez cliquer sur [{ok}] afin de compléter la\ clickToFinishEmailVerification: "Veuillez cliquer sur [{ok}] afin de compléter la
\ vérification par courriel." vérification par courriel."
overridedDeviceKind: "Type dappareil" overridedDeviceKind: "Type dappareil"
smartphone: "Smartphone" smartphone: "Smartphone"
tablet: "Tablette" tablet: "Tablette"
@ -948,16 +948,16 @@ _ffVisibility:
_signup: _signup:
almostThere: "Bientôt fini" almostThere: "Bientôt fini"
emailAddressInfo: "Insérez votre adresse e-mail." emailAddressInfo: "Insérez votre adresse e-mail."
emailSent: "Un courriel de confirmation vient d'être envoyé à l'adresse que vous\ emailSent: "Un courriel de confirmation vient d'être envoyé à l'adresse que vous
\ avez renseignée ({email}). Cliquez sur le lien contenu dans le message pour\ avez renseignée ({email}). Cliquez sur le lien contenu dans le message pour terminer
\ terminer la création de votre compte." la création de votre compte."
_accountDelete: _accountDelete:
accountDelete: "Supprimer le compte" accountDelete: "Supprimer le compte"
mayTakeTime: "La suppression de compte nécessitant beaucoup de ressources, l'exécution\ mayTakeTime: "La suppression de compte nécessitant beaucoup de ressources, l'exécution
\ du processus peut prendre du temps, en fonction de la quantité de contenus que\ du processus peut prendre du temps, en fonction de la quantité de contenus que
\ vous avez créés et du nombre de fichiers que vous avez téléversés." vous avez créés et du nombre de fichiers que vous avez téléversés."
sendEmail: "Une fois la suppression de votre compte effectuée, un courriel sera\ sendEmail: "Une fois la suppression de votre compte effectuée, un courriel sera
\ envoyé à l'adresse que vous aviez enregistrée." envoyé à l'adresse que vous aviez enregistrée."
requestAccountDelete: "Demander la suppression de votre compte" requestAccountDelete: "Demander la suppression de votre compte"
started: "La procédure de suppression a commencé." started: "La procédure de suppression a commencé."
inProgress: "Suppression en cours" inProgress: "Suppression en cours"
@ -965,14 +965,14 @@ _ad:
back: "Retour" back: "Retour"
reduceFrequencyOfThisAd: "Voir cette publicité moins souvent" reduceFrequencyOfThisAd: "Voir cette publicité moins souvent"
_forgotPassword: _forgotPassword:
enterEmail: "Entrez ici l'adresse e-mail que vous avez enregistrée pour votre compte.\ enterEmail: "Entrez ici l'adresse e-mail que vous avez enregistrée pour votre compte.
\ Un lien vous permettant de réinitialiser votre mot de passe sera envoyé à cette\ Un lien vous permettant de réinitialiser votre mot de passe sera envoyé à cette
\ adresse." adresse."
ifNoEmail: "Si vous n'avez pas enregistré d'adresse e-mail, merci de contacter l'administrateur·rice\ ifNoEmail: "Si vous n'avez pas enregistré d'adresse e-mail, merci de contacter l'administrateur·rice
\ de votre instance." de votre instance."
contactAdmin: "Cette instance ne permettant pas l'utilisation d'adresses e-mail,\ contactAdmin: "Cette instance ne permettant pas l'utilisation d'adresses e-mail,
\ prenez contact avec l'administrateur·rice pour procéder à la réinitialisation\ prenez contact avec l'administrateur·rice pour procéder à la réinitialisation
\ de votre mot de passe." de votre mot de passe."
_gallery: _gallery:
my: "Mes publications" my: "Mes publications"
liked: " Publications que j'ai aimées" liked: " Publications que j'ai aimées"
@ -1000,8 +1000,8 @@ _aboutMisskey:
source: "Code source" source: "Code source"
translation: "Traduire Calckey" translation: "Traduire Calckey"
donate: "Soutenir Calckey" donate: "Soutenir Calckey"
morePatrons: "Nous apprécions vraiment le soutien de nombreuses autres personnes\ morePatrons: "Nous apprécions vraiment le soutien de nombreuses autres personnes
\ non mentionnées ici. Merci à toutes et à tous ! \U0001F970" non mentionnées ici. Merci à toutes et à tous ! 🥰"
patrons: "Contributeurs" patrons: "Contributeurs"
_nsfw: _nsfw:
respect: "Cacher les médias marqués comme contenu sensible" respect: "Cacher les médias marqués comme contenu sensible"
@ -1009,22 +1009,22 @@ _nsfw:
force: "Cacher tous les médias" force: "Cacher tous les médias"
_mfm: _mfm:
cheatSheet: "Antisèche MFM" cheatSheet: "Antisèche MFM"
intro: "MFM est un langage Markdown spécifique utilisable ici et là dans Calckey.\ intro: "MFM est un langage Markdown spécifique utilisable ici et là dans Calckey.
\ Vous pouvez vérifier ici les structures utilisables avec MFM." Vous pouvez vérifier ici les structures utilisables avec MFM."
dummy: "La Fédiverse s'agrandit avec Calckey" dummy: "La Fédiverse s'agrandit avec Calckey"
mention: "Mentionner" mention: "Mentionner"
mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant\ mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant
\ une arobase suivie d'un nom d'utilisateur" une arobase suivie d'un nom d'utilisateur"
hashtag: "Hashtags" hashtag: "Hashtags"
hashtagDescription: "Vous pouvez afficher un mot-dièse en utilisant un croisillon\ hashtagDescription: "Vous pouvez afficher un mot-dièse en utilisant un croisillon
\ et du texte" et du texte"
url: "URL" url: "URL"
urlDescription: "L'adresse web peut être affichée." urlDescription: "L'adresse web peut être affichée."
link: "Lien" link: "Lien"
linkDescription: "Une partie précise d'une phrase peut être liée à l'adresse web." linkDescription: "Une partie précise d'une phrase peut être liée à l'adresse web."
bold: "Gras" bold: "Gras"
boldDescription: "Il est possible de mettre le texte en exergue en le mettant en\ boldDescription: "Il est possible de mettre le texte en exergue en le mettant en
\ gras." gras."
small: "Diminuer l'emphase" small: "Diminuer l'emphase"
smallDescription: "Le contenu peut être affiché en petit et fin." smallDescription: "Le contenu peut être affiché en petit et fin."
center: "Centrer" center: "Centrer"
@ -1036,8 +1036,8 @@ _mfm:
inlineMath: "Formule mathématique (inline)" inlineMath: "Formule mathématique (inline)"
inlineMathDescription: "Afficher les formules mathématiques (KaTeX)." inlineMathDescription: "Afficher les formules mathématiques (KaTeX)."
blockMath: "Formule mathématique (bloc)" blockMath: "Formule mathématique (bloc)"
blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes\ blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes
\ dans un bloc." dans un bloc."
quote: "Citer" quote: "Citer"
quoteDescription: "Affiche le contenu sous forme de citation." quoteDescription: "Affiche le contenu sous forme de citation."
emoji: "Émojis personnalisés" emoji: "Émojis personnalisés"
@ -1067,8 +1067,8 @@ _mfm:
x4: "Plus grand" x4: "Plus grand"
x4Description: "Afficher le contenu en plus grand." x4Description: "Afficher le contenu en plus grand."
blur: "Flou" blur: "Flou"
blurDescription: "Le contenu peut être flouté ; il sera visible en le survolant\ blurDescription: "Le contenu peut être flouté ; il sera visible en le survolant
\ avec le curseur." avec le curseur."
font: "Police de caractères" font: "Police de caractères"
fontDescription: "Il est possible de choisir la police." fontDescription: "Il est possible de choisir la police."
rainbow: "Arc-en-ciel" rainbow: "Arc-en-ciel"
@ -1109,14 +1109,14 @@ _menuDisplay:
hide: "Masquer" hide: "Masquer"
_wordMute: _wordMute:
muteWords: "Mots à filtrer" muteWords: "Mots à filtrer"
muteWordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec\ muteWordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec
\ un saut de ligne pour une condition OR." un saut de ligne pour une condition OR."
muteWordsDescription2: "Pour utiliser des expressions régulières (regex), mettez\ muteWordsDescription2: "Pour utiliser des expressions régulières (regex), mettez
\ les mots-clés entre barres obliques." les mots-clés entre barres obliques."
softDescription: "Masquez les notes de votre fil selon les paramètres que vous définissez." softDescription: "Masquez les notes de votre fil selon les paramètres que vous définissez."
hardDescription: "Empêchez votre fil de charger les notes selon les paramètres que\ hardDescription: "Empêchez votre fil de charger les notes selon les paramètres que
\ vous définissez. Cette action est irréversible : si vous modifiez ces paramètres\ vous définissez. Cette action est irréversible : si vous modifiez ces paramètres
\ plus tard, les notes précédemment filtrées ne seront pas récupérées." plus tard, les notes précédemment filtrées ne seront pas récupérées."
soft: "Doux" soft: "Doux"
hard: "Strict" hard: "Strict"
mutedNotes: "Notes filtrées" mutedNotes: "Notes filtrées"
@ -1155,10 +1155,10 @@ _theme:
darken: "Sombre" darken: "Sombre"
lighten: "Clair" lighten: "Clair"
inputConstantName: "Insérez un nom de constante" inputConstantName: "Insérez un nom de constante"
importInfo: "Vous pouvez importer un thème vers léditeur de thèmes en saisissant\ importInfo: "Vous pouvez importer un thème vers léditeur de thèmes en saisissant
\ son code ici." son code ici."
deleteConstantConfirm: "Êtes-vous sûr·e de vouloir supprimer la constante {const}\ deleteConstantConfirm: "Êtes-vous sûr·e de vouloir supprimer la constante {const}
\ ?" ?"
keys: keys:
accent: "Accentuation" accent: "Accentuation"
bg: "Arrière-plan" bg: "Arrière-plan"
@ -1231,51 +1231,51 @@ _tutorial:
step1_1: "Bienvenue!" step1_1: "Bienvenue!"
step1_2: "On va vous installer. Vous serez opérationnel en un rien de temps" step1_2: "On va vous installer. Vous serez opérationnel en un rien de temps"
step2_1: "Tout d'abord, remplissez votre profil" step2_1: "Tout d'abord, remplissez votre profil"
step2_2: "En fournissant quelques informations sur qui vous êtes, il sera plus facile\ step2_2: "En fournissant quelques informations sur qui vous êtes, il sera plus facile
\ pour les autres de savoir s'ils veulent voir vos notes ou vous suivre." pour les autres de savoir s'ils veulent voir vos notes ou vous suivre."
step3_1: "Maintenant il est temps de suivre des gens !" step3_1: "Maintenant il est temps de suivre des gens !"
step3_2: "Votre page d'accueil et vos timelines sociales sont basées sur les personnes\ step3_2: "Votre page d'accueil et vos timelines sociales sont basées sur les personnes
\ que vous suivez, alors essayez de suivre quelques comptes pour commencer.\n\ que vous suivez, alors essayez de suivre quelques comptes pour commencer.\nCliquez
Cliquez sur le cercle plus en haut à droite d'un profil pour le suivre." sur le cercle plus en haut à droite d'un profil pour le suivre."
step4_1: "On y va." step4_1: "On y va."
step4_2: "Pour votre premier post, certaines personnes aiment faire un post {introduction}\ step4_2: "Pour votre premier post, certaines personnes aiment faire un post {introduction}
\ ou un simple post 'Hello world'." ou un simple post 'Hello world'."
step5_1: "Lignes de temps, lignes de temps partout !" step5_1: "Lignes de temps, lignes de temps partout !"
step5_2: "Votre instance a {timelines} différentes chronologies activées !" step5_2: "Votre instance a {timelines} différentes chronologies activées !"
step5_3: "La timeline Home {icon} est l'endroit où vous pouvez voir les publications\ step5_3: "La timeline Home {icon} est l'endroit où vous pouvez voir les publications
\ de vos followers." de vos followers."
step5_4: "La timeline locale {icon} est l'endroit où vous pouvez voir les messages\ step5_4: "La timeline locale {icon} est l'endroit où vous pouvez voir les messages
\ de tout le monde sur cette instance." de tout le monde sur cette instance."
step5_5: "La chronologie {icon} sociale est l'endroit où vous pouvez voir uniquement\ step5_5: "La chronologie {icon} sociale est l'endroit où vous pouvez voir uniquement
\ les publications des comptes que vous suivez." les publications des comptes que vous suivez."
step5_6: "La chronologie {icon} recommandée est l'endroit où vous pouvez voir les\ step5_6: "La chronologie {icon} recommandée est l'endroit où vous pouvez voir les
\ publications des instances recommandées par les administrateurs." publications des instances recommandées par les administrateurs."
step5_7: "La timeline globale {icon} est l'endroit où vous pouvez voir les messages\ step5_7: "La timeline globale {icon} est l'endroit où vous pouvez voir les messages
\ de toutes les autres instances connectées." de toutes les autres instances connectées."
step6_1: "Alors quel est cet endroit ?" step6_1: "Alors quel est cet endroit ?"
step6_2: "Eh bien, vous ne venez pas de rejoindre Calckey. Vous avez rejoint un\ step6_2: "Eh bien, vous ne venez pas de rejoindre Calckey. Vous avez rejoint un
\ portail vers le Fediverse, un réseau interconnecté de milliers de serveurs,\ portail vers le Fediverse, un réseau interconnecté de milliers de serveurs, appelés
\ appelés \"instances\"." \"instances\"."
step6_3: "Chaque serveur fonctionne différemment, et tous les serveurs n'utilisent\ step6_3: "Chaque serveur fonctionne différemment, et tous les serveurs n'utilisent
\ pas Calckey. Cependant, celui-ci le fait ! C'est un peu délicat, mais vous aurez\ pas Calckey. Cependant, celui-ci le fait ! C'est un peu délicat, mais vous aurez
\ le coup de main en un rien de temps." le coup de main en un rien de temps."
step6_4: "Maintenant, allez-y, explorez et amusez-vous !" step6_4: "Maintenant, allez-y, explorez et amusez-vous !"
_2fa: _2fa:
alreadyRegistered: "Configuration déjà achevée." alreadyRegistered: "Configuration déjà achevée."
registerTOTP: "Ajouter un nouvel appareil" registerTOTP: "Ajouter un nouvel appareil"
registerSecurityKey: "Enregistrer une clef" registerSecurityKey: "Enregistrer une clef"
step1: "Tout d'abord, installez une application d'authentification, telle que {a}\ step1: "Tout d'abord, installez une application d'authentification, telle que {a}
\ ou {b}, sur votre appareil." ou {b}, sur votre appareil."
step2: "Ensuite, scannez le code QR affiché sur lécran." step2: "Ensuite, scannez le code QR affiché sur lécran."
step2Url: "Vous pouvez également saisir cette URL si vous utilisez un programme\ step2Url: "Vous pouvez également saisir cette URL si vous utilisez un programme
\ de bureau :" de bureau :"
step3: "Entrez le jeton affiché sur votre application pour compléter la configuration." step3: "Entrez le jeton affiché sur votre application pour compléter la configuration."
step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos\ step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos
\ connexions." connexions."
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser\ securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser
\ davantage le processus de connexion grâce à une clé de sécurité matérielle qui\ davantage le processus de connexion grâce à une clé de sécurité matérielle qui
\ prend en charge FIDO2, ou bien en configurant l'authentification par empreinte\ prend en charge FIDO2, ou bien en configurant l'authentification par empreinte
\ digitale ou par code PIN sur votre appareil." digitale ou par code PIN sur votre appareil."
_permissions: _permissions:
"read:account": "Afficher les informations du compte" "read:account": "Afficher les informations du compte"
"write:account": "Mettre à jour les informations de votre compte" "write:account": "Mettre à jour les informations de votre compte"
@ -1311,8 +1311,8 @@ _permissions:
"write:gallery-likes": "Gérer les mentions « J'aime » dans la galerie" "write:gallery-likes": "Gérer les mentions « J'aime » dans la galerie"
_auth: _auth:
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?" shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre\ shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre
\ compte?" compte?"
permissionAsk: "Cette application nécessite les autorisations suivantes :" permissionAsk: "Cette application nécessite les autorisations suivantes :"
pleaseGoBack: "Veuillez retourner à lapplication" pleaseGoBack: "Veuillez retourner à lapplication"
callback: "Retour vers lapplication" callback: "Retour vers lapplication"
@ -1412,8 +1412,8 @@ _profile:
youCanIncludeHashtags: "Vous pouvez également inclure des hashtags." youCanIncludeHashtags: "Vous pouvez également inclure des hashtags."
metadata: "Informations supplémentaires" metadata: "Informations supplémentaires"
metadataEdit: "Éditer les informations supplémentaires" metadataEdit: "Éditer les informations supplémentaires"
metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires\ metadataDescription: "Vous pouvez afficher jusqu'à quatre informations supplémentaires
\ dans votre profil." dans votre profil."
metadataLabel: "Étiquette" metadataLabel: "Étiquette"
metadataContent: "Contenu" metadataContent: "Contenu"
changeAvatar: "Changer l'image de profil" changeAvatar: "Changer l'image de profil"
@ -1487,8 +1487,8 @@ _pages:
url: "URL de la page" url: "URL de la page"
summary: "Résumé de page" summary: "Résumé de page"
alignCenter: "Centrée" alignCenter: "Centrée"
hideTitleWhenPinned: "Masquer le titre de la page lorsque celle-ci est épinglée\ hideTitleWhenPinned: "Masquer le titre de la page lorsque celle-ci est épinglée
\ au profil" au profil"
font: "Police de caractères" font: "Police de caractères"
fontSerif: "Serif" fontSerif: "Serif"
fontSansSerif: "Sans Serif" fontSansSerif: "Sans Serif"
@ -1538,8 +1538,8 @@ _pages:
note: "Note intégrée" note: "Note intégrée"
_note: _note:
id: "Identifiant de la note" id: "Identifiant de la note"
idDescription: "Pour configurer la note, vous pouvez aussi coller ici l'URL\ idDescription: "Pour configurer la note, vous pouvez aussi coller ici l'URL
\ correspondante." correspondante."
detailed: "Afficher les détails" detailed: "Afficher les détails"
switch: "Interrupteur" switch: "Interrupteur"
_switch: _switch:
@ -1692,8 +1692,8 @@ _pages:
_dailyRannum: _dailyRannum:
arg1: "Minimum" arg1: "Minimum"
arg2: "Maximum" arg2: "Maximum"
dailyRandomPick: "Sélectionné au hasard dans la liste (Quotidien pour chaque\ dailyRandomPick: "Sélectionné au hasard dans la liste (Quotidien pour chaque
\ utilisateur)" utilisateur)"
_dailyRandomPick: _dailyRandomPick:
arg1: "Listes" arg1: "Listes"
seedRandom: "Aléatoire (graine)" seedRandom: "Aléatoire (graine)"
@ -1709,8 +1709,8 @@ _pages:
_seedRandomPick: _seedRandomPick:
arg1: "Graine" arg1: "Graine"
arg2: "Listes" arg2: "Listes"
DRPWPM: "Sélectionné au hasard dans une liste de probabilités (Quotidien pour\ DRPWPM: "Sélectionné au hasard dans une liste de probabilités (Quotidien pour
\ chaque utilisateur)" chaque utilisateur)"
_DRPWPM: _DRPWPM:
arg1: "Liste de texte" arg1: "Liste de texte"
pick: "Sélectionner dans la liste" pick: "Sélectionner dans la liste"
@ -1889,10 +1889,10 @@ adminCustomCssWarn: Ce paramètre ne devrait être utilisé que si vous savez ce
dans vos paramètres utilisateur. dans vos paramètres utilisateur.
swipeOnDesktop: Permettre le style de glissement de fenêtre de mobile sur PC swipeOnDesktop: Permettre le style de glissement de fenêtre de mobile sur PC
moveFromLabel: 'Compte depuis lequel vous migrez :' moveFromLabel: 'Compte depuis lequel vous migrez :'
migrationConfirm: "Êtes-vous absolument certain⋅e que vous voulez migrer votre compte\ migrationConfirm: "Êtes-vous absolument certain⋅e que vous voulez migrer votre compte
\ vers {account} ? Une fois fait, vous ne pourrez pas revenir en arrière, et vous\ vers {account} ? Une fois fait, vous ne pourrez pas revenir en arrière, et vous
\ ne pourrez plus utiliser le compte actuel normalement à nouveau.\nAussi, assurez-vous\ ne pourrez plus utiliser le compte actuel normalement à nouveau.\nAussi, assurez-vous
\ d'avoir configuré le compte actuel comme le compte depuis lequel vous migrez." d'avoir configuré le compte actuel comme le compte depuis lequel vous migrez."
_preferencesBackups: _preferencesBackups:
updatedAt: 'Mis à jour le : {date} {time}' updatedAt: 'Mis à jour le : {date} {time}'
cannotLoad: Le chargement a échoué cannotLoad: Le chargement a échoué
@ -1934,8 +1934,8 @@ enterSendsMessage: Appuyer sur Entrée pendant la rédaction pour envoyer le mes
allowedInstancesDescription: Hôtes des instances autorisées pour la fédération, chacun allowedInstancesDescription: Hôtes des instances autorisées pour la fédération, chacun
séparé par une nouvelle ligne (s'applique uniquement en mode privé). séparé par une nouvelle ligne (s'applique uniquement en mode privé).
enableAutoSensitive: Marquage automatique du contenu sensible (NSFW) enableAutoSensitive: Marquage automatique du contenu sensible (NSFW)
regexpErrorDescription: "Il y a eu une erreur dans l'expression régulière à la ligne\ regexpErrorDescription: "Il y a eu une erreur dans l'expression régulière à la ligne
\ {line} de votre {tab} des mots masqués:" {line} de votre {tab} des mots masqués:"
forwardReportIsAnonymous: À la place de votre compte, un compte système anonyme sera forwardReportIsAnonymous: À la place de votre compte, un compte système anonyme sera
affiché comme rapporteur à l'instance distante. affiché comme rapporteur à l'instance distante.
noThankYou: Non merci noThankYou: Non merci
@ -1944,10 +1944,10 @@ renoteMute: Mettre en silence les renotes
flagSpeakAsCat: Parler comme un chat flagSpeakAsCat: Parler comme un chat
flagSpeakAsCatDescription: Vos messages seront nyanifiés en mode chat flagSpeakAsCatDescription: Vos messages seront nyanifiés en mode chat
hiddenTags: Hashtags cachés hiddenTags: Hashtags cachés
hiddenTagsDescription: "Lister les hashtags (sans le #) que vous souhaitez cacher\ hiddenTagsDescription: "Lister les hashtags (sans le #) que vous souhaitez cacher
\ de tendances et explorer. Les hashtags cachés sont toujours découvrables par d'autres\ de tendances et explorer. Les hashtags cachés sont toujours découvrables par d'autres
\ moyens. Les instances bloqués ne sont pas ne sont pas affectés, même si ils sont\ moyens. Les instances bloqués ne sont pas ne sont pas affectés, même si ils sont
\ présent dans cette liste." présent dans cette liste."
antennaInstancesDescription: Lister un hôte d'instance par ligne antennaInstancesDescription: Lister un hôte d'instance par ligne
userSaysSomethingReason: '{name} a dit {reason}' userSaysSomethingReason: '{name} a dit {reason}'
breakFollowConfirm: Êtes vous sur de vouloir retirer l'abonné ? breakFollowConfirm: Êtes vous sur de vouloir retirer l'abonné ?
@ -2005,17 +2005,16 @@ indexNotice: Indexation en cours. Cela prendra certainement du temps, veuillez n
customKaTeXMacro: Macros KaTeX personnalisées customKaTeXMacro: Macros KaTeX personnalisées
enableCustomKaTeXMacro: Activer les macros KaTeX personnalisées enableCustomKaTeXMacro: Activer les macros KaTeX personnalisées
noteId: ID de note noteId: ID de note
customKaTeXMacroDescription: "Définissez des macros pour écrire des expressions mathématiques\ customKaTeXMacroDescription: "Définissez des macros pour écrire des expressions mathématiques
\ simplement ! La notation se conforme aux définitions de commandes LaTeX et s'écrit\ simplement ! La notation se conforme aux définitions de commandes LaTeX et s'écrit
\ \\newcommand{\\name}{content} ou \\newcommand{\\name}[number of arguments]{content}.\ \\newcommand{\\name}{content} ou \\newcommand{\\name}[number of arguments]{content}.
\ Par exemple, \\newcommand{\\add}[2]{#1 + #2} étendra \\add{3}{foo} en 3 + foo.\ Par exemple, \\newcommand{\\add}[2]{#1 + #2} étendra \\add{3}{foo} en 3 + foo. Les
\ Les accolades entourant le nom de la macro peuvent être changés pour des parenthèses\ accolades entourant le nom de la macro peuvent être changés pour des parenthèses
\ ou des crochets. Cela affectera les types de parenthèses utilisées pour les arguments.\ ou des crochets. Cela affectera les types de parenthèses utilisées pour les arguments.
\ Une (et une seule) macro peut être définie par ligne, et vous ne pouvez pas couper\ Une (et une seule) macro peut être définie par ligne, et vous ne pouvez pas couper
\ la ligne au milieu d'une définition. Les lignes invalides sont simplement ignorées.\ la ligne au milieu d'une définition. Les lignes invalides sont simplement ignorées.
\ Seulement de simples fonctions de substitution de chaines sont supportées; la\ Seulement de simples fonctions de substitution de chaines sont supportées; la syntaxe
\ syntaxe avancée, telle que la ramification conditionnelle, ne peut pas être utilisée\ avancée, telle que la ramification conditionnelle, ne peut pas être utilisée ici."
\ ici."
enableRecommendedTimeline: Activer la chronologie recommandée enableRecommendedTimeline: Activer la chronologie recommandée
silenceThisInstance: Ne plus montrer cet instance silenceThisInstance: Ne plus montrer cet instance
silencedInstances: Instances silencieuses silencedInstances: Instances silencieuses
@ -2038,3 +2037,4 @@ signupsDisabled: Les inscriptions sur ce serveur sont actuellement désactivés,
apps: Applications apps: Applications
userSaysSomethingReasonReply: '{noms} a répondu à une note contenant {raison}' userSaysSomethingReasonReply: '{noms} a répondu à une note contenant {raison}'
defaultValueIs: 'défaut: {valeur}' defaultValueIs: 'défaut: {valeur}'
searchPlaceholder: Recherchez sur Calckey

View file

@ -1108,9 +1108,9 @@ _wordMute:
muteWordsDescription2: "将关键字用斜线括起来表示正则表达式。" muteWordsDescription2: "将关键字用斜线括起来表示正则表达式。"
softDescription: "隐藏时间线中指定条件的帖子。" softDescription: "隐藏时间线中指定条件的帖子。"
hardDescription: "防止将具有指定条件的帖子添加到时间线。 即使您更改条件,原先未添加的帖文也会被排除在外。" hardDescription: "防止将具有指定条件的帖子添加到时间线。 即使您更改条件,原先未添加的帖文也会被排除在外。"
soft: "软屏蔽" soft: "软过滤"
hard: "硬屏蔽" hard: "硬过滤"
mutedNotes: "已静音的帖子" mutedNotes: "已过滤的帖子"
_instanceMute: _instanceMute:
instanceMuteDescription: "静音列出服务器中的所有帖子和转帖,包括服务器的用户回复。" instanceMuteDescription: "静音列出服务器中的所有帖子和转帖,包括服务器的用户回复。"
instanceMuteDescription2: "设置时用换行符来分隔" instanceMuteDescription2: "设置时用换行符来分隔"

View file

@ -1845,3 +1845,6 @@ selectChannel: 選擇一個頻道
newer: 較新 newer: 較新
older: 較舊 older: 較舊
jumpToPrevious: 跳到上一個 jumpToPrevious: 跳到上一個
removeReaction: 移除你的反應
listsDesc: 清單可以創建一個只有您指定用戶的時間線。 可以從時間線頁面訪問它們。
flagSpeakAsCatDescription: 在喵咪模式下你的貼文會被喵化ヾ(•ω•`)o

View file

@ -6,7 +6,7 @@
"type": "git", "type": "git",
"url": "https://codeberg.org/calckey/calckey.git" "url": "https://codeberg.org/calckey/calckey.git"
}, },
"packageManager": "pnpm@8.6.3", "packageManager": "pnpm@8.6.6",
"private": true, "private": true,
"scripts": { "scripts": {
"rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp", "rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp",
@ -44,6 +44,7 @@
"seedrandom": "^3.0.5" "seedrandom": "^3.0.5"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "18.11.18",
"@types/gulp": "4.0.10", "@types/gulp": "4.0.10",
"@types/gulp-rename": "2.0.1", "@types/gulp-rename": "2.0.1",
"chalk": "4.1.2", "chalk": "4.1.2",

View file

@ -7,3 +7,4 @@ This directory contains all of the packages Calckey uses.
- `client`: Web interface written in Vue3 and TypeScript - `client`: Web interface written in Vue3 and TypeScript
- `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript
- `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use - `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use
- `megalodon`: TypeScript library used for Mastodon compatibility

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View file

@ -13,7 +13,6 @@ pub enum IdConvertType {
#[napi] #[napi]
pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> { pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> {
println!("converting id: {}", in_id);
use IdConvertType::*; use IdConvertType::*;
match id_convert_type { match id_convert_type {
MastodonId => { MastodonId => {

View file

@ -28,7 +28,7 @@
"@bull-board/api": "5.2.0", "@bull-board/api": "5.2.0",
"@bull-board/koa": "5.2.0", "@bull-board/koa": "5.2.0",
"@bull-board/ui": "5.2.0", "@bull-board/ui": "5.2.0",
"@calckey/megalodon": "5.2.0", "megalodon": "workspace:*",
"@discordapp/twemoji": "14.1.2", "@discordapp/twemoji": "14.1.2",
"@elastic/elasticsearch": "7.17.0", "@elastic/elasticsearch": "7.17.0",
"@koa/cors": "3.4.3", "@koa/cors": "3.4.3",

View file

@ -37,7 +37,7 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
if (!signature?.keyId) { if (!signature?.keyId) {
const err = `Invalid signature: ${signature}`; const err = `Invalid signature: ${signature}`;
job.moveToFailed({message: err}); job.moveToFailed({ message: err });
return err; return err;
} }
//#endregion //#endregion

View file

@ -1,5 +1,11 @@
import define from "../define.js"; import define from "../define.js";
import { redisClient } from "@/db/redis.js"; import { redisClient } from "@/db/redis.js";
import * as fs from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
export const meta = { export const meta = {
tags: ["meta"], tags: ["meta"],
@ -35,7 +41,10 @@ export default define(meta, paramDef, async (ps) => {
) )
.then((response) => response.json()) .then((response) => response.json())
.catch(() => { .catch(() => {
patrons = cachedPatrons ? JSON.parse(cachedPatrons) : []; const staticPatrons = JSON.parse(
fs.readFileSync(`${_dirname}/../../../../../../patrons.json`, "utf-8"),
);
patrons = cachedPatrons ? JSON.parse(cachedPatrons) : staticPatrons;
}); });
await redisClient.set("patrons", JSON.stringify(patrons), "EX", 3600); await redisClient.set("patrons", JSON.stringify(patrons), "EX", 3600);
} }

View file

@ -1,5 +1,5 @@
import Router from "@koa/router"; import Router from "@koa/router";
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import { apiAuthMastodon } from "./endpoints/auth.js"; import { apiAuthMastodon } from "./endpoints/auth.js";
import { apiAccountMastodon } from "./endpoints/account.js"; import { apiAccountMastodon } from "./endpoints/account.js";
import { apiStatusMastodon } from "./endpoints/status.js"; import { apiStatusMastodon } from "./endpoints/status.js";
@ -18,11 +18,7 @@ export function getClient(
const accessTokenArr = authorization?.split(" ") ?? [null]; const accessTokenArr = authorization?.split(" ") ?? [null];
const accessToken = accessTokenArr[accessTokenArr.length - 1]; const accessToken = accessTokenArr[accessTokenArr.length - 1];
const generator = (megalodon as any).default; const generator = (megalodon as any).default;
const client = generator( const client = generator(BASE_URL, accessToken) as MegalodonInterface;
"misskey",
BASE_URL,
accessToken,
) as MegalodonInterface;
return client; return client;
} }

View file

@ -1,4 +1,4 @@
import { Entity } from "@calckey/megalodon"; import { Entity } from "megalodon";
import { convertId, IdType } from "../index.js"; import { convertId, IdType } from "../index.js";
function simpleConvert(data: any) { function simpleConvert(data: any) {
@ -21,6 +21,9 @@ export function convertFilter(filter: Entity.Filter) {
export function convertList(list: Entity.List) { export function convertList(list: Entity.List) {
return simpleConvert(list); return simpleConvert(list);
} }
export function convertFeaturedTag(tag: Entity.FeaturedTag) {
return simpleConvert(tag);
}
export function convertNotification(notification: Entity.Notification) { export function convertNotification(notification: Entity.Notification) {
notification.account = convertAccount(notification.account); notification.account = convertAccount(notification.account);

View file

@ -7,6 +7,7 @@ import { argsToBools, convertTimelinesArgsId, limitToInt } from "./timeline.js";
import { convertId, IdType } from "../../index.js"; import { convertId, IdType } from "../../index.js";
import { import {
convertAccount, convertAccount,
convertFeaturedTag,
convertList, convertList,
convertRelationship, convertRelationship,
convertStatus, convertStatus,
@ -42,8 +43,8 @@ export function apiAccountMastodon(router: Router): void {
acct.url = `${BASE_URL}/@${acct.url}`; acct.url = `${BASE_URL}/@${acct.url}`;
acct.note = acct.note || ""; acct.note = acct.note || "";
acct.avatar_static = acct.avatar; acct.avatar_static = acct.avatar;
acct.header = acct.header || "https://http.cat/404"; acct.header = acct.header || "/static-assets/transparent.png";
acct.header_static = acct.header || "https://http.cat/404"; acct.header_static = acct.header || "/static-assets/transparent.png";
acct.source = { acct.source = {
note: acct.note, note: acct.note,
fields: acct.fields, fields: acct.fields,
@ -164,6 +165,25 @@ export function apiAccountMastodon(router: Router): void {
} }
}, },
); );
router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/featured_tags",
async (ctx) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getAccountFeaturedTags(
convertId(ctx.params.id, IdType.CalckeyId),
);
ctx.body = data.data.map((tag) => convertFeaturedTag(tag));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
ctx.status = 401;
ctx.body = e.response.data;
}
},
);
router.get<{ Params: { id: string } }>( router.get<{ Params: { id: string } }>(
"/v1/accounts/:id/followers", "/v1/accounts/:id/followers",
async (ctx) => { async (ctx) => {
@ -342,6 +362,34 @@ export function apiAccountMastodon(router: Router): void {
} }
}, },
); );
router.get("/v1/featured_tags", async (ctx) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getFeaturedTags();
ctx.body = data.data.map((tag) => convertFeaturedTag(tag));
} catch (e: any) {
console.error(e);
console.error(e.response.data);
ctx.status = 401;
ctx.body = e.response.data;
}
});
router.get("/v1/followed_tags", async (ctx) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getFollowedTags();
ctx.body = data.data;
} catch (e: any) {
console.error(e);
console.error(e.response.data);
ctx.status = 401;
ctx.body = e.response.data;
}
});
router.get("/v1/bookmarks", async (ctx) => { router.get("/v1/bookmarks", async (ctx) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization; const accessTokens = ctx.headers.authorization;

View file

@ -1,4 +1,4 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import Router from "@koa/router"; import Router from "@koa/router";
import { koaBody } from "koa-body"; import { koaBody } from "koa-body";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";

View file

@ -1,4 +1,4 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import Router from "@koa/router"; import Router from "@koa/router";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";
import { IdType, convertId } from "../../index.js"; import { IdType, convertId } from "../../index.js";

View file

@ -1,4 +1,4 @@
import { Entity } from "@calckey/megalodon"; import { Entity } from "megalodon";
import { fetchMeta } from "@/misc/fetch-meta.js"; import { fetchMeta } from "@/misc/fetch-meta.js";
import { Users, Notes } from "@/models/index.js"; import { Users, Notes } from "@/models/index.js";
import { IsNull, MoreThan } from "typeorm"; import { IsNull, MoreThan } from "typeorm";
@ -24,7 +24,7 @@ export async function getInstance(response: Entity.Instance) {
status_count: await totalStatuses, status_count: await totalStatuses,
domain_count: response.stats.domain_count, domain_count: response.stats.domain_count,
}, },
thumbnail: response.thumbnail || "https://http.cat/404", thumbnail: response.thumbnail || "/static-assets/transparent.png",
languages: meta.langs, languages: meta.langs,
registrations: !meta.disableRegistration || response.registrations, registrations: !meta.disableRegistration || response.registrations,
approval_required: !response.registrations, approval_required: !response.registrations,
@ -96,8 +96,8 @@ export async function getInstance(response: Entity.Instance) {
url: `${response.uri}/`, url: `${response.uri}/`,
avatar: `${response.uri}/static-assets/badges/info.png`, avatar: `${response.uri}/static-assets/badges/info.png`,
avatar_static: `${response.uri}/static-assets/badges/info.png`, avatar_static: `${response.uri}/static-assets/badges/info.png`,
header: "https://http.cat/404", header: "/static-assets/transparent.png",
header_static: "https://http.cat/404", header_static: "/static-assets/transparent.png",
followers_count: -1, followers_count: -1,
following_count: 0, following_count: 0,
statuses_count: 0, statuses_count: 0,

View file

@ -1,9 +1,9 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import Router from "@koa/router"; import Router from "@koa/router";
import { koaBody } from "koa-body"; import { koaBody } from "koa-body";
import { convertId, IdType } from "../../index.js"; import { convertId, IdType } from "../../index.js";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";
import { convertTimelinesArgsId, toTextWithReaction } from "./timeline.js"; import { convertTimelinesArgsId } from "./timeline.js";
import { convertNotification } from "../converters.js"; import { convertNotification } from "../converters.js";
function toLimitToInt(q: any) { function toLimitToInt(q: any) {
if (q.limit) if (typeof q.limit === "string") q.limit = parseInt(q.limit, 10); if (q.limit) if (typeof q.limit === "string") q.limit = parseInt(q.limit, 10);
@ -25,10 +25,6 @@ export function apiNotificationsMastodon(router: Router): void {
n = convertNotification(n); n = convertNotification(n);
if (n.type !== "follow" && n.type !== "follow_request") { if (n.type !== "follow" && n.type !== "follow_request") {
if (n.type === "reaction") n.type = "favourite"; if (n.type === "reaction") n.type = "favourite";
n.status = toTextWithReaction(
n.status ? [n.status] : [],
ctx.hostname,
)[0];
return n; return n;
} else { } else {
return n; return n;
@ -52,11 +48,13 @@ export function apiNotificationsMastodon(router: Router): void {
convertId(ctx.params.id, IdType.CalckeyId), convertId(ctx.params.id, IdType.CalckeyId),
); );
const data = convertNotification(dataRaw.data); const data = convertNotification(dataRaw.data);
if (data.type !== "follow" && data.type !== "follow_request") { ctx.body = data;
if (data.type === "reaction") data.type = "favourite"; if (
ctx.body = toTextWithReaction([data as any], ctx.request.hostname)[0]; data.type !== "follow" &&
} else { data.type !== "follow_request" &&
ctx.body = data; data.type === "reaction"
) {
data.type = "favourite";
} }
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);

View file

@ -1,8 +1,8 @@
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import Router from "@koa/router"; import Router from "@koa/router";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";
import axios from "axios"; import axios from "axios";
import { Converter } from "@calckey/megalodon"; import { Converter } from "megalodon";
import { convertTimelinesArgsId, limitToInt } from "./timeline.js"; import { convertTimelinesArgsId, limitToInt } from "./timeline.js";
import { convertAccount, convertStatus } from "../converters.js"; import { convertAccount, convertStatus } from "../converters.js";
@ -103,7 +103,7 @@ async function getHighlight(
i: accessToken, i: accessToken,
}); });
const data: MisskeyEntity.Note[] = api.data; const data: MisskeyEntity.Note[] = api.data;
return data.map((note) => Converter.note(note, domain)); return data.map((note) => new Converter(BASE_URL).note(note, domain));
} catch (e: any) { } catch (e: any) {
console.log(e); console.log(e);
console.log(e.response.data); console.log(e.response.data);
@ -131,7 +131,7 @@ async function getFeaturedUser(
return data.map((u) => { return data.map((u) => {
return { return {
source: "past_interactions", source: "past_interactions",
account: Converter.userDetail(u, host), account: new Converter(BASE_URL).userDetail(u, host),
}; };
}); });
} catch (e: any) { } catch (e: any) {

View file

@ -59,6 +59,11 @@ export function apiStatusMastodon(router: Router): void {
} }
if (!body.media_ids) body.media_ids = undefined; if (!body.media_ids) body.media_ids = undefined;
if (body.media_ids && !body.media_ids.length) body.media_ids = undefined; if (body.media_ids && !body.media_ids.length) body.media_ids = undefined;
if (body.media_ids) {
body.media_ids = (body.media_ids as string[]).map((p) =>
convertId(p, IdType.CalckeyId),
);
}
const { sensitive } = body; const { sensitive } = body;
body.sensitive = body.sensitive =
typeof sensitive === "string" ? sensitive === "true" : sensitive; typeof sensitive === "string" ? sensitive === "true" : sensitive;
@ -153,6 +158,24 @@ export function apiStatusMastodon(router: Router): void {
} }
}, },
); );
router.get<{ Params: { id: string } }>(
"/v1/statuses/:id/history",
async (ctx) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const data = await client.getStatusHistory(
convertId(ctx.params.id, IdType.CalckeyId),
);
ctx.body = data.data.map((account) => convertAccount(account));
} catch (e: any) {
console.error(e);
ctx.status = 401;
ctx.body = e.response.data;
}
},
);
router.get<{ Params: { id: string } }>( router.get<{ Params: { id: string } }>(
"/v1/statuses/:id/reblogged_by", "/v1/statuses/:id/reblogged_by",
async (ctx) => { async (ctx) => {
@ -431,8 +454,8 @@ export function statusModel(
const now = new Date().toISOString(); const now = new Date().toISOString();
return { return {
id: "9atm5frjhb", id: "9atm5frjhb",
uri: "https://http.cat/404", // "" uri: "/static-assets/transparent.png", // ""
url: "https://http.cat/404", // "", url: "/static-assets/transparent.png", // "",
account: { account: {
id: "9arzuvv0sw", id: "9arzuvv0sw",
username: "Reactions", username: "Reactions",
@ -444,11 +467,11 @@ export function statusModel(
following_count: 0, following_count: 0,
statuses_count: 0, statuses_count: 0,
note: "", note: "",
url: "https://http.cat/404", url: "/static-assets/transparent.png",
avatar: "/static-assets/badges/info.png", avatar: "/static-assets/badges/info.png",
avatar_static: "/static-assets/badges/info.png", avatar_static: "/static-assets/badges/info.png",
header: "https://http.cat/404", // "" header: "/static-assets/transparent.png", // ""
header_static: "https://http.cat/404", // "" header_static: "/static-assets/transparent.png", // ""
emojis: [], emojis: [],
fields: [], fields: [],
moved: null, moved: null,

View file

@ -1,8 +1,5 @@
import Router from "@koa/router"; import Router from "@koa/router";
import megalodon, { Entity, MegalodonInterface } from "@calckey/megalodon";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";
import { statusModel } from "./status.js";
import Autolinker from "autolinker";
import { ParsedUrlQuery } from "querystring"; import { ParsedUrlQuery } from "querystring";
import { convertAccount, convertList, convertStatus } from "../converters.js"; import { convertAccount, convertList, convertStatus } from "../converters.js";
import { convertId, IdType } from "../../index.js"; import { convertId, IdType } from "../../index.js";
@ -41,66 +38,6 @@ export function convertTimelinesArgsId(q: ParsedUrlQuery) {
return q; return q;
} }
export function toTextWithReaction(status: Entity.Status[], host: string) {
return status.map((t) => {
if (!t) return statusModel(null, null, [], "no content");
t.quote = null as any;
if (!t.emoji_reactions) return t;
if (t.reblog) t.reblog = toTextWithReaction([t.reblog], host)[0];
const reactions = t.emoji_reactions.map((r) => {
const emojiNotation = r.url ? `:${r.name.replace("@.", "")}:` : r.name;
return `${emojiNotation} (${r.count}${r.me ? `* ` : ""})`;
});
const reaction = t.emoji_reactions as Entity.Reaction[];
const emoji = t.emojis || [];
for (const r of reaction) {
if (!r.url) continue;
emoji.push({
shortcode: r.name,
url: r.url,
static_url: r.url,
visible_in_picker: true,
category: "",
});
}
const isMe = reaction.findIndex((r) => r.me) > -1;
const total = reaction.reduce((sum, reaction) => sum + reaction.count, 0);
t.favourited = isMe;
t.favourites_count = total;
t.emojis = emoji;
t.content = `<p>${autoLinker(t.content, host)}</p><p>${reactions.join(
", ",
)}</p>`;
return t;
});
}
export function autoLinker(input: string, host: string) {
return Autolinker.link(input, {
hashtag: "twitter",
mention: "twitter",
email: false,
stripPrefix: false,
replaceFn: function (match) {
switch (match.type) {
case "url":
return true;
case "mention":
console.log("Mention: ", match.getMention());
console.log("Mention Service Name: ", match.getServiceName());
return `<a href="https://${host}/@${encodeURIComponent(
match.getMention(),
)}" target="_blank">@${match.getMention()}</a>`;
case "hashtag":
console.log("Hashtag: ", match.getHashtag());
return `<a href="https://${host}/tags/${encodeURIComponent(
match.getHashtag(),
)}" target="_blank">#${match.getHashtag()}</a>`;
}
return false;
},
});
}
export function apiTimelineMastodon(router: Router): void { export function apiTimelineMastodon(router: Router): void {
router.get("/v1/timelines/public", async (ctx, reply) => { router.get("/v1/timelines/public", async (ctx, reply) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
@ -115,8 +52,7 @@ export function apiTimelineMastodon(router: Router): void {
: await client.getPublicTimeline( : await client.getPublicTimeline(
convertTimelinesArgsId(argsToBools(limitToInt(query))), convertTimelinesArgsId(argsToBools(limitToInt(query))),
); );
let resp = data.data.map((status) => convertStatus(status)); ctx.body = data.data.map((status) => convertStatus(status));
ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
console.error(e.response.data); console.error(e.response.data);
@ -135,8 +71,7 @@ export function apiTimelineMastodon(router: Router): void {
ctx.params.hashtag, ctx.params.hashtag,
convertTimelinesArgsId(argsToBools(limitToInt(ctx.query))), convertTimelinesArgsId(argsToBools(limitToInt(ctx.query))),
); );
let resp = data.data.map((status) => convertStatus(status)); ctx.body = data.data.map((status) => convertStatus(status));
ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
console.error(e.response.data); console.error(e.response.data);
@ -153,8 +88,7 @@ export function apiTimelineMastodon(router: Router): void {
const data = await client.getHomeTimeline( const data = await client.getHomeTimeline(
convertTimelinesArgsId(limitToInt(ctx.query)), convertTimelinesArgsId(limitToInt(ctx.query)),
); );
let resp = data.data.map((status) => convertStatus(status)); ctx.body = data.data.map((status) => convertStatus(status));
ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
console.error(e.response.data); console.error(e.response.data);
@ -173,8 +107,7 @@ export function apiTimelineMastodon(router: Router): void {
convertId(ctx.params.listId, IdType.CalckeyId), convertId(ctx.params.listId, IdType.CalckeyId),
convertTimelinesArgsId(limitToInt(ctx.query)), convertTimelinesArgsId(limitToInt(ctx.query)),
); );
let resp = data.data.map((status) => convertStatus(status)); ctx.body = data.data.map((status) => convertStatus(status));
ctx.body = toTextWithReaction(resp, ctx.hostname);
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
console.error(e.response.data); console.error(e.response.data);

View file

@ -25,9 +25,8 @@ import { readNotification } from "../common/read-notification.js";
import channels from "./channels/index.js"; import channels from "./channels/index.js";
import type Channel from "./channel.js"; import type Channel from "./channel.js";
import type { StreamEventEmitter, StreamMessages } from "./types.js"; import type { StreamEventEmitter, StreamMessages } from "./types.js";
import { Converter } from "@calckey/megalodon"; import { Converter } from "megalodon";
import { getClient } from "../mastodon/ApiMastodonCompatibleService.js"; import { getClient } from "../mastodon/ApiMastodonCompatibleService.js";
import { toTextWithReaction } from "../mastodon/endpoints/timeline.js";
/** /**
* Main stream connection * Main stream connection
@ -400,12 +399,7 @@ export default class Connection {
JSON.stringify({ JSON.stringify({
stream: [payload.id], stream: [payload.id],
event: "update", event: "update",
payload: JSON.stringify( payload: JSON.stringify(Converter.note(payload.body, this.host)),
toTextWithReaction(
[Converter.note(payload.body, this.host)],
this.host,
)[0],
),
}), }),
); );
this.onSubscribeNote({ this.onSubscribeNote({
@ -415,7 +409,7 @@ export default class Connection {
// reaction // reaction
const client = getClient(this.host, this.accessToken); const client = getClient(this.host, this.accessToken);
client.getStatus(payload.id).then((data) => { client.getStatus(payload.id).then((data) => {
const newPost = toTextWithReaction([data.data], this.host); const newPost = [data.data];
const targetPost = newPost[0]; const targetPost = newPost[0];
for (const stream of this.currentSubscribe) { for (const stream of this.currentSubscribe) {
this.wsConnection.send( this.wsConnection.send(
@ -442,10 +436,6 @@ export default class Connection {
if (payload.id === "user") { if (payload.id === "user") {
const body = Converter.notification(payload.body, this.host); const body = Converter.notification(payload.body, this.host);
if (body.type === "reaction") body.type = "favourite"; if (body.type === "reaction") body.type = "favourite";
body.status = toTextWithReaction(
body.status ? [body.status] : [],
"",
)[0];
this.wsConnection.send( this.wsConnection.send(
JSON.stringify({ JSON.stringify({
stream: ["user"], stream: ["user"],

View file

@ -22,7 +22,7 @@ import { createTemp } from "@/misc/create-temp.js";
import { publishMainStream } from "@/services/stream.js"; import { publishMainStream } from "@/services/stream.js";
import * as Acct from "@/misc/acct.js"; import * as Acct from "@/misc/acct.js";
import { envOption } from "@/env.js"; import { envOption } from "@/env.js";
import megalodon, { MegalodonInterface } from "@calckey/megalodon"; import megalodon, { MegalodonInterface } from "megalodon";
import activityPub from "./activitypub.js"; import activityPub from "./activitypub.js";
import nodeinfo from "./nodeinfo.js"; import nodeinfo from "./nodeinfo.js";
import wellKnown from "./well-known.js"; import wellKnown from "./well-known.js";
@ -166,7 +166,7 @@ mastoRouter.post("/oauth/token", async (ctx) => {
let client_id: any = body.client_id; let client_id: any = body.client_id;
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
const generator = (megalodon as any).default; const generator = (megalodon as any).default;
const client = generator("misskey", BASE_URL, null) as MegalodonInterface; const client = generator(BASE_URL, null) as MegalodonInterface;
let m = null; let m = null;
let token = null; let token = null;
if (body.code) { if (body.code) {

View file

@ -57,7 +57,7 @@
"matter-js": "0.18.0", "matter-js": "0.18.0",
"mfm-js": "0.23.3", "mfm-js": "0.23.3",
"photoswipe": "5.3.7", "photoswipe": "5.3.7",
"prettier": "2.8.8", "prettier": "3.0.0",
"prettier-plugin-vue": "1.1.6", "prettier-plugin-vue": "1.1.6",
"prismjs": "1.29.0", "prismjs": "1.29.0",
"punycode": "2.1.1", "punycode": "2.1.1",

View file

@ -67,7 +67,7 @@ function send() {
userId: props.user.id, userId: props.user.id,
comment: comment.value, comment: comment.value,
}, },
undefined undefined,
).then((res) => { ).then((res) => {
os.alert({ os.alert({
type: "success", type: "success",

View file

@ -19,7 +19,7 @@
0, 0,
1 - 1 -
angleDiff(hAngle, angle) / Math.PI - angleDiff(hAngle, angle) / Math.PI -
numbersOpacityFactor numbersOpacityFactor,
) )
" "
/> />
@ -48,7 +48,7 @@
0, 0,
1 - 1 -
angleDiff(hAngle, angle) / Math.PI - angleDiff(hAngle, angle) / Math.PI -
numbersOpacityFactor numbersOpacityFactor,
) )
" "
> >
@ -151,7 +151,7 @@ const props = withDefaults(
graduations: "dots", graduations: "dots",
fadeGraduations: true, fadeGraduations: true,
sAnimation: "elastic", sAnimation: "elastic",
} },
); );
const graduationsMajor = computed(() => { const graduationsMajor = computed(() => {
@ -192,7 +192,7 @@ let sOneRound = false;
function tick() { function tick() {
const now = new Date(); const now = new Date();
now.setMinutes( now.setMinutes(
now.getMinutes() + (new Date().getTimezoneOffset() + props.offset) now.getMinutes() + (new Date().getTimezoneOffset() + props.offset),
); );
s = now.getSeconds(); s = now.getSeconds();
m = now.getMinutes(); m = now.getMinutes();
@ -225,7 +225,7 @@ function calcColors() {
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(document.documentElement);
const dark = tinycolor(computedStyle.getPropertyValue("--bg")).isDark(); const dark = tinycolor(computedStyle.getPropertyValue("--bg")).isDark();
const accent = tinycolor( const accent = tinycolor(
computedStyle.getPropertyValue("--accent") computedStyle.getPropertyValue("--accent"),
).toHexString(); ).toHexString();
majorGraduationColor = dark majorGraduationColor = dark
? "rgba(255, 255, 255, 0.3)" ? "rgba(255, 255, 255, 0.3)"
@ -233,7 +233,7 @@ function calcColors() {
//minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; //minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
sHandColor = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)"; sHandColor = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)";
mHandColor = tinycolor( mHandColor = tinycolor(
computedStyle.getPropertyValue("--fg") computedStyle.getPropertyValue("--fg"),
).toHexString(); ).toHexString();
hHandColor = accent; hHandColor = accent;
nowColor = accent; nowColor = accent;

View file

@ -268,7 +268,7 @@ function exec() {
} else if (props.type === "hashtag") { } else if (props.type === "hashtag") {
if (!props.q || props.q === "") { if (!props.q || props.q === "") {
hashtags.value = JSON.parse( hashtags.value = JSON.parse(
localStorage.getItem("hashtags") || "[]" localStorage.getItem("hashtags") || "[]",
); );
fetching.value = false; fetching.value = false;
} else { } else {
@ -288,7 +288,7 @@ function exec() {
// //
sessionStorage.setItem( sessionStorage.setItem(
cacheKey, cacheKey,
JSON.stringify(searchedHashtags) JSON.stringify(searchedHashtags),
); );
}); });
} }
@ -298,7 +298,7 @@ function exec() {
// 使 // 使
emojis.value = defaultStore.state.recentlyUsedEmojis emojis.value = defaultStore.state.recentlyUsedEmojis
.map((emoji) => .map((emoji) =>
emojiDb.find((dbEmoji) => dbEmoji.emoji === emoji) emojiDb.find((dbEmoji) => dbEmoji.emoji === emoji),
) )
.filter((x) => x) as EmojiDef[]; .filter((x) => x) as EmojiDef[];
return; return;
@ -450,7 +450,7 @@ onMounted(() => {
nextTick(() => { nextTick(() => {
exec(); exec();
}); });
} },
); );
}); });
}); });
@ -470,7 +470,9 @@ onBeforeUnmount(() => {
max-width: 100%; max-width: 100%;
margin-top: calc(1em + 8px); margin-top: calc(1em + 8px);
overflow: hidden; overflow: hidden;
transition: top 0.1s ease, left 0.1s ease; transition:
top 0.1s ease,
left 0.1s ease;
> ol { > ol {
display: block; display: block;

View file

@ -90,7 +90,7 @@ function onMousedown(evt: MouseEvent): void {
target.clientWidth, target.clientWidth,
target.clientHeight, target.clientHeight,
circleCenterX, circleCenterX,
circleCenterY circleCenterY,
); );
window.setTimeout(() => { window.setTimeout(() => {

View file

@ -25,7 +25,7 @@ type Captcha = {
| "expired-callback" | "expired-callback"
| "error-callback" | "error-callback"
| "endpoint"]?: unknown; | "endpoint"]?: unknown;
} },
): string; ): string;
remove(id: string): void; remove(id: string): void;
execute(id: string): void; execute(id: string): void;
@ -78,7 +78,7 @@ const src = computed(() => {
}); });
const captcha = computed<Captcha>( const captcha = computed<Captcha>(
() => window[variable.value] || ({} as unknown as Captcha) () => window[variable.value] || ({} as unknown as Captcha),
); );
if (loaded) { if (loaded) {
@ -91,7 +91,7 @@ if (loaded) {
async: true, async: true,
id: props.provider, id: props.provider,
src: src.value, src: src.value,
}) }),
) )
).addEventListener("load", () => (available.value = true)); ).addEventListener("load", () => (available.value = true));
} }

View file

@ -34,7 +34,7 @@ const props = withDefaults(
}>(), }>(),
{ {
full: false, full: false,
} },
); );
const isFollowing = ref<boolean>(props.channel.isFollowing); const isFollowing = ref<boolean>(props.channel.isFollowing);

View file

@ -35,7 +35,7 @@ const props = withDefaults(
}>(), }>(),
{ {
extractor: (item) => item, extractor: (item) => item,
} },
); );
</script> </script>

View file

@ -91,7 +91,7 @@ Chart.register(
Tooltip, Tooltip,
SubTitle, SubTitle,
Filler, Filler,
zoomPlugin zoomPlugin,
//gradient, //gradient,
); );
@ -179,11 +179,11 @@ const render = () => {
// //
Chart.defaults.color = getComputedStyle( Chart.defaults.color = getComputedStyle(
document.documentElement document.documentElement,
).getPropertyValue("--fg"); ).getPropertyValue("--fg");
const maxes = chartData.series.map((x, i) => const maxes = chartData.series.map((x, i) =>
Math.max(...x.data.map((d) => d.y)) Math.max(...x.data.map((d) => d.y)),
); );
chartInstance = new Chart(chartEl.value, { chartInstance = new Chart(chartEl.value, {
@ -471,9 +471,9 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
raw.local.inc, raw.local.inc,
negate(raw.local.dec), negate(raw.local.dec),
raw.remote.inc, raw.remote.inc,
negate(raw.remote.dec) negate(raw.remote.dec),
) )
: sum(raw[type].inc, negate(raw[type].dec)) : sum(raw[type].inc, negate(raw[type].dec)),
), ),
color: "#888888", color: "#888888",
}, },
@ -483,7 +483,7 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
data: format( data: format(
type === "combined" type === "combined"
? sum(raw.local.diffs.renote, raw.remote.diffs.renote) ? sum(raw.local.diffs.renote, raw.remote.diffs.renote)
: raw[type].diffs.renote : raw[type].diffs.renote,
), ),
color: colors.green, color: colors.green,
}, },
@ -493,7 +493,7 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
data: format( data: format(
type === "combined" type === "combined"
? sum(raw.local.diffs.reply, raw.remote.diffs.reply) ? sum(raw.local.diffs.reply, raw.remote.diffs.reply)
: raw[type].diffs.reply : raw[type].diffs.reply,
), ),
color: colors.yellow, color: colors.yellow,
}, },
@ -503,7 +503,7 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
data: format( data: format(
type === "combined" type === "combined"
? sum(raw.local.diffs.normal, raw.remote.diffs.normal) ? sum(raw.local.diffs.normal, raw.remote.diffs.normal)
: raw[type].diffs.normal : raw[type].diffs.normal,
), ),
color: colors.blue, color: colors.blue,
}, },
@ -514,9 +514,9 @@ const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
type === "combined" type === "combined"
? sum( ? sum(
raw.local.diffs.withFile, raw.local.diffs.withFile,
raw.remote.diffs.withFile raw.remote.diffs.withFile,
) )
: raw[type].diffs.withFile : raw[type].diffs.withFile,
), ),
color: colors.purple, color: colors.purple,
}, },
@ -567,8 +567,8 @@ const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
raw.local.inc, raw.local.inc,
negate(raw.local.dec), negate(raw.local.dec),
raw.remote.inc, raw.remote.inc,
negate(raw.remote.dec) negate(raw.remote.dec),
) ),
), ),
}, },
{ {
@ -577,7 +577,7 @@ const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
data: format( data: format(
total total
? raw.local.total ? raw.local.total
: sum(raw.local.inc, negate(raw.local.dec)) : sum(raw.local.inc, negate(raw.local.dec)),
), ),
}, },
{ {
@ -586,7 +586,7 @@ const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
data: format( data: format(
total total
? raw.remote.total ? raw.remote.total
: sum(raw.remote.inc, negate(raw.remote.dec)) : sum(raw.remote.inc, negate(raw.remote.dec)),
), ),
}, },
], ],
@ -675,8 +675,8 @@ const fetchDriveChart = async (): Promise<typeof chartData> => {
raw.local.incSize, raw.local.incSize,
negate(raw.local.decSize), negate(raw.local.decSize),
raw.remote.incSize, raw.remote.incSize,
negate(raw.remote.decSize) negate(raw.remote.decSize),
) ),
), ),
}, },
{ {
@ -719,8 +719,8 @@ const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
raw.local.incCount, raw.local.incCount,
negate(raw.local.decCount), negate(raw.local.decCount),
raw.remote.incCount, raw.remote.incCount,
negate(raw.remote.decCount) negate(raw.remote.decCount),
) ),
), ),
}, },
{ {
@ -778,7 +778,7 @@ const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
}; };
const fetchInstanceUsersChart = async ( const fetchInstanceUsersChart = async (
total: boolean total: boolean,
): Promise<typeof chartData> => { ): Promise<typeof chartData> => {
const raw = await os.apiGet("charts/instance", { const raw = await os.apiGet("charts/instance", {
host: props.args.host, host: props.args.host,
@ -794,7 +794,7 @@ const fetchInstanceUsersChart = async (
data: format( data: format(
total total
? raw.users.total ? raw.users.total
: sum(raw.users.inc, negate(raw.users.dec)) : sum(raw.users.inc, negate(raw.users.dec)),
), ),
}, },
], ],
@ -802,7 +802,7 @@ const fetchInstanceUsersChart = async (
}; };
const fetchInstanceNotesChart = async ( const fetchInstanceNotesChart = async (
total: boolean total: boolean,
): Promise<typeof chartData> => { ): Promise<typeof chartData> => {
const raw = await os.apiGet("charts/instance", { const raw = await os.apiGet("charts/instance", {
host: props.args.host, host: props.args.host,
@ -818,7 +818,7 @@ const fetchInstanceNotesChart = async (
data: format( data: format(
total total
? raw.notes.total ? raw.notes.total
: sum(raw.notes.inc, negate(raw.notes.dec)) : sum(raw.notes.inc, negate(raw.notes.dec)),
), ),
}, },
], ],
@ -826,7 +826,7 @@ const fetchInstanceNotesChart = async (
}; };
const fetchInstanceFfChart = async ( const fetchInstanceFfChart = async (
total: boolean total: boolean,
): Promise<typeof chartData> => { ): Promise<typeof chartData> => {
const raw = await os.apiGet("charts/instance", { const raw = await os.apiGet("charts/instance", {
host: props.args.host, host: props.args.host,
@ -842,7 +842,7 @@ const fetchInstanceFfChart = async (
data: format( data: format(
total total
? raw.following.total ? raw.following.total
: sum(raw.following.inc, negate(raw.following.dec)) : sum(raw.following.inc, negate(raw.following.dec)),
), ),
}, },
{ {
@ -852,7 +852,7 @@ const fetchInstanceFfChart = async (
data: format( data: format(
total total
? raw.followers.total ? raw.followers.total
: sum(raw.followers.inc, negate(raw.followers.dec)) : sum(raw.followers.inc, negate(raw.followers.dec)),
), ),
}, },
], ],
@ -860,7 +860,7 @@ const fetchInstanceFfChart = async (
}; };
const fetchInstanceDriveUsageChart = async ( const fetchInstanceDriveUsageChart = async (
total: boolean total: boolean,
): Promise<typeof chartData> => { ): Promise<typeof chartData> => {
const raw = await os.apiGet("charts/instance", { const raw = await os.apiGet("charts/instance", {
host: props.args.host, host: props.args.host,
@ -877,7 +877,7 @@ const fetchInstanceDriveUsageChart = async (
data: format( data: format(
total total
? raw.drive.totalUsage ? raw.drive.totalUsage
: sum(raw.drive.incUsage, negate(raw.drive.decUsage)) : sum(raw.drive.incUsage, negate(raw.drive.decUsage)),
), ),
}, },
], ],
@ -885,7 +885,7 @@ const fetchInstanceDriveUsageChart = async (
}; };
const fetchInstanceDriveFilesChart = async ( const fetchInstanceDriveFilesChart = async (
total: boolean total: boolean,
): Promise<typeof chartData> => { ): Promise<typeof chartData> => {
const raw = await os.apiGet("charts/instance", { const raw = await os.apiGet("charts/instance", {
host: props.args.host, host: props.args.host,
@ -901,7 +901,7 @@ const fetchInstanceDriveFilesChart = async (
data: format( data: format(
total total
? raw.drive.totalFiles ? raw.drive.totalFiles
: sum(raw.drive.incFiles, negate(raw.drive.decFiles)) : sum(raw.drive.incFiles, negate(raw.drive.decFiles)),
), ),
}, },
], ],

View file

@ -11,7 +11,7 @@
message.groupId message.groupId
? `/my/messaging/group/${message.groupId}` ? `/my/messaging/group/${message.groupId}`
: `/my/messaging/${getAcct( : `/my/messaging/${getAcct(
isMe(message) ? message.recipient : message.user isMe(message) ? message.recipient : message.user,
)}` )}`
" "
> >

View file

@ -18,13 +18,13 @@ const props = defineProps<{
}>(); }>();
const prismLang = computed(() => const prismLang = computed(() =>
Prism.languages[props.lang] ? props.lang : "js" Prism.languages[props.lang] ? props.lang : "js",
); );
const html = computed(() => const html = computed(() =>
Prism.highlight( Prism.highlight(
props.code, props.code,
Prism.languages[prismLang.value], Prism.languages[prismLang.value],
prismLang.value prismLang.value,
) ),
); );
</script> </script>

View file

@ -12,6 +12,6 @@ defineProps<{
}>(); }>();
const XCode = defineAsyncComponent( const XCode = defineAsyncComponent(
() => import("@/components/MkCode.core.vue") () => import("@/components/MkCode.core.vue"),
); );
</script> </script>

View file

@ -125,7 +125,7 @@ export default defineComponent({
}, },
{ {
immediate: true, immediate: true,
} },
); );
this.$el.style.setProperty("--maxHeight", this.maxHeight + "px"); this.$el.style.setProperty("--maxHeight", this.maxHeight + "px");
@ -174,7 +174,9 @@ export default defineComponent({
.container-toggle-enter-active, .container-toggle-enter-active,
.container-toggle-leave-active { .container-toggle-leave-active {
overflow-y: hidden; overflow-y: hidden;
transition: opacity 0.5s, height 0.5s !important; transition:
opacity 0.5s,
height 0.5s !important;
} }
.container-toggle-enter-from { .container-toggle-enter-from {
opacity: 0; opacity: 0;

View file

@ -80,7 +80,8 @@ function onMousedown(evt: Event) {
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transition:
opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1),
transform 0.5s cubic-bezier(0.16, 1, 0.3, 1); transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
transform-origin: left top; transform-origin: left top;
} }

View file

@ -118,7 +118,7 @@ onMounted(() => {
const selection = cropper.getCropperSelection()!; const selection = cropper.getCropperSelection()!;
selection.themeColor = tinycolor( selection.themeColor = tinycolor(
computedStyle.getPropertyValue("--accent") computedStyle.getPropertyValue("--accent"),
).toHexString(); ).toHexString();
selection.aspectRatio = props.aspectRatio; selection.aspectRatio = props.aspectRatio;
selection.initialAspectRatio = props.aspectRatio; selection.initialAspectRatio = props.aspectRatio;

View file

@ -63,7 +63,9 @@ defineExpose({
> span { > span {
background: var(--cwBg) !important; background: var(--cwBg) !important;
color: var(--cwFg); color: var(--cwFg);
transition: background 0.2s, color 0.2s; transition:
background 0.2s,
color 0.2s;
> span { > span {
font-weight: 500; font-weight: 500;
&::before { &::before {

View file

@ -84,8 +84,8 @@ export default defineComponent({
class: "ph-caret-down ph-bold ph-lg icon", class: "ph-caret-down ph-bold ph-lg icon",
}), }),
]), ]),
] ],
) ),
); );
return [el, separator]; return [el, separator];
@ -119,7 +119,7 @@ export default defineComponent({
: { : {
class: "sqadhkmv" + (props.noGap ? " noGap" : ""), class: "sqadhkmv" + (props.noGap ? " noGap" : ""),
}, },
{ default: renderChildren } { default: renderChildren },
); );
}, },
}); });
@ -140,7 +140,8 @@ export default defineComponent({
} }
> .list-enter-active { > .list-enter-active {
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1), transition:
transform 0.7s cubic-bezier(0.23, 1, 0.32, 1),
opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1); opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1);
} }

View file

@ -78,14 +78,24 @@
okButtonDisabled && okButtonDisabled &&
disabledReason === 'charactersExceeded' disabledReason === 'charactersExceeded'
" "
v-text="i18n.t('_dialog.charactersExceeded', { current: (inputValue as string).length, max: input.maxLength ?? 'NaN' })" v-text="
i18n.t('_dialog.charactersExceeded', {
current: (inputValue as string).length,
max: input.maxLength ?? 'NaN',
})
"
/> />
<span <span
v-else-if=" v-else-if="
okButtonDisabled && okButtonDisabled &&
disabledReason === 'charactersBelow' disabledReason === 'charactersBelow'
" "
v-text="i18n.t('_dialog.charactersBelow', { current: (inputValue as string).length, min: input.minLength ?? 'NaN' })" v-text="
i18n.t('_dialog.charactersBelow', {
current: (inputValue as string).length,
min: input.minLength ?? 'NaN',
})
"
/> />
</template> </template>
<template v-if="input.type === 'search'" #suffix> <template v-if="input.type === 'search'" #suffix>
@ -258,7 +268,7 @@ const props = withDefaults(
isYesNo: false, isYesNo: false,
cancelableByBgClick: true, cancelableByBgClick: true,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -272,7 +282,7 @@ const inputValue = ref<string | number | null>(props.input?.default ?? null);
const selectedValue = ref(props.select?.default ?? null); const selectedValue = ref(props.select?.default ?? null);
let disabledReason = $ref<null | "charactersExceeded" | "charactersBelow">( let disabledReason = $ref<null | "charactersExceeded" | "charactersBelow">(
null null,
); );
const okButtonDisabled = $computed<boolean>(() => { const okButtonDisabled = $computed<boolean>(() => {
if (props.input) { if (props.input) {
@ -439,7 +449,7 @@ async function openSearchFilters(ev) {
}, },
], ],
ev.target, ev.target,
{ noReturnFocus: true } { noReturnFocus: true },
); );
inputEl.value.focus(); inputEl.value.focus();
inputEl.value.selectRange(inputValue.value.length, inputValue.value.length); // cursor at end inputEl.value.selectRange(inputValue.value.length, inputValue.value.length); // cursor at end

View file

@ -23,7 +23,7 @@ const props = withDefaults(
showS: true, showS: true,
showMs: false, showMs: false,
offset: 0 - new Date().getTimezoneOffset(), offset: 0 - new Date().getTimezoneOffset(),
} },
); );
let intervalId; let intervalId;
@ -45,7 +45,7 @@ watch(showColon, (v) => {
const tick = () => { const tick = () => {
const now = new Date(); const now = new Date();
now.setMinutes( now.setMinutes(
now.getMinutes() + (new Date().getTimezoneOffset() + props.offset) now.getMinutes() + (new Date().getTimezoneOffset() + props.offset),
); );
hh.value = now.getHours().toString().padStart(2, "0"); hh.value = now.getHours().toString().padStart(2, "0");
mm.value = now.getMinutes().toString().padStart(2, "0"); mm.value = now.getMinutes().toString().padStart(2, "0");
@ -65,7 +65,7 @@ watch(
if (intervalId) window.clearInterval(intervalId); if (intervalId) window.clearInterval(intervalId);
intervalId = window.setInterval(tick, props.showMs ? 10 : 1000); intervalId = window.setInterval(tick, props.showMs ? 10 : 1000);
}, },
{ immediate: true } { immediate: true },
); );
onUnmounted(() => { onUnmounted(() => {

View file

@ -56,7 +56,7 @@ const props = withDefaults(
{ {
isSelected: false, isSelected: false,
selectMode: false, selectMode: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -68,7 +68,7 @@ const emit = defineEmits<{
const isDragging = ref(false); const isDragging = ref(false);
const title = computed( const title = computed(
() => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}` () => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}`,
); );
function getMenu() { function getMenu() {
@ -124,7 +124,7 @@ function onClick(ev: MouseEvent) {
getMenu(), getMenu(),
(ev.currentTarget ?? ev.target ?? undefined) as (ev.currentTarget ?? ev.target ?? undefined) as
| HTMLElement | HTMLElement
| undefined | undefined,
); );
} }
} }
@ -138,7 +138,7 @@ function onDragstart(ev: DragEvent) {
ev.dataTransfer.effectAllowed = "move"; ev.dataTransfer.effectAllowed = "move";
ev.dataTransfer.setData( ev.dataTransfer.setData(
_DATA_TRANSFER_DRIVE_FILE_, _DATA_TRANSFER_DRIVE_FILE_,
JSON.stringify(props.file) JSON.stringify(props.file),
); );
} }
isDragging.value = true; isDragging.value = true;
@ -186,7 +186,7 @@ function describe() {
}); });
}, },
}, },
"closed" "closed",
); );
} }

View file

@ -52,7 +52,7 @@ const props = withDefaults(
{ {
isSelected: false, isSelected: false,
selectMode: false, selectMode: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -184,7 +184,7 @@ function onDragstart(ev: DragEvent) {
ev.dataTransfer.effectAllowed = "move"; ev.dataTransfer.effectAllowed = "move";
ev.dataTransfer.setData( ev.dataTransfer.setData(
_DATA_TRANSFER_DRIVE_FOLDER_, _DATA_TRANSFER_DRIVE_FOLDER_,
JSON.stringify(props.folder) JSON.stringify(props.folder),
); );
isDragging.value = true; isDragging.value = true;
@ -256,13 +256,13 @@ function onContextmenu(ev: MouseEvent) {
action: () => { action: () => {
os.popup( os.popup(
defineAsyncComponent( defineAsyncComponent(
() => import("@/components/MkDriveWindow.vue") () => import("@/components/MkDriveWindow.vue"),
), ),
{ {
initialFolder: props.folder, initialFolder: props.folder,
}, },
{}, {},
"closed" "closed",
); );
}, },
}, },
@ -280,7 +280,7 @@ function onContextmenu(ev: MouseEvent) {
action: deleteFolder, action: deleteFolder,
}, },
], ],
ev ev,
); );
} }
</script> </script>

View file

@ -29,7 +29,7 @@ const emit = defineEmits<{
( (
ev: "upload", ev: "upload",
file: File, file: File,
folder?: Misskey.entities.DriveFolder | null folder?: Misskey.entities.DriveFolder | null,
): void; ): void;
(ev: "removeFile", v: Misskey.entities.DriveFile["id"]): void; (ev: "removeFile", v: Misskey.entities.DriveFile["id"]): void;
(ev: "removeFolder", v: Misskey.entities.DriveFolder["id"]): void; (ev: "removeFolder", v: Misskey.entities.DriveFolder["id"]): void;

View file

@ -161,17 +161,17 @@ const props = withDefaults(
{ {
multiple: false, multiple: false,
select: null, select: null,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
( (
ev: "selected", ev: "selected",
v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder,
): void; ): void;
( (
ev: "change-selection", ev: "change-selection",
v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[] v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[],
): void; ): void;
(ev: "move-root"): void; (ev: "move-root"): void;
(ev: "cd", v: Misskey.entities.DriveFolder | null): void; (ev: "cd", v: Misskey.entities.DriveFolder | null): void;
@ -207,7 +207,7 @@ const ilFilesObserver = new IntersectionObserver(
entries.some((entry) => entry.isIntersecting) && entries.some((entry) => entry.isIntersecting) &&
!fetching.value && !fetching.value &&
moreFiles.value && moreFiles.value &&
fetchMoreFiles() fetchMoreFiles(),
); );
watch(folder, () => emit("cd", folder.value)); watch(folder, () => emit("cd", folder.value));
@ -230,13 +230,13 @@ function onStreamDriveFileDeleted(fileId: string) {
} }
function onStreamDriveFolderCreated( function onStreamDriveFolderCreated(
createdFolder: Misskey.entities.DriveFolder createdFolder: Misskey.entities.DriveFolder,
) { ) {
addFolder(createdFolder, true); addFolder(createdFolder, true);
} }
function onStreamDriveFolderUpdated( function onStreamDriveFolderUpdated(
updatedFolder: Misskey.entities.DriveFolder updatedFolder: Misskey.entities.DriveFolder,
) { ) {
const current = folder.value ? folder.value.id : null; const current = folder.value ? folder.value.id : null;
if (current !== updatedFolder.parentId) { if (current !== updatedFolder.parentId) {
@ -433,7 +433,7 @@ function onChangeFileInput() {
function upload( function upload(
file: File, file: File,
folderToUpload?: Misskey.entities.DriveFolder | null folderToUpload?: Misskey.entities.DriveFolder | null,
) { ) {
uploadFile( uploadFile(
file, file,
@ -441,7 +441,7 @@ function upload(
? folderToUpload.id ? folderToUpload.id
: null, : null,
undefined, undefined,
keepOriginal.value keepOriginal.value,
).then((res) => { ).then((res) => {
addFile(res, true); addFile(res, true);
}); });
@ -452,7 +452,7 @@ function chooseFile(file: Misskey.entities.DriveFile) {
if (props.multiple) { if (props.multiple) {
if (isAlreadySelected) { if (isAlreadySelected) {
selectedFiles.value = selectedFiles.value.filter( selectedFiles.value = selectedFiles.value.filter(
(f) => f.id !== file.id (f) => f.id !== file.id,
); );
} else { } else {
selectedFiles.value.push(file); selectedFiles.value.push(file);
@ -470,12 +470,12 @@ function chooseFile(file: Misskey.entities.DriveFile) {
function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) { function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
const isAlreadySelected = selectedFolders.value.some( const isAlreadySelected = selectedFolders.value.some(
(f) => f.id === folderToChoose.id (f) => f.id === folderToChoose.id,
); );
if (props.multiple) { if (props.multiple) {
if (isAlreadySelected) { if (isAlreadySelected) {
selectedFolders.value = selectedFolders.value.filter( selectedFolders.value = selectedFolders.value.filter(
(f) => f.id !== folderToChoose.id (f) => f.id !== folderToChoose.id,
); );
} else { } else {
selectedFolders.value.push(folderToChoose); selectedFolders.value.push(folderToChoose);
@ -707,7 +707,7 @@ function getMenu() {
icon: "ph-trash ph-bold ph-lg", icon: "ph-trash ph-bold ph-lg",
action: () => { action: () => {
deleteFolder( deleteFolder(
folder.value as Misskey.entities.DriveFolder folder.value as Misskey.entities.DriveFolder,
); );
}, },
} }
@ -725,7 +725,7 @@ function getMenu() {
function showMenu(ev: MouseEvent) { function showMenu(ev: MouseEvent) {
os.popupMenu( os.popupMenu(
getMenu(), getMenu(),
(ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined,
); );
} }

View file

@ -50,7 +50,7 @@ withDefaults(
}>(), }>(),
{ {
type: "file", type: "file",
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -16,7 +16,7 @@
class="_button" class="_button"
@click.stop=" @click.stop="
applyUnicodeSkinTone( applyUnicodeSkinTone(
props.skinTones.indexOf(skinTone) + 1 props.skinTones.indexOf(skinTone) + 1,
) )
" "
> >
@ -83,7 +83,7 @@ watch(
() => props.emojis, () => props.emojis,
(newVal) => { (newVal) => {
localEmojis.value = [...newVal]; localEmojis.value = [...newVal];
} },
); );
</script> </script>

View file

@ -191,7 +191,7 @@ const props = withDefaults(
}>(), }>(),
{ {
showPinned: true, showPinned: true,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -220,22 +220,22 @@ const unicodeEmojiSkinTones = [
]; ];
const unicodeEmojiSkinToneLabels = [ const unicodeEmojiSkinToneLabels = [
i18n.ts._skinTones.yellow, i18n.ts._skinTones?.yellow ?? "Yellow",
i18n.ts._skinTones.light, i18n.ts._skinTones?.light ?? "Light",
i18n.ts._skinTones.mediumLight, i18n.ts._skinTones?.mediumLight ?? "Medium Light",
i18n.ts._skinTones.medium, i18n.ts._skinTones?.medium ?? "Medium",
i18n.ts._skinTones.mediumDark, i18n.ts._skinTones?.mediumDark ?? "Medium Dark",
i18n.ts._skinTones.dark, i18n.ts._skinTones?.dark ?? "Dark",
]; ];
const size = computed(() => const size = computed(() =>
props.asReactionPicker ? reactionPickerSize.value : 1 props.asReactionPicker ? reactionPickerSize.value : 1,
); );
const width = computed(() => const width = computed(() =>
props.asReactionPicker ? reactionPickerWidth.value : 3 props.asReactionPicker ? reactionPickerWidth.value : 3,
); );
const height = computed(() => const height = computed(() =>
props.asReactionPicker ? reactionPickerHeight.value : 2 props.asReactionPicker ? reactionPickerHeight.value : 2,
); );
const customEmojiCategories = emojiCategories; const customEmojiCategories = emojiCategories;
const customEmojis = instance.emojis; const customEmojis = instance.emojis;
@ -283,8 +283,8 @@ watch(q, () => {
(keyword) => (keyword) =>
emoji.name.includes(keyword) || emoji.name.includes(keyword) ||
emoji.aliases.some((alias) => emoji.aliases.some((alias) =>
alias.includes(keyword) alias.includes(keyword),
) ),
) )
) { ) {
matches.add(emoji); matches.add(emoji);
@ -355,8 +355,8 @@ watch(q, () => {
(keyword) => (keyword) =>
emoji.slug.includes(keyword) || emoji.slug.includes(keyword) ||
emoji.keywords?.some((alias) => emoji.keywords?.some((alias) =>
alias.includes(keyword) alias.includes(keyword),
) ),
) )
) { ) {
matches.add(emoji); matches.add(emoji);
@ -419,7 +419,7 @@ function reset() {
} }
function getKey( function getKey(
emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef,
): string { ): string {
return typeof emoji === "string" ? emoji : emoji.emoji || `:${emoji.name}:`; return typeof emoji === "string" ? emoji : emoji.emoji || `:${emoji.name}:`;
} }
@ -465,7 +465,7 @@ function done(query?: any): boolean | void {
return true; return true;
} }
const exactMatchUnicode = emojilist.find( const exactMatchUnicode = emojilist.find(
(emoji) => emoji.emoji === q2 || emoji.slug === q2 (emoji) => emoji.emoji === q2 || emoji.slug === q2,
); );
if (exactMatchUnicode) { if (exactMatchUnicode) {
chosen(exactMatchUnicode); chosen(exactMatchUnicode);

View file

@ -47,7 +47,7 @@ withDefaults(
manualShowing: null, manualShowing: null,
showPinned: true, showPinned: true,
asReactionPicker: false, asReactionPicker: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -11,7 +11,7 @@
:key="file.id" :key="file.id"
v-tooltip.mfm=" v-tooltip.mfm="
`${file.type}\n${bytes(file.size)}\n${new Date( `${file.type}\n${bytes(file.size)}\n${new Date(
file.createdAt file.createdAt,
).toLocaleString()}\nby ${ ).toLocaleString()}\nby ${
file.user ? '@' + Acct.toString(file.user) : 'system' file.user ? '@' + Acct.toString(file.user) : 'system'
}` }`

View file

@ -56,7 +56,7 @@ export default defineComponent({
this.persistKey && this.persistKey &&
localStorage.getItem(localStoragePrefix + this.persistKey) localStorage.getItem(localStoragePrefix + this.persistKey)
? localStorage.getItem( ? localStorage.getItem(
localStoragePrefix + this.persistKey localStoragePrefix + this.persistKey,
) === "t" ) === "t"
: this.expanded, : this.expanded,
}; };
@ -66,7 +66,7 @@ export default defineComponent({
if (this.persistKey) { if (this.persistKey) {
localStorage.setItem( localStorage.setItem(
localStoragePrefix + this.persistKey, localStoragePrefix + this.persistKey,
this.showBody ? "t" : "f" this.showBody ? "t" : "f",
); );
} }
}, },
@ -85,9 +85,9 @@ export default defineComponent({
const bg = tinycolor( const bg = tinycolor(
rawBg.startsWith("var(") rawBg.startsWith("var(")
? getComputedStyle(document.documentElement).getPropertyValue( ? getComputedStyle(document.documentElement).getPropertyValue(
rawBg.slice(4, -1) rawBg.slice(4, -1),
) )
: rawBg : rawBg,
); );
bg.setAlpha(0.85); bg.setAlpha(0.85);
this.bg = bg.toRgbString(); this.bg = bg.toRgbString();
@ -123,7 +123,9 @@ export default defineComponent({
.folder-toggle-enter-active, .folder-toggle-enter-active,
.folder-toggle-leave-active { .folder-toggle-leave-active {
overflow-y: hidden; overflow-y: hidden;
transition: opacity 0.5s, height 0.5s !important; transition:
opacity 0.5s,
height 0.5s !important;
} }
.folder-toggle-enter-from { .folder-toggle-enter-from {
opacity: 0; opacity: 0;

View file

@ -83,7 +83,7 @@ const props = withDefaults(
{ {
full: false, full: false,
large: false, large: false,
} },
); );
const isBlocking = computed(() => props.user.isBlocking); const isBlocking = computed(() => props.user.isBlocking);
@ -92,7 +92,7 @@ let state = $ref(i18n.ts.processing);
let isFollowing = $ref(props.user.isFollowing); let isFollowing = $ref(props.user.isFollowing);
let hasPendingFollowRequestFromYou = $ref( let hasPendingFollowRequestFromYou = $ref(
props.user.hasPendingFollowRequestFromYou props.user.hasPendingFollowRequestFromYou,
); );
let wait = $ref(false); let wait = $ref(false);
const connection = stream.useChannel("main"); const connection = stream.useChannel("main");
@ -166,7 +166,7 @@ async function onClick() {
function menu(ev) { function menu(ev) {
os.popupMenu( os.popupMenu(
getUserMenu(props.user, router), getUserMenu(props.user, router),
ev.currentTarget ?? ev.target ev.currentTarget ?? ev.target,
); );
} }

View file

@ -18,7 +18,7 @@
<div class="xkpnjxcv _formRoot"> <div class="xkpnjxcv _formRoot">
<template <template
v-for="item in Object.keys(form).filter( v-for="item in Object.keys(form).filter(
(item) => !form[item].hidden (item) => !form[item].hidden,
)" )"
> >
<FormInput <FormInput

View file

@ -9,7 +9,7 @@ import * as os from "@/os";
export default defineComponent({ export default defineComponent({
components: { components: {
XFormula: defineAsyncComponent( XFormula: defineAsyncComponent(
() => import("@/components/MkFormulaCore.vue") () => import("@/components/MkFormulaCore.vue"),
), ),
}, },
props: { props: {

View file

@ -21,7 +21,7 @@ const query = ref(props.q);
const search = () => { const search = () => {
window.open( window.open(
`https://search.annoyingorange.xyz/search?q=${query.value}`, `https://search.annoyingorange.xyz/search?q=${query.value}`,
"_blank" "_blank",
); );
}; };
</script> </script>

View file

@ -259,7 +259,7 @@ watch(
() => { () => {
fetching = true; fetching = true;
renderChart(); renderChart();
} },
); );
onMounted(async () => { onMounted(async () => {

View file

@ -36,7 +36,7 @@ const props = withDefaults(
defineProps<{ defineProps<{
image: misskey.entities.DriveFile; image: misskey.entities.DriveFile;
}>(), }>(),
{} {},
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -40,7 +40,7 @@ const props = withDefaults(
title: null, title: null,
size: 64, size: 64,
cover: true, cover: true,
} },
); );
const canvas = $ref<HTMLCanvasElement>(); const canvas = $ref<HTMLCanvasElement>();

View file

@ -95,7 +95,7 @@ const search = () => {
id: x.id, id: x.id,
host: x.host, host: x.host,
iconUrl: x.iconUrl, iconUrl: x.iconUrl,
} as Instance) }) as Instance,
); );
}); });
}; };

View file

@ -138,7 +138,7 @@ function createDoughnut(chartEl, tooltip, data) {
{ {
backgroundColor: data.map((x) => x.color), backgroundColor: data.map((x) => x.color),
borderColor: getComputedStyle( borderColor: getComputedStyle(
document.documentElement document.documentElement,
).getPropertyValue("--panel"), ).getPropertyValue("--panel"),
borderWidth: 2, borderWidth: 2,
hoverOffset: 0, hoverOffset: 0,
@ -161,7 +161,7 @@ function createDoughnut(chartEl, tooltip, data) {
ev, ev,
"nearest", "nearest",
{ intersect: true }, { intersect: true },
false false,
)[0]; )[0];
if (hit && data[hit.index].onClick) { if (hit && data[hit.index].onClick) {
data[hit.index].onClick(); data[hit.index].onClick();
@ -206,7 +206,7 @@ onMounted(() => {
color: "#80808080", color: "#80808080",
value: fedStats.otherFollowersCount, value: fedStats.otherFollowersCount,
}, },
]) ]),
); );
createDoughnut( createDoughnut(
@ -227,7 +227,7 @@ onMounted(() => {
color: "#80808080", color: "#80808080",
value: fedStats.otherFollowingCount, value: fedStats.otherFollowingCount,
}, },
]) ]),
); );
}); });
}); });

View file

@ -32,7 +32,7 @@ const instance = props.instance ?? {
name: instanceName, name: instanceName,
themeColor: ( themeColor: (
document.querySelector( document.querySelector(
'meta[name="theme-color-orig"]' 'meta[name="theme-color-orig"]',
) as HTMLMetaElement ) as HTMLMetaElement
)?.content, )?.content,
softwareName: Instance.softwareName || "Calckey", softwareName: Instance.softwareName || "Calckey",
@ -86,8 +86,11 @@ function getInstanceIcon(instance): string {
font-weight: bold; font-weight: bold;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
text-shadow: -1px -1px 0 var(--bg), 1px -1px 0 var(--bg), text-shadow:
-1px 1px 0 var(--bg), 1px 1px 0 var(--bg); -1px -1px 0 var(--bg),
1px -1px 0 var(--bg),
-1px 1px 0 var(--bg),
1px 1px 0 var(--bg);
.article > .main &, .article > .main &,
.header > .body & { .header > .body & {
display: unset; display: unset;

View file

@ -32,7 +32,7 @@ const props = withDefaults(
{ {
copy: null, copy: null,
oneline: false, oneline: false,
} },
); );
const copy_ = () => { const copy_ = () => {

View file

@ -78,7 +78,7 @@ const props = withDefaults(
}>(), }>(),
{ {
anchor: () => ({ x: "right", y: "center" }), anchor: () => ({ x: "right", y: "center" }),
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -28,7 +28,7 @@ const props = withDefaults(
url: string; url: string;
rel?: null | string; rel?: null | string;
}>(), }>(),
{} {},
); );
const self = props.url.startsWith(local); const self = props.url.startsWith(local);
@ -40,7 +40,7 @@ const el = $ref();
useTooltip($$(el), (showing) => { useTooltip($$(el), (showing) => {
os.popup( os.popup(
defineAsyncComponent( defineAsyncComponent(
() => import("@/components/MkUrlPreviewPopup.vue") () => import("@/components/MkUrlPreviewPopup.vue"),
), ),
{ {
showing, showing,
@ -48,7 +48,7 @@ useTooltip($$(el), (showing) => {
source: el, source: el,
}, },
{}, {},
"closed" "closed",
); );
}); });
</script> </script>

View file

@ -63,9 +63,9 @@ export default {
: undefined, : undefined,
}, },
}, },
$slots.default() $slots.default(),
) ),
) ),
), ),
]); ]);
}, },

View file

@ -103,7 +103,8 @@ const plyrMini = ref(false);
const url = const url =
props.raw || defaultStore.state.loadRawImages props.raw || defaultStore.state.loadRawImages
? props.media.url ? props.media.url
: defaultStore.state.disableShowingAnimatedImages && props.media.type.startsWith('image') : defaultStore.state.disableShowingAnimatedImages &&
props.media.type.startsWith("image")
? getStaticImageUrl(props.media.thumbnailUrl) ? getStaticImageUrl(props.media.thumbnailUrl)
: props.media.thumbnailUrl; : props.media.thumbnailUrl;
@ -127,7 +128,7 @@ watch(
{ {
deep: true, deep: true,
immediate: true, immediate: true,
} },
); );
onMounted(() => { onMounted(() => {

View file

@ -67,7 +67,7 @@ const props = withDefaults(
defineProps<{ defineProps<{
media: misskey.entities.DriveFile; media: misskey.entities.DriveFile;
}>(), }>(),
{} {},
); );
const audioEl = $ref<HTMLAudioElement | null>(); const audioEl = $ref<HTMLAudioElement | null>();

View file

@ -184,10 +184,10 @@ export default defineComponent({
caption() { caption() {
const img = document.getElementById( const img = document.getElementById(
"imgtocaption" "imgtocaption",
) as HTMLImageElement; ) as HTMLImageElement;
const ta = document.getElementById( const ta = document.getElementById(
"captioninput" "captioninput",
) as HTMLTextAreaElement; ) as HTMLTextAreaElement;
os.api("drive/files/caption-image", { os.api("drive/files/caption-image", {
url: img.src, url: img.src,

View file

@ -14,7 +14,7 @@
<div ref="gallery" @click.stop> <div ref="gallery" @click.stop>
<template <template
v-for="media in mediaList.filter((media) => v-for="media in mediaList.filter((media) =>
previewable(media) previewable(media),
)" )"
> >
<XMedia <XMedia
@ -111,6 +111,8 @@ onMounted(() => {
imageClickAction: "close", imageClickAction: "close",
tapAction: "toggle-controls", tapAction: "toggle-controls",
preloadFirstSlide: false, preloadFirstSlide: false,
showAnimationDuration: 100,
hideAnimationDuration: 100,
pswpModule: PhotoSwipe, pswpModule: PhotoSwipe,
}); });
@ -207,7 +209,7 @@ const isModule = (file: misskey.entities.DriveFile): boolean => {
}; };
const previewableCount = props.mediaList.filter((media) => const previewableCount = props.mediaList.filter((media) =>
previewable(media) previewable(media),
).length; ).length;
</script> </script>

View file

@ -251,7 +251,7 @@ watch(
() => props.items, () => props.items,
() => { () => {
const items: (MenuItem | MenuPending)[] = [...props.items].filter( const items: (MenuItem | MenuPending)[] = [...props.items].filter(
(item) => item !== undefined (item) => item !== undefined,
); );
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
@ -270,7 +270,7 @@ watch(
}, },
{ {
immediate: true, immediate: true,
} },
); );
let childMenu = $ref<MenuItem[] | null>(); let childMenu = $ref<MenuItem[] | null>();

View file

@ -43,7 +43,7 @@ let headX = $ref<number | null>(null);
let headY = $ref<number | null>(null); let headY = $ref<number | null>(null);
let clock = $ref<number | null>(null); let clock = $ref<number | null>(null);
const accent = tinycolor( const accent = tinycolor(
getComputedStyle(document.documentElement).getPropertyValue("--accent") getComputedStyle(document.documentElement).getPropertyValue("--accent"),
); );
const color = accent.toRgbString(); const color = accent.toRgbString();

View file

@ -116,7 +116,7 @@ const props = withDefaults(
noOverlap: true, noOverlap: true,
transparentBg: false, transparentBg: false,
noReturnFocus: false, noReturnFocus: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -153,7 +153,7 @@ const type = $computed<ModalTypes>(() => {
} }
}); });
const isEnableBgTransparent = $computed( const isEnableBgTransparent = $computed(
() => props.transparentBg && type === "popup" () => props.transparentBg && type === "popup",
); );
let transitionName = $computed(() => let transitionName = $computed(() =>
defaultStore.state.animation defaultStore.state.animation
@ -164,7 +164,7 @@ let transitionName = $computed(() =>
: type === "popup" : type === "popup"
? "modal-popup" ? "modal-popup"
: "modal" : "modal"
: "" : "",
); );
let transitionDuration = $computed(() => let transitionDuration = $computed(() =>
transitionName === "send" transitionName === "send"
@ -175,7 +175,7 @@ let transitionDuration = $computed(() =>
? 200 ? 200
: transitionName === "modal-drawer" : transitionName === "modal-drawer"
? 200 ? 200
: 0 : 0,
); );
let contentClicking = false; let contentClicking = false;
@ -359,10 +359,10 @@ const onOpened = () => {
contentClicking = false; contentClicking = false;
}, 100); }, 100);
}, },
{ passive: true, once: true } { passive: true, once: true },
); );
}, },
{ passive: true } { passive: true },
); );
// if (props.preferType == "dialog") { // if (props.preferType == "dialog") {
// history.pushState(null, "", location.href); // history.pushState(null, "", location.href);
@ -384,7 +384,7 @@ onMounted(() => {
align(); align();
}, },
{ immediate: true } { immediate: true },
); );
nextTick(() => { nextTick(() => {
@ -414,7 +414,8 @@ defineExpose({
> .content { > .content {
transform: translateY(0px); transform: translateY(0px);
transition: opacity 0.3s ease-in, transition:
opacity 0.3s ease-in,
transform 0.3s cubic-bezier(0.5, -0.5, 1, 0.5) !important; transform 0.3s cubic-bezier(0.5, -0.5, 1, 0.5) !important;
} }
} }
@ -439,7 +440,9 @@ defineExpose({
> .content { > .content {
transform-origin: var(--transformOrigin); transform-origin: var(--transformOrigin);
transition: opacity 0.2s, transform 0.2s !important; transition:
opacity 0.2s,
transform 0.2s !important;
} }
} }
.transition_modal_enterFrom, .transition_modal_enterFrom,
@ -464,7 +467,8 @@ defineExpose({
> .content { > .content {
transform-origin: var(--transformOrigin); transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transition:
opacity 0.2s cubic-bezier(0, 0, 0.2, 1),
transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important; transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important;
} }
} }

View file

@ -80,7 +80,7 @@ const props = withDefaults(
width: 400, width: 400,
height: null, height: null,
scroll: true, scroll: true,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -128,8 +128,15 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="detailedView || (appearNote.channel && !inChannel)" class="info"> <div
<MkA v-if="detailedView" class="created-at" :to="notePage(appearNote)"> v-if="detailedView || (appearNote.channel && !inChannel)"
class="info"
>
<MkA
v-if="detailedView"
class="created-at"
:to="notePage(appearNote)"
>
<MkTime :time="appearNote.createdAt" mode="absolute" /> <MkTime :time="appearNote.createdAt" mode="absolute" />
</MkA> </MkA>
<MkA <MkA
@ -173,7 +180,7 @@
:count=" :count="
Object.values(appearNote.reactions).reduce( Object.values(appearNote.reactions).reduce(
(partialSum, val) => partialSum + val, (partialSum, val) => partialSum + val,
0 0,
) )
" "
:reacted="appearNote.myReaction != null" :reacted="appearNote.myReaction != null"
@ -332,7 +339,7 @@ const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const renoteTime = ref<HTMLElement>(); const renoteTime = ref<HTMLElement>();
const reactButton = ref<HTMLElement>(); const reactButton = ref<HTMLElement>();
let appearNote = $computed(() => let appearNote = $computed(() =>
isRenote ? (note.renote as misskey.entities.Note) : note isRenote ? (note.renote as misskey.entities.Note) : note,
); );
const isMyRenote = $i && $i.id === note.userId; const isMyRenote = $i && $i.id === note.userId;
const showContent = ref(false); const showContent = ref(false);
@ -369,7 +376,7 @@ function reply(viaKeyboard = false): void {
}, },
() => { () => {
focus(); focus();
} },
); );
} }
@ -386,7 +393,7 @@ function react(viaKeyboard = false): void {
}, },
() => { () => {
focus(); focus();
} },
); );
} }
@ -400,7 +407,7 @@ function undoReact(note): void {
const currentClipPage = inject<Ref<misskey.entities.Clip> | null>( const currentClipPage = inject<Ref<misskey.entities.Clip> | null>(
"currentClipPage", "currentClipPage",
null null,
); );
function onContextmenu(ev: MouseEvent): void { function onContextmenu(ev: MouseEvent): void {
@ -466,7 +473,7 @@ function onContextmenu(ev: MouseEvent): void {
} }
: undefined, : undefined,
], ],
ev ev,
); );
} }
} }
@ -484,7 +491,7 @@ function menu(viaKeyboard = false): void {
menuButton.value, menuButton.value,
{ {
viaKeyboard, viaKeyboard,
} },
).then(focus); ).then(focus);
} }
@ -507,7 +514,7 @@ function showRenoteMenu(viaKeyboard = false): void {
renoteTime.value, renoteTime.value,
{ {
viaKeyboard: viaKeyboard, viaKeyboard: viaKeyboard,
} },
); );
} }

View file

@ -233,7 +233,7 @@ let isScrolling;
const reactionsCount = Object.values(props.note.reactions).reduce( const reactionsCount = Object.values(props.note.reactions).reduce(
(x, y) => x + y, (x, y) => x + y,
0 0,
); );
const keymap = { const keymap = {
@ -274,7 +274,7 @@ function react(viaKeyboard = false): void {
}, },
() => { () => {
focus(); focus();
} },
); );
} }
@ -308,7 +308,7 @@ function onContextmenu(ev: MouseEvent): void {
menuButton, menuButton,
isDeleted, isDeleted,
}), }),
ev ev,
).then(focus); ).then(focus);
} }
} }
@ -325,7 +325,7 @@ function menu(viaKeyboard = false): void {
menuButton.value, menuButton.value,
{ {
viaKeyboard, viaKeyboard,
} },
).then(focus); ).then(focus);
} }
@ -551,7 +551,9 @@ onUnmounted(() => {
background: var(--panelHighlight); background: var(--panelHighlight);
border-radius: var(--radius); border-radius: var(--radius);
opacity: 0; opacity: 0;
transition: opacity 0.2s, background 0.2s; transition:
opacity 0.2s,
background 0.2s;
z-index: -1; z-index: -1;
} }
&.reply-to { &.reply-to {

View file

@ -23,10 +23,10 @@
v-tooltip.noDelay=" v-tooltip.noDelay="
i18n.t('edited', { i18n.t('edited', {
date: new Date( date: new Date(
note.updatedAt note.updatedAt,
).toLocaleDateString(), ).toLocaleDateString(),
time: new Date( time: new Date(
note.updatedAt note.updatedAt,
).toLocaleTimeString(), ).toLocaleTimeString(),
}) })
" "

View file

@ -85,7 +85,7 @@
:count=" :count="
Object.values(appearNote.reactions).reduce( Object.values(appearNote.reactions).reduce(
(partialSum, val) => partialSum + val, (partialSum, val) => partialSum + val,
0 0,
) )
" "
:reacted="appearNote.myReaction != null" :reacted="appearNote.myReaction != null"
@ -220,7 +220,7 @@ const props = withDefaults(
{ {
depth: 1, depth: 1,
replyLevel: 1, replyLevel: 1,
} },
); );
let note = $ref(deepClone(props.note)); let note = $ref(deepClone(props.note));
@ -248,7 +248,7 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
const renoteButton = ref<InstanceType<typeof XRenoteButton>>(); const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const reactButton = ref<HTMLElement>(); const reactButton = ref<HTMLElement>();
let appearNote = $computed(() => let appearNote = $computed(() =>
isRenote ? (note.renote as misskey.entities.Note) : note isRenote ? (note.renote as misskey.entities.Note) : note,
); );
const isDeleted = ref(false); const isDeleted = ref(false);
const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords)); const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
@ -259,7 +259,7 @@ const replies: misskey.entities.Note[] =
?.filter( ?.filter(
(item) => (item) =>
item.replyId === props.note.id || item.replyId === props.note.id ||
item.renoteId === props.note.id item.renoteId === props.note.id,
) )
.reverse() ?? []; .reverse() ?? [];
const enableEmojiReactions = defaultStore.state.enableEmojiReactions; const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
@ -294,7 +294,7 @@ function react(viaKeyboard = false): void {
}, },
() => { () => {
focus(); focus();
} },
); );
} }
@ -308,7 +308,7 @@ function undoReact(note): void {
const currentClipPage = inject<Ref<misskey.entities.Clip> | null>( const currentClipPage = inject<Ref<misskey.entities.Clip> | null>(
"currentClipPage", "currentClipPage",
null null,
); );
function menu(viaKeyboard = false): void { function menu(viaKeyboard = false): void {
@ -324,7 +324,7 @@ function menu(viaKeyboard = false): void {
menuButton.value, menuButton.value,
{ {
viaKeyboard, viaKeyboard,
} },
).then(focus); ).then(focus);
} }
@ -389,7 +389,7 @@ function onContextmenu(ev: MouseEvent): void {
} }
: undefined, : undefined,
], ],
ev ev,
); );
} }
} }

View file

@ -73,7 +73,7 @@
notification.reaction notification.reaction
? notification.reaction.replace( ? notification.reaction.replace(
/^:(\w+):$/, /^:(\w+):$/,
':$1@.:' ':$1@.:',
) )
: notification.reaction : notification.reaction
" "
@ -297,7 +297,7 @@ const props = withDefaults(
{ {
withTime: false, withTime: false,
full: false, full: false,
} },
); );
const elRef = ref<HTMLElement>(null); const elRef = ref<HTMLElement>(null);
@ -378,7 +378,7 @@ useTooltip(reactionRef, (showing) => {
targetElement: reactionRef.value.$el, targetElement: reactionRef.value.$el,
}, },
{}, {},
"closed" "closed",
); );
}); });
</script> </script>

View file

@ -60,7 +60,7 @@ const props = withDefaults(
{ {
includingTypes: () => [], includingTypes: () => [],
showGlobalToggle: true, showGlobalToggle: true,
} },
); );
let includingTypes = $computed(() => props.includingTypes || []); let includingTypes = $computed(() => props.includingTypes || []);
@ -70,7 +70,7 @@ const dialog = $ref<InstanceType<typeof XModalWindow>>();
let typesMap = $ref<Record<(typeof notificationTypes)[number], boolean>>({}); let typesMap = $ref<Record<(typeof notificationTypes)[number], boolean>>({});
let useGlobalSetting = $ref( let useGlobalSetting = $ref(
(includingTypes === null || includingTypes.length === 0) && (includingTypes === null || includingTypes.length === 0) &&
props.showGlobalToggle props.showGlobalToggle,
); );
for (const ntype of notificationTypes) { for (const ntype of notificationTypes) {

View file

@ -40,7 +40,9 @@ onMounted(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
.notification-toast-enter-active, .notification-toast-enter-active,
.notification-toast-leave-active { .notification-toast-leave-active {
transition: opacity 0.3s, transform 0.3s !important; transition:
opacity 0.3s,
transform 0.3s !important;
} }
.notification-toast-enter-from, .notification-toast-enter-from,
.notification-toast-leave-to { .notification-toast-leave-to {

View file

@ -21,7 +21,7 @@
<XNote <XNote
v-if=" v-if="
['reply', 'quote', 'mention'].includes( ['reply', 'quote', 'mention'].includes(
notification.type notification.type,
) )
" "
:key="notification.id" :key="notification.id"

View file

@ -22,6 +22,6 @@ watch(
}, },
{ {
immediate: true, immediate: true,
} },
); );
</script> </script>

View file

@ -136,7 +136,7 @@ function back() {
history.pop(); history.pop();
router.replace( router.replace(
history[history.length - 1].path, history[history.length - 1].path,
history[history.length - 1].key history[history.length - 1].key,
); );
} }

View file

@ -86,7 +86,7 @@ import MkButton from "@/components/MkButton.vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
export type Paging< export type Paging<
E extends keyof misskey.Endpoints = keyof misskey.Endpoints E extends keyof misskey.Endpoints = keyof misskey.Endpoints,
> = { > = {
endpoint: E; endpoint: E;
limit: number; limit: number;
@ -118,7 +118,7 @@ const props = withDefaults(
}>(), }>(),
{ {
displayLimit: 30, displayLimit: 30,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -186,7 +186,7 @@ const init = async (): Promise<void> => {
(err) => { (err) => {
error.value = true; error.value = true;
fetching.value = false; fetching.value = false;
} },
); );
}; };
@ -209,10 +209,13 @@ const refresh = async (): void => {
}) })
.then( .then(
(res) => { (res) => {
let ids = items.value.reduce((a, b) => { let ids = items.value.reduce(
a[b.id] = true; (a, b) => {
return a; a[b.id] = true;
}, {} as { [id: string]: boolean }); return a;
},
{} as { [id: string]: boolean },
);
for (let i = 0; i < res.length; i++) { for (let i = 0; i < res.length; i++) {
const item = res[i]; const item = res[i];
@ -229,7 +232,7 @@ const refresh = async (): void => {
(err) => { (err) => {
error.value = true; error.value = true;
fetching.value = false; fetching.value = false;
} },
); );
}; };
@ -291,7 +294,7 @@ const fetchMore = async (): Promise<void> => {
}, },
(err) => { (err) => {
moreFetching.value = false; moreFetching.value = false;
} },
); );
}; };
@ -344,7 +347,7 @@ const fetchMoreAhead = async (): Promise<void> => {
}, },
(err) => { (err) => {
moreFetching.value = false; moreFetching.value = false;
} },
); );
}; };
@ -445,7 +448,7 @@ watch(
if (a.length === 0 && b.length === 0) return; if (a.length === 0 && b.length === 0) return;
emit("queue", queue.value.length); emit("queue", queue.value.length);
}, },
{ deep: true } { deep: true },
); );
init(); init();

View file

@ -73,7 +73,7 @@ const isLocal = computed(() => !props.note.uri);
const isVoted = computed( const isVoted = computed(
() => () =>
!props.note.poll.multiple && !props.note.poll.multiple &&
props.note.poll.choices.some((c) => c.isVoted) props.note.poll.choices.some((c) => c.isVoted),
); );
const timer = computed(() => const timer = computed(() =>
i18n.t( i18n.t(
@ -89,8 +89,8 @@ const timer = computed(() =>
m: Math.floor(remaining.value / 60) % 60, m: Math.floor(remaining.value / 60) % 60,
h: Math.floor(remaining.value / 3600) % 24, h: Math.floor(remaining.value / 3600) % 24,
d: Math.floor(remaining.value / 86400), d: Math.floor(remaining.value / 86400),
} },
) ),
); );
const showResult = ref(props.readOnly || isVoted.value); const showResult = ref(props.readOnly || isVoted.value);
@ -101,8 +101,8 @@ if (props.note.poll.expiresAt) {
remaining.value = Math.floor( remaining.value = Math.floor(
Math.max( Math.max(
new Date(props.note.poll.expiresAt).getTime() - Date.now(), new Date(props.note.poll.expiresAt).getTime() - Date.now(),
0 0,
) / 1000 ) / 1000,
); );
if (remaining.value === 0) { if (remaining.value === 0) {
showResult.value = true; showResult.value = true;

View file

@ -96,7 +96,7 @@ const emit = defineEmits<{
expiredAfter: number; expiredAfter: number;
choices: string[]; choices: string[];
multiple: boolean; multiple: boolean;
} },
): void; ): void;
}>(); }>();
@ -104,7 +104,7 @@ const choices = ref(props.modelValue.choices);
const multiple = ref(props.modelValue.multiple); const multiple = ref(props.modelValue.multiple);
const expiration = ref("infinite"); const expiration = ref("infinite");
const atDate = ref( const atDate = ref(
formatDateTimeString(addTime(new Date(), 1, "day"), "yyyy-MM-dd") formatDateTimeString(addTime(new Date(), 1, "day"), "yyyy-MM-dd"),
); );
const atTime = ref("00:00"); const atTime = ref("00:00");
const after = ref(0); const after = ref(0);
@ -176,7 +176,7 @@ watch(
() => emit("update:modelValue", get()), () => emit("update:modelValue", get()),
{ {
deep: true, deep: true,
} },
); );
</script> </script>

View file

@ -284,7 +284,7 @@ const props = withDefaults(
initialVisibleUsers: () => [], initialVisibleUsers: () => [],
autofocus: true, autofocus: true,
showMfmCheatSheet: true, showMfmCheatSheet: true,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -313,14 +313,14 @@ let cw = $ref<string | null>(null);
let localOnly = $ref<boolean>( let localOnly = $ref<boolean>(
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
? defaultStore.state.localOnly ? defaultStore.state.localOnly
: defaultStore.state.defaultNoteLocalOnly : defaultStore.state.defaultNoteLocalOnly,
); );
let visibility = $ref( let visibility = $ref(
props.initialVisibility ?? props.initialVisibility ??
((defaultStore.state.rememberNoteVisibility ((defaultStore.state.rememberNoteVisibility
? defaultStore.state.visibility ? defaultStore.state.visibility
: defaultStore.state : defaultStore.state
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]) .defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
); );
let visibleUsers = $ref([]); let visibleUsers = $ref([]);
if (props.initialVisibleUsers) { if (props.initialVisibleUsers) {
@ -405,7 +405,7 @@ const canPost = $computed((): boolean => {
}); });
const withHashtags = $computed( const withHashtags = $computed(
defaultStore.makeGetterSetter("postFormWithHashtags") defaultStore.makeGetterSetter("postFormWithHashtags"),
); );
const hashtags = $computed(defaultStore.makeGetterSetter("postFormHashtags")); const hashtags = $computed(defaultStore.makeGetterSetter("postFormHashtags"));
@ -420,7 +420,7 @@ watch(
}, },
{ {
deep: true, deep: true,
} },
); );
if (props.mention) { if (props.mention) {
@ -488,7 +488,7 @@ if (
if (props.reply.visibleUserIds) { if (props.reply.visibleUserIds) {
os.api("users/show", { os.api("users/show", {
userIds: props.reply.visibleUserIds.filter( userIds: props.reply.visibleUserIds.filter(
(uid) => uid !== $i.id && uid !== props.reply.userId (uid) => uid !== $i.id && uid !== props.reply.userId,
), ),
}).then((users) => { }).then((users) => {
users.forEach(pushVisibleUser); users.forEach(pushVisibleUser);
@ -499,7 +499,7 @@ if (
os.api("users/show", { userId: props.reply.userId }).then( os.api("users/show", { userId: props.reply.userId }).then(
(user) => { (user) => {
pushVisibleUser(user); pushVisibleUser(user);
} },
); );
} }
} }
@ -533,7 +533,7 @@ function checkMissingMention() {
for (const x of extractMentions(ast)) { for (const x of extractMentions(ast)) {
if ( if (
!visibleUsers.some( !visibleUsers.some(
(u) => u.username === x.username && u.host === x.host (u) => u.username === x.username && u.host === x.host,
) )
) { ) {
hasNotSpecifiedMentions = true; hasNotSpecifiedMentions = true;
@ -550,13 +550,13 @@ function addMissingMention() {
for (const x of extractMentions(ast)) { for (const x of extractMentions(ast)) {
if ( if (
!visibleUsers.some( !visibleUsers.some(
(u) => u.username === x.username && u.host === x.host (u) => u.username === x.username && u.host === x.host,
) )
) { ) {
os.api("users/show", { username: x.username, host: x.host }).then( os.api("users/show", { username: x.username, host: x.host }).then(
(user) => { (user) => {
visibleUsers.push(user); visibleUsers.push(user);
} },
); );
} }
} }
@ -584,7 +584,7 @@ function focus() {
textareaEl.focus(); textareaEl.focus();
textareaEl.setSelectionRange( textareaEl.setSelectionRange(
textareaEl.value.length, textareaEl.value.length,
textareaEl.value.length textareaEl.value.length,
); );
} }
} }
@ -595,7 +595,7 @@ function chooseFileFrom(ev) {
for (const file of files_) { for (const file of files_) {
files.push(file); files.push(file);
} }
} },
); );
} }
@ -629,7 +629,7 @@ function setVisibility() {
os.popup( os.popup(
defineAsyncComponent( defineAsyncComponent(
() => import("@/components/MkVisibilityPicker.vue") () => import("@/components/MkVisibilityPicker.vue"),
), ),
{ {
currentVisibility: visibility, currentVisibility: visibility,
@ -650,14 +650,14 @@ function setVisibility() {
} }
}, },
}, },
"closed" "closed",
); );
} }
function pushVisibleUser(user) { function pushVisibleUser(user) {
if ( if (
!visibleUsers.some( !visibleUsers.some(
(u) => u.username === user.username && u.host === user.host (u) => u.username === user.username && u.host === user.host,
) )
) { ) {
visibleUsers.push(user); visibleUsers.push(user);
@ -703,7 +703,7 @@ function onCompositionEnd(ev: CompositionEvent) {
async function onPaste(ev: ClipboardEvent) { async function onPaste(ev: ClipboardEvent) {
for (const { item, i } of Array.from(ev.clipboardData.items).map( for (const { item, i } of Array.from(ev.clipboardData.items).map(
(item, i) => ({ item, i }) (item, i) => ({ item, i }),
)) { )) {
if (item.kind === "file") { if (item.kind === "file") {
const file = item.getAsFile(); const file = item.getAsFile();
@ -711,7 +711,7 @@ async function onPaste(ev: ClipboardEvent) {
const ext = lio >= 0 ? file.name.slice(lio) : ""; const ext = lio >= 0 ? file.name.slice(lio) : "";
const formatted = `${formatTimeString( const formatted = `${formatTimeString(
new Date(file.lastModified), new Date(file.lastModified),
defaultStore.state.pastedFileName defaultStore.state.pastedFileName,
).replace(/{{number}}/g, `${i + 1}`)}${ext}`; ).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
upload(file, formatted); upload(file, formatted);
} }
@ -879,11 +879,11 @@ async function post() {
.filter((x) => x.type === "hashtag") .filter((x) => x.type === "hashtag")
.map((x) => x.props.hashtag); .map((x) => x.props.hashtag);
const history = JSON.parse( const history = JSON.parse(
localStorage.getItem("hashtags") || "[]" localStorage.getItem("hashtags") || "[]",
) as string[]; ) as string[];
localStorage.setItem( localStorage.setItem(
"hashtags", "hashtags",
JSON.stringify(unique(hashtags_.concat(history))) JSON.stringify(unique(hashtags_.concat(history))),
); );
} }
posting = false; posting = false;
@ -930,11 +930,11 @@ function showActions(ev) {
if (key === "text") { if (key === "text") {
text = value; text = value;
} }
} },
); );
}, },
})), })),
ev.currentTarget ?? ev.target ev.currentTarget ?? ev.target,
); );
} }
@ -954,7 +954,7 @@ function openAccountMenu(ev: MouseEvent) {
} }
}, },
}, },
ev ev,
); );
} }
@ -985,7 +985,7 @@ onMounted(() => {
visibility = draft.data.visibility; visibility = draft.data.visibility;
localOnly = draft.data.localOnly; localOnly = draft.data.localOnly;
files = (draft.data.files || []).filter( files = (draft.data.files || []).filter(
(draftFile) => draftFile (draftFile) => draftFile,
); );
if (draft.data.poll) { if (draft.data.poll) {
poll = draft.data.poll; poll = draft.data.poll;

View file

@ -39,7 +39,7 @@ import { i18n } from "@/i18n";
export default defineComponent({ export default defineComponent({
components: { components: {
XDraggable: defineAsyncComponent(() => XDraggable: defineAsyncComponent(() =>
import("vuedraggable").then((x) => x.default) import("vuedraggable").then((x) => x.default),
), ),
MkDriveFileThumbnail, MkDriveFileThumbnail,
}, },
@ -110,7 +110,7 @@ export default defineComponent({
async describe(file) { async describe(file) {
os.popup( os.popup(
defineAsyncComponent( defineAsyncComponent(
() => import("@/components/MkMediaCaption.vue") () => import("@/components/MkMediaCaption.vue"),
), ),
{ {
title: i18n.ts.describeFile, title: i18n.ts.describeFile,
@ -133,7 +133,7 @@ export default defineComponent({
}); });
}, },
}, },
"closed" "closed",
); );
}, },
@ -175,7 +175,7 @@ export default defineComponent({
}, },
}, },
], ],
ev.currentTarget ?? ev.target ev.currentTarget ?? ev.target,
) )
.then(() => (this.menu = null)); .then(() => (this.menu = null));
}, },

View file

@ -99,7 +99,7 @@ function subscribe() {
.subscribe({ .subscribe({
userVisibleOnly: true, userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array( applicationServerKey: urlBase64ToUint8Array(
instance.swPublickey instance.swPublickey,
), ),
}) })
.then( .then(
@ -118,7 +118,7 @@ function subscribe() {
// //
if (err?.name === "NotAllowedError") { if (err?.name === "NotAllowedError") {
console.info( console.info(
"User denied the notification permission request." "User denied the notification permission request.",
); );
return; return;
} }
@ -128,10 +128,10 @@ function subscribe() {
// //
// //
await unsubscribe(); await unsubscribe();
} },
), ),
null, null,
null null,
); );
} }

View file

@ -24,7 +24,7 @@ const props = defineProps<{
const canRenote = computed( const canRenote = computed(
() => () =>
["public", "home"].includes(props.note.visibility) || ["public", "home"].includes(props.note.visibility) ||
props.note.userId === $i?.id props.note.userId === $i?.id,
); );
function quote(): void { function quote(): void {

View file

@ -91,10 +91,10 @@ useTooltip(
targetElement: buttonRef.value, targetElement: buttonRef.value,
}, },
{}, {},
"closed" "closed",
); );
}, },
100 100,
); );
</script> </script>

View file

@ -39,7 +39,7 @@ const buttonRef = ref<HTMLElement>();
const canRenote = computed( const canRenote = computed(
() => () =>
["public", "home"].includes(props.note.visibility) || ["public", "home"].includes(props.note.visibility) ||
props.note.userId === $i.id props.note.userId === $i.id,
); );
useTooltip(buttonRef, async (showing) => { useTooltip(buttonRef, async (showing) => {
@ -61,7 +61,7 @@ useTooltip(buttonRef, async (showing) => {
targetElement: buttonRef.value, targetElement: buttonRef.value,
}, },
{}, {},
"closed" "closed",
); );
}); });
@ -205,7 +205,7 @@ const renote = (viaKeyboard = false, ev?: MouseEvent) => {
renoteId: props.note.id, renoteId: props.note.id,
visibility: props.note.visibility, visibility: props.note.visibility,
localOnly: true, localOnly: true,
} },
); );
hasRenotedBefore = true; hasRenotedBefore = true;
const el = const el =

View file

@ -85,7 +85,7 @@ const props = withDefaults(
}>(), }>(),
{ {
particle: true, particle: true,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -122,7 +122,7 @@ export default defineComponent({
action: () => {}, action: () => {},
}, },
], ],
ev.currentTarget ?? ev.target ev.currentTarget ?? ev.target,
); );
}, },
}, },

View file

@ -223,7 +223,7 @@ function onUsernameChange() {
}, },
() => { () => {
user = null; user = null;
} },
); );
} }
@ -259,7 +259,7 @@ function queryKey() {
password, password,
signature: hexify(credential.response.signature), signature: hexify(credential.response.signature),
authenticatorData: hexify( authenticatorData: hexify(
credential.response.authenticatorData credential.response.authenticatorData,
), ),
clientDataJSON: hexify(credential.response.clientDataJSON), clientDataJSON: hexify(credential.response.clientDataJSON),
credentialId: credential.id, credentialId: credential.id,
@ -370,7 +370,7 @@ function resetPassword() {
defineAsyncComponent(() => import("@/components/MkForgotPassword.vue")), defineAsyncComponent(() => import("@/components/MkForgotPassword.vue")),
{}, {},
{}, {},
"closed" "closed",
); );
} }

View file

@ -25,7 +25,7 @@ const props = withDefaults(
{ {
autoSet: false, autoSet: false,
message: "", message: "",
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -303,7 +303,7 @@ const props = withDefaults(
}>(), }>(),
{ {
autoSet: false, autoSet: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -31,7 +31,7 @@ const props = withDefaults(
}>(), }>(),
{ {
autoSet: false, autoSet: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -105,13 +105,16 @@ onMounted(() => {
particles.value.push(particle); particles.value.push(particle);
window.setTimeout(() => { window.setTimeout(() => {
particles.value = particles.value.filter( particles.value = particles.value.filter(
(x) => x.id !== particle.id (x) => x.id !== particle.id,
); );
}, particle.dur - 100); }, particle.dur - 100);
window.setTimeout(() => { window.setTimeout(
add(); () => {
}, 500 + Math.random() * 500); add();
},
500 + Math.random() * 500,
);
}; };
add(); add();
} }

Some files were not shown because too many files have changed in this diff Show more