diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2022-08-07 00:39:21 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2022-08-07 00:39:21 +0900 |
| commit | 3b1669fb6b131e0809b3a4a93270b2b9e4a74247 (patch) | |
| tree | d9c0397e52f722e53fb99be6c6cae7023f5f054a | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.118.0 (diff) | |
| download | misskey-3b1669fb6b131e0809b3a4a93270b2b9e4a74247.tar.gz misskey-3b1669fb6b131e0809b3a4a93270b2b9e4a74247.tar.bz2 misskey-3b1669fb6b131e0809b3a4a93270b2b9e4a74247.zip | |
Merge branch 'develop'
165 files changed, 4023 insertions, 2775 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 59c748fb68..1f99af88b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 12.x.x (unreleased) ### Improvements +- Client: Preferences Registry ### Bugfixes - @@ -9,6 +10,19 @@ You should also include the user name that made the change. --> +## 12.118.0 (2022/08/07) + +### Improvements +- Client: è¨å®šã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—/リストア機能 +- Client: Add vi-VN language support +- Client: Add unix time widget @syuilo + +### Bugfixes +- Server: リモートユーザーをæ£ã—ãブãƒãƒƒã‚¯ã§ãるよã†ã«ä¿®æ£ã™ã‚‹ @xianonn +- Client: 一度作ã£ãŸwebhookã®è¨å®šç”»é¢ã‚’é–‹ã“ã†ã¨ã™ã‚‹ã¨ãƒšãƒ¼ã‚¸ãŒãƒ•リーズã™ã‚‹ @syuilo +- Client: MiAuthèªè¨¼ãƒšãƒ¼ã‚¸ãŒæ©Ÿèƒ½ã—ã¦ã„ãªã„ @syuilo +- Client: 一部ã®ã‚¢ãƒ—リã‹ã‚‰ãƒ•ァイルを投稿フォームã¸ãƒ‰ãƒãƒƒãƒ—ã§ããªã„å ´åˆãŒã‚ã‚‹å•é¡Œã‚’ä¿®æ£ @m-hayabusa + ## 12.117.1 (2022/07/19) ### Improvements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4a5d48cf0..4547138eb4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -140,6 +140,34 @@ Misskey uses Vue(v3) as its front-end framework. - **When creating a new component, please use the Composition API (with [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html) and [ref sugar](https://github.com/vuejs/rfcs/discussions/369)) instead of the Options API.** - Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome. +## nirax +niraxã¯ã€Misskeyã§ä½¿ç”¨ã—ã¦ã„るオリジナルã®ãƒ•ãƒãƒ³ãƒˆã‚¨ãƒ³ãƒ‰ãƒ«ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã‚·ã‚¹ãƒ†ãƒ ã§ã™ã€‚ +**vue-routerã‹ã‚‰å½±éŸ¿ã‚’多大ã«å—ã‘ã¦ã„ã‚‹ã®ã§ã€ã¾ãšã¯vue-routerã«ã¤ã„ã¦å¦ã¶ã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚** + +### ルート定義 +ルート定義ã¯ã€ä»¥ä¸‹ã®å½¢å¼ã®ã‚ªãƒ–ジェクトã®é…列ã§ã™ã€‚ + +``` ts +{ + name?: string; + path: string; + component: Component; + query?: Record<string, string>; + loginRequired?: boolean; + hash?: string; + globalCacheKey?: string; + children?: RouteDef[]; +} +``` + +> **Warning** +> ç¾çжã€ãƒ«ãƒ¼ãƒˆã¯å®šç¾©ã•れãŸé †ã«è©•価ã•れã¾ã™ã€‚ +> ãŸã¨ãˆã°ã€`/foo/:id`ãƒ«ãƒ¼ãƒˆå®šç¾©ã®æ¬¡ã«`/foo/bar`ルート定義ãŒã•れã¦ã„ãŸå ´åˆã€å¾Œè€…ãŒãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ã‚りã¾ã›ã‚“。 + +### 複数ã®ãƒ«ãƒ¼ã‚¿ãƒ¼ +vue-routerã¨ã®æœ€å¤§ã®é•ã„ã¯ã€niraxã¯è¤‡æ•°ã®ãƒ«ãƒ¼ã‚¿ãƒ¼ãŒå˜åœ¨ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¦ã„る点ã§ã™ã€‚ +ã“れã«ã‚ˆã‚Šã€ã‚¢ãƒ—リ内ウィンドウã§ãƒ–ラウザã¨ã¯å€‹åˆ¥ã«ãƒ«ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã™ã‚‹ã“ã¨ãªã©ãŒå¯èƒ½ã«ãªã‚Šã¾ã™ã€‚ + ## Notes ### How to resolve conflictions occurred at yarn.lock? diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 992eeb0f50..7fa8c23ad0 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -52,6 +52,7 @@ searchUser: "Ø§Ø¨ØØ« عن مستخدمين" reply: "رد" loadMore: "عرض المزيد" showMore: "عرض المزيد" +showLess: "اغلق" youGotNewFollower: "يتابعك" receiveFollowRequest: "تلقيت طلب متابعة" followRequestAccepted: "Ù‚ÙØ¨Ù„ طلب المتابعة" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index f488935074..a19fc0832e 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -52,6 +52,7 @@ searchUser: "বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•ারী খà§à¦à¦œà§à¦¨..." reply: "জবাব" loadMore: "আরও দেখà§à¦¨" showMore: "আরও দেখà§à¦¨" +showLess: "বনà§à¦§" youGotNewFollower: "আপনাকে অনà§à¦¸à¦°à¦£ করছে" receiveFollowRequest: "অনà§à¦¸à¦°à¦£ করার জনà§à¦¯ অনà§à¦°à§‹à¦§ পাওয়া গেছে" followRequestAccepted: "অনà§à¦¸à¦°à¦£ করার অনà§à¦°à§‹à¦§ গৃহীত হয়েছে" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index c2b5e38fb5..ff8a7ae8b8 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -52,6 +52,7 @@ searchUser: "Vyhledat uživatele" reply: "OdpovÄ›dÄ›t" loadMore: "Zobrazit vÃce" showMore: "Zobrazit vÃce" +showLess: "ZavÅ™Ãt" youGotNewFollower: "Máte nového následovnÃka" receiveFollowRequest: "Žádost o sledovánà pÅ™ijata" followRequestAccepted: "Žádost o sledovánà pÅ™ijata" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 1ae3e77b6d..1498992586 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -52,6 +52,7 @@ searchUser: "Nach einem Benutzer suchen" reply: "Antworten" loadMore: "Mehr laden" showMore: "Mehr anzeigen" +showLess: "Schließen" youGotNewFollower: "ist dir gefolgt" receiveFollowRequest: "Follow-Anfrage erhalten" followRequestAccepted: "Follow-Anfrage akzeptiert" @@ -561,6 +562,7 @@ author: "Autor" leaveConfirm: "Es gibt unspeicherte Änderungen. Möchtest du diese verwerfen?" manage: "Verwaltung" plugins: "Plugins" +preferencesBackups: "Einstellungsbackups" deck: "Deck" undeck: "Deck verlassen" useBlurEffectForModal: "Weichzeichnungseffekt für Modals verwenden" @@ -862,7 +864,7 @@ requireAdminForView: "Melde dich mit einem Administratorkonto an, um dies einzus isSystemAccount: "Ein Benutzerkonto, dass durch das System erstellt und automatisch kontrolliert wird." typeToConfirm: "Bitte gib zur Bestätigung {x} ein" deleteAccount: "Benutzerkonto löschen" -document: "Dokument" +document: "Dokumentation" numberOfPageCache: "Seitencachegröße" numberOfPageCacheDescription: "Das Erhöhen dieses Caches führt zu einer angenehmerern Benutzererfahrung, erhöht aber Serverlast und Arbeitsspeicherauslastung." logoutConfirm: "Wirklich abmelden?" @@ -941,6 +943,24 @@ _plugin: install: "Plugins installieren" installWarn: "Installiere bitte nur vertrauenswürdige Plugins." manage: "Plugins verwalten" +_preferencesBackups: + list: "Erstellte Backups" + saveNew: "Neu erstellen" + loadFile: "Von Datei laden" + apply: "Auf dieses Gerät anwenden" + save: "Speichern" + inputName: "Gib einen Namen für dieses Backup ein" + cannotSave: "Speichern fehlgeschlagen" + nameAlreadyExists: "Es existiert bereits ein Backup unter dem Namen \"{name}\". Bitte gib einen anderen Namen ein." + applyConfirm: "Wirklich das Backup \"{name}\" auf dieses Gerät anwenden? Bestehende Einstellungen darauf werden überschrieben." + saveConfirm: "Als {name} speichern?" + deleteConfirm: "Das Backup {name} löschen?" + renameConfirm: "Soll dieses Backup von \"{old}\" zu \"{new}\" umbenannt werden?" + noBackups: "Keine Backups existieren. Backups können über \"Neu erstellen\" erstelllt werden." + createdAt: "Erstellt am: {date} {time}" + updatedAt: "Aktualisiert am: {date} {time}" + cannotLoad: "Laden fehlgeschlagen" + invalidFile: "Ungültiges Dateiformat." _registry: scope: "Scope" key: "Schlüssel" @@ -1024,6 +1044,8 @@ _mfm: sparkleDescription: "Verleiht Inhalt einen glitzernden Partikeleffekt." rotate: "Drehen" rotateDescription: "Dreht den Inhalt um einen angegebenen Winkel." + plain: "Schlicht" + plainDescription: "Deaktiviert jegliche MFM-Syntax, die sich innerhalb dieses MFM-Effekts befindet." _instanceTicker: none: "Nie anzeigen" remote: "Für Benutzer fremder Instanzen anzeigen" @@ -1257,6 +1279,7 @@ _widgets: activity: "Aktivität" photos: "Fotos" digitalClock: "Digitaluhr" + unixClock: "UNIX-Uhr" federation: "Föderation" instanceCloud: "Instanzwolke" postForm: "Notizfenster" diff --git a/locales/en-US.yml b/locales/en-US.yml index 92c85507de..3b04b401dd 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -52,6 +52,7 @@ searchUser: "Search for a user" reply: "Reply" loadMore: "Load more" showMore: "Show more" +showLess: "Close" youGotNewFollower: "followed you" receiveFollowRequest: "Follow request received" followRequestAccepted: "Follow request accepted" @@ -561,6 +562,7 @@ author: "Author" leaveConfirm: "There are unsaved changes. Do you want to discard them?" manage: "Management" plugins: "Plugins" +preferencesBackups: "Preference backups" deck: "Deck" undeck: "Leave Deck" useBlurEffectForModal: "Use blur effect for modals" @@ -862,7 +864,7 @@ requireAdminForView: "You must log in with an administrator account to view this isSystemAccount: "An account created and automatically operated by the system." typeToConfirm: "Please enter {x} to confirm" deleteAccount: "Delete account" -document: "Document" +document: "Documentation" numberOfPageCache: "Number of cached pages" numberOfPageCacheDescription: "Increasing this number will improve convenience for users but cause more server load as well as more memory to be used." logoutConfirm: "Really log out?" @@ -941,6 +943,24 @@ _plugin: install: "Install plugins" installWarn: "Please do not install untrustworthy plugins." manage: "Manage plugins" +_preferencesBackups: + list: "Created backups" + saveNew: "Save new backup" + loadFile: "Load from file" + apply: "Apply to this device" + save: "Save changes" + inputName: "Please enter a name for this backup" + cannotSave: "Saving failed" + nameAlreadyExists: "A backup called \"{name}\" already exists. Please enter a different name." + applyConfirm: "Do you really want to apply the \"{name}\" backup to this device? Existing settings of this device will be overwritten." + saveConfirm: "Save backup as {name}?" + deleteConfirm: "Delete the {name} backup?" + renameConfirm: "Rename this backup from \"{old}\" to \"{new}\"?" + noBackups: "No backups exist. You may backup your client settings on this server by using \"Create new backup\"." + createdAt: "Created at: {date} {time}" + updatedAt: "Updated at: {date} {time}" + cannotLoad: "Loading failed" + invalidFile: "Invalid file format" _registry: scope: "Scope" key: "Key" @@ -1024,6 +1044,8 @@ _mfm: sparkleDescription: "Gives content a sparkling particle effect." rotate: "Rotate" rotateDescription: "Turns content by a specified angle." + plain: "Plain" + plainDescription: "Deactivates the effects of all MFM contained within this MFM effect." _instanceTicker: none: "Never show" remote: "Show for remote users" @@ -1257,6 +1279,7 @@ _widgets: activity: "Activity" photos: "Photos" digitalClock: "Digital clock" + unixClock: "UNIX clock" federation: "Federation" instanceCloud: "Instance cloud" postForm: "Posting form" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 8383864ede..b74eed85d6 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1,16 +1,16 @@ --- _lang_: "Español" headlineMisskey: "Red conectada por notas" -introMisskey: "¡Bienvenido/a! Misskey es un servicio de microblogging descentralizado de código abierto.\nEscribe \"notas\" para compartir lo que te ocurre ahora o para contar sobre ti a todos 📡\nCon la función de \"reacciones\", puedes también añadir una reacción rápida a las notas de todos ðŸ‘\nExplora un nuevo mundo 🚀" +introMisskey: "¡Bienvenido/a! Misskey es un servicio de microblogging descentralizado de código abierto.\nEscribe \"notas\" para compartir lo que te ocurre ahora o para contar sobre ti a todos 📡\nCon la función de \"reacciones\", puedes también añadir una reacción rápida a las notas de todos ðŸ‘\n¡Exploremos juntos un nuevo mundo! 🚀" monthAndDay: "{day}/{month}" search: "Buscar" notifications: "Notificaciones" username: "Nombre de usuario" password: "Contraseña" forgotPassword: "Olvidé mi Contraseña" -fetchingAsApObject: "Buscando en el fediverso" +fetchingAsApObject: "Recuperando desde el Fediverso..." ok: "OK" -gotIt: "Entendido" +gotIt: "¡Lo tengo!" cancel: "Cancelar" enterUsername: "Introduce el nombre de usuario" renotedBy: "Renotado por {user}" @@ -22,36 +22,37 @@ basicSettings: "Configuración Básica" otherSettings: "Configuración avanzada" openInWindow: "Abrir en una ventana" profile: "Perfil" -timeline: "Linea de tiempo" -noAccountDescription: "Este usuario no tiene una descripción" +timeline: "LÃnea de tiempo" +noAccountDescription: "Este usuario no ha escrito su biografÃa aún" login: "Iniciar sesión" loggingIn: "Iniciando sesión" logout: "Cerrar sesión" signup: "Registrarse" -uploading: "Cargando" +uploading: "Cargando..." save: "Guardar" users: "Usuarios" addUser: "Agregar usuario" -favorite: "Favorito" +favorite: "Añadir a favoritos" favorites: "Favoritos" unfavorite: "Quitar de favoritos" -favorited: "Añadido a favoritos" +favorited: "Añadido a favoritos." alreadyFavorited: "Ya habÃa sido añadido a favoritos" -cantFavorite: "No fue añadido a favoritos" -pin: "Fijar" +cantFavorite: "No se puede añadir a favoritos." +pin: "Fijar al perfil" unpin: "Desfijar" copyContent: "Copiar contenido" copyLink: "Copiar enlace" delete: "Borrar" deleteAndEdit: "Borrar y editar" -deleteAndEditConfirm: "¿Quieres borrar y editar este nota? Las reacciones, renotes, respuestas y todo desaparecerán." +deleteAndEditConfirm: "¿Estás seguro de que quieres borrar esta nota y editarla? Perderás todas las reacciones, renotas y respuestas." addToList: "Agregar a lista" -sendMessage: "Énviar mensaje" +sendMessage: "Enviar un mensaje" copyUsername: "Copiar nombre de usuario" -searchUser: "Búsqueda de usuarios" +searchUser: "Buscar un usuario" reply: "Responder" loadMore: "Ver más" showMore: "Ver más" +showLess: "Cerrar" youGotNewFollower: "te ha seguido" receiveFollowRequest: "Recibiste una solicitud de seguimiento" followRequestAccepted: "La solicitud de seguimiento fue aceptada" @@ -87,11 +88,11 @@ enterListName: "Ingrese nombre de lista" privacy: "Privacidad" makeFollowManuallyApprove: "Aprobar manualmente las solicitudes de seguimiento" defaultNoteVisibility: "Visibilidad por defecto" -follow: "Sigue" -followRequest: "Solicitud de seguimiento" +follow: "Seguir" +followRequest: "Enviar solicitud de seguimiento" followRequests: "Solicitudes de seguimiento" unfollow: "Dejar de seguir" -followRequestPending: "Solicitudes de seguimiento pendientes" +followRequestPending: "Solicitudes de seguimiento pendiente" enterEmoji: "Ingresar emojis" renote: "Renotar" unrenote: "Quitar renota" @@ -100,7 +101,7 @@ cantRenote: "No se puede renotar este post" cantReRenote: "No se puede renotar una renota" quote: "Citar" pinnedNote: "Nota fijada" -pinned: "Fijar" +pinned: "Fijar al perfil" you: "Tú" clickToShow: "Click para ver" sensitive: "Marcado como sensible" @@ -203,6 +204,7 @@ done: "Terminado" processing: "Procesando" preview: "Vista previa" default: "Predeterminado" +defaultValueIs: "Predeterminado" noCustomEmojis: "No hay emojis personalizados" noJobs: "No hay trabajos" federating: "Federando" @@ -381,6 +383,7 @@ administrator: "Administrador" token: "Token" twoStepAuthentication: "Autenticación de dos factores" moderator: "Moderador" +moderation: "Moderación" nUsersMentioned: "{n} usuarios mencionados" securityKey: "Clave de seguridad" securityKeyName: "Nombre de la Clave" @@ -559,6 +562,7 @@ author: "Autor" leaveConfirm: "Hay modificaciones sin guardar. ¿Desea descartarlas?" manage: "Administrar" plugins: "Plugins" +preferencesBackups: "Respaldo de preferencias" deck: "Deck" undeck: "Quitar deck" useBlurEffectForModal: "Usar efecto borroso en modales" @@ -854,6 +858,9 @@ noEmailServerWarning: "No se ha configurado un servidor de correo electrónico." thereIsUnresolvedAbuseReportWarning: "Hay reportes sin resolver" recommended: "Recomendado" check: "Verificar" +driveCapOverrideLabel: "Cambiar la capacidad de la unidad para este usuario" +driveCapOverrideCaption: "Restablecer la capacidad a su predeterminado ingresando un valor de 0 o menos" +requireAdminForView: "Necesitas iniciar sesión como administrador para ver esto." isSystemAccount: "Cuenta creada y operada automáticamente por el sistema" typeToConfirm: "Ingrese {x} para confirmar" deleteAccount: "Borrar cuenta" @@ -861,11 +868,39 @@ document: "Documento" numberOfPageCache: "Cantidad de páginas cacheadas" numberOfPageCacheDescription: "Al aumentar el número mejora la conveniencia pero tambien puede aumentar la carga y la memoria a usarse" logoutConfirm: "¿Cerrar sesión?" +lastActiveDate: "Utilizado por última vez el" +statusbar: "Barra de estado" +pleaseSelect: "Selecciona una opción" reverse: "Echar de un capirotazo" colored: "Color" +refreshInterval: "Intervalo de actualización" label: "Etiqueta" +type: "Tipo" +speed: "Velocidad" +slow: "Lento" +fast: "Rápido" +sensitiveMediaDetection: "Detección de contenido NSFW" localOnly: "Solo local" +remoteOnly: "Sólo remoto" +failedToUpload: "La subida falló" +cannotUploadBecauseInappropriate: "Este archivo no se puede subir debido a que algunas partes han sido detectadas comoNSFW." +cannotUploadBecauseNoFreeSpace: "La subida falló debido a falta de espacio libre en la unidad del usuario." +beta: "Beta" +enableAutoSensitive: "Marcar automáticamente contenido NSFW" +enableAutoSensitiveDescription: "Permite la detección y marcado automático de contenido NSFW usando 'Machine Learning' cuando sea posible. Incluso si esta opción está desactivada, puede ser activado para toda la instancia." +activeEmailValidationDescription: "Habilita la validación estricta de direcciones de correo electrónico, lo cual incluye la revisión de direcciones desechables y si se puede comunicar con éstas. Cuando está deshabilitado, sólo el formato de la dirección es validado." +navbar: "Barra de navegación" +shuffle: "Aleatorio" account: "Cuentas" +move: "Mover" +_sensitiveMediaDetection: + description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor." + sensitivity: "Sensibilidad de detección" + sensitivityDescription: "Reducir la sensibilidad puede acarrear a varios falsos positivos, mientras que incrementarla puede reducir las detecciones (falsos negativos)." + setSensitiveFlagAutomatically: "Marcar como NSFW" + setSensitiveFlagAutomaticallyDescription: "Los resultados de la detección interna pueden ser retenidos incluso si la opción está desactivada." + analyzeVideos: "Habilitar el análisis de videos" + analyzeVideosDescription: "Analizar videos en adición a las imágenes. Esto puede incrementar ligeramente la carga del servidor." _emailUnavailable: used: "Ya fue usado" format: "Formato no válido." @@ -908,6 +943,24 @@ _plugin: install: "Instalar plugins" installWarn: "Por favor no instale plugins que no son de confianza" manage: "Gestionar plugins" +_preferencesBackups: + list: "Respaldos creados" + saveNew: "Guardar nuevo respaldo" + loadFile: "Cargar desde archivo" + apply: "Aplicar a este dispositivo" + save: "Guardar cambios" + inputName: "Por favor, ingresa un nombre para este respaldo" + cannotSave: "Fallo al guardar" + nameAlreadyExists: "Un respaldo llamado \"{name}\" ya existe. Por favor ingresa un nombre diferente" + applyConfirm: "¿Realmente quieres aplicar los cambios desde el archivo \"{name}\" a este dispositivo? Las configuraciones existentes serán sobreescritas. " + saveConfirm: "¿Guardar respaldo como \"{name}\"?" + deleteConfirm: "¿Borrar el respaldo \"{name}\"?" + renameConfirm: "¿Renombrar este respaldo de \"{old}\" a \"{new}\"?" + noBackups: "No existen respaldos. Deberás respaldar las configuraciones del cliente en este servidor usando \"Crear nuevo respaldo\"" + createdAt: "Creado: {date} {time}" + updatedAt: "Actualizado: {date} {time}" + cannotLoad: "La carga falló" + invalidFile: "Formato de archivo inválido" _registry: scope: "Alcance" key: "Clave" @@ -991,6 +1044,8 @@ _mfm: sparkleDescription: "Aplica un efecto de partÃculas parpadeantes" rotate: "Rotar" rotateDescription: "Rota el contenido a un ángulo especificado." + plain: "Plano" + plainDescription: "Desactiva los efectos de todo el contenido MFM con este efecto MFM." _instanceTicker: none: "No mostrar" remote: "Mostrar a usuarios remotos" @@ -1220,9 +1275,11 @@ _widgets: trends: "Tendencias" clock: "Reloj" rss: "Lector RSS" + rssTicker: "Ticker-RSS" activity: "Actividad" photos: "Fotos" digitalClock: "Reloj digital" + unixClock: "Reloj UNIX" federation: "Federación" instanceCloud: "Nube de palabras de la instancia" postForm: "Formulario" @@ -1663,6 +1720,7 @@ _deck: alwaysShowMainColumn: "Siempre mostrar la columna principal" columnAlign: "Alinear columnas" addColumn: "Agregar columna" + configureColumn: "Ajustes de columna" swapLeft: "Mover a la izquierda" swapRight: "Mover a la derecha" swapUp: "Mover arriba" @@ -1670,6 +1728,11 @@ _deck: stackLeft: "Apilar a la izquierda" popRight: "Sacar a la derecha" profile: "Perfil" + newProfile: "Nuevo perfil" + deleteProfile: "Eliminar perfil" + introduction: "¡Crea la interfaz perfecta para tà organizando las columnas libremente!" + introduction2: "Presiona en la + de la derecha de la pantalla para añadir nuevas columnas donde quieras." + widgetsIntroduction: "Por favor selecciona \"Editar Widgets\" en el menú columna y agrega un widget." _columns: main: "Principal" widgets: "Widgets" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index b14d3d14b6..d6047b48da 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -52,6 +52,7 @@ searchUser: "Chercher un·e utilisateur·rice" reply: "Répondre" loadMore: "Afficher plus …" showMore: "Afficher plus …" +showLess: "Fermer" youGotNewFollower: "Vous suit" receiveFollowRequest: "Demande d’abonnement reçue" followRequestAccepted: "La demande d’abonnement a été acceptée" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 315b690b0f..dc214f4ea1 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -52,6 +52,7 @@ searchUser: "Cari pengguna" reply: "Balas" loadMore: "Selebihnya" showMore: "Selebihnya" +showLess: "Tutup" youGotNewFollower: "Mengikuti kamu" receiveFollowRequest: "Ingin mengikuti kamu" followRequestAccepted: "Permintaan mengikuti telah disetujui" diff --git a/locales/index.js b/locales/index.js index 98c30fe016..92cd9b467c 100644 --- a/locales/index.js +++ b/locales/index.js @@ -36,6 +36,7 @@ const languages = [ 'sk-SK', 'ug-CN', 'uk-UA', + 'vi-VN', 'zh-CN', 'zh-TW', ]; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index ac14bed133..410928bc51 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -52,6 +52,7 @@ searchUser: "Cerca utente" reply: "Rispondi" loadMore: "Mostra di più" showMore: "Mostra di più" +showLess: "Chiudi" youGotNewFollower: "Ha iniziato a seguirti" receiveFollowRequest: "Hai ricevuto una richiesta di follow." followRequestAccepted: "Richiesta di follow accettata" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0c4a7c7231..b10cce9231 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -52,6 +52,7 @@ searchUser: "ユーザーを検索" reply: "返信" loadMore: "ã‚‚ã£ã¨è¦‹ã‚‹" showMore: "ã‚‚ã£ã¨è¦‹ã‚‹" +showLess: "é–‰ã˜ã‚‹" youGotNewFollower: "フォãƒãƒ¼ã•れã¾ã—ãŸ" receiveFollowRequest: "フォãƒãƒ¼ãƒªã‚¯ã‚¨ã‚¹ãƒˆã•れã¾ã—ãŸ" followRequestAccepted: "フォãƒãƒ¼ãŒæ‰¿èªã•れã¾ã—ãŸ" @@ -561,6 +562,7 @@ author: "作者" leaveConfirm: "未ä¿å˜ã®å¤‰æ›´ãŒã‚りã¾ã™ã€‚ç ´æ£„ã—ã¾ã™ã‹ï¼Ÿ" manage: "管ç†" plugins: "プラグイン" +preferencesBackups: "è¨å®šã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—" deck: "デッã‚" undeck: "デッã‚解除" useBlurEffectForModal: "モーダルã«ã¼ã‹ã—効果を使用" @@ -952,6 +954,25 @@ _plugin: installWarn: "ä¿¡é ¼ã§ããªã„プラグインã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãªã„ã§ãã ã•ã„。" manage: "プラグインã®ç®¡ç†" +_preferencesBackups: + list: "作æˆã—ãŸãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—" + saveNew: "æ–°è¦ä¿å˜" + loadFile: "ファイルをèªã¿è¾¼ã¿" + apply: "ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«é©ç”¨" + save: "上書ãä¿å˜" + inputName: "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—åを入力" + cannotSave: "ä¿å˜ã§ãã¾ã›ã‚“" + nameAlreadyExists: "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—å「{name}ã€ã¯æ—¢ã«å˜åœ¨ã—ã¾ã™ã€‚é•ã†åå‰ã‚’指定ã—ã¦ãã ã•ã„。" + applyConfirm: "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—「{name}ã€ã‚’ç¾åœ¨ã®ãƒ‡ãƒã‚¤ã‚¹ã«é©ç”¨ã—ã¾ã™ã‹ï¼Ÿç¾åœ¨ã®ãƒ‡ãƒã‚¤ã‚¹è¨å®šã¯å¤±ã‚れã¾ã™ã€‚" + saveConfirm: "{name}ã«ä¸Šæ›¸ãä¿å˜ã—ã¾ã™ã‹ï¼Ÿ" + deleteConfirm: "{name}を削除ã—ã¾ã™ã‹ï¼Ÿ" + renameConfirm: "「{old}ã€ã‚’「{new}ã€ã«å¤‰æ›´ã—ã¾ã™ã‹ï¼Ÿ" + noBackups: "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã¯ã‚りã¾ã›ã‚“。「新è¦ä¿å˜ã€ã§ç¾åœ¨ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨å®šã‚’サーãƒãƒ¼ã«ä¿å˜ã§ãã¾ã™ã€‚" + createdAt: "ä½œæˆæ—¥æ™‚: {date} {time}" + updatedAt: "更新日時: {date} {time}" + cannotLoad: "èªã¿è¾¼ã¿ã§ãã¾ã›ã‚“" + invalidFile: "ファイル形å¼ãŒé•ã„ã¾ã™ã€‚" + _registry: scope: "スコープ" key: "ã‚ー" @@ -1291,6 +1312,7 @@ _widgets: activity: "アクティビティ" photos: "フォト" digitalClock: "デジタル時計" + unixClock: "UNIX時計" federation: "連åˆ" instanceCloud: "インスタンスクラウド" postForm: "投稿フォーム" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index bae0ab5e1f..7d93fd83e9 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -52,6 +52,7 @@ searchUser: "ユーザーを検索" reply: "返事" loadMore: "ã¾ã ã¾ã ã‚ã‚‹ã§ï¼" showMore: "ã¾ã ã¾ã ã‚ã‚‹ã§ï¼" +showLess: "é–‰ã˜ã‚‹" youGotNewFollower: "フォãƒãƒ¼ã•れãŸã§" receiveFollowRequest: "フォãƒãƒ¼ãƒªã‚¯ã‚¨ã‚¹ãƒˆã•れãŸã§" followRequestAccepted: "フォãƒãƒ¼ãŒæ‰¿èªã•れãŸã§" @@ -203,6 +204,7 @@ done: "ã§ã‘ãŸ" processing: "処ç†ã—ã¨ã‚‹" preview: "プレビュー" default: "デフォルト" +defaultValueIs: "デフォルト" noCustomEmojis: "絵文å—ã¯ã‚らã¸ã‚“" noJobs: "ジョブã¯ã‚らã¸ã‚“" federating: "連åˆã—ã¨ã‚‹" @@ -317,6 +319,8 @@ monthX: "{month}月" yearX: "{year}å¹´" pages: "ページ" integration: "連æº" +connectService: "ã¤ãªã’ã‚‹ã§" +disconnectService: "切るã§" enableLocalTimeline: "ãƒãƒ¼ã‚«ãƒ«ã‚¿ã‚¤ãƒ ラインを使ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹" enableGlobalTimeline: "ã‚°ãƒãƒ¼ãƒãƒ«ã‚¿ã‚¤ãƒ ラインを使ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹" disablingTimelinesInfo: "ã“ã“らã¸ã‚“ã®ã‚¿ã‚¤ãƒ ラインを使ãˆã‚“よã†ã«ã—ã¦ã—ã‚‚ã¦ã‚‚ã€ç®¡ç†è€…ã¨ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚¿ãƒ¼ã¯ä½¿ãˆã‚‹ã¾ã¾ã«ãªã£ã¦ã‚‹ã§ã€ãã†ã‚„ãªã‹ã£ãŸã‚‰ä¸ä¾¿ã‚„ã‹ã‚‰ãªã€‚" @@ -328,10 +332,13 @@ driveCapacityPerRemoteAccount: "リモートユーザーã²ã¨ã‚Šã‚ãŸã‚Šã®ãƒ‰ inMb: "メガãƒã‚¤ãƒˆå˜ä½" iconUrl: "アイコン画åƒã®URL" bannerUrl: "ãƒãƒŠãƒ¼ç”»åƒã®URL" +backgroundImageUrl: "背景画åƒã®URL" basicInfo: "åŸºæœ¬æƒ…å ±" pinnedUsers: "ピン留ã‚ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼" pinnedUsersDescription: "「ã¿ã¤ã‘ã‚‹ã€ãƒšãƒ¼ã‚¸ã¨ã‹ã«ãƒ”ン留ã‚ã—ãŸã„ユーザーをã“ã“ã«æ›¸ã‘ã°ãˆãˆã‚“ã‚„ã§ã€‚他ん人ã¨ã®åå‰ã¯æ”¹è¡Œã§åŒºåˆ‡ã‚Œã°ãˆãˆã‚“ã‚„ã§ã€‚" pinnedPages: "ピン留ã‚ページ" +pinnedPagesDescription: "インスタンスã®ã„ã£ã¡ã‚ƒã‚“上ã«ãƒ”ン留ã‚ã—ãŸã„ページã®ãƒ‘スを改行ã§åŒºåˆ‡ã£ã¦è¨˜è¿°ã—ã¦ãª" +pinnedClipId: "ピン留ã‚ã™ã‚‹ã‚¯ãƒªãƒƒãƒ—ã®ID" pinnedNotes: "ピン留ã‚ã•れã¨ã‚‹ãƒŽãƒ¼ãƒˆ" hcaptcha: "hCaptcha(ã‚ャプãƒãƒ£ï¼‰" enableHcaptcha: "hCaptcha(ã‚ャプãƒãƒ£ï¼‰ã‚’ã¤ã‘ã¨ã" @@ -376,6 +383,7 @@ administrator: "管ç†è€…" token: "トークン" twoStepAuthentication: "二段階èªè¨¼" moderator: "モデレーター" +moderation: "モデレーション" nUsersMentioned: "{n}äººãŒæŠ•ç¨¿" securityKey: "ã‚»ã‚ュリティã‚ー" securityKeyName: "ã‚ーã®åå‰" @@ -435,13 +443,17 @@ strongPassword: "ãˆãˆæ„Ÿã˜ã®ãƒ‘スワード" passwordMatched: "よã—ï¼ä¸€è‡´ã‚„ï¼" passwordNotMatched: "一致ã—ã¨ã‚‰ã‚“ã§ï¼Ÿ" signinWith: "{x}ã§ãƒã‚°ã‚¤ãƒ³" +signinFailed: "ãƒã‚°ã‚¤ãƒ³ã§ãã‚“ã‹ã£ãŸã§ã€‚ã‚‚ã£ã‹ã„ユーザーåã¨ãƒ‘スワードを確èªã—ã¦ã¿ã¦ãªã€‚" +tapSecurityKey: "ã‚»ã‚ュリティã‚ーã«ã‚¿ãƒƒãƒã—ã¦ãª" or: "ãれã‹" language: "言語" uiLanguage: "UIã®è¡¨ç¤ºè¨€èªž" groupInvited: "ã‚°ãƒ«ãƒ¼ãƒ—ã«æ‹›å¾…ã•れã¨ã‚‹ã§" aboutX: "{x}ã«ã¤ã„ã¦" useOsNativeEmojis: "OSãƒã‚¤ãƒ†ã‚£ãƒ–ã®çµµæ–‡å—を使ã†" +disableDrawer: "メニューをドãƒãƒ¯ãƒ¼ã§è¡¨ç¤ºã›ã‡ã¸ã‚“" youHaveNoGroups: "グループãŒã‚らã¸ã‚“ãã‡ã€‚" +joinOrCreateGroup: "æ—¢å˜ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«æ‹›å¾…ã—ã¦ã‚‚らã†ã‹ã€æ–°ã—ãグループ作ã£ã¦ã‹ã‚‰ã‚„ã£ã¦ãª" noHistory: "å±¥æ´ã¯ã‚らã¸ã‚“ãã‡ã€‚" signinHistory: "ãƒã‚°ã‚¤ãƒ³å±¥æ´" disableAnimatedMfm: "å‹•ããŒã‚„ã‹ã¾ã—ã„MFMã‚’æ¢ã‚ã‚‹" @@ -450,6 +462,7 @@ category: "カテゴリ" tags: "ã‚¿ã‚°" docSource: "ã“ã®ãƒ‰ã‚ュメントã®ã‚½ãƒ¼ã‚¹" createAccount: "アカウントを作æˆ" +existingAccount: "æ—¢å˜ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" regenerate: "å†ç”Ÿæˆ" fontSize: "フォントサイズ" noFollowRequests: "フォãƒãƒ¼ç”³è«‹ã¯ã‚らã¸ã‚“ã§" @@ -473,10 +486,15 @@ useObjectStorage: "オブジェクトストレージを使ã†" objectStorageBaseUrl: "Base URL" objectStorageBaseUrlDesc: "å‚ç…§ã«ä½¿ã†ã«URLã‚„ã§ã€‚CDNã‚„Proxyを使用ã—ã¦ã‚‹ã‚“ãªã‚‰ãã®URLã€S3: 'https://<bucket>.s3.amazonaws.com'ã€GCSã¨ã‹ãªã‚‰: 'https://storage.googleapis.com/<bucket>'。" objectStorageBucket: "Bucket" +objectStorageBucketDesc: "使ã£ã¦ã‚‹ã‚µãƒ¼ãƒ“スã®bucketåã‚’é¸ã‚“ã§ãª" objectStoragePrefix: "Prefix" +objectStoragePrefixDesc: "ã“ã®prefixã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸‹ã«æ ¼ç´ã•れるã§" objectStorageEndpoint: "Endpoint" +objectStorageEndpointDesc: "S3ã®ã¨ãã¯ç©ºã€ãれ以外ã¯å„サービスã®endpointを指定ã—ã¦ãªãƒ¼ã€‚'<host>'ã£ã¦ã‚„ã‚‹ã‹'<host>:<port>'ã¿ãŸã„ã«æŒ‡å®šã™ã‚‹ã‚“ã‚„ã§ã€‚" objectStorageRegion: "Region" +objectStorageRegionDesc: "'xx-east-1'ã¿ãŸã„ãªregionを指定ã—ãŸã£ã¦ã‚„ー。使ã£ã¦ã‚‹ã‚µãƒ¼ãƒ“スã«regionã®æ¦‚念ãŒãªã„ã¨ãã¯ã€ç©ºã‹'us-east-1'ã«ã™ã‚‹ã‚“ã‚„ã§ã€‚" objectStorageUseSSL: "SSLを使ã†" +objectStorageUseSSLDesc: "API接続ã«httpsを使ã‚ã‚“å ´åˆã¯ã‚ªãƒ•ã«ã™ã‚‹ã‚“ã‚„ã§" objectStorageUseProxy: "Proxyを使ã†" objectStorageUseProxyDesc: "API接続ã«proxy使ã‚ã‚“ã®ã‚„ã£ãŸã‚‰åˆ‡ã£ã¦ãれã¸ã‚“?" objectStorageSetPublicRead: "アップãƒãƒ¼ãƒ‰ã—ãŸæ™‚ã«'public-read'ã‚’è¨å®šã—ã¦ã‚„" @@ -517,29 +535,52 @@ removeAllFollowing: "フォãƒãƒ¼ã‚’全解除" removeAllFollowingDescription: "{host}ã‹ã‚‰ã®ãƒ•ã‚©ãƒãƒ¼ã‚’ã™ã¹ã¦è§£é™¤ã™ã‚‹ã§ã€‚ãã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒæ¶ˆãˆã¦ç„¡ããªã£ãŸæ™‚ã¨ã‹ã«ã¯ä¾¿åˆ©ãªæ©Ÿèƒ½ã‚„ã§ã€‚" userSuspended: "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯...å‡çµã•れã¨ã‚‹ã€‚" userSilenced: "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯...サイレンスã•れã¨ã‚‹ã€‚" +yourAccountSuspendedTitle: "ã‚ã‚“ãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆå‡çµã•れã¨ã‚‹ã§" +yourAccountSuspendedDescription: "ã‚ã‚“ãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯ã€ã‚µãƒ¼ãƒãƒ¼ã®åˆ©ç”¨è¦ç´„ã«é•åã—ãŸã¨ã‹ã®ç†ç”±ã§ã€å‡çµã•れã¨ã‚‹ã§ã€‚ç´°ã‹ã„ã“ã¨ã¯ç®¡ç†è€…ã¾ã§ãŠå•ã„åˆã‚ã›ãŸã£ã¦ãªãƒ¼ã€‚çµ¶å¯¾ã«æ–°ã—ã„アカウント作ã£ãŸã‚‰ã‚ã‹ã‚“ã§ã€‚絶対やã§ã€‚" +menu: "メニュー" divider: "分割線" +addItem: "é …ç›®ã‚’è¿½åŠ " relays: "リレー" addRelay: "リレーã®è¿½åŠ " inboxUrl: "inboxã®URL" addedRelays: "è¿½åŠ æ¸ˆã¿ã®ãƒªãƒ¬ãƒ¼" +serviceworkerInfo: "プッシュ通知をã™ã‚‹ã‚“ãªã‚‰æœ‰åйã«ã›ãªã‚ã‹ã‚“ã§ã€‚" +deletedNote: "消ã•ã‚ŒãŸæŠ•ç¨¿" +invisibleNote: "éžå…¬é–‹ã®æŠ•稿" +enableInfiniteScroll: "自動ã§ã‚‚ã£ã¨è¦‹ã‚‹" +visibility: "公開範囲" poll: "アンケート" +useCw: "å†…å®¹ã‚’éš ã™" enablePlayer: "プレイヤーを開ã" disablePlayer: "プレイヤーを閉ã˜ã‚‹" expandTweet: "ツイートを展開ã™ã‚‹" themeEditor: "テーマエディター" description: "説明" +describeFile: "ã‚ャプションを付ã‘ã‚‹" +enterFileDescription: "ã‚ャプションを入力" author: "作者" leaveConfirm: "未ä¿å˜ã®å¤‰æ›´ãŒã‚ã‚‹ã§ï¼ã»ã‹ã—ã¦ãˆãˆã‹ï¼Ÿ" manage: "管ç†" plugins: "プラグイン" deck: "デッã‚" undeck: "デッã‚解除" +useBlurEffectForModal: "モーダルã«ã¼ã‹ã—効果を使用" +useFullReactionPicker: "フル機能ã«ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãƒ”ッカーを使用" width: "å¹…" height: "高ã•" large: "大" medium: "ä¸" small: "å°" +generateAccessToken: "アクセストークンã®ç™ºè¡Œ" +permission: "権é™" +enableAll: "全部使ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹" +disableAll: "全部使ãˆã¸ã‚“よã†ã«ã™ã‚‹" +tokenRequested: "アカウントã¸ã®ã‚¢ã‚¯ã‚»ã‚¹è¨±å¯" +pluginTokenRequestedDescription: "ã“ã®ãƒ—ラグインã¯ã“ã“ã§è¨å®šã—ãŸæ¨©é™ã‚’使ãˆã‚‹ã‚ˆã†ã«ãªã‚‹ã§ã€‚" +notificationType: "通知ã®ç¨®é¡ž" edit: "編集" +useStarForReactionFallback: "リアクションãŒã‚ˆã†ã‚ã‹ã‚‰ã‚“å ´åˆã€â˜…を使ã†" +emailServer: "メールサーãƒãƒ¼" enableEmail: "メールé…ä¿¡ã‚’å—ã‘å–ã‚‹" emailConfigInfo: "メールアドレスã®ç¢ºèªã¨ã‹ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ãƒªã‚»ãƒƒãƒˆã®æ™‚ã«ä½¿ã†ã§" email: "メール" @@ -551,8 +592,12 @@ smtpUser: "ユーザーå" smtpPass: "パスワード" emptyToDisableSmtpAuth: "ユーザーåã¨ãƒ‘スワードã«ãªã‚“も入れんã‹ã£ãŸã‚‰ã€SMTPèªè¨¼ã‚’無効化ã™ã‚‹ã§" smtpSecure: "SMTP æŽ¥ç¶šã«æš—黙的ãªSSL/TLSを使用ã™ã‚‹" +smtpSecureInfo: "STARTTLS使ã£ã¨ã‚‹æ™‚ã¯ã‚ªãƒ•ã«ã™ã‚‹ã§ã€‚" testEmail: "é…信テスト" wordMute: "ワードミュート" +regexpError: "æ£è¦è¡¨ç¾ã‚¨ãƒ©ãƒ¼" +regexpErrorDescription: "{tab}ワードミュートã®{line}è¡Œç›®ã®æ£è¦è¡¨ç¾ã«ã‚¨ãƒ©ãƒ¼ãŒå‡ºã¦ããŸã§:" +instanceMute: "インスタンスミュート" userSaysSomething: "{name}ãŒä½•ã‹è¨€ã£ãŸã‚ˆã†ã‚„ã§" makeActive: "使ã†ã§" display: "表示" @@ -567,13 +612,24 @@ create: "作æˆ" notificationSetting: "通知è¨å®š" notificationSettingDesc: "表示ã™ã‚‹é€šçŸ¥ã®ç¨®é¡žãˆã‚‰ã‚“ã§ã‚„。" useGlobalSetting: "ã‚°ãƒãƒ¼ãƒãƒ«è¨å®šã‚’使ã£ã¦ã‚„" +useGlobalSettingDesc: "オンã«ã™ã‚‹ã¨ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®é€šçŸ¥è¨å®šãŒä½¿ã‚れるã§ã€‚オフã«ã™ã‚‹ã¨ã€åˆ¥ã€…ã«è¨å®šã§ãるよã†ã«ãªã‚‹ã§ã€‚" other: "ãã®ä»–" regenerateLoginToken: "ãƒã‚°ã‚¤ãƒ³ãƒˆãƒ¼ã‚¯ãƒ³ã‚’å†ç”Ÿæˆ" +regenerateLoginTokenDescription: "ãƒã‚°ã‚¤ãƒ³ã«ä½¿ã‚れる内部トークンをもã£ã‹ã„作るã§ã€‚ã„ã¤ã‚‚ãªã‚‰ã“れをやる必è¦ã¯ãªã„ã§ã€‚ã‚‚ã£ã‹ã„作るã¨ã€å…¨éƒ¨ã®ãƒ‡ãƒã‚¤ã‚¹ã§ãƒã‚°ã‚¢ã‚¦ãƒˆã•ã‚Œã‚‹ã§æ°—ãƒã¤ã‘ã¦ãªãƒ¼ã€‚" +setMultipleBySeparatingWithSpace: "スペースã§åŒºåˆ‡ã£ã¦è¤‡æ•°è¨å®šã§ãã‚‹ã§ã€‚" +fileIdOrUrl: "ファイルIDã‹URL" behavior: "動作" sample: "サンプル" abuseReports: "é€šå ±" reportAbuse: "é€šå ±" reportAbuseOf: "{name}ã‚’é€šå ±ã™ã‚‹" +fillAbuseReportDescription: "ç´°ã‹ã„é€šå ±ç†ç”±ã‚’書ã„ã¦ãªãƒ¼ã€‚対象ノートãŒã‚る時ã¯ãã®URLも書ã„ã¨ã„ã¦ãªãƒ¼ã€‚" +abuseReported: "無事内容ãŒé€ä¿¡ã•れãŸã¿ãŸã„ã‚„ã§ã€‚ãŠãŠãã«ã€œã€‚" +reporter: "é€šå ±è€…" +reporteeOrigin: "é€šå ±å…ˆ" +reporterOrigin: "é€šå ±å…ƒ" +forwardReport: "リモートインスタンスã«é€šå ±ã‚’転é€ã™ã‚‹ã§" +forwardReportIsAnonymous: "リモートインスタンスã‹ã‚‰ã¯ã‚ã‚“ãŸã®æƒ…å ±ã¯è¦‹ã‚Œã¸ã‚“ãã£ã¦ã€åŒ¿åã®ã‚·ã‚¹ãƒ†ãƒ アカウントã¨ã—ã¦è¡¨ç¤ºã•れるã§ã€‚" send: "é€ä¿¡" abuseMarkAsResolved: "対応ã—ãŸã§" openInNewTab: "æ–°ã—ã„タブã§é–‹ã" @@ -587,22 +643,57 @@ system: "システム" switchUi: "UI切り替ãˆ" desktop: "デスクトップ" clip: "クリップ" +createNew: "æ–°ã—ã作るã§" +optional: "ä»»æ„" +createNewClip: "æ–°ã—ã„クリップを作るã§" +unclip: "クリップ解除ã™ã‚‹ã§" +confirmToUnclipAlreadyClippedNote: "ã“ã®ãƒŽãƒ¼ãƒˆã¯ã™ã§ã«ã‚¯ãƒªãƒƒãƒ—「{name}ã€ã«å«ã¾ã‚Œã¨ã‚‹ã§ã€‚ノートをã“ã®ã‚¯ãƒªãƒƒãƒ—ã‹ã‚‰é™¤å¤–ã—ãŸã‚‹ï¼Ÿ" +public: "パブリック" +i18nInfo: "Misskeyã¯æœ‰å¿—ã«ã‚ˆã£ã¦ã„ã‚ã‚“ãªè¨€èªžã«ç¿»è¨³ã•れã¨ã‚‹ã§ã€‚{link}ã§ç¿»è¨³ã«å”力ã—ãŸã£ã¦ã‚„ー。" +manageAccessTokens: "アクセストークンã®ç®¡ç†" +accountInfo: "ã‚¢ã‚«ã‚¦ãƒ³ãƒˆæƒ…å ±" +notesCount: "ãƒŽãƒ¼ãƒˆã®æ•°ã‚„ã§" +repliesCount: "返信ã—ãŸæ•°ã‚„ã§" +renotesCount: "Renoteã—ãŸæ•°ã‚„ã§" +repliedCount: "返信ã•ã‚ŒãŸæ•°ã‚„ã§" +renotedCount: "Renoteã•ã‚ŒãŸæ•°ã‚„ã§" +followingCount: "フォãƒãƒ¼æ•°ã‚„ã§" +followersCount: "フォãƒãƒ¯ãƒ¼æ•°ã‚„ã§" +sentReactionsCount: "リアクションã—ãŸæ•°ã‚„ã§" receivedReactionsCount: "リアクションã•ã‚ŒãŸæ•°" pollVotesCount: "ã‚¢ãƒ³ã‚±ãƒ¼ãƒˆã«æŠ•ç¥¨ã—ãŸæ•°" pollVotedCount: "ã‚¢ãƒ³ã‚±ãƒ¼ãƒˆã«æŠ•ç¥¨ã•ã‚ŒãŸæ•°" yes: "ã¯ã„" no: "ã„ã„ãˆ" driveFilesCount: "ドライブã®ãƒ•ァイル数" +driveUsage: "ドライブ使用é‡ã‚„ã§" +noCrawle: "クãƒãƒ¼ãƒ©ãƒ¼ã«ã‚ˆã‚‹ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’æ‹’å¦ã™ã‚‹ã§" +noCrawleDescription: "検索エンジンã«ã‚ã‚“ãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒšãƒ¼ã‚¸ã€ãƒŽãƒ¼ãƒˆã€Pagesã¨ã‹ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を登録(インデックス)ã›ã‡ã¸ã‚“よã†ã«é ¼ã‚€ã§ã€‚" +lockedAccountInfo: "フォãƒãƒ¼ã‚’承èªåˆ¶ã«ã—ã¨ã£ã¦ã‚‚ã€ãƒŽãƒ¼ãƒˆã®å…¬é–‹ç¯„囲を「フォãƒãƒ¯ãƒ¼ã€ã«ã›ã‡ã¸ã‚“é™ã‚Šã€èª°ã§ã‚‚ã‚ã‚“ãŸã®ãƒŽãƒ¼ãƒˆã‚’見れるã§ã€‚" +alwaysMarkSensitive: "デフォルトã§ãƒ¡ãƒ‡ã‚£ã‚¢ã‚’閲覧注æ„ã«ã™ã‚‹ã§" +loadRawImages: "添付画åƒã®ã‚µãƒ ãƒã‚¤ãƒ«ã‚’オリジナル画質ã«ã™ã‚‹ã§" +disableShowingAnimatedImages: "アニメーション画åƒã‚’å†ç”Ÿã—ã‚„ã¸ã‚“ã§" +verificationEmailSent: "無事確èªã®ãƒ¡ãƒ¼ãƒ«ã‚’é€ã‚ŒãŸã§ã€‚ãƒ¡ãƒ¼ãƒ«ã«æ›¸ã„ã¦ã‚るリンクã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã€è¨å®šã‚’完了ã—ã¦ãªãƒ¼ã€‚" +notSet: "未è¨å®š" emailVerified: "メールアドレスã¯ç¢ºèªã•れãŸã§" +noteFavoritesCount: "ãŠæ°—ã«å…¥ã‚ŠãƒŽãƒ¼ãƒˆã®æ•°ã‚„ã§" pageLikesCount: "Pageã«ãˆãˆã‚„ã‚“ã¨æ€ã£ãŸæ•°" pageLikedCount: "Pageã«ãˆãˆã‚„ã‚“ã¨æ€ã£ã¦ãã‚ŒãŸæ•°" +contact: "連絡先" +useSystemFont: "システムã®ãƒ‡ãƒ•ォルトã®ãƒ•ォントを使ã†ã§" clips: "クリップ" +experimentalFeatures: "実験的機能やã§" +developer: "開発者やã§" +makeExplorable: "アカウントを見ã¤ã‘ã‚„ã™ãã™ã‚‹ã§" +makeExplorableDescription: "オフã«ã™ã‚‹ã¨ã€ã€Œã¿ã¤ã‘ã‚‹ã€ã«ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒè¼‰ã‚‰ã‚“ããªã‚‹ã§ã€‚" +showGapBetweenNotesInTimeline: "タイムラインã®ãƒŽãƒ¼ãƒˆã‚’放ã—ã¦è¡¨ç¤ºã™ã‚‹ã§" duplicate: "複製" left: "å·¦" center: "ä¸å¤®" wide: "広ã„" narrow: "ç‹ã„" reloadToApplySetting: "è¨å®šã¯ãƒšãƒ¼ã‚¸ãƒªãƒãƒ¼ãƒ‰å¾Œã«åæ˜ ã•れるã§ã€‚今リãƒãƒ¼ãƒ‰ã—ã¨ãã‹ï¼Ÿ" +needReloadToApply: "åæ˜ ã«ã¯å†èµ·å‹•ã›ãªã‚ã‹ã‚“ã§" showTitlebar: "タイトルãƒãƒ¼ã‚’見ã›ã‚‹" clearCache: "ã‚ャッシュをã»ã‹ã™" onlineUsersCount: "{n}人ãŒèµ·ãã¨ã‚‹ã§" @@ -621,6 +712,7 @@ createdAt: "作æˆã—ãŸæ—¥" updatedAt: "更新日時" saveConfirm: "ä¿å˜ã™ã‚‹ã§ï¼Ÿ" deleteConfirm: "ホンマã«å‰Šé™¤ã™ã‚‹ã§ï¼Ÿ" +invalidValue: "有効ãªå€¤ã˜ã‚ƒãªã„ã¿ãŸã„ã‚„ã§ã€‚" registry: "レジストリ" closeAccount: "アカウントを閉鎖ã™ã‚‹" currentVersion: "ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³" @@ -634,6 +726,7 @@ editCode: "コードを編集" apply: "é©ç”¨" receiveAnnouncementFromInstance: "インスタンスã‹ã‚‰ã®ãŠçŸ¥ã‚‰ã›ã‚’å—ã‘å–ã‚‹" emailNotification: "メール通知" +publish: "公開" inChannelSearch: "ãƒãƒ£ãƒ³ãƒãƒ«å†…検索" useReactionPickerForContextMenu: "å³ã‚¯ãƒªãƒƒã‚¯ã§ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãƒ”ッカーを開ãよã†ã«ã™ã‚‹" typingUsers: "{users}ãŒä»Šæ›¸ãよるã§" @@ -642,23 +735,121 @@ showingPastTimeline: "éŽåŽ»ã®ã‚¿ã‚¤ãƒ ラインを表示ã—ã¦ã‚‹ã§" clear: "クリア" markAllAsRead: "ã‚‚ã†ã¿ãªèªã‚“ã§ã‚‚ã†ãŸã‚" goBack: "戻る" +unlikeConfirm: "ã„ã„ã解除ã™ã‚‹ã‚“ã‹ï¼Ÿ" +fullView: "フルビュー" +quitFullView: "フルビュー解除" +addDescription: "èª¬æ˜Žã‚’è¿½åŠ ã™ã‚‹ã§" +userPagePinTip: "個々ã®ãƒŽãƒ¼ãƒˆã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‹ã‚‰ã€Œãƒ”ン留ã‚ã€ã‚’é¸ã‚“ã©ãã¨ã€ã“ã“ã«ãƒŽãƒ¼ãƒˆã‚’表示ã—ã¦ãŠã‘ã‚‹ã§ã€‚" +notSpecifiedMentionWarning: "宛先ã«å«ã¾ã‚Œã¦ã¸ã‚“メンションãŒã‚ã‚‹ã§" info: "æƒ…å ±" +userInfo: "ãƒ¦ãƒ¼ã‚¶ãƒ¼æƒ…å ±ã‚„ã§" +unknown: "䏿˜Ž" +onlineStatus: "オンライン状態" +hideOnlineStatus: "ã‚ªãƒ³ãƒ©ã‚¤ãƒ³çŠ¶æ…‹ã‚’éš ã™ã§" +hideOnlineStatusDescription: "ã‚ªãƒ³ãƒ©ã‚¤ãƒ³çŠ¶æ…‹ã‚’éš ã™ã¨ã€æ¤œç´¢ã¨ã‹ã®ä¸€éƒ¨ã®æ©Ÿèƒ½ã§ä½¿ã„ã«ãããªã‚‹ã‹ã‚‚ã—れんよ。" +online: "オンライン" +active: "アクティブ" +offline: "オフライン" +notRecommended: "ã‚ã‚“ã¾æŽ¨å¥¨ã—ã‚„ã‚“ã§" +botProtection: "Botプãƒãƒ†ã‚¯ã‚·ãƒ§ãƒ³" +instanceBlocking: "インスタンスブãƒãƒƒã‚¯" +selectAccount: "アカウントをé¸ã‚“ã§ãªãƒ¼" +switchAccount: "アカウントを変ãˆã‚‹ã§" +enabled: "有効" +disabled: "無効" +quickAction: "クイックアクション" user: "ユーザー" administration: "管ç†" +accounts: "アカウント" +switch: "切り替ãˆ" +noMaintainerInformationWarning: "管ç†è€…æƒ…å ±ãŒè¨å®šã•れã¦ã¸ã‚“ã§" +noBotProtectionWarning: "Botプãƒãƒ†ã‚¯ã‚·ãƒ§ãƒ³ãŒè¨å®šã•れã¦ã¸ã‚“ã§ã€‚" +configure: "è¨å®šã™ã‚‹" +postToGallery: "ã‚®ãƒ£ãƒ©ãƒªãƒ¼ã¸æŠ•ç¨¿" +gallery: "ギャラリー" +recentPosts: "æœ€è¿‘ã®æŠ•ç¨¿" +popularPosts: "äººæ°—ã®æŠ•ç¨¿" +shareWithNote: "ノートã§å…±æœ‰" ads: "広告" expiration: "期é™" memo: "メモ" +priority: "優先度" high: "高ã„" middle: "ä¸" low: "低ã„" +emailNotConfiguredWarning: "メアドã®è¨å®šãŒã•れã¦ã¸ã‚“ã§ã€‚" +ratio: "比率" +previewNoteText: "本文を下見ã™ã‚‹ã§" +customCss: "カスタムCSS" +customCssWarn: "ã“ã®è¨å®šã¯å¿…ãšçŸ¥è˜ã®ã‚る人ãŒã‚„らãªã‚ã‹ã‚“ã§ã€‚ã‚ã‚“ã¾è‰¯ããªã„è¨å®šã‚’ã—ãŸã‚‹ã¨ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒã¡ã‚ƒã‚“ã¨ä½¿ãˆã¸ã‚“ããªã£ã¦ãã§ã€‚" global: "ã‚°ãƒãƒ¼ãƒãƒ«" +squareAvatars: "アイコンを四角形ã§è¡¨ç¤ºã™ã‚‹ã§" sent: "é€ä¿¡" +received: "å—ä¿¡" +searchResult: "æ¤œç´¢çµæžœã‚„ã§" hashtags: "ãƒãƒƒã‚·ãƒ¥ã‚¿ã‚°" +troubleshooting: "トラブルシューティング" +useBlurEffect: "UIã«ã¼ã‹ã—効果を使ã†ã§" +learnMore: "詳ã—ã" +misskeyUpdated: "MisskeyãŒæ›´æ–°ã•れãŸã§ï¼\nモデレーターã®äººã‚‰ã«æ„Ÿè¬ã›ãªã‚ã‹ã‚“ã§" +whatIsNew: "æ›´æ–°æƒ…å ±ã‚’è¦‹ã‚‹ã§" +translate: "翻訳" +translatedFrom: "{x}ã‹ã‚‰ç¿»è¨³ã™ã‚‹ã§" +accountDeletionInProgress: "アカウント削除ã—ã¨ã‚‹ã§å¾…ã£ã¨ã£ã¦ãªãƒ¼" +usernameInfo: "サーãƒãƒ¼ä¸Šã§ã‚ã‚“ãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’ã‚ã‚“ãŸã‚„ã¨åˆ†ã‹ã‚‹ã‚ˆã†ã«ã™ã‚‹ãŸã‚ã®åå‰ã‚„ã§ã€‚アルファベット(a~z, A~Z)ã€æ•°å—(0~9)ã€ãれã¨ã‚¢ãƒ³ãƒ€ãƒ¼ãƒãƒ¼(_)ãŒä½¿ã£ã¦è€ƒãˆã¦ãªã€‚ã“ã®åå‰ã¯å¾Œã‹ã‚‰å¤‰æ›´ã™ã‚‹ã“ã¨ã¯ã§ãã¸ã‚“ã‹ã‚‰ã¡ã‚ƒã‚“ã¨è€ƒãˆã‚‹ã‚“ã‚„ã§ã€‚" +aiChanMode: "è—モードやã§" +keepCw: "CWã‚’ç¶æŒã™ã‚‹ã§" +pubSub: "Pub/Subã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" +lastCommunication: "ç›´è¿‘ã®é€šä¿¡" +resolved: "解決ã—ãŸã§" +unresolved: "ã¾ã 解決ã—ã¦ãªã„ã§" +breakFollow: "フォãƒãƒ¯ãƒ¼ã‚’解除ã™ã‚‹ã§" +itsOn: "オンã«ãªã£ã¨ã‚‹ã‚ˆ" hide: "éš ã™" searchByGoogle: "探ã™" indefinitely: "無期é™" file: "ファイル" +requireAdminForView: "ã“れを見るã«ã¯ç®¡ç†è€…アカウントã§ãƒã‚°ã‚¤ãƒ³ã—ã¨ã‚‰ãªã‚ã‹ã‚“ã§ã€‚" +isSystemAccount: "システムãŒè‡ªå‹•ã§ä½œæˆãƒ»ç®¡ç†ã—ã¨ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚„ã§ã€‚" +typeToConfirm: "ã“ã®æ“作をやるんãªã‚‰ {x} ã¨å…¥åŠ›ã—ã¦ãªãƒ¼" +deleteAccount: "アカウント削除ã™ã‚‹ã§" +document: "ドã‚ュメント" +numberOfPageCache: "ページã‚ャッシュ数やã§" +numberOfPageCacheDescription: "増やã™ã¨ä½¿ã„ã‚„ã™ããªã‚‹ã€è² è·ã¨ãƒ¡ãƒ¢ãƒªä½¿ç”¨é‡ãŒå¢—ãˆã¦ãã§ã€‚一長一çŸã‚„ãªã€‚" +logoutConfirm: "ãƒã‚°ã‚¢ã‚¦ãƒˆã—ã¾ã£ã‹ï¼Ÿ" +lastActiveDate: "最後ã«ä½¿ã£ãŸæ—¥æ™‚" +statusbar: "ステータスãƒãƒ¼" +pleaseSelect: "é¸æŠžã—ãŸã£ã¦ã‚„ー" +reverse: "å転" colored: "色付ã" +refreshInterval: "æ›´æ–°é–“éš”" +label: "ラベル" +type: "タイプ" +speed: "速度" +slow: "é…ã„" +fast: "速ã„" +sensitiveMediaDetection: "センシティブãªãƒ¡ãƒ‡ã‚£ã‚¢ã®æ¤œå‡º" +localOnly: "ãƒãƒ¼ã‚«ãƒ«ã®ã¿" +remoteOnly: "リモートã®ã¿" +failedToUpload: "アップãƒãƒ¼ãƒ‰ã«å¤±æ•—ã—ãŸã§" +cannotUploadBecauseInappropriate: "ä¸é©åˆ‡ãªå†…容をå«ã‚€ã‹ã‚‚ã—れã¸ã‚“ã£ã¦åˆ¤å®šã•れãŸã§ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã§ãã¾ã¸ã‚“。" +cannotUploadBecauseNoFreeSpace: "ドライブã®ç©ºã容é‡ãŒç„¡ã„ã§ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã§ãã¾ã¸ã‚“。" +beta: "ベータ" +enableAutoSensitive: "自動NSFW判定" +enableAutoSensitiveDescription: "使ãˆã‚‹æ™‚ã¯ã€æ©Ÿæ¢°å¦ç¿’を使ã£ã¦è‡ªå‹•ã§ãƒ¡ãƒ‡ã‚£ã‚¢ã«NSFWフラグをè¨å®šã™ã‚‹ã§ã€‚ã“ã®æ©Ÿèƒ½ã‚’オフã«ã—ã¦ã‚‚ã€ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ã‚ˆã£ã¦ã¯è‡ªå‹•ã§è¨å®šã•れるã“ã¨ãŒã‚ã‚‹ã§ã€‚" +activeEmailValidationDescription: "ユーザーã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®ãƒãƒªãƒ‡ãƒ¼ã‚·ãƒ§ãƒ³ã‚’ã€æ¨ã¦ã‚¢ãƒ‰ã‹ã©ã†ã‹ã‚„実際ã«é€šä¿¡å¯èƒ½ã‹ã©ã†ã‹ã¨ã‹ã‚’判定ã—ã¦ç©æ¥µçš„ã«è¡Œã†ã§ã€‚オフã«ã™ã‚‹ã¨å˜ã«æ–‡å—列ã¨ã—ã¦æ£ã—ã„ã‹ã©ã†ã‹ã ã‘ãƒã‚§ãƒƒã‚¯ã™ã‚‹ã§ã€‚" +navbar: "ナビゲーションãƒãƒ¼" +shuffle: "シャッフルã™ã‚‹ã§" +account: "アカウント" +move: "移動ã™ã‚‹ã§" +_sensitiveMediaDetection: + description: "機械å¦ç¿’を使ã£ã¦è‡ªå‹•ã§ã‚»ãƒ³ã‚·ãƒ†ã‚£ãƒ–ãªãƒ¡ãƒ‡ã‚£ã‚¢ã‚’検出ã—ã¦ã€ãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã«å½¹ç«‹ã¦ã‚‹ã“ã¨ãŒã§ãã‚‹ã§ã€‚サーãƒãƒ¼ã®è² è·ãŒå°‘ã—増ãˆã¦ã¾ã†ãªã‚。" + sensitivity: "検出感度やã§" + sensitivityDescription: "感度を低ãã™ã‚‹ã¨ã€èª¤æ¤œçŸ¥(å½é™½æ€§)ãŒæ¸›ã‚‹ã§ã€‚感度を高ãã™ã‚‹ã¨ã€æ¤œçŸ¥æ¼ã‚Œ(å½é™°æ€§)ãŒæ¸›ã‚‹ã§ã€‚" + setSensitiveFlagAutomatically: "NSFWフラグをè¨å®šã™ã‚‹ã§" + setSensitiveFlagAutomaticallyDescription: "ã“ã®è¨å®šã‚’オフã«ã—ã¦ã‚‚内部的ã«åˆ¤å®šçµæžœã¯ä¿æŒã•れるã§ã€‚" +_ffVisibility: + public: "公開" _ad: back: "戻る" _gallery: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 7959a3dc31..168fa9d65e 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -52,6 +52,7 @@ searchUser: "ì‚¬ìš©ìž ê²€ìƒ‰" reply: "답글" loadMore: "ë” ë³´ê¸°" showMore: "ë” ë³´ê¸°" +showLess: "닫기" youGotNewFollower: "새로운 팔로워가 있습니다" receiveFollowRequest: "새로운 팔로우 ìš”ì²ì´ 있습니다" followRequestAccepted: "팔로우가 수ë½ë˜ì—ˆìŠµë‹ˆë‹¤" @@ -889,6 +890,7 @@ activeEmailValidationDescription: "ìœ ì €ê°€ ìž…ë ¥í•œ ë©”ì¼ ì£¼ì†Œê°€ ì¼íšŒìš navbar: "네비게ì´ì…˜ ë°”" shuffle: "셔플" account: "ê³„ì •" +move: "ì´ë™" _sensitiveMediaDetection: description: "ê¸°ê³„í•™ìŠµì„ í†µí•´ ìžë™ìœ¼ë¡œ 민ê°í•œ 미디어를 íƒì§€í•˜ì—¬, 모ë”ë ˆì´ì…˜ì— ì°¸ê³ í• ìˆ˜ 있ë„ë¡ í•©ë‹ˆë‹¤. ì„œë²„ì˜ ë¶€í•˜ë¥¼ 약간 ì¦ê°€ì‹œí‚µë‹ˆë‹¤." sensitivity: "íƒì§€ 민ê°ë„" @@ -1022,6 +1024,8 @@ _mfm: sparkleDescription: "ë°˜ì§ì´ëŠ” íŒŒí‹°í´ íš¨ê³¼ë¥¼ 추가합니다." rotate: "íšŒì „" rotateDescription: "ì§€ì •í•œ ê°ë„로 íšŒì „ì‹œí‚µë‹ˆë‹¤." + plain: "í‰ë¬¸" + plainDescription: "ì•ˆì— ìžˆëŠ” MFM êµ¬ë¬¸ì„ ëª¨ë‘ ë¬´ì‹œí•˜ê³ í‰ë¬¸ìœ¼ë¡œ 표시합니다." _instanceTicker: none: "ë³´ì´ì§€ 않ìŒ" remote: "리모트 ìœ ì €ì—게만 ë³´ì´ê¸°" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 41ba8fdd35..f0470395fb 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -52,6 +52,7 @@ searchUser: "Wyszukiwanie użytkowników" reply: "Odpowiedz" loadMore: "ZaÅ‚aduj wiÄ™cej" showMore: "ZaÅ‚aduj wiÄ™cej" +showLess: "Zamknij" youGotNewFollower: "ZaobserwowaÅ‚(a) CiÄ™" receiveFollowRequest: "Otrzymano proÅ›bÄ™ o możliwość obserwacji" followRequestAccepted: "Zaakceptowano proÅ›bÄ™ o możliwość obserwacji" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 046c307b17..054e845b73 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -52,6 +52,7 @@ searchUser: "Pesquisar utilizador" reply: "Responder" loadMore: "Carregar mais" showMore: "Ver mais" +showLess: "Fechar" youGotNewFollower: "Você tem um novo seguidor" receiveFollowRequest: "Pedido de seguimento recebido" followRequestAccepted: "Pedido de seguir aceito" diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 6f0553b223..8254994b23 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -52,6 +52,7 @@ searchUser: "Caută un utilizator" reply: "Răspunde" loadMore: "Incarcă mai mult" showMore: "Arată mai mult" +showLess: "ÃŽnchide" youGotNewFollower: "te-a urmărit" receiveFollowRequest: "Cerere de urmărire primită" followRequestAccepted: "Cerere de urmărire acceptată" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index a22cacca3b..2a6988e9b4 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -52,6 +52,7 @@ searchUser: "ПоиÑк людей" reply: "Ответить" loadMore: "Показать еще" showMore: "Показать еще" +showLess: "Закрыть" youGotNewFollower: "Ðовый подпиÑчик" receiveFollowRequest: "Получен Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подпиÑку" followRequestAccepted: "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подпиÑку принÑÑ‚" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 4fbdc1cb12..43129edcf0 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -52,6 +52,7 @@ searchUser: "HľadaÅ¥ použÃvateľov" reply: "OdpovedaÅ¥" loadMore: "ZobraziÅ¥ viac" showMore: "ZobraziÅ¥ viac" +showLess: "ZavrieÅ¥" youGotNewFollower: "Máte nového sledujúceho" receiveFollowRequest: "ŽiadosÅ¥ o sledovanie prijatá" followRequestAccepted: "ŽiadosÅ¥ o sledovanie akceptovaná" @@ -561,6 +562,7 @@ author: "Autor" leaveConfirm: "Máte neuložené zmeny. Chcete ich zahodiÅ¥?" manage: "Administrácia" plugins: "Pluginy" +preferencesBackups: "Zálohy nastavenÃ" deck: "Deck" useBlurEffectForModal: "PoužiÅ¥ efekt rozmazania na okná" useFullReactionPicker: "PoužiÅ¥ plnú veľkosÅ¥ výberu reakciÃ" @@ -936,6 +938,24 @@ _plugin: install: "InÅ¡talova pluginy" installWarn: "ProsÃm neinÅ¡talujte nedôveryhodné pluginy." manage: "Spravovanie pluginov" +_preferencesBackups: + list: "Vytvorené zálohy" + saveNew: "UložiÅ¥ novú" + loadFile: "NahraÅ¥ súbor" + apply: "PoužiÅ¥ na toto zariadenie" + save: "UložiÅ¥" + inputName: "Názov zálohy" + cannotSave: "Nedá sa uložiÅ¥" + nameAlreadyExists: "Záloha s názvom \"{name}\" už existuje. Zadajte iný názov." + applyConfirm: "Chcete použiÅ¥ zálohu '{name}' na aktuálne zariadenie? Aktuálne nastavenia zariadenia sa stratia." + saveConfirm: "Chcete prepÃsaÅ¥ {name}?" + deleteConfirm: "Naozaj chcete odstrániÅ¥ \"{name}\"?" + renameConfirm: "Chcete zmeniÅ¥ \"{old}\" na \"{new}\"?" + noBackups: "Nie je k dispozÃcii žiadna záloha. \"UložiÅ¥ novú\" umožňuje uložiÅ¥ aktuálnu konfiguráciu zariadenia na server." + createdAt: "Dátum vytvorenia: {date} {time}" + updatedAt: "Dátum úpravy: {date} {time}" + cannotLoad: "Nedá sa nahraÅ¥" + invalidFile: "Neplatný formát súboru" _registry: scope: "OblasÅ¥" key: "KľúÄ" @@ -1019,6 +1039,8 @@ _mfm: sparkleDescription: "Obsahu dodá trblietajúci efekt." rotate: "OtáÄaÅ¥" rotateDescription: "OtoÄà obsah o urÄitý uhol." + plain: "ObyÄajné" + plainDescription: "Bez akejkoľvej syntaxe" _instanceTicker: none: "Nikdy nezobrazovaÅ¥" remote: "ZobraziÅ¥ pre vzdialených použÃvateľov" @@ -1252,6 +1274,7 @@ _widgets: activity: "Aktivita" photos: "Fotky" digitalClock: "Digitálne hodiny" + unixClock: "UNIX Äas" federation: "Federácia" instanceCloud: "Cloud serverov" postForm: "NapÃsaÅ¥ poznámku" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 208c7c8510..3f68d36417 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -203,6 +203,7 @@ done: "Klar" processing: "Bearbetar..." preview: "Förhandsvisning" default: "Standard" +defaultValueIs: "Standard: {value}" noCustomEmojis: "Det finns ingen emoji" noJobs: "Det finns inga jobb" federating: "Federerar" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 610a5da3d0..6c731ea6e7 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -52,6 +52,7 @@ searchUser: "ค้นหาผู้ใช้งาน" reply: "ตà¸à¸šà¸à¸¥à¸±à¸š" loadMore: "โหลดเพิ่มเติม" showMore: "à¹à¸ªà¸”งเพิ่มเติม" +showLess: "ปิด" youGotNewFollower: "ได้ติดตามคุณ" receiveFollowRequest: "คำขà¸à¸œà¸¹à¹‰à¸•ิดตามที่ได้รับ" followRequestAccepted: "ผู้ติดตามได้ตà¸à¸šà¸£à¸±à¸šà¸„ำขà¸à¸£à¹‰à¸à¸‡à¸‚à¸à¸‡à¸„ุณà¹à¸¥à¹‰à¸§" @@ -835,10 +836,83 @@ themeColor: "à¸à¸´à¸™à¸ªà¹à¸•นซ์ Ticker Color" size: "ขนาด" numberOfColumn: "จำนวนคà¸à¸¥à¸±à¸¡à¸™à¹Œ" searchByGoogle: "ค้นหา" +instanceDefaultLightTheme: "ธีมสว่างค่าเริ่มต้นสำหรับà¸à¸´à¸™à¸ªà¹à¸•นซ์" +instanceDefaultDarkTheme: "ธีมมืดค่าเริ่มต้นà¸à¸´à¸™à¸ªà¹à¸•นซ์" +instanceDefaultThemeDescription: "ป้à¸à¸™à¸£à¸«à¸±à¸ªà¸˜à¸µà¸¡à¹ƒà¸™à¸£à¸¹à¸›à¹à¸šà¸šà¸à¸à¸šà¹€à¸ˆà¹‡à¸à¸•์" +mutePeriod: "ระยะเวลาปิดเสียง" +indefinitely: "ตลà¸à¸”ไป" +tenMinutes: "10 นาที" +oneHour: "1 ชั่วโมง" +oneDay: "1 วัน" +oneWeek: "1 สัปดาห์" +reflectMayTakeTime: "à¸à¸²à¸ˆà¸ˆà¸³à¹€à¸›à¹‡à¸™à¸•้à¸à¸‡à¹ƒà¸Šà¹‰à¹€à¸§à¸¥à¸²à¸ªà¸±à¸à¸£à¸°à¸¢à¸°à¸«à¸™à¸¶à¹ˆà¸‡à¸ˆà¸¶à¸‡à¸ˆà¸°à¹€à¸«à¹‡à¸™à¹à¸ªà¸”งผลได้นะ" +failedToFetchAccountInformation: "ไม่สามารถเรียà¸à¸”ึงข้à¸à¸¡à¸¹à¸¥à¸šà¸±à¸à¸Šà¸µà¹„ด้" +rateLimitExceeded: "เà¸à¸´à¸™à¸‚ีดจำà¸à¸±à¸”à¸à¸±à¸•รา" +cropImage: "ครà¸à¸šà¸•ัดรูปภาพ" +cropImageAsk: "คุณต้à¸à¸‡à¸à¸²à¸£à¸„รà¸à¸šà¸•ัดรูปภาพนี้à¸à¸¢à¹ˆà¸²à¸‡à¸‡à¸±à¹‰à¸™à¸«à¸£à¸·à¸?" file: "ไฟล์" +recentNHours: "ล่าสุด {n} ชั่วโมงที่à¹à¸¥à¹‰à¸§" +recentNDays: "ล่าสุด {n} วันที่à¹à¸¥à¹‰à¸§" +noEmailServerWarning: "ไม่ได้à¸à¸³à¸«à¸™à¸”ค่าเซิร์ฟเวà¸à¸£à¹Œà¸à¸µà¹€à¸¡à¸¥à¸™à¸µà¹‰" +thereIsUnresolvedAbuseReportWarning: "มีรายงานที่ยังไม่ได้à¹à¸à¹‰à¹„ข" +recommended: "à¹à¸™à¸°à¸™à¸³" +check: "ตรวจสà¸à¸š" +driveCapOverrideLabel: "เปลี่ยนความจุขà¸à¸‡à¹„ดรฟ์สำหรับผู้ใช้รายนี้" +driveCapOverrideCaption: "รีเซ็ตความจุเป็นค่าเริ่มต้นโดยà¸à¸²à¸£à¸›à¹‰à¸à¸™à¸„่าเป็น 0 หรืภต่ำà¸à¸§à¹ˆà¸²" +requireAdminForView: "คุณจำเป็นต้à¸à¸‡à¹€à¸‚้าสู่ระบบด้วยบัà¸à¸Šà¸µà¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸šà¸šà¹€à¸žà¸·à¹ˆà¸à¹€à¸‚้าดูสิ่งนี้" +isSystemAccount: "บัà¸à¸Šà¸µà¸—ี่ถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¸¡à¸²à¸™à¸±à¹‰à¸™ à¹à¸¥à¸°à¸–ูà¸à¸”ำเนินà¸à¸²à¸£à¹‚ดยà¸à¸±à¸•โนมัติด้วยระบบ" +typeToConfirm: "โปรดป้à¸à¸™ {x} เพื่à¸à¸¢à¸·à¸™à¸¢à¸±à¸™" +deleteAccount: "ลบบัà¸à¸Šà¸µ" +document: "เà¸à¸à¸ªà¸²à¸£" +numberOfPageCache: "จำนวนหน้าเพจที่à¹à¸„ช" +numberOfPageCacheDescription: "à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸ˆà¸³à¸™à¸§à¸™à¸™à¸µà¹‰à¸ˆà¸°à¸Šà¹ˆà¸§à¸¢à¹€à¸žà¸´à¹ˆà¸¡à¸„วามสะดวà¸à¹ƒà¸«à¹‰à¸à¸±à¸šà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸‡à¸²à¸™ à¹à¸•่จะทำให้เซิร์ฟเวà¸à¸£à¹Œà¹‚หลดมาà¸à¸‚ึ้นà¹à¸¥à¸°à¸•้à¸à¸‡à¹ƒà¸Šà¹‰à¸«à¸™à¹ˆà¸§à¸¢à¸„วามจำมาà¸à¸‚ึ้นà¸à¸µà¸à¸”้วย" +logoutConfirm: "คุณà¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸•้à¸à¸‡à¸à¸²à¸£à¸à¸à¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸š?" +lastActiveDate: "ใช้งานล่าสุดที่" +statusbar: "ไà¸à¸„à¸à¸™à¸šà¸™à¹à¸–บสถานะ" +pleaseSelect: "ตัวเลืà¸à¸" +reverse: "ย้à¸à¸™à¸à¸¥à¸±à¸š" +colored: "สี" +refreshInterval: "รà¸à¸šà¸à¸²à¸£à¸à¸±à¸žà¹€à¸”ต" +label: "ป้ายชื่à¸" +type: "รูปà¹à¸šà¸š" +speed: "ความเร็ว" +slow: "ช้า" +fast: "เร็ว" +sensitiveMediaDetection: "à¸à¸²à¸£à¸•รวจจับขà¸à¸‡à¸ªà¸·à¹ˆà¸ NSFW" +localOnly: "เฉพาะท้à¸à¸‡à¸–ิ่น" +remoteOnly: "รีโมทเท่านั้น" +failedToUpload: "à¸à¸²à¸£à¸à¸±à¸›à¹‚หลดล้มเหลว" +cannotUploadBecauseInappropriate: "ไม่สามารถà¸à¸±à¸›à¹‚หลดไฟล์นี้ได้เนื่à¸à¸‡à¸ˆà¸²à¸à¸£à¸°à¸šà¸šà¸•รวจพบบางส่วนขà¸à¸‡à¹„ฟล์ว่านี้à¸à¸²à¸ˆà¸ˆà¸°à¹€à¸›à¹‡à¸™ NSFW" +cannotUploadBecauseNoFreeSpace: "à¸à¸²à¸£à¸à¸±à¸›à¹‚หลดนั้นล้มเหลวเนื่à¸à¸‡à¸ˆà¸²à¸à¹„ม่มีความจุขà¸à¸‡à¹„ดรฟ์" +beta: "เบต้า" +enableAutoSensitive: "ทำเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢ NSFW à¸à¸±à¸•โนมัติ" +enableAutoSensitiveDescription: "à¸à¸™à¸¸à¸à¸²à¸•ให้ตรวจหาà¹à¸¥à¸°à¸—ำเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢à¸ªà¸·à¹ˆà¸ NSFW โดยà¸à¸±à¸•โนมัติผ่านà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¸‚à¸à¸‡à¹€à¸„รื่à¸à¸‡à¸«à¸²à¸à¹€à¸›à¹‡à¸™à¹„ปได้ à¹à¸¡à¹‰à¸§à¹ˆà¸²à¸•ัวเลืà¸à¸à¸™à¸µà¹‰à¸ˆà¸°à¸–ูà¸à¸›à¸´à¸”ใช้งาน à¹à¸•่à¸à¹‡à¸ªà¸²à¸¡à¸²à¸£à¸–เปิดใช้งานได้ทั้งà¸à¸´à¸™à¸ªà¹à¸•นซ์นี้" +activeEmailValidationDescription: "เปิดใช้งานà¸à¸²à¸£à¸•รวจสà¸à¸šà¸—ี่à¸à¸¢à¸¹à¹ˆà¸à¸µà¹€à¸¡à¸¥à¹ƒà¸«à¹‰à¸¡à¸µà¸„วามเข้มงวดยิ่งขึ้น ซึ่งà¸à¸²à¸ˆà¸ˆà¸°à¸£à¸§à¸¡à¹„ปถึงà¸à¸²à¸£à¸•รวจสà¸à¸šà¸—ี่à¸à¸¢à¸¹à¹ˆà¸à¸µà¹€à¸¡à¸¥à¹Œà¸—ี่ใช้à¹à¸¥à¹‰à¸§à¸—ิ้งà¹à¸¥à¸°à¹‚ดยให้พิจารณาว่าสามารถสื่à¸à¸ªà¸²à¸£à¸”้วยได้หรืà¸à¹„ม่ เมื่à¸à¹„ม่เลืà¸à¸à¸£à¸°à¸šà¸šà¸ˆà¸°à¸•รวจสà¸à¸šà¹€à¸‰à¸žà¸²à¸°à¸£à¸¹à¸›à¹à¸šà¸šà¸‚à¸à¸‡à¸à¸µà¹€à¸¡à¸¥à¹€à¸—่านั้น" +navbar: "à¹à¸–บนำทาง" +shuffle: "สลับ" account: "บัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰" +move: "ย้าย" +_sensitiveMediaDetection: + description: "ลดความพยายามในà¸à¸²à¸£à¸”ูà¹à¸¥à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸à¸£à¹Œà¸œà¹ˆà¸²à¸™à¸à¸²à¸£à¸ˆà¸”จำสื่ภNSFW โดยà¸à¸±à¸•โนมัติผ่านà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸™à¸£à¸¹à¹‰à¸‚à¸à¸‡à¹€à¸„รื่à¸à¸‡ à¸à¸²à¸£à¸—ำสิ่งนี้à¸à¸²à¸ˆà¸ˆà¸°à¹€à¸žà¸´à¹ˆà¸¡à¸ าระบนเซิร์ฟเวà¸à¸£à¹Œà¹€à¸¥à¹‡à¸à¸™à¹‰à¸à¸¢" + sensitivity: "à¸à¸²à¸£à¸•รวจจับความไว" + sensitivityDescription: "à¸à¸²à¸£à¸¥à¸”ความไวนั้นจะนำไปสู่à¸à¸²à¸£à¸•รวจจับที่ผิดพลาดน้à¸à¸¢à¸¥à¸‡ (ผลบวà¸à¸—ี่ผิดพลาด) à¹à¸•่ในขณะที่à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸™à¸±à¹‰à¸™à¸ˆà¸°à¸™à¸³à¹„ปสู่à¸à¸²à¸£à¸•รวจหาที่พลาดน้à¸à¸¢à¸¥à¸‡ (ผลลบเท็จ)" + setSensitiveFlagAutomatically: "ทำเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢à¸§à¹ˆà¸²à¹€à¸›à¹‡à¸™ NSFW" + setSensitiveFlagAutomaticallyDescription: "ผลลัพธ์ขà¸à¸‡à¸à¸²à¸£à¸•รวจจับภายในนั้นจะยังคงà¸à¸¢à¸¹à¹ˆ ถึงà¹à¸¡à¹‰à¸§à¹ˆà¸²à¸ˆà¸°à¸›à¸´à¸”ตัวเลืà¸à¸à¸™à¸µà¹‰" + analyzeVideos: "เปิดใช้งานวิเคราะห์ขà¸à¸‡à¸§à¸´à¸”ีโà¸" + analyzeVideosDescription: "à¸à¸²à¸£à¸§à¸´à¹€à¸„ราะห์วิดีโà¸à¸™à¸à¸à¹€à¸«à¸™à¸·à¸à¸ˆà¸²à¸à¸£à¸¹à¸›à¸ าพนั้น à¸à¸²à¸£à¸—ำสิ่งนี้จะทำให้เพิ่มภาระบนเซิร์ฟเวà¸à¸£à¹Œà¹€à¸¥à¹‡à¸à¸™à¹‰à¸à¸¢" +_emailUnavailable: + used: "ที่à¸à¸¢à¸¹à¹ˆà¸à¸µà¹€à¸¡à¸¥à¸™à¸µà¹‰à¹„ด้ถูà¸à¹ƒà¸Šà¹‰à¹„ปà¹à¸¥à¹‰à¸§" + format: "รูปà¹à¸šà¸šà¸‚à¸à¸‡à¸—ี่à¸à¸¢à¸¹à¹ˆà¸à¸µà¹€à¸¡à¸¥à¸™à¸µà¹‰à¹„ม่ถูà¸à¸•้à¸à¸‡" + disposable: "ที่à¸à¸¢à¸¹à¹ˆà¸à¸µà¹€à¸¡à¸¥à¸—ี่ใช้à¹à¸¥à¹‰à¸§à¸—ิ้งนั้นไม่สามารถใช้ได้" + mx: "เซิร์ฟเวà¸à¸£à¹Œà¸à¸µà¹€à¸¡à¸¥à¸™à¸µà¹‰à¹„ม่ถูà¸à¸•้à¸à¸‡" + smtp: "เซิร์ฟเวà¸à¸£à¹Œà¸à¸µà¹€à¸¡à¸¥à¸™à¸µà¹‰à¹„ม่มีà¸à¸²à¸£à¸•à¸à¸šà¸ªà¸™à¸à¸‡" _ffVisibility: public: "เผยà¹à¸žà¸£à¹ˆ" + followers: "ปราà¸à¸à¹ƒà¸«à¹‰à¹à¸à¹ˆà¸œà¸¹à¹‰à¸•ิดตามเท่านั้น" + private: "ส่วนตัว" +_signup: + almostThere: "เà¸à¸·à¸à¸šà¸ˆà¸°à¸¡à¸µ" + emailAddressInfo: "โปรดà¸à¸£à¸à¸à¸à¸µà¹€à¸¡à¸¥à¸‚à¸à¸‡à¸„ุณ มันจะไม่เปิดเผยต่à¸à¸ªà¸²à¸˜à¸²à¸£à¸“ะ" _ad: back: "ย้à¸à¸™à¸à¸¥à¸±à¸š" _email: @@ -846,9 +920,22 @@ _email: title: "ได้ติดตามคุณ" _mfm: mention: "à¸à¸¥à¹ˆà¸²à¸§à¸–ึง" + centerDescription: "à¹à¸ªà¸”งผลเนื้à¸à¸«à¸²à¹€à¸›à¹‡à¸™à¸¨à¸¹à¸™à¸¢à¹Œà¸à¸¥à¸²à¸‡" + inlineCode: "โค้ด (à¸à¸´à¸™à¹„ลน์)" + inlineCodeDescription: "à¹à¸ªà¸”งผลà¸à¸²à¸£à¹€à¸™à¹‰à¸™à¹„วยาà¸à¸£à¸“์à¹à¸šà¸šà¸à¸´à¸™à¹„ลน์สำหรับโค้ด (โปรà¹à¸à¸£à¸¡)" + blockCode: "โค้ด (บล็à¸à¸)" + blockCodeDescription: "à¹à¸ªà¸”งผลà¸à¸²à¸£à¹€à¸™à¹‰à¸™à¹„วยาà¸à¸£à¸“์สำหรับโค้ดหลายบรรทัด (โปรà¹à¸à¸£à¸¡) ในบล็à¸à¸" + inlineMath: "คณิต (à¸à¸´à¸™à¹„ลน์)" + inlineMathDescription: "à¹à¸ªà¸”งผลสูตรคณิต (KaTeX) ในบรรทัด" + blockMath: "คณิต (บล็à¸à¸)" + blockMathDescription: "à¹à¸ªà¸”งผลสูตรคณิตหลายบรรทัด (KaTeX) ในบล็à¸à¸" quote: "à¸à¹‰à¸²à¸‡à¸„ำพูด" + quoteDescription: "à¹à¸ªà¸”งผลเนื้à¸à¸«à¸²à¹€à¸›à¹‡à¸™à¹ƒà¸šà¹€à¸ªà¸™à¸à¸£à¸²à¸„า" emoji: "à¸à¸³à¸«à¸™à¸”à¸à¸µà¹‚มจิเà¸à¸‡" + emojiDescription: "โดยล้à¸à¸¡à¸£à¸à¸šà¸Šà¸·à¹ˆà¸à¸à¸µà¹‚มจิที่à¸à¸³à¸«à¸™à¸”เà¸à¸‡à¸”้วยเครื่à¸à¸‡à¸«à¸¡à¸²à¸¢à¸—วิภาค จะสามารถà¹à¸ªà¸”งผลà¸à¸µà¹‚มจิที่à¸à¸³à¸«à¸™à¸”เà¸à¸‡à¹„ด้" search: "ค้นหา" + searchDescription: "à¹à¸ªà¸”งผลà¸à¸¥à¹ˆà¸à¸‡à¸„้นหาพร้à¸à¸¡à¸à¸±à¸šà¸‚้à¸à¸„วามที่ป้à¸à¸™à¹„ว้ล่วงหน้า" + flip: "พลิà¸" _theme: description: "รายละเà¸à¸µà¸¢à¸”" keys: diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 7b4d77548a..b696a58b95 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -52,6 +52,7 @@ searchUser: "Пошук кориÑтувачів" reply: "ВідповіÑти" loadMore: "Показати більше" showMore: "Показати більше" +showLess: "Закрити" youGotNewFollower: "Ðовий підпиÑник" receiveFollowRequest: "Отримано запит на підпиÑку" followRequestAccepted: "ПідпиÑка прийнÑта" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 4cc1c37f33..3cac0585a8 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -52,6 +52,7 @@ searchUser: "Tìm kiếm ngưá»i dùng" reply: "Trả lá»i" loadMore: "Tải thêm" showMore: "Xem thêm" +showLess: "Äóng" youGotNewFollower: "đã theo dõi bạn" receiveFollowRequest: "Äã yêu cầu theo dõi" followRequestAccepted: "Äã chấp nháºn yêu cầu theo dõi" @@ -561,6 +562,7 @@ author: "Tác giả" leaveConfirm: "Có những thay đổi chưa được lưu. Bạn có muốn bá» chúng không?" manage: "Quản lý" plugins: "Plugin" +preferencesBackups: "Sao lưu thiết láºp" deck: "Deck" undeck: "Bá» Deck" useBlurEffectForModal: "Sá» dụng hiệu ứng má» cho các há»™p thoại" @@ -890,6 +892,7 @@ activeEmailValidationDescription: "Cho phép xác minh địa chỉ email chặt navbar: "Thanh Ä‘iá»u hướng" shuffle: "Xáo trá»™n" account: "Tà i khoản cá»§a bạn" +move: "Di chuyển" _sensitiveMediaDetection: description: "Giảm ná»— lá»±c kiểm duyệt máy chá»§ thông qua việc tá»± động nháºn dạng media NSFW thông qua há»c máy. Äiá»u nà y sẽ là m tăng má»™t chút áp lá»±c trên máy chá»§." sensitivity: "Phát hiện nhạy cảm" @@ -940,6 +943,24 @@ _plugin: install: "Cà i đặt tiện Ãch" installWarn: "Vui lòng không cà i đặt những tiện Ãch đáng ngá»." manage: "Quản lý plugin" +_preferencesBackups: + list: "Tạo sao lưu" + saveNew: "Lưu bản sao lưu" + loadFile: "Nháºp táºp tin" + apply: "Ãp dụng lên thiết bị nà y" + save: "Lưu thay đổi" + inputName: "Nháºp tên bản sao lưu" + cannotSave: "Không thể lưu" + nameAlreadyExists: "Bản sao lưu \"{name}\" đã tồn tại. Xin nháºp tên khác." + applyConfirm: "Bạn có chắc muốn áp dụng bản sao lưu \"{name}\" cho thiết bị nà y? Thiết láºp hiện tại sẽ bị ghi đè." + saveConfirm: "Lưu bản sao lưu {name}?" + deleteConfirm: "Xóa bản sao lưu {name}?" + renameConfirm: "Äổi tên bản sao lưu \"{old}\" thà nh \"{new}\"?" + noBackups: "Chưa có bản sao lưu. Bạn có thể sao lưu thiết láºp trên máy chá»§ nà y bằng cách sá» dụng \"Tạo sao lưu\"." + createdAt: "Tạo và o: {time} {date}" + updatedAt: "Cáºp nháºt: {time} {date}" + cannotLoad: "Tải thất bại" + invalidFile: "Sai định dạng táºp tin" _registry: scope: "Phạm vi" key: "Mã" @@ -1023,6 +1044,8 @@ _mfm: sparkleDescription: "Là m cho ná»™i dung hiệu ứng hạt lấp lánh." rotate: "Xoay" rotateDescription: "Xoay ná»™i dung theo má»™t góc cụ thể." + plain: "ÄÆ¡n giản" + plainDescription: "Vô hiệu hóa má»i hiệu ứng MFM chứa trong hiệu ứng MFM nà y." _instanceTicker: none: "Không hiển thị" remote: "Hiện cho ngưá»i dùng từ máy chá»§ khác" @@ -1256,6 +1279,7 @@ _widgets: activity: "Hoạt động" photos: "Kho ảnh" digitalClock: "Äồng hồ số" + unixClock: "Äồng hồ UNIX" federation: "Liên hợp" instanceCloud: "Instance cloud" postForm: "Mẫu đăng" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 8c6c4b3582..182cebf5a5 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -52,6 +52,7 @@ searchUser: "æœç´¢ç”¨æˆ·" reply: "回å¤" loadMore: "查看更多" showMore: "查看更多" +showLess: "å…³é—" youGotNewFollower: "ä½ æœ‰æ–°çš„å…³æ³¨è€…" receiveFollowRequest: "您收到了关注请求" followRequestAccepted: "您的关注请求被通过了" @@ -483,13 +484,13 @@ showFeaturedNotesInTimeline: "在时间线上显示çƒé—¨æŽ¨è" objectStorage: "对象å˜å‚¨" useObjectStorage: "使用对象å˜å‚¨" objectStorageBaseUrl: "Base URL" -objectStorageBaseUrlDesc: "URLå‰ç¼€ï¼Œç”¨äºŽæž„é€ URL到对象(媒体)的引用,如果您使用的是CDN或åå‘代ç†ï¼Œè¯·æŒ‡å®šå…¶URL,å¦åˆ™è¯·æ ¹æ®æ‚¨ä½¿ç”¨çš„æœåŠ¡æŒ‡å®šå¯å…¬å¼€è®¿é—®çš„地å€ã€‚例如“https://<bucket>.s3.amazonaws.comâ€ç”¨äºŽAWS S3,“https://storage.googleapis.com/<bucket>â€ç”¨äºŽGCS" +objectStorageBaseUrlDesc: "用于引用的URL。如果您æ£åœ¨ä½¿ç”¨CDN或åå‘代ç†ï¼Œè¯·æŒ‡å®šå…¶URL,例如S3:“https://<bucket>.s3.amazonaws.comâ€ï¼ŒGCS:“https://storage.googleapis.com/<bucket>â€" objectStorageBucket: "å˜å‚¨æ¡¶" objectStorageBucketDesc: "请指定使用的对象å˜å‚¨æœåŠ¡çš„å˜å‚¨æ¡¶å称。" objectStoragePrefix: "å‰ç¼€" objectStoragePrefixDesc: "文件将å˜å‚¨åœ¨æ¤å‰ç¼€çš„目录下。" objectStorageEndpoint: "端点" -objectStorageEndpointDesc: "å¦‚æžœä½ å¸Œæœ›ä½¿ç”¨AWS S3请留空。å¦åˆ™è¯·æ ¹æ®ä½ 使用的æœåŠ¡æ¥è¿›è¡Œè®¾ç½®ï¼ŒæŒ‡å®šç«¯ç‚¹å½¢å¼ä¸ºâ€œ<host>â€æˆ–“<host>:<port>â€ã€‚" +objectStorageEndpointDesc: "å¦‚æžœä½ ä½¿ç”¨AWS S3请留空。å¦åˆ™è¯·æ ¹æ®ä½ 使用的æœåŠ¡å•†çš„è¯´æ˜Žæ¥è¿›è¡Œè®¾ç½®ï¼ŒæŒ‡å®šç«¯ç‚¹å½¢å¼ä¸ºâ€œ<host>â€æˆ–“<host>:<port>â€ã€‚" objectStorageRegion: "å¯ç”¨åŒº" objectStorageRegionDesc: "指定一个å¯ç”¨åŒºï¼Œä¾‹å¦‚“xx-east-1â€ã€‚ 如果您的对象å˜å‚¨æœåŠ¡æ²¡æœ‰å¯ç”¨åŒºæ¦‚念,请将其留空或填写“us-east-1â€ã€‚" objectStorageUseSSL: "使用SSL" @@ -561,6 +562,7 @@ author: "作者" leaveConfirm: "å˜åœ¨æœªä¿å˜çš„æ›´æ”¹ã€‚è¦æ”¾å¼ƒæ›´æ”¹å—?" manage: "管ç†" plugins: "æ’ä»¶" +preferencesBackups: "备份设置" deck: "Deck" undeck: "å–æ¶ˆDeck" useBlurEffectForModal: "å¯¹è¯æ¡†ä½¿ç”¨æ¨¡ç³Šæ•ˆæžœ" @@ -846,6 +848,7 @@ oneDay: "1天" oneWeek: "1周" reflectMayTakeTime: "å¯èƒ½éœ€è¦ä¸€äº›æ—¶é—´æ‰èƒ½ä½“现出效果。" failedToFetchAccountInformation: "获å–账户信æ¯å¤±è´¥" +rateLimitExceeded: "已超éŽé€Ÿçއé™åˆ¶" cropImage: "剪è£å›¾åƒ" cropImageAsk: "是å¦è¦è£å‰ªå›¾åƒï¼Ÿ" file: "文件" @@ -855,6 +858,7 @@ noEmailServerWarning: "电å邮件æœåŠ¡å™¨æœªè®¾ç½®ã€‚" thereIsUnresolvedAbuseReportWarning: "有未解决的报告" recommended: "推è" check: "检查" +driveCapOverrideLabel: "變更æ¤ç”¨æˆ¶çš„雲端硬碟容é‡ä¸Šé™" driveCapOverrideCaption: "设定为 0 以下则会解除æ¤é™åˆ¶ã€‚" requireAdminForView: "需è¦ä½¿ç”¨ç®¡ç†å‘˜è´¦æˆ·ç™»å½•æ‰èƒ½æŸ¥çœ‹ã€‚" isSystemAccount: "该账å·ç”±ç³»ç»Ÿè‡ªåŠ¨åˆ›å»ºå’Œç®¡ç†ã€‚" @@ -883,9 +887,12 @@ cannotUploadBecauseInappropriate: "å› ä¸ºå¯èƒ½å«æœ‰ä¸é€‚å®œçš„å†…å®¹ï¼Œæ— æ³• cannotUploadBecauseNoFreeSpace: "å› ä¸ºå·²æ— å¯ç”¨ç©ºé—´ï¼Œæ— æ³•ä¸Šä¼ ã€‚" beta: "测试" enableAutoSensitive: "自动 NSFW 识别" +enableAutoSensitiveDescription: "如果å¯ç”¨ï¼Œè¯·ä½¿ç”¨æœºå™¨å¦ä¹ 在媒体上自动设置 NSFW æ ‡å¿—ã€‚å³ä½¿å…³é—æ¤åŠŸèƒ½ï¼Œä¹Ÿå¯èƒ½ä¼šæ ¹æ®å®žä¾‹è‡ªåŠ¨è®¾ç½®ã€‚" +activeEmailValidationDescription: "积æžåœ°éªŒè¯ç”¨æˆ·çš„电å邮件地å€ï¼Œåˆ¤æ–它是一次性的电å邮件地å€ï¼Œè¿˜æ˜¯å¯ä»¥å®žé™…通信的地å€ã€‚关闿—¶ï¼Œåˆ™åªæ£€æŸ¥å—ç¬¦ä¸²æ˜¯å¦æ£ç¡®ã€‚" navbar: "导航æ " shuffle: "éšæœº" account: "账户" +move: "移动" _sensitiveMediaDetection: description: "å¯ä»¥ä½¿ç”¨æœºå™¨å¦ä¹ æŠ€æœ¯è‡ªåŠ¨æ£€æµ‹æ•æ„Ÿåª’ä½“ï¼Œä»¥ä¾¿è¿›è¡Œå®¡æ ¸ã€‚æœåŠ¡å™¨è´Ÿè½½å°†ç•¥å¾®å¢žåŠ ã€‚" sensitivity: "æ£€æµ‹æ•æ„Ÿåº¦" @@ -936,6 +943,24 @@ _plugin: install: "安装æ’ä»¶" installWarn: "请ä¸è¦å®‰è£…ä¸å¯ä¿¡çš„æ’ä»¶ã€‚" manage: "ç®¡ç†æ’ä»¶..." +_preferencesBackups: + list: "已创建的备份" + saveNew: "å¦å˜ä¸º" + loadFile: "导入文件" + apply: "应用于本设备" + save: "è¦†ç›–å˜æ¡£" + inputName: "请输入备份的åç§°" + cannotSave: "æ— æ³•ä¿å˜" + nameAlreadyExists: "备份åç§°\"{name}\"å·²ç»å˜åœ¨ï¼Œè¯·æŒ‡å®šå…¶ä»–å称。" + applyConfirm: "您是å¦è¦å°†å¤‡ä»½\"{name}\"应用到当å‰è®¾å¤‡ä¸Šï¼Ÿå½“å‰è®¾å¤‡çŽ°æœ‰é…置将被丢弃。" + saveConfirm: "您确定è¦è¦†ç›–ä¿å˜ {name} å—?" + deleteConfirm: "您确定è¦åˆ 除 {name} å—?" + renameConfirm: "æ‚¨ç¡®å®šè¦æŠŠâ€œ{old}â€æ”¹ä¸ºâ€œ{new}â€å—?" + noBackups: "当剿²¡æœ‰å¤‡ä»½ï¼Œâ€œå¦å˜ä¸ºâ€å…许您在æœåŠ¡å™¨ä¸Šä¿å˜å½“å‰å®¢æˆ·ç«¯çš„é…置。" + createdAt: "创建日期:{date} {time}" + updatedAt: "更新日期:{date} {time}" + cannotLoad: "æ— æ³•åŠ è½½" + invalidFile: "æ— æ•ˆçš„çš„æ–‡ä»¶æ ¼å¼ã€‚" _registry: scope: "范围" key: "主è¦" @@ -1019,6 +1044,8 @@ _mfm: sparkleDescription: "æ·»åŠ å‘å…‰ç²’åæ•ˆæžœã€‚" rotate: "旋转" rotateDescription: "旋转指定的角度。" + plain: "简æ´" + plainDescription: "ç¦ç”¨æ‰€æœ‰å†…éƒ¨è¯æ³•。" _instanceTicker: none: "䏿˜¾ç¤º" remote: "仅远程用户" @@ -1248,9 +1275,11 @@ _widgets: trends: "趋势" clock: "æ—¶é’Ÿ" rss: "RSS阅读器" + rssTicker: "RSS Ticker" activity: "活动" photos: "照片" digitalClock: "æ•°å—æ—¶é’Ÿ" + unixClock: "UNIXæ—¶é’Ÿ" federation: "è”邦宇宙" instanceCloud: "实例云" postForm: "投稿窗å£" @@ -1701,6 +1730,9 @@ _deck: profile: "é…置文件" newProfile: "新建é…置文件" deleteProfile: "åˆ é™¤é…置文件" + introduction: "å°†å„列进行组åˆä»¥åˆ›å»ºæ‚¨è‡ªå·±çš„界é¢ï¼" + introduction2: "您å¯ä»¥éšæ—¶é€šè¿‡å±å¹•å³ä¾§çš„ + æ¥æ·»åŠ åˆ—" + widgetsIntroduction: "从列èœå•ä¸ï¼Œé€‰æ‹©â€œå°å·¥å…·ç¼–è¾‘â€æ¥æ·»åŠ å°å·¥å…·" _columns: main: "主列" widgets: "å°å·¥å…·" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index a79ec2fed1..c7b4fe77fb 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -52,6 +52,7 @@ searchUser: "æœå°‹ä½¿ç”¨è€…" reply: "回覆" loadMore: "載入更多" showMore: "載入更多" +showLess: "關閉" youGotNewFollower: "您有新的追隨者" receiveFollowRequest: "您有新的追隨請求" followRequestAccepted: "追隨請求已接å—" @@ -561,6 +562,7 @@ author: "作者" leaveConfirm: "有未ä¿å˜çš„æ›´æ”¹ã€‚è¦æ”¾æ£„嗎?" manage: "管ç†" plugins: "外掛" +preferencesBackups: "備份è¨å®šæª”" deck: "多欄模å¼" undeck: "å–æ¶ˆå¤šæ¬„模å¼" useBlurEffectForModal: "在模態框使用模糊效果" @@ -888,7 +890,9 @@ enableAutoSensitive: "自動NSFW判定" enableAutoSensitiveDescription: "如果å¯ç”¨ï¼Œè«‹åˆ©ç”¨æ©Ÿå™¨å¸ç¿’在媒體上自動è¨ç½® NSFW 旗標。 å³ä½¿é—œé–‰æ¤åŠŸèƒ½ï¼Œä¾å¯¦ä¾‹è€Œå®šä¹Ÿå¯èƒ½æœƒè‡ªå‹•è¨ç½®ã€‚" activeEmailValidationDescription: "ç©æ¥µåœ°é©—è‰ç”¨æˆ¶çš„é›»å郵件地å€ï¼Œåˆ¤æ–·å®ƒæ˜¯å¦ç‚ºå…洗地å€ï¼Œæˆ–者它是å¦å¯ä»¥é€šä¿¡ã€‚ è‹¥é—œé–‰ï¼Œå‰‡åªæœƒæª¢æŸ¥å—å…ƒæ˜¯å¦æ£ç¢ºã€‚" navbar: "導覽列" +shuffle: "隨機" account: "帳戶" +move: "移動 " _sensitiveMediaDetection: description: "您å¯ä»¥ä½¿ç”¨æ©Ÿå™¨å¸ç¿’è‡ªå‹•æª¢æ¸¬æ•æ„Ÿåª’é«”ä¸¦å°‡å…¶ç”¨æ–¼å¯©æ ¸ã€‚ 伺æœå™¨çš„è² è·æœƒç¨å¾®å¢žåŠ ã€‚" sensitivity: "æª¢æ¸¬æ•æ„Ÿåº¦" @@ -939,6 +943,24 @@ _plugin: install: "安è£å¤–掛組件" installWarn: "è«‹ä¸è¦å®‰è£ä¾†æºä¸æ˜Žçš„外掛組件。" manage: "管ç†å¤–掛" +_preferencesBackups: + list: "已備份的è¨å®šæª”" + saveNew: "å¦å˜æ–°æª”" + loadFile: "è®€å–æª”案" + apply: "套用在æ¤è£ç½®" + save: "è¦†è“‹å˜æª”" + inputName: "輸入備份檔å稱" + cannotSave: "無法儲å˜" + nameAlreadyExists: "備份檔å稱「{name}ã€å·²ç¶“å˜åœ¨ã€‚請指定ä¸åŒçš„å稱。" + applyConfirm: "將備份檔「{name}ã€å¥—用在ç¾åœ¨çš„è£ç½®å—Žï¼Ÿç¾åœ¨çš„è£ç½®è¨å®šå°‡æœƒæ¶ˆå¤±ã€‚" + saveConfirm: "è¦è¦†è“‹å˜æª”{name}嗎?" + deleteConfirm: "è¦åˆªé™¤{name}嗎?" + renameConfirm: "è¦å°‡ã€Œ{old}ã€è®Šæ›´ç‚ºã€Œ{new}ã€å—Žï¼Ÿ" + noBackups: "沒有備份檔。您å¯ä»¥ç”¨ã€Œå¦å˜æ–°æª”ã€å°‡ç¾åœ¨çš„客戶端è¨å®šå„²å˜åœ¨ä¼ºæœå™¨ä¸Šã€‚" + createdAt: "建立日期:{date} {time}" + updatedAt: "更新日期:{date} {time}" + cannotLoad: "無法讀å–" + invalidFile: "檔案形å¼éŒ¯èª¤ã€‚" _registry: scope: "範åœ" key: "機碼" @@ -1022,6 +1044,8 @@ _mfm: sparkleDescription: "æ·»åŠ é–ƒé–ƒç™¼å…‰çš„ç²’åæ•ˆæžœã€‚" rotate: "旋轉" rotateDescription: "以指定的角度旋轉。" + plain: "ç°¡æ½”" + plainDescription: "åœç”¨å…¨éƒ¨çš„內部語法。" _instanceTicker: none: "éš±è—" remote: "å‘é 端使用者顯示" @@ -1255,6 +1279,7 @@ _widgets: activity: "å‹•æ…‹" photos: "照片" digitalClock: "電忙‚é˜" + unixClock: "UNIX時間" federation: "è¯é‚¦å®‡å®™" instanceCloud: "實例雲" postForm: "發佈窗å£" diff --git a/package.json b/package.json index cabb9f8f9b..65f5fb24ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.117.1", + "version": "12.118.0", "codename": "indigo", "repository": { "type": "git", @@ -41,9 +41,9 @@ "devDependencies": { "@types/gulp": "4.0.9", "@types/gulp-rename": "2.0.1", - "@typescript-eslint/parser": "5.30.6", + "@typescript-eslint/parser": "5.31.0", "cross-env": "7.0.3", - "cypress": "10.3.0", + "cypress": "10.3.1", "start-server-and-test": "1.14.0", "typescript": "4.7.4" } diff --git a/packages/backend/package.json b/packages/backend/package.json index b91f5fc32f..5e749b80dc 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -14,10 +14,10 @@ "lodash": "^4.17.21" }, "optionalDependencies": { - "@tensorflow/tfjs-node": "3.18.0" + "@tensorflow/tfjs-node": "3.19.0" }, "dependencies": { - "@bull-board/koa": "4.0.0", + "@bull-board/koa": "4.1.1", "@discordapp/twemoji": "14.0.2", "@elastic/elasticsearch": "7.11.0", "@koa/cors": "3.1.0", @@ -26,15 +26,14 @@ "@peertube/http-signature": "1.6.0", "@sinonjs/fake-timers": "9.1.2", "@syuilo/aiscript": "0.11.1", - "abort-controller": "3.0.0", "ajv": "8.11.0", "archiver": "5.3.1", "autobind-decorator": "2.4.0", "autwh": "0.1.0", - "aws-sdk": "2.1165.0", + "aws-sdk": "2.1185.0", "bcryptjs": "2.4.3", "blurhash": "1.1.5", - "bull": "4.8.4", + "bull": "4.8.5", "cacheable-lookup": "6.0.4", "cbor": "8.1.0", "chalk": "5.0.1", @@ -43,13 +42,13 @@ "cli-highlight": "2.1.11", "color-convert": "2.0.1", "content-disposition": "0.5.4", - "date-fns": "2.28.0", + "date-fns": "2.29.1", "deep-email-validator": "0.1.21", "escape-regexp": "0.0.1", "feed": "4.2.2", - "file-type": "17.1.2", + "file-type": "17.1.4", "fluent-ffmpeg": "2.1.2", - "got": "12.1.0", + "got": "12.3.0", "hpagent": "0.1.2", "ioredis": "4.28.5", "ip-cidr": "3.0.10", @@ -59,7 +58,7 @@ "json5": "2.2.1", "json5-loader": "4.0.1", "jsonld": "6.0.0", - "jsrsasign": "10.5.25", + "jsrsasign": "10.5.26", "koa": "2.13.4", "koa-bodyparser": "4.3.0", "koa-favicon": "2.1.0", @@ -69,14 +68,14 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", - "mfm-js": "0.23.0-canary.1", + "mfm-js": "0.23.0", "mime-types": "2.1.35", "misskey-js": "0.0.14", "mocha": "10.0.0", "ms": "3.0.0-canary.1", "multer": "1.4.4", "nested-property": "4.0.0", - "node-fetch": "3.2.8", + "node-fetch": "3.2.10", "nodemailer": "6.7.7", "nsfwjs": "2.4.1", "os-utils": "0.0.14", @@ -88,32 +87,30 @@ "pug": "3.0.2", "punycode": "2.1.1", "pureimage": "0.3.14", - "qrcode": "1.5.0", + "qrcode": "1.5.1", "random-seed": "0.3.0", "ratelimiter": "3.4.1", "re2": "1.17.7", "redis-lock": "0.1.4", "reflect-metadata": "0.1.13", "rename": "1.0.4", - "require-all": "3.0.0", "rndstr": "1.0.0", "rss-parser": "3.12.0", "s-age": "1.1.2", - "sanitize-html": "2.7.0", + "sanitize-html": "2.7.1", "semver": "7.3.7", "sharp": "0.29.3", "speakeasy": "2.0.0", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "style-loader": "3.3.1", "summaly": "2.7.0", "syslog-pro": "1.0.0", - "systeminformation": "5.12.0", + "systeminformation": "5.12.1", "tinycolor2": "1.4.2", "tmp": "0.2.1", "ts-loader": "9.3.1", - "ts-node": "10.8.2", - "tsc-alias": "1.6.11", + "ts-node": "10.9.1", + "tsc-alias": "1.7.0", "tsconfig-paths": "4.0.0", "twemoji-parser": "14.0.0", "typeorm": "0.3.7", @@ -122,21 +119,20 @@ "uuid": "8.3.2", "web-push": "3.5.0", "websocket": "1.0.34", - "ws": "8.8.0", + "ws": "8.8.1", "xev": "3.0.2" }, "devDependencies": { - "@redocly/openapi-core": "1.0.0-beta.97", + "@redocly/openapi-core": "1.0.0-beta.105", "@types/bcryptjs": "2.4.2", - "@types/bull": "3.15.8", + "@types/bull": "3.15.9", "@types/cbor": "6.0.0", "@types/escape-regexp": "0.0.1", "@types/fluent-ffmpeg": "2.1.20", - "@types/is-url": "1.2.30", "@types/js-yaml": "4.0.5", "@types/jsdom": "16.2.14", "@types/jsonld": "1.5.6", - "@types/jsrsasign": "10.5.1", + "@types/jsrsasign": "10.5.2", "@types/koa": "2.13.5", "@types/koa-bodyparser": "4.3.7", "@types/koa-cors": "0.0.2", @@ -149,7 +145,7 @@ "@types/koa__multer": "2.0.4", "@types/koa__router": "8.0.11", "@types/mocha": "9.1.1", - "@types/node": "18.0.3", + "@types/node": "18.6.3", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.4", "@types/oauth": "0.9.1", @@ -171,10 +167,10 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.30.6", - "@typescript-eslint/parser": "5.30.6", + "@typescript-eslint/eslint-plugin": "5.31.0", + "@typescript-eslint/parser": "5.31.0", "cross-env": "7.0.3", - "eslint": "8.19.0", + "eslint": "8.20.0", "eslint-plugin-import": "2.26.0", "execa": "6.1.0", "typescript": "4.7.4" diff --git a/packages/backend/src/remote/activitypub/renderer/block.ts b/packages/backend/src/remote/activitypub/renderer/block.ts index 13815fb76f..802d7280b1 100644 --- a/packages/backend/src/remote/activitypub/renderer/block.ts +++ b/packages/backend/src/remote/activitypub/renderer/block.ts @@ -7,7 +7,7 @@ import { Blocking } from '@/models/entities/blocking.js'; * @param block The block to be rendered. The blockee relation must be loaded. */ export function renderBlock(block: Blocking) { - if (block.blockee?.url == null) { + if (block.blockee?.uri == null) { throw new Error('renderBlock: missing blockee uri'); } diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index a2249803ee..2b343dabdd 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -13,7 +13,7 @@ export const meta = { limit: { duration: 60000, - max: 10, + max: 15, }, kind: 'read:notifications', diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index 9570115423..b0d529ec36 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -138,6 +138,8 @@ </button> <p class="dont-worry">Don't worry, it's (probably) not your fault.</p> <p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p> + <p>Update your os and browser.</p> + <p>Disable an adblocker.</p> <a href="/flush"> <button class="button-small"> <span class="button-label-small">Clear preferences and cache</span> diff --git a/packages/backend/src/server/web/views/flush.pug b/packages/backend/src/server/web/views/flush.pug index ec585a34db..a73a45212f 100644 --- a/packages/backend/src/server/web/views/flush.pug +++ b/packages/backend/src/server/web/views/flush.pug @@ -27,7 +27,7 @@ html .then(registrations => { return Promise.all(registrations.map(registration => registration.unregister())); }) - .catch(e => { throw Error(e) }); + .catch(e => { throw new Error(e) }); } message(successText); diff --git a/packages/backend/test/tsconfig.json b/packages/backend/test/tsconfig.json index 3f9020d467..bc7a9968b5 100644 --- a/packages/backend/test/tsconfig.json +++ b/packages/backend/test/tsconfig.json @@ -9,7 +9,7 @@ "noFallthroughCasesInSwitch": true, "declaration": false, "sourceMap": true, - "target": "es2017", + "target": "es2021", "module": "es2020", "moduleResolution": "node", "allowSyntheticDefaultImports": true, diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 22338a4976..dea4eb27db 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -9,7 +9,7 @@ "noFallthroughCasesInSwitch": true, "declaration": false, "sourceMap": false, - "target": "es2017", + "target": "es2021", "module": "es2020", "moduleResolution": "node", "allowSyntheticDefaultImports": true, diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index dea6c38343..b104072278 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -21,20 +21,20 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@bull-board/api@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-4.0.0.tgz#63931cbee56ff3b1525f8771d9b8a6df12838962" - integrity sha512-4STXOhQv07/8d/Ei6LA38D3aaYtMuOHJMejkkF2CTAW3gAzEtwhDHmrKlk7tG01Gq2jnPNIcYxbd4WIbtP/+fQ== +"@bull-board/api@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-4.1.1.tgz#138364357ff8a6e6c9c94a64d325d8334275181f" + integrity sha512-xpezACPl80Emry/uY+T2GoKllTQlKYaWTUWZnBq0J1ak9Zzo00JHP5v+hI7CgPjbCJVGarrTKywUEpL7S8aRXw== dependencies: redis-info "^3.0.8" -"@bull-board/koa@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@bull-board/koa/-/koa-4.0.0.tgz#e9d39f166abdc942c0d9e045bbc23941e9e47db1" - integrity sha512-8UN8h0NKkpND2w47YmvacG3TZPp0GHjw2By/fuX/MqoLG2Wtu58GCzhmKij8DHW5nfAr5c/0azWwyKJZ6jR5wA== +"@bull-board/koa@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@bull-board/koa/-/koa-4.1.1.tgz#32887977a3999794df3ae58acf30d252323e330c" + integrity sha512-GWfMYHPl+ePU77pPigFLd1wMr4UWYlfcJd6XsdS9QBpgeLkqEPrsi3SmtwT0fk+DOohLD+sdAo5VeFYvxcOz+w== dependencies: - "@bull-board/api" "4.0.0" - "@bull-board/ui" "4.0.0" + "@bull-board/api" "4.1.1" + "@bull-board/ui" "4.1.1" ejs "^3.1.7" koa "^2.13.1" koa-mount "^4.0.0" @@ -42,12 +42,12 @@ koa-static "^5.0.0" koa-views "^7.0.1" -"@bull-board/ui@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@bull-board/ui/-/ui-4.0.0.tgz#6702d2fa286ba54d3f18a0af2e2344c3fe21d836" - integrity sha512-sesp3n3e/Zkw7oFxrihB/AGsPWRzLywTXlcc3N6ttGLE1U5ow5yRSg6F/1LFe9OpHsYko0VsYJMcTAeZk7AJ+w== +"@bull-board/ui@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@bull-board/ui/-/ui-4.1.1.tgz#71d415f8b93ef1a215819cbdc5c7fd577e873fbe" + integrity sha512-qyfrC0XkQNXTuC8g9BEjHLAbzOVW4Qw5rDo65oGqDBd4lpLmTa2MCFh1lm6GDZ9ak/ltH3aayvacNoH0L6ldZw== dependencies: - "@bull-board/api" "4.0.0" + "@bull-board/api" "4.1.1" "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -166,20 +166,20 @@ methods "^1.1.2" path-to-regexp "^6.1.0" -"@mapbox/node-pre-gyp@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.4.tgz#6c76e7a40138eac39e1a4dc869a083e43e236c00" - integrity sha512-M669Qo4nRT7iDmQEjQYC7RU8Z6dpz9UmSbkJ1OFEja3uevCdLKh7IZZki7L1TZj02kRyl82snXFY8QqkyfowrQ== +"@mapbox/node-pre-gyp@1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== dependencies: - detect-libc "^1.0.3" + detect-libc "^2.0.0" https-proxy-agent "^5.0.0" make-dir "^3.1.0" - node-fetch "^2.6.1" + node-fetch "^2.6.7" nopt "^5.0.0" - npmlog "^4.1.2" + npmlog "^5.0.1" rimraf "^3.0.2" - semver "^7.3.4" - tar "^6.1.0" + semver "^7.3.5" + tar "^6.1.11" "@node-redis/bloom@^1.0.0": version "1.0.1" @@ -287,10 +287,10 @@ require-from-string "^2.0.2" uri-js "^4.2.2" -"@redocly/openapi-core@1.0.0-beta.97": - version "1.0.0-beta.97" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.97.tgz#324ed46e9a9aee4c615be22ee348c53f7bb5f180" - integrity sha512-3WW9/6flosJuRtU3GI0Vw39OYFZqqXMDCp5TLa3EjXOb7Nm6AZTWRb3Y+I/+UdNJ/NTszVJkQczoa1t476ekiQ== +"@redocly/openapi-core@1.0.0-beta.105": + version "1.0.0-beta.105" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.0.0-beta.105.tgz#bf8ad66c086cadfe22dbaa3027494ab74f5297bd" + integrity sha512-8uYDMcqBOPhFgjRlg5uetW/E2uTVVRpk+YsJhaH78ZNuzBkQP5Waw5s8P8ym6myvHs5me8l5AdniY/ePLMT5xg== dependencies: "@redocly/ajv" "^8.6.4" "@types/node" "^14.11.8" @@ -303,11 +303,16 @@ pluralize "^8.0.0" yaml-ast-parser "0.0.43" -"@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.6.0": +"@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@sindresorhus/is@^5.2.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.3.0.tgz#0ec9264cf54a527671d990eb874e030b55b70dcc" + integrity sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw== + "@sinonjs/commons@^1.7.0": version "1.7.2" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2" @@ -352,65 +357,66 @@ dependencies: defer-to-connect "^2.0.1" -"@tensorflow/tfjs-backend-cpu@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.18.0.tgz#f0596911c14adf3dfa428e7d04305ef37c6f65e1" - integrity sha512-LcSqlylzGtpgngcMFIL3q9Q3eVaPRJ7ITZt7ivhzkCj4R5ZsnPa9qM3DCVihkQ77heAwSw4hPTo2jp5C4mJ4Cg== +"@tensorflow/tfjs-backend-cpu@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.19.0.tgz#c7524ccdfded81df0c5cb53185b14e5222ac51e5" + integrity sha512-02f+WkiL9gc9G7P8PwfsvuXREcAUdM/3uAL6fTle3xKEj7KOxX+E/mc3jxPY5UzjAsgHVBZrPJ2xi6AG16WPkQ== dependencies: - "@types/seedrandom" "2.4.27" - seedrandom "2.4.3" + "@types/seedrandom" "^2.4.28" + seedrandom "^3.0.5" -"@tensorflow/tfjs-backend-webgl@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.18.0.tgz#56d806a43b4695b1af4ee04c01d6381b1973c2c7" - integrity sha512-3NknSzS1oX2BEBOrpjPMZl823S12RgshQthmIbG6QADHb4bCJA8aM4UjWpw+3bNQnRKbRDQdFbuvj10Un79s2A== +"@tensorflow/tfjs-backend-webgl@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.19.0.tgz#64b8a14df35ee7d27859c7d141c527cefc6d9484" + integrity sha512-2HTkAE21t3WQTt8P6iK80ni03AzC8UNZmbIB7/pBDYBbhDwZwe/C5fXrJWnP9m6u4hvCdMAJ3o+OP3NeaEL1pw== dependencies: - "@tensorflow/tfjs-backend-cpu" "3.18.0" + "@tensorflow/tfjs-backend-cpu" "3.19.0" "@types/offscreencanvas" "~2019.3.0" - "@types/seedrandom" "2.4.27" + "@types/seedrandom" "^2.4.28" "@types/webgl-ext" "0.0.30" "@types/webgl2" "0.0.6" - seedrandom "2.4.3" + seedrandom "^3.0.5" -"@tensorflow/tfjs-converter@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-3.18.0.tgz#f4b6d8812d133aa0b6eaa06f75abbde1dbb3550f" - integrity sha512-hpChA+zVNQOVwRnCfqDb1WI9jbEAKA6DuEm4m75Zb3dIlE6VVooDmAaHBhlc++z2q2G1sBzF9A4Bv48SUpN6vA== +"@tensorflow/tfjs-converter@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-3.19.0.tgz#701db7255ef45578811a191478db5a09bcca6dda" + integrity sha512-B69HQq9/orsM8pGJPjNp1cV+hIcc90mxcRIsQSYGovTUNEcftmz2Sh+mqXDWysKUk0gRfx5CX6eJk6NaE55Xow== -"@tensorflow/tfjs-core@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-3.18.0.tgz#c9eb420d1ae2852109fae640ae8a38041b82f9ec" - integrity sha512-gMxisZozqsr5sCKlphF/eVBLg91MjlBiN60tjX8hJAu0WlSn6Gi5k65GNIL+Pq6hrxpvImcfdCmTH/2XJVZ0Mg== +"@tensorflow/tfjs-core@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-3.19.0.tgz#981c50bb38a6441a4375cfc8806784e7490f01bc" + integrity sha512-znJ+TOJ3NdNL5yjw8M7dn2jO96sokiH1wfFuD7gglCkbZ4SXlFpFj2xelNdRHHmeYanMhJzqeyOW9whUnNcBqw== dependencies: "@types/long" "^4.0.1" "@types/offscreencanvas" "~2019.3.0" - "@types/seedrandom" "2.4.27" + "@types/seedrandom" "^2.4.28" "@types/webgl-ext" "0.0.30" - "@webgpu/types" "^0.1.16" + "@webgpu/types" "0.1.16" long "4.0.0" node-fetch "~2.6.1" - seedrandom "2.4.3" + seedrandom "^3.0.5" -"@tensorflow/tfjs-data@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-data/-/tfjs-data-3.18.0.tgz#c6edf3bfa05fe581eeebb6a6c08cd4815d96bbf9" - integrity sha512-s43vISJh8K/UN2E2zGRhtj/Kyn8dr4ll8EQkapwzm7fGO9afXCnMsTp6rkZq3fFXouCYA2k1B/j7JssIDr50+w== +"@tensorflow/tfjs-data@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-data/-/tfjs-data-3.19.0.tgz#31de23cbea6cc594d60bd2216ab39faa8b2219cb" + integrity sha512-rkZv+YZowZwnm4RaedkV44WDrjokRHld9Py/0Fb7IvMyUh37lY0WsAsV94kJ+QuLc6iVNcDLaV29K+dUz57bRA== dependencies: "@types/node-fetch" "^2.1.2" node-fetch "~2.6.1" + string_decoder "^1.3.0" -"@tensorflow/tfjs-layers@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-layers/-/tfjs-layers-3.18.0.tgz#8b7d32030e797456e49fd5c26d6f169e0c59b9ca" - integrity sha512-AV7yDnPlH+RCcq8VPqkX1iyEchObE+e66m0XmJvLj+ncfKHYLa+39ZNroUA+OgB2/cMG6jgq77R4EhZbT6hwJA== +"@tensorflow/tfjs-layers@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-layers/-/tfjs-layers-3.19.0.tgz#b624c25a2bdec09ea1c71db6547eb0952707fb35" + integrity sha512-+sVWjWWyTuT3sImrtNLtMv8/4FS30GAYpTgyJKhCQ3+GSvHUXulxJfncD0QqOg9fTbhtuF1TRAkzDU8v64791g== -"@tensorflow/tfjs-node@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-node/-/tfjs-node-3.18.0.tgz#bc6de241ba178f951db1d60df59e464b737eff78" - integrity sha512-jW6bFKO6hH4tGvlijvpcIbCRRa6vDZ2xIIbEO7qZ17s0QOMPBGjDLyQGUaSQ00uog0Rid/sdZNpiueDqB0ZGbA== +"@tensorflow/tfjs-node@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-node/-/tfjs-node-3.19.0.tgz#b7e58ff8bbea48881554d9178361726a83e56f92" + integrity sha512-6l8+56J66zf5k+WS8zTA1SbXno+iV7LgchwKPa62fsPRwjdzNIm1QondJbQYbFOILYx6bsgJs7nOoxStOlygAw== dependencies: - "@mapbox/node-pre-gyp" "1.0.4" - "@tensorflow/tfjs" "3.18.0" + "@mapbox/node-pre-gyp" "1.0.9" + "@tensorflow/tfjs" "3.19.0" adm-zip "^0.5.2" google-protobuf "^3.9.2" https-proxy-agent "^2.2.1" @@ -418,17 +424,17 @@ rimraf "^2.6.2" tar "^4.4.6" -"@tensorflow/tfjs@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@tensorflow/tfjs/-/tfjs-3.18.0.tgz#be59951d1981c887d2b786100e43abc4c2332164" - integrity sha512-mOzz4jJdgIpqFS7EHndVuxrQnLUDVIKGyTqOPTYps89fZwcOFfTVxi4BHemDNQpqlVE8IaGh9UUxVXpjgPY5+Q== +"@tensorflow/tfjs@3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tensorflow/tfjs/-/tfjs-3.19.0.tgz#a08c35e6101bdbc0bf9a58f468270eee15f77bb0" + integrity sha512-fZF3HOON8jgKhFk06WIScIXf7j/gkl6cLbU1brFWutBhHlPSzxSWvdJR/TivCK7p+yMBunoyK50TjiwOrcoclA== dependencies: - "@tensorflow/tfjs-backend-cpu" "3.18.0" - "@tensorflow/tfjs-backend-webgl" "3.18.0" - "@tensorflow/tfjs-converter" "3.18.0" - "@tensorflow/tfjs-core" "3.18.0" - "@tensorflow/tfjs-data" "3.18.0" - "@tensorflow/tfjs-layers" "3.18.0" + "@tensorflow/tfjs-backend-cpu" "3.19.0" + "@tensorflow/tfjs-backend-webgl" "3.19.0" + "@tensorflow/tfjs-converter" "3.19.0" + "@tensorflow/tfjs-core" "3.19.0" + "@tensorflow/tfjs-data" "3.19.0" + "@tensorflow/tfjs-layers" "3.19.0" argparse "^1.0.10" chalk "^4.1.0" core-js "3" @@ -485,10 +491,10 @@ "@types/connect" "*" "@types/node" "*" -"@types/bull@3.15.8": - version "3.15.8" - resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.8.tgz#ae2139f94490d740b37c8da5d828ce75dd82ce7c" - integrity sha512-8DbSPMSsZH5PWPnGEkAZLYgJEH4ghHJNKF7LB6Wr5R0/v6g+Vs+JoaA7kcvLtHE936xg2WpFPkaoaJgExOmKDw== +"@types/bull@3.15.9": + version "3.15.9" + resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.15.9.tgz#e10e0901ec3762bff85716b3c580277960751c93" + integrity sha512-MPUcyPPQauAmynoO3ezHAmCOhbB0pWmYyijr/5ctaCqhbKWsjW0YCod38ZcLzUBprosfZ9dPqfYIcfdKjk7RNQ== dependencies: "@types/ioredis" "*" "@types/redis" "^2.8.0" @@ -604,11 +610,6 @@ dependencies: "@types/node" "*" -"@types/is-url@1.2.30": - version "1.2.30" - resolved "https://registry.yarnpkg.com/@types/is-url/-/is-url-1.2.30.tgz#85567e8bee4fee69202bc3448f9fb34b0d56c50a" - integrity sha512-AnlNFwjzC8XLda5VjRl4ItSd8qp8pSNowvsut0WwQyBWHpOxjxRJm8iO6uETWqEyLdYdb9/1j+Qd9gQ4l5I4fw== - "@types/js-yaml@4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" @@ -643,10 +644,10 @@ resolved "https://registry.yarnpkg.com/@types/jsonld/-/jsonld-1.5.6.tgz#4396c0b17128abf5773bb68b5453b88fc565b0d4" integrity sha512-OUcfMjRie5IOrJulUQwVNvV57SOdKcTfBj3pjXNxzXqeOIrY2aGDNGW/Tlp83EQPkz4tCE6YWVrGuc/ZeaAQGg== -"@types/jsrsasign@10.5.1": - version "10.5.1" - resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.1.tgz#6f9defd46dfcf324b1cff08a06be639858deee3b" - integrity sha512-QqM03IXHY6SX835mWdx7Vp8ZOxw/hcnMjGjapUQf+pgFPRyGdjg3jxFsr4p+rolKcdRhptm3mtVQNk4OMhCQcA== +"@types/jsrsasign@10.5.2": + version "10.5.2" + resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.2.tgz#c8d5a7bccffd2fdee73553a130876a88e91419ec" + integrity sha512-oroCALq37fnUKPRYatawNq3oBNITN7lROpy6JBUanYLhuMZwG5shVxCyZ1/wM3RQCNJ/Ac5/+g7yZaZ+tVBy3A== "@types/keygrip@*": version "1.0.2" @@ -800,10 +801,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA== -"@types/node@18.0.3": - version "18.0.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" - integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== +"@types/node@18.6.3": + version "18.6.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.3.tgz#4e4a95b6fe44014563ceb514b2598b3e623d1c98" + integrity sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg== "@types/node@^14.11.8": version "14.17.9" @@ -906,10 +907,10 @@ dependencies: htmlparser2 "^6.0.0" -"@types/seedrandom@2.4.27": - version "2.4.27" - resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.27.tgz#9db563937dd86915f69092bc43259d2f48578e41" - integrity sha512-YvMLqFak/7rt//lPBtEHv3M4sRNA+HGxrhFZ+DQs9K2IkYJbNwVIb8avtJfhDiuaUBX/AW0jnjv48FV8h3u9bQ== +"@types/seedrandom@^2.4.28": + version "2.4.30" + resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.30.tgz#d2efe425869b84163c2d56e779dddadb9372cbfa" + integrity sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ== "@types/semver@7.3.10": version "7.3.10" @@ -994,14 +995,14 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" - integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== +"@typescript-eslint/eslint-plugin@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe" + integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/type-utils" "5.30.6" - "@typescript-eslint/utils" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/type-utils" "5.31.0" + "@typescript-eslint/utils" "5.31.0" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -1009,69 +1010,69 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" - integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== +"@typescript-eslint/parser@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" + integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" - integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== +"@typescript-eslint/scope-manager@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" + integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" -"@typescript-eslint/type-utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" - integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== +"@typescript-eslint/type-utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9" + integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w== dependencies: - "@typescript-eslint/utils" "5.30.6" + "@typescript-eslint/utils" "5.31.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" - integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== +"@typescript-eslint/types@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" + integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== -"@typescript-eslint/typescript-estree@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" - integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== +"@typescript-eslint/typescript-estree@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" + integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" - integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== +"@typescript-eslint/utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd" + integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" - integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== +"@typescript-eslint/visitor-keys@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" + integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== dependencies: - "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/types" "5.31.0" eslint-visitor-keys "^3.3.0" "@ungap/promise-all-settled@1.1.2": @@ -1079,10 +1080,10 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -"@webgpu/types@^0.1.16": - version "0.1.20" - resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.20.tgz#9263846b99052a35b9ad8b15adc60b9394d306b0" - integrity sha512-MFb5oyxX+A7PWQNjcY3kSCSG2FAHaBo7IJBWtxWFgsS20FtY3D9UY7lYqLZ6avS8fSkdSylIS4qiHzFlQUdXag== +"@webgpu/types@0.1.16": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.16.tgz#1f05497b95b7c013facf7035c8e21784645f5cc4" + integrity sha512-9E61voMP4+Rze02jlTXud++Htpjyyk8vw5Hyw9FGRrmhHQg2GqbuOfwf5Klrb8vTxc2XWI3EfO7RUHMpxTj26A== abab@^2.0.6: version "2.0.6" @@ -1094,7 +1095,7 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abort-controller@3.0.0, abort-controller@^3.0.0: +abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== @@ -1447,10 +1448,15 @@ autwh@0.1.0: dependencies: oauth "0.9.15" -aws-sdk@2.1165.0: - version "2.1165.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1165.0.tgz#4da669d1e9020344cef75d961882f52a7931a379" - integrity sha512-2oVkSuXsLeErt+H4M2OGIz4p1LPS+QRfY2WnW4QKMndASOcvHKZTfzuY8jmc9ZnDGyguiGdT3idYU8KpNg0sGw== +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +aws-sdk@2.1185.0: + version "2.1185.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1185.0.tgz#157c6a900a9449cb36b37493337cae418e01210d" + integrity sha512-viFlYC6RAKOqBRM4gIB4rE80KMFNVvEkQpNmpd3PqCOemGPETDxCVHS0oqZ26qM278sZVHt+oAjPy5HmZasskg== dependencies: buffer "4.9.2" events "1.1.1" @@ -1459,6 +1465,7 @@ aws-sdk@2.1165.0: querystring "0.2.0" sax "1.2.1" url "0.10.3" + util "^0.12.4" uuid "8.0.0" xml2js "0.4.19" @@ -1669,10 +1676,10 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "~3.7.0" -bull@4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/bull/-/bull-4.8.4.tgz#c538610492050d5160dbd9180704145f135a0aa9" - integrity sha512-vDNhM/pvfFY3+msulMbqPBdBO7ntKxRZRtMfi3EguVW/Ozo4uez+B81I8ZoDxYCLgSOBfwRuPnFtcv7QNzm4Ew== +bull@4.8.5: + version "4.8.5" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.8.5.tgz#eebafddc3249d6d5e8ced1c42b8bfa8efcc274aa" + integrity sha512-2Z630e4f6VsLJnWMAtfEHwIqJYmND4W3dcG48RIbXeWpvb4UnYtpe/zxEdslJu0PKrltB4IkFj5YtBsdeQRn8w== dependencies: cron-parser "^4.2.1" debuglog "^1.0.0" @@ -2276,7 +2283,12 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -date-fns@2.28.0, date-fns@^2.28.0: +date-fns@2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.1.tgz#9667c2615525e552b5135a3116b95b1961456e60" + integrity sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw== + +date-fns@^2.28.0: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== @@ -2404,6 +2416,14 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2738,6 +2758,35 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-abstract@^1.19.5, es-abstract@^1.20.0: + version "1.20.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -2890,10 +2939,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.19.0: - version "8.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" - integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== +eslint@8.20.0: + version "8.20.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" + integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" @@ -3125,13 +3174,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-type@17.1.2: - version "17.1.2" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-17.1.2.tgz#9257437a64e0c3623f70d9f27430522d978b1384" - integrity sha512-3thBUSfa9YEUEGO/NAAiQGvjujZxZiJTF6xNwyDn6kB0NcEtwMn5ttkGG9jGwm/Nt/t8U1bpBNqyBNZCz4F4ig== +file-type@17.1.4: + version "17.1.4" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-17.1.4.tgz#e86bd6cc1b727ff2b2bd62f100958e4bcf37a6a3" + integrity sha512-3w/rJUUPBj6CYhVER3D5JCKwYJJiC36uj5dP+LnyubHI6H6FJo1TeWVCEA09YLVoZqV3/mLP26j9+Pz1GjAyjQ== dependencies: readable-web-to-node-stream "^3.0.2" - strtok3 "^7.0.0-alpha.7" + strtok3 "^7.0.0-alpha.9" token-types "^5.0.0-alpha.2" filelist@^1.0.1: @@ -3202,15 +3251,22 @@ follow-redirects@^1.14.4: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -form-data-encoder@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.1.tgz#ac80660e4f87ee0d3d3c3638b7da8278ddb8ec96" - integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== +form-data-encoder@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.0.1.tgz#aec41860aca0275cb6026650d139c6701b0992c1" + integrity sha512-Oy+P9w5mnO4TWXVgUiQvggNKPI9/ummcSt5usuIV6HkaLKigwzPpoenhEqmGmx3zHqm6ZLJ+CR/99N8JLinaEw== form-data@^3.0.0: version "3.0.1" @@ -3309,11 +3365,41 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.0.tgz#afba07aa0374a93c6219603b1fb83eaa2264d8f8" @@ -3532,19 +3618,19 @@ got@11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -got@12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-12.1.0.tgz#099f3815305c682be4fd6b0ee0726d8e4c6b0af4" - integrity sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig== +got@12.3.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/got/-/got-12.3.0.tgz#744625bcb072e7b1fd41a706e0af2bd1f73a2c64" + integrity sha512-7uK06aluHF0UibYFBX3lFUZ2FG/W0KS4O4EqAIrbWIdbPxIT33r6ZJy7Zy+pdh0CP/ZbF3zBa7Fd9dCn7vGPBg== dependencies: - "@sindresorhus/is" "^4.6.0" + "@sindresorhus/is" "^5.2.0" "@szmarczak/http-timer" "^5.0.1" "@types/cacheable-request" "^6.0.2" "@types/responselike" "^1.0.0" cacheable-lookup "^6.0.4" cacheable-request "^7.0.2" decompress-response "^6.0.0" - form-data-encoder "1.7.1" + form-data-encoder "^2.0.1" get-stream "^6.0.1" http2-wrapper "^2.1.10" lowercase-keys "^3.0.0" @@ -3584,6 +3670,11 @@ has-bigints@^1.0.1: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3594,6 +3685,13 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" @@ -3604,6 +3702,11 @@ has-symbols@^1.0.2: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -3952,6 +4055,14 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-arrayish@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" @@ -3984,16 +4095,16 @@ is-buffer@^1.0.2, is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-callable@^1.1.3, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + is-callable@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== -is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - is-core-module@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" @@ -4077,6 +4188,11 @@ is-negative-zero@^2.0.1: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + is-number-object@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" @@ -4129,6 +4245,13 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" @@ -4162,6 +4285,17 @@ is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" +is-typed-array@^1.1.3, is-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" + integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -4179,6 +4313,13 @@ is-weakref@^1.0.1: dependencies: call-bind "^1.0.0" +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-whitespace@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f" @@ -4399,10 +4540,10 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -jsrsasign@10.5.25: - version "10.5.25" - resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.5.25.tgz#8eb3f943718d73f2dd3d85f587f241a5316b835a" - integrity sha512-N7zxHaCwYvFlXsybq4p4RxRwn4AbEq3cEiyjbCrWmwA7g8aS4LTKDJ9AJmsXxwtYesYx0imJ+ITtkyyxLCgeIg== +jsrsasign@10.5.26: + version "10.5.26" + resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.5.26.tgz#bc36d4c4019c83f144066725ea0ca6ab306702fc" + integrity sha512-TjEu1yPdI+8whpe6CA/6XNb7U1sm9+PUItOUfSThOLvx7JCfYHIfuvZK2Egz2DWUKioafn98LPuk+geLGckxMg== jstransformer@1.0.0: version "1.0.0" @@ -4869,10 +5010,10 @@ methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -mfm-js@0.23.0-canary.1: - version "0.23.0-canary.1" - resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0-canary.1.tgz#1b7b7635f18bed9776054406b72e6bd613c8d0eb" - integrity sha512-SkMrW1rQAv+mFGtLKN9DSv6vxSREDu8ChmkBl1Ch5sQfp47BhuvcRg5EKGmt3WAQRAOylXYMg8wVYR7C5BHKeA== +mfm-js@0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0.tgz#1d1477761aa8259ddcac2e6882df53ed9ca5b82b" + integrity sha512-2Oe/YicoaP1EU2y9JB5729/PQLZK/7aAVomeJkp1h4XGP2//NMDC+DHkBbSO71U3GG086SAZM0JBB/hdPPSEXg== dependencies: twemoji-parser "14.0.0" @@ -5296,16 +5437,16 @@ node-fetch@*: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-fetch@3.2.8: - version "3.2.8" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.8.tgz#0d9516dcf43a758d78d6dbe538adf0b1f6a4944e" - integrity sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg== +node-fetch@3.2.10: + version "3.2.10" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8" + integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA== dependencies: data-uri-to-buffer "^4.0.0" fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-fetch@^2.6.1, node-fetch@~2.6.1: +node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@~2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -5396,7 +5537,7 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -npmlog@^4.0.1, npmlog@^4.1.2: +npmlog@^4.0.1: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -5406,6 +5547,16 @@ npmlog@^4.0.1, npmlog@^4.1.2: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + npmlog@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.0.tgz#ba9ef39413c3d936ea91553db7be49c34ad0520c" @@ -5460,6 +5611,11 @@ object-inspect@^1.11.0, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.12.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6137,10 +6293,10 @@ q@1.4.1: resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= -qrcode@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" - integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== +qrcode@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" + integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== dependencies: dijkstrajs "^1.0.1" encode-utf8 "^1.0.3" @@ -6347,6 +6503,15 @@ regenerator-runtime@^0.13.5: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" @@ -6522,10 +6687,10 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-html@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279" - integrity sha512-jfQelabOn5voO7FAfnQF7v+jsA6z9zC/O4ec0z3E35XPEtHYJT/OdUziVWlKW4irCr2kXaQAyXTXDHWAibg1tA== +sanitize-html@2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.1.tgz#a6c2c1a88054a79eeacfac9b0a43f1b393476901" + integrity sha512-oOpe8l4J8CaBk++2haoN5yNI5beekjuHv3JRPKUx/7h40Rdr85pemn4NkvUB3TcBP7yjat574sPlcMAyv4UQig== dependencies: deepmerge "^4.2.2" escape-string-regexp "^4.0.0" @@ -6570,12 +6735,7 @@ seedrandom@2.4.2: resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.2.tgz#18d78c41287d13aff8eadb29e235938b248aa9ff" integrity sha1-GNeMQSh9E6/46tsp4jWTiySKqf8= -seedrandom@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.3.tgz#2438504dad33917314bff18ac4d794f16d6aaecc" - integrity sha512-2CkZ9Wn2dS4mMUWQaXLsOAfGD+irMlLEeSP3cMxpGbgyOOzJGFa+MWCOMTOCMyZinHRPxyOj/S/C57li/1to6Q== - -seedrandom@3.0.5: +seedrandom@3.0.5, seedrandom@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== @@ -6885,6 +7045,15 @@ string.prototype.trimend@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + string.prototype.trimstart@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" @@ -6893,7 +7062,16 @@ string.prototype.trimstart@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" -string_decoder@^1.1.1: +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -6967,19 +7145,14 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -strtok3@^7.0.0-alpha.7: - version "7.0.0-alpha.8" - resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0-alpha.8.tgz#23a7870974e0494b58b14af6dd1c2c67cf13314d" - integrity sha512-u+k19v+rTxBjGYxncRQjGvZYwYvEd0uP3D+uHKe/s4WB1eXS5ZwpZsTlBu5xSS4zEd89mTXECXg6WW3FSeV8cA== +strtok3@^7.0.0-alpha.9: + version "7.0.0-alpha.9" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0-alpha.9.tgz#a4ad5889e4fb5cea3514298435c6d7e84e595752" + integrity sha512-G8WxjBFjTZ77toVElv1i7k3jCXNkBB14FVaZ/6LIOka/WGo4La5XHLrU7neFVLdKbXESZf4BejVKZu5maOmocA== dependencies: "@tokenizer/token" "^0.3.0" peek-readable "^5.0.0-alpha.5" -style-loader@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" - integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== - summaly@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/summaly/-/summaly-2.7.0.tgz#ccccec0477938edea13cb34412a33e705398c0c4" @@ -7035,10 +7208,10 @@ syslog-pro@1.0.0: dependencies: moment "^2.22.2" -systeminformation@5.12.0: - version "5.12.0" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.12.0.tgz#1ff8d0b0fef9c2a6f70e1b1f2e681b8cd2d4b78e" - integrity sha512-2fa/2cnWxiC/g8v3XX4aEC2CQWl/WJ+JrfLq9f76lxYqkW4DWiU3vJhrEgAzBT07ta73c5wHd0xgMeMo0vBiMQ== +systeminformation@5.12.1: + version "5.12.1" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.12.1.tgz#8e512e4f9f21caaaa5f802fcb6a337cb4dc8b2f5" + integrity sha512-qAV0xSeSJlg0ZHmQ1T2rLrL54SATalBx6v4T8Sd5s17pEm6saX3LKzlPhfPx+EfT91y9yhRYnKhnMoLTFkxbqw== tapable@^2.2.0: version "2.2.0" @@ -7100,7 +7273,7 @@ tar@^4.4.6: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.1.0, tar@^6.1.11, tar@^6.1.2: +tar@^6.1.11, tar@^6.1.2: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== @@ -7232,10 +7405,10 @@ ts-loader@9.3.1: micromatch "^4.0.0" semver "^7.3.4" -ts-node@10.8.2: - version "10.8.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.8.2.tgz#3185b75228cef116bf82ffe8762594f54b2a23f2" - integrity sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA== +ts-node@10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -7251,10 +7424,10 @@ ts-node@10.8.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsc-alias@1.6.11: - version "1.6.11" - resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.6.11.tgz#d6d83f030ad11f48e4ead8ec5729929e5e60519b" - integrity sha512-mXEM21WriTJMQyo07B4Kc2nNFFk/1qOjU+jZ0ymXOyLz/A8J+dIBkimqZrh3s/x1qLGoJ1cNZQxa8GGoWOGX1Q== +tsc-alias@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.7.0.tgz#733482751133a25b97608ee424f8a1f085fcaaef" + integrity sha512-n/K6g8S7Ec7Y/A2Z77Ikp2Uv1S1ERtT63ni69XV4W1YPT4rnNmz8ItgIiJYvKfFnKfqcZQ81UPjoKpMTxaC/rg== dependencies: chokidar "^3.5.3" commander "^9.0.0" @@ -7418,10 +7591,20 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + undici@^5.2.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.5.1.tgz#baaf25844a99eaa0b22e1ef8d205bffe587c8f43" - integrity sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw== + version "5.8.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.0.tgz#dec9a8ccd90e5a1d81d43c0eab6503146d649a4f" + integrity sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q== uniq@^1.0.0: version "1.0.1" @@ -7500,6 +7683,18 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +util@^0.12.4: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + uuid@7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" @@ -7646,6 +7841,18 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which-typed-array@^1.1.2: + version "1.1.8" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" + integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.9" + which@^1.1.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -7717,7 +7924,12 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@8.8.0, ws@^8.8.0: +ws@8.8.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" + integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== + +ws@^8.8.0: version "8.8.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== diff --git a/packages/client/package.json b/packages/client/package.json index eaebf69ed8..d2bbe0c193 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -11,102 +11,79 @@ }, "dependencies": { "@discordapp/twemoji": "14.0.2", - "@fortawesome/fontawesome-free": "6.1.1", + "@fortawesome/fontawesome-free": "6.1.2", "@rollup/plugin-alias": "3.1.9", "@rollup/plugin-json": "4.1.0", "@syuilo/aiscript": "0.11.1", "@vitejs/plugin-vue": "3.0.1", "@vue/compiler-sfc": "3.2.37", - "abort-controller": "3.0.0", "autobind-decorator": "2.4.0", "autosize": "5.0.1", - "autwh": "0.1.0", "blurhash": "1.1.5", - "broadcast-channel": "4.13.0", + "broadcast-channel": "4.14.0", "browser-image-resizer": "git+https://github.com/misskey-dev/browser-image-resizer#v2.2.1-misskey.2", - "chart.js": "3.8.0", + "chart.js": "3.8.2", "chartjs-adapter-date-fns": "2.0.0", "chartjs-plugin-gradient": "0.5.0", "chartjs-plugin-zoom": "1.2.1", "compare-versions": "4.1.3", - "content-disposition": "0.5.4", "cropperjs": "2.0.0-beta", - "date-fns": "2.28.0", + "date-fns": "2.29.1", "escape-regexp": "0.0.1", "eventemitter3": "4.0.7", - "feed": "4.2.2", "idb-keyval": "6.2.0", "insert-text-at-cursor": "0.3.0", "json5": "2.2.1", "katex": "0.15.6", "matter-js": "0.18.0", - "mfm-js": "0.23.0-canary.1", + "mfm-js": "0.23.0", "misskey-js": "0.0.14", - "mocha": "10.0.0", - "ms": "2.1.3", - "nested-property": "4.0.0", - "photoswipe": "5.2.8", + "photoswipe": "5.3.0", "prismjs": "1.28.0", - "private-ip": "2.3.3", - "promise-limit": "2.7.0", - "pug": "3.0.2", "punycode": "2.1.1", - "qrcode": "1.5.0", "querystring": "0.2.1", - "random-seed": "0.3.0", - "reflect-metadata": "0.1.13", "rndstr": "1.0.0", "s-age": "1.1.2", - "sass": "1.53.0", + "sass": "1.54.0", "seedrandom": "3.0.5", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", - "three": "0.142.0", + "three": "0.143.0", "throttle-debounce": "5.0.0", "tinycolor2": "1.4.2", - "tsc-alias": "1.6.11", + "tsc-alias": "1.7.0", "tsconfig-paths": "4.0.0", "twemoji-parser": "14.0.0", "typescript": "4.7.4", "uuid": "8.3.2", - "v-debounce": "0.1.2", "vanilla-tilt": "1.7.2", - "vite": "3.0.2", + "vite": "3.0.4", "vue": "3.2.37", "vue-prism-editor": "2.0.0-alpha.2", - "vuedraggable": "4.0.1", - "websocket": "1.0.34", - "ws": "8.8.0" + "vuedraggable": "4.0.1" }, "devDependencies": { "@types/escape-regexp": "0.0.1", "@types/glob": "7.2.0", "@types/gulp": "4.0.9", "@types/gulp-rename": "2.0.1", - "@types/is-url": "1.2.30", "@types/katex": "0.14.0", "@types/matter-js": "0.17.7", - "@types/mocha": "9.1.1", - "@types/oauth": "0.9.1", "@types/punycode": "2.1.0", - "@types/qrcode": "1.4.2", - "@types/random-seed": "0.3.3", "@types/seedrandom": "3.0.2", "@types/throttle-debounce": "5.0.0", "@types/tinycolor2": "1.4.3", "@types/uuid": "8.3.4", - "@types/websocket": "1.0.5", - "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.30.6", - "@typescript-eslint/parser": "5.30.6", - "rollup": "2.76.0", + "@typescript-eslint/eslint-plugin": "5.31.0", + "@typescript-eslint/parser": "5.31.0", "cross-env": "7.0.3", - "cypress": "10.3.0", - "eslint": "8.19.0", + "cypress": "10.3.1", + "eslint": "8.20.0", "eslint-plugin-import": "2.26.0", - "eslint-plugin-vue": "9.2.0", + "eslint-plugin-vue": "9.3.0", + "rollup": "2.77.2", "start-server-and-test": "1.14.0" } } diff --git a/packages/client/src/components/MkNoteSub.vue b/packages/client/src/components/MkNoteSub.vue index 30c27e6235..9ae773bfb6 100644 --- a/packages/client/src/components/MkNoteSub.vue +++ b/packages/client/src/components/MkNoteSub.vue @@ -6,7 +6,7 @@ <XNoteHeader class="header" :note="note" :mini="true"/> <div class="body"> <p v-if="note.cw != null" class="cw"> - <Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis" /> + <Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis"/> <XCwButton v-model="showContent" :note="note"/> </p> <div v-show="note.cw == null || showContent" class="content"> @@ -19,7 +19,7 @@ <MkNoteSub v-for="reply in replies" :key="reply.id" :note="reply" class="reply" :detail="true" :depth="depth + 1"/> </template> <div v-else class="more"> - <MkA class="text _link" :to="notePage(note)">{{ $ts.continueThread }} <i class="fas fa-angle-double-right"></i></MkA> + <MkA class="text _link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="fas fa-angle-double-right"></i></MkA> </div> </div> </template> @@ -27,11 +27,12 @@ <script lang="ts" setup> import { } from 'vue'; import * as misskey from 'misskey-js'; -import { notePage } from '@/filters/note'; import XNoteHeader from './note-header.vue'; import MkNoteSubNoteContent from './sub-note-content.vue'; import XCwButton from './cw-button.vue'; +import { notePage } from '@/filters/note'; import * as os from '@/os'; +import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ note: misskey.entities.Note; @@ -49,7 +50,7 @@ let replies: misskey.entities.Note[] = $ref([]); if (props.detail) { os.api('notes/children', { noteId: props.note.id, - limit: 5 + limit: 5, }).then(res => { replies = res; }); diff --git a/packages/client/src/components/abuse-report.vue b/packages/client/src/components/abuse-report.vue index 2b89eef85a..8c25df1107 100644 --- a/packages/client/src/components/abuse-report.vue +++ b/packages/client/src/components/abuse-report.vue @@ -9,7 +9,7 @@ </div> </MkA> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.registeredDate }}</template> + <template #key>{{ i18n.ts.registeredDate }}</template> <template #value>{{ new Date(report.targetUser.createdAt).toLocaleString() }} (<MkTime :time="report.targetUser.createdAt"/>)</template> </MkKeyValue> </div> @@ -18,18 +18,18 @@ <Mfm :text="report.comment"/> </div> <hr/> - <div>{{ $ts.reporter }}: <MkAcct :user="report.reporter"/></div> + <div>{{ i18n.ts.reporter }}: <MkAcct :user="report.reporter"/></div> <div v-if="report.assignee"> - {{ $ts.moderator }}: + {{ i18n.ts.moderator }}: <MkAcct :user="report.assignee"/> </div> <div><MkTime :time="report.createdAt"/></div> <div class="action"> <MkSwitch v-model="forward" :disabled="report.targetUser.host == null || report.resolved"> - {{ $ts.forwardReport }} - <template #caption>{{ $ts.forwardReportIsAnonymous }}</template> + {{ i18n.ts.forwardReport }} + <template #caption>{{ i18n.ts.forwardReportIsAnonymous }}</template> </MkSwitch> - <MkButton v-if="!report.resolved" primary @click="resolve">{{ $ts.abuseMarkAsResolved }}</MkButton> + <MkButton v-if="!report.resolved" primary @click="resolve">{{ i18n.ts.abuseMarkAsResolved }}</MkButton> </div> </div> </div> @@ -41,6 +41,7 @@ import MkSwitch from '@/components/form/switch.vue'; import MkKeyValue from '@/components/key-value.vue'; import { acct, userPage } from '@/filters/user'; import * as os from '@/os'; +import { i18n } from '@/i18n'; const props = defineProps<{ report: any; diff --git a/packages/client/src/components/analog-clock.vue b/packages/client/src/components/analog-clock.vue index 18dd1e3f41..b138bfcb46 100644 --- a/packages/client/src/components/analog-clock.vue +++ b/packages/client/src/components/analog-clock.vue @@ -1,12 +1,30 @@ <template> <svg class="mbcofsoe" viewBox="0 0 10 10" preserveAspectRatio="none"> - <circle v-for="(angle, i) in graduations" - :key="i" - :cx="5 + (Math.sin(angle) * (5 - graduationsPadding))" - :cy="5 - (Math.cos(angle) * (5 - graduationsPadding))" - :r="i % 5 == 0 ? 0.125 : 0.05" - :fill="i % 5 == 0 ? majorGraduationColor : minorGraduationColor" - /> + <template v-if="props.graduations === 'dots'"> + <circle + v-for="(angle, i) in graduationsMajor" + :cx="5 + (Math.sin(angle) * (5 - graduationsPadding))" + :cy="5 - (Math.cos(angle) * (5 - graduationsPadding))" + :r="0.125" + :fill="(props.twentyfour ? h : h % 12) === i ? nowColor : majorGraduationColor" + :opacity="!props.fadeGraduations || (props.twentyfour ? h : h % 12) === i ? 1 : Math.max(0, 1 - (angleDiff(hAngle, angle) / Math.PI) - numbersOpacityFactor)" + /> + </template> + <template v-else-if="props.graduations === 'numbers'"> + <text + v-for="(angle, i) in texts" + :x="5 + (Math.sin(angle) * (5 - textsPadding))" + :y="5 - (Math.cos(angle) * (5 - textsPadding))" + text-anchor="middle" + dominant-baseline="middle" + :font-size="(props.twentyfour ? h : h % 12) === i ? 1 : 0.7" + :font-weight="(props.twentyfour ? h : h % 12) === i ? 'bold' : 'normal'" + :fill="(props.twentyfour ? h : h % 12) === i ? nowColor : 'currentColor'" + :opacity="!props.fadeGraduations || (props.twentyfour ? h : h % 12) === i ? 1 : Math.max(0, 1 - (angleDiff(hAngle, angle) / Math.PI) - numbersOpacityFactor)" + > + {{ i === 0 ? (props.twentyfour ? '24' : '12') : i }} + </text> + </template> <line :x1="5 - (Math.sin(sAngle) * (sHandLengthRatio * handsTailLength))" @@ -41,63 +59,116 @@ </template> <script lang="ts" setup> -import { ref, computed, onMounted, onBeforeUnmount } from 'vue'; +import { ref, computed, onMounted, onBeforeUnmount, shallowRef } from 'vue'; import tinycolor from 'tinycolor2'; +import { globalEvents } from '@/events.js'; + +// https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles +const angleDiff = (a: number, b: number) => { + const x = Math.abs(a - b); + return Math.abs((x + Math.PI) % (Math.PI * 2) - Math.PI); +}; + +const graduationsPadding = 0.5; +const textsPadding = 0.6; +const handsPadding = 1; +const handsTailLength = 0.7; +const hHandLengthRatio = 0.75; +const mHandLengthRatio = 1; +const sHandLengthRatio = 1; +const numbersOpacityFactor = 0.35; -withDefaults(defineProps<{ - thickness: number; +const props = withDefaults(defineProps<{ + thickness?: number; + offset?: number; + twentyfour?: boolean; + graduations?: 'none' | 'dots' | 'numbers'; + fadeGraduations?: boolean; }>(), { + numbers: false, thickness: 0.1, + offset: 0 - new Date().getTimezoneOffset(), + twentyfour: false, + graduations: 'dots', + fadeGraduations: true, }); -const now = ref(new Date()); -const enabled = ref(true); -const graduationsPadding = ref(0.5); -const handsPadding = ref(1); -const handsTailLength = ref(0.7); -const hHandLengthRatio = ref(0.75); -const mHandLengthRatio = ref(1); -const sHandLengthRatio = ref(1); -const computedStyle = getComputedStyle(document.documentElement); - -const dark = computed(() => tinycolor(computedStyle.getPropertyValue('--bg')).isDark()); -const majorGraduationColor = computed(() => dark.value ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)'); -const minorGraduationColor = computed(() => dark.value ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'); -const sHandColor = computed(() => dark.value ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.3)'); -const mHandColor = computed(() => tinycolor(computedStyle.getPropertyValue('--fg')).toHexString()); -const hHandColor = computed(() => tinycolor(computedStyle.getPropertyValue('--accent')).toHexString()); -const s = computed(() => now.value.getSeconds()); -const m = computed(() => now.value.getMinutes()); -const h = computed(() => now.value.getHours()); -const hAngle = computed(() => Math.PI * (h.value % 12 + (m.value + s.value / 60) / 60) / 6); -const mAngle = computed(() => Math.PI * (m.value + s.value / 60) / 30); -const sAngle = computed(() => Math.PI * s.value / 30); -const graduations = computed(() => { +const graduationsMajor = computed(() => { const angles: number[] = []; - for (let i = 0; i < 60; i++) { - const angle = Math.PI * i / 30; + const times = props.twentyfour ? 24 : 12; + for (let i = 0; i < times; i++) { + const angle = Math.PI * i / (times / 2); angles.push(angle); } - return angles; }); +const texts = computed(() => { + const angles: number[] = []; + const times = props.twentyfour ? 24 : 12; + for (let i = 0; i < times; i++) { + const angle = Math.PI * i / (times / 2); + angles.push(angle); + } + return angles; +}); + +let enabled = true; +let majorGraduationColor = $ref<string>(); +//let minorGraduationColor = $ref<string>(); +let sHandColor = $ref<string>(); +let mHandColor = $ref<string>(); +let hHandColor = $ref<string>(); +let nowColor = $ref<string>(); +let h = $ref<number>(0); +let m = $ref<number>(0); +let s = $ref<number>(0); +let hAngle = $ref<number>(0); +let mAngle = $ref<number>(0); +let sAngle = $ref<number>(0); function tick() { - now.value = new Date(); + const now = new Date(); + now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)); + s = now.getSeconds(); + m = now.getMinutes(); + h = now.getHours(); + hAngle = Math.PI * (h % (props.twentyfour ? 24 : 12) + (m + s / 60) / 60) / (props.twentyfour ? 12 : 6); + mAngle = Math.PI * (m + s / 60) / 30; + sAngle = Math.PI * s / 30; +} + +tick(); + +function calcColors() { + const computedStyle = getComputedStyle(document.documentElement); + const dark = tinycolor(computedStyle.getPropertyValue('--bg')).isDark(); + const accent = tinycolor(computedStyle.getPropertyValue('--accent')).toHexString(); + majorGraduationColor = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)'; + //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)'; + mHandColor = tinycolor(computedStyle.getPropertyValue('--fg')).toHexString(); + hHandColor = accent; + nowColor = accent; } +calcColors(); + onMounted(() => { const update = () => { - if (enabled.value) { + if (enabled) { tick(); window.setTimeout(update, 1000); } }; update(); + + globalEvents.on('themeChanged', calcColors); }); onBeforeUnmount(() => { - enabled.value = false; + enabled = false; + + globalEvents.off('themeChanged', calcColors); }); </script> diff --git a/packages/client/src/components/cropper-dialog.vue b/packages/client/src/components/cropper-dialog.vue index a8bde6ea05..c320b21d72 100644 --- a/packages/client/src/components/cropper-dialog.vue +++ b/packages/client/src/components/cropper-dialog.vue @@ -9,7 +9,7 @@ @ok="ok()" @closed="$emit('closed')" > - <template #header>{{ $ts.cropImage }}</template> + <template #header>{{ i18n.ts.cropImage }}</template> <template #default="{ width, height }"> <div class="mk-cropper-dialog" :style="`--vw: ${width}px; --vh: ${height}px;`"> <Transition name="fade"> @@ -36,6 +36,7 @@ import { $i } from '@/account'; import { defaultStore } from '@/store'; import { apiUrl, url } from '@/config'; import { query } from '@/scripts/url'; +import { i18n } from '@/i18n'; const emit = defineEmits<{ (ev: 'ok', cropped: misskey.entities.DriveFile): void; diff --git a/packages/client/src/components/digital-clock.vue b/packages/client/src/components/digital-clock.vue new file mode 100644 index 0000000000..9ed8d63d19 --- /dev/null +++ b/packages/client/src/components/digital-clock.vue @@ -0,0 +1,77 @@ +<template> +<span class="zjobosdg"> + <span v-text="hh"></span> + <span class="colon" :class="{ showColon }">:</span> + <span v-text="mm"></span> + <span v-if="showS" class="colon" :class="{ showColon }">:</span> + <span v-if="showS" v-text="ss"></span> + <span v-if="showMs" class="colon" :class="{ showColon }">:</span> + <span v-if="showMs" v-text="ms"></span> +</span> +</template> + +<script lang="ts" setup> +import { onUnmounted, ref, watch } from 'vue'; + +const props = withDefaults(defineProps<{ + showS?: boolean; + showMs?: boolean; + offset?: number; +}>(), { + showS: true, + showMs: false, + offset: 0 - new Date().getTimezoneOffset(), +}); + +let intervalId; +const hh = ref(''); +const mm = ref(''); +const ss = ref(''); +const ms = ref(''); +const showColon = ref(false); +let prevSec: number | null = null; + +watch(showColon, (v) => { + if (v) { + window.setTimeout(() => { + showColon.value = false; + }, 30); + } +}); + +const tick = () => { + const now = new Date(); + now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)); + hh.value = now.getHours().toString().padStart(2, '0'); + mm.value = now.getMinutes().toString().padStart(2, '0'); + ss.value = now.getSeconds().toString().padStart(2, '0'); + ms.value = Math.floor(now.getMilliseconds() / 10).toString().padStart(2, '0'); + if (now.getSeconds() !== prevSec) showColon.value = true; + prevSec = now.getSeconds(); +}; + +tick(); + +watch(() => props.showMs, () => { + if (intervalId) window.clearInterval(intervalId); + intervalId = window.setInterval(tick, props.showMs ? 10 : 1000); +}, { immediate: true }); + +onUnmounted(() => { + window.clearInterval(intervalId); +}); +</script> + +<style lang="scss" scoped> +.zjobosdg { + > .colon { + opacity: 0; + transition: opacity 1s ease; + + &.showColon { + opacity: 1; + transition: opacity 0s; + } + } +} +</style> diff --git a/packages/client/src/components/form/checkbox.vue b/packages/client/src/components/form/checkbox.vue index fadb770aee..fb5c82bb48 100644 --- a/packages/client/src/components/form/checkbox.vue +++ b/packages/client/src/components/form/checkbox.vue @@ -9,7 +9,7 @@ :disabled="disabled" @keydown.enter="toggle" > - <span ref="button" v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle"> + <span ref="button" v-adaptive-border v-tooltip="checked ? i18n.ts.itsOn : i18n.ts.itsOff" class="button" @click.prevent="toggle"> <i class="check fas fa-check"></i> </span> <span class="label"> @@ -24,6 +24,7 @@ import { toRefs, Ref } from 'vue'; import * as os from '@/os'; import Ripple from '@/components/ripple.vue'; +import { i18n } from '@/i18n'; const props = defineProps<{ modelValue: boolean | Ref<boolean>; diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue index 2a03d6a5d4..1c9fee8c77 100644 --- a/packages/client/src/components/form/input.vue +++ b/packages/client/src/components/form/input.vue @@ -29,7 +29,7 @@ </div> <div class="caption"><slot name="caption"></slot></div> - <MkButton v-if="manualSave && changed" primary class="save" @click="updated"><i class="fas fa-check"></i> {{ $ts.save }}</MkButton> + <MkButton v-if="manualSave && changed" primary class="save" @click="updated"><i class="fas fa-check"></i> {{ i18n.ts.save }}</MkButton> </div> </template> @@ -38,6 +38,7 @@ import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from ' import { debounce } from 'throttle-debounce'; import MkButton from '@/components/ui/button.vue'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const props = defineProps<{ modelValue: string | number; diff --git a/packages/client/src/components/form/link.vue b/packages/client/src/components/form/link.vue index b74e9bd684..34b641ffb6 100644 --- a/packages/client/src/components/form/link.vue +++ b/packages/client/src/components/form/link.vue @@ -19,33 +19,16 @@ </div> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { } from 'vue'; -export default defineComponent({ - props: { - to: { - type: String, - required: true - }, - active: { - type: Boolean, - required: false - }, - external: { - type: Boolean, - required: false - }, - behavior: { - type: String, - required: false, - }, - inline: { - type: Boolean, - required: false - }, - }, -}); +const props = defineProps<{ + to: string; + active?: boolean; + external?: boolean; + behavior?: null | 'window' | 'browser' | 'modalWindow'; + inline?: boolean; +}>(); </script> <style lang="scss" scoped> @@ -61,7 +44,7 @@ export default defineComponent({ align-items: center; width: 100%; box-sizing: border-box; - padding: 12px 14px 12px 14px; + padding: 10px 14px; background: var(--buttonBg); border-radius: 6px; font-size: 0.9em; diff --git a/packages/client/src/components/form/radio.vue b/packages/client/src/components/form/radio.vue index b4d39507e3..b36f7e9fdc 100644 --- a/packages/client/src/components/form/radio.vue +++ b/packages/client/src/components/form/radio.vue @@ -18,34 +18,25 @@ </div> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { } from 'vue'; -export default defineComponent({ - props: { - modelValue: { - required: false, - }, - value: { - required: false, - }, - disabled: { - type: Boolean, - default: false, - }, - }, - computed: { - checked(): boolean { - return this.modelValue === this.value; - }, - }, - methods: { - toggle() { - if (this.disabled) return; - this.$emit('update:modelValue', this.value); - }, - }, -}); +const props = defineProps<{ + modelValue: any; + value: any; + disabled: boolean; +}>(); + +const emit = defineEmits<{ + (ev: 'update:modelValue', value: any): void; +}>(); + +let checked = $computed(() => props.modelValue === props.value); + +function toggle(): void { + if (props.disabled) return; + emit('update:modelValue', props.value); +} </script> <style lang="scss" scoped> @@ -54,13 +45,13 @@ export default defineComponent({ display: inline-block; text-align: left; cursor: pointer; - padding: 9px 12px; + padding: 8px 10px; min-width: 60px; background-color: var(--panel); background-clip: padding-box !important; border: solid 1px var(--panel); border-radius: 6px; - transition: all 0.3s; + transition: all 0.2s; > * { user-select: none; diff --git a/packages/client/src/components/form/select.vue b/packages/client/src/components/form/select.vue index 78282dfdc1..70db2dbae3 100644 --- a/packages/client/src/components/form/select.vue +++ b/packages/client/src/components/form/select.vue @@ -22,7 +22,7 @@ </div> <div class="caption"><slot name="caption"></slot></div> - <MkButton v-if="manualSave && changed" primary @click="updated"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton v-if="manualSave && changed" primary @click="updated"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton> </div> </template> @@ -31,6 +31,7 @@ import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode, import MkButton from '@/components/ui/button.vue'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const props = defineProps<{ modelValue: string; @@ -144,6 +145,8 @@ const onClick = (ev: MouseEvent) => { } else if (Array.isArray(vnode.children)) { // 何故ã‹ãƒ•ラグメントã«ãªã£ã¦ãã‚‹ã“ã¨ãŒã‚ã‚‹ const fragment = vnode; scanOptions(fragment.children); + } else if (vnode.props == null) { // v-if ã§æ¡ä»¶ãŒ false ã®ã¨ãã«ã“ã†ãªã‚‹ + // nop? } else { const option = vnode; pushOption(option); diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue index fead163552..1ed00ae655 100644 --- a/packages/client/src/components/form/switch.vue +++ b/packages/client/src/components/form/switch.vue @@ -9,7 +9,7 @@ :disabled="disabled" @keydown.enter="toggle" > - <span ref="button" v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle"> + <span ref="button" v-tooltip="checked ? i18n.ts.itsOn : i18n.ts.itsOff" class="button" @click.prevent="toggle"> <div class="knob"></div> </span> <span class="label"> @@ -23,6 +23,7 @@ <script lang="ts" setup> import { toRefs, Ref } from 'vue'; import * as os from '@/os'; +import { i18n } from '@/i18n'; const props = defineProps<{ modelValue: boolean | Ref<boolean>; diff --git a/packages/client/src/components/form/textarea.vue b/packages/client/src/components/form/textarea.vue index c9ba9b97a2..73633399de 100644 --- a/packages/client/src/components/form/textarea.vue +++ b/packages/client/src/components/form/textarea.vue @@ -2,7 +2,8 @@ <div class="adhpbeos"> <div class="label" @click="focus"><slot name="label"></slot></div> <div class="input" :class="{ disabled, focused, tall, pre }"> - <textarea ref="inputEl" + <textarea + ref="inputEl" v-model="v" v-adaptive-border :class="{ code, _monospace: code }" @@ -21,14 +22,15 @@ </div> <div class="caption"><slot name="caption"></slot></div> - <MkButton v-if="manualSave && changed" primary class="save" @click="updated"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton v-if="manualSave && changed" primary class="save" @click="updated"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton> </div> </template> <script lang="ts"> import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; -import MkButton from '@/components/ui/button.vue'; import { debounce } from 'throttle-debounce'; +import MkButton from '@/components/ui/button.vue'; +import { i18n } from '@/i18n'; export default defineComponent({ components: { @@ -37,66 +39,66 @@ export default defineComponent({ props: { modelValue: { - required: true + required: true, }, type: { type: String, - required: false + required: false, }, required: { type: Boolean, - required: false + required: false, }, readonly: { type: Boolean, - required: false + required: false, }, disabled: { type: Boolean, - required: false + required: false, }, pattern: { type: String, - required: false + required: false, }, placeholder: { type: String, - required: false + required: false, }, autofocus: { type: Boolean, required: false, - default: false + default: false, }, autocomplete: { - required: false + required: false, }, spellcheck: { - required: false + required: false, }, code: { type: Boolean, - required: false + required: false, }, tall: { type: Boolean, required: false, - default: false + default: false, }, pre: { type: Boolean, required: false, - default: false + default: false, }, debounce: { type: Boolean, required: false, - default: false + default: false, }, manualSave: { type: Boolean, required: false, - default: false + default: false, }, }, @@ -166,6 +168,7 @@ export default defineComponent({ onInput, onKeydown, updated, + i18n, }; }, }); diff --git a/packages/client/src/components/global/error.vue b/packages/client/src/components/global/error.vue index 98b96fb414..4e2ba07d30 100644 --- a/packages/client/src/components/global/error.vue +++ b/packages/client/src/components/global/error.vue @@ -2,14 +2,15 @@ <transition :name="$store.state.animation ? 'zoom' : ''" appear> <div class="mjndxjcg"> <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> - <p><i class="fas fa-exclamation-triangle"></i> {{ $ts.somethingHappened }}</p> - <MkButton class="button" @click="() => $emit('retry')">{{ $ts.retry }}</MkButton> + <p><i class="fas fa-exclamation-triangle"></i> {{ i18n.ts.somethingHappened }}</p> + <MkButton class="button" @click="() => $emit('retry')">{{ i18n.ts.retry }}</MkButton> </div> </transition> </template> <script lang="ts" setup> import MkButton from '@/components/ui/button.vue'; +import { i18n } from '@/i18n'; </script> <style lang="scss" scoped> diff --git a/packages/client/src/components/global/router-view.vue b/packages/client/src/components/global/router-view.vue index fca2371f0d..1d841e050c 100644 --- a/packages/client/src/components/global/router-view.vue +++ b/packages/client/src/components/global/router-view.vue @@ -1,12 +1,18 @@ <template> <KeepAlive :max="defaultStore.state.numberOfPageCache"> - <component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/> + <Suspense> + <component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/> + + <template #fallback> + Loading... + </template> + </Suspense> </KeepAlive> </template> <script lang="ts" setup> -import { inject, nextTick, onMounted, onUnmounted, watch } from 'vue'; -import { Router } from '@/nirax'; +import { inject, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, watch } from 'vue'; +import { Resolved, Router } from '@/nirax'; import { defaultStore } from '@/store'; const props = defineProps<{ @@ -19,19 +25,37 @@ if (router == null) { throw new Error('no router provided'); } -let currentPageComponent = $shallowRef(router.getCurrentComponent()); -let currentPageProps = $ref(router.getCurrentProps()); -let key = $ref(router.getCurrentKey()); +const currentDepth = inject('routerCurrentDepth', 0); +provide('routerCurrentDepth', currentDepth + 1); + +function resolveNested(current: Resolved, d = 0): Resolved | null { + if (d === currentDepth) { + return current; + } else { + if (current.child) { + return resolveNested(current.child, d + 1); + } else { + return null; + } + } +} + +const current = resolveNested(router.current)!; +let currentPageComponent = $shallowRef(current.route.component); +let currentPageProps = $ref(current.props); +let key = $ref(current.route.path + JSON.stringify(Object.fromEntries(current.props))); -function onChange({ route, props: newProps, key: newKey }) { - currentPageComponent = route.component; - currentPageProps = newProps; - key = newKey; +function onChange({ resolved, key: newKey }) { + const current = resolveNested(resolved); + if (current == null) return; + currentPageComponent = current.route.component; + currentPageProps = current.props; + key = current.route.path + JSON.stringify(Object.fromEntries(current.props)); } router.addListener('change', onChange); -onUnmounted(() => { +onBeforeUnmount(() => { router.removeListener('change', onChange); }); </script> diff --git a/packages/client/src/components/global/time.vue b/packages/client/src/components/global/time.vue index 801490225b..f72b153f56 100644 --- a/packages/client/src/components/global/time.vue +++ b/packages/client/src/components/global/time.vue @@ -20,7 +20,7 @@ const props = withDefaults(defineProps<{ const _time = typeof props.time === 'string' ? new Date(props.time) : props.time; const absolute = _time.toLocaleString(); -let now = $ref(new Date()); +let now = $shallowRef(new Date()); const relative = $computed(() => { const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/; return ( diff --git a/packages/client/src/components/instance-stats.vue b/packages/client/src/components/instance-stats.vue index 1a811c2d87..65465dd9a2 100644 --- a/packages/client/src/components/instance-stats.vue +++ b/packages/client/src/components/instance-stats.vue @@ -4,29 +4,29 @@ <div class="body"> <div class="selects" style="display: flex;"> <MkSelect v-model="chartSrc" style="margin: 0; flex: 1;"> - <optgroup :label="$ts.federation"> - <option value="federation">{{ $ts._charts.federation }}</option> - <option value="ap-request">{{ $ts._charts.apRequest }}</option> + <optgroup :label="i18n.ts.federation"> + <option value="federation">{{ i18n.ts._charts.federation }}</option> + <option value="ap-request">{{ i18n.ts._charts.apRequest }}</option> </optgroup> - <optgroup :label="$ts.users"> - <option value="users">{{ $ts._charts.usersIncDec }}</option> - <option value="users-total">{{ $ts._charts.usersTotal }}</option> - <option value="active-users">{{ $ts._charts.activeUsers }}</option> + <optgroup :label="i18n.ts.users"> + <option value="users">{{ i18n.ts._charts.usersIncDec }}</option> + <option value="users-total">{{ i18n.ts._charts.usersTotal }}</option> + <option value="active-users">{{ i18n.ts._charts.activeUsers }}</option> </optgroup> - <optgroup :label="$ts.notes"> - <option value="notes">{{ $ts._charts.notesIncDec }}</option> - <option value="local-notes">{{ $ts._charts.localNotesIncDec }}</option> - <option value="remote-notes">{{ $ts._charts.remoteNotesIncDec }}</option> - <option value="notes-total">{{ $ts._charts.notesTotal }}</option> + <optgroup :label="i18n.ts.notes"> + <option value="notes">{{ i18n.ts._charts.notesIncDec }}</option> + <option value="local-notes">{{ i18n.ts._charts.localNotesIncDec }}</option> + <option value="remote-notes">{{ i18n.ts._charts.remoteNotesIncDec }}</option> + <option value="notes-total">{{ i18n.ts._charts.notesTotal }}</option> </optgroup> - <optgroup :label="$ts.drive"> - <option value="drive-files">{{ $ts._charts.filesIncDec }}</option> - <option value="drive">{{ $ts._charts.storageUsageIncDec }}</option> + <optgroup :label="i18n.ts.drive"> + <option value="drive-files">{{ i18n.ts._charts.filesIncDec }}</option> + <option value="drive">{{ i18n.ts._charts.storageUsageIncDec }}</option> </optgroup> </MkSelect> <MkSelect v-model="chartSpan" style="margin: 0 0 0 10px;"> - <option value="hour">{{ $ts.perHour }}</option> - <option value="day">{{ $ts.perDay }}</option> + <option value="hour">{{ i18n.ts.perHour }}</option> + <option value="day">{{ i18n.ts.perDay }}</option> </MkSelect> </div> <div class="chart"> @@ -71,6 +71,7 @@ import MkSelect from '@/components/form/select.vue'; import MkChart from '@/components/chart.vue'; import { useChartTooltip } from '@/scripts/use-chart-tooltip'; import * as os from '@/os'; +import { i18n } from '@/i18n'; Chart.register( ArcElement, diff --git a/packages/client/src/components/key-value.vue b/packages/client/src/components/key-value.vue index 3d665e159d..586f7a3f9d 100644 --- a/packages/client/src/components/key-value.vue +++ b/packages/client/src/components/key-value.vue @@ -5,7 +5,7 @@ </div> <div class="value"> <slot name="value"></slot> - <button v-if="copy" v-tooltip="$ts.copy" class="_textButton" style="margin-left: 0.5em;" @click="copy_"><i class="far fa-copy"></i></button> + <button v-if="copy" v-tooltip="i18n.ts.copy" class="_textButton" style="margin-left: 0.5em;" @click="copy_"><i class="far fa-copy"></i></button> </div> </div> </template> @@ -14,6 +14,7 @@ import { } from 'vue'; import copyToClipboard from '@/scripts/copy-to-clipboard'; import * as os from '@/os'; +import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ copy?: string | null; diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue index 85bffca4a5..1e0625b6c9 100644 --- a/packages/client/src/components/note-detailed.vue +++ b/packages/client/src/components/note-detailed.vue @@ -14,7 +14,7 @@ <div v-if="isRenote" class="renote"> <MkAvatar class="avatar" :user="note.user"/> <i class="fas fa-retweet"></i> - <I18n :src="$ts.renotedBy" tag="span"> + <I18n :src="i18n.ts.renotedBy" tag="span"> <template #user> <MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)"> <MkUserName :user="note.user"/> @@ -54,7 +54,7 @@ </p> <div v-show="appearNote.cw == null || showContent" class="content"> <div class="text"> - <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span> + <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <a v-if="appearNote.renote != null" class="rp">RN:</a> @@ -103,7 +103,7 @@ <MkNoteSub v-for="note in replies" :key="note.id" :note="note" class="reply" :detail="true"/> </div> <div v-else class="_panel muted" @click="muted = false"> - <I18n :src="$ts.userSaysSomething" tag="small"> + <I18n :src="i18n.ts.userSaysSomething" tag="small"> <template #name> <MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)"> <MkUserName :user="appearNote.user"/> diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index 3c9d361702..0279f014c6 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -41,7 +41,7 @@ <Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <XCwButton v-model="showContent" :note="appearNote"/> </p> - <div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed }"> + <div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed, isLong }"> <div class="text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> @@ -61,9 +61,12 @@ <XPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/> <div v-if="appearNote.renote" class="renote"><XNoteSimple :note="appearNote.renote"/></div> - <button v-if="collapsed" class="fade _button" @click="collapsed = false"> + <button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false"> <span>{{ i18n.ts.showMore }}</span> </button> + <button v-else-if="isLong && !collapsed" class="showLess _button" @click="collapsed = true"> + <span>{{ i18n.ts.showLess }}</span> + </button> </div> <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA> </div> @@ -162,10 +165,11 @@ const reactButton = ref<HTMLElement>(); let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note); const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); -const collapsed = ref(appearNote.cw == null && appearNote.text != null && ( +const isLong = (appearNote.cw == null && appearNote.text != null && ( (appearNote.text.split('\n').length > 9) || (appearNote.text.length > 500) )); +const collapsed = ref(appearNote.cw == null && isLong); const isDeleted = ref(false); const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords)); const translation = ref(null); @@ -442,6 +446,24 @@ function readPromo() { } > .content { + &.isLong { + > .showLess { + width: 100%; + margin-top: 1em; + position: sticky; + bottom: 1em; + + > span { + display: inline-block; + background: var(--popup); + padding: 6px 10px; + font-size: 0.8em; + border-radius: 999px; + box-shadow: 0 2px 6px rgb(0 0 0 / 20%); + } + } + } + &.collapsed { position: relative; max-height: 9em; diff --git a/packages/client/src/components/notes.vue b/packages/client/src/components/notes.vue index 41bec5a579..e351a76eb5 100644 --- a/packages/client/src/components/notes.vue +++ b/packages/client/src/components/notes.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.noNotes }}</div> + <div>{{ i18n.ts.noNotes }}</div> </div> </template> @@ -21,8 +21,8 @@ import { ref } from 'vue'; import XNote from '@/components/note.vue'; import XList from '@/components/date-separated-list.vue'; -import MkPagination from '@/components/ui/pagination.vue'; -import { Paging } from '@/components/ui/pagination.vue'; +import MkPagination, { Paging } from '@/components/ui/pagination.vue'; +import { i18n } from '@/i18n'; const props = defineProps<{ pagination: Paging; diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue index 10cbe20902..9589970a44 100644 --- a/packages/client/src/components/notification.vue +++ b/packages/client/src/components/notification.vue @@ -61,10 +61,10 @@ <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/> <i class="fas fa-quote-right"></i> </MkA> - <span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span> - <span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $ts.followRequestAccepted }}</span> - <span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $ts.reject }}</button></div></span> - <span v-if="notification.type === 'groupInvited'" class="text" style="opacity: 0.6;">{{ $ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ $ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ $ts.reject }}</button></div></span> + <span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ i18n.ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span> + <span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ i18n.ts.followRequestAccepted }}</span> + <span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ i18n.ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ i18n.ts.reject }}</button></div></span> + <span v-if="notification.type === 'groupInvited'" class="text" style="opacity: 0.6;">{{ i18n.ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ i18n.ts.reject }}</button></div></span> <span v-if="notification.type === 'app'" class="text"> <Mfm :text="notification.body" :nowrap="!full"/> </span> diff --git a/packages/client/src/components/notifications.vue b/packages/client/src/components/notifications.vue index eb19ad488c..baac2fdca2 100644 --- a/packages/client/src/components/notifications.vue +++ b/packages/client/src/components/notifications.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.noNotifications }}</div> + <div>{{ i18n.ts.noNotifications }}</div> </div> </template> @@ -26,6 +26,7 @@ import XNote from '@/components/note.vue'; import * as os from '@/os'; import { stream } from '@/stream'; import { $i } from '@/account'; +import { i18n } from '@/i18n'; const props = defineProps<{ includeTypes?: typeof notificationTypes[number][]; diff --git a/packages/client/src/components/page-window.vue b/packages/client/src/components/page-window.vue index 98140b95c0..43d75b0cf9 100644 --- a/packages/client/src/components/page-window.vue +++ b/packages/client/src/components/page-window.vue @@ -114,7 +114,7 @@ function menu(ev) { function back() { history.pop(); - router.change(history[history.length - 1].path, history[history.length - 1].key); + router.replace(history[history.length - 1].path, history[history.length - 1].key); } function close() { diff --git a/packages/client/src/components/poll-editor.vue b/packages/client/src/components/poll-editor.vue index a068aca79e..6c1a4cc89f 100644 --- a/packages/client/src/components/poll-editor.vue +++ b/packages/client/src/components/poll-editor.vue @@ -1,7 +1,7 @@ <template> <div class="zmdxowus"> <p v-if="choices.length < 2" class="caution"> - <i class="fas fa-exclamation-triangle"></i>{{ $ts._poll.noOnlyOneChoice }} + <i class="fas fa-exclamation-triangle"></i>{{ i18n.ts._poll.noOnlyOneChoice }} </p> <ul> <li v-for="(choice, i) in choices" :key="i"> @@ -12,34 +12,34 @@ </button> </li> </ul> - <MkButton v-if="choices.length < 10" class="add" @click="add">{{ $ts.add }}</MkButton> - <MkButton v-else class="add" disabled>{{ $ts._poll.noMore }}</MkButton> - <MkSwitch v-model="multiple">{{ $ts._poll.canMultipleVote }}</MkSwitch> + <MkButton v-if="choices.length < 10" class="add" @click="add">{{ i18n.ts.add }}</MkButton> + <MkButton v-else class="add" disabled>{{ i18n.ts._poll.noMore }}</MkButton> + <MkSwitch v-model="multiple">{{ i18n.ts._poll.canMultipleVote }}</MkSwitch> <section> <div> <MkSelect v-model="expiration" small> - <template #label>{{ $ts._poll.expiration }}</template> - <option value="infinite">{{ $ts._poll.infinite }}</option> - <option value="at">{{ $ts._poll.at }}</option> - <option value="after">{{ $ts._poll.after }}</option> + <template #label>{{ i18n.ts._poll.expiration }}</template> + <option value="infinite">{{ i18n.ts._poll.infinite }}</option> + <option value="at">{{ i18n.ts._poll.at }}</option> + <option value="after">{{ i18n.ts._poll.after }}</option> </MkSelect> <section v-if="expiration === 'at'"> <MkInput v-model="atDate" small type="date" class="input"> - <template #label>{{ $ts._poll.deadlineDate }}</template> + <template #label>{{ i18n.ts._poll.deadlineDate }}</template> </MkInput> <MkInput v-model="atTime" small type="time" class="input"> - <template #label>{{ $ts._poll.deadlineTime }}</template> + <template #label>{{ i18n.ts._poll.deadlineTime }}</template> </MkInput> </section> <section v-else-if="expiration === 'after'"> <MkInput v-model="after" small type="number" class="input"> - <template #label>{{ $ts._poll.duration }}</template> + <template #label>{{ i18n.ts._poll.duration }}</template> </MkInput> <MkSelect v-model="unit" small> - <option value="second">{{ $ts._time.second }}</option> - <option value="minute">{{ $ts._time.minute }}</option> - <option value="hour">{{ $ts._time.hour }}</option> - <option value="day">{{ $ts._time.day }}</option> + <option value="second">{{ i18n.ts._time.second }}</option> + <option value="minute">{{ i18n.ts._time.minute }}</option> + <option value="hour">{{ i18n.ts._time.hour }}</option> + <option value="day">{{ i18n.ts._time.day }}</option> </MkSelect> </section> </div> @@ -55,6 +55,7 @@ import MkSwitch from './form/switch.vue'; import MkButton from './ui/button.vue'; import { formatDateTimeString } from '@/scripts/format-time-string'; import { addTime } from '@/scripts/time'; +import { i18n } from '@/i18n'; const props = defineProps<{ modelValue: { diff --git a/packages/client/src/components/poll.vue b/packages/client/src/components/poll.vue index 35f87325d8..d90af1cfee 100644 --- a/packages/client/src/components/poll.vue +++ b/packages/client/src/components/poll.vue @@ -13,97 +13,77 @@ <p v-if="!readOnly"> <span>{{ $t('_poll.totalVotes', { n: total }) }}</span> <span> · </span> - <a v-if="!closed && !isVoted" @click="showResult = !showResult">{{ showResult ? $ts._poll.vote : $ts._poll.showResult }}</a> - <span v-if="isVoted">{{ $ts._poll.voted }}</span> - <span v-else-if="closed">{{ $ts._poll.closed }}</span> + <a v-if="!closed && !isVoted" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a> + <span v-if="isVoted">{{ i18n.ts._poll.voted }}</span> + <span v-else-if="closed">{{ i18n.ts._poll.closed }}</span> <span v-if="remaining > 0"> · {{ timer }}</span> </p> </div> </template> -<script lang="ts"> -import { computed, defineComponent, onUnmounted, ref, toRef } from 'vue'; +<script lang="ts" setup> +import { computed, onUnmounted, ref, toRef } from 'vue'; +import * as misskey from 'misskey-js'; import { sum } from '@/scripts/array'; import { pleaseLogin } from '@/scripts/please-login'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { useInterval } from '@/scripts/use-interval'; -export default defineComponent({ - props: { - note: { - type: Object, - required: true, - }, - readOnly: { - type: Boolean, - required: false, - default: false, - }, - }, +const props = defineProps<{ + note: misskey.entities.Note; + readOnly?: boolean; +}>(); - setup(props) { - const remaining = ref(-1); +const remaining = ref(-1); - const total = computed(() => sum(props.note.poll.choices.map(x => x.votes))); - const closed = computed(() => remaining.value === 0); - const isVoted = computed(() => !props.note.poll.multiple && props.note.poll.choices.some(c => c.isVoted)); - const timer = computed(() => i18n.t( - remaining.value >= 86400 ? '_poll.remainingDays' : - remaining.value >= 3600 ? '_poll.remainingHours' : - remaining.value >= 60 ? '_poll.remainingMinutes' : '_poll.remainingSeconds', { - s: Math.floor(remaining.value % 60), - m: Math.floor(remaining.value / 60) % 60, - h: Math.floor(remaining.value / 3600) % 24, - d: Math.floor(remaining.value / 86400), - })); +const total = computed(() => sum(props.note.poll.choices.map(x => x.votes))); +const closed = computed(() => remaining.value === 0); +const isVoted = computed(() => !props.note.poll.multiple && props.note.poll.choices.some(c => c.isVoted)); +const timer = computed(() => i18n.t( + remaining.value >= 86400 ? '_poll.remainingDays' : + remaining.value >= 3600 ? '_poll.remainingHours' : + remaining.value >= 60 ? '_poll.remainingMinutes' : '_poll.remainingSeconds', { + s: Math.floor(remaining.value % 60), + m: Math.floor(remaining.value / 60) % 60, + h: Math.floor(remaining.value / 3600) % 24, + d: Math.floor(remaining.value / 86400), + })); - const showResult = ref(props.readOnly || isVoted.value); +const showResult = ref(props.readOnly || isVoted.value); - // 期é™ä»˜ãアンケート - if (props.note.poll.expiresAt) { - const tick = () => { - remaining.value = Math.floor(Math.max(new Date(props.note.poll.expiresAt).getTime() - Date.now(), 0) / 1000); - if (remaining.value === 0) { - showResult.value = true; - } - }; - - useInterval(tick, 3000, { - immediate: true, - afterMounted: false, - }); +// 期é™ä»˜ãアンケート +if (props.note.poll.expiresAt) { + const tick = () => { + remaining.value = Math.floor(Math.max(new Date(props.note.poll.expiresAt).getTime() - Date.now(), 0) / 1000); + if (remaining.value === 0) { + showResult.value = true; } + }; - const vote = async (id) => { - pleaseLogin(); + useInterval(tick, 3000, { + immediate: true, + afterMounted: false, + }); +} - if (props.readOnly || closed.value || isVoted.value) return; +const vote = async (id) => { + pleaseLogin(); - const { canceled } = await os.confirm({ - type: 'question', - text: i18n.t('voteConfirm', { choice: props.note.poll.choices[id].text }), - }); - if (canceled) return; + if (props.readOnly || closed.value || isVoted.value) return; - await os.api('notes/polls/vote', { - noteId: props.note.id, - choice: id, - }); - if (!showResult.value) showResult.value = !props.note.poll.multiple; - }; + const { canceled } = await os.confirm({ + type: 'question', + text: i18n.t('voteConfirm', { choice: props.note.poll.choices[id].text }), + }); + if (canceled) return; - return { - remaining, - showResult, - total, - isVoted, - closed, - timer, - vote, - }; - }, -}); + await os.api('notes/polls/vote', { + noteId: props.note.id, + choice: id, + }); + if (!showResult.value) showResult.value = !props.note.poll.multiple; +}; </script> <style lang="scss" scoped> diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue index 77fcd79c13..6dfb2edcb8 100644 --- a/packages/client/src/components/post-form.vue +++ b/packages/client/src/components/post-form.vue @@ -479,7 +479,22 @@ function onDragover(ev) { if (isFile || isDriveFile) { ev.preventDefault(); draghover = true; - ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move'; + switch (ev.dataTransfer.effectAllowed) { + case 'all': + case 'uninitialized': + case 'copy': + case 'copyLink': + case 'copyMove': + ev.dataTransfer.dropEffect = 'copy'; + break; + case 'linkMove': + case 'move': + ev.dataTransfer.dropEffect = 'move'; + break; + default: + ev.dataTransfer.dropEffect = 'none'; + break; + } } } diff --git a/packages/client/src/components/remote-caution.vue b/packages/client/src/components/remote-caution.vue index 130a0249b6..e9461197ca 100644 --- a/packages/client/src/components/remote-caution.vue +++ b/packages/client/src/components/remote-caution.vue @@ -1,8 +1,10 @@ <template> -<div class="jmgmzlwq _block"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>{{ $ts.remoteUserCaution }}<a class="link" :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div> +<div class="jmgmzlwq _block"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>{{ i18n.ts.remoteUserCaution }}<a class="link" :href="href" rel="nofollow noopener" target="_blank">{{ i18n.ts.showOnRemote }}</a></div> </template> <script lang="ts" setup> +import { i18n } from '@/i18n'; + defineProps<{ href: string; }>(); diff --git a/packages/client/src/components/renote-button.vue b/packages/client/src/components/renote-button.vue index 3bcbe665bf..d267f30403 100644 --- a/packages/client/src/components/renote-button.vue +++ b/packages/client/src/components/renote-button.vue @@ -1,5 +1,6 @@ <template> -<button v-if="canRenote" +<button + v-if="canRenote" ref="buttonRef" class="eddddedb _button canRenote" @click="renote()" @@ -12,8 +13,9 @@ </button> </template> -<script lang="ts"> -import { computed, defineComponent, ref } from 'vue'; +<script lang="ts" setup> +import { computed, ref } from 'vue'; +import * as misskey from 'misskey-js'; import XDetails from '@/components/users-tooltip.vue'; import { pleaseLogin } from '@/scripts/please-login'; import * as os from '@/os'; @@ -21,71 +23,55 @@ import { $i } from '@/account'; import { useTooltip } from '@/scripts/use-tooltip'; import { i18n } from '@/i18n'; -export default defineComponent({ - props: { - count: { - type: Number, - required: true, - }, - note: { - type: Object, - required: true, - }, - }, +const props = defineProps<{ + note: misskey.entities.Note; + count: number; +}>(); - setup(props) { - const buttonRef = ref<HTMLElement>(); +const buttonRef = ref<HTMLElement>(); - const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); +const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); - useTooltip(buttonRef, async (showing) => { - const renotes = await os.api('notes/renotes', { - noteId: props.note.id, - limit: 11 - }); +useTooltip(buttonRef, async (showing) => { + const renotes = await os.api('notes/renotes', { + noteId: props.note.id, + limit: 11, + }); - const users = renotes.map(x => x.user); + const users = renotes.map(x => x.user); - if (users.length < 1) return; + if (users.length < 1) return; - os.popup(XDetails, { - showing, - users, - count: props.count, - targetElement: buttonRef.value - }, {}, 'closed'); - }); + os.popup(XDetails, { + showing, + users, + count: props.count, + targetElement: buttonRef.value, + }, {}, 'closed'); +}); - const renote = (viaKeyboard = false) => { - pleaseLogin(); - os.popupMenu([{ - text: i18n.ts.renote, - icon: 'fas fa-retweet', - action: () => { - os.api('notes/create', { - renoteId: props.note.id - }); - } - }, { - text: i18n.ts.quote, - icon: 'fas fa-quote-right', - action: () => { - os.post({ - renote: props.note, - }); - } - }], buttonRef.value, { - viaKeyboard +const renote = (viaKeyboard = false) => { + pleaseLogin(); + os.popupMenu([{ + text: i18n.ts.renote, + icon: 'fas fa-retweet', + action: () => { + os.api('notes/create', { + renoteId: props.note.id, }); - }; - - return { - buttonRef, - canRenote, - renote, - }; - }, -}); + }, + }, { + text: i18n.ts.quote, + icon: 'fas fa-quote-right', + action: () => { + os.post({ + renote: props.note, + }); + }, + }], buttonRef.value, { + viaKeyboard, + }); +}; </script> <style lang="scss" scoped> diff --git a/packages/client/src/components/signin-dialog.vue b/packages/client/src/components/signin-dialog.vue index 848b11fada..ec68668a7f 100644 --- a/packages/client/src/components/signin-dialog.vue +++ b/packages/client/src/components/signin-dialog.vue @@ -1,11 +1,12 @@ <template> -<XModalWindow ref="dialog" +<XModalWindow + ref="dialog" :width="370" :height="400" @close="onClose" @closed="emit('closed')" > - <template #header>{{ $ts.login }}</template> + <template #header>{{ i18n.ts.login }}</template> <MkSignin :auto-set="autoSet" :message="message" @login="onLogin"/> </XModalWindow> @@ -13,15 +14,16 @@ <script lang="ts" setup> import { } from 'vue'; -import XModalWindow from '@/components/ui/modal-window.vue'; import MkSignin from './signin.vue'; +import XModalWindow from '@/components/ui/modal-window.vue'; +import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ autoSet?: boolean; message?: string, }>(), { autoSet: false, - message: '' + message: '', }); const emit = defineEmits<{ diff --git a/packages/client/src/components/signup-dialog.vue b/packages/client/src/components/signup-dialog.vue index 6dad9257a4..c5f933f6b3 100644 --- a/packages/client/src/components/signup-dialog.vue +++ b/packages/client/src/components/signup-dialog.vue @@ -1,11 +1,12 @@ <template> -<XModalWindow ref="dialog" +<XModalWindow + ref="dialog" :width="366" :height="500" @close="dialog.close()" @closed="$emit('closed')" > - <template #header>{{ $ts.signup }}</template> + <template #header>{{ i18n.ts.signup }}</template> <div class="_monolithic_"> <div class="_section"> @@ -17,8 +18,9 @@ <script lang="ts" setup> import { } from 'vue'; -import XModalWindow from '@/components/ui/modal-window.vue'; import XSignup from './signup.vue'; +import XModalWindow from '@/components/ui/modal-window.vue'; +import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ autoSet?: boolean; diff --git a/packages/client/src/components/signup.vue b/packages/client/src/components/signup.vue index c35d65d5de..f8e39985bc 100644 --- a/packages/client/src/components/signup.vue +++ b/packages/client/src/components/signup.vue @@ -1,65 +1,65 @@ <template> <form class="qlvuhzng _formRoot" autocomplete="new-password" @submit.prevent="onSubmit"> <MkInput v-if="instance.disableRegistration" v-model="invitationCode" class="_formBlock" type="text" :spellcheck="false" required> - <template #label>{{ $ts.invitationCode }}</template> + <template #label>{{ i18n.ts.invitationCode }}</template> <template #prefix><i class="fas fa-key"></i></template> </MkInput> <MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-signup-username @update:modelValue="onChangeUsername"> - <template #label>{{ $ts.username }} <div v-tooltip:dialog="$ts.usernameInfo" class="_button _help"><i class="far fa-question-circle"></i></div></template> + <template #label>{{ i18n.ts.username }} <div v-tooltip:dialog="i18n.ts.usernameInfo" class="_button _help"><i class="far fa-question-circle"></i></div></template> <template #prefix>@</template> <template #suffix>@{{ host }}</template> <template #caption> - <span v-if="usernameState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span> - <span v-else-if="usernameState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span> - <span v-else-if="usernameState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span> - <span v-else-if="usernameState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span> - <span v-else-if="usernameState === 'invalid-format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span> - <span v-else-if="usernameState === 'min-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span> - <span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span> + <span v-if="usernameState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ i18n.ts.checking }}</span> + <span v-else-if="usernameState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ i18n.ts.available }}</span> + <span v-else-if="usernameState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.unavailable }}</span> + <span v-else-if="usernameState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.error }}</span> + <span v-else-if="usernameState === 'invalid-format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.usernameInvalidFormat }}</span> + <span v-else-if="usernameState === 'min-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.tooShort }}</span> + <span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.tooLong }}</span> </template> </MkInput> <MkInput v-if="instance.emailRequiredForSignup" v-model="email" class="_formBlock" :debounce="true" type="email" :spellcheck="false" required data-cy-signup-email @update:modelValue="onChangeEmail"> - <template #label>{{ $ts.emailAddress }} <div v-tooltip:dialog="$ts._signup.emailAddressInfo" class="_button _help"><i class="far fa-question-circle"></i></div></template> + <template #label>{{ i18n.ts.emailAddress }} <div v-tooltip:dialog="i18n.ts._signup.emailAddressInfo" class="_button _help"><i class="far fa-question-circle"></i></div></template> <template #prefix><i class="fas fa-envelope"></i></template> <template #caption> - <span v-if="emailState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span> - <span v-else-if="emailState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span> - <span v-else-if="emailState === 'unavailable:used'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts._emailUnavailable.used }}</span> - <span v-else-if="emailState === 'unavailable:format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts._emailUnavailable.format }}</span> - <span v-else-if="emailState === 'unavailable:disposable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts._emailUnavailable.disposable }}</span> - <span v-else-if="emailState === 'unavailable:mx'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts._emailUnavailable.mx }}</span> - <span v-else-if="emailState === 'unavailable:smtp'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts._emailUnavailable.smtp }}</span> - <span v-else-if="emailState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span> - <span v-else-if="emailState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span> + <span v-if="emailState === 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ i18n.ts.checking }}</span> + <span v-else-if="emailState === 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ i18n.ts.available }}</span> + <span v-else-if="emailState === 'unavailable:used'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts._emailUnavailable.used }}</span> + <span v-else-if="emailState === 'unavailable:format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts._emailUnavailable.format }}</span> + <span v-else-if="emailState === 'unavailable:disposable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts._emailUnavailable.disposable }}</span> + <span v-else-if="emailState === 'unavailable:mx'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts._emailUnavailable.mx }}</span> + <span v-else-if="emailState === 'unavailable:smtp'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts._emailUnavailable.smtp }}</span> + <span v-else-if="emailState === 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.unavailable }}</span> + <span v-else-if="emailState === 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.error }}</span> </template> </MkInput> <MkInput v-model="password" class="_formBlock" type="password" autocomplete="new-password" required data-cy-signup-password @update:modelValue="onChangePassword"> - <template #label>{{ $ts.password }}</template> + <template #label>{{ i18n.ts.password }}</template> <template #prefix><i class="fas fa-lock"></i></template> <template #caption> - <span v-if="passwordStrength == 'low'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.weakPassword }}</span> - <span v-if="passwordStrength == 'medium'" style="color: var(--warn)"><i class="fas fa-check fa-fw"></i> {{ $ts.normalPassword }}</span> - <span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span> + <span v-if="passwordStrength == 'low'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.weakPassword }}</span> + <span v-if="passwordStrength == 'medium'" style="color: var(--warn)"><i class="fas fa-check fa-fw"></i> {{ i18n.ts.normalPassword }}</span> + <span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ i18n.ts.strongPassword }}</span> </template> </MkInput> <MkInput v-model="retypedPassword" class="_formBlock" type="password" autocomplete="new-password" required data-cy-signup-password-retype @update:modelValue="onChangePasswordRetype"> - <template #label>{{ $ts.password }} ({{ $ts.retype }})</template> + <template #label>{{ i18n.ts.password }} ({{ i18n.ts.retype }})</template> <template #prefix><i class="fas fa-lock"></i></template> <template #caption> - <span v-if="passwordRetypeState == 'match'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.passwordMatched }}</span> - <span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span> + <span v-if="passwordRetypeState == 'match'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ i18n.ts.passwordMatched }}</span> + <span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ i18n.ts.passwordNotMatched }}</span> </template> </MkInput> <MkSwitch v-if="instance.tosUrl" v-model="ToSAgreement" class="_formBlock tou"> - <I18n :src="$ts.agreeTo"> + <I18n :src="i18n.ts.agreeTo"> <template #0> - <a :href="instance.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a> + <a :href="instance.tosUrl" class="_link" target="_blank">{{ i18n.ts.tos }}</a> </template> </I18n> </MkSwitch> <MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/> <MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/> - <MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton> + <MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ i18n.ts.start }}</MkButton> </form> </template> diff --git a/packages/client/src/components/sparkle.vue b/packages/client/src/components/sparkle.vue index b52dbe31c4..cdeaf9c417 100644 --- a/packages/client/src/components/sparkle.vue +++ b/packages/client/src/components/sparkle.vue @@ -63,63 +63,51 @@ </span> </template> -<script lang="ts"> -import { defineComponent, onMounted, onUnmounted, ref } from 'vue'; -import * as os from '@/os'; +<script lang="ts" setup> +import { onMounted, onUnmounted, ref } from 'vue'; -export default defineComponent({ - setup() { - const particles = ref([]); - const el = ref<HTMLElement>(); - const width = ref(0); - const height = ref(0); - const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202']; - let stop = false; - let ro: ResizeObserver | undefined; +const particles = ref([]); +const el = ref<HTMLElement>(); +const width = ref(0); +const height = ref(0); +const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202']; +let stop = false; +let ro: ResizeObserver | undefined; - onMounted(() => { - ro = new ResizeObserver((entries, observer) => { - width.value = el.value?.offsetWidth + 64; - height.value = el.value?.offsetHeight + 64; - }); - ro.observe(el.value); - const add = () => { - if (stop) return; - const x = (Math.random() * (width.value - 64)); - const y = (Math.random() * (height.value - 64)); - const sizeFactor = Math.random(); - const particle = { - id: Math.random().toString(), - x, - y, - size: 0.2 + ((sizeFactor / 10) * 3), - dur: 1000 + (sizeFactor * 1000), - color: colors[Math.floor(Math.random() * colors.length)], - }; - particles.value.push(particle); - window.setTimeout(() => { - particles.value = particles.value.filter(x => x.id !== particle.id); - }, particle.dur - 100); +onMounted(() => { + ro = new ResizeObserver((entries, observer) => { + width.value = el.value?.offsetWidth + 64; + height.value = el.value?.offsetHeight + 64; + }); + ro.observe(el.value); + const add = () => { + if (stop) return; + const x = (Math.random() * (width.value - 64)); + const y = (Math.random() * (height.value - 64)); + const sizeFactor = Math.random(); + const particle = { + id: Math.random().toString(), + x, + y, + size: 0.2 + ((sizeFactor / 10) * 3), + dur: 1000 + (sizeFactor * 1000), + color: colors[Math.floor(Math.random() * colors.length)], + }; + particles.value.push(particle); + window.setTimeout(() => { + particles.value = particles.value.filter(x => x.id !== particle.id); + }, particle.dur - 100); - window.setTimeout(() => { - add(); - }, 500 + (Math.random() * 500)); - }; + window.setTimeout(() => { add(); - }); - - onUnmounted(() => { - if (ro) ro.disconnect(); - stop = true; - }); + }, 500 + (Math.random() * 500)); + }; + add(); +}); - return { - el, - width, - height, - particles, - }; - }, +onUnmounted(() => { + if (ro) ro.disconnect(); + stop = true; }); </script> diff --git a/packages/client/src/components/sub-note-content.vue b/packages/client/src/components/sub-note-content.vue index d6a37d07be..25ab883f40 100644 --- a/packages/client/src/components/sub-note-content.vue +++ b/packages/client/src/components/sub-note-content.vue @@ -1,8 +1,8 @@ <template> <div class="wrmlmaau" :class="{ collapsed }"> <div class="body"> - <span v-if="note.isHidden" style="opacity: 0.5">({{ $ts.private }})</span> - <span v-if="note.deletedAt" style="opacity: 0.5">({{ $ts.deleted }})</span> + <span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> + <span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deleted }})</span> <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="fas fa-reply"></i></MkA> <Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :custom-emojis="note.emojis"/> <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> @@ -12,20 +12,21 @@ <XMediaList :media-list="note.files"/> </details> <details v-if="note.poll"> - <summary>{{ $ts.poll }}</summary> + <summary>{{ i18n.ts.poll }}</summary> <XPoll :note="note"/> </details> <button v-if="collapsed" class="fade _button" @click="collapsed = false"> - <span>{{ $ts.showMore }}</span> + <span>{{ i18n.ts.showMore }}</span> </button> </div> </template> <script lang="ts" setup> import { } from 'vue'; +import * as misskey from 'misskey-js'; import XPoll from './poll.vue'; import XMediaList from './media-list.vue'; -import * as misskey from 'misskey-js'; +import { i18n } from '@/i18n'; const props = defineProps<{ note: misskey.entities.Note; diff --git a/packages/client/src/components/tab.vue b/packages/client/src/components/tab.vue index c629727358..669e9e2e11 100644 --- a/packages/client/src/components/tab.vue +++ b/packages/client/src/components/tab.vue @@ -18,13 +18,13 @@ export default defineComponent({ disabled: this.modelValue === option.props.value, onClick: () => { this.$emit('update:modelValue', option.props.value); - } + }, }, option.children), [ - [resolveDirective('click-anime')] + [resolveDirective('click-anime')], ]))), [ - [resolveDirective('size'), { max: [500] }] + [resolveDirective('size'), { max: [500] }], ]); - } + }, }); </script> diff --git a/packages/client/src/components/tag-cloud.vue b/packages/client/src/components/tag-cloud.vue index bbebff497f..2dfd26edb0 100644 --- a/packages/client/src/components/tag-cloud.vue +++ b/packages/client/src/components/tag-cloud.vue @@ -25,23 +25,25 @@ let tagsEl = $ref<HTMLElement | null>(null); let width = $ref(300); watch($$(available), () => { - window.TagCanvas.Start(idForCanvas, idForTags, { - textColour: '#ffffff', - outlineColour: tinycolor(computedStyle.getPropertyValue('--accent')).toHexString(), - outlineRadius: 10, - initial: [-0.030, -0.010], - frontSelect: true, - imageRadius: 8, - //dragControl: true, - dragThreshold: 3, - wheelZoom: false, - reverse: true, - depth: 0.5, - maxSpeed: 0.2, - minSpeed: 0.003, - stretchX: 0.8, - stretchY: 0.8, - }); + try { + window.TagCanvas.Start(idForCanvas, idForTags, { + textColour: '#ffffff', + outlineColour: tinycolor(computedStyle.getPropertyValue('--accent')).toHexString(), + outlineRadius: 10, + initial: [-0.030, -0.010], + frontSelect: true, + imageRadius: 8, + //dragControl: true, + dragThreshold: 3, + wheelZoom: false, + reverse: true, + depth: 0.5, + maxSpeed: 0.2, + minSpeed: 0.003, + stretchX: 0.8, + stretchY: 0.8, + }); + } catch (err) {} }); onMounted(() => { @@ -58,7 +60,7 @@ onMounted(() => { }); onBeforeUnmount(() => { - window.TagCanvas.Delete(idForCanvas); + if (window.TagCanvas) window.TagCanvas.Delete(idForCanvas); }); defineExpose({ diff --git a/packages/client/src/components/ui/button.vue b/packages/client/src/components/ui/button.vue index d3a4b5ea92..350629bf08 100644 --- a/packages/client/src/components/ui/button.vue +++ b/packages/client/src/components/ui/button.vue @@ -141,7 +141,7 @@ export default defineComponent({ display: block; min-width: 100px; width: max-content; - padding: 8px 14px; + padding: 8px 16px; text-align: center; font-weight: normal; font-size: 1em; diff --git a/packages/client/src/components/ui/menu.vue b/packages/client/src/components/ui/menu.vue index 6d1a2cc770..60b68954d6 100644 --- a/packages/client/src/components/ui/menu.vue +++ b/packages/client/src/components/ui/menu.vue @@ -46,7 +46,7 @@ </button> </template> <span v-if="items2.length === 0" class="none item"> - <span>{{ $ts.none }}</span> + <span>{{ i18n.ts.none }}</span> </span> </div> <div v-if="childMenu" class="child"> @@ -61,6 +61,8 @@ import { focusPrev, focusNext } from '@/scripts/focus'; import FormSwitch from '@/components/form/switch.vue'; import { MenuItem, InnerMenuItem, MenuPending, MenuAction } from '@/types/menu'; import * as os from '@/os'; +import { i18n } from '@/i18n'; + const XChild = defineAsyncComponent(() => import('./menu.child.vue')); const props = defineProps<{ @@ -335,6 +337,9 @@ onBeforeUnmount(() => { &.asDrawer { padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0; width: 100%; + border-radius: 24px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; > .item { font-size: 1em; diff --git a/packages/client/src/components/ui/pagination.vue b/packages/client/src/components/ui/pagination.vue index a03c2b3a1d..7650c5b33a 100644 --- a/packages/client/src/components/ui/pagination.vue +++ b/packages/client/src/components/ui/pagination.vue @@ -8,7 +8,7 @@ <slot name="empty"> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.nothing }}</div> + <div>{{ i18n.ts.nothing }}</div> </div> </slot> </div> @@ -16,14 +16,14 @@ <div v-else ref="rootEl"> <div v-show="pagination.reversed && more" key="_more_" class="cxiknjgy _gap"> <MkButton v-if="!moreFetching" class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMoreAhead"> - {{ $ts.loadMore }} + {{ i18n.ts.loadMore }} </MkButton> <MkLoading v-else class="loading"/> </div> <slot :items="items"></slot> <div v-show="!pagination.reversed && more" key="_more_" class="cxiknjgy _gap"> <MkButton v-if="!moreFetching" v-appear="($store.state.enableInfiniteScroll && !disableAutoLoad) ? fetchMore : null" class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMore"> - {{ $ts.loadMore }} + {{ i18n.ts.loadMore }} </MkButton> <MkLoading v-else class="loading"/> </div> @@ -37,6 +37,7 @@ import * as misskey from 'misskey-js'; import * as os from '@/os'; import { onScrollTop, isTopVisible, getScrollPosition, getScrollContainer } from '@/scripts/scroll'; import MkButton from '@/components/ui/button.vue'; +import { i18n } from '@/i18n'; const SECOND_FETCH_LIMIT = 30; @@ -196,21 +197,23 @@ const prepend = (item: Item): void => { if (props.pagination.reversed) { if (rootEl.value) { const container = getScrollContainer(rootEl.value); - if (container == null) return; // TODO? - - const pos = getScrollPosition(rootEl.value); - const viewHeight = container.clientHeight; - const height = container.scrollHeight; - const isBottom = (pos + viewHeight > height - 32); - if (isBottom) { - // オーãƒãƒ¼ãƒ•ãƒãƒ¼ã—ãŸã‚‰å¤ã„ã‚¢ã‚¤ãƒ†ãƒ ã¯æ¨ã¦ã‚‹ - if (items.value.length >= props.displayLimit) { - // ã“ã®ã‚„り方ã ã¨Vue 3.2以é™ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ãŒå‹•ã‹ãªããªã‚‹ - //items.value = items.value.slice(-props.displayLimit); - while (items.value.length >= props.displayLimit) { - items.value.shift(); + if (container == null) { + // TODO? + } else { + const pos = getScrollPosition(rootEl.value); + const viewHeight = container.clientHeight; + const height = container.scrollHeight; + const isBottom = (pos + viewHeight > height - 32); + if (isBottom) { + // オーãƒãƒ¼ãƒ•ãƒãƒ¼ã—ãŸã‚‰å¤ã„ã‚¢ã‚¤ãƒ†ãƒ ã¯æ¨ã¦ã‚‹ + if (items.value.length >= props.displayLimit) { + // ã“ã®ã‚„り方ã ã¨Vue 3.2以é™ã‚¢ãƒ‹ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ãŒå‹•ã‹ãªããªã‚‹ + //items.value = items.value.slice(-props.displayLimit); + while (items.value.length >= props.displayLimit) { + items.value.shift(); + } + more.value = true; } - more.value = true; } } } diff --git a/packages/client/src/components/ui/window.vue b/packages/client/src/components/ui/window.vue index 460cf7d597..758d4d47b6 100644 --- a/packages/client/src/components/ui/window.vue +++ b/packages/client/src/components/ui/window.vue @@ -170,6 +170,7 @@ function onHeaderMousedown(evt: MouseEvent) { beforeClickedAt = Date.now(); const main = rootEl; + if (main == null) return; if (!contains(main, document.activeElement)) main.focus(); diff --git a/packages/client/src/components/updated.vue b/packages/client/src/components/updated.vue index 375ac0dbbb..1c1e5f4aed 100644 --- a/packages/client/src/components/updated.vue +++ b/packages/client/src/components/updated.vue @@ -1,10 +1,10 @@ <template> <MkModal ref="modal" :z-priority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')"> <div class="ewlycnyt"> - <div class="title"><MkSparkle>{{ $ts.misskeyUpdated }}</MkSparkle></div> + <div class="title"><MkSparkle>{{ i18n.ts.misskeyUpdated }}</MkSparkle></div> <div class="version">✨{{ version }}🚀</div> - <MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton> - <MkButton class="gotIt" primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton> + <MkButton full @click="whatIsNew">{{ i18n.ts.whatIsNew }}</MkButton> + <MkButton class="gotIt" primary full @click="$refs.modal.close()">{{ i18n.ts.gotIt }}</MkButton> </div> </MkModal> </template> @@ -15,8 +15,9 @@ import MkModal from '@/components/ui/modal.vue'; import MkButton from '@/components/ui/button.vue'; import MkSparkle from '@/components/sparkle.vue'; import { version } from '@/config'; +import { i18n } from '@/i18n'; -const modal = ref(); +const modal = ref<InstanceType<typeof MkModal>>(); const whatIsNew = () => { modal.value.close(); diff --git a/packages/client/src/components/url-preview.vue b/packages/client/src/components/url-preview.vue index e15d28a382..df4b0e53b8 100644 --- a/packages/client/src/components/url-preview.vue +++ b/packages/client/src/components/url-preview.vue @@ -1,6 +1,6 @@ <template> <div v-if="playerEnabled" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`"> - <button class="disablePlayer" :title="$ts.disablePlayer" @click="playerEnabled = false"><i class="fas fa-times"></i></button> + <button class="disablePlayer" :title="i18n.ts.disablePlayer" @click="playerEnabled = false"><i class="fas fa-times"></i></button> <iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen/> </div> <div v-else-if="tweetId && tweetExpanded" ref="twitter" class="twitter"> @@ -10,7 +10,7 @@ <transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> <component :is="self ? 'MkA' : 'a'" v-if="!fetching" class="link" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url"> <div v-if="thumbnail" class="thumbnail" :style="`background-image: url('${thumbnail}')`"> - <button v-if="!playerEnabled && player.url" class="_button" :title="$ts.enablePlayer" @click.prevent="playerEnabled = true"><i class="fas fa-play-circle"></i></button> + <button v-if="!playerEnabled && player.url" class="_button" :title="i18n.ts.enablePlayer" @click.prevent="playerEnabled = true"><i class="fas fa-play-circle"></i></button> </div> <article> <header> @@ -26,7 +26,7 @@ </transition> <div v-if="tweetId" class="expandTweet"> <a @click="tweetExpanded = true"> - <i class="fab fa-twitter"></i> {{ $ts.expandTweet }} + <i class="fab fa-twitter"></i> {{ i18n.ts.expandTweet }} </a> </div> </div> @@ -35,6 +35,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted } from 'vue'; import { url as local, lang } from '@/config'; +import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ url: string; diff --git a/packages/client/src/components/user-info.vue b/packages/client/src/components/user-info.vue index 6a25d412fc..1cd275a6df 100644 --- a/packages/client/src/components/user-info.vue +++ b/packages/client/src/components/user-info.vue @@ -10,17 +10,17 @@ <div v-if="user.description" class="mfm"> <Mfm :text="user.description" :author="user" :i="$i" :custom-emojis="user.emojis"/> </div> - <span v-else style="opacity: 0.7;">{{ $ts.noAccountDescription }}</span> + <span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span> </div> <div class="status"> <div> - <p>{{ $ts.notes }}</p><span>{{ user.notesCount }}</span> + <p>{{ i18n.ts.notes }}</p><span>{{ user.notesCount }}</span> </div> <div> - <p>{{ $ts.following }}</p><span>{{ user.followingCount }}</span> + <p>{{ i18n.ts.following }}</p><span>{{ user.followingCount }}</span> </div> <div> - <p>{{ $ts.followers }}</p><span>{{ user.followersCount }}</span> + <p>{{ i18n.ts.followers }}</p><span>{{ user.followersCount }}</span> </div> </div> <MkFollowButton v-if="$i && user.id != $i.id" class="koudoku-button" :user="user" mini/> @@ -31,6 +31,7 @@ import * as misskey from 'misskey-js'; import MkFollowButton from './follow-button.vue'; import { userPage } from '@/filters/user'; +import { i18n } from '@/i18n'; defineProps<{ user: misskey.entities.UserDetailed; diff --git a/packages/client/src/components/user-list.vue b/packages/client/src/components/user-list.vue index 3e273721c7..fe30d371fe 100644 --- a/packages/client/src/components/user-list.vue +++ b/packages/client/src/components/user-list.vue @@ -3,7 +3,7 @@ <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.noUsers }}</div> + <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -18,9 +18,9 @@ <script lang="ts" setup> import { ref } from 'vue'; import MkUserInfo from '@/components/user-info.vue'; -import MkPagination from '@/components/ui/pagination.vue'; -import { Paging } from '@/components/ui/pagination.vue'; +import MkPagination, { Paging } from '@/components/ui/pagination.vue'; import { userPage } from '@/filters/user'; +import { i18n } from '@/i18n'; const props = defineProps<{ pagination: Paging; diff --git a/packages/client/src/components/user-select-dialog.vue b/packages/client/src/components/user-select-dialog.vue index 972d353486..4d8e427a72 100644 --- a/packages/client/src/components/user-select-dialog.vue +++ b/packages/client/src/components/user-select-dialog.vue @@ -1,5 +1,6 @@ <template> -<XModalWindow ref="dialogEl" +<XModalWindow + ref="dialogEl" :with-ok-button="true" :ok-button-disabled="selected == null" @click="cancel()" @@ -7,16 +8,16 @@ @ok="ok()" @closed="$emit('closed')" > - <template #header>{{ $ts.selectUser }}</template> + <template #header>{{ i18n.ts.selectUser }}</template> <div class="tbhwbxda"> <div class="form"> <FormSplit :min-width="170"> <MkInput v-model="username" :autofocus="true" @update:modelValue="search"> - <template #label>{{ $ts.username }}</template> + <template #label>{{ i18n.ts.username }}</template> <template #prefix>@</template> </MkInput> <MkInput v-model="host" @update:modelValue="search"> - <template #label>{{ $ts.host }}</template> + <template #label>{{ i18n.ts.host }}</template> <template #prefix>@</template> </MkInput> </FormSplit> @@ -32,7 +33,7 @@ </div> </div> <div v-else class="empty"> - <span>{{ $ts.noUsers }}</span> + <span>{{ i18n.ts.noUsers }}</span> </div> </div> <div v-if="username == '' && host == ''" class="recent"> @@ -58,6 +59,7 @@ import FormSplit from '@/components/form/split.vue'; import XModalWindow from '@/components/ui/modal-window.vue'; import * as os from '@/os'; import { defaultStore } from '@/store'; +import { i18n } from '@/i18n'; const emit = defineEmits<{ (ev: 'ok', selected: misskey.entities.UserDetailed): void; @@ -81,7 +83,7 @@ const search = () => { username: username, host: host, limit: 10, - detail: false + detail: false, }).then(_users => { users = _users; }); diff --git a/packages/client/src/components/visibility-picker.vue b/packages/client/src/components/visibility-picker.vue index 7fe55858cc..f4830cd2c6 100644 --- a/packages/client/src/components/visibility-picker.vue +++ b/packages/client/src/components/visibility-picker.vue @@ -4,37 +4,37 @@ <button key="public" class="_button" :class="{ active: v === 'public' }" data-index="1" @click="choose('public')"> <div><i class="fas fa-globe"></i></div> <div> - <span>{{ $ts._visibility.public }}</span> - <span>{{ $ts._visibility.publicDescription }}</span> + <span>{{ i18n.ts._visibility.public }}</span> + <span>{{ i18n.ts._visibility.publicDescription }}</span> </div> </button> <button key="home" class="_button" :class="{ active: v === 'home' }" data-index="2" @click="choose('home')"> <div><i class="fas fa-home"></i></div> <div> - <span>{{ $ts._visibility.home }}</span> - <span>{{ $ts._visibility.homeDescription }}</span> + <span>{{ i18n.ts._visibility.home }}</span> + <span>{{ i18n.ts._visibility.homeDescription }}</span> </div> </button> <button key="followers" class="_button" :class="{ active: v === 'followers' }" data-index="3" @click="choose('followers')"> <div><i class="fas fa-unlock"></i></div> <div> - <span>{{ $ts._visibility.followers }}</span> - <span>{{ $ts._visibility.followersDescription }}</span> + <span>{{ i18n.ts._visibility.followers }}</span> + <span>{{ i18n.ts._visibility.followersDescription }}</span> </div> </button> <button key="specified" :disabled="localOnly" class="_button" :class="{ active: v === 'specified' }" data-index="4" @click="choose('specified')"> <div><i class="fas fa-envelope"></i></div> <div> - <span>{{ $ts._visibility.specified }}</span> - <span>{{ $ts._visibility.specifiedDescription }}</span> + <span>{{ i18n.ts._visibility.specified }}</span> + <span>{{ i18n.ts._visibility.specifiedDescription }}</span> </div> </button> <div class="divider"></div> <button key="localOnly" class="_button localOnly" :class="{ active: localOnly }" data-index="5" @click="localOnly = !localOnly"> <div><i class="fas fa-biohazard"></i></div> <div> - <span>{{ $ts._visibility.localOnly }}</span> - <span>{{ $ts._visibility.localOnlyDescription }}</span> + <span>{{ i18n.ts._visibility.localOnly }}</span> + <span>{{ i18n.ts._visibility.localOnlyDescription }}</span> </div> <div><i :class="localOnly ? 'fas fa-toggle-on' : 'fas fa-toggle-off'"></i></div> </button> @@ -46,6 +46,7 @@ import { nextTick, watch } from 'vue'; import * as misskey from 'misskey-js'; import MkModal from '@/components/ui/modal.vue'; +import { i18n } from '@/i18n'; const modal = $ref<InstanceType<typeof MkModal>>(); diff --git a/packages/client/src/components/widgets.vue b/packages/client/src/components/widgets.vue index 0a9769e197..54d4c57af3 100644 --- a/packages/client/src/components/widgets.vue +++ b/packages/client/src/components/widgets.vue @@ -3,11 +3,11 @@ <template v-if="edit"> <header> <MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)" class="mk-widget-select"> - <template #label>{{ $ts.selectWidget }}</template> + <template #label>{{ i18n.ts.selectWidget }}</template> <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.t(`_widgets.${widget}`) }}</option> </MkSelect> - <MkButton inline primary class="mk-widget-add" @click="addWidget"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton> - <MkButton inline @click="$emit('exit')">{{ $ts.close }}</MkButton> + <MkButton inline primary class="mk-widget-add" @click="addWidget"><i class="fas fa-plus"></i> {{ i18n.ts.add }}</MkButton> + <MkButton inline @click="$emit('exit')">{{ i18n.ts.close }}</MkButton> </header> <XDraggable v-model="widgets_" diff --git a/packages/client/src/nirax.ts b/packages/client/src/nirax.ts index 4ba1fe70f6..0ee39bf473 100644 --- a/packages/client/src/nirax.ts +++ b/packages/client/src/nirax.ts @@ -13,6 +13,7 @@ type RouteDef = { name?: string; hash?: string; globalCacheKey?: string; + children?: RouteDef[]; }; type ParsedPath = (string | { @@ -22,6 +23,8 @@ type ParsedPath = (string | { optional?: boolean; })[]; +export type Resolved = { route: RouteDef; props: Map<string, string>; child?: Resolved; }; + function parsePath(path: string): ParsedPath { const res = [] as ParsedPath; @@ -51,8 +54,11 @@ export class Router extends EventEmitter<{ change: (ctx: { beforePath: string; path: string; - route: RouteDef | null; - props: Map<string, string> | null; + resolved: Resolved; + key: string; + }) => void; + replace: (ctx: { + path: string; key: string; }) => void; push: (ctx: { @@ -65,12 +71,12 @@ export class Router extends EventEmitter<{ same: () => void; }> { private routes: RouteDef[]; + public current: Resolved; + public currentRef: ShallowRef<Resolved> = shallowRef(); + public currentRoute: ShallowRef<RouteDef> = shallowRef(); private currentPath: string; - private currentComponent: Component | null = null; - private currentProps: Map<string, string> | null = null; private currentKey = Date.now().toString(); - public currentRoute: ShallowRef<RouteDef | null> = shallowRef(null); public navHook: ((path: string, flag?: any) => boolean) | null = null; constructor(routes: Router['routes'], currentPath: Router['currentPath']) { @@ -78,10 +84,10 @@ export class Router extends EventEmitter<{ this.routes = routes; this.currentPath = currentPath; - this.navigate(currentPath, null, true); + this.navigate(currentPath, null, false); } - public resolve(path: string): { route: RouteDef; props: Map<string, string>; } | null { + public resolve(path: string): Resolved | null { let queryString: string | null = null; let hash: string | null = null; if (path[0] === '/') path = path.substring(1); @@ -96,77 +102,108 @@ export class Router extends EventEmitter<{ if (_DEV_) console.log('Routing: ', path, queryString); - const _parts = path.split('/').filter(part => part.length !== 0); - - forEachRouteLoop: - for (const route of this.routes) { - let parts = [ ..._parts ]; - const props = new Map<string, string>(); + function check(routes: RouteDef[], _parts: string[]): Resolved | null { + forEachRouteLoop: + for (const route of routes) { + let parts = [ ..._parts ]; + const props = new Map<string, string>(); - pathMatchLoop: - for (const p of parsePath(route.path)) { - if (typeof p === 'string') { - if (p === parts[0]) { - parts.shift(); - } else { - continue forEachRouteLoop; - } - } else { - if (parts[0] == null && !p.optional) { - continue forEachRouteLoop; - } - if (p.wildcard) { - if (parts.length !== 0) { - props.set(p.name, safeURIDecode(parts.join('/'))); - parts = []; + pathMatchLoop: + for (const p of parsePath(route.path)) { + if (typeof p === 'string') { + if (p === parts[0]) { + parts.shift(); + } else { + continue forEachRouteLoop; } - break pathMatchLoop; } else { - if (p.startsWith) { - if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop; - - props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length))); - parts.shift(); + if (parts[0] == null && !p.optional) { + continue forEachRouteLoop; + } + if (p.wildcard) { + if (parts.length !== 0) { + props.set(p.name, safeURIDecode(parts.join('/'))); + parts = []; + } + break pathMatchLoop; } else { - if (parts[0]) { - props.set(p.name, safeURIDecode(parts[0])); + if (p.startsWith) { + if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop; + + props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length))); + parts.shift(); + } else { + if (parts[0]) { + props.set(p.name, safeURIDecode(parts[0])); + } + parts.shift(); } - parts.shift(); } } } - } - - if (parts.length !== 0) continue forEachRouteLoop; - if (route.hash != null && hash != null) { - props.set(route.hash, safeURIDecode(hash)); - } - - if (route.query != null && queryString != null) { - const queryObject = [...new URLSearchParams(queryString).entries()] - .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {}); + if (parts.length === 0) { + if (route.children) { + const child = check(route.children, []); + if (child) { + return { + route, + props, + child, + }; + } else { + continue forEachRouteLoop; + } + } - for (const q in route.query) { - const as = route.query[q]; - if (queryObject[q]) { - props.set(as, safeURIDecode(queryObject[q])); + if (route.hash != null && hash != null) { + props.set(route.hash, safeURIDecode(hash)); + } + + if (route.query != null && queryString != null) { + const queryObject = [...new URLSearchParams(queryString).entries()] + .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {}); + + for (const q in route.query) { + const as = route.query[q]; + if (queryObject[q]) { + props.set(as, safeURIDecode(queryObject[q])); + } + } + } + + return { + route, + props, + }; + } else { + if (route.children) { + const child = check(route.children, parts); + if (child) { + return { + route, + props, + child, + }; + } else { + continue forEachRouteLoop; + } + } else { + continue forEachRouteLoop; } } } - return { - route, - props, - }; + return null; } - return null; + const _parts = path.split('/').filter(part => part.length !== 0); + + return check(this.routes, _parts); } - private navigate(path: string, key: string | null | undefined, initial = false) { + private navigate(path: string, key: string | null | undefined, emitChange = true) { const beforePath = this.currentPath; - const beforeRoute = this.currentRoute.value; this.currentPath = path; const res = this.resolve(this.currentPath); @@ -181,28 +218,21 @@ export class Router extends EventEmitter<{ const isSamePath = beforePath === path; if (isSamePath && key == null) key = this.currentKey; - this.currentComponent = res.route.component; - this.currentProps = res.props; + this.current = res; + this.currentRef.value = res; this.currentRoute.value = res.route; - this.currentKey = this.currentRoute.value.globalCacheKey ?? key ?? Date.now().toString(); + this.currentKey = res.route.globalCacheKey ?? key ?? path; - if (!initial) { + if (emitChange) { this.emit('change', { beforePath, path, - route: this.currentRoute.value, - props: this.currentProps, + resolved: res, key: this.currentKey, }); } - } - public getCurrentComponent() { - return this.currentComponent; - } - - public getCurrentProps() { - return this.currentProps; + return res; } public getCurrentPath() { @@ -223,17 +253,23 @@ export class Router extends EventEmitter<{ const cancel = this.navHook(path, flag); if (cancel) return; } - this.navigate(path, null); + const res = this.navigate(path, null); this.emit('push', { beforePath, path, - route: this.currentRoute.value, - props: this.currentProps, + route: res.route, + props: res.props, key: this.currentKey, }); } - public change(path: string, key?: string | null) { + public replace(path: string, key?: string | null, emitEvent = true) { this.navigate(path, key); + if (emitEvent) { + this.emit('replace', { + path, + key: this.currentKey, + }); + } } } diff --git a/packages/client/src/pages/_empty_.vue b/packages/client/src/pages/_empty_.vue new file mode 100644 index 0000000000..000b6decc9 --- /dev/null +++ b/packages/client/src/pages/_empty_.vue @@ -0,0 +1,7 @@ +<template> +<div></div> +</template> + +<script lang="ts" setup> +import { } from 'vue'; +</script> diff --git a/packages/client/src/pages/about.federation.vue b/packages/client/src/pages/about.federation.vue index 00ca44eec8..8d93908725 100644 --- a/packages/client/src/pages/about.federation.vue +++ b/packages/client/src/pages/about.federation.vue @@ -3,35 +3,35 @@ <div class="query"> <MkInput v-model="host" :debounce="true" class=""> <template #prefix><i class="fas fa-search"></i></template> - <template #label>{{ $ts.host }}</template> + <template #label>{{ i18n.ts.host }}</template> </MkInput> <FormSplit style="margin-top: var(--margin);"> <MkSelect v-model="state"> - <template #label>{{ $ts.state }}</template> - <option value="all">{{ $ts.all }}</option> - <option value="federating">{{ $ts.federating }}</option> - <option value="subscribing">{{ $ts.subscribing }}</option> - <option value="publishing">{{ $ts.publishing }}</option> - <option value="suspended">{{ $ts.suspended }}</option> - <option value="blocked">{{ $ts.blocked }}</option> - <option value="notResponding">{{ $ts.notResponding }}</option> + <template #label>{{ i18n.ts.state }}</template> + <option value="all">{{ i18n.ts.all }}</option> + <option value="federating">{{ i18n.ts.federating }}</option> + <option value="subscribing">{{ i18n.ts.subscribing }}</option> + <option value="publishing">{{ i18n.ts.publishing }}</option> + <option value="suspended">{{ i18n.ts.suspended }}</option> + <option value="blocked">{{ i18n.ts.blocked }}</option> + <option value="notResponding">{{ i18n.ts.notResponding }}</option> </MkSelect> <MkSelect v-model="sort"> - <template #label>{{ $ts.sort }}</template> - <option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option> - <option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option> - <option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option> - <option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option> - <option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option> - <option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option> - <option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option> - <option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option> - <option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option> - <option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option> - <option value="+caughtAt">{{ $ts.registeredAt }} ({{ $ts.descendingOrder }})</option> - <option value="-caughtAt">{{ $ts.registeredAt }} ({{ $ts.ascendingOrder }})</option> - <option value="+lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.descendingOrder }})</option> - <option value="-lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.ascendingOrder }})</option> + <template #label>{{ i18n.ts.sort }}</template> + <option value="+pubSub">{{ i18n.ts.pubSub }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-pubSub">{{ i18n.ts.pubSub }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+notes">{{ i18n.ts.notes }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-notes">{{ i18n.ts.notes }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+users">{{ i18n.ts.users }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-users">{{ i18n.ts.users }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+following">{{ i18n.ts.following }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-following">{{ i18n.ts.following }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+followers">{{ i18n.ts.followers }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-followers">{{ i18n.ts.followers }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-caughtAt">{{ i18n.ts.registeredAt }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-lastCommunicatedAt">{{ i18n.ts.lastCommunication }} ({{ i18n.ts.ascendingOrder }})</option> </MkSelect> </FormSplit> </div> diff --git a/packages/client/src/pages/about.vue b/packages/client/src/pages/about.vue index e482c4ca6d..ff50ba8452 100644 --- a/packages/client/src/pages/about.vue +++ b/packages/client/src/pages/about.vue @@ -13,7 +13,7 @@ </div> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.description }}</template> + <template #key>{{ i18n.ts.description }}</template> <template #value>{{ $instance.description }}</template> </MkKeyValue> @@ -22,33 +22,33 @@ <template #key>Misskey</template> <template #value>{{ version }}</template> </MkKeyValue> - <FormLink to="/about-misskey">{{ $ts.aboutMisskey }}</FormLink> + <FormLink to="/about-misskey">{{ i18n.ts.aboutMisskey }}</FormLink> </FormSection> <FormSection> <FormSplit> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.administrator }}</template> + <template #key>{{ i18n.ts.administrator }}</template> <template #value>{{ $instance.maintainerName }}</template> </MkKeyValue> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.contact }}</template> + <template #key>{{ i18n.ts.contact }}</template> <template #value>{{ $instance.maintainerEmail }}</template> </MkKeyValue> </FormSplit> - <FormLink v-if="$instance.tosUrl" :to="$instance.tosUrl" class="_formBlock" external>{{ $ts.tos }}</FormLink> + <FormLink v-if="$instance.tosUrl" :to="$instance.tosUrl" class="_formBlock" external>{{ i18n.ts.tos }}</FormLink> </FormSection> <FormSuspense :p="initStats"> <FormSection> - <template #label>{{ $ts.statistics }}</template> + <template #label>{{ i18n.ts.statistics }}</template> <FormSplit> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.users }}</template> + <template #key>{{ i18n.ts.users }}</template> <template #value>{{ number(stats.originalUsersCount) }}</template> </MkKeyValue> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.notes }}</template> + <template #key>{{ i18n.ts.notes }}</template> <template #value>{{ number(stats.originalNotesCount) }}</template> </MkKeyValue> </FormSplit> diff --git a/packages/client/src/pages/admin/abuses.vue b/packages/client/src/pages/admin/abuses.vue index 11cf284b22..9c718ab9e4 100644 --- a/packages/client/src/pages/admin/abuses.vue +++ b/packages/client/src/pages/admin/abuses.vue @@ -7,31 +7,31 @@ <div class="_content"> <div class="inputs" style="display: flex;"> <MkSelect v-model="state" style="margin: 0; flex: 1;"> - <template #label>{{ $ts.state }}</template> - <option value="all">{{ $ts.all }}</option> - <option value="unresolved">{{ $ts.unresolved }}</option> - <option value="resolved">{{ $ts.resolved }}</option> + <template #label>{{ i18n.ts.state }}</template> + <option value="all">{{ i18n.ts.all }}</option> + <option value="unresolved">{{ i18n.ts.unresolved }}</option> + <option value="resolved">{{ i18n.ts.resolved }}</option> </MkSelect> <MkSelect v-model="targetUserOrigin" style="margin: 0; flex: 1;"> - <template #label>{{ $ts.reporteeOrigin }}</template> - <option value="combined">{{ $ts.all }}</option> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <template #label>{{ i18n.ts.reporteeOrigin }}</template> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkSelect> <MkSelect v-model="reporterOrigin" style="margin: 0; flex: 1;"> - <template #label>{{ $ts.reporterOrigin }}</template> - <option value="combined">{{ $ts.all }}</option> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <template #label>{{ i18n.ts.reporterOrigin }}</template> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkSelect> </div> <!-- TODO <div class="inputs" style="display: flex; padding-top: 1.2em;"> <MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" :spellcheck="false"> - <span>{{ $ts.username }}</span> + <span>{{ i18n.ts.username }}</span> </MkInput> <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params().origin === 'local'"> - <span>{{ $ts.host }}</span> + <span>{{ i18n.ts.host }}</span> </MkInput> </div> --> diff --git a/packages/client/src/pages/admin/bot-protection.vue b/packages/client/src/pages/admin/bot-protection.vue index d316f973bc..cf2cdea92b 100644 --- a/packages/client/src/pages/admin/bot-protection.vue +++ b/packages/client/src/pages/admin/bot-protection.vue @@ -3,7 +3,7 @@ <FormSuspense :p="init"> <div class="_formRoot"> <FormRadios v-model="provider" class="_formBlock"> - <option :value="null">{{ $ts.none }} ({{ $ts.notRecommended }})</option> + <option :value="null">{{ i18n.ts.none }} ({{ i18n.ts.notRecommended }})</option> <option value="hcaptcha">hCaptcha</option> <option value="recaptcha">reCAPTCHA</option> </FormRadios> @@ -11,33 +11,33 @@ <template v-if="provider === 'hcaptcha'"> <FormInput v-model="hcaptchaSiteKey" class="_formBlock"> <template #prefix><i class="fas fa-key"></i></template> - <template #label>{{ $ts.hcaptchaSiteKey }}</template> + <template #label>{{ i18n.ts.hcaptchaSiteKey }}</template> </FormInput> <FormInput v-model="hcaptchaSecretKey" class="_formBlock"> <template #prefix><i class="fas fa-key"></i></template> - <template #label>{{ $ts.hcaptchaSecretKey }}</template> + <template #label>{{ i18n.ts.hcaptchaSecretKey }}</template> </FormInput> <FormSlot class="_formBlock"> - <template #label>{{ $ts.preview }}</template> + <template #label>{{ i18n.ts.preview }}</template> <MkCaptcha provider="hcaptcha" :sitekey="hcaptchaSiteKey || '10000000-ffff-ffff-ffff-000000000001'"/> </FormSlot> </template> <template v-else-if="provider === 'recaptcha'"> <FormInput v-model="recaptchaSiteKey" class="_formBlock"> <template #prefix><i class="fas fa-key"></i></template> - <template #label>{{ $ts.recaptchaSiteKey }}</template> + <template #label>{{ i18n.ts.recaptchaSiteKey }}</template> </FormInput> <FormInput v-model="recaptchaSecretKey" class="_formBlock"> <template #prefix><i class="fas fa-key"></i></template> - <template #label>{{ $ts.recaptchaSecretKey }}</template> + <template #label>{{ i18n.ts.recaptchaSecretKey }}</template> </FormInput> <FormSlot v-if="recaptchaSiteKey" class="_formBlock"> - <template #label>{{ $ts.preview }}</template> + <template #label>{{ i18n.ts.preview }}</template> <MkCaptcha provider="recaptcha" :sitekey="recaptchaSiteKey"/> </FormSlot> </template> - <FormButton primary @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> + <FormButton primary @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton> </div> </FormSuspense> </div> @@ -52,6 +52,7 @@ import FormSuspense from '@/components/form/suspense.vue'; import FormSlot from '@/components/form/slot.vue'; import * as os from '@/os'; import { fetchInstance } from '@/instance'; +import { i18n } from '@/i18n'; const MkCaptcha = defineAsyncComponent(() => import('@/components/captcha.vue')); diff --git a/packages/client/src/pages/admin/emoji-edit-dialog.vue b/packages/client/src/pages/admin/emoji-edit-dialog.vue index d482fa49e6..af91044e7d 100644 --- a/packages/client/src/pages/admin/emoji-edit-dialog.vue +++ b/packages/client/src/pages/admin/emoji-edit-dialog.vue @@ -1,5 +1,6 @@ <template> -<XModalWindow ref="dialog" +<XModalWindow + ref="dialog" :width="370" :with-ok-button="true" @close="$refs.dialog.close()" @@ -12,16 +13,16 @@ <div class="yigymqpb _section"> <img :src="emoji.url" class="img"/> <MkInput v-model="name" class="_formBlock"> - <template #label>{{ $ts.name }}</template> + <template #label>{{ i18n.ts.name }}</template> </MkInput> <MkInput v-model="category" class="_formBlock" :datalist="categories"> - <template #label>{{ $ts.category }}</template> + <template #label>{{ i18n.ts.category }}</template> </MkInput> <MkInput v-model="aliases" class="_formBlock"> - <template #label>{{ $ts.tags }}</template> - <template #caption>{{ $ts.setMultipleBySeparatingWithSpace }}</template> + <template #label>{{ i18n.ts.tags }}</template> + <template #caption>{{ i18n.ts.setMultipleBySeparatingWithSpace }}</template> </MkInput> - <MkButton danger @click="del()"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton> + <MkButton danger @click="del()"><i class="fas fa-trash-alt"></i> {{ i18n.ts.delete }}</MkButton> </div> </div> </XModalWindow> @@ -70,7 +71,7 @@ async function update() { name, category, aliases: aliases.split(' '), - } + }, }); dialog.close(); @@ -84,10 +85,10 @@ async function del() { if (canceled) return; os.api('admin/emoji/delete', { - id: props.emoji.id + id: props.emoji.id, }).then(() => { emit('done', { - deleted: true + deleted: true, }); dialog.close(); }); diff --git a/packages/client/src/pages/admin/emojis.vue b/packages/client/src/pages/admin/emojis.vue index 5ed2b14789..51ecd1b794 100644 --- a/packages/client/src/pages/admin/emojis.vue +++ b/packages/client/src/pages/admin/emojis.vue @@ -7,7 +7,7 @@ <div v-if="tab === 'local'" class="local"> <MkInput v-model="query" :debounce="true" type="search"> <template #prefix><i class="fas fa-search"></i></template> - <template #label>{{ $ts.search }}</template> + <template #label>{{ i18n.ts.search }}</template> </MkInput> <MkSwitch v-model="selectMode" style="margin: 8px 0;"> <template #label>Select mode</template> @@ -21,7 +21,7 @@ <MkButton inline danger @click="delBulk">Delete</MkButton> </div> <MkPagination ref="emojisPaginationComponent" :pagination="pagination"> - <template #empty><span>{{ $ts.noCustomEmojis }}</span></template> + <template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template> <template #default="{items}"> <div class="ldhfsamy"> <button v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" :class="{ selected: selectedEmojis.includes(emoji.id) }" @click="selectMode ? toggleSelect(emoji) : edit(emoji)"> @@ -40,14 +40,14 @@ <FormSplit> <MkInput v-model="queryRemote" :debounce="true" type="search"> <template #prefix><i class="fas fa-search"></i></template> - <template #label>{{ $ts.search }}</template> + <template #label>{{ i18n.ts.search }}</template> </MkInput> <MkInput v-model="host" :debounce="true"> - <template #label>{{ $ts.host }}</template> + <template #label>{{ i18n.ts.host }}</template> </MkInput> </FormSplit> <MkPagination :pagination="remotePagination"> - <template #empty><span>{{ $ts.noCustomEmojis }}</span></template> + <template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template> <template #default="{items}"> <div class="ldhfsamy"> <div v-for="emoji in items" :key="emoji.id" class="emoji _panel _button" @click="remoteMenu(emoji, $event)"> diff --git a/packages/client/src/pages/admin/files.vue b/packages/client/src/pages/admin/files.vue index dd309180a7..2614a6b8d9 100644 --- a/packages/client/src/pages/admin/files.vue +++ b/packages/client/src/pages/admin/files.vue @@ -7,13 +7,13 @@ <div> <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> <MkSelect v-model="origin" style="margin: 0; flex: 1;"> - <template #label>{{ $ts.instance }}</template> - <option value="combined">{{ $ts.all }}</option> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <template #label>{{ i18n.ts.instance }}</template> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkSelect> <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params.origin === 'local'"> - <template #label>{{ $ts.host }}</template> + <template #label>{{ i18n.ts.host }}</template> </MkInput> </div> <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap; padding-top: 1.2em;"> diff --git a/packages/client/src/pages/admin/index.vue b/packages/client/src/pages/admin/index.vue index d82880c34a..154b854809 100644 --- a/packages/client/src/pages/admin/index.vue +++ b/packages/client/src/pages/admin/index.vue @@ -1,23 +1,23 @@ <template> <div ref="el" class="hiyeyicy" :class="{ wide: !narrow }"> - <div v-if="!narrow || initialPage == null" class="nav"> + <div v-if="!narrow || currentPage?.route.name == null" class="nav"> <MkSpacer :content-max="700" :margin-min="16"> <div class="lxpfedzu"> <div class="banner"> <img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/> </div> - <MkInfo v-if="thereIsUnresolvedAbuseReport" warn class="info">{{ $ts.thereIsUnresolvedAbuseReportWarning }} <MkA to="/admin/abuses" class="_link">{{ $ts.check }}</MkA></MkInfo> - <MkInfo v-if="noMaintainerInformation" warn class="info">{{ $ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkInfo v-if="noBotProtection" warn class="info">{{ $ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkInfo v-if="noEmailServer" warn class="info">{{ $ts.noEmailServerWarning }} <MkA to="/admin/email-settings" class="_link">{{ $ts.configure }}</MkA></MkInfo> + <MkInfo v-if="thereIsUnresolvedAbuseReport" warn class="info">{{ i18n.ts.thereIsUnresolvedAbuseReportWarning }} <MkA to="/admin/abuses" class="_link">{{ i18n.ts.check }}</MkA></MkInfo> + <MkInfo v-if="noMaintainerInformation" warn class="info">{{ i18n.ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo> + <MkInfo v-if="noBotProtection" warn class="info">{{ i18n.ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo> + <MkInfo v-if="noEmailServer" warn class="info">{{ i18n.ts.noEmailServerWarning }} <MkA to="/admin/email-settings" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo> - <MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu> + <MkSuperMenu :def="menuDef" :grid="currentPage?.route.name == null"></MkSuperMenu> </div> </MkSpacer> </div> - <div v-if="!(narrow && initialPage == null)" class="main"> - <component :is="component" :key="initialPage" v-bind="pageProps"/> + <div v-if="!(narrow && currentPage?.route.name == null)" class="main"> + <RouterView/> </div> </div> </template> @@ -44,15 +44,10 @@ const indexInfo = { hideHeader: true, }; -const props = defineProps<{ - initialPage?: string, -}>(); - provide('shouldOmitHeaderTitle', false); let INFO = $ref(indexInfo); let childInfo = $ref(null); -let page = $ref(props.initialPage); let narrow = $ref(false); let view = $ref(null); let el = $ref(null); @@ -61,6 +56,7 @@ let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instan let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha; let noEmailServer = !instance.enableEmail; let thereIsUnresolvedAbuseReport = $ref(false); +let currentPage = $computed(() => router.currentRef.value.child); os.api('admin/abuse-user-reports', { state: 'unresolved', @@ -94,47 +90,47 @@ const menuDef = $computed(() => [{ icon: 'fas fa-tachometer-alt', text: i18n.ts.dashboard, to: '/admin/overview', - active: props.initialPage === 'overview', + active: currentPage?.route.name === 'overview', }, { icon: 'fas fa-users', text: i18n.ts.users, to: '/admin/users', - active: props.initialPage === 'users', + active: currentPage?.route.name === 'users', }, { icon: 'fas fa-laugh', text: i18n.ts.customEmojis, to: '/admin/emojis', - active: props.initialPage === 'emojis', + active: currentPage?.route.name === 'emojis', }, { icon: 'fas fa-globe', text: i18n.ts.federation, to: '/about#federation', - active: props.initialPage === 'federation', + active: currentPage?.route.name === 'federation', }, { icon: 'fas fa-clipboard-list', text: i18n.ts.jobQueue, to: '/admin/queue', - active: props.initialPage === 'queue', + active: currentPage?.route.name === 'queue', }, { icon: 'fas fa-cloud', text: i18n.ts.files, to: '/admin/files', - active: props.initialPage === 'files', + active: currentPage?.route.name === 'files', }, { icon: 'fas fa-broadcast-tower', text: i18n.ts.announcements, to: '/admin/announcements', - active: props.initialPage === 'announcements', + active: currentPage?.route.name === 'announcements', }, { icon: 'fas fa-audio-description', text: i18n.ts.ads, to: '/admin/ads', - active: props.initialPage === 'ads', + active: currentPage?.route.name === 'ads', }, { icon: 'fas fa-exclamation-circle', text: i18n.ts.abuseReports, to: '/admin/abuses', - active: props.initialPage === 'abuses', + active: currentPage?.route.name === 'abuses', }], }, { title: i18n.ts.settings, @@ -142,47 +138,47 @@ const menuDef = $computed(() => [{ icon: 'fas fa-cog', text: i18n.ts.general, to: '/admin/settings', - active: props.initialPage === 'settings', + active: currentPage?.route.name === 'settings', }, { icon: 'fas fa-envelope', text: i18n.ts.emailServer, to: '/admin/email-settings', - active: props.initialPage === 'email-settings', + active: currentPage?.route.name === 'email-settings', }, { icon: 'fas fa-cloud', text: i18n.ts.objectStorage, to: '/admin/object-storage', - active: props.initialPage === 'object-storage', + active: currentPage?.route.name === 'object-storage', }, { icon: 'fas fa-lock', text: i18n.ts.security, to: '/admin/security', - active: props.initialPage === 'security', + active: currentPage?.route.name === 'security', }, { icon: 'fas fa-globe', text: i18n.ts.relays, to: '/admin/relays', - active: props.initialPage === 'relays', + active: currentPage?.route.name === 'relays', }, { icon: 'fas fa-share-alt', text: i18n.ts.integration, to: '/admin/integrations', - active: props.initialPage === 'integrations', + active: currentPage?.route.name === 'integrations', }, { icon: 'fas fa-ban', text: i18n.ts.instanceBlocking, to: '/admin/instance-block', - active: props.initialPage === 'instance-block', + active: currentPage?.route.name === 'instance-block', }, { icon: 'fas fa-ghost', text: i18n.ts.proxyAccount, to: '/admin/proxy-account', - active: props.initialPage === 'proxy-account', + active: currentPage?.route.name === 'proxy-account', }, { icon: 'fas fa-cogs', text: i18n.ts.other, to: '/admin/other-settings', - active: props.initialPage === 'other-settings', + active: currentPage?.route.name === 'other-settings', }], }, { title: i18n.ts.info, @@ -190,55 +186,12 @@ const menuDef = $computed(() => [{ icon: 'fas fa-database', text: i18n.ts.database, to: '/admin/database', - active: props.initialPage === 'database', + active: currentPage?.route.name === 'database', }], }]); -const component = $computed(() => { - if (props.initialPage == null) return null; - switch (props.initialPage) { - case 'overview': return defineAsyncComponent(() => import('./overview.vue')); - case 'users': return defineAsyncComponent(() => import('./users.vue')); - case 'emojis': return defineAsyncComponent(() => import('./emojis.vue')); - //case 'federation': return defineAsyncComponent(() => import('../federation.vue')); - case 'queue': return defineAsyncComponent(() => import('./queue.vue')); - case 'files': return defineAsyncComponent(() => import('./files.vue')); - case 'announcements': return defineAsyncComponent(() => import('./announcements.vue')); - case 'ads': return defineAsyncComponent(() => import('./ads.vue')); - case 'database': return defineAsyncComponent(() => import('./database.vue')); - case 'abuses': return defineAsyncComponent(() => import('./abuses.vue')); - case 'settings': return defineAsyncComponent(() => import('./settings.vue')); - case 'email-settings': return defineAsyncComponent(() => import('./email-settings.vue')); - case 'object-storage': return defineAsyncComponent(() => import('./object-storage.vue')); - case 'security': return defineAsyncComponent(() => import('./security.vue')); - case 'relays': return defineAsyncComponent(() => import('./relays.vue')); - case 'integrations': return defineAsyncComponent(() => import('./integrations.vue')); - case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue')); - case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue')); - case 'other-settings': return defineAsyncComponent(() => import('./other-settings.vue')); - } -}); - -watch(component, () => { - pageProps = {}; - - nextTick(() => { - scroll(el, { top: 0 }); - }); -}, { immediate: true }); - -watch(() => props.initialPage, () => { - if (props.initialPage == null && !narrow) { - router.push('/admin/overview'); - } else { - if (props.initialPage == null) { - INFO = indexInfo; - } - } -}); - watch(narrow, () => { - if (props.initialPage == null && !narrow) { + if (currentPage?.route.name == null && !narrow) { router.push('/admin/overview'); } }); @@ -247,7 +200,7 @@ onMounted(() => { ro.observe(el); narrow = el.offsetWidth < NARROW_THRESHOLD; - if (props.initialPage == null && !narrow) { + if (currentPage?.route.name == null && !narrow) { router.push('/admin/overview'); } }); diff --git a/packages/client/src/pages/admin/integrations.discord.vue b/packages/client/src/pages/admin/integrations.discord.vue index 9fdc51a6ca..eff318dc17 100644 --- a/packages/client/src/pages/admin/integrations.discord.vue +++ b/packages/client/src/pages/admin/integrations.discord.vue @@ -2,7 +2,7 @@ <FormSuspense :p="init"> <div class="_formRoot"> <FormSwitch v-model="enableDiscordIntegration" class="_formBlock"> - <template #label>{{ $ts.enable }}</template> + <template #label>{{ i18n.ts.enable }}</template> </FormSwitch> <template v-if="enableDiscordIntegration"> @@ -19,7 +19,7 @@ </FormInput> </template> - <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> + <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton> </div> </FormSuspense> </template> @@ -33,6 +33,7 @@ import FormInfo from '@/components/ui/info.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os'; import { fetchInstance } from '@/instance'; +import { i18n } from '@/i18n'; let uri: string = $ref(''); let enableDiscordIntegration: boolean = $ref(false); diff --git a/packages/client/src/pages/admin/integrations.github.vue b/packages/client/src/pages/admin/integrations.github.vue index b10ccb8394..f6e56e1ed3 100644 --- a/packages/client/src/pages/admin/integrations.github.vue +++ b/packages/client/src/pages/admin/integrations.github.vue @@ -2,7 +2,7 @@ <FormSuspense :p="init"> <div class="_formRoot"> <FormSwitch v-model="enableGithubIntegration" class="_formBlock"> - <template #label>{{ $ts.enable }}</template> + <template #label>{{ i18n.ts.enable }}</template> </FormSwitch> <template v-if="enableGithubIntegration"> @@ -19,7 +19,7 @@ </FormInput> </template> - <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> + <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton> </div> </FormSuspense> </template> @@ -33,6 +33,7 @@ import FormInfo from '@/components/ui/info.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os'; import { fetchInstance } from '@/instance'; +import { i18n } from '@/i18n'; let uri: string = $ref(''); let enableGithubIntegration: boolean = $ref(false); diff --git a/packages/client/src/pages/admin/integrations.twitter.vue b/packages/client/src/pages/admin/integrations.twitter.vue index 11b5fd86b2..48da4648f4 100644 --- a/packages/client/src/pages/admin/integrations.twitter.vue +++ b/packages/client/src/pages/admin/integrations.twitter.vue @@ -2,7 +2,7 @@ <FormSuspense :p="init"> <div class="_formRoot"> <FormSwitch v-model="enableTwitterIntegration" class="_formBlock"> - <template #label>{{ $ts.enable }}</template> + <template #label>{{ i18n.ts.enable }}</template> </FormSwitch> <template v-if="enableTwitterIntegration"> @@ -19,7 +19,7 @@ </FormInput> </template> - <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> + <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton> </div> </FormSuspense> </template> @@ -33,6 +33,7 @@ import FormInfo from '@/components/ui/info.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os'; import { fetchInstance } from '@/instance'; +import { i18n } from '@/i18n'; let uri: string = $ref(''); let enableTwitterIntegration: boolean = $ref(false); diff --git a/packages/client/src/pages/admin/queue.chart.vue b/packages/client/src/pages/admin/queue.chart.vue index c213037b65..186a22c43e 100644 --- a/packages/client/src/pages/admin/queue.chart.vue +++ b/packages/client/src/pages/admin/queue.chart.vue @@ -33,7 +33,7 @@ <span style="margin-left: 8px; opacity: 0.7;">({{ number(job[1]) }} jobs)</span> </div> </div> - <span v-else style="opacity: 0.5;">{{ $ts.noJobs }}</span> + <span v-else style="opacity: 0.5;">{{ i18n.ts.noJobs }}</span> </div> </div> </template> @@ -44,6 +44,7 @@ import XChart from './queue.chart.chart.vue'; import number from '@/filters/number'; import * as os from '@/os'; import { stream } from '@/stream'; +import { i18n } from '@/i18n'; const connection = markRaw(stream.useChannel('queueStats')); diff --git a/packages/client/src/pages/admin/users.vue b/packages/client/src/pages/admin/users.vue index c6755672f7..6bc569f246 100644 --- a/packages/client/src/pages/admin/users.vue +++ b/packages/client/src/pages/admin/users.vue @@ -7,36 +7,36 @@ <div class="users"> <div class="inputs"> <MkSelect v-model="sort" style="flex: 1;"> - <template #label>{{ $ts.sort }}</template> - <option value="-createdAt">{{ $ts.registeredDate }} ({{ $ts.ascendingOrder }})</option> - <option value="+createdAt">{{ $ts.registeredDate }} ({{ $ts.descendingOrder }})</option> - <option value="-updatedAt">{{ $ts.lastUsed }} ({{ $ts.ascendingOrder }})</option> - <option value="+updatedAt">{{ $ts.lastUsed }} ({{ $ts.descendingOrder }})</option> + <template #label>{{ i18n.ts.sort }}</template> + <option value="-createdAt">{{ i18n.ts.registeredDate }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+createdAt">{{ i18n.ts.registeredDate }} ({{ i18n.ts.descendingOrder }})</option> + <option value="-updatedAt">{{ i18n.ts.lastUsed }} ({{ i18n.ts.ascendingOrder }})</option> + <option value="+updatedAt">{{ i18n.ts.lastUsed }} ({{ i18n.ts.descendingOrder }})</option> </MkSelect> <MkSelect v-model="state" style="flex: 1;"> - <template #label>{{ $ts.state }}</template> - <option value="all">{{ $ts.all }}</option> - <option value="available">{{ $ts.normal }}</option> - <option value="admin">{{ $ts.administrator }}</option> - <option value="moderator">{{ $ts.moderator }}</option> - <option value="silenced">{{ $ts.silence }}</option> - <option value="suspended">{{ $ts.suspend }}</option> + <template #label>{{ i18n.ts.state }}</template> + <option value="all">{{ i18n.ts.all }}</option> + <option value="available">{{ i18n.ts.normal }}</option> + <option value="admin">{{ i18n.ts.administrator }}</option> + <option value="moderator">{{ i18n.ts.moderator }}</option> + <option value="silenced">{{ i18n.ts.silence }}</option> + <option value="suspended">{{ i18n.ts.suspend }}</option> </MkSelect> <MkSelect v-model="origin" style="flex: 1;"> - <template #label>{{ $ts.instance }}</template> - <option value="combined">{{ $ts.all }}</option> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <template #label>{{ i18n.ts.instance }}</template> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkSelect> </div> <div class="inputs"> <MkInput v-model="searchUsername" style="flex: 1;" type="text" :spellcheck="false" @update:modelValue="$refs.users.reload()"> <template #prefix>@</template> - <template #label>{{ $ts.username }}</template> + <template #label>{{ i18n.ts.username }}</template> </MkInput> <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params.origin === 'local'" @update:modelValue="$refs.users.reload()"> <template #prefix>@</template> - <template #label>{{ $ts.host }}</template> + <template #label>{{ i18n.ts.host }}</template> </MkInput> </div> diff --git a/packages/client/src/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue index 0fa1f69518..5b5d0454f9 100644 --- a/packages/client/src/pages/channel-editor.vue +++ b/packages/client/src/pages/channel-editor.vue @@ -4,22 +4,22 @@ <MkSpacer :content-max="700"> <div class="_formRoot"> <MkInput v-model="name" class="_formBlock"> - <template #label>{{ $ts.name }}</template> + <template #label>{{ i18n.ts.name }}</template> </MkInput> <MkTextarea v-model="description" class="_formBlock"> - <template #label>{{ $ts.description }}</template> + <template #label>{{ i18n.ts.description }}</template> </MkTextarea> <div class="banner"> - <MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton> + <MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ i18n.ts._channel.setBanner }}</MkButton> <div v-else-if="bannerUrl"> <img :src="bannerUrl" style="width: 100%;"/> - <MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton> + <MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ i18n.ts._channel.removeBanner }}</MkButton> </div> </div> <div class="_formBlock"> - <MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton> + <MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? i18n.ts.save : i18n.ts.create }}</MkButton> </div> </div> </MkSpacer> diff --git a/packages/client/src/pages/channel.vue b/packages/client/src/pages/channel.vue index 1443a9b644..4a3c97cdae 100644 --- a/packages/client/src/pages/channel.vue +++ b/packages/client/src/pages/channel.vue @@ -13,8 +13,8 @@ </div> <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner"> <div class="status"> - <div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> - <div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> + <div><i class="fas fa-users fa-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> + <div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> </div> <div class="fade"></div> </div> diff --git a/packages/client/src/pages/explore.users.vue b/packages/client/src/pages/explore.users.vue index 8af37ab529..ed5ee3b791 100644 --- a/packages/client/src/pages/explore.users.vue +++ b/packages/client/src/pages/explore.users.vue @@ -1,32 +1,32 @@ <template> <MkSpacer :content-max="1200"> <MkTab v-model="origin" style="margin-bottom: var(--margin);"> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkTab> <div v-if="origin === 'local'"> <template v-if="tag == null"> <MkFolder class="_gap" persist-key="explore-pinned-users"> - <template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template> + <template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedUsers }}</template> <XUserList :pagination="pinnedUsers"/> </MkFolder> <MkFolder class="_gap" persist-key="explore-popular-users"> - <template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> + <template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template> <XUserList :pagination="popularUsers"/> </MkFolder> <MkFolder class="_gap" persist-key="explore-recently-updated-users"> - <template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> + <template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template> <XUserList :pagination="recentlyUpdatedUsers"/> </MkFolder> <MkFolder class="_gap" persist-key="explore-recently-registered-users"> - <template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template> + <template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyRegisteredUsers }}</template> <XUserList :pagination="recentlyRegisteredUsers"/> </MkFolder> </template> </div> <div v-else> <MkFolder ref="tagsEl" :foldable="true" :expanded="false" class="_gap"> - <template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template> + <template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularTags }}</template> <div class="vxjfqztj"> <MkA v-for="tag in tagsLocal" :key="'local:' + tag.tag" :to="`/explore/tags/${tag.tag}`" class="local">{{ tag.tag }}</MkA> @@ -41,15 +41,15 @@ <template v-if="tag == null"> <MkFolder class="_gap"> - <template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> + <template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template> <XUserList :pagination="popularUsersF"/> </MkFolder> <MkFolder class="_gap"> - <template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> + <template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template> <XUserList :pagination="recentlyUpdatedUsersF"/> </MkFolder> <MkFolder class="_gap"> - <template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template> + <template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyDiscoveredUsers }}</template> <XUserList :pagination="recentlyRegisteredUsersF"/> </MkFolder> </template> diff --git a/packages/client/src/pages/explore.vue b/packages/client/src/pages/explore.vue index 059e94d1df..4725278ab6 100644 --- a/packages/client/src/pages/explore.vue +++ b/packages/client/src/pages/explore.vue @@ -13,12 +13,12 @@ <div> <MkInput v-model="searchQuery" :debounce="true" type="search" class="_formBlock"> <template #prefix><i class="fas fa-search"></i></template> - <template #label>{{ $ts.searchUser }}</template> + <template #label>{{ i18n.ts.searchUser }}</template> </MkInput> <MkRadios v-model="searchOrigin" class="_formBlock"> - <option value="combined">{{ $ts.all }}</option> - <option value="local">{{ $ts.local }}</option> - <option value="remote">{{ $ts.remote }}</option> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> </MkRadios> </div> diff --git a/packages/client/src/pages/favorites.vue b/packages/client/src/pages/favorites.vue index 6f75d68def..203dc4a51b 100644 --- a/packages/client/src/pages/favorites.vue +++ b/packages/client/src/pages/favorites.vue @@ -6,7 +6,7 @@ <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.noNotes }}</div> + <div>{{ i18n.ts.noNotes }}</div> </div> </template> diff --git a/packages/client/src/pages/follow-requests.vue b/packages/client/src/pages/follow-requests.vue index 1f4dc9e938..f87bcbf24b 100644 --- a/packages/client/src/pages/follow-requests.vue +++ b/packages/client/src/pages/follow-requests.vue @@ -6,7 +6,7 @@ <template #empty> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> - <div>{{ $ts.noFollowRequests }}</div> + <div>{{ i18n.ts.noFollowRequests }}</div> </div> </template> <template #default="{items}"> diff --git a/packages/client/src/pages/gallery/edit.vue b/packages/client/src/pages/gallery/edit.vue index f8a5d54f71..2e0e5063e9 100644 --- a/packages/client/src/pages/gallery/edit.vue +++ b/packages/client/src/pages/gallery/edit.vue @@ -4,27 +4,27 @@ <MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> <FormSuspense :p="init"> <FormInput v-model="title"> - <template #label>{{ $ts.title }}</template> + <template #label>{{ i18n.ts.title }}</template> </FormInput> <FormTextarea v-model="description" :max="500"> - <template #label>{{ $ts.description }}</template> + <template #label>{{ i18n.ts.description }}</template> </FormTextarea> <div class=""> <div v-for="file in files" :key="file.id" class="wqugxsfx" :style="{ backgroundImage: file ? `url(${ file.thumbnailUrl })` : null }"> <div class="name">{{ file.name }}</div> - <button v-tooltip="$ts.remove" class="remove _button" @click="remove(file)"><i class="fas fa-times"></i></button> + <button v-tooltip="i18n.ts.remove" class="remove _button" @click="remove(file)"><i class="fas fa-times"></i></button> </div> - <FormButton primary @click="selectFile"><i class="fas fa-plus"></i> {{ $ts.attachFile }}</FormButton> + <FormButton primary @click="selectFile"><i class="fas fa-plus"></i> {{ i18n.ts.attachFile }}</FormButton> </div> - <FormSwitch v-model="isSensitive">{{ $ts.markAsSensitive }}</FormSwitch> + <FormSwitch v-model="isSensitive">{{ i18n.ts.markAsSensitive }}</FormSwitch> - <FormButton v-if="postId" primary @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton> - <FormButton v-else primary @click="save"><i class="fas fa-save"></i> {{ $ts.publish }}</FormButton> + <FormButton v-if="postId" primary @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton> + <FormButton v-else primary @click="save"><i class="fas fa-save"></i> {{ i18n.ts.publish }}</FormButton> - <FormButton v-if="postId" danger @click="del"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</FormButton> + <FormButton v-if="postId" danger @click="del"><i class="fas fa-trash-alt"></i> {{ i18n.ts.delete }}</FormButton> </FormSuspense> </MkSpacer> </MkStickyContainer> diff --git a/packages/client/src/pages/gallery/index.vue b/packages/client/src/pages/gallery/index.vue index 6b406af742..fba8b96bda 100644 --- a/packages/client/src/pages/gallery/index.vue +++ b/packages/client/src/pages/gallery/index.vue @@ -5,7 +5,7 @@ <div class="_root"> <div v-if="tab === 'explore'"> <MkFolder class="_gap"> - <template #header><i class="fas fa-clock"></i>{{ $ts.recentPosts }}</template> + <template #header><i class="fas fa-clock"></i>{{ i18n.ts.recentPosts }}</template> <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disable-auto-load="true"> <div class="vfpdbgtk"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> @@ -13,7 +13,7 @@ </MkPagination> </MkFolder> <MkFolder class="_gap"> - <template #header><i class="fas fa-fire-alt"></i>{{ $ts.popularPosts }}</template> + <template #header><i class="fas fa-fire-alt"></i>{{ i18n.ts.popularPosts }}</template> <MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disable-auto-load="true"> <div class="vfpdbgtk"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> @@ -29,7 +29,7 @@ </MkPagination> </div> <div v-else-if="tab === 'my'"> - <MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="fas fa-plus"></i> {{ $ts.postToGallery }}</MkA> + <MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="fas fa-plus"></i> {{ i18n.ts.postToGallery }}</MkA> <MkPagination v-slot="{items}" :pagination="myPostsPagination"> <div class="vfpdbgtk"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> diff --git a/packages/client/src/pages/gallery/post.vue b/packages/client/src/pages/gallery/post.vue index e87a541e98..a3a11d9a65 100644 --- a/packages/client/src/pages/gallery/post.vue +++ b/packages/client/src/pages/gallery/post.vue @@ -18,13 +18,13 @@ </div> <div class="actions"> <div class="like"> - <MkButton v-if="post.isLiked" v-tooltip="$ts._gallery.unlike" class="button" primary @click="unlike()"><i class="fas fa-heart"></i><span v-if="post.likedCount > 0" class="count">{{ post.likedCount }}</span></MkButton> - <MkButton v-else v-tooltip="$ts._gallery.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="post.likedCount > 0" class="count">{{ post.likedCount }}</span></MkButton> + <MkButton v-if="post.isLiked" v-tooltip="i18n.ts._gallery.unlike" class="button" primary @click="unlike()"><i class="fas fa-heart"></i><span v-if="post.likedCount > 0" class="count">{{ post.likedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts._gallery.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="post.likedCount > 0" class="count">{{ post.likedCount }}</span></MkButton> </div> <div class="other"> - <button v-if="$i && $i.id === post.user.id" v-tooltip="$ts.edit" v-click-anime class="_button" @click="edit"><i class="fas fa-pencil-alt fa-fw"></i></button> - <button v-tooltip="$ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button> - <button v-tooltip="$ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button> + <button v-if="$i && $i.id === post.user.id" v-tooltip="i18n.ts.edit" v-click-anime class="_button" @click="edit"><i class="fas fa-pencil-alt fa-fw"></i></button> + <button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button> + <button v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button> </div> </div> <div class="user"> @@ -38,7 +38,7 @@ </div> <MkAd :prefer="['horizontal', 'horizontal-big']"/> <MkContainer :max-height="300" :foldable="true" class="other"> - <template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template> + <template #header><i class="fas fa-clock"></i> {{ i18n.ts.recentPosts }}</template> <MkPagination v-slot="{items}" :pagination="otherPostsPagination"> <div class="sdrarzaf"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> diff --git a/packages/client/src/pages/instance-info.vue b/packages/client/src/pages/instance-info.vue index d4d338b125..eaa9b2b319 100644 --- a/packages/client/src/pages/instance-info.vue +++ b/packages/client/src/pages/instance-info.vue @@ -5,51 +5,51 @@ <div v-if="tab === 'overview'" class="_formRoot"> <div class="fnfelxur"> <img :src="instance.iconUrl || instance.faviconUrl" alt="" class="icon"/> - <span class="name">{{ instance.name || `(${$ts.unknown})` }}</span> + <span class="name">{{ instance.name || `(${i18n.ts.unknown})` }}</span> </div> <MkKeyValue :copy="host" oneline style="margin: 1em 0;"> <template #key>Host</template> <template #value><span class="_monospace"><MkLink :url="`https://${host}`">{{ host }}</MkLink></span></template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.software }}</template> - <template #value><span class="_monospace">{{ instance.softwareName || `(${$ts.unknown})` }} / {{ instance.softwareVersion || `(${$ts.unknown})` }}</span></template> + <template #key>{{ i18n.ts.software }}</template> + <template #value><span class="_monospace">{{ instance.softwareName || `(${i18n.ts.unknown})` }} / {{ instance.softwareVersion || `(${i18n.ts.unknown})` }}</span></template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.administrator }}</template> - <template #value>{{ instance.maintainerName || `(${$ts.unknown})` }} ({{ instance.maintainerEmail || `(${$ts.unknown})` }})</template> + <template #key>{{ i18n.ts.administrator }}</template> + <template #value>{{ instance.maintainerName || `(${i18n.ts.unknown})` }} ({{ instance.maintainerEmail || `(${i18n.ts.unknown})` }})</template> </MkKeyValue> <MkKeyValue> - <template #key>{{ $ts.description }}</template> + <template #key>{{ i18n.ts.description }}</template> <template #value>{{ instance.description }}</template> </MkKeyValue> <FormSection v-if="iAmModerator"> <template #label>Moderation</template> - <FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ $ts.stopActivityDelivery }}</FormSwitch> - <FormSwitch v-model="isBlocked" class="_formBlock" @update:modelValue="toggleBlock">{{ $ts.blockThisInstance }}</FormSwitch> + <FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</FormSwitch> + <FormSwitch v-model="isBlocked" class="_formBlock" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</FormSwitch> <MkButton @click="refreshMetadata"><i class="fas fa-refresh"></i> Refresh metadata</MkButton> </FormSection> <FormSection> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.registeredAt }}</template> + <template #key>{{ i18n.ts.registeredAt }}</template> <template #value><MkTime mode="detail" :time="instance.caughtAt"/></template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.updatedAt }}</template> + <template #key>{{ i18n.ts.updatedAt }}</template> <template #value><MkTime mode="detail" :time="instance.infoUpdatedAt"/></template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.latestRequestSentAt }}</template> + <template #key>{{ i18n.ts.latestRequestSentAt }}</template> <template #value><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.latestStatus }}</template> + <template #key>{{ i18n.ts.latestStatus }}</template> <template #value>{{ instance.latestStatus ? instance.latestStatus : 'N/A' }}</template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.latestRequestReceivedAt }}</template> + <template #key>{{ i18n.ts.latestRequestReceivedAt }}</template> <template #value><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></template> </MkKeyValue> </FormSection> @@ -78,17 +78,17 @@ <div class="cmhjzshl"> <div class="selects"> <MkSelect v-model="chartSrc" style="margin: 0 10px 0 0; flex: 1;"> - <option value="instance-requests">{{ $ts._instanceCharts.requests }}</option> - <option value="instance-users">{{ $ts._instanceCharts.users }}</option> - <option value="instance-users-total">{{ $ts._instanceCharts.usersTotal }}</option> - <option value="instance-notes">{{ $ts._instanceCharts.notes }}</option> - <option value="instance-notes-total">{{ $ts._instanceCharts.notesTotal }}</option> - <option value="instance-ff">{{ $ts._instanceCharts.ff }}</option> - <option value="instance-ff-total">{{ $ts._instanceCharts.ffTotal }}</option> - <option value="instance-drive-usage">{{ $ts._instanceCharts.cacheSize }}</option> - <option value="instance-drive-usage-total">{{ $ts._instanceCharts.cacheSizeTotal }}</option> - <option value="instance-drive-files">{{ $ts._instanceCharts.files }}</option> - <option value="instance-drive-files-total">{{ $ts._instanceCharts.filesTotal }}</option> + <option value="instance-requests">{{ i18n.ts._instanceCharts.requests }}</option> + <option value="instance-users">{{ i18n.ts._instanceCharts.users }}</option> + <option value="instance-users-total">{{ i18n.ts._instanceCharts.usersTotal }}</option> + <option value="instance-notes">{{ i18n.ts._instanceCharts.notes }}</option> + <option value="instance-notes-total">{{ i18n.ts._instanceCharts.notesTotal }}</option> + <option value="instance-ff">{{ i18n.ts._instanceCharts.ff }}</option> + <option value="instance-ff-total">{{ i18n.ts._instanceCharts.ffTotal }}</option> + <option value="instance-drive-usage">{{ i18n.ts._instanceCharts.cacheSize }}</option> + <option value="instance-drive-usage-total">{{ i18n.ts._instanceCharts.cacheSizeTotal }}</option> + <option value="instance-drive-files">{{ i18n.ts._instanceCharts.files }}</option> + <option value="instance-drive-files-total">{{ i18n.ts._instanceCharts.filesTotal }}</option> </MkSelect> </div> <div class="charts"> diff --git a/packages/client/src/pages/messaging/messaging-room.vue b/packages/client/src/pages/messaging/messaging-room.vue index 2e00c3ab19..fe1590b240 100644 --- a/packages/client/src/pages/messaging/messaging-room.vue +++ b/packages/client/src/pages/messaging/messaging-room.vue @@ -292,6 +292,7 @@ definePageMetadata(computed(() => !fetching ? user ? { <style lang="scss" scoped> .mk-messaging-room { position: relative; + overflow: auto; > .body { .more { @@ -335,10 +336,7 @@ definePageMetadata(computed(() => !fetching ? user ? { z-index: 2; bottom: 0; padding-top: 8px; - - @media (max-width: 500px) { - bottom: calc(env(safe-area-inset-bottom, 0px) + 92px); - } + bottom: calc(env(safe-area-inset-bottom, 0px) + 8px); > .new-message { width: 100%; diff --git a/packages/client/src/pages/mfm-cheat-sheet.vue b/packages/client/src/pages/mfm-cheat-sheet.vue index 0b5dae996f..bd8ae4e0b6 100644 --- a/packages/client/src/pages/mfm-cheat-sheet.vue +++ b/packages/client/src/pages/mfm-cheat-sheet.vue @@ -3,11 +3,11 @@ <template #header><MkPageHeader/></template> <MkSpacer :content-max="800"> <div class="mwysmxbg"> - <div>{{ $ts._mfm.intro }}</div> + <div>{{ i18n.ts._mfm.intro }}</div> <div class="section _block"> - <div class="title">{{ $ts._mfm.mention }}</div> + <div class="title">{{ i18n.ts._mfm.mention }}</div> <div class="content"> - <p>{{ $ts._mfm.mentionDescription }}</p> + <p>{{ i18n.ts._mfm.mentionDescription }}</p> <div class="preview"> <Mfm :text="preview_mention"/> <MkTextarea v-model="preview_mention"><template #label>MFM</template></MkTextarea> @@ -15,9 +15,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.hashtag }}</div> + <div class="title">{{ i18n.ts._mfm.hashtag }}</div> <div class="content"> - <p>{{ $ts._mfm.hashtagDescription }}</p> + <p>{{ i18n.ts._mfm.hashtagDescription }}</p> <div class="preview"> <Mfm :text="preview_hashtag"/> <MkTextarea v-model="preview_hashtag"><template #label>MFM</template></MkTextarea> @@ -25,9 +25,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.url }}</div> + <div class="title">{{ i18n.ts._mfm.url }}</div> <div class="content"> - <p>{{ $ts._mfm.urlDescription }}</p> + <p>{{ i18n.ts._mfm.urlDescription }}</p> <div class="preview"> <Mfm :text="preview_url"/> <MkTextarea v-model="preview_url"><template #label>MFM</template></MkTextarea> @@ -35,9 +35,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.link }}</div> + <div class="title">{{ i18n.ts._mfm.link }}</div> <div class="content"> - <p>{{ $ts._mfm.linkDescription }}</p> + <p>{{ i18n.ts._mfm.linkDescription }}</p> <div class="preview"> <Mfm :text="preview_link"/> <MkTextarea v-model="preview_link"><template #label>MFM</template></MkTextarea> @@ -45,9 +45,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.emoji }}</div> + <div class="title">{{ i18n.ts._mfm.emoji }}</div> <div class="content"> - <p>{{ $ts._mfm.emojiDescription }}</p> + <p>{{ i18n.ts._mfm.emojiDescription }}</p> <div class="preview"> <Mfm :text="preview_emoji"/> <MkTextarea v-model="preview_emoji"><template #label>MFM</template></MkTextarea> @@ -55,9 +55,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.bold }}</div> + <div class="title">{{ i18n.ts._mfm.bold }}</div> <div class="content"> - <p>{{ $ts._mfm.boldDescription }}</p> + <p>{{ i18n.ts._mfm.boldDescription }}</p> <div class="preview"> <Mfm :text="preview_bold"/> <MkTextarea v-model="preview_bold"><template #label>MFM</template></MkTextarea> @@ -65,9 +65,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.small }}</div> + <div class="title">{{ i18n.ts._mfm.small }}</div> <div class="content"> - <p>{{ $ts._mfm.smallDescription }}</p> + <p>{{ i18n.ts._mfm.smallDescription }}</p> <div class="preview"> <Mfm :text="preview_small"/> <MkTextarea v-model="preview_small"><template #label>MFM</template></MkTextarea> @@ -75,9 +75,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.quote }}</div> + <div class="title">{{ i18n.ts._mfm.quote }}</div> <div class="content"> - <p>{{ $ts._mfm.quoteDescription }}</p> + <p>{{ i18n.ts._mfm.quoteDescription }}</p> <div class="preview"> <Mfm :text="preview_quote"/> <MkTextarea v-model="preview_quote"><template #label>MFM</template></MkTextarea> @@ -85,9 +85,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.center }}</div> + <div class="title">{{ i18n.ts._mfm.center }}</div> <div class="content"> - <p>{{ $ts._mfm.centerDescription }}</p> + <p>{{ i18n.ts._mfm.centerDescription }}</p> <div class="preview"> <Mfm :text="preview_center"/> <MkTextarea v-model="preview_center"><template #label>MFM</template></MkTextarea> @@ -95,9 +95,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.inlineCode }}</div> + <div class="title">{{ i18n.ts._mfm.inlineCode }}</div> <div class="content"> - <p>{{ $ts._mfm.inlineCodeDescription }}</p> + <p>{{ i18n.ts._mfm.inlineCodeDescription }}</p> <div class="preview"> <Mfm :text="preview_inlineCode"/> <MkTextarea v-model="preview_inlineCode"><template #label>MFM</template></MkTextarea> @@ -105,9 +105,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.blockCode }}</div> + <div class="title">{{ i18n.ts._mfm.blockCode }}</div> <div class="content"> - <p>{{ $ts._mfm.blockCodeDescription }}</p> + <p>{{ i18n.ts._mfm.blockCodeDescription }}</p> <div class="preview"> <Mfm :text="preview_blockCode"/> <MkTextarea v-model="preview_blockCode"><template #label>MFM</template></MkTextarea> @@ -115,9 +115,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.inlineMath }}</div> + <div class="title">{{ i18n.ts._mfm.inlineMath }}</div> <div class="content"> - <p>{{ $ts._mfm.inlineMathDescription }}</p> + <p>{{ i18n.ts._mfm.inlineMathDescription }}</p> <div class="preview"> <Mfm :text="preview_inlineMath"/> <MkTextarea v-model="preview_inlineMath"><template #label>MFM</template></MkTextarea> @@ -126,9 +126,9 @@ </div> <!-- deprecated <div class="section _block"> - <div class="title">{{ $ts._mfm.search }}</div> + <div class="title">{{ i18n.ts._mfm.search }}</div> <div class="content"> - <p>{{ $ts._mfm.searchDescription }}</p> + <p>{{ i18n.ts._mfm.searchDescription }}</p> <div class="preview"> <Mfm :text="preview_search"/> <MkTextarea v-model="preview_search"><template #label>MFM</template></MkTextarea> @@ -137,9 +137,9 @@ </div> --> <div class="section _block"> - <div class="title">{{ $ts._mfm.flip }}</div> + <div class="title">{{ i18n.ts._mfm.flip }}</div> <div class="content"> - <p>{{ $ts._mfm.flipDescription }}</p> + <p>{{ i18n.ts._mfm.flipDescription }}</p> <div class="preview"> <Mfm :text="preview_flip"/> <MkTextarea v-model="preview_flip"><template #label>MFM</template></MkTextarea> @@ -147,9 +147,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.font }}</div> + <div class="title">{{ i18n.ts._mfm.font }}</div> <div class="content"> - <p>{{ $ts._mfm.fontDescription }}</p> + <p>{{ i18n.ts._mfm.fontDescription }}</p> <div class="preview"> <Mfm :text="preview_font"/> <MkTextarea v-model="preview_font"><template #label>MFM</template></MkTextarea> @@ -157,9 +157,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.x2 }}</div> + <div class="title">{{ i18n.ts._mfm.x2 }}</div> <div class="content"> - <p>{{ $ts._mfm.x2Description }}</p> + <p>{{ i18n.ts._mfm.x2Description }}</p> <div class="preview"> <Mfm :text="preview_x2"/> <MkTextarea v-model="preview_x2"><template #label>MFM</template></MkTextarea> @@ -167,9 +167,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.x3 }}</div> + <div class="title">{{ i18n.ts._mfm.x3 }}</div> <div class="content"> - <p>{{ $ts._mfm.x3Description }}</p> + <p>{{ i18n.ts._mfm.x3Description }}</p> <div class="preview"> <Mfm :text="preview_x3"/> <MkTextarea v-model="preview_x3"><template #label>MFM</template></MkTextarea> @@ -177,9 +177,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.x4 }}</div> + <div class="title">{{ i18n.ts._mfm.x4 }}</div> <div class="content"> - <p>{{ $ts._mfm.x4Description }}</p> + <p>{{ i18n.ts._mfm.x4Description }}</p> <div class="preview"> <Mfm :text="preview_x4"/> <MkTextarea v-model="preview_x4"><template #label>MFM</template></MkTextarea> @@ -187,9 +187,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.blur }}</div> + <div class="title">{{ i18n.ts._mfm.blur }}</div> <div class="content"> - <p>{{ $ts._mfm.blurDescription }}</p> + <p>{{ i18n.ts._mfm.blurDescription }}</p> <div class="preview"> <Mfm :text="preview_blur"/> <MkTextarea v-model="preview_blur"><template #label>MFM</template></MkTextarea> @@ -197,9 +197,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.jelly }}</div> + <div class="title">{{ i18n.ts._mfm.jelly }}</div> <div class="content"> - <p>{{ $ts._mfm.jellyDescription }}</p> + <p>{{ i18n.ts._mfm.jellyDescription }}</p> <div class="preview"> <Mfm :text="preview_jelly"/> <MkTextarea v-model="preview_jelly"><template #label>MFM</template></MkTextarea> @@ -207,9 +207,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.tada }}</div> + <div class="title">{{ i18n.ts._mfm.tada }}</div> <div class="content"> - <p>{{ $ts._mfm.tadaDescription }}</p> + <p>{{ i18n.ts._mfm.tadaDescription }}</p> <div class="preview"> <Mfm :text="preview_tada"/> <MkTextarea v-model="preview_tada"><template #label>MFM</template></MkTextarea> @@ -217,9 +217,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.jump }}</div> + <div class="title">{{ i18n.ts._mfm.jump }}</div> <div class="content"> - <p>{{ $ts._mfm.jumpDescription }}</p> + <p>{{ i18n.ts._mfm.jumpDescription }}</p> <div class="preview"> <Mfm :text="preview_jump"/> <MkTextarea v-model="preview_jump"><template #label>MFM</template></MkTextarea> @@ -227,9 +227,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.bounce }}</div> + <div class="title">{{ i18n.ts._mfm.bounce }}</div> <div class="content"> - <p>{{ $ts._mfm.bounceDescription }}</p> + <p>{{ i18n.ts._mfm.bounceDescription }}</p> <div class="preview"> <Mfm :text="preview_bounce"/> <MkTextarea v-model="preview_bounce"><template #label>MFM</template></MkTextarea> @@ -237,9 +237,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.spin }}</div> + <div class="title">{{ i18n.ts._mfm.spin }}</div> <div class="content"> - <p>{{ $ts._mfm.spinDescription }}</p> + <p>{{ i18n.ts._mfm.spinDescription }}</p> <div class="preview"> <Mfm :text="preview_spin"/> <MkTextarea v-model="preview_spin"><template #label>MFM</template></MkTextarea> @@ -247,9 +247,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.shake }}</div> + <div class="title">{{ i18n.ts._mfm.shake }}</div> <div class="content"> - <p>{{ $ts._mfm.shakeDescription }}</p> + <p>{{ i18n.ts._mfm.shakeDescription }}</p> <div class="preview"> <Mfm :text="preview_shake"/> <MkTextarea v-model="preview_shake"><template #label>MFM</template></MkTextarea> @@ -257,9 +257,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.twitch }}</div> + <div class="title">{{ i18n.ts._mfm.twitch }}</div> <div class="content"> - <p>{{ $ts._mfm.twitchDescription }}</p> + <p>{{ i18n.ts._mfm.twitchDescription }}</p> <div class="preview"> <Mfm :text="preview_twitch"/> <MkTextarea v-model="preview_twitch"><template #label>MFM</template></MkTextarea> @@ -267,9 +267,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.rainbow }}</div> + <div class="title">{{ i18n.ts._mfm.rainbow }}</div> <div class="content"> - <p>{{ $ts._mfm.rainbowDescription }}</p> + <p>{{ i18n.ts._mfm.rainbowDescription }}</p> <div class="preview"> <Mfm :text="preview_rainbow"/> <MkTextarea v-model="preview_rainbow"><template #label>MFM</template></MkTextarea> @@ -277,9 +277,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.sparkle }}</div> + <div class="title">{{ i18n.ts._mfm.sparkle }}</div> <div class="content"> - <p>{{ $ts._mfm.sparkleDescription }}</p> + <p>{{ i18n.ts._mfm.sparkleDescription }}</p> <div class="preview"> <Mfm :text="preview_sparkle"/> <MkTextarea v-model="preview_sparkle"><span>MFM</span></MkTextarea> @@ -287,9 +287,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.rotate }}</div> + <div class="title">{{ i18n.ts._mfm.rotate }}</div> <div class="content"> - <p>{{ $ts._mfm.rotateDescription }}</p> + <p>{{ i18n.ts._mfm.rotateDescription }}</p> <div class="preview"> <Mfm :text="preview_rotate"/> <MkTextarea v-model="preview_rotate"><span>MFM</span></MkTextarea> @@ -297,9 +297,9 @@ </div> </div> <div class="section _block"> - <div class="title">{{ $ts._mfm.plain }}</div> + <div class="title">{{ i18n.ts._mfm.plain }}</div> <div class="content"> - <p>{{ $ts._mfm.plainDescription }}</p> + <p>{{ i18n.ts._mfm.plainDescription }}</p> <div class="preview"> <Mfm :text="preview_plain"/> <MkTextarea v-model="preview_plain"><span>MFM</span></MkTextarea> diff --git a/packages/client/src/pages/miauth.vue b/packages/client/src/pages/miauth.vue index 4b3ac7761e..cbdf6b2832 100644 --- a/packages/client/src/pages/miauth.vue +++ b/packages/client/src/pages/miauth.vue @@ -1,85 +1,88 @@ <template> -<div v-if="$i"> - <div v-if="state == 'waiting'" class="waiting _section"> - <div class="_content"> - <MkLoading/> +<MkSpacer :content-max="800"> + <div v-if="$i"> + <div v-if="state == 'waiting'" class="waiting _section"> + <div class="_content"> + <MkLoading/> + </div> </div> - </div> - <div v-if="state == 'denied'" class="denied _section"> - <div class="_content"> - <p>{{ $ts._auth.denied }}</p> + <div v-if="state == 'denied'" class="denied _section"> + <div class="_content"> + <p>{{ i18n.ts._auth.denied }}</p> + </div> </div> - </div> - <div v-else-if="state == 'accepted'" class="accepted _section"> - <div class="_content"> - <p v-if="callback">{{ $ts._auth.callback }}<MkEllipsis/></p> - <p v-else>{{ $ts._auth.pleaseGoBack }}</p> + <div v-else-if="state == 'accepted'" class="accepted _section"> + <div class="_content"> + <p v-if="callback">{{ i18n.ts._auth.callback }}<MkEllipsis/></p> + <p v-else>{{ i18n.ts._auth.pleaseGoBack }}</p> + </div> </div> - </div> - <div v-else class="_section"> - <div v-if="name" class="_title">{{ $t('_auth.shareAccess', { name: name }) }}</div> - <div v-else class="_title">{{ $ts._auth.shareAccessAsk }}</div> - <div class="_content"> - <p>{{ $ts._auth.permissionAsk }}</p> - <ul> - <li v-for="p in permission" :key="p">{{ $t(`_permissions.${p}`) }}</li> - </ul> - </div> - <div class="_footer"> - <MkButton inline @click="deny">{{ $ts.cancel }}</MkButton> - <MkButton inline primary @click="accept">{{ $ts.accept }}</MkButton> + <div v-else class="_section"> + <div v-if="name" class="_title">{{ $t('_auth.shareAccess', { name: name }) }}</div> + <div v-else class="_title">{{ i18n.ts._auth.shareAccessAsk }}</div> + <div class="_content"> + <p>{{ i18n.ts._auth.permissionAsk }}</p> + <ul> + <li v-for="p in _permissions" :key="p">{{ $t(`_permissions.${p}`) }}</li> + </ul> + </div> + <div class="_footer"> + <MkButton inline @click="deny">{{ i18n.ts.cancel }}</MkButton> + <MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton> + </div> </div> </div> -</div> -<div v-else class="signin"> - <MkSignin @login="onLogin"/> -</div> + <div v-else class="signin"> + <MkSignin @login="onLogin"/> + </div> +</MkSpacer> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { } from 'vue'; import MkSignin from '@/components/signin.vue'; import MkButton from '@/components/ui/button.vue'; import * as os from '@/os'; -import { login } from '@/account'; +import { $i, login } from '@/account'; import { appendQuery, query } from '@/scripts/url'; +import { i18n } from '@/i18n'; + +const props = defineProps<{ + session: string; + callback?: string; + name: string; + icon: string; + permission: string; // コンマ区切り +}>(); + +const _permissions = props.permission.split(','); + +let state = $ref<string | null>(null); + +async function accept(): Promise<void> { + state = 'waiting'; + await os.api('miauth/gen-token', { + session: props.session, + name: props.name, + iconUrl: props.icon, + permission: _permissions, + }); + + state = 'accepted'; + if (props.callback) { + location.href = appendQuery(props.callback, query({ + session: props.session, + })); + } +} -export default defineComponent({ - components: { - MkSignin, - MkButton, - }, - props: ['session', 'callback', 'name', 'icon', 'permission'], - data() { - return { - state: null, - }; - }, - methods: { - async accept() { - this.state = 'waiting'; - await os.api('miauth/gen-token', { - session: this.session, - name: this.name, - iconUrl: this.icon, - permission: this.permission, - }); +function deny(): void { + state = 'denied'; +} - this.state = 'accepted'; - if (this.callback) { - location.href = appendQuery(this.callback, query({ - session: this.session, - })); - } - }, - deny() { - this.state = 'denied'; - }, - onLogin(res) { - login(res.i); - }, - }, -}); +function onLogin(res): void { + login(res.i); +} </script> <style lang="scss" scoped> diff --git a/packages/client/src/pages/my-antennas/editor.vue b/packages/client/src/pages/my-antennas/editor.vue index 9470257c6c..32027846cc 100644 --- a/packages/client/src/pages/my-antennas/editor.vue +++ b/packages/client/src/pages/my-antennas/editor.vue @@ -2,44 +2,44 @@ <div class="shaynizk"> <div class="form"> <MkInput v-model="name" class="_formBlock"> - <template #label>{{ $ts.name }}</template> + <template #label>{{ i18n.ts.name }}</template> </MkInput> <MkSelect v-model="src" class="_formBlock"> - <template #label>{{ $ts.antennaSource }}</template> - <option value="all">{{ $ts._antennaSources.all }}</option> - <!--<option value="home">{{ $ts._antennaSources.homeTimeline }}</option>--> - <option value="users">{{ $ts._antennaSources.users }}</option> - <!--<option value="list">{{ $ts._antennaSources.userList }}</option>--> - <!--<option value="group">{{ $ts._antennaSources.userGroup }}</option>--> + <template #label>{{ i18n.ts.antennaSource }}</template> + <option value="all">{{ i18n.ts._antennaSources.all }}</option> + <!--<option value="home">{{ i18n.ts._antennaSources.homeTimeline }}</option>--> + <option value="users">{{ i18n.ts._antennaSources.users }}</option> + <!--<option value="list">{{ i18n.ts._antennaSources.userList }}</option>--> + <!--<option value="group">{{ i18n.ts._antennaSources.userGroup }}</option>--> </MkSelect> <MkSelect v-if="src === 'list'" v-model="userListId" class="_formBlock"> - <template #label>{{ $ts.userList }}</template> + <template #label>{{ i18n.ts.userList }}</template> <option v-for="list in userLists" :key="list.id" :value="list.id">{{ list.name }}</option> </MkSelect> <MkSelect v-else-if="src === 'group'" v-model="userGroupId" class="_formBlock"> - <template #label>{{ $ts.userGroup }}</template> + <template #label>{{ i18n.ts.userGroup }}</template> <option v-for="group in userGroups" :key="group.id" :value="group.id">{{ group.name }}</option> </MkSelect> <MkTextarea v-else-if="src === 'users'" v-model="users" class="_formBlock"> - <template #label>{{ $ts.users }}</template> - <template #caption>{{ $ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ $ts.addUser }}</button></template> + <template #label>{{ i18n.ts.users }}</template> + <template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template> </MkTextarea> - <MkSwitch v-model="withReplies" class="_formBlock">{{ $ts.withReplies }}</MkSwitch> + <MkSwitch v-model="withReplies" class="_formBlock">{{ i18n.ts.withReplies }}</MkSwitch> <MkTextarea v-model="keywords" class="_formBlock"> - <template #label>{{ $ts.antennaKeywords }}</template> - <template #caption>{{ $ts.antennaKeywordsDescription }}</template> + <template #label>{{ i18n.ts.antennaKeywords }}</template> + <template #caption>{{ i18n.ts.antennaKeywordsDescription }}</template> </MkTextarea> <MkTextarea v-model="excludeKeywords" class="_formBlock"> - <template #label>{{ $ts.antennaExcludeKeywords }}</template> - <template #caption>{{ $ts.antennaKeywordsDescription }}</template> + <template #label>{{ i18n.ts.antennaExcludeKeywords }}</template> + <template #caption>{{ i18n.ts.antennaKeywordsDescription }}</template> </MkTextarea> - <MkSwitch v-model="caseSensitive" class="_formBlock">{{ $ts.caseSensitive }}</MkSwitch> - <MkSwitch v-model="withFile" class="_formBlock">{{ $ts.withFileAntenna }}</MkSwitch> - <MkSwitch v-model="notify" class="_formBlock">{{ $ts.notifyAntenna }}</MkSwitch> + <MkSwitch v-model="caseSensitive" class="_formBlock">{{ i18n.ts.caseSensitive }}</MkSwitch> + <MkSwitch v-model="withFile" class="_formBlock">{{ i18n.ts.withFileAntenna }}</MkSwitch> + <MkSwitch v-model="notify" class="_formBlock">{{ i18n.ts.notifyAntenna }}</MkSwitch> </div> <div class="actions"> - <MkButton inline primary @click="saveAntenna()"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> - <MkButton v-if="antenna.id != null" inline danger @click="deleteAntenna()"><i class="fas fa-trash"></i> {{ $ts.delete }}</MkButton> + <MkButton inline primary @click="saveAntenna()"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton> + <MkButton v-if="antenna.id != null" inline danger @click="deleteAntenna()"><i class="fas fa-trash"></i> {{ i18n.ts.delete }}</MkButton> </div> </div> </template> diff --git a/packages/client/src/pages/my-clips/index.vue b/packages/client/src/pages/my-clips/index.vue index ac5a3578f8..5e5454b729 100644 --- a/packages/client/src/pages/my-clips/index.vue +++ b/packages/client/src/pages/my-clips/index.vue @@ -1,17 +1,19 @@ -<template><MkStickyContainer> +<template> +<MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> - <div class="qtcaoidl"> - <MkButton primary class="add" @click="create"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton> + <MkSpacer :content-max="700"> + <div class="qtcaoidl"> + <MkButton primary class="add" @click="create"><i class="fas fa-plus"></i> {{ i18n.ts.add }}</MkButton> - <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="list"> - <MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _gap"> - <b>{{ item.name }}</b> - <div v-if="item.description" class="description">{{ item.description }}</div> - </MkA> - </MkPagination> - </div> -</MkSpacer></MkStickyContainer> + <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="list"> + <MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _gap"> + <b>{{ item.name }}</b> + <div v-if="item.description" class="description">{{ item.description }}</div> + </MkA> + </MkPagination> + </div> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> diff --git a/packages/client/src/pages/my-lists/index.vue b/packages/client/src/pages/my-lists/index.vue index 03b638151e..144cba684f 100644 --- a/packages/client/src/pages/my-lists/index.vue +++ b/packages/client/src/pages/my-lists/index.vue @@ -1,17 +1,19 @@ -<template><MkStickyContainer> +<template> +<MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> - <div class="qkcjvfiv"> - <MkButton primary class="add" @click="create"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton> + <MkSpacer :content-max="700"> + <div class="qkcjvfiv"> + <MkButton primary class="add" @click="create"><i class="fas fa-plus"></i> {{ i18n.ts.createList }}</MkButton> - <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists _content"> - <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> - <div class="name">{{ list.name }}</div> - <MkAvatars :user-ids="list.userIds"/> - </MkA> - </MkPagination> - </div> -</MkSpacer></MkStickyContainer> + <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists _content"> + <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> + <div class="name">{{ list.name }}</div> + <MkAvatars :user-ids="list.userIds"/> + </MkA> + </MkPagination> + </div> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> diff --git a/packages/client/src/pages/my-lists/list.vue b/packages/client/src/pages/my-lists/list.vue index 892878ae88..8b23c667dc 100644 --- a/packages/client/src/pages/my-lists/list.vue +++ b/packages/client/src/pages/my-lists/list.vue @@ -1,42 +1,44 @@ -<template><MkStickyContainer> +<template> +<MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> - <div class="mk-list-page"> - <transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> - <div v-if="list" class="_section"> - <div class="_content"> - <MkButton inline @click="addUser()">{{ $ts.addUser }}</MkButton> - <MkButton inline @click="renameList()">{{ $ts.rename }}</MkButton> - <MkButton inline @click="deleteList()">{{ $ts.delete }}</MkButton> + <MkSpacer :content-max="700"> + <div class="mk-list-page"> + <transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> + <div v-if="list" class="_section"> + <div class="_content"> + <MkButton inline @click="addUser()">{{ i18n.ts.addUser }}</MkButton> + <MkButton inline @click="renameList()">{{ i18n.ts.rename }}</MkButton> + <MkButton inline @click="deleteList()">{{ i18n.ts.delete }}</MkButton> + </div> </div> - </div> - </transition> + </transition> - <transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> - <div v-if="list" class="_section members _gap"> - <div class="_title">{{ $ts.members }}</div> - <div class="_content"> - <div class="users"> - <div v-for="user in users" :key="user.id" class="user _panel"> - <MkAvatar :user="user" class="avatar" :show-indicator="true"/> - <div class="body"> - <MkUserName :user="user" class="name"/> - <MkAcct :user="user" class="acct"/> - </div> - <div class="action"> - <button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button> + <transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> + <div v-if="list" class="_section members _gap"> + <div class="_title">{{ i18n.ts.members }}</div> + <div class="_content"> + <div class="users"> + <div v-for="user in users" :key="user.id" class="user _panel"> + <MkAvatar :user="user" class="avatar" :show-indicator="true"/> + <div class="body"> + <MkUserName :user="user" class="name"/> + <MkAcct :user="user" class="acct"/> + </div> + <div class="action"> + <button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button> + </div> </div> </div> </div> </div> - </div> - </transition> - </div> -</MkSpacer></MkStickyContainer> + </transition> + </div> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> -import { computed, defineComponent, watch } from 'vue'; +import { computed, watch } from 'vue'; import MkButton from '@/components/ui/button.vue'; import * as os from '@/os'; import { mainRouter } from '@/router'; diff --git a/packages/client/src/pages/not-found.vue b/packages/client/src/pages/not-found.vue index a819cce961..253ecdb235 100644 --- a/packages/client/src/pages/not-found.vue +++ b/packages/client/src/pages/not-found.vue @@ -2,7 +2,7 @@ <div class="ipledcug"> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/not-found.jpg" class="_ghost"/> - <div>{{ $ts.notFoundDescription }}</div> + <div>{{ i18n.ts.notFoundDescription }}</div> </div> </div> </template> diff --git a/packages/client/src/pages/note.vue b/packages/client/src/pages/note.vue index 5e153482d6..240a0d4eb7 100644 --- a/packages/client/src/pages/note.vue +++ b/packages/client/src/pages/note.vue @@ -16,7 +16,7 @@ <XNoteDetailed :key="note.id" v-model:note="note" class="note"/> </div> <div v-if="clips && clips.length > 0" class="_content clips _gap"> - <div class="title">{{ $ts.clip }}</div> + <div class="title">{{ i18n.ts.clip }}</div> <MkA v-for="item in clips" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _gap"> <b>{{ item.name }}</b> <div v-if="item.description" class="description">{{ item.description }}</div> diff --git a/packages/client/src/pages/page.vue b/packages/client/src/pages/page.vue index c60b7069e9..02fd61f58b 100644 --- a/packages/client/src/pages/page.vue +++ b/packages/client/src/pages/page.vue @@ -18,12 +18,12 @@ </div> <div class="actions"> <div class="like"> - <MkButton v-if="page.isLiked" v-tooltip="$ts._pages.unlike" class="button" primary @click="unlike()"><i class="fas fa-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> - <MkButton v-else v-tooltip="$ts._pages.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> + <MkButton v-if="page.isLiked" v-tooltip="i18n.ts._pages.unlike" class="button" primary @click="unlike()"><i class="fas fa-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts._pages.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> </div> <div class="other"> - <button v-tooltip="$ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button> - <button v-tooltip="$ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button> + <button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button> + <button v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button> </div> </div> <div class="user"> @@ -35,21 +35,21 @@ <MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> </div> <div class="links"> - <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA> + <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ i18n.ts._pages.viewSource }}</MkA> <template v-if="$i && $i.id === page.userId"> - <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA> - <button v-if="$i.pinnedPageId === page.id" class="link _textButton" @click="pin(false)">{{ $ts.unpin }}</button> - <button v-else class="link _textButton" @click="pin(true)">{{ $ts.pin }}</button> + <MkA :to="`/pages/edit/${page.id}`" class="link">{{ i18n.ts._pages.editThisPage }}</MkA> + <button v-if="$i.pinnedPageId === page.id" class="link _textButton" @click="pin(false)">{{ i18n.ts.unpin }}</button> + <button v-else class="link _textButton" @click="pin(true)">{{ i18n.ts.pin }}</button> </template> </div> </div> <div class="footer"> - <div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> - <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> + <div><i class="far fa-clock"></i> {{ i18n.ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> + <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ i18n.ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> </div> <MkAd :prefer="['horizontal', 'horizontal-big']"/> <MkContainer :max-height="300" :foldable="true" class="other"> - <template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template> + <template #header><i class="fas fa-clock"></i> {{ i18n.ts.recentPosts }}</template> <MkPagination v-slot="{items}" :pagination="otherPostsPagination"> <MkPagePreview v-for="page in items" :key="page.id" :page="page" class="_gap"/> </MkPagination> diff --git a/packages/client/src/pages/registry.keys.vue b/packages/client/src/pages/registry.keys.vue index e580779052..ae500386dd 100644 --- a/packages/client/src/pages/registry.keys.vue +++ b/packages/client/src/pages/registry.keys.vue @@ -4,11 +4,11 @@ <MkSpacer :content-max="600" :margin-min="16"> <FormSplit> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts._registry.domain }}</template> - <template #value>{{ $ts.system }}</template> + <template #key>{{ i18n.ts._registry.domain }}</template> + <template #value>{{ i18n.ts.system }}</template> </MkKeyValue> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts._registry.scope }}</template> + <template #key>{{ i18n.ts._registry.scope }}</template> <template #value>{{ scope.join('/') }}</template> </MkKeyValue> </FormSplit> diff --git a/packages/client/src/pages/registry.value.vue b/packages/client/src/pages/registry.value.vue index 9deb31e4a4..562f9df884 100644 --- a/packages/client/src/pages/registry.value.vue +++ b/packages/client/src/pages/registry.value.vue @@ -2,36 +2,36 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :content-max="600" :margin-min="16"> - <FormInfo warn>{{ $ts.editTheseSettingsMayBreakAccount }}</FormInfo> + <FormInfo warn>{{ i18n.ts.editTheseSettingsMayBreakAccount }}</FormInfo> <template v-if="value"> <FormSplit> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts._registry.domain }}</template> - <template #value>{{ $ts.system }}</template> + <template #key>{{ i18n.ts._registry.domain }}</template> + <template #value>{{ i18n.ts.system }}</template> </MkKeyValue> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts._registry.scope }}</template> + <template #key>{{ i18n.ts._registry.scope }}</template> <template #value>{{ scope.join('/') }}</template> </MkKeyValue> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts._registry.key }}</template> + <template #key>{{ i18n.ts._registry.key }}</template> <template #value>{{ key }}</template> </MkKeyValue> </FormSplit> <FormTextarea v-model="valueForEditor" tall class="_formBlock _monospace"> - <template #label>{{ $ts.value }} (JSON)</template> + <template #label>{{ i18n.ts.value }} (JSON)</template> </FormTextarea> - <MkButton class="_formBlock" primary @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton class="_formBlock" primary @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton> <MkKeyValue class="_formBlock"> - <template #key>{{ $ts.updatedAt }}</template> + <template #key>{{ i18n.ts.updatedAt }}</template> <template #value><MkTime :time="value.updatedAt" mode="detail"/></template> </MkKeyValue> - <MkButton danger @click="del"><i class="fas fa-trash"></i> {{ $ts.delete }}</MkButton> + <MkButton danger @click="del"><i class="fas fa-trash"></i> {{ i18n.ts.delete }}</MkButton> </template> </MkSpacer> </MkStickyContainer> diff --git a/packages/client/src/pages/settings/email.vue b/packages/client/src/pages/settings/email.vue index 9d2afd6a6f..1dae233a07 100644 --- a/packages/client/src/pages/settings/email.vue +++ b/packages/client/src/pages/settings/email.vue @@ -1,39 +1,39 @@ <template> <div class="_formRoot"> <FormSection> - <template #label>{{ $ts.emailAddress }}</template> + <template #label>{{ i18n.ts.emailAddress }}</template> <FormInput v-model="emailAddress" type="email" manual-save> <template #prefix><i class="fas fa-envelope"></i></template> - <template v-if="$i.email && !$i.emailVerified" #caption>{{ $ts.verificationEmailSent }}</template> - <template v-else-if="emailAddress === $i.email && $i.emailVerified" #caption><i class="fas fa-check" style="color: var(--success);"></i> {{ $ts.emailVerified }}</template> + <template v-if="$i.email && !$i.emailVerified" #caption>{{ i18n.ts.verificationEmailSent }}</template> + <template v-else-if="emailAddress === $i.email && $i.emailVerified" #caption><i class="fas fa-check" style="color: var(--success);"></i> {{ i18n.ts.emailVerified }}</template> </FormInput> </FormSection> <FormSection> <FormSwitch :model-value="$i.receiveAnnouncementEmail" @update:modelValue="onChangeReceiveAnnouncementEmail"> - {{ $ts.receiveAnnouncementFromInstance }} + {{ i18n.ts.receiveAnnouncementFromInstance }} </FormSwitch> </FormSection> <FormSection> - <template #label>{{ $ts.emailNotification }}</template> + <template #label>{{ i18n.ts.emailNotification }}</template> <FormSwitch v-model="emailNotification_mention" class="_formBlock"> - {{ $ts._notification._types.mention }} + {{ i18n.ts._notification._types.mention }} </FormSwitch> <FormSwitch v-model="emailNotification_reply" class="_formBlock"> - {{ $ts._notification._types.reply }} + {{ i18n.ts._notification._types.reply }} </FormSwitch> <FormSwitch v-model="emailNotification_quote" class="_formBlock"> - {{ $ts._notification._types.quote }} + {{ i18n.ts._notification._types.quote }} </FormSwitch> <FormSwitch v-model="emailNotification_follow" class="_formBlock"> - {{ $ts._notification._types.follow }} + {{ i18n.ts._notification._types.follow }} </FormSwitch> <FormSwitch v-model="emailNotification_receiveFollowRequest" class="_formBlock"> - {{ $ts._notification._types.receiveFollowRequest }} + {{ i18n.ts._notification._types.receiveFollowRequest }} </FormSwitch> <FormSwitch v-model="emailNotification_groupInvited" class="_formBlock"> - {{ $ts._notification._types.groupInvited }} + {{ i18n.ts._notification._types.groupInvited }} </FormSwitch> </FormSection> </div> diff --git a/packages/client/src/pages/settings/import-export.vue b/packages/client/src/pages/settings/import-export.vue index d48dab9f8d..13c2b7fc85 100644 --- a/packages/client/src/pages/settings/import-export.vue +++ b/packages/client/src/pages/settings/import-export.vue @@ -1,69 +1,69 @@ <template> <div class="_formRoot"> <FormSection> - <template #label>{{ $ts._exportOrImport.allNotes }}</template> + <template #label>{{ i18n.ts._exportOrImport.allNotes }}</template> <FormFolder> - <template #label>{{ $ts.export }}</template> + <template #label>{{ i18n.ts.export }}</template> <template #icon><i class="fas fa-download"></i></template> - <MkButton primary :class="$style.button" inline @click="exportNotes()"><i class="fas fa-download"></i> {{ $ts.export }}</MkButton> + <MkButton primary :class="$style.button" inline @click="exportNotes()"><i class="fas fa-download"></i> {{ i18n.ts.export }}</MkButton> </FormFolder> </FormSection> <FormSection> - <template #label>{{ $ts._exportOrImport.followingList }}</template> + <template #label>{{ i18n.ts._exportOrImport.followingList }}</template> <FormFolder class="_formBlock"> - <template #label>{{ $ts.export }}</template> + <template #label>{{ i18n.ts.export }}</template> <template #icon><i class="fas fa-download"></i></template> <FormSwitch v-model="excludeMutingUsers" class="_formBlock"> - {{ $ts._exportOrImport.excludeMutingUsers }} + {{ i18n.ts._exportOrImport.excludeMutingUsers }} </FormSwitch> <FormSwitch v-model="excludeInactiveUsers" class="_formBlock"> - {{ $ts._exportOrImport.excludeInactiveUsers }} + {{ i18n.ts._exportOrImport.excludeInactiveUsers }} </FormSwitch> - <MkButton primary :class="$style.button" inline @click="exportFollowing()"><i class="fas fa-download"></i> {{ $ts.export }}</MkButton> + <MkButton primary :class="$style.button" inline @click="exportFollowing()"><i class="fas fa-download"></i> {{ i18n.ts.export }}</MkButton> </FormFolder> <FormFolder class="_formBlock"> - <template #label>{{ $ts.import }}</template> + <template #label>{{ i18n.ts.import }}</template> <template #icon><i class="fas fa-upload"></i></template> - <MkButton primary :class="$style.button" inline @click="importFollowing($event)"><i class="fas fa-upload"></i> {{ $ts.import }}</MkButton> + <MkButton primary :class="$style.button" inline @click="importFollowing($event)"><i class="fas fa-upload"></i> {{ i18n.ts.import }}</MkButton> </FormFolder> </FormSection> <FormSection> - <template #label>{{ $ts._exportOrImport.userLists }}</template> + <template #label>{{ i18n.ts._exportOrImport.userLists }}</template> <FormFolder class="_formBlock"> - <template #label>{{ $ts.export }}</template> + <template #label>{{ i18n.ts.export }}</template> <template #icon><i class="fas fa-download"></i></template> - <MkButton primary :class="$style.button" inline @click="exportUserLists()"><i class="fas fa-download"></i> {{ $ts.export }}</MkButton> + <MkButton primary :class="$style.button" inline @click="exportUserLists()"><i class="fas fa-download"></i> {{ i18n.ts.export }}</MkButton> </FormFolder> <FormFolder class="_formBlock"> - <template #label>{{ $ts.import }}</template> + <template #label>{{ i18n.ts.import }}</template> <template #icon><i class="fas fa-upload"></i></template> - <MkButton primary :class="$style.button" inline @click="importUserLists($event)"><i class="fas fa-upload"></i> {{ $ts.import }}</MkButton> + <MkButton primary :class="$style.button" inline @click="importUserLists($event)"><i class="fas fa-upload"></i> {{ i18n.ts.import }}</MkButton> </FormFolder> </FormSection> <FormSection> - <template #label>{{ $ts._exportOrImport.muteList }}</template> + <template #label>{{ i18n.ts._exportOrImport.muteList }}</template> <FormFolder class="_formBlock"> - <template #label>{{ $ts.export }}</template> + <template #label>{{ i18n.ts.export }}</template> <template #icon><i class="fas fa-download"></i></template> - <MkButton primary :class="$style.button" inline @click="exportMuting()"><i class="fas fa-download"></i> {{ $ts.export }}</MkButton> + <MkButton primary :class="$style.button" inline @click="exportMuting()"><i class="fas fa-download"></i> {{ i18n.ts.export }}</MkButton> </FormFolder> <FormFolder class="_formBlock"> - <template #label>{{ $ts.import }}</template> + <template #label>{{ i18n.ts.import }}</template> <template #icon><i class="fas fa-upload"></i></template> - <MkButton primary :class="$style.button" inline @click="importMuting($event)"><i class="fas fa-upload"></i> {{ $ts.import }}</MkButton> + <MkButton primary :class="$style.button" inline @click="importMuting($event)"><i class="fas fa-upload"></i> {{ i18n.ts.import }}</MkButton> </FormFolder> </FormSection> <FormSection> - <template #label>{{ $ts._exportOrImport.blockingList }}</template> + <template #label>{{ i18n.ts._exportOrImport.blockingList }}</template> <FormFolder class="_formBlock"> - <template #label>{{ $ts.export }}</template> + <template #label>{{ i18n.ts.export }}</template> <template #icon><i class="fas fa-download"></i></template> - <MkButton primary :class="$style.button" inline @click="exportBlocking()"><i class="fas fa-download"></i> {{ $ts.export }}</MkButton> + <MkButton primary :class="$style.button" inline @click="exportBlocking()"><i class="fas fa-download"></i> {{ i18n.ts.export }}</MkButton> </FormFolder> <FormFolder class="_formBlock"> - <template #label>{{ $ts.import }}</template> + <template #label>{{ i18n.ts.import }}</template> <template #icon><i class="fas fa-upload"></i></template> - <MkButton primary :class="$style.button" inline @click="importBlocking($event)"><i class="fas fa-upload"></i> {{ $ts.import }}</MkButton> + <MkButton primary :class="$style.button" inline @click="importBlocking($event)"><i class="fas fa-upload"></i> {{ i18n.ts.import }}</MkButton> </FormFolder> </FormSection> </div> diff --git a/packages/client/src/pages/settings/index.vue b/packages/client/src/pages/settings/index.vue index 8b1cc6c124..862435eb3f 100644 --- a/packages/client/src/pages/settings/index.vue +++ b/packages/client/src/pages/settings/index.vue @@ -4,15 +4,15 @@ <MkSpacer :content-max="900" :margin-min="20" :margin-max="32"> <div ref="el" class="vvcocwet" :class="{ wide: !narrow }"> <div class="body"> - <div v-if="!narrow || initialPage == null" class="nav"> + <div v-if="!narrow || currentPage?.route.name == null" class="nav"> <div class="baaadecd"> - <MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu> + <MkInfo v-if="emailNotConfigured" warn class="info">{{ i18n.ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ i18n.ts.configure }}</MkA></MkInfo> + <MkSuperMenu :def="menuDef" :grid="currentPage?.route.name == null"></MkSuperMenu> </div> </div> - <div v-if="!(narrow && initialPage == null)" class="main"> + <div v-if="!(narrow && currentPage?.route.name == null)" class="main"> <div class="bkzroven"> - <component :is="component" :key="initialPage" v-bind="pageProps"/> + <RouterView/> </div> </div> </div> @@ -22,7 +22,7 @@ </template> <script setup lang="ts"> -import { computed, defineAsyncComponent, inject, nextTick, onMounted, onUnmounted, provide, ref, watch } from 'vue'; +import { computed, defineAsyncComponent, inject, nextTick, onActivated, onMounted, onUnmounted, provide, ref, watch } from 'vue'; import { i18n } from '@/i18n'; import MkInfo from '@/components/ui/info.vue'; import MkSuperMenu from '@/components/ui/super-menu.vue'; @@ -34,11 +34,6 @@ import { useRouter } from '@/router'; import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import * as os from '@/os'; -const props = withDefaults(defineProps<{ - initialPage?: string; -}>(), { -}); - const indexInfo = { title: i18n.ts.settings, icon: 'fas fa-cog', @@ -50,12 +45,14 @@ const childInfo = ref(null); const router = useRouter(); -const narrow = ref(false); +let narrow = $ref(false); const NARROW_THRESHOLD = 600; +let currentPage = $computed(() => router.currentRef.value.child); + const ro = new ResizeObserver((entries, observer) => { if (entries.length === 0) return; - narrow.value = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD; + narrow = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD; }); const menuDef = computed(() => [{ @@ -64,42 +61,42 @@ const menuDef = computed(() => [{ icon: 'fas fa-user', text: i18n.ts.profile, to: '/settings/profile', - active: props.initialPage === 'profile', + active: currentPage?.route.name === 'profile', }, { icon: 'fas fa-lock-open', text: i18n.ts.privacy, to: '/settings/privacy', - active: props.initialPage === 'privacy', + active: currentPage?.route.name === 'privacy', }, { icon: 'fas fa-laugh', text: i18n.ts.reaction, to: '/settings/reaction', - active: props.initialPage === 'reaction', + active: currentPage?.route.name === 'reaction', }, { icon: 'fas fa-cloud', text: i18n.ts.drive, to: '/settings/drive', - active: props.initialPage === 'drive', + active: currentPage?.route.name === 'drive', }, { icon: 'fas fa-bell', text: i18n.ts.notifications, to: '/settings/notifications', - active: props.initialPage === 'notifications', + active: currentPage?.route.name === 'notifications', }, { icon: 'fas fa-envelope', text: i18n.ts.email, to: '/settings/email', - active: props.initialPage === 'email', + active: currentPage?.route.name === 'email', }, { icon: 'fas fa-share-alt', text: i18n.ts.integration, to: '/settings/integration', - active: props.initialPage === 'integration', + active: currentPage?.route.name === 'integration', }, { icon: 'fas fa-lock', text: i18n.ts.security, to: '/settings/security', - active: props.initialPage === 'security', + active: currentPage?.route.name === 'security', }], }, { title: i18n.ts.clientSettings, @@ -107,32 +104,32 @@ const menuDef = computed(() => [{ icon: 'fas fa-cogs', text: i18n.ts.general, to: '/settings/general', - active: props.initialPage === 'general', + active: currentPage?.route.name === 'general', }, { icon: 'fas fa-palette', text: i18n.ts.theme, to: '/settings/theme', - active: props.initialPage === 'theme', + active: currentPage?.route.name === 'theme', }, { icon: 'fas fa-bars', text: i18n.ts.navbar, to: '/settings/navbar', - active: props.initialPage === 'navbar', + active: currentPage?.route.name === 'navbar', }, { icon: 'fas fa-bars-progress', text: i18n.ts.statusbar, - to: '/settings/statusbars', - active: props.initialPage === 'statusbars', + to: '/settings/statusbar', + active: currentPage?.route.name === 'statusbar', }, { icon: 'fas fa-music', text: i18n.ts.sounds, to: '/settings/sounds', - active: props.initialPage === 'sounds', + active: currentPage?.route.name === 'sounds', }, { icon: 'fas fa-plug', text: i18n.ts.plugins, to: '/settings/plugin', - active: props.initialPage === 'plugin', + active: currentPage?.route.name === 'plugin', }], }, { title: i18n.ts.otherSettings, @@ -140,40 +137,45 @@ const menuDef = computed(() => [{ icon: 'fas fa-boxes', text: i18n.ts.importAndExport, to: '/settings/import-export', - active: props.initialPage === 'import-export', + active: currentPage?.route.name === 'import-export', }, { icon: 'fas fa-volume-mute', text: i18n.ts.instanceMute, to: '/settings/instance-mute', - active: props.initialPage === 'instance-mute', + active: currentPage?.route.name === 'instance-mute', }, { icon: 'fas fa-ban', text: i18n.ts.muteAndBlock, to: '/settings/mute-block', - active: props.initialPage === 'mute-block', + active: currentPage?.route.name === 'mute-block', }, { icon: 'fas fa-comment-slash', text: i18n.ts.wordMute, to: '/settings/word-mute', - active: props.initialPage === 'word-mute', + active: currentPage?.route.name === 'word-mute', }, { icon: 'fas fa-key', text: 'API', to: '/settings/api', - active: props.initialPage === 'api', + active: currentPage?.route.name === 'api', }, { icon: 'fas fa-bolt', text: 'Webhook', to: '/settings/webhook', - active: props.initialPage === 'webhook', + active: currentPage?.route.name === 'webhook', }, { icon: 'fas fa-ellipsis-h', text: i18n.ts.other, to: '/settings/other', - active: props.initialPage === 'other', + active: currentPage?.route.name === 'other', }], }, { items: [{ + icon: 'fas fa-floppy-disk', + text: i18n.ts.preferencesBackups, + to: '/settings/preferences-backups', + active: currentPage?.route.name === 'preferences-backups', + }, { type: 'button', icon: 'fas fa-trash', text: i18n.ts.clearCache, @@ -198,77 +200,24 @@ const menuDef = computed(() => [{ }], }]); -const pageProps = ref({}); -const component = computed(() => { - if (props.initialPage == null) return null; - switch (props.initialPage) { - case 'accounts': return defineAsyncComponent(() => import('./accounts.vue')); - case 'profile': return defineAsyncComponent(() => import('./profile.vue')); - case 'privacy': return defineAsyncComponent(() => import('./privacy.vue')); - case 'reaction': return defineAsyncComponent(() => import('./reaction.vue')); - case 'drive': return defineAsyncComponent(() => import('./drive.vue')); - case 'notifications': return defineAsyncComponent(() => import('./notifications.vue')); - case 'mute-block': return defineAsyncComponent(() => import('./mute-block.vue')); - case 'word-mute': return defineAsyncComponent(() => import('./word-mute.vue')); - case 'instance-mute': return defineAsyncComponent(() => import('./instance-mute.vue')); - case 'integration': return defineAsyncComponent(() => import('./integration.vue')); - case 'security': return defineAsyncComponent(() => import('./security.vue')); - case '2fa': return defineAsyncComponent(() => import('./2fa.vue')); - case 'api': return defineAsyncComponent(() => import('./api.vue')); - case 'webhook': return defineAsyncComponent(() => import('./webhook.vue')); - case 'webhook/new': return defineAsyncComponent(() => import('./webhook.new.vue')); - case 'webhook/edit': return defineAsyncComponent(() => import('./webhook.edit.vue')); - case 'apps': return defineAsyncComponent(() => import('./apps.vue')); - case 'other': return defineAsyncComponent(() => import('./other.vue')); - case 'general': return defineAsyncComponent(() => import('./general.vue')); - case 'email': return defineAsyncComponent(() => import('./email.vue')); - case 'theme': return defineAsyncComponent(() => import('./theme.vue')); - case 'theme/install': return defineAsyncComponent(() => import('./theme.install.vue')); - case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue')); - case 'navbar': return defineAsyncComponent(() => import('./navbar.vue')); - case 'statusbars': return defineAsyncComponent(() => import('./statusbars.vue')); - case 'sounds': return defineAsyncComponent(() => import('./sounds.vue')); - case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue')); - case 'deck': return defineAsyncComponent(() => import('./deck.vue')); - case 'plugin': return defineAsyncComponent(() => import('./plugin.vue')); - case 'plugin/install': return defineAsyncComponent(() => import('./plugin.install.vue')); - case 'import-export': return defineAsyncComponent(() => import('./import-export.vue')); - case 'account-info': return defineAsyncComponent(() => import('./account-info.vue')); - case 'delete-account': return defineAsyncComponent(() => import('./delete-account.vue')); - } - return null; +watch($$(narrow), () => { }); -watch(component, () => { - pageProps.value = {}; - - nextTick(() => { - scroll(el.value, { top: 0 }); - }); -}, { immediate: true }); +onMounted(() => { + ro.observe(el.value); -watch(() => props.initialPage, () => { - if (props.initialPage == null && !narrow.value) { - router.push('/settings/profile'); - } else { - if (props.initialPage == null) { - INFO.value = indexInfo; - } - } -}); + narrow = el.value.offsetWidth < NARROW_THRESHOLD; -watch(narrow, () => { - if (props.initialPage == null && !narrow.value) { - router.push('/settings/profile'); + if (!narrow && currentPage?.route.name == null) { + router.replace('/settings/profile'); } }); -onMounted(() => { - ro.observe(el.value); +onActivated(() => { + narrow = el.value.offsetWidth < NARROW_THRESHOLD; - narrow.value = el.value.offsetWidth < NARROW_THRESHOLD; - if (props.initialPage == null && !narrow.value) { - router.push('/settings/profile'); + if (!narrow && currentPage?.route.name == null) { + router.replace('/settings/profile'); } }); diff --git a/packages/client/src/pages/settings/mute-block.vue b/packages/client/src/pages/settings/mute-block.vue index 397a0c815c..495d52d4d3 100644 --- a/packages/client/src/pages/settings/mute-block.vue +++ b/packages/client/src/pages/settings/mute-block.vue @@ -1,12 +1,12 @@ <template> <div class="_formRoot"> <MkTab v-model="tab" style="margin-bottom: var(--margin);"> - <option value="mute">{{ $ts.mutedUsers }}</option> - <option value="block">{{ $ts.blockedUsers }}</option> + <option value="mute">{{ i18n.ts.mutedUsers }}</option> + <option value="block">{{ i18n.ts.blockedUsers }}</option> </MkTab> <div v-if="tab === 'mute'"> <MkPagination :pagination="mutingPagination" class="muting"> - <template #empty><FormInfo>{{ $ts.noUsers }}</FormInfo></template> + <template #empty><FormInfo>{{ i18n.ts.noUsers }}</FormInfo></template> <template #default="{items}"> <FormLink v-for="mute in items" :key="mute.id" :to="userPage(mute.mutee)"> <MkAcct :user="mute.mutee"/> @@ -16,7 +16,7 @@ </div> <div v-if="tab === 'block'"> <MkPagination :pagination="blockingPagination" class="blocking"> - <template #empty><FormInfo>{{ $ts.noUsers }}</FormInfo></template> + <template #empty><FormInfo>{{ i18n.ts.noUsers }}</FormInfo></template> <template #default="{items}"> <FormLink v-for="block in items" :key="block.id" :to="userPage(block.blockee)"> <MkAcct :user="block.blockee"/> diff --git a/packages/client/src/pages/settings/preferences-backups.vue b/packages/client/src/pages/settings/preferences-backups.vue new file mode 100644 index 0000000000..991bb7902d --- /dev/null +++ b/packages/client/src/pages/settings/preferences-backups.vue @@ -0,0 +1,444 @@ +<template> +<div class="_formRoot"> + <div :class="$style.buttons"> + <MkButton inline primary @click="saveNew">{{ ts._preferencesBackups.saveNew }}</MkButton> + <MkButton inline @click="loadFile">{{ ts._preferencesBackups.loadFile }}</MkButton> + </div> + + <FormSection> + <template #label>{{ ts._preferencesBackups.list }}</template> + <template v-if="profiles && Object.keys(profiles).length > 0"> + <div + v-for="(profile, id) in profiles" + :key="id" + class="_formBlock _panel" + :class="$style.profile" + @click="$event => menu($event, id)" + @contextmenu.prevent.stop="$event => menu($event, id)" + > + <div :class="$style.profileName">{{ profile.name }}</div> + <div :class="$style.profileTime">{{ t('_preferencesBackups.createdAt', { date: (new Date(profile.createdAt)).toLocaleDateString(), time: (new Date(profile.createdAt)).toLocaleTimeString() }) }}</div> + <div v-if="profile.updatedAt" :class="$style.profileTime">{{ t('_preferencesBackups.updatedAt', { date: (new Date(profile.updatedAt)).toLocaleDateString(), time: (new Date(profile.updatedAt)).toLocaleTimeString() }) }}</div> + </div> + </template> + <div v-else-if="profiles"> + <MkInfo>{{ ts._preferencesBackups.noBackups }}</MkInfo> + </div> + <MkLoading v-else/> + </FormSection> +</div> +</template> + +<script lang="ts" setup> +import { computed, onMounted, onUnmounted, useCssModule } from 'vue'; +import { v4 as uuid } from 'uuid'; +import FormSection from '@/components/form/section.vue'; +import MkButton from '@/components/ui/button.vue'; +import MkInfo from '@/components/ui/info.vue'; +import * as os from '@/os'; +import { ColdDeviceStorage, defaultStore } from '@/store'; +import { unisonReload } from '@/scripts/unison-reload'; +import { stream } from '@/stream'; +import { $i } from '@/account'; +import { i18n } from '@/i18n'; +import { version, host } from '@/config'; +import { definePageMetadata } from '@/scripts/page-metadata'; +const { t, ts } = i18n; + +useCssModule(); + +const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ + 'menu', + 'visibility', + 'localOnly', + 'statusbars', + 'widgets', + 'tl', + 'overridedDeviceKind', + 'serverDisconnectedBehavior', + 'nsfw', + 'animation', + 'animatedMfm', + 'loadRawImages', + 'imageNewTab', + 'disableShowingAnimatedImages', + 'disablePagesScript', + 'useOsNativeEmojis', + 'disableDrawer', + 'useBlurEffectForModal', + 'useBlurEffect', + 'showFixedPostForm', + 'enableInfiniteScroll', + 'useReactionPickerForContextMenu', + 'showGapBetweenNotesInTimeline', + 'instanceTicker', + 'reactionPickerSize', + 'reactionPickerWidth', + 'reactionPickerHeight', + 'reactionPickerUseDrawerForMobile', + 'defaultSideView', + 'menuDisplay', + 'reportError', + 'squareAvatars', + 'numberOfPageCache', + 'aiChanMode', +]; +const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [ + 'lightTheme', + 'darkTheme', + 'syncDeviceDarkMode', + 'plugins', + 'mediaVolume', + 'sound_masterVolume', + 'sound_note', + 'sound_noteMy', + 'sound_notification', + 'sound_chat', + 'sound_chatBg', + 'sound_antenna', + 'sound_channel', +]; + +const scope = ['clientPreferencesProfiles']; + +const profileProps = ['name', 'createdAt', 'updatedAt', 'misskeyVersion', 'settings']; + +type Profile = { + name: string; + createdAt: string; + updatedAt: string | null; + misskeyVersion: string; + host: string; + settings: { + hot: Record<keyof typeof defaultStoreSaveKeys, unknown>; + cold: Record<keyof typeof coldDeviceStorageSaveKeys, unknown>; + fontSize: string | null; + useSystemFont: 't' | null; + wallpaper: string | null; + }; +}; + +const connection = $i && stream.useChannel('main'); + +let profiles = $ref<Record<string, Profile> | null>(null); + +os.api('i/registry/get-all', { scope }) + .then(res => { + profiles = res || {}; + }); + +function isObject(value: unknown): value is Record<string, unknown> { + return value != null && typeof value === 'object' && !Array.isArray(value); +} + +function validate(profile: unknown): void { + if (!isObject(profile)) throw new Error('not an object'); + + // Check if unnecessary properties exist + if (Object.keys(profile).some(key => !profileProps.includes(key))) throw new Error('Unnecessary properties exist'); + + if (!profile.name) throw new Error('Missing required prop: name'); + if (!profile.misskeyVersion) throw new Error('Missing required prop: misskeyVersion'); + + // Check if createdAt and updatedAt is Date + // https://zenn.dev/lollipop_onl/articles/eoz-judge-js-invalid-date + if (!profile.createdAt || Number.isNaN(new Date(profile.createdAt).getTime())) throw new Error('createdAt is falsy or not Date'); + if (profile.updatedAt) { + if (Number.isNaN(new Date(profile.updatedAt).getTime())) { + throw new Error('updatedAt is not Date'); + } + } else if (profile.updatedAt !== null) { + throw new Error('updatedAt is not null'); + } + + if (!profile.settings) throw new Error('Missing required prop: settings'); + if (!isObject(profile.settings)) throw new Error('Invalid prop: settings'); +} + +function getSettings(): Profile['settings'] { + const hot = {} as Record<keyof typeof defaultStoreSaveKeys, unknown>; + for (const key of defaultStoreSaveKeys) { + hot[key] = defaultStore.state[key]; + } + + const cold = {} as Record<keyof typeof coldDeviceStorageSaveKeys, unknown>; + for (const key of coldDeviceStorageSaveKeys) { + cold[key] = ColdDeviceStorage.get(key); + } + + return { + hot, + cold, + fontSize: localStorage.getItem('fontSize'), + useSystemFont: localStorage.getItem('useSystemFont') as 't' | null, + wallpaper: localStorage.getItem('wallpaper'), + }; +} + +async function saveNew(): Promise<void> { + if (!profiles) return; + + const { canceled, result: name } = await os.inputText({ + title: ts._preferencesBackups.inputName, + }); + if (canceled) return; + + if (Object.values(profiles).some(x => x.name === name)) { + return os.alert({ + title: ts._preferencesBackups.cannotSave, + text: t('_preferencesBackups.nameAlreadyExists', { name }), + }); + } + + const id = uuid(); + const profile: Profile = { + name, + createdAt: (new Date()).toISOString(), + updatedAt: null, + misskeyVersion: version, + host, + settings: getSettings(), + }; + await os.apiWithDialog('i/registry/set', { scope, key: id, value: profile }); +} + +function loadFile(): void { + const input = document.createElement('input'); + input.type = 'file'; + input.multiple = false; + input.onchange = async () => { + if (!profiles) return; + if (!input.files || input.files.length === 0) return; + + const file = input.files[0]; + + if (file.type !== 'application/json') { + return os.alert({ + type: 'error', + title: ts._preferencesBackups.cannotLoad, + text: ts._preferencesBackups.invalidFile, + }); + } + + let profile: Profile; + try { + profile = JSON.parse(await file.text()) as unknown as Profile; + validate(profile); + } catch (err) { + return os.alert({ + type: 'error', + title: ts._preferencesBackups.cannotLoad, + text: err?.message, + }); + } + + const id = uuid(); + await os.apiWithDialog('i/registry/set', { scope, key: id, value: profile }); + + // 一応廃棄 + (window as any).__misskey_input_ref__ = null; + }; + + // https://qiita.com/fukasawah/items/b9dc732d95d99551013d + // iOS Safari ã§æ£å¸¸ã«å‹•ã‹ã™ç‚ºã®ãŠã¾ã˜ãªã„ + (window as any).__misskey_input_ref__ = input; + + input.click(); +} + +async function applyProfile(id: string): Promise<void> { + if (!profiles) return; + + const profile = profiles[id]; + + const { canceled: cancel1 } = await os.confirm({ + type: 'warning', + title: ts._preferencesBackups.apply, + text: t('_preferencesBackups.applyConfirm', { name: profile.name }), + }); + if (cancel1) return; + + // TODO: ãƒãƒ¼ã‚¸ãƒ§ãƒ³ or ホストãŒé•ã£ãŸã‚‰ã•らã«è¦å‘Šã‚’表示 + + const settings = profile.settings; + + // defaultStore + for (const key of defaultStoreSaveKeys) { + if (settings.hot[key] !== undefined) { + defaultStore.set(key, settings.hot[key]); + } + } + + // coldDeviceStorage + for (const key of coldDeviceStorageSaveKeys) { + if (settings.cold[key] !== undefined) { + ColdDeviceStorage.set(key, settings.cold[key]); + } + } + + // fontSize + if (settings.fontSize) { + localStorage.setItem('fontSize', settings.fontSize); + } else { + localStorage.removeItem('fontSize'); + } + + // useSystemFont + if (settings.useSystemFont) { + localStorage.setItem('useSystemFont', settings.useSystemFont); + } else { + localStorage.removeItem('useSystemFont'); + } + + // wallpaper + if (settings.wallpaper != null) { + localStorage.setItem('wallpaper', settings.wallpaper); + } else { + localStorage.removeItem('wallpaper'); + } + + const { canceled: cancel2 } = await os.confirm({ + type: 'info', + text: ts.reloadToApplySetting, + }); + if (cancel2) return; + + unisonReload(); +} + +async function deleteProfile(id: string): Promise<void> { + if (!profiles) return; + + const { canceled } = await os.confirm({ + type: 'info', + title: ts.delete, + text: t('deleteAreYouSure', { x: profiles[id].name }), + }); + if (canceled) return; + + await os.apiWithDialog('i/registry/remove', { scope, key: id }); + delete profiles[id]; +} + +async function save(id: string): Promise<void> { + if (!profiles) return; + + const { name, createdAt } = profiles[id]; + + const { canceled } = await os.confirm({ + type: 'info', + title: ts._preferencesBackups.save, + text: t('_preferencesBackups.saveConfirm', { name }), + }); + if (canceled) return; + + const profile: Profile = { + name, + createdAt, + updatedAt: (new Date()).toISOString(), + misskeyVersion: version, + host, + settings: getSettings(), + }; + await os.apiWithDialog('i/registry/set', { scope, key: id, value: profile }); +} + +async function rename(id: string): Promise<void> { + if (!profiles) return; + + const { canceled: cancel1, result: name } = await os.inputText({ + title: ts._preferencesBackups.inputName, + }); + if (cancel1 || profiles[id].name === name) return; + + if (Object.values(profiles).some(x => x.name === name)) { + return os.alert({ + title: ts._preferencesBackups.cannotSave, + text: t('_preferencesBackups.nameAlreadyExists', { name }), + }); + } + + const registry = Object.assign({}, { ...profiles[id] }); + + const { canceled: cancel2 } = await os.confirm({ + type: 'info', + title: ts._preferencesBackups.rename, + text: t('_preferencesBackups.renameConfirm', { old: registry.name, new: name }), + }); + if (cancel2) return; + + registry.name = name; + await os.apiWithDialog('i/registry/set', { scope, key: id, value: registry }); +} + +function menu(ev: MouseEvent, profileId: string) { + if (!profiles) return; + + return os.popupMenu([{ + text: ts._preferencesBackups.apply, + icon: 'fas fa-circle-down', + action: () => applyProfile(profileId), + }, { + type: 'a', + text: ts.download, + icon: 'fas fa-download', + href: URL.createObjectURL(new Blob([JSON.stringify(profiles[profileId], null, 2)], { type: 'application/json' })), + download: `${profiles[profileId].name}.json`, + }, null, { + text: ts.rename, + icon: 'fas fa-i-cursor', + action: () => rename(profileId), + }, { + text: ts._preferencesBackups.save, + icon: 'fas fa-floppy-disk', + action: () => save(profileId), + }, null, { + text: ts._preferencesBackups.delete, + icon: 'fas fa-trash-can', + action: () => deleteProfile(profileId), + danger: true, + }], ev.currentTarget ?? ev.target); +} + +onMounted(() => { + // streamingã®user storage updateイベントを監視ã—ã¦æ›´æ–° + connection?.on('registryUpdated', ({ scope: recievedScope, key, value }) => { + if (!recievedScope || recievedScope.length !== scope.length || recievedScope[0] !== scope[0]) return; + if (!profiles) return; + + profiles[key] = value; + }); +}); + +onUnmounted(() => { + connection?.off('registryUpdated'); +}); + +definePageMetadata(computed(() => ({ + title: ts.preferencesBackups, + icon: 'fas fa-floppy-disk', + bg: 'var(--bg)', +}))); +</script> + +<style lang="scss" module> +.buttons { + display: flex; + gap: var(--margin); + flex-wrap: wrap; +} + +.profile { + padding: 20px; + cursor: pointer; + + &Name { + font-weight: 700; + } + + &Time { + font-size: .85em; + opacity: .7; + } +} +</style> diff --git a/packages/client/src/pages/settings/privacy.vue b/packages/client/src/pages/settings/privacy.vue index be9e34cdfb..45a0358a92 100644 --- a/packages/client/src/pages/settings/privacy.vue +++ b/packages/client/src/pages/settings/privacy.vue @@ -1,54 +1,54 @@ <template> <div class="_formRoot"> - <FormSwitch v-model="isLocked" class="_formBlock" @update:modelValue="save()">{{ $ts.makeFollowManuallyApprove }}<template #caption>{{ $ts.lockedAccountInfo }}</template></FormSwitch> - <FormSwitch v-if="isLocked" v-model="autoAcceptFollowed" class="_formBlock" @update:modelValue="save()">{{ $ts.autoAcceptFollowed }}</FormSwitch> + <FormSwitch v-model="isLocked" class="_formBlock" @update:modelValue="save()">{{ i18n.ts.makeFollowManuallyApprove }}<template #caption>{{ i18n.ts.lockedAccountInfo }}</template></FormSwitch> + <FormSwitch v-if="isLocked" v-model="autoAcceptFollowed" class="_formBlock" @update:modelValue="save()">{{ i18n.ts.autoAcceptFollowed }}</FormSwitch> <FormSwitch v-model="publicReactions" class="_formBlock" @update:modelValue="save()"> - {{ $ts.makeReactionsPublic }} - <template #caption>{{ $ts.makeReactionsPublicDescription }}</template> + {{ i18n.ts.makeReactionsPublic }} + <template #caption>{{ i18n.ts.makeReactionsPublicDescription }}</template> </FormSwitch> <FormSelect v-model="ffVisibility" class="_formBlock" @update:modelValue="save()"> - <template #label>{{ $ts.ffVisibility }}</template> - <option value="public">{{ $ts._ffVisibility.public }}</option> - <option value="followers">{{ $ts._ffVisibility.followers }}</option> - <option value="private">{{ $ts._ffVisibility.private }}</option> - <template #caption>{{ $ts.ffVisibilityDescription }}</template> + <template #label>{{ i18n.ts.ffVisibility }}</template> + <option value="public">{{ i18n.ts._ffVisibility.public }}</option> + <option value="followers">{{ i18n.ts._ffVisibility.followers }}</option> + <option value="private">{{ i18n.ts._ffVisibility.private }}</option> + <template #caption>{{ i18n.ts.ffVisibilityDescription }}</template> </FormSelect> <FormSwitch v-model="hideOnlineStatus" class="_formBlock" @update:modelValue="save()"> - {{ $ts.hideOnlineStatus }} - <template #caption>{{ $ts.hideOnlineStatusDescription }}</template> + {{ i18n.ts.hideOnlineStatus }} + <template #caption>{{ i18n.ts.hideOnlineStatusDescription }}</template> </FormSwitch> <FormSwitch v-model="noCrawle" class="_formBlock" @update:modelValue="save()"> - {{ $ts.noCrawle }} - <template #caption>{{ $ts.noCrawleDescription }}</template> + {{ i18n.ts.noCrawle }} + <template #caption>{{ i18n.ts.noCrawleDescription }}</template> </FormSwitch> <FormSwitch v-model="isExplorable" class="_formBlock" @update:modelValue="save()"> - {{ $ts.makeExplorable }} - <template #caption>{{ $ts.makeExplorableDescription }}</template> + {{ i18n.ts.makeExplorable }} + <template #caption>{{ i18n.ts.makeExplorableDescription }}</template> </FormSwitch> <FormSection> - <FormSwitch v-model="rememberNoteVisibility" class="_formBlock" @update:modelValue="save()">{{ $ts.rememberNoteVisibility }}</FormSwitch> + <FormSwitch v-model="rememberNoteVisibility" class="_formBlock" @update:modelValue="save()">{{ i18n.ts.rememberNoteVisibility }}</FormSwitch> <FormFolder v-if="!rememberNoteVisibility" class="_formBlock"> - <template #label>{{ $ts.defaultNoteVisibility }}</template> - <template v-if="defaultNoteVisibility === 'public'" #suffix>{{ $ts._visibility.public }}</template> - <template v-else-if="defaultNoteVisibility === 'home'" #suffix>{{ $ts._visibility.home }}</template> - <template v-else-if="defaultNoteVisibility === 'followers'" #suffix>{{ $ts._visibility.followers }}</template> - <template v-else-if="defaultNoteVisibility === 'specified'" #suffix>{{ $ts._visibility.specified }}</template> + <template #label>{{ i18n.ts.defaultNoteVisibility }}</template> + <template v-if="defaultNoteVisibility === 'public'" #suffix>{{ i18n.ts._visibility.public }}</template> + <template v-else-if="defaultNoteVisibility === 'home'" #suffix>{{ i18n.ts._visibility.home }}</template> + <template v-else-if="defaultNoteVisibility === 'followers'" #suffix>{{ i18n.ts._visibility.followers }}</template> + <template v-else-if="defaultNoteVisibility === 'specified'" #suffix>{{ i18n.ts._visibility.specified }}</template> <FormSelect v-model="defaultNoteVisibility" class="_formBlock"> - <option value="public">{{ $ts._visibility.public }}</option> - <option value="home">{{ $ts._visibility.home }}</option> - <option value="followers">{{ $ts._visibility.followers }}</option> - <option value="specified">{{ $ts._visibility.specified }}</option> + <option value="public">{{ i18n.ts._visibility.public }}</option> + <option value="home">{{ i18n.ts._visibility.home }}</option> + <option value="followers">{{ i18n.ts._visibility.followers }}</option> + <option value="specified">{{ i18n.ts._visibility.specified }}</option> </FormSelect> - <FormSwitch v-model="defaultNoteLocalOnly" class="_formBlock">{{ $ts._visibility.localOnly }}</FormSwitch> + <FormSwitch v-model="defaultNoteLocalOnly" class="_formBlock">{{ i18n.ts._visibility.localOnly }}</FormSwitch> </FormFolder> </FormSection> - <FormSwitch v-model="keepCw" class="_formBlock" @update:modelValue="save()">{{ $ts.keepCw }}</FormSwitch> + <FormSwitch v-model="keepCw" class="_formBlock" @update:modelValue="save()">{{ i18n.ts.keepCw }}</FormSwitch> </div> </template> diff --git a/packages/client/src/pages/settings/reaction.vue b/packages/client/src/pages/settings/reaction.vue index 382e1b081e..170124eacd 100644 --- a/packages/client/src/pages/settings/reaction.vue +++ b/packages/client/src/pages/settings/reaction.vue @@ -1,7 +1,7 @@ <template> <div class="_formRoot"> <FromSlot class="_formBlock"> - <template #label>{{ $ts.reactionSettingDescription }}</template> + <template #label>{{ i18n.ts.reactionSettingDescription }}</template> <div v-panel style="border-radius: 6px;"> <XDraggable v-model="reactions" class="zoaiodol" :item-key="item => item" animation="150" delay="100" delay-on-touch-only="true"> <template #item="{element}"> @@ -14,17 +14,17 @@ </template> </XDraggable> </div> - <template #caption>{{ $ts.reactionSettingDescription2 }} <button class="_textButton" @click="preview">{{ $ts.preview }}</button></template> + <template #caption>{{ i18n.ts.reactionSettingDescription2 }} <button class="_textButton" @click="preview">{{ i18n.ts.preview }}</button></template> </FromSlot> <FormRadios v-model="reactionPickerSize" class="_formBlock"> - <template #label>{{ $ts.size }}</template> - <option :value="1">{{ $ts.small }}</option> - <option :value="2">{{ $ts.medium }}</option> - <option :value="3">{{ $ts.large }}</option> + <template #label>{{ i18n.ts.size }}</template> + <option :value="1">{{ i18n.ts.small }}</option> + <option :value="2">{{ i18n.ts.medium }}</option> + <option :value="3">{{ i18n.ts.large }}</option> </FormRadios> <FormRadios v-model="reactionPickerWidth" class="_formBlock"> - <template #label>{{ $ts.numberOfColumn }}</template> + <template #label>{{ i18n.ts.numberOfColumn }}</template> <option :value="1">5</option> <option :value="2">6</option> <option :value="3">7</option> @@ -32,22 +32,22 @@ <option :value="5">9</option> </FormRadios> <FormRadios v-model="reactionPickerHeight" class="_formBlock"> - <template #label>{{ $ts.height }}</template> - <option :value="1">{{ $ts.small }}</option> - <option :value="2">{{ $ts.medium }}</option> - <option :value="3">{{ $ts.large }}</option> - <option :value="4">{{ $ts.large }}+</option> + <template #label>{{ i18n.ts.height }}</template> + <option :value="1">{{ i18n.ts.small }}</option> + <option :value="2">{{ i18n.ts.medium }}</option> + <option :value="3">{{ i18n.ts.large }}</option> + <option :value="4">{{ i18n.ts.large }}+</option> </FormRadios> <FormSwitch v-model="reactionPickerUseDrawerForMobile" class="_formBlock"> - {{ $ts.useDrawerReactionPickerForMobile }} - <template #caption>{{ $ts.needReloadToApply }}</template> + {{ i18n.ts.useDrawerReactionPickerForMobile }} + <template #caption>{{ i18n.ts.needReloadToApply }}</template> </FormSwitch> <FormSection> <div style="display: flex; gap: var(--margin); flex-wrap: wrap;"> - <FormButton inline @click="preview"><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton> - <FormButton inline danger @click="setDefault"><i class="fas fa-undo"></i> {{ $ts.default }}</FormButton> + <FormButton inline @click="preview"><i class="fas fa-eye"></i> {{ i18n.ts.preview }}</FormButton> + <FormButton inline danger @click="setDefault"><i class="fas fa-undo"></i> {{ i18n.ts.default }}</FormButton> </div> </FormSection> </div> diff --git a/packages/client/src/pages/settings/statusbars.statusbar.vue b/packages/client/src/pages/settings/statusbar.statusbar.vue index 2f0c6fc1ee..2f0c6fc1ee 100644 --- a/packages/client/src/pages/settings/statusbars.statusbar.vue +++ b/packages/client/src/pages/settings/statusbar.statusbar.vue diff --git a/packages/client/src/pages/settings/statusbars.vue b/packages/client/src/pages/settings/statusbar.vue index c81bd7fbdf..3f23ed470c 100644 --- a/packages/client/src/pages/settings/statusbars.vue +++ b/packages/client/src/pages/settings/statusbar.vue @@ -12,7 +12,7 @@ <script lang="ts" setup> import { computed, onMounted, ref, watch } from 'vue'; import { v4 as uuid } from 'uuid'; -import XStatusbar from './statusbars.statusbar.vue'; +import XStatusbar from './statusbar.statusbar.vue'; import FormRadios from '@/components/form/radios.vue'; import FormFolder from '@/components/form/folder.vue'; import FormButton from '@/components/ui/button.vue'; diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue index 667155019b..cc869699a6 100644 --- a/packages/client/src/pages/settings/theme.vue +++ b/packages/client/src/pages/settings/theme.vue @@ -5,8 +5,8 @@ <div class="toggleWrapper"> <input id="dn" v-model="darkMode" type="checkbox" class="dn"/> <label for="dn" class="toggle"> - <span class="before">{{ $ts.light }}</span> - <span class="after">{{ $ts.dark }}</span> + <span class="before">{{ i18n.ts.light }}</span> + <span class="after">{{ i18n.ts.dark }}</span> <span class="toggle__handler"> <span class="crater crater--1"></span> <span class="crater crater--2"></span> @@ -22,44 +22,46 @@ </div> </div> <div class="sync"> - <FormSwitch v-model="syncDeviceDarkMode">{{ $ts.syncDeviceDarkMode }}</FormSwitch> + <FormSwitch v-model="syncDeviceDarkMode">{{ i18n.ts.syncDeviceDarkMode }}</FormSwitch> </div> </div> <div class="selects _formBlock"> <FormSelect v-model="lightThemeId" large class="select"> - <template #label>{{ $ts.themeForLightMode }}</template> + <template #label>{{ i18n.ts.themeForLightMode }}</template> <template #prefix><i class="fas fa-sun"></i></template> - <optgroup :label="$ts.lightThemes"> - <option v-for="x in lightThemes" :key="x.id" :value="x.id">{{ x.name }}</option> + <option v-if="instanceLightTheme" :key="'instance:' + instanceLightTheme.id" :value="instanceLightTheme.id">{{ instanceLightTheme.name }}</option> + <optgroup v-if="installedLightThemes.length > 0" :label="i18n.ts._theme.installedThemes"> + <option v-for="x in installedLightThemes" :key="'installed:' + x.id" :value="x.id">{{ x.name }}</option> </optgroup> - <optgroup :label="$ts.darkThemes"> - <option v-for="x in darkThemes" :key="x.id" :value="x.id">{{ x.name }}</option> + <optgroup :label="i18n.ts._theme.builtinThemes"> + <option v-for="x in builtinLightThemes" :key="'builtin:' + x.id" :value="x.id">{{ x.name }}</option> </optgroup> </FormSelect> <FormSelect v-model="darkThemeId" large class="select"> - <template #label>{{ $ts.themeForDarkMode }}</template> + <template #label>{{ i18n.ts.themeForDarkMode }}</template> <template #prefix><i class="fas fa-moon"></i></template> - <optgroup :label="$ts.darkThemes"> - <option v-for="x in darkThemes" :key="x.id" :value="x.id">{{ x.name }}</option> + <option v-if="instanceDarkTheme" :key="'instance:' + instanceDarkTheme.id" :value="instanceDarkTheme.id">{{ instanceDarkTheme.name }}</option> + <optgroup v-if="installedDarkThemes.length > 0" :label="i18n.ts._theme.installedThemes"> + <option v-for="x in installedDarkThemes" :key="'installed:' + x.id" :value="x.id">{{ x.name }}</option> </optgroup> - <optgroup :label="$ts.lightThemes"> - <option v-for="x in lightThemes" :key="x.id" :value="x.id">{{ x.name }}</option> + <optgroup :label="i18n.ts._theme.builtinThemes"> + <option v-for="x in builtinDarkThemes" :key="'builtin:' + x.id" :value="x.id">{{ x.name }}</option> </optgroup> </FormSelect> </div> <FormSection> <div class="_formLinksGrid"> - <FormLink to="/settings/theme/manage"><template #icon><i class="fas fa-folder-open"></i></template>{{ $ts._theme.manage }}<template #suffix>{{ themesCount }}</template></FormLink> - <FormLink to="https://assets.misskey.io/theme/list" external><template #icon><i class="fas fa-globe"></i></template>{{ $ts._theme.explore }}</FormLink> - <FormLink to="/settings/theme/install"><template #icon><i class="fas fa-download"></i></template>{{ $ts._theme.install }}</FormLink> - <FormLink to="/theme-editor"><template #icon><i class="fas fa-paint-roller"></i></template>{{ $ts._theme.make }}</FormLink> + <FormLink to="/settings/theme/manage"><template #icon><i class="fas fa-folder-open"></i></template>{{ i18n.ts._theme.manage }}<template #suffix>{{ themesCount }}</template></FormLink> + <FormLink to="https://assets.misskey.io/theme/list" external><template #icon><i class="fas fa-globe"></i></template>{{ i18n.ts._theme.explore }}</FormLink> + <FormLink to="/settings/theme/install"><template #icon><i class="fas fa-download"></i></template>{{ i18n.ts._theme.install }}</FormLink> + <FormLink to="/theme-editor"><template #icon><i class="fas fa-paint-roller"></i></template>{{ i18n.ts._theme.make }}</FormLink> </div> </FormSection> - <FormButton v-if="wallpaper == null" class="_formBlock" @click="setWallpaper">{{ $ts.setWallpaper }}</FormButton> - <FormButton v-else class="_formBlock" @click="wallpaper = null">{{ $ts.removeWallpaper }}</FormButton> + <FormButton v-if="wallpaper == null" class="_formBlock" @click="setWallpaper">{{ i18n.ts.setWallpaper }}</FormButton> + <FormButton v-else class="_formBlock" @click="wallpaper = null">{{ i18n.ts.removeWallpaper }}</FormButton> </div> </template> @@ -83,14 +85,15 @@ import { definePageMetadata } from '@/scripts/page-metadata'; const installedThemes = ref(getThemes()); const builtinThemes = getBuiltinThemesRef(); -const instanceThemes = []; -if (instance.defaultLightTheme != null) instanceThemes.push(JSON5.parse(instance.defaultLightTheme)); -if (instance.defaultDarkTheme != null) instanceThemes.push(JSON5.parse(instance.defaultDarkTheme)); +const instanceDarkTheme = computed(() => instance.defaultDarkTheme ? JSON5.parse(instance.defaultDarkTheme) : null); +const installedDarkThemes = computed(() => installedThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); +const builtinDarkThemes = computed(() => builtinThemes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); +const instanceLightTheme = computed(() => instance.defaultLightTheme ? JSON5.parse(instance.defaultLightTheme) : null); +const installedLightThemes = computed(() => installedThemes.value.filter(t => t.base === 'light' || t.kind === 'light')); +const builtinLightThemes = computed(() => builtinThemes.value.filter(t => t.base === 'light' || t.kind === 'light')); +const themes = computed(() => uniqueBy([ instanceDarkTheme.value, instanceLightTheme.value, ...builtinThemes.value, ...installedThemes.value ].filter(x => x != null), theme => theme.id)); -const themes = computed(() => uniqueBy([ ...instanceThemes, ...builtinThemes.value, ...installedThemes.value ], theme => theme.id)); -const darkThemes = computed(() => themes.value.filter(t => t.base === 'dark' || t.kind === 'dark')); -const lightThemes = computed(() => themes.value.filter(t => t.base === 'light' || t.kind === 'light')); const darkTheme = ColdDeviceStorage.ref('darkTheme'); const darkThemeId = computed({ get() { @@ -183,6 +186,7 @@ definePageMetadata({ text-align: left; overflow: clip; padding: 0 100px; + vertical-align: bottom; input { position: absolute; diff --git a/packages/client/src/pages/settings/webhook.edit.vue b/packages/client/src/pages/settings/webhook.edit.vue index 618250958b..e36e1d7540 100644 --- a/packages/client/src/pages/settings/webhook.edit.vue +++ b/packages/client/src/pages/settings/webhook.edit.vue @@ -43,8 +43,12 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +const props = defineProps<{ + webhookId: string; +}>(); + const webhook = await os.api('i/webhooks/show', { - webhookId: new URLSearchParams(window.location.search).get('id'), + webhookId: props.webhookId, }); let name = $ref(webhook.name); diff --git a/packages/client/src/pages/settings/webhook.vue b/packages/client/src/pages/settings/webhook.vue index ef9b9b56f7..868d273ce4 100644 --- a/packages/client/src/pages/settings/webhook.vue +++ b/packages/client/src/pages/settings/webhook.vue @@ -9,7 +9,7 @@ <FormSection> <MkPagination :pagination="pagination"> <template #default="{items}"> - <FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit?id=${webhook.id}`" class="_formBlock"> + <FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit/${webhook.id}`" class="_formBlock"> <template #icon> <i v-if="webhook.active === false" class="fas fa-circle-pause"></i> <i v-else-if="webhook.latestStatus === null" class="far fa-circle"></i> diff --git a/packages/client/src/pages/share.vue b/packages/client/src/pages/share.vue index 8984823b60..f4b6f66fa6 100644 --- a/packages/client/src/pages/share.vue +++ b/packages/client/src/pages/share.vue @@ -1,31 +1,30 @@ <template> -<div class=""> - <section class="_section"> - <div class="_content"> - <XPostForm - v-if="state === 'writing'" - fixed - :instant="true" - :initial-text="initialText" - :initial-visibility="visibility" - :initial-files="files" - :initial-local-only="localOnly" - :reply="reply" - :renote="renote" - :initial-visible-users="visibleUsers" - class="_panel" - @posted="state = 'posted'" - /> - <MkButton v-else-if="state === 'posted'" primary class="close" @click="close()">{{ $ts.close }}</MkButton> - </div> - </section> -</div> +<MkStickyContainer> + <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> + <MkSpacer :content-max="800"> + <XPostForm + v-if="state === 'writing'" + fixed + :instant="true" + :initial-text="initialText" + :initial-visibility="visibility" + :initial-files="files" + :initial-local-only="localOnly" + :reply="reply" + :renote="renote" + :initial-visible-users="visibleUsers" + class="_panel" + @posted="state = 'posted'" + /> + <MkButton v-else-if="state === 'posted'" primary class="close" @click="close()">{{ i18n.ts.close }}</MkButton> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> // SPECIFICATION: https://misskey-hub.net/docs/features/share-form.html -import { defineComponent } from 'vue'; +import { } from 'vue'; import { noteVisibilities } from 'misskey-js'; import * as Acct from 'misskey-js/built/acct'; import * as Misskey from 'misskey-js'; diff --git a/packages/client/src/pages/tag.vue b/packages/client/src/pages/tag.vue index 406eb1c988..950d26a72e 100644 --- a/packages/client/src/pages/tag.vue +++ b/packages/client/src/pages/tag.vue @@ -1,7 +1,10 @@ <template> -<div class="_section"> - <XNotes class="_content" :pagination="pagination"/> -</div> +<MkStickyContainer> + <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> + <MkSpacer :content-max="800"> + <XNotes class="_content" :pagination="pagination"/> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> diff --git a/packages/client/src/pages/timeline.tutorial.vue b/packages/client/src/pages/timeline.tutorial.vue index 432d28c60b..f69bf58100 100644 --- a/packages/client/src/pages/timeline.tutorial.vue +++ b/packages/client/src/pages/timeline.tutorial.vue @@ -1,52 +1,52 @@ <template> <div class="_card tbkwesmv"> - <div class="_title"><i class="fas fa-info-circle"></i> {{ $ts._tutorial.title }}</div> + <div class="_title"><i class="fas fa-info-circle"></i> {{ i18n.ts._tutorial.title }}</div> <div v-if="tutorial === 0" class="_content"> - <div>{{ $ts._tutorial.step1_1 }}</div> - <div>{{ $ts._tutorial.step1_2 }}</div> - <div>{{ $ts._tutorial.step1_3 }}</div> + <div>{{ i18n.ts._tutorial.step1_1 }}</div> + <div>{{ i18n.ts._tutorial.step1_2 }}</div> + <div>{{ i18n.ts._tutorial.step1_3 }}</div> </div> <div v-else-if="tutorial === 1" class="_content"> - <div>{{ $ts._tutorial.step2_1 }}</div> - <div>{{ $ts._tutorial.step2_2 }}</div> - <MkA class="_link" to="/settings/profile">{{ $ts.editProfile }}</MkA> + <div>{{ i18n.ts._tutorial.step2_1 }}</div> + <div>{{ i18n.ts._tutorial.step2_2 }}</div> + <MkA class="_link" to="/settings/profile">{{ i18n.ts.editProfile }}</MkA> </div> <div v-else-if="tutorial === 2" class="_content"> - <div>{{ $ts._tutorial.step3_1 }}</div> - <div>{{ $ts._tutorial.step3_2 }}</div> - <div>{{ $ts._tutorial.step3_3 }}</div> - <small>{{ $ts._tutorial.step3_4 }}</small> + <div>{{ i18n.ts._tutorial.step3_1 }}</div> + <div>{{ i18n.ts._tutorial.step3_2 }}</div> + <div>{{ i18n.ts._tutorial.step3_3 }}</div> + <small>{{ i18n.ts._tutorial.step3_4 }}</small> </div> <div v-else-if="tutorial === 3" class="_content"> - <div>{{ $ts._tutorial.step4_1 }}</div> - <div>{{ $ts._tutorial.step4_2 }}</div> + <div>{{ i18n.ts._tutorial.step4_1 }}</div> + <div>{{ i18n.ts._tutorial.step4_2 }}</div> </div> <div v-else-if="tutorial === 4" class="_content"> - <div>{{ $ts._tutorial.step5_1 }}</div> - <I18n :src="$ts._tutorial.step5_2" tag="div"> + <div>{{ i18n.ts._tutorial.step5_1 }}</div> + <I18n :src="i18n.ts._tutorial.step5_2" tag="div"> <template #featured> - <MkA class="_link" to="/featured">{{ $ts.featured }}</MkA> + <MkA class="_link" to="/featured">{{ i18n.ts.featured }}</MkA> </template> <template #explore> - <MkA class="_link" to="/explore">{{ $ts.explore }}</MkA> + <MkA class="_link" to="/explore">{{ i18n.ts.explore }}</MkA> </template> </I18n> - <div>{{ $ts._tutorial.step5_3 }}</div> - <small>{{ $ts._tutorial.step5_4 }}</small> + <div>{{ i18n.ts._tutorial.step5_3 }}</div> + <small>{{ i18n.ts._tutorial.step5_4 }}</small> </div> <div v-else-if="tutorial === 5" class="_content"> - <div>{{ $ts._tutorial.step6_1 }}</div> - <div>{{ $ts._tutorial.step6_2 }}</div> - <div>{{ $ts._tutorial.step6_3 }}</div> + <div>{{ i18n.ts._tutorial.step6_1 }}</div> + <div>{{ i18n.ts._tutorial.step6_2 }}</div> + <div>{{ i18n.ts._tutorial.step6_3 }}</div> </div> <div v-else-if="tutorial === 6" class="_content"> - <div>{{ $ts._tutorial.step7_1 }}</div> - <I18n :src="$ts._tutorial.step7_2" tag="div"> + <div>{{ i18n.ts._tutorial.step7_1 }}</div> + <I18n :src="i18n.ts._tutorial.step7_2" tag="div"> <template #help> - <a href="https://misskey-hub.net/help.html" target="_blank" class="_link">{{ $ts.help }}</a> + <a href="https://misskey-hub.net/help.html" target="_blank" class="_link">{{ i18n.ts.help }}</a> </template> </I18n> - <div>{{ $ts._tutorial.step7_3 }}</div> + <div>{{ i18n.ts._tutorial.step7_3 }}</div> </div> <div class="_footer navigation"> @@ -59,8 +59,8 @@ <i class="fas fa-chevron-right"></i> </button> </div> - <MkButton v-if="tutorial === 6" class="ok" primary @click="tutorial = -1"><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton> - <MkButton v-else class="ok" primary @click="tutorial++"><i class="fas fa-check"></i> {{ $ts.next }}</MkButton> + <MkButton v-if="tutorial === 6" class="ok" primary @click="tutorial = -1"><i class="fas fa-check"></i> {{ i18n.ts.gotIt }}</MkButton> + <MkButton v-else class="ok" primary @click="tutorial++"><i class="fas fa-check"></i> {{ i18n.ts.next }}</MkButton> </div> </div> </template> @@ -69,10 +69,11 @@ import { computed } from 'vue'; import MkButton from '@/components/ui/button.vue'; import { defaultStore } from '@/store'; +import { i18n } from '@/i18n'; const tutorial = computed({ get() { return defaultStore.reactiveState.tutorial.value || 0; }, - set(value) { defaultStore.set('tutorial', value); } + set(value) { defaultStore.set('tutorial', value); }, }); </script> diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue index 40eb85ff43..f62ab95b5b 100644 --- a/packages/client/src/pages/timeline.vue +++ b/packages/client/src/pages/timeline.vue @@ -6,7 +6,7 @@ <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/> <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/> - <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div> + <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div class="tl _block"> <XTimeline ref="tl" :key="src" diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue index fd24ec2848..9154c7348e 100644 --- a/packages/client/src/pages/user-info.vue +++ b/packages/client/src/pages/user-info.vue @@ -57,15 +57,15 @@ <div class="_formBlock"> <MkKeyValue v-if="user.host" oneline style="margin: 1em 0;"> - <template #key>{{ $ts.instanceInfo }}</template> + <template #key>{{ i18n.ts.instanceInfo }}</template> <template #value><MkA :to="`/instance-info/${user.host}`" class="_link">{{ user.host }} <i class="fas fa-angle-right"></i></MkA></template> </MkKeyValue> <MkKeyValue v-else oneline style="margin: 1em 0;"> - <template #key>{{ $ts.instanceInfo }}</template> + <template #key>{{ i18n.ts.instanceInfo }}</template> <template #value>(Local user)</template> </MkKeyValue> <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ $ts.updatedAt }}</template> + <template #key>{{ i18n.ts.updatedAt }}</template> <template #value><MkTime v-if="user.lastFetchedAt" mode="detail" :time="user.lastFetchedAt"/><span v-else>N/A</span></template> </MkKeyValue> <MkKeyValue v-if="ap" oneline style="margin: 1em 0;"> @@ -74,7 +74,7 @@ </MkKeyValue> </div> - <FormButton v-if="user.host != null" class="_formBlock" @click="updateRemoteUser"><i class="fas fa-sync"></i> {{ $ts.updateRemoteUser }}</FormButton> + <FormButton v-if="user.host != null" class="_formBlock" @click="updateRemoteUser"><i class="fas fa-sync"></i> {{ i18n.ts.updateRemoteUser }}</FormButton> <FormFolder class="_formBlock"> <template #label>Raw</template> @@ -85,13 +85,13 @@ </FormSection> </div> <div v-else-if="tab === 'moderation'" class="_formRoot"> - <FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" v-model="moderator" class="_formBlock" @update:modelValue="toggleModerator">{{ $ts.moderator }}</FormSwitch> - <FormSwitch v-model="silenced" class="_formBlock" @update:modelValue="toggleSilence">{{ $ts.silence }}</FormSwitch> - <FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ $ts.suspend }}</FormSwitch> - {{ $ts.reflectMayTakeTime }} + <FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" v-model="moderator" class="_formBlock" @update:modelValue="toggleModerator">{{ i18n.ts.moderator }}</FormSwitch> + <FormSwitch v-model="silenced" class="_formBlock" @update:modelValue="toggleSilence">{{ i18n.ts.silence }}</FormSwitch> + <FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</FormSwitch> + {{ i18n.ts.reflectMayTakeTime }} <div class="_formBlock"> - <FormButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="fas fa-key"></i> {{ $ts.resetPassword }}</FormButton> - <FormButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ $ts.deleteAccount }}</FormButton> + <FormButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="fas fa-key"></i> {{ i18n.ts.resetPassword }}</FormButton> + <FormButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</FormButton> </div> <FormTextarea v-model="moderationNote" manual-save class="_formBlock"> <template #label>Moderation note</template> @@ -128,7 +128,7 @@ <div class="cmhjzshm"> <div class="selects"> <MkSelect v-model="chartSrc" style="margin: 0 10px 0 0; flex: 1;"> - <option value="per-user-notes">{{ $ts.notes }}</option> + <option value="per-user-notes">{{ i18n.ts.notes }}</option> </MkSelect> </div> <div class="charts"> diff --git a/packages/client/src/pages/user-list-timeline.vue b/packages/client/src/pages/user-list-timeline.vue index 593db1dea7..c1f4569a02 100644 --- a/packages/client/src/pages/user-list-timeline.vue +++ b/packages/client/src/pages/user-list-timeline.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <div ref="rootEl" v-size="{ min: [800] }" class="eqqrhokj"> - <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div> + <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div class="tl _block"> <XTimeline ref="tlEl" :key="listId" diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue index c28079bb32..fa72a995b3 100644 --- a/packages/client/src/pages/user/home.vue +++ b/packages/client/src/pages/user/home.vue @@ -3,8 +3,8 @@ <div ref="rootEl" v-size="{ max: [500] }" class="ftskorzw" :class="{ wide: !narrow }"> <div class="main"> <!-- TODO --> - <!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> --> - <!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> --> + <!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSuspended }}</div> --> + <!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSilenced }}</div> --> <div class="profile"> <MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/> @@ -17,13 +17,13 @@ <MkUserName class="name" :user="user" :nowrap="true"/> <div class="bottom"> <span class="username"><MkAcct :user="user" :detail="true"/></span> - <span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span> - <span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span> - <span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span> - <span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span> + <span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span> + <span v-if="!user.isAdmin && user.isModerator" :title="i18n.ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span> + <span v-if="user.isLocked" :title="i18n.ts.isLocked"><i class="fas fa-lock"></i></span> + <span v-if="user.isBot" :title="i18n.ts.isBot"><i class="fas fa-robot"></i></span> </div> </div> - <span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ $ts.followsYou }}</span> + <span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ i18n.ts.followsYou }}</span> <div v-if="$i" class="actions"> <button class="menu _button" @click="menu"><i class="fas fa-ellipsis-h"></i></button> <MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/> @@ -34,27 +34,27 @@ <MkUserName :user="user" :nowrap="false" class="name"/> <div class="bottom"> <span class="username"><MkAcct :user="user" :detail="true"/></span> - <span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span> - <span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span> - <span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span> - <span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span> + <span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span> + <span v-if="!user.isAdmin && user.isModerator" :title="i18n.ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span> + <span v-if="user.isLocked" :title="i18n.ts.isLocked"><i class="fas fa-lock"></i></span> + <span v-if="user.isBot" :title="i18n.ts.isBot"><i class="fas fa-robot"></i></span> </div> </div> <div class="description"> <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/> - <p v-else class="empty">{{ $ts.noAccountDescription }}</p> + <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> </div> <div class="fields system"> <dl v-if="user.location" class="field"> - <dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt> + <dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ i18n.ts.location }}</dt> <dd class="value">{{ user.location }}</dd> </dl> <dl v-if="user.birthday" class="field"> - <dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt> + <dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ i18n.ts.birthday }}</dt> <dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd> </dl> <dl class="field"> - <dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt> + <dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ i18n.ts.registeredDate }}</dt> <dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd> </dl> </div> @@ -71,15 +71,15 @@ <div class="status"> <MkA v-click-anime :to="userPage(user)" :class="{ active: page === 'index' }"> <b>{{ number(user.notesCount) }}</b> - <span>{{ $ts.notes }}</span> + <span>{{ i18n.ts.notes }}</span> </MkA> <MkA v-click-anime :to="userPage(user, 'following')" :class="{ active: page === 'following' }"> <b>{{ number(user.followingCount) }}</b> - <span>{{ $ts.following }}</span> + <span>{{ i18n.ts.following }}</span> </MkA> <MkA v-click-anime :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }"> <b>{{ number(user.followersCount) }}</b> - <span>{{ $ts.followers }}</span> + <span>{{ i18n.ts.followers }}</span> </MkA> </div> </div> @@ -89,7 +89,7 @@ <div v-if="user.pinnedNotes.length > 0" class="_gap"> <XNote v-for="note in user.pinnedNotes" :key="note.id" class="note _block" :note="note" :pinned="true"/> </div> - <MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo> + <MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> <template v-if="narrow"> <XPhotos :key="user.id" :user="user"/> <XActivity :key="user.id" :user="user" style="margin-top: var(--margin);"/> diff --git a/packages/client/src/pages/user/index.timeline.vue b/packages/client/src/pages/user/index.timeline.vue index 1bcc0a1b85..0345978b8d 100644 --- a/packages/client/src/pages/user/index.timeline.vue +++ b/packages/client/src/pages/user/index.timeline.vue @@ -2,9 +2,9 @@ <MkStickyContainer> <template #header> <MkTab v-model="include" :class="$style.tab"> - <option :value="null">{{ $ts.notes }}</option> - <option value="replies">{{ $ts.notesAndReplies }}</option> - <option value="files">{{ $ts.withFiles }}</option> + <option :value="null">{{ i18n.ts.notes }}</option> + <option value="replies">{{ i18n.ts.notesAndReplies }}</option> + <option value="files">{{ i18n.ts.withFiles }}</option> </MkTab> </template> <XNotes :no-gap="true" :pagination="pagination"/> @@ -17,6 +17,7 @@ import * as misskey from 'misskey-js'; import XNotes from '@/components/notes.vue'; import MkTab from '@/components/tab.vue'; import * as os from '@/os'; +import { i18n } from '@/i18n'; const props = defineProps<{ user: misskey.entities.UserDetailed; diff --git a/packages/client/src/router.ts b/packages/client/src/router.ts index b61b77eeeb..93bea0b2f4 100644 --- a/packages/client/src/router.ts +++ b/packages/client/src/router.ts @@ -42,9 +42,121 @@ export const routes = [{ component: page(() => import('./pages/instance-info.vue')), }, { name: 'settings', - path: '/settings/:initialPage(*)?', + path: '/settings', component: page(() => import('./pages/settings/index.vue')), loginRequired: true, + children: [{ + path: '/profile', + name: 'profile', + component: page(() => import('./pages/settings/profile.vue')), + }, { + path: '/privacy', + name: 'privacy', + component: page(() => import('./pages/settings/privacy.vue')), + }, { + path: '/reaction', + name: 'reaction', + component: page(() => import('./pages/settings/reaction.vue')), + }, { + path: '/drive', + name: 'drive', + component: page(() => import('./pages/settings/drive.vue')), + }, { + path: '/notifications', + name: 'notifications', + component: page(() => import('./pages/settings/notifications.vue')), + }, { + path: '/email', + name: 'email', + component: page(() => import('./pages/settings/email.vue')), + }, { + path: '/integration', + name: 'integration', + component: page(() => import('./pages/settings/integration.vue')), + }, { + path: '/security', + name: 'security', + component: page(() => import('./pages/settings/security.vue')), + }, { + path: '/general', + name: 'general', + component: page(() => import('./pages/settings/general.vue')), + }, { + path: '/theme/install', + name: 'theme', + component: page(() => import('./pages/settings/theme.install.vue')), + }, { + path: '/theme/manage', + name: 'theme', + component: page(() => import('./pages/settings/theme.manage.vue')), + }, { + path: '/theme', + name: 'theme', + component: page(() => import('./pages/settings/theme.vue')), + }, { + path: '/navbar', + name: 'navbar', + component: page(() => import('./pages/settings/navbar.vue')), + }, { + path: '/statusbar', + name: 'statusbar', + component: page(() => import('./pages/settings/statusbar.vue')), + }, { + path: '/sounds', + name: 'sounds', + component: page(() => import('./pages/settings/sounds.vue')), + }, { + path: '/plugin', + name: 'plugin', + component: page(() => import('./pages/settings/plugin.vue')), + }, { + path: '/import-export', + name: 'import-export', + component: page(() => import('./pages/settings/import-export.vue')), + }, { + path: '/instance-mute', + name: 'instance-mute', + component: page(() => import('./pages/settings/instance-mute.vue')), + }, { + path: '/mute-block', + name: 'mute-block', + component: page(() => import('./pages/settings/mute-block.vue')), + }, { + path: '/word-mute', + name: 'word-mute', + component: page(() => import('./pages/settings/word-mute.vue')), + }, { + path: '/api', + name: 'api', + component: page(() => import('./pages/settings/api.vue')), + }, { + path: '/webhook/edit/:webhookId', + name: 'webhook', + component: page(() => import('./pages/settings/webhook.edit.vue')), + }, { + path: '/webhook/new', + name: 'webhook', + component: page(() => import('./pages/settings/webhook.new.vue')), + }, { + path: '/webhook', + name: 'webhook', + component: page(() => import('./pages/settings/webhook.vue')), + }, { + path: '/deck', + name: 'deck', + component: page(() => import('./pages/settings/deck.vue')), + }, { + path: '/preferences-backups', + name: 'preferences-backups', + component: page(() => import('./pages/settings/preferences-backups.vue')), + }, { + path: '/other', + name: 'other', + component: page(() => import('./pages/settings/other.vue')), + }, { + path: '/', + component: page(() => import('./pages/_empty_.vue')), + }], }, { path: '/reset-password/:token?', component: page(() => import('./pages/reset-password.vue')), @@ -166,8 +278,84 @@ export const routes = [{ path: '/admin/file/:fileId', component: iAmModerator ? page(() => import('./pages/admin-file.vue')) : page(() => import('./pages/not-found.vue')), }, { - path: '/admin/:initialPage(*)?', + path: '/admin', component: iAmModerator ? page(() => import('./pages/admin/index.vue')) : page(() => import('./pages/not-found.vue')), + children: [{ + path: '/overview', + name: 'overview', + component: page(() => import('./pages/admin/overview.vue')), + }, { + path: '/users', + name: 'users', + component: page(() => import('./pages/admin/users.vue')), + }, { + path: '/emojis', + name: 'emojis', + component: page(() => import('./pages/admin/emojis.vue')), + }, { + path: '/queue', + name: 'queue', + component: page(() => import('./pages/admin/queue.vue')), + }, { + path: '/files', + name: 'files', + component: page(() => import('./pages/admin/files.vue')), + }, { + path: '/announcements', + name: 'announcements', + component: page(() => import('./pages/admin/announcements.vue')), + }, { + path: '/ads', + name: 'ads', + component: page(() => import('./pages/admin/ads.vue')), + }, { + path: '/database', + name: 'database', + component: page(() => import('./pages/admin/database.vue')), + }, { + path: '/abuses', + name: 'abuses', + component: page(() => import('./pages/admin/abuses.vue')), + }, { + path: '/settings', + name: 'settings', + component: page(() => import('./pages/admin/settings.vue')), + }, { + path: '/email-settings', + name: 'email-settings', + component: page(() => import('./pages/admin/email-settings.vue')), + }, { + path: '/object-storage', + name: 'object-storage', + component: page(() => import('./pages/admin/object-storage.vue')), + }, { + path: '/security', + name: 'security', + component: page(() => import('./pages/admin/security.vue')), + }, { + path: '/relays', + name: 'relays', + component: page(() => import('./pages/admin/relays.vue')), + }, { + path: '/integrations', + name: 'integrations', + component: page(() => import('./pages/admin/integrations.vue')), + }, { + path: '/instance-block', + name: 'instance-block', + component: page(() => import('./pages/admin/instance-block.vue')), + }, { + path: '/proxy-account', + name: 'proxy-account', + component: page(() => import('./pages/admin/proxy-account.vue')), + }, { + path: '/other-settings', + name: 'other-settings', + component: page(() => import('./pages/admin/other-settings.vue')), + }, { + path: '/', + component: page(() => import('./pages/_empty_.vue')), + }], }, { path: '/my/notifications', component: page(() => import('./pages/notifications.vue')), @@ -263,21 +451,25 @@ mainRouter.addListener('push', ctx => { if (scrollPos !== 0) { window.setTimeout(() => { // é·ç§»ç›´å¾Œã¯ã‚¿ã‚¤ãƒŸãƒ³ã‚°ã«ã‚ˆã£ã¦ã¯ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆãŒå¾©å…ƒã—切ã£ã¦ãªã„å¯èƒ½æ€§ã‚‚考ãˆã‚‰ã‚Œã‚‹ãŸã‚å°‘ã—æ™‚間を空ã‘ã¦å†åº¦ã‚¹ã‚¯ãƒãƒ¼ãƒ« window.scroll({ top: scrollPos, behavior: 'instant' }); - }, 1000); + }, 100); } }); +mainRouter.addListener('replace', ctx => { + window.history.replaceState({ key: ctx.key }, '', ctx.path); +}); + mainRouter.addListener('same', () => { window.scroll({ top: 0, behavior: 'smooth' }); }); window.addEventListener('popstate', (event) => { - mainRouter.change(location.pathname + location.search + location.hash, event.state?.key); + mainRouter.replace(location.pathname + location.search + location.hash, event.state?.key, false); const scrollPos = scrollPosStore.get(event.state?.key) ?? 0; window.scroll({ top: scrollPos, behavior: 'instant' }); window.setTimeout(() => { // é·ç§»ç›´å¾Œã¯ã‚¿ã‚¤ãƒŸãƒ³ã‚°ã«ã‚ˆã£ã¦ã¯ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆãŒå¾©å…ƒã—切ã£ã¦ãªã„å¯èƒ½æ€§ã‚‚考ãˆã‚‰ã‚Œã‚‹ãŸã‚å°‘ã—æ™‚間を空ã‘ã¦å†åº¦ã‚¹ã‚¯ãƒãƒ¼ãƒ« window.scroll({ top: scrollPos, behavior: 'instant' }); - }, 1000); + }, 100); }); export function useRouter(): Router { diff --git a/packages/client/src/scripts/theme.ts b/packages/client/src/scripts/theme.ts index 77d1df0826..02ac77b59d 100644 --- a/packages/client/src/scripts/theme.ts +++ b/packages/client/src/scripts/theme.ts @@ -25,6 +25,7 @@ export const getBuiltinThemes = () => Promise.all( 'l-vivid', 'l-cherry', 'l-sushi', + 'l-u0', 'd-dark', 'd-persimmon', @@ -35,6 +36,7 @@ export const getBuiltinThemes = () => Promise.all( 'd-green-orange', 'd-cherry', 'd-ice', + 'd-u0', ].map(name => import(`../themes/${name}.json5`).then(({ default: _default }): Theme => _default)), ); diff --git a/packages/client/src/scripts/timezones.ts b/packages/client/src/scripts/timezones.ts new file mode 100644 index 0000000000..8ce07323f6 --- /dev/null +++ b/packages/client/src/scripts/timezones.ts @@ -0,0 +1,49 @@ +export const timezones = [{ + name: 'UTC', + abbrev: 'UTC', + offset: 0, +}, { + name: 'Europe/Berlin', + abbrev: 'CET', + offset: 60, +}, { + name: 'Asia/Tokyo', + abbrev: 'JST', + offset: 540, +}, { + name: 'Asia/Seoul', + abbrev: 'KST', + offset: 540, +}, { + name: 'Asia/Shanghai', + abbrev: 'CST', + offset: 480, +}, { + name: 'Australia/Sydney', + abbrev: 'AEST', + offset: 600, +}, { + name: 'Australia/Darwin', + abbrev: 'ACST', + offset: 570, +}, { + name: 'Australia/Perth', + abbrev: 'AWST', + offset: 480, +}, { + name: 'America/New_York', + abbrev: 'EST', + offset: -300, +}, { + name: 'America/Mexico_City', + abbrev: 'CST', + offset: -360, +}, { + name: 'America/Phoenix', + abbrev: 'MST', + offset: -420, +}, { + name: 'America/Los_Angeles', + abbrev: 'PST', + offset: -480, +}]; diff --git a/packages/client/src/themes/d-u0.json5 b/packages/client/src/themes/d-u0.json5 new file mode 100644 index 0000000000..b270f809ac --- /dev/null +++ b/packages/client/src/themes/d-u0.json5 @@ -0,0 +1,88 @@ +{ + id: '7a5bc13b-df8f-4d44-8e94-4452f0c634bb', + base: 'dark', + name: 'Mi U0 Dark', + props: { + X2: ':darken<2<@panel', + X3: 'rgba(255, 255, 255, 0.05)', + X4: 'rgba(255, 255, 255, 0.1)', + X5: 'rgba(255, 255, 255, 0.05)', + X6: 'rgba(255, 255, 255, 0.15)', + X7: 'rgba(255, 255, 255, 0.05)', + X8: ':lighten<5<@accent', + X9: ':darken<5<@accent', + bg: '#172426', + fg: '#dadada', + X10: ':alpha<0.4<@accent', + X11: 'rgba(0, 0, 0, 0.3)', + X12: 'rgba(255, 255, 255, 0.1)', + X13: 'rgba(255, 255, 255, 0.15)', + X14: ':alpha<0.5<@navBg', + X15: ':alpha<0<@panel', + X16: ':alpha<0.7<@panel', + X17: ':alpha<0.8<@bg', + cwBg: '#687390', + cwFg: '#393f4f', + link: '@accent', + warn: '#ecb637', + badge: '#31b1ce', + error: '#ec4137', + focus: ':alpha<0.3<@accent', + navBg: '@panel', + navFg: '@fg', + panel: ':lighten<3<@bg', + popup: ':lighten<3<@panel', + accent: '#00a497', + header: ':alpha<0.7<@panel', + infoBg: '#253142', + infoFg: '#fff', + renote: '@accent', + shadow: 'rgba(0, 0, 0, 0.3)', + divider: 'rgba(255, 255, 255, 0.1)', + hashtag: '#e6b422', + mention: '@accent', + modalBg: 'rgba(0, 0, 0, 0.5)', + success: '#86b300', + buttonBg: 'rgba(255, 255, 255, 0.05)', + switchBg: 'rgba(255, 255, 255, 0.15)', + acrylicBg: ':alpha<0.5<@bg', + cwHoverBg: '#707b97', + indicator: '@accent', + mentionMe: '@mention', + messageBg: '@bg', + navActive: '@accent', + accentedBg: ':alpha<0.15<@accent', + codeNumber: '#cfff9e', + codeString: '#ffb675', + fgOnAccent: '#fff', + infoWarnBg: '#42321c', + infoWarnFg: '#ffbd3e', + navHoverFg: ':lighten<17<@fg', + codeBoolean: '#c59eff', + dateLabelFg: '@fg', + inputBorder: 'rgba(255, 255, 255, 0.1)', + panelBorder: '" solid 1px var(--divider)', + accentDarken: ':darken<10<@accent', + acrylicPanel: ':alpha<0.5<@panel', + navIndicator: '@indicator', + accentLighten: ':lighten<10<@accent', + buttonHoverBg: 'rgba(255, 255, 255, 0.1)', + driveFolderBg: ':alpha<0.3<@accent', + fgHighlighted: ':lighten<3<@fg', + fgTransparent: ':alpha<0.5<@fg', + panelHeaderBg: ':lighten<3<@panel', + panelHeaderFg: '@fg', + buttonGradateA: '@accent', + buttonGradateB: ':hue<20<@accent', + htmlThemeColor: '@bg', + panelHighlight: ':lighten<3<@panel', + listItemHoverBg: 'rgba(255, 255, 255, 0.03)', + scrollbarHandle: 'rgba(255, 255, 255, 0.2)', + inputBorderHover: 'rgba(255, 255, 255, 0.2)', + wallpaperOverlay: 'rgba(0, 0, 0, 0.5)', + fgTransparentWeak: ':alpha<0.75<@fg', + panelHeaderDivider: 'rgba(0, 0, 0, 0)', + scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)', + deckDivider: '#142022', + }, +} diff --git a/packages/client/src/themes/l-u0.json5 b/packages/client/src/themes/l-u0.json5 new file mode 100644 index 0000000000..03b114ba39 --- /dev/null +++ b/packages/client/src/themes/l-u0.json5 @@ -0,0 +1,87 @@ +{ + id: 'e2c940b5-6e9a-4c03-b738-261c720c426d', + base: 'light', + name: 'Mi U0 Light', + props: { + X2: ':darken<2<@panel', + X3: 'rgba(255, 255, 255, 0.05)', + X4: 'rgba(255, 255, 255, 0.1)', + X5: 'rgba(255, 255, 255, 0.05)', + X6: 'rgba(255, 255, 255, 0.15)', + X7: 'rgba(255, 255, 255, 0.05)', + X8: ':lighten<5<@accent', + X9: ':darken<5<@accent', + bg: '#e7e7eb', + fg: '#5f5f5f', + X10: ':alpha<0.4<@accent', + X11: 'rgba(0, 0, 0, 0.3)', + X12: 'rgba(255, 255, 255, 0.1)', + X13: 'rgba(255, 255, 255, 0.15)', + X14: ':alpha<0.5<@navBg', + X15: ':alpha<0<@panel', + X16: ':alpha<0.7<@panel', + X17: ':alpha<0.8<@bg', + cwBg: '#687390', + cwFg: '#393f4f', + link: '@accent', + warn: '#ecb637', + badge: '#31b1ce', + error: '#ec4137', + focus: ':alpha<0.3<@accent', + navBg: '@panel', + navFg: '@fg', + panel: ':lighten<3<@bg', + popup: ':lighten<3<@panel', + accent: '#478384', + header: ':alpha<0.7<@panel', + infoBg: '#253142', + infoFg: '#fff', + renote: '@accent', + shadow: 'rgba(0, 0, 0, 0.3)', + divider: '#4646461a', + hashtag: '#1f3134', + mention: '@accent', + modalBg: 'rgba(0, 0, 0, 0.5)', + success: '#86b300', + buttonBg: '#0000000d', + switchBg: 'rgba(255, 255, 255, 0.15)', + acrylicBg: ':alpha<0.5<@bg', + cwHoverBg: '#707b97', + indicator: '@accent', + mentionMe: '@mention', + messageBg: '@bg', + navActive: '@accent', + accentedBg: ':alpha<0.15<@accent', + codeNumber: '#cfff9e', + codeString: '#ffb675', + fgOnAccent: '#fff', + infoWarnBg: '#42321c', + infoWarnFg: '#ffbd3e', + navHoverFg: ':lighten<17<@fg', + codeBoolean: '#c59eff', + dateLabelFg: '@fg', + inputBorder: 'rgba(255, 255, 255, 0.1)', + panelBorder: '" solid 1px var(--divider)', + accentDarken: ':darken<10<@accent', + acrylicPanel: ':alpha<0.5<@panel', + navIndicator: '@indicator', + accentLighten: ':lighten<10<@accent', + buttonHoverBg: '#0000001a', + driveFolderBg: ':alpha<0.3<@accent', + fgHighlighted: ':lighten<3<@fg', + fgTransparent: ':alpha<0.5<@fg', + panelHeaderBg: ':lighten<3<@panel', + panelHeaderFg: '@fg', + buttonGradateA: '@accent', + buttonGradateB: ':hue<20<@accent', + htmlThemeColor: '@bg', + panelHighlight: ':lighten<3<@panel', + listItemHoverBg: 'rgba(255, 255, 255, 0.03)', + scrollbarHandle: '#74747433', + inputBorderHover: 'rgba(255, 255, 255, 0.2)', + wallpaperOverlay: 'rgba(0, 0, 0, 0.5)', + fgTransparentWeak: ':alpha<0.75<@fg', + panelHeaderDivider: 'rgba(0, 0, 0, 0)', + scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)', + }, +} diff --git a/packages/client/src/ui/_common_/navbar-for-mobile.vue b/packages/client/src/ui/_common_/navbar-for-mobile.vue index f2521cfc72..2bac239d41 100644 --- a/packages/client/src/ui/_common_/navbar-for-mobile.vue +++ b/packages/client/src/ui/_common_/navbar-for-mobile.vue @@ -9,30 +9,30 @@ </div> <div class="middle"> <MkA v-click-anime class="item index" active-class="active" to="/" exact> - <i class="icon fas fa-home fa-fw"></i><span class="text">{{ $ts.timeline }}</span> + <i class="icon fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> </MkA> <template v-for="item in menu"> <div v-if="item === '-'" class="divider"></div> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> - <i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ $ts[navbarItemDef[item].title] }}</span> + <i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ i18n.ts[navbarItemDef[item].title] }}</span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> </component> </template> <div class="divider"></div> <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" active-class="active" to="/admin"> - <i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span> + <i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> </MkA> <button v-click-anime class="item _button" @click="more"> - <i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> + <i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span> <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon fas fa-circle"></i></span> </button> <MkA v-click-anime class="item" active-class="active" to="/settings"> - <i class="icon fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span> + <i class="icon fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span> </MkA> </div> <div class="bottom"> <button class="item _button post" data-cy-open-post-form @click="os.post"> - <i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span> + <i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ i18n.ts.note }}</span> </button> <button v-click-anime class="item _button account" @click="openAccountMenu"> <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> diff --git a/packages/client/src/ui/_common_/stream-indicator.vue b/packages/client/src/ui/_common_/stream-indicator.vue index 5e811e1b88..a855de8ab9 100644 --- a/packages/client/src/ui/_common_/stream-indicator.vue +++ b/packages/client/src/ui/_common_/stream-indicator.vue @@ -1,9 +1,9 @@ <template> <div v-if="hasDisconnected && $store.state.serverDisconnectedBehavior === 'quiet'" class="nsbbhtug" @click="resetDisconnected"> - <div>{{ $ts.disconnectedFromServer }}</div> + <div>{{ i18n.ts.disconnectedFromServer }}</div> <div class="command"> - <button class="_textButton" @click="reload">{{ $ts.reload }}</button> - <button class="_textButton">{{ $ts.doNothing }}</button> + <button class="_textButton" @click="reload">{{ i18n.ts.reload }}</button> + <button class="_textButton">{{ i18n.ts.doNothing }}</button> </div> </div> </template> @@ -11,6 +11,7 @@ <script lang="ts" setup> import { onUnmounted } from 'vue'; import { stream } from '@/stream'; +import { i18n } from '@/i18n'; let hasDisconnected = $ref(false); diff --git a/packages/client/src/ui/_common_/upload.vue b/packages/client/src/ui/_common_/upload.vue index f3703d0e8f..8324e9e75e 100644 --- a/packages/client/src/ui/_common_/upload.vue +++ b/packages/client/src/ui/_common_/upload.vue @@ -6,7 +6,7 @@ <div class="top"> <p class="name"><i class="fas fa-spinner fa-pulse"></i>{{ ctx.name }}</p> <p class="status"> - <span v-if="ctx.progressValue === undefined" class="initing">{{ $ts.waiting }}<MkEllipsis/></span> + <span v-if="ctx.progressValue === undefined" class="initing">{{ i18n.ts.waiting }}<MkEllipsis/></span> <span v-if="ctx.progressValue !== undefined" class="kb">{{ String(Math.floor(ctx.progressValue / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progressMax / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span> <span v-if="ctx.progressValue !== undefined" class="percentage">{{ Math.floor((ctx.progressValue / ctx.progressMax) * 100) }}</span> </p> @@ -21,6 +21,7 @@ import { } from 'vue'; import * as os from '@/os'; import { uploads } from '@/scripts/upload'; +import { i18n } from '@/i18n'; const zIndex = os.claimZIndex('high'); </script> diff --git a/packages/client/src/ui/universal.vue b/packages/client/src/ui/universal.vue index e4b5de9918..0ef0da70b5 100644 --- a/packages/client/src/ui/universal.vue +++ b/packages/client/src/ui/universal.vue @@ -70,6 +70,7 @@ import { $i } from '@/account'; import { Router } from '@/nirax'; import { mainRouter } from '@/router'; import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; +import { deviceKind } from '@/scripts/device-kind'; const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); @@ -77,10 +78,11 @@ const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars. const DESKTOP_THRESHOLD = 1100; const MOBILE_THRESHOLD = 500; +// デスクトップã§ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’ç‹ãã—ãŸã¨ãモãƒã‚¤ãƒ«UIãŒè¡¨ç¤ºã•ã‚Œã¦æ¬²ã—ã„ã“ã¨ã¯ã‚ã‚‹ã®ã§ deviceKind === 'desktop' ã®åˆ¤å®šã¯è¡Œã‚ãªã„ const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD); -const isMobile = ref(window.innerWidth <= MOBILE_THRESHOLD); +const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD); window.addEventListener('resize', () => { - isMobile.value = window.innerWidth <= MOBILE_THRESHOLD; + isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD; }); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); diff --git a/packages/client/src/widgets/activity.vue b/packages/client/src/widgets/activity.vue index 7252d65403..97e354e1bb 100644 --- a/packages/client/src/widgets/activity.vue +++ b/packages/client/src/widgets/activity.vue @@ -1,6 +1,6 @@ <template> <MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" class="mkw-activity"> - <template #header><i class="fas fa-chart-simple"></i>{{ $ts._widgets.activity }}</template> + <template #header><i class="fas fa-chart-simple"></i>{{ i18n.ts._widgets.activity }}</template> <template #func><button class="_button" @click="toggleView()"><i class="fas fa-sort"></i></button></template> <div> @@ -22,6 +22,7 @@ import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import MkContainer from '@/components/ui/container.vue'; import { $i } from '@/account'; +import { i18n } from '@/i18n'; const name = 'activity'; diff --git a/packages/client/src/widgets/aiscript.vue b/packages/client/src/widgets/aiscript.vue index 9fed292a69..6ae1a9877b 100644 --- a/packages/client/src/widgets/aiscript.vue +++ b/packages/client/src/widgets/aiscript.vue @@ -1,6 +1,6 @@ <template> <MkContainer :show-header="widgetProps.showHeader" class="mkw-aiscript"> - <template #header><i class="fas fa-terminal"></i>{{ $ts._widgets.aiscript }}</template> + <template #header><i class="fas fa-terminal"></i>{{ i18n.ts._widgets.aiscript }}</template> <div class="uylguesu _monospace"> <textarea v-model="widgetProps.script" placeholder="(1 + 1)"></textarea> @@ -14,13 +14,14 @@ <script lang="ts" setup> import { onMounted, onUnmounted, ref, watch } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; +import { AiScript, parse, utils } from '@syuilo/aiscript'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import MkContainer from '@/components/ui/container.vue'; -import { AiScript, parse, utils } from '@syuilo/aiscript'; import { createAiScriptEnv } from '@/scripts/aiscript/api'; import { $i } from '@/account'; +import { i18n } from '@/i18n'; const name = 'aiscript'; @@ -88,7 +89,7 @@ const run = async () => { }); break; default: break; } - } + }, }); let ast; diff --git a/packages/client/src/widgets/calendar.vue b/packages/client/src/widgets/calendar.vue index 3a0dc8970c..99bd36e2fc 100644 --- a/packages/client/src/widgets/calendar.vue +++ b/packages/client/src/widgets/calendar.vue @@ -11,19 +11,19 @@ </div> <div class="info"> <div> - <p>{{ $ts.today }}: <b>{{ dayP.toFixed(1) }}%</b></p> + <p>{{ i18n.ts.today }}: <b>{{ dayP.toFixed(1) }}%</b></p> <div class="meter"> <div class="val" :style="{ width: `${dayP}%` }"></div> </div> </div> <div> - <p>{{ $ts.thisMonth }}: <b>{{ monthP.toFixed(1) }}%</b></p> + <p>{{ i18n.ts.thisMonth }}: <b>{{ monthP.toFixed(1) }}%</b></p> <div class="meter"> <div class="val" :style="{ width: `${monthP}%` }"></div> </div> </div> <div> - <p>{{ $ts.thisYear }}: <b>{{ yearP.toFixed(1) }}%</b></p> + <p>{{ i18n.ts.thisYear }}: <b>{{ yearP.toFixed(1) }}%</b></p> <div class="meter"> <div class="val" :style="{ width: `${yearP}%` }"></div> </div> diff --git a/packages/client/src/widgets/clock.vue b/packages/client/src/widgets/clock.vue index fbd2f9e899..7d78b05f84 100644 --- a/packages/client/src/widgets/clock.vue +++ b/packages/client/src/widgets/clock.vue @@ -1,17 +1,30 @@ <template> <MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-clock"> - <div class="vubelbmv"> - <MkAnalogClock class="clock" :thickness="widgetProps.thickness"/> + <div class="vubelbmv" :class="widgetProps.size"> + <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label a abbrev">{{ tzAbbrev }}</div> + <MkAnalogClock + class="clock" + :thickness="widgetProps.thickness" + :offset="tzOffset" + :graduations="widgetProps.graduations" + :fade-graduations="widgetProps.fadeGraduations" + :twentyfour="widgetProps.twentyFour" + /> + <MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :show-s="false" :offset="tzOffset"/> + <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label d offset">{{ tzOffsetLabel }}</div> </div> </MkContainer> </template> <script lang="ts" setup> import { } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/ui/container.vue'; import MkAnalogClock from '@/components/analog-clock.vue'; +import MkDigitalClock from '@/components/digital-clock.vue'; +import { timezones } from '@/scripts/timezones'; +import { i18n } from '@/i18n'; const name = 'clock'; @@ -20,15 +33,69 @@ const widgetPropsDef = { type: 'boolean' as const, default: false, }, + size: { + type: 'radio' as const, + default: 'medium', + options: [{ + value: 'small', label: i18n.ts.small, + }, { + value: 'medium', label: i18n.ts.medium, + }, { + value: 'large', label: i18n.ts.large, + }], + }, thickness: { type: 'radio' as const, - default: 0.1, + default: 0.2, + options: [{ + value: 0.1, label: 'thin', + }, { + value: 0.2, label: 'medium', + }, { + value: 0.3, label: 'thick', + }], + }, + graduations: { + type: 'radio' as const, + default: 'numbers', + options: [{ + value: 'none', label: 'None', + }, { + value: 'dots', label: 'Dots', + }, { + value: 'numbers', label: 'Numbers', + }], + }, + fadeGraduations: { + type: 'boolean' as const, + default: true, + }, + twentyFour: { + type: 'boolean' as const, + default: false, + }, + label: { + type: 'radio' as const, + default: 'none', options: [{ - value: 0.1, label: 'thin' + value: 'none', label: 'None', + }, { + value: 'time', label: 'Time', }, { - value: 0.2, label: 'medium' + value: 'tz', label: 'TZ', }, { - value: 0.3, label: 'thick' + value: 'timeAndTz', label: 'Time + TZ', + }], + }, + timezone: { + type: 'enum' as const, + default: null, + enum: [...timezones.map((tz) => ({ + label: tz.name, + value: tz.name.toLowerCase(), + })), { + label: '(auto)', + value: null, }], }, }; @@ -47,6 +114,16 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); +const tzAbbrev = $computed(() => (widgetProps.timezone === null + ? timezones.find((tz) => tz.name.toLowerCase() === Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase())?.abbrev + : timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.abbrev) ?? '?'); + +const tzOffset = $computed(() => widgetProps.timezone === null + ? 0 - new Date().getTimezoneOffset() + : timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.offset ?? 0); + +const tzOffsetLabel = $computed(() => (tzOffset >= 0 ? '+' : '-') + Math.floor(tzOffset / 60).toString().padStart(2, '0') + ':' + (tzOffset % 60).toString().padStart(2, '0')); + defineExpose<WidgetComponentExpose>({ name, configure, @@ -56,11 +133,59 @@ defineExpose<WidgetComponentExpose>({ <style lang="scss" scoped> .vubelbmv { - padding: 8px; + position: relative; + + > .label { + position: absolute; + opacity: 0.7; + + &.a { + top: 14px; + left: 14px; + } + + &.b { + top: 14px; + right: 14px; + } + + &.c { + bottom: 14px; + left: 14px; + } + + &.d { + bottom: 14px; + right: 14px; + } + } > .clock { - height: 150px; margin: auto; } + + &.small { + padding: 12px; + + > .clock { + height: 100px; + } + } + + &.medium { + padding: 14px; + + > .clock { + height: 150px; + } + } + + &.large { + padding: 16px; + + > .clock { + height: 200px; + } + } } </style> diff --git a/packages/client/src/widgets/digital-clock.vue b/packages/client/src/widgets/digital-clock.vue index a17ed040c9..387fad9b62 100644 --- a/packages/client/src/widgets/digital-clock.vue +++ b/packages/client/src/widgets/digital-clock.vue @@ -1,21 +1,19 @@ <template> <div class="mkw-digitalClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> - <span> - <span v-text="hh"></span> - <span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> - <span v-text="mm"></span> - <span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> - <span v-text="ss"></span> - <span v-if="widgetProps.showMs" :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> - <span v-if="widgetProps.showMs" v-text="ms"></span> - </span> + <div v-if="widgetProps.showLabel" class="label">{{ tzAbbrev }}</div> + <div class="time"> + <MkDigitalClock :show-ms="widgetProps.showMs" :offset="tzOffset"/> + </div> + <div v-if="widgetProps.showLabel" class="label">{{ tzOffsetLabel }}</div> </div> </template> <script lang="ts" setup> import { onUnmounted, ref, watch } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; +import { timezones } from '@/scripts/timezones'; +import MkDigitalClock from '@/components/digital-clock.vue'; const name = 'digitalClock'; @@ -33,6 +31,21 @@ const widgetPropsDef = { type: 'boolean' as const, default: true, }, + showLabel: { + type: 'boolean' as const, + default: true, + }, + timezone: { + type: 'enum' as const, + default: null, + enum: [...timezones.map((tz) => ({ + label: tz.name, + value: tz.name.toLowerCase(), + })), { + label: '(auto)', + value: null, + }], + }, }; type WidgetProps = GetFormResultType<typeof widgetPropsDef>; @@ -49,31 +62,15 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -let intervalId; -const hh = ref(''); -const mm = ref(''); -const ss = ref(''); -const ms = ref(''); -const showColon = ref(true); -const tick = () => { - const now = new Date(); - hh.value = now.getHours().toString().padStart(2, '0'); - mm.value = now.getMinutes().toString().padStart(2, '0'); - ss.value = now.getSeconds().toString().padStart(2, '0'); - ms.value = Math.floor(now.getMilliseconds() / 10).toString().padStart(2, '0'); - showColon.value = now.getSeconds() % 2 === 0; -}; +const tzAbbrev = $computed(() => (widgetProps.timezone === null + ? timezones.find((tz) => tz.name.toLowerCase() === Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase())?.abbrev + : timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.abbrev) ?? '?'); -tick(); +const tzOffset = $computed(() => widgetProps.timezone === null + ? 0 - new Date().getTimezoneOffset() + : timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)?.offset ?? 0); -watch(() => widgetProps.showMs, () => { - if (intervalId) window.clearInterval(intervalId); - intervalId = window.setInterval(tick, widgetProps.showMs ? 10 : 1000); -}, { immediate: true }); - -onUnmounted(() => { - window.clearInterval(intervalId); -}); +const tzOffsetLabel = $computed(() => (tzOffset >= 0 ? '+' : '-') + Math.floor(tzOffset / 60).toString().padStart(2, '0') + ':' + (tzOffset % 60).toString().padStart(2, '0')); defineExpose<WidgetComponentExpose>({ name, @@ -86,5 +83,10 @@ defineExpose<WidgetComponentExpose>({ .mkw-digitalClock { padding: 16px 0; text-align: center; + + > .label { + font-size: 65%; + opacity: 0.7; + } } </style> diff --git a/packages/client/src/widgets/federation.vue b/packages/client/src/widgets/federation.vue index ac87cdac2e..9619aa53ee 100644 --- a/packages/client/src/widgets/federation.vue +++ b/packages/client/src/widgets/federation.vue @@ -1,6 +1,6 @@ <template> <MkContainer :show-header="widgetProps.showHeader" :foldable="foldable" :scrollable="scrollable" class="mkw-federation"> - <template #header><i class="fas fa-globe"></i>{{ $ts._widgets.federation }}</template> + <template #header><i class="fas fa-globe"></i>{{ i18n.ts._widgets.federation }}</template> <div class="wbrkwalb"> <MkLoading v-if="fetching"/> @@ -26,6 +26,7 @@ import MkContainer from '@/components/ui/container.vue'; import MkMiniChart from '@/components/mini-chart.vue'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const name = 'federation'; diff --git a/packages/client/src/widgets/index.ts b/packages/client/src/widgets/index.ts index baf6acd23d..66bec7c83f 100644 --- a/packages/client/src/widgets/index.ts +++ b/packages/client/src/widgets/index.ts @@ -12,6 +12,7 @@ export default function(app: App) { app.component('MkwActivity', defineAsyncComponent(() => import('./activity.vue'))); app.component('MkwPhotos', defineAsyncComponent(() => import('./photos.vue'))); app.component('MkwDigitalClock', defineAsyncComponent(() => import('./digital-clock.vue'))); + app.component('MkwUnixClock', defineAsyncComponent(() => import('./unix-clock.vue'))); app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue'))); app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue'))); app.component('MkwSlideshow', defineAsyncComponent(() => import('./slideshow.vue'))); @@ -36,6 +37,7 @@ export const widgets = [ 'activity', 'photos', 'digitalClock', + 'unixClock', 'federation', 'instanceCloud', 'postForm', diff --git a/packages/client/src/widgets/memo.vue b/packages/client/src/widgets/memo.vue index 8670cb2bac..14cc2a4e4a 100644 --- a/packages/client/src/widgets/memo.vue +++ b/packages/client/src/widgets/memo.vue @@ -1,21 +1,22 @@ <template> <MkContainer :show-header="widgetProps.showHeader" class="mkw-memo"> - <template #header><i class="fas fa-sticky-note"></i>{{ $ts._widgets.memo }}</template> + <template #header><i class="fas fa-sticky-note"></i>{{ i18n.ts._widgets.memo }}</template> <div class="otgbylcu"> - <textarea v-model="text" :placeholder="$ts.placeholder" @input="onChange"></textarea> - <button :disabled="!changed" class="_buttonPrimary" @click="saveMemo">{{ $ts.save }}</button> + <textarea v-model="text" :placeholder="i18n.ts.placeholder" @input="onChange"></textarea> + <button :disabled="!changed" class="_buttonPrimary" @click="saveMemo">{{ i18n.ts.save }}</button> </div> </MkContainer> </template> <script lang="ts" setup> import { onMounted, onUnmounted, reactive, ref, watch } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import MkContainer from '@/components/ui/container.vue'; import { defaultStore } from '@/store'; +import { i18n } from '@/i18n'; const name = 'memo'; diff --git a/packages/client/src/widgets/notifications.vue b/packages/client/src/widgets/notifications.vue index 18c546ee74..05b24e5cba 100644 --- a/packages/client/src/widgets/notifications.vue +++ b/packages/client/src/widgets/notifications.vue @@ -1,6 +1,6 @@ <template> <MkContainer :style="`height: ${widgetProps.height}px;`" :show-header="widgetProps.showHeader" :scrollable="true" class="mkw-notifications"> - <template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template> + <template #header><i class="fas fa-bell"></i>{{ i18n.ts.notifications }}</template> <template #func><button class="_button" @click="configureNotification()"><i class="fas fa-cog"></i></button></template> <div> @@ -10,12 +10,13 @@ </template> <script lang="ts" setup> -import { GetFormResultType } from '@/scripts/form'; +import { defineAsyncComponent } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/ui/container.vue'; import XNotifications from '@/components/notifications.vue'; import * as os from '@/os'; -import { defineAsyncComponent } from 'vue'; +import { i18n } from '@/i18n'; const name = 'notifications'; @@ -57,7 +58,7 @@ const configureNotification = () => { const { includingTypes } = res; widgetProps.includingTypes = includingTypes; save(); - } + }, }, 'closed'); }; diff --git a/packages/client/src/widgets/online-users.vue b/packages/client/src/widgets/online-users.vue index 4122a82657..e9ab79b111 100644 --- a/packages/client/src/widgets/online-users.vue +++ b/packages/client/src/widgets/online-users.vue @@ -1,6 +1,6 @@ <template> <div class="mkw-onlineUsers" :class="{ _panel: !widgetProps.transparent, pad: !widgetProps.transparent }"> - <I18n v-if="onlineUsersCount" :src="$ts.onlineUsersCount" text-tag="span" class="text"> + <I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" text-tag="span" class="text"> <template #n><b>{{ onlineUsersCount }}</b></template> </I18n> </div> @@ -12,6 +12,7 @@ import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExp import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const name = 'onlineUsers'; diff --git a/packages/client/src/widgets/photos.vue b/packages/client/src/widgets/photos.vue index 5d9b9e2984..41bec5dc56 100644 --- a/packages/client/src/widgets/photos.vue +++ b/packages/client/src/widgets/photos.vue @@ -1,11 +1,12 @@ <template> <MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" :class="$style.root" :data-transparent="widgetProps.transparent ? true : null" class="mkw-photos"> - <template #header><i class="fas fa-camera"></i>{{ $ts._widgets.photos }}</template> + <template #header><i class="fas fa-camera"></i>{{ i18n.ts._widgets.photos }}</template> <div class=""> <MkLoading v-if="fetching"/> <div v-else :class="$style.stream"> - <div v-for="(image, i) in images" :key="i" + <div + v-for="(image, i) in images" :key="i" :class="$style.img" :style="`background-image: url(${thumbnail(image)})`" ></div> @@ -16,13 +17,14 @@ <script lang="ts" setup> import { onMounted, onUnmounted, reactive, ref } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; import { stream } from '@/stream'; import { getStaticImageUrl } from '@/scripts/get-static-image-url'; import * as os from '@/os'; import MkContainer from '@/components/ui/container.vue'; import { defaultStore } from '@/store'; +import { i18n } from '@/i18n'; const name = 'photos'; @@ -70,7 +72,7 @@ const thumbnail = (image: any): string => { os.api('drive/stream', { type: 'image/*', - limit: 9 + limit: 9, }).then(res => { images.value = res; fetching.value = false; diff --git a/packages/client/src/widgets/server-metric/index.vue b/packages/client/src/widgets/server-metric/index.vue index 9e86b811d1..3350620ad8 100644 --- a/packages/client/src/widgets/server-metric/index.vue +++ b/packages/client/src/widgets/server-metric/index.vue @@ -1,6 +1,6 @@ <template> <MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent"> - <template #header><i class="fas fa-server"></i>{{ $ts._widgets.serverMetric }}</template> + <template #header><i class="fas fa-server"></i>{{ i18n.ts._widgets.serverMetric }}</template> <template #func><button class="_button" @click="toggleView()"><i class="fas fa-sort"></i></button></template> <div v-if="meta" class="mkw-serverMetric"> @@ -15,16 +15,17 @@ <script lang="ts" setup> import { onMounted, onUnmounted, ref } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from '../widget'; -import MkContainer from '@/components/ui/container.vue'; import XCpuMemory from './cpu-mem.vue'; import XNet from './net.vue'; import XCpu from './cpu.vue'; import XMemory from './mem.vue'; import XDisk from './disk.vue'; +import MkContainer from '@/components/ui/container.vue'; +import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { stream } from '@/stream'; +import { i18n } from '@/i18n'; const name = 'serverMetric'; diff --git a/packages/client/src/widgets/slideshow.vue b/packages/client/src/widgets/slideshow.vue index c286312161..e317b8ab94 100644 --- a/packages/client/src/widgets/slideshow.vue +++ b/packages/client/src/widgets/slideshow.vue @@ -2,7 +2,7 @@ <div class="kvausudm _panel mkw-slideshow" :style="{ height: widgetProps.height + 'px' }"> <div @click="choose"> <p v-if="widgetProps.folderId == null"> - {{ $ts.folder }} + {{ i18n.ts.folder }} </p> <p v-if="widgetProps.folderId != null && images.length === 0 && !fetching">{{ $t('no-image') }}</p> <div ref="slideA" class="slide a"></div> @@ -17,6 +17,7 @@ import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExp import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const name = 'slideshow'; diff --git a/packages/client/src/widgets/trends.vue b/packages/client/src/widgets/trends.vue index 0f34ea6341..8d11b69cb8 100644 --- a/packages/client/src/widgets/trends.vue +++ b/packages/client/src/widgets/trends.vue @@ -1,6 +1,6 @@ <template> <MkContainer :show-header="widgetProps.showHeader" class="mkw-trends"> - <template #header><i class="fas fa-hashtag"></i>{{ $ts._widgets.trends }}</template> + <template #header><i class="fas fa-hashtag"></i>{{ i18n.ts._widgets.trends }}</template> <div class="wbrkwala"> <MkLoading v-if="fetching"/> @@ -25,6 +25,7 @@ import MkContainer from '@/components/ui/container.vue'; import MkMiniChart from '@/components/mini-chart.vue'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; +import { i18n } from '@/i18n'; const name = 'hashtags'; diff --git a/packages/client/src/widgets/unix-clock.vue b/packages/client/src/widgets/unix-clock.vue new file mode 100644 index 0000000000..c9e2b4b92a --- /dev/null +++ b/packages/client/src/widgets/unix-clock.vue @@ -0,0 +1,116 @@ +<template> +<div class="mkw-unixClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> + <div v-if="widgetProps.showLabel" class="label">UNIX time</div> + <div class="time"> + <span v-text="ss"></span> + <span v-if="widgetProps.showMs" class="colon" :class="{ showColon }">:</span> + <span v-if="widgetProps.showMs" v-text="ms"></span> + </div> + <div v-if="widgetProps.showLabel" class="label">UTC</div> +</div> +</template> + +<script lang="ts" setup> +import { onUnmounted, ref, watch } from 'vue'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; + +const name = 'unixClock'; + +const widgetPropsDef = { + transparent: { + type: 'boolean' as const, + default: false, + }, + fontSize: { + type: 'number' as const, + default: 1.5, + step: 0.1, + }, + showMs: { + type: 'boolean' as const, + default: true, + }, + showLabel: { + type: 'boolean' as const, + default: true, + }, +}; + +type WidgetProps = GetFormResultType<typeof widgetPropsDef>; + +// ç¾æ™‚点ã§ã¯vueã®åˆ¶é™ã«ã‚ˆã‚Šimportã—ãŸtypeをジェãƒãƒªãƒƒã‚¯ã«æ¸¡ã›ãªã„ +//const props = defineProps<WidgetComponentProps<WidgetProps>>(); +//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); +const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); +const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); + +const { widgetProps, configure } = useWidgetPropsManager(name, + widgetPropsDef, + props, + emit, +); + +let intervalId; +const ss = ref(''); +const ms = ref(''); +const showColon = ref(false); +let prevSec: string | null = null; + +watch(showColon, (v) => { + if (v) { + window.setTimeout(() => { + showColon.value = false; + }, 30); + } +}); + +const tick = () => { + const now = new Date(); + ss.value = Math.floor(now.getTime() / 1000).toString(); + ms.value = Math.floor(now.getTime() % 1000 / 10).toString().padStart(2, '0'); + if (ss.value !== prevSec) showColon.value = true; + prevSec = ss.value; +}; + +tick(); + +watch(() => widgetProps.showMs, () => { + if (intervalId) window.clearInterval(intervalId); + intervalId = window.setInterval(tick, widgetProps.showMs ? 10 : 1000); +}, { immediate: true }); + +onUnmounted(() => { + window.clearInterval(intervalId); +}); + +defineExpose<WidgetComponentExpose>({ + name, + configure, + id: props.widget ? props.widget.id : null, +}); +</script> + +<style lang="scss" scoped> +.mkw-unixClock { + padding: 16px 0; + text-align: center; + + > .label { + font-size: 65%; + opacity: 0.7; + } + + > .time { + > .colon { + opacity: 0; + transition: opacity 1s ease; + + &.showColon { + opacity: 1; + transition: opacity 0s; + } + } + } +} +</style> diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock index af3af22fc9..6cc63a261b 100644 --- a/packages/client/yarn.lock +++ b/packages/client/yarn.lock @@ -2,21 +2,11 @@ # yarn lockfile v1 -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== - "@babel/parser@^7.16.4": version "7.16.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.6.tgz#8f194828193e8fa79166f34a4b4e52f3e769a314" integrity sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ== -"@babel/parser@^7.6.0", "@babel/parser@^7.9.6": - version "7.13.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.9.tgz#ca34cb95e1c2dd126863a84465ae8ef66114be99" - integrity sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw== - "@babel/runtime@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" @@ -31,15 +21,6 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/types@^7.6.1", "@babel/types@^7.9.6": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" - integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - "@cropper/element-canvas@^2.0.0-beta": version "2.0.0-beta" resolved "https://registry.yarnpkg.com/@cropper/element-canvas/-/element-canvas-2.0.0-beta.tgz#9501e6a2512a78c7503f2974b1fc65f90c7fecca" @@ -196,10 +177,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@fortawesome/fontawesome-free@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1" - integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg== +"@fortawesome/fontawesome-free@6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.2.tgz#d18880eddeadd42b1c64cb559f2f3d13d47a4a64" + integrity sha512-XwWADtfdSN73/udaFm+1mnGIj/ShDZNFMe/PRoqv3FhQ4GNI2PUN70yFTPsjq65Lw2C9i4TG5/hTbxXIXVCiqQ== "@hapi/hoek@^9.0.0": version "9.2.0" @@ -366,11 +347,6 @@ "@types/vinyl-fs" "*" chokidar "^3.3.1" -"@types/is-url@1.2.30": - version "1.2.30" - resolved "https://registry.yarnpkg.com/@types/is-url/-/is-url-1.2.30.tgz#85567e8bee4fee69202bc3448f9fb34b0d56c50a" - integrity sha512-AnlNFwjzC8XLda5VjRl4ItSd8qp8pSNowvsut0WwQyBWHpOxjxRJm8iO6uETWqEyLdYdb9/1j+Qd9gQ4l5I4fw== - "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" @@ -396,11 +372,6 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/mocha@9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" - integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== - "@types/node@*": version "16.6.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" @@ -411,30 +382,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.9.tgz#b97c057e6138adb7b720df2bd0264b03c9f504fd" integrity sha512-CMjgRNsks27IDwI785YMY0KLt3co/c0cQ5foxHYv/shC2w8oOnVwz5Ubq1QG5KzrcW+AXk6gzdnxIkDnTvzu3g== -"@types/oauth@0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@types/oauth/-/oauth-0.9.1.tgz#e17221e7f7936b0459ae7d006255dff61adca305" - integrity sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A== - dependencies: - "@types/node" "*" - "@types/punycode@2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/punycode/-/punycode-2.1.0.tgz#89e4f3d09b3f92e87a80505af19be7e0c31d4e83" integrity sha512-PG5aLpW6PJOeV2fHRslP4IOMWn+G+Uq8CfnyJ+PDS8ndCbU+soO+fB3NKCKo0p/Jh2Y4aPaiQZsrOXFdzpcA6g== -"@types/qrcode@1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74" - integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ== - dependencies: - "@types/node" "*" - -"@types/random-seed@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@types/random-seed/-/random-seed-0.3.3.tgz#7741f7b0a4513198a9396ce4ad25832f799a6727" - integrity sha512-kHsCbIRHNXJo6EN5W8EA5b4i1hdT6jaZke5crBPLUcLqaLdZ0QBq8QVMbafHzhjFF83Cl9qlee2dChD18d/kPg== - "@types/seedrandom@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.2.tgz#7f30db28221067a90b02e73ffd46b6685b18df1a" @@ -494,20 +446,6 @@ "@types/expect" "^1.20.4" "@types/node" "*" -"@types/websocket@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.5.tgz#3fb80ed8e07f88e51961211cd3682a3a4a81569c" - integrity sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ== - dependencies: - "@types/node" "*" - -"@types/ws@8.5.3": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" - integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== - dependencies: - "@types/node" "*" - "@types/yauzl@^2.9.1": version "2.9.2" resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" @@ -515,14 +453,14 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" - integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== +"@typescript-eslint/eslint-plugin@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe" + integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/type-utils" "5.30.6" - "@typescript-eslint/utils" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/type-utils" "5.31.0" + "@typescript-eslint/utils" "5.31.0" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -530,76 +468,71 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" - integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== +"@typescript-eslint/parser@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" + integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" - integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== +"@typescript-eslint/scope-manager@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" + integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" -"@typescript-eslint/type-utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" - integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== +"@typescript-eslint/type-utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9" + integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w== dependencies: - "@typescript-eslint/utils" "5.30.6" + "@typescript-eslint/utils" "5.31.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" - integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== +"@typescript-eslint/types@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" + integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== -"@typescript-eslint/typescript-estree@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" - integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== +"@typescript-eslint/typescript-estree@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" + integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" - integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== +"@typescript-eslint/utils@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd" + integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" - integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== +"@typescript-eslint/visitor-keys@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" + integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== dependencies: - "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/types" "5.31.0" eslint-visitor-keys "^3.3.0" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - "@vitejs/plugin-vue@3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.0.1.tgz#b6af8f782485374bbb5fe09edf067a845bf4caae" @@ -695,23 +628,11 @@ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702" integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw== -abort-controller@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - acorn@^8.7.1: version "8.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" @@ -735,7 +656,7 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@4.1.1, ansi-colors@^4.1.1: +ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== @@ -803,11 +724,6 @@ array.prototype.flat@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -815,11 +731,6 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -assert-never@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe" - integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw== - assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" @@ -855,13 +766,6 @@ autosize@5.0.1: resolved "https://registry.yarnpkg.com/autosize/-/autosize-5.0.1.tgz#ed269b0fa9b7eb47627048a1bb3299e99e003a0f" integrity sha512-UIWUlE4TOVPNNj2jjrU39wI4hEYbneUypEqcyRmRFIx5CC2gNdg3rQr+Zh7/3h6egbBvm33TDQjNQKtj9Tk1HA== -autwh@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/autwh/-/autwh-0.1.0.tgz#24a5300923309d105133401a2568f9c8ab7d7e03" - integrity sha512-IkGZ4kjVlZMkEmDiVtZpGG3lDGHPqsMBIh4IpQKN7idYOJ5EGedqKPO+ychNqh8zrJEEqYsN0NcBkcmoE2uFAw== - dependencies: - oauth "0.9.15" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -879,13 +783,6 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -babel-walk@3.0.0-canary-5: - version "3.0.0-canary-5" - resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" - integrity sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw== - dependencies: - "@babel/types" "^7.9.6" - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -936,13 +833,6 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -950,14 +840,14 @@ braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -broadcast-channel@4.13.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.13.0.tgz#21387b2602b9e9ec3b97b03bd8a8d2c198352ff6" - integrity sha512-fcDr8QNJ4SOb6jyjUNZatVNmcHtSWfW4PFcs4xIEFZAtorKCIFoEYtjIjaQ4c0jrbr/Bl8NIwOWiLSyspoAnEQ== +broadcast-channel@4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.14.0.tgz#cd2ce466128130ec3a93f7c1f1ed01d658575e35" + integrity sha512-uNzxOgBQ+boWCRDESLNg3zZWQ3iz/X7j/uD8pAfr4/S7wQerXVvJI/SBKd9J6ckaPt2jil0gq+7l+3b+kuxJYw== dependencies: "@babel/runtime" "^7.16.0" detect-node "^2.1.0" - microtime "3.0.0" + microtime "3.1.0" oblivious-set "1.1.1" p-queue "6.6.2" rimraf "3.0.2" @@ -967,11 +857,6 @@ broadcast-channel@4.13.0: version "2.2.1-misskey.2" resolved "git+https://github.com/misskey-dev/browser-image-resizer#a58834f5fe2af9f9f31ff115121aef3de6f9d416" -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -985,13 +870,6 @@ buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" -bufferutil@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" - integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA== - dependencies: - node-gyp-build "~3.7.0" - cachedir@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" @@ -1010,16 +888,6 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -1046,17 +914,10 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -character-parser@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" - integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= - dependencies: - is-regex "^1.0.3" - -chart.js@3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.8.0.tgz#c6c14c457b9dc3ce7f1514a59e9b262afd6f1a94" - integrity sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg== +chart.js@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.8.2.tgz#e3ebb88f7072780eec4183a788a990f4a58ba7a1" + integrity sha512-7rqSlHWMUKFyBDOJvmFGW2lxULtcwaPLegDjX/Nu5j6QybY+GCiQkEY+6cqHw62S5tcwXMD8Y+H5OBGoR7d+ZQ== chartjs-adapter-date-fns@2.0.0: version "2.0.0" @@ -1080,7 +941,7 @@ check-more-types@2.24.0, check-more-types@^2.24.0: resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= -chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^3.3.1, chokidar@^3.5.3: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.3.1, chokidar@^3.5.3: version "3.3.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== @@ -1129,24 +990,6 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1206,21 +1049,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -constantinople@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" - integrity sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw== - dependencies: - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.1" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1260,10 +1088,10 @@ csstype@^2.6.8: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== -cypress@10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" - integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== +cypress@10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.1.tgz#7fab4ef43481c05a9a17ebe9a0ec860e15b95a19" + integrity sha512-As9HrExjAgpgjCnbiQCuPdw5sWKx5HUJcK2EOKziu642akwufr/GUeqL5UnCPYXTyyibvEdWT/pSC2qnGW/e5w== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -1308,14 +1136,6 @@ cypress@10.3.0: untildify "^4.0.0" yauzl "^2.10.0" -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1323,10 +1143,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-fns@2.28.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" - integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== +date-fns@2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.1.tgz#9667c2615525e552b5135a3116b95b1961456e60" + integrity sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw== dayjs@^1.10.4: version "1.10.6" @@ -1340,14 +1160,7 @@ debug@4.3.2, debug@^4.3.2: dependencies: ms "2.1.2" -debug@4.3.4, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^2.2.0, debug@^2.6.9: +debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -1368,15 +1181,12 @@ debug@^4.1.1: dependencies: ms "2.1.2" -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" deep-is@^0.1.3: version "0.1.3" @@ -1400,16 +1210,6 @@ detect-node@2.1.0, detect-node@^2.1.0: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -dijkstrajs@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.1.tgz#d3cd81221e3ea40742cfcde556d4e99e98ddc71b" - integrity sha1-082BIh4+pAdCz83lVtTpnpjdxxs= - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -1431,11 +1231,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -doctypes@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" - integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= - duplexer@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -1454,11 +1249,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -encode-utf8@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" - integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== - end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1508,32 +1298,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - esbuild-android-64@0.14.48: version "0.14.48" resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3" @@ -1660,26 +1424,21 @@ esbuild@^0.14.47: esbuild-windows-64 "0.14.48" esbuild-windows-arm64 "0.14.48" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - escape-regexp@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/escape-regexp/-/escape-regexp-0.0.1.tgz#f44bda12d45bbdf9cb7f862ee7e4827b3dd32254" integrity sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ= -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + eslint-import-resolver-node@^0.3.6: version "0.3.6" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" @@ -1715,10 +1474,10 @@ eslint-plugin-import@2.26.0: resolve "^1.22.0" tsconfig-paths "^3.14.1" -eslint-plugin-vue@9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz#b7ca02b2ce8218b7586346440fc61c2655db353a" - integrity sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g== +eslint-plugin-vue@9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.3.0.tgz#c3f5ce515dae387e062428725c5cf96098d9da0b" + integrity sha512-iscKKkBZgm6fGZwFt6poRoWC0Wy2dQOlwUPW++CiPoQiw1enctV2Hj5DBzzjJZfyqs+FAXhgzL4q0Ww03AgSmQ== dependencies: eslint-utils "^3.0.0" natural-compare "^1.4.0" @@ -1761,10 +1520,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.19.0: - version "8.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" - integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== +eslint@8.20.0: + version "8.20.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" + integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" @@ -1868,11 +1627,6 @@ event-stream@=3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - eventemitter2@^6.4.3: version "6.4.4" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.4.tgz#aa96e8275c4dbeb017a5d0e03780c65612a1202b" @@ -1920,13 +1674,6 @@ executable@^4.1.1: dependencies: pify "^2.2.0" -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - dependencies: - type "^2.0.0" - extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -2010,13 +1757,6 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -feed@4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e" - integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ== - dependencies: - xml-js "^1.6.11" - figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -2038,14 +1778,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -2053,14 +1785,6 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -2069,11 +1793,6 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - flatted@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" @@ -2147,11 +1866,6 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" @@ -2209,18 +1923,6 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.1.3: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -2320,11 +2022,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - http-signature@~1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" @@ -2367,9 +2064,9 @@ ignore@^5.2.0: integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== immutable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" - integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" + integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.2.1" @@ -2421,16 +2118,6 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -ip-regex@^4.0.0, ip-regex@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== - -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -2496,14 +2183,6 @@ is-date-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== -is-expression@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" - integrity sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A== - dependencies: - acorn "^7.1.1" - object-assign "^4.1.1" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2529,13 +2208,6 @@ is-installed-globally@~0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" -is-ip@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" - integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== - dependencies: - ip-regex "^4.0.0" - is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" @@ -2558,23 +2230,6 @@ is-path-inside@^3.0.2: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-promise@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - -is-regex@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== - dependencies: - has "^1.0.3" - is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -2614,7 +2269,7 @@ is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -2652,12 +2307,7 @@ joi@^17.4.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" -js-stringify@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" - integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= - -js-yaml@4.1.0, js-yaml@^4.1.0: +js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -2684,7 +2334,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -2736,14 +2386,6 @@ jsprim@^2.0.2: json-schema "0.4.0" verror "1.10.0" -jstransformer@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" - integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= - dependencies: - is-promise "^2.0.0" - promise "^7.0.1" - katex@0.15.6: version "0.15.6" resolved "https://registry.yarnpkg.com/katex/-/katex-0.15.6.tgz#c4e2f6ced2ac4de1ef6f737fe7c67d3026baa0e5" @@ -2785,20 +2427,6 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -2809,12 +2437,12 @@ lodash.once@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash@^4.17.19, lodash@^4.17.21: +lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@4.1.0, log-symbols@^4.0.0: +log-symbols@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -2866,10 +2494,10 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -mfm-js@0.23.0-canary.1: - version "0.23.0-canary.1" - resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0-canary.1.tgz#1b7b7635f18bed9776054406b72e6bd613c8d0eb" - integrity sha512-SkMrW1rQAv+mFGtLKN9DSv6vxSREDu8ChmkBl1Ch5sQfp47BhuvcRg5EKGmt3WAQRAOylXYMg8wVYR7C5BHKeA== +mfm-js@0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0.tgz#1d1477761aa8259ddcac2e6882df53ed9ca5b82b" + integrity sha512-2Oe/YicoaP1EU2y9JB5729/PQLZK/7aAVomeJkp1h4XGP2//NMDC+DHkBbSO71U3GG086SAZM0JBB/hdPPSEXg== dependencies: twemoji-parser "14.0.0" @@ -2889,13 +2517,13 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -microtime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.0.0.tgz#d140914bde88aa89b4f9fd2a18620b435af0f39b" - integrity sha512-SirJr7ZL4ow2iWcb54bekS4aWyBQNVcEDBiwAz9D/sTgY59A+uE8UJU15cp5wyZmPBwg/3zf8lyCJ5NUe1nVlQ== +microtime@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/microtime/-/microtime-3.1.0.tgz#599a71250e3116c59f0fe5271dae4cc44321869c" + integrity sha512-GcjhfC2y/DF2znac8IRwri7+YUIy34QRHz/iZK3bHrh74qrNNOpAJQwiOMnIG+v1J0K4eiqd+RiGzN3F1eofTQ== dependencies: - node-addon-api "^1.2.0" - node-gyp-build "^3.8.0" + node-addon-api "^5.0.0" + node-gyp-build "^4.4.0" mime-db@1.44.0: version "1.44.0" @@ -2914,13 +2542,6 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" - minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -2949,34 +2570,6 @@ misskey-js@0.0.14: eventemitter3 "^4.0.7" reconnecting-websocket "^4.4.0" -mocha@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" - integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - nanoid "3.3.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2987,7 +2580,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2997,7 +2590,7 @@ mylas@^2.1.9: resolved "https://registry.yarnpkg.com/mylas/-/mylas-2.1.9.tgz#8329626f95c0ce522ca7d3c192eca6221d172cdc" integrity sha512-pa+cQvmhoM8zzgitPYZErmDt9EdTNVnXsH1XFjMeM4TyG4FFcgxrvK1+jwabVFwUOEDaSWuXBMjg43kqt/Ydlg== -nanoid@3.3.3, nanoid@^3.3.3: +nanoid@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== @@ -3012,35 +2605,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -nested-property@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d" - integrity sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA== - -netmask@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - -node-addon-api@^1.2.0: - version "1.7.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" - integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== - -node-gyp-build@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25" - integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A== +node-addon-api@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" + integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== -node-gyp-build@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" - integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== +node-gyp-build@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -3061,16 +2634,6 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -oauth@0.9.15: - version "0.9.15" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" - integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - object-inspect@^1.11.0, object-inspect@^1.9.0: version "1.11.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" @@ -3148,20 +2711,6 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" - integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== - dependencies: - p-try "^2.0.0" - p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -3169,20 +2718,6 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -3210,11 +2745,6 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3227,11 +2757,6 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -3269,10 +2794,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -photoswipe@5.2.8: - version "5.2.8" - resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.2.8.tgz#c276a17dac575c746262472ceb594fc390786176" - integrity sha512-tsbG+1ILcli4mR3Tzp4xdxCUSSJaz14wct4dSznk3suVst9tBdt6vDlSASOw/VFqSkcDjbRUA1tC1LoF2DCkzg== +photoswipe@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.3.0.tgz#fe118b147dddaf58ccc17c9403c7d7148805f8d2" + integrity sha512-vZMwziQorjiagzX7EvWimVT0YHO0DWNtR9UT6cv3yW1FA199LgsTpj4ziB2oJ/X/197gKmi56Oux5PudWUAmuw== picocolors@^1.0.0: version "1.0.0" @@ -3301,11 +2826,6 @@ plimit-lit@^1.2.6: dependencies: queue-lit "^1.2.7" -pngjs@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" - integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== - postcss-selector-parser@^6.0.9: version "6.0.9" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" @@ -3347,28 +2867,6 @@ prismjs@1.28.0: resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6" integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== -private-ip@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/private-ip/-/private-ip-2.3.3.tgz#1e80ff8443e5ac78f555631aec3ea6ff027fa6aa" - integrity sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw== - dependencies: - ip-regex "^4.3.0" - ipaddr.js "^2.0.1" - is-ip "^3.1.0" - netmask "^2.0.2" - -promise-limit@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/promise-limit/-/promise-limit-2.7.0.tgz#eb5737c33342a030eaeaecea9b3d3a93cb592b26" - integrity sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw== - -promise@^7.0.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - proxy-from-env@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" @@ -3386,109 +2884,6 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== -pug-attrs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" - integrity sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA== - dependencies: - constantinople "^4.0.1" - js-stringify "^1.0.2" - pug-runtime "^3.0.0" - -pug-code-gen@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce" - integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg== - dependencies: - constantinople "^4.0.1" - doctypes "^1.1.0" - js-stringify "^1.0.2" - pug-attrs "^3.0.0" - pug-error "^2.0.0" - pug-runtime "^3.0.0" - void-elements "^3.1.0" - with "^7.0.0" - -pug-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5" - integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ== - -pug-filters@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" - integrity sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A== - dependencies: - constantinople "^4.0.1" - jstransformer "1.0.0" - pug-error "^2.0.0" - pug-walk "^2.0.0" - resolve "^1.15.1" - -pug-lexer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" - integrity sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w== - dependencies: - character-parser "^2.2.0" - is-expression "^4.0.0" - pug-error "^2.0.0" - -pug-linker@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" - integrity sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw== - dependencies: - pug-error "^2.0.0" - pug-walk "^2.0.0" - -pug-load@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" - integrity sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ== - dependencies: - object-assign "^4.1.1" - pug-walk "^2.0.0" - -pug-parser@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" - integrity sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw== - dependencies: - pug-error "^2.0.0" - token-stream "1.0.0" - -pug-runtime@^3.0.0, pug-runtime@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" - integrity sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg== - -pug-strip-comments@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" - integrity sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ== - dependencies: - pug-error "^2.0.0" - -pug-walk@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" - integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ== - -pug@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535" - integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw== - dependencies: - pug-code-gen "^3.0.2" - pug-filters "^4.0.0" - pug-lexer "^5.0.1" - pug-linker "^4.0.0" - pug-load "^3.0.0" - pug-parser "^6.0.0" - pug-runtime "^3.0.1" - pug-strip-comments "^2.0.0" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -3502,16 +2897,6 @@ punycode@2.1.1, punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qrcode@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" - integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== - dependencies: - dijkstrajs "^1.0.1" - encode-utf8 "^1.0.3" - pngjs "^5.0.0" - yargs "^15.3.1" - qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -3527,20 +2912,6 @@ queue-lit@^1.2.7: resolved "https://registry.yarnpkg.com/queue-lit/-/queue-lit-1.2.7.tgz#69081656c9e7b81f09770bb2de6aa007f1a90763" integrity sha512-K/rTdggORRcmf3+c89ijPlgJ/ldGP4oBj6Sm7VcTup4B2clf03Jo8QaXTnMst4EEQwkUbOZFN4frKocq2I85gw== -random-seed@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/random-seed/-/random-seed-0.3.0.tgz#d945f2e1f38f49e8d58913431b8bf6bb937556cd" - integrity sha1-2UXy4fOPSejViRNDG4v2u5N1Vs0= - dependencies: - json-stringify-safe "^5.0.1" - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - rangestr@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/rangestr/-/rangestr-0.0.1.tgz#f72ff9246f10f2a7d7c16e14616f617be2c2635a" @@ -3558,11 +2929,6 @@ reconnecting-websocket@^4.4.0: resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783" integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng== -reflect-metadata@0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== - regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -3580,22 +2946,12 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.15.1, resolve@^1.20.0: +resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -3649,10 +3005,10 @@ rndstr@1.0.0: rangestr "0.0.1" seedrandom "2.4.2" -rollup@2.76.0: - version "2.76.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.76.0.tgz#c69fe03db530ac53fcb9523b3caa0d3c0b9491a1" - integrity sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA== +rollup@2.77.2: + version "2.77.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.2.tgz#6b6075c55f9cc2040a5912e6e062151e42e2c4e3" + integrity sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g== optionalDependencies: fsevents "~2.3.2" @@ -3692,12 +3048,7 @@ safari-14-idb-fix@^3.0.0: resolved "https://registry.yarnpkg.com/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz#450fc049b996ec7f3fd9ca2f89d32e0761583440" integrity sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog== -safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== @@ -3707,20 +3058,15 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@1.53.0: - version "1.53.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.53.0.tgz#eab73a7baac045cc57ddc1d1ff501ad2659952eb" - integrity sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ== +sass@1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.0.tgz#24873673265e2a4fe3d3a997f714971db2fba1f4" + integrity sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - seedrandom@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.2.tgz#18d78c41287d13aff8eadb29e235938b248aa9ff" @@ -3752,18 +3098,6 @@ semver@^7.3.6, semver@^7.3.7: dependencies: lru-cache "^6.0.0" -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3936,18 +3270,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@8.1.1, supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -3955,6 +3282,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -3975,10 +3309,10 @@ textarea-caret@3.1.0: resolved "https://registry.yarnpkg.com/textarea-caret/-/textarea-caret-3.1.0.tgz#5d5a35bb035fd06b2ff0e25d5359e97f2655087f" integrity sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q== -three@0.142.0: - version "0.142.0" - resolved "https://registry.yarnpkg.com/three/-/three-0.142.0.tgz#89e226a16221f212eb1d40f0786604b711f28aed" - integrity sha512-ESjPO+3geFr+ZUfVMpMnF/eVU2uJPOh0e2ZpMFqjNca1wApS9lJb7E4MjwGIczgt9iuKd8PEm6Pfgp2bJ92Xtg== +three@0.143.0: + version "0.143.0" + resolved "https://registry.yarnpkg.com/three/-/three-0.143.0.tgz#1455bca132cc2b20beb7f41d313e10c29e5ed9df" + integrity sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg== throttle-debounce@5.0.0: version "5.0.0" @@ -4007,11 +3341,6 @@ tmp@~0.2.1: dependencies: rimraf "^3.0.0" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -4019,11 +3348,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -token-stream@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" - integrity sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ= - tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -4032,10 +3356,10 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" -tsc-alias@1.6.11: - version "1.6.11" - resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.6.11.tgz#d6d83f030ad11f48e4ead8ec5729929e5e60519b" - integrity sha512-mXEM21WriTJMQyo07B4Kc2nNFFk/1qOjU+jZ0ymXOyLz/A8J+dIBkimqZrh3s/x1qLGoJ1cNZQxa8GGoWOGX1Q== +tsc-alias@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.7.0.tgz#733482751133a25b97608ee424f8a1f085fcaaef" + integrity sha512-n/K6g8S7Ec7Y/A2Z77Ikp2Uv1S1ERtT63ni69XV4W1YPT4rnNmz8ItgIiJYvKfFnKfqcZQ81UPjoKpMTxaC/rg== dependencies: chokidar "^3.5.3" commander "^9.0.0" @@ -4114,23 +3438,6 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" - integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - typescript@4.7.4: version "4.7.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" @@ -4176,13 +3483,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -utf-8-validate@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3" - integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw== - dependencies: - node-gyp-build "~3.7.0" - util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -4198,11 +3498,6 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v-debounce@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/v-debounce/-/v-debounce-0.1.2.tgz#cab75df7def2783215bf449ef85c69c2decf0a55" - integrity sha1-yrdd997yeDIVv0Se+Fxpwt7PClU= - v8-compile-cache@^2.0.3: version "2.2.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" @@ -4222,10 +3517,10 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.2.tgz#2a7b4642c53ae066cf724e7e581d6c1fd24e2c32" - integrity sha512-TAqydxW/w0U5AoL5AsD9DApTvGb2iNbGs3sN4u2VdT1GFkQVUfgUldt+t08TZgi23uIauh1TUOQJALduo9GXqw== +vite@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.4.tgz#c61688d6b97573e96cf5ac25f2d68597b5ce68e8" + integrity sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA== dependencies: esbuild "^0.14.47" postcss "^8.4.14" @@ -4234,11 +3529,6 @@ vite@3.0.2: optionalDependencies: fsevents "~2.3.2" -void-elements@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" - integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= - vue-eslint-parser@^9.0.1: version "9.0.2" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz#d2535516f3f55adb387939427fe741065eb7948a" @@ -4286,18 +3576,6 @@ wait-on@6.0.0: minimist "^1.2.5" rxjs "^7.1.0" -websocket@1.0.34: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -4309,11 +3587,6 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -4321,26 +3594,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -with@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" - integrity sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w== - dependencies: - "@babel/parser" "^7.9.6" - "@babel/types" "^7.9.6" - assert-never "^1.2.1" - babel-walk "3.0.0-canary-5" - word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -workerpool@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" - integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -4364,96 +3622,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" - integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== - -xml-js@^1.6.11: - version "1.6.11" - resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" - integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== - dependencies: - sax "^1.2.4" - xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== -y18n@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" - integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== - -y18n@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" - integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== - -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@20.2.4, yargs-parser@^20.2.2: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^15.3.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" @@ -46,6 +46,46 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -194,50 +234,55 @@ dependencies: "@types/node" "*" -"@typescript-eslint/parser@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" - integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== +"@typescript-eslint/parser@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" + integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "5.31.0" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/typescript-estree" "5.31.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" - integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== +"@typescript-eslint/scope-manager@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" + integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" -"@typescript-eslint/types@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" - integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== +"@typescript-eslint/types@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" + integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== -"@typescript-eslint/typescript-estree@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" - integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== +"@typescript-eslint/typescript-estree@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" + integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/visitor-keys" "5.31.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" - integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== +"@typescript-eslint/visitor-keys@5.31.0": + version "5.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" + integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== dependencies: - "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/types" "5.31.0" eslint-visitor-keys "^3.3.0" +acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -648,9 +693,9 @@ buffer-equal@^1.0.0: integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer@^5.6.0: version "5.7.1" @@ -1084,10 +1129,10 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" -cypress@10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" - integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== +cypress@10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.1.tgz#7fab4ef43481c05a9a17ebe9a0ec860e15b95a19" + integrity sha512-As9HrExjAgpgjCnbiQCuPdw5sWKx5HUJcK2EOKziu642akwufr/GUeqL5UnCPYXTyyibvEdWT/pSC2qnGW/e5w== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -3788,9 +3833,9 @@ source-map-resolve@^0.5.0: urix "^0.1.0" source-map-support@~0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -3810,11 +3855,6 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - sparkles@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" @@ -4034,12 +4074,13 @@ svgo@^0.7.0: whet.extend "~0.9.9" terser@^5.9.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351" - integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== + version "5.14.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" textextensions@^3.2.0: |