Merge branch 'develop' into sw-notification-action

This commit is contained in:
tamaina 2021-05-06 20:52:53 +09:00
commit 72fe859e03
129 changed files with 4778 additions and 906 deletions

View File

@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
node-version: [12.x, 14.x, 15.x]
node-version: [14.x, 16.x]
services:
postgres:

View File

@ -1 +1 @@
v14.15.5
v16.0.0

View File

@ -50,7 +50,7 @@ Configuration files are located in [`/.circleci`](/.circleci).
* Your PR should include all source files (e.g. `.png`, `.blend`) of your models (for later editing).
* Your PR must include the glTF binary files (`.glb`) of your models.
* Add a locale key `room.furnitures.YOUR_ITEM` at [`/locales/ja-JP.yml`](/locales/ja-JP.yml).
* Add a furniture definition at [`/src/client/app/common/scripts/room/furnitures.json5`](/src/client/app/common/scripts/room/furnitures.json5).
* Add a furniture definition at [`src/client/scripts/room/furnitures.json5`](src/client/scripts/room/furnitures.json5).
If you have no experience on 3D modeling, we suggest to use the free 3DCG software [Blender](https://www.blender.org/).
You can find information on glTF 2.0 at [glTF 2.0 — Blender Manual]( https://docs.blender.org/manual/en/dev/addons/io_scene_gltf2.html).

View File

@ -1,4 +1,4 @@
FROM node:14.15.5-alpine3.13 AS base
FROM node:16.0.0-alpine3.13 AS base
ENV NODE_ENV=production

View File

@ -5,7 +5,7 @@
import * as fs from 'fs';
import * as gulp from 'gulp';
import * as rimraf from 'rimraf';
import * as replace from 'gulp-replace';
const replace = require('gulp-replace');
const terser = require('gulp-terser');
const cssnano = require('gulp-cssnano');

View File

@ -111,7 +111,6 @@ customEmojis: "إيموجي مخصص"
addEmoji: "إضافة إيموجي"
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
autoAcceptFollowed: "اقبل طلبات المتابعة تلقائيا من الحسابات المتابَعة"
addAcount: "إضافة حساب"
loginFailed: "فشل الولوج"
showOnRemote: "رؤيته على مثيل الخادم البُعدي"
general: "الرئيسية"
@ -354,7 +353,6 @@ category: "الفئات"
tags: "الوسوم"
docSource: "مصدر هذا المستند"
createAccount: "أنشئ حسابًا"
existingAcount: "الحسابات الموجودة"
regenerate: "أعِد التوليد"
fontSize: "حجم الخط"
openImageInNewTab: "إفتح الصورة بصفحة جديدة"
@ -430,6 +428,10 @@ usageAmount: "الإستخدام"
capacity: "السعة"
inUse: "مستخدم"
info: "عن"
user: "المستخدمون"
administration: "إدارة "
expiration: "ينتهي استطلاع الرأي في"
middle: "متوسط"
_email:
_follow:
title: "يتابعك"

View File

@ -72,6 +72,7 @@ error: "Chyba"
somethingHappened: "Jejda. Něco se nepovedlo."
retry: "Opakovat"
pageLoadError: "Nepodařilo se načíst stránku"
privacy: "Soukromí"
follow: "Sledovaní"
unfollow: "Přestat sledovat"
renote: "Přeposlat"
@ -116,7 +117,6 @@ flagAsBotDescription: "Pokud je tento účet kontrolován programem zaškrtněte
flagAsCat: "Tenhle účet je kočka"
flagAsCatDescription: "Vyberte tuto možnost aby tento účet byl označen jako kočka."
autoAcceptFollowed: "Automaticky akceptovat následování od účtů které sledujete"
addAcount: "Přidat účet"
loginFailed: "Přihlášení se nezdařilo."
general: "Obecně"
wallpaper: "Obrázek na pozadí"
@ -149,6 +149,7 @@ clearQueue: "Vyčistit frontu"
clearQueueConfirmTitle: "Jste si jisti že zrušit všechny úlohy ve frontě?"
clearCachedFiles: "Vyprázdnit mezipaměť"
blockedInstances: "Blokované instance"
editProfile: "Upravit můj profil"
pinLimitExceeded: "Nemůžete připnout další poznámky."
intro: "Instalace Misskey byla dokončena! Prosím vytvořte admina."
done: "Hotovo"
@ -161,6 +162,7 @@ all: "Vše"
subscribing: "Odebíráte"
publishing: "Publikuji"
notResponding: "Neodpovídá"
instanceFollowing: "Následovníci na instanci"
instanceFollowers: "Následovníci na instanci"
instanceUsers: "Uživatelé této instance"
changePassword: "Změnit heslo"
@ -170,6 +172,7 @@ newPassword: "Nové heslo"
newPasswordRetype: "Nové heslo (znovu)"
attachFile: "Přiložit soubor"
more: "Více!"
featured: "Oblíbené poznámky"
usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
noSuchUser: "Uživatel nebyl nalezen"
announcements: "Oznámení"
@ -203,6 +206,8 @@ images: "Obrázky"
birthday: "Datum narození"
registeredDate: "Datum registrace"
location: "Lokace"
light: "Světlý"
dark: "Tmavý"
lightThemes: "Světlý vzhled"
darkThemes: "Tmavý vzhled"
syncDeviceDarkMode: "Synchronizovat tmavý vzhled s nastavením Vašeho systému"
@ -217,6 +222,10 @@ folderName: "Název složky"
createFolder: "Vytvořit složku"
renameFolder: "Přejmenovat složku"
deleteFolder: "Odstranit složku"
addFile: "Přidat soubor"
emptyFolder: "Tato složka je prázdná"
unableToDelete: "Nelze smazat"
inputNewFileName: "Zadejte nový název"
copyUrl: "Kopírovat URL"
rename: "Přejmenovat"
avatar: "Avatar"
@ -224,6 +233,7 @@ banner: "Baner"
nsfw: "NSFW"
disconnectedFromServer: "Spojení bylo přerušeno"
reload: "Aktualizovat"
doNothing: "Ignorovat"
watch: "Sledovat"
unwatch: "Přestat sledovat"
accept: "Souhlasím"
@ -254,6 +264,17 @@ iconUrl: "Favicon URL"
bannerUrl: "Baner URL"
basicInfo: "Základní informace"
hcaptcha: "hCaptcha"
hcaptchaSecretKey: "Tajný Klíč (Secret Key)"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Zapnout ReCAPTCHu"
recaptchaSecretKey: "Tajný Klíč (Secret Key)"
antennas: "Antény"
manageAntennas: "Spravovat Antény"
name: "Jméno"
antennaSource: "Zdroj Antény"
enableServiceworker: "Povolit ServiceWorker"
caseSensitive: "Rozlišuje malá a velká písmena"
connectedTo: "Následující účty jsou připojeny"
userList: "Seznamy"
about: "Informace"
aboutMisskey: "O Misskey"
@ -298,15 +319,70 @@ retype: "Zadejte znovu"
noteOf: "{user} poznámky"
inviteToGroup: "Pozvat do skupiny"
invitations: "Pozvat"
tooShort: "Příliš krátké"
tooLong: "Příliš dlouhé"
weakPassword: "Slabé heslo"
normalPassword: "Dobré heslo"
strongPassword: "Silné heslo"
passwordMatched: "Hesla se schodují"
passwordNotMatched: "Hesla se neschodují"
signinWith: "Přihlásit se s {x}"
signinFailed: "Nelze se přihlásit. Zkontrolujte prosím své uživatelské jméno a heslo."
or: "Nebo"
language: "Jazyk"
youHaveNoGroups: "Nemáte žádné skupiny"
signinHistory: "Historie přihlášení"
category: "Kategorie"
tags: "Štítky"
createAccount: "Vytvořit účet"
fontSize: "Velikost písma"
openImageInNewTab: "Otevřít obrázek v novém panelu"
dashboard: "Přehled"
local: "Lokální"
total: "Celkem"
weekOverWeekChanges: "Týdně"
dayOverDayChanges: "Denně"
appearance: "Vzhled"
clientSettings: "Nastavení klienta"
accountSettings: "Nastavení účtu"
promotion: "Propagace"
promote: "Propagovat"
numberOfDays: "Počet dní"
chooseEmoji: "Vybrat emotikon"
unableToProcess: "Operace nebyla dokončena."
recentUsed: "Naposledy použité"
install: "Nainstalovat"
uninstall: "Odinstalovat"
installedApps: "Autorizované aplikace"
nothing: "Nic nebylo nalezeno"
lastUsedDate: "Poslední použití"
state: "Stav"
ascendingOrder: "Vzestupně"
descendingOrder: "Sestupně"
scratchpad: "Zápisník"
output: "Výstup"
script: "Skript"
deleteAllFiles: "Smazat všechny soubory"
deleteAllFilesConfirm: "Jste si jistí že chcete smazat všechny soubory?"
userSuspended: "Tomuto uživateli byl pozastaven účet."
sidebar: "Postranní panel"
addItem: "Přidat položku"
rooms: "Místnost"
inboxUrl: "Inbox URL"
deletedNote: "Odstraněné příspěvky"
invisibleNote: "Skryté příspěvky"
smtpUser: "Uživatelské jméno"
smtpPass: "Heslo"
clearCache: "Vyprázdnit mezipaměť"
info: "Informace"
user: "Uživatelé"
_mfm:
mention: "Zmínění"
quote: "Citovat"
emoji: "Vlastní emoji"
search: "Vyhledávání"
_reversi:
total: "Celkem"
_sidebar:
icon: "Avatar"
_theme:
@ -328,6 +404,7 @@ _visibility:
home: "Domů"
followers: "Sledující"
_profile:
name: "Jméno"
username: "Uživatelské jméno"
_exportOrImport:
followingList: "Sledovaní"
@ -371,5 +448,6 @@ _deck:
_columns:
notifications: "Oznámení"
tl: "Časová osa"
antenna: "Antény"
list: "Seznamy"
mentions: "Zmínění"

View File

@ -7,6 +7,7 @@ search: "Suchen"
notifications: "Benachrichtigungen"
username: "Benutzername"
password: "Passwort"
forgotPassword: "Passwort vergessen"
fetchingAsApObject: "Wird aus dem Fediverse angefragt..."
ok: "OK"
gotIt: "Verstanden!"
@ -134,11 +135,11 @@ settingGuide: "Empfohlene Einstellung"
cacheRemoteFiles: "Dateien von anderen Instanzen im Cache speichern"
cacheRemoteFilesDescription: "Wenn diese Einstellung deaktiviert ist, werden Dateien anderer Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz gespart, aber mehr Bandbreite verbraucht, da keine Vorschaubilder generiert werden."
flagAsBot: "Als Bot markieren"
flagAsBotDescription: "Wenn dieser Account durch ein Programm gesteuert wird, setze diesen Haken. Falls aktiviert, agiert es als Flag für andere Entwickler um endlose Kettenreaktionen mit anderen Bots zu verhindern und lässt Misskey's interne Systeme diesen Account als Bot behandeln."
flagAsBotDescription: "Wenn dieses Benutzerkonto durch ein Programm gesteuert wird, setze diesen Haken. Falls aktiviert, agiert es als Flag für andere Entwickler um endlose Kettenreaktionen mit anderen Bots zu verhindern und lässt Misskey's interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren"
flagAsCatDescription: "Setze diese Flag um dieses Benutzerkonto als Katze zu markieren."
autoAcceptFollowed: "Follow-Anfragen automatisch akzeptieren"
addAcount: "Benutzerkonto hinzufügen"
addAccount: "Benutzerkonto hinzufügen"
loginFailed: "Login fehlgeschlagen"
showOnRemote: "Auf Ursprungsinstanz ansehen"
general: "Allgemein"
@ -298,8 +299,8 @@ reject: "Ablehnen"
normal: "Normal"
instanceName: "Name der Instanz"
instanceDescription: "Beschreibung der Instanz"
maintainerName: "Betreiber"
maintainerEmail: "Betreiber-Email"
maintainerName: "Administrator"
maintainerEmail: "Administrator-Email"
tosUrl: "URL der Nutzungsbedingungen"
thisYear: "Dieses Jahr"
thisMonth: "Dieser Monat"
@ -349,7 +350,6 @@ antennaExcludeKeywords: "Schlüsselwörter, die ignoriert werden sollen"
antennaKeywordsDescription: "Mit Leerzeichen für eine \"UND\"-Verknüpfung trennen, durch Zeilenumbrüche für eine \"ODER\"-Verknüpfung trennen."
notifyAntenna: "Über neue Notizen benachrichtigen"
withFileAntenna: "Nur Notizen mit Dateien"
serviceworker: "ServiceWorker"
enableServiceworker: "ServiceWorker aktivieren"
antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben"
caseSensitive: "Groß-/Kleinschreibung unterscheiden"
@ -453,7 +453,7 @@ category: "Kategorie"
tags: "Schlagwörter"
docSource: "Quelle dieses Dokuments"
createAccount: "Benutzerkonto erstellen"
existingAcount: "Bestehendes Benutzerkonto"
existingAccount: "Bestehendes Benutzerkonto"
regenerate: "Regenerieren"
fontSize: "Schriftgröße"
noFollowRequests: "Du hast keine Follow-Anfragen"
@ -568,7 +568,7 @@ pluginTokenRequestedDescription: "Dieses Plugin wird die hier konfigurierten Ber
notificationType: "Benachrichtigungsart"
edit: "Bearbeiten"
useStarForReactionFallback: "Verwende ★ falls das Reaktions-Emoji unbekannt ist"
emailConfig: "Email-Server Konfiguration"
emailServer: "Email-Server"
enableEmail: "Email-Versand aktivieren"
emailConfigInfo: "Zur Email-Bestätigung bei Registrierung und zum Zurücksetzen des Passworts verwendet"
email: "Email"
@ -705,6 +705,7 @@ editCode: "Code bearbeiten"
apply: "Anwenden"
receiveAnnouncementFromInstance: "E-Mail-Benachrichtigungen von dieser Instanz empfangen"
emailNotification: "E-Mail-Benachrichtigungen"
publish: "Veröffentlichen"
inChannelSearch: "In Kanal suchen"
useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen"
typingUsers: "{users} ist/sind am schreiben..."
@ -728,6 +729,40 @@ hideOnlineStatusDescription: "Das Verbergen deines Online-Statuses reduziert die
online: "Online"
active: "Aktiv"
offline: "Offline"
notRecommended: "Nicht empfohlen"
botProtection: "Bot-Schutz"
selectAccount: "Benutzerkonto auswählen"
enabled: "Aktiviert"
disabled: "Deaktiviert"
user: "Benutzer"
administration: "Verwaltung"
accounts: "Benutzerkonten"
switch: "Wechseln"
noMaintainerInformationWarning: "Administratorinformationen sind nicht konfiguriert."
noBotProtectionWarning: "Bot-Schutz ist nicht konfiguriert."
configure: "Konfigurieren"
postToGallery: "Beitrag zu Galerie hinzufügen"
gallery: "Galerie"
recentPosts: "Neue Beiträge"
popularPosts: "Beliebte Beiträge"
shareWithNote: "Mit Notiz teilen"
ads: "Werbung"
expiration: "Frist"
memo: "Merkzettel"
priority: "Priorität"
high: "Hoch"
middle: "Mittel"
low: "Niedrig"
emailNotConfiguredWarning: "Keine Email-Adresse hinterlegt"
_forgotPassword:
enterEmail: "Gib die Email-Adresse ein, mit der du dich registriert hast. An diese wird ein Link gesendet, mit der du dein Passwort zurücksetzen kannst."
ifNoEmail: "Solltest du bei der Registrierung keine Email-Adresse angegeben haben, wende dich bitte an den Administrator."
contactAdmin: "Diese Instanz unterstützt die Verwendung von Email-Adressen nicht. Wende dich, um dein Passwort zurückzusetzen, an den Administrator."
_gallery:
my: "Meine Galerie"
liked: "Beiträge, die mir gefallen"
like: "Gefällt mir"
unlike: "\"Gefällt mir\" entfernen"
_email:
_follow:
title: "Du hast einen neuen Follower"

View File

@ -7,6 +7,7 @@ search: "Search"
notifications: "Notifications"
username: "Username"
password: "Password"
forgotPassword: "Forgot password"
fetchingAsApObject: "Fetching from Fediverse..."
ok: "OK"
gotIt: "Got it!"
@ -138,7 +139,7 @@ flagAsBotDescription: "If this account is controlled by a program, set this opti
flagAsCat: "This account is a cat"
flagAsCatDescription: "Toggle this flag on for this account to be marked as a cat."
autoAcceptFollowed: "Automatically approve follow requests from users you're following"
addAcount: "Add Account"
addAccount: "Add account"
loginFailed: "Failed to sign in"
showOnRemote: "View on remote instance"
general: "General"
@ -339,7 +340,7 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Enable reCAPTCHA"
recaptchaSiteKey: "Site key"
recaptchaSecretKey: "Secret key"
avoidMultiCaptchaConfirm: "Using multiple Captchas may cause interference. Would you like to disable the other Captcha? You can leave multiple Captchas enabled by press cancel."
avoidMultiCaptchaConfirm: "Using multiple Captchas may cause interferences. Would you like to disable the other Captcha? You can leave multiple Captchas enabled by pressing cancel."
antennas: "Antennas"
manageAntennas: "Manage Antennas"
name: "Name"
@ -349,7 +350,6 @@ antennaExcludeKeywords: "Keywords to exclude"
antennaKeywordsDescription: "Separate with spaces for AND condition. Separate with line breaks for OR."
notifyAntenna: "Notify for new notes"
withFileAntenna: "Filter only notes with file(s) attached"
serviceworker: "ServiceWorker"
enableServiceworker: "Enable ServiceWorker"
antennaUsersDescription: "List one username per line"
caseSensitive: "Case sensitive"
@ -453,7 +453,7 @@ category: "Category"
tags: "Tags"
docSource: "Source of this document"
createAccount: "Create account"
existingAcount: "Existing accounts"
existingAccount: "Existing account"
regenerate: "Regenerate"
fontSize: "Font size"
noFollowRequests: "You don't have any pending follow requests"
@ -568,7 +568,7 @@ pluginTokenRequestedDescription: "This plugin will be able to use the permission
notificationType: "Notification type"
edit: "Edit"
useStarForReactionFallback: "Use ★ as fallback if the reaction emoji is unknown"
emailConfig: "Email server configuration"
emailServer: "Email server"
enableEmail: "Enable email distribution"
emailConfigInfo: "Used to confirm your email during sign-up and if you forget your password"
email: "Email"
@ -679,7 +679,7 @@ onlineUsersCount: "{n} people are online"
nUsers: "{n} Users"
nNotes: "{n} Notes"
sendErrorReports: "Send error reports"
sendErrorReportsDescription: "When turned on, detailed error information will be shared with Misskey when a problem occurs, helping to improve the quality of Misskey."
sendErrorReportsDescription: "When turned on, detailed error information will be shared with Misskey when a problem occurs, helping to improve the quality of Misskey.\nThis may include informations such as your OS and its version, the kind of browser you're using, your activity history, etc."
myTheme: "My theme"
backgroundColor: "Background"
accentColor: "Accent"
@ -705,6 +705,7 @@ editCode: "Edit code"
apply: "Apply"
receiveAnnouncementFromInstance: "Receive Email notifications from this instance"
emailNotification: "Email notifications"
publish: "Publish"
inChannelSearch: "Search in channel"
useReactionPickerForContextMenu: "Open reaction picker on right-click"
typingUsers: "{users} is/are typing..."
@ -728,6 +729,42 @@ hideOnlineStatusDescription: "Hiding your online status reduces the convenience
online: "Online"
active: "Active"
offline: "Offline"
notRecommended: "Not recommended"
botProtection: "Bot Protection"
instanceBlocking: "Blocked Instances"
selectAccount: "Select account"
enabled: "Enabled"
disabled: "Disabled"
quickAction: "Quick action"
user: "Users"
administration: "Management"
accounts: "Accounts"
switch: "Switch"
noMaintainerInformationWarning: "Maintainer information is not configured."
noBotProtectionWarning: "Bot protection is not configured."
configure: "Configure"
postToGallery: "Post to Gallery"
gallery: "Gallery"
recentPosts: "Recent posts"
popularPosts: "Popular posts"
shareWithNote: "Share with note"
ads: "Advertisements"
expiration: "Deadline"
memo: "Memo"
priority: "Priority"
high: "High"
middle: "Medium"
low: "Low"
emailNotConfiguredWarning: "Email address not set"
_forgotPassword:
enterEmail: "Enter the email address you used to register. A link with which you can reset your password will then be sent to it."
ifNoEmail: "If you did not use an email during registration, please contact the administrator instead."
contactAdmin: "This instance does not support using email addresses, please contact the administrator to reset your password instead."
_gallery:
my: "My Gallery"
liked: "Liked Posts"
like: "Like"
unlike: "Undo like"
_email:
_follow:
title: "You've got a new follower"
@ -1045,7 +1082,7 @@ _auth:
permissionAsk: "This application requires following permissions:"
pleaseGoBack: "Please go back to the application"
callback: "Returning back to the application"
denied: "Access Denied"
denied: "Access denied"
_antennaSources:
all: "All notes"
homeTimeline: "Notes from following users"

View File

@ -1,5 +1,6 @@
---
_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 🚀"
monthAndDay: "{day}/{month}"
search: "Buscar"
@ -137,7 +138,7 @@ flagAsBotDescription: "En caso de que esta cuenta fuera usada por un programa, a
flagAsCat: "Esta cuenta es un gato"
flagAsCatDescription: "En caso de que declare que esta cuenta es de un gato, active esta opción."
autoAcceptFollowed: "Aceptar automáticamente las solicitudes de seguimiento de los usuarios que sigues"
addAcount: "Agregar cuenta"
addAccount: "Agregar Cuenta"
loginFailed: "Error al iniciar sesión."
showOnRemote: "Ver en una instancia remota"
general: "General"
@ -348,7 +349,6 @@ antennaExcludeKeywords: "Palabras clave para excluir"
antennaKeywordsDescription: "Separar con espacios es una declaración AND, separar con una linea nueva es una declaración OR"
notifyAntenna: "Notificar nueva nota"
withFileAntenna: "Sólo notas con archivos adjuntados"
serviceworker: "ServiceWorker"
enableServiceworker: "Activar ServiceWorker"
antennaUsersDescription: "Elegir nombres de usuarios separados por una linea nueva"
caseSensitive: "Distinguir mayúsculas de minúsculas"
@ -437,6 +437,7 @@ signinWith: "Inicie sesión con {x}"
signinFailed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario y contraseña correctos."
tapSecurityKey: "Toque la clave de seguridad"
or: "O"
language: "Idioma"
uiLanguage: "Idioma de visualización de la interfaz"
groupInvited: "Invitado al grupo"
aboutX: "Acerca de {x}"
@ -451,7 +452,7 @@ category: "Categoría"
tags: "Etiqueta"
docSource: "Fuente de este documento"
createAccount: "Crear cuenta"
existingAcount: "Cuentas existentes"
existingAccount: "Cuenta existente"
regenerate: "Regenerar"
fontSize: "Tamaño de la letra"
noFollowRequests: "No hay solicitudes de seguimiento"
@ -566,7 +567,7 @@ pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos
notificationType: "Tipo de notificación"
edit: "Editar"
useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella"
emailConfig: "Configuración del servidor de correos"
emailServer: "Servidor de correo"
enableEmail: "Activar el envío de correos electrónicos"
emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña"
email: "Correo"
@ -646,6 +647,14 @@ driveFilesCount: "Cantidad de archivos en el drive"
driveUsage: "Uso del drive"
noCrawle: "Rechazar indexación del crawler"
noCrawleDescription: "Pedir a los motores de búsqueda que no indexen tu perfil, notas, páginas, etc."
alwaysMarkSensitive: "Marcar los medios de comunicación como contenido sensible por defecto"
verificationEmailSent: "Se le ha enviado un correo electrónico de confirmación. Por favor, acceda al enlace proporcionado en el correo electrónico para completar la configuración."
notSet: "Sin especificar"
emailVerified: "Su dirección de correo electrónico ha sido verificada."
noteFavoritesCount: "Número de notas favoritas"
pageLikesCount: "Número de favoritos en la página"
pageLikedCount: "Número de favoritos de su página"
contact: "Contacto"
clips: "Clip"
clearCache: "Limpiar caché"
backgroundColor: "Fondo"
@ -654,6 +663,12 @@ textColor: "Texto"
value: "Valores"
goBack: "Deseleccionar"
info: "Información"
user: "Usuarios"
administration: "Administrar"
expiration: "Termina el"
middle: "Mediano"
_gallery:
unlike: "Quitar me gusta"
_email:
_follow:
title: "te ha seguido"

View File

@ -7,6 +7,7 @@ search: "Rechercher"
notifications: "Notifications"
username: "Nom dutilisateur·rice"
password: "Mot de passe"
forgotPassword: "Mot de passe oublié"
fetchingAsApObject: "Récupération depuis le fédiverse …"
ok: "OK"
gotIt: "Jai compris !"
@ -138,7 +139,7 @@ flagAsBotDescription: "Si ce compte est géré de manière automatisée , défin
flagAsCat: "Ce compte est un chat"
flagAsCatDescription: "Activer l'option \" Je suis un chat \" pour ce compte."
autoAcceptFollowed: "Accepter automatiquement les demandes dabonnement venant dutilisateur·rice·s que vous suivez"
addAcount: "Ajouter un compte"
addAccount: "Ajouter un compte"
loginFailed: "Échec de la connexion"
showOnRemote: "Voir sur linstance distante"
general: "Général"
@ -349,7 +350,6 @@ antennaExcludeKeywords: "Mots clés à exclure"
antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
notifyAntenna: "Je souhaite recevoir les notifications des nouvelles notes"
withFileAntenna: "Notes ayant des attachements uniquement"
serviceworker: "ServiceWorker"
enableServiceworker: "Activer ServiceWorker"
antennaUsersDescription: "Saisissez un seul nom dutilisateur·rice par ligne"
caseSensitive: "Sensible à la casse"
@ -453,7 +453,7 @@ category: "Catégorie"
tags: "Étiquettes"
docSource: "Source de ce document"
createAccount: "Créer un compte"
existingAcount: "Comptes existants"
existingAccount: "Compte existant"
regenerate: "Générer à nouveau"
fontSize: "Taille de la police"
noFollowRequests: "Vous navez aucune demande dabonnement en attente"
@ -487,7 +487,7 @@ objectStorageRegionDesc: "Spécifiez une région comme 'xx-east-1'. Si votre ser
objectStorageUseSSL: "Utiliser SSL"
objectStorageUseSSLDesc: "Désactivez cette option si vous n'utilisez pas HTTPS pour la connexion API"
objectStorageUseProxy: "Se connecter via proxy"
objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas Proxy pour la connexion API"
objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas de proxy pour la connexion API"
objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
serverLogs: "Journal du serveur"
deleteAll: "Supprimer tout"
@ -541,8 +541,8 @@ enableInfiniteScroll: "Activer le défilement infini"
visibility: "Visibilité"
poll: "Sondage"
useCw: "Masquer le contenu"
enablePlayer: "Activer le lecteur vidéo"
disablePlayer: "Désactiver le lecteur vidéo"
enablePlayer: "Ouvrir dans le lecteur vidéo"
disablePlayer: "Fermer le lecteur vidéo"
expandTweet: "Étendre le tweet"
themeEditor: "Éditeur de thèmes"
description: "Description"
@ -568,7 +568,7 @@ pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations d
notificationType: "Type de notifications"
edit: "Editer"
useStarForReactionFallback: "Utiliser ★ comme alternative si lémoji de réaction est inconnu"
emailConfig: "Configuration du serveur email"
emailServer: "Serveur mail"
enableEmail: "Activer la distribution de courriel"
emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas doubli."
email: "E-mail "
@ -601,10 +601,11 @@ useGlobalSettingDesc: "S'il est activé, les paramètres de notification de votr
other: "Autre"
regenerateLoginToken: "Régénérer le jeton de connexion"
regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau jeton, tous les appareils seront déconnectés. "
setMultipleBySeparatingWithSpace: "Vous pouvez définir plus dun, séparés par des espaces."
setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant par des espaces."
fileIdOrUrl: "ID du fichier ou URL"
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
behavior: "Comportement"
sample: "Exemple"
abuseReports: "Signalements"
reportAbuse: "Signalements"
reportAbuseOf: "Signaler {name}"
@ -678,7 +679,7 @@ onlineUsersCount: "{n} utilisateur(s) en ligne"
nUsers: "{n} utilisateur·rice·s"
nNotes: "{n} Notes"
sendErrorReports: "Envoyer les rapports derreur"
sendErrorReportsDescription: "Lorsqu'il est activé, des informations détaillées sur les erreurs sont partagées avec Misskey lorsqu'un problème survient, ce qui contribue à améliorer la qualité de Misskey."
sendErrorReportsDescription: "Si vous activez l'envoi des rapports d'erreur, vous contribuerez à améliorer la qualité de Misskey grâce au partage d'informations détaillées sur les erreurs lorsqu'un problème survient.\nCela inclut des informations telles que la version de votre système d'exploitation, le type de navigateur que vous utilisez, votre historique d'activité, etc."
myTheme: "Mes thèmes"
backgroundColor: "Arrière-plan"
accentColor: "Accentuation"
@ -704,6 +705,7 @@ editCode: "Modifier le code"
apply: "Appliquer"
receiveAnnouncementFromInstance: "Recevoir les messages d'information de l'instance"
emailNotification: "Notifications par mail"
publish: "Public"
inChannelSearch: "Chercher dans le canal"
useReactionPickerForContextMenu: "Clic-droit pour ouvrir le panneau de réactions"
typingUsers: "{users} est en train d'écrire"
@ -722,10 +724,47 @@ info: "Informations"
userInfo: "Informations sur l'utilisateur"
unknown: "Inconnu"
onlineStatus: "Statut"
hideOnlineStatus: "Toujours apparaître hors ligne"
hideOnlineStatusDescription: "Forcer votre statut à toujours apparaître hors ligne peut diminuer les performances de certaines fonctionnalités, telles que la Recherche."
hideOnlineStatus: "Se rendre invisible"
hideOnlineStatusDescription: "Rendre votre statut invisible peut diminuer les performances de certaines fonctionnalités, telles que la Recherche."
online: "En ligne"
active: "Actif·ve"
offline: "Hors ligne"
notRecommended: "Déconseillé"
botProtection: "Protection contre les bots"
instanceBlocking: "Instances bloquées"
selectAccount: "Sélectionner un compte"
enabled: "Activé"
disabled: "Désactivé"
quickAction: "Actions rapides"
user: "Utilisateur·rice·s"
administration: "Gestion"
accounts: "Comptes"
switch: "Remplacer"
noMaintainerInformationWarning: "Informations administrateur non configurées."
noBotProtectionWarning: "La protection contre les bots n'est pas configurée."
configure: "Configurer"
postToGallery: "Publier dans la galerie"
gallery: "Galerie"
recentPosts: "Les plus récentes"
popularPosts: "Les plus consultées"
shareWithNote: "Partager dans une note"
ads: "Publicité"
expiration: "Échéance"
memo: "Mémo"
priority: "Priorité"
high: "Haute"
middle: "Moyen"
low: "Basse"
emailNotConfiguredWarning: "Vous n'avez pas configuré d'adresse e-mail."
_forgotPassword:
enterEmail: "Entrez ici l'adresse e-mail que vous avez enregistrée pour votre compte. Un lien vous permettant de réinitialiser votre mot de passe sera envoyé à cette adresse."
ifNoEmail: "Si vous n'avez pas enregistré d'adresse e-mail, merci de contacter l'administrateur·rice de votre instance."
contactAdmin: "Cette instance ne permettant pas l'utilisation d'adresses e-mail, prenez contact avec l'administrateur·rice pour procéder à la réinitialisation de votre mot de passe."
_gallery:
my: "Mes publications"
liked: " Publications que j'ai aimées"
like: "J'aime"
unlike: "Je naime pas"
_email:
_follow:
title: "Vous suit"
@ -736,6 +775,7 @@ _plugin:
installWarn: "Ninstallez que des extensions provenant de sources de confiance."
manage: "Gestion des plugins"
_registry:
scope: "Portée"
key: "Clé "
keys: "Clé "
domain: "Domaine"
@ -769,18 +809,38 @@ _mfm:
boldDescription: "Il est possible de mettre le texte en exergue en le mettant en gras."
small: "Diminuer l'emphase"
smallDescription: "Le contenu peut être affiché en petit et fin."
center: "Centrée"
center: "Centrer"
centerDescription: "Le contenu peut être centré"
inlineCode: "Code (inline)"
inlineCodeDescription: "Coloration syntaxique des lignes de code."
blockCode: "Bloc de code"
blockCodeDescription: "Coloration syntaxique des lignes de code pour les blocs multi-lignes."
inlineMath: "Formule mathématique (inline)"
inlineMathDescription: "Afficher les formules mathématiques (KaTeX)."
blockMath: "Formule mathématique (bloc)"
blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes dans un bloc."
quote: "Citer"
quoteDescription: "Affiche le contenu sous forme de citation."
emoji: "Émojis personnalisés"
emojiDescription: "Entourez le nom de l'émoji personnalisé de deux points pour l'afficher."
search: "Rechercher"
searchDescription: "Affiche une boîte de recherche avec du texte pré-saisi."
flip: "Inverser"
flipDescription: "Rotation verticale ou horizontale du contenu"
jelly: "Animation (Gelée)"
jellyDescription: "Donne une animation d'étirement."
tada: "Animation (Tada)"
tadaDescription: "Donne une animation qui donne une impression de \"Tada !\""
jump: "Animation (Saut)"
jumpDescription: "Donne une animation qui saute."
bounce: "Animation (Rebond)"
bounceDescription: "Donne une animation de rebondissement."
shake: "Animation (Secousse)"
shakeDescription: "Donne une animation tremblante."
twitch: "Animation (Tremblement)"
twitchDescription: "Donne une animation de tremblement intense."
spin: "Animation (Rotation)"
spinDescription: "Donne une animation de rotation."
x2: "Grand"
x2Description: "Afficher le contenu en grand."
x3: "Très grand"
@ -822,6 +882,7 @@ _reversi:
ended: "Fin de partie"
playing: "En cours"
isLlotheo: "Celui ou celle qui a le moins de pièces gagne (Llotheo)"
loopedMap: "Carte en boucle"
canPutEverywhere: "Les pions peuvent être placés partout "
_instanceTicker:
none: "Cacher "
@ -871,17 +932,21 @@ _theme:
constant: "Constante"
defaultValue: "Valeur par défaut"
color: "Couleur"
refConst: "Référencez une constante"
refProp: "Appeler une propriété"
refConst: "Appeler une constante"
key: "Clé "
func: "Fonction"
funcKind: "Type de fonction"
argument: "Argument"
basedProp: "Nom de la propriété référencée"
alpha: "Transparence"
darken: "Assombrir"
darken: "Sombre"
lighten: "Clair"
inputConstantName: "Insérez un nom de constante"
importInfo: "Vous pouvez importer un thème vers léditeur de thèmes en saisissant son code ici."
deleteConstantConfirm: "Êtes-vous sûr·e de vouloir supprimer la constante {const} ?"
keys:
accent: "Accentuation"
bg: "Arrière-plan"
fg: "Texte"
focus: "Mise au point"
@ -899,29 +964,37 @@ _theme:
mention: "Mentionner"
mentionMe: "Mentions (Moi)"
renote: "Partager"
modalBg: "Modal d'arrière-plan"
divider: "Séparateur"
scrollbarHandle: "Poignée de la barre de navigation"
scrollbarHandleHover: "Poignée de la barre de navigation (survolée)"
dateLabelFg: "Texte de l'étiquette de la date"
infoBg: "Arrière-plan pour les informations"
infoFg: "Texte d'information"
infoWarnBg: "Arrière-plan des avertissements"
infoWarnFg: "Texte davertissement"
cwBg: "Arrière-plan du CW"
cwFg: "Texte du bouton CW"
cwHoverBg: "Arrière-plan du bouton CW (survolé)"
toastBg: "Arrière-plan de la bulle de notification"
toastFg: "Texte de la bulle de notification"
buttonBg: "Arrière-plan du bouton"
buttonHoverBg: "Arrière-plan du bouton (survolé)"
inputBorder: "Cadre de la zone de texte"
listItemHoverBg: "Arrière-plan d'item de liste (survolé)"
driveFolderBg: "Arrière-plan du dossier de disque"
wallpaperOverlay: "Superposition de fond d'écran"
badge: "Badge"
messageBg: "Arrière plan de la discussion"
accentDarken: "Plus sombre"
accentLighten: "Plus clair"
fgHighlighted: "Texte mis en évidence"
_sfx:
note: "Nouvelle note"
noteMy: "Ma note"
notification: "Notifications"
chat: "Discuter"
chatBg: "Discuter (De fond)"
chatBg: "Discussion (arrière-plan)"
antenna: "Réception de lantenne"
channel: "Notifications de canal"
reversiPutBlack: "Reversi : les pions noirs ont joué"
@ -966,14 +1039,14 @@ _tutorial:
step7_2: "Si vous désirez en savoir plus sur Misskey, jetez un œil sur la section {help}."
step7_3: "Bon courage et amusez-vous bien sur Misskey ! 🚀"
_2fa:
alreadyRegistered: "Cette étape à déjà été complétée"
alreadyRegistered: "Configuration déjà achevée."
registerDevice: "Ajouter un nouvel appareil"
registerKey: "Sinscrire la clé"
registerKey: "Enregistrer une clef"
step1: "Tout d'abord, installez une application d'authentification, telle que {a} ou {b}, sur votre appareil."
step2: "Ensuite, scannez le code QR affiché sur lécran."
step3: "Entrez le jeton affiché sur votre application pour compléter la configuration."
step4: "Lorsque vous vous connectez, entrez le jeton de la même manière."
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion avec non seulement la clé de sécurité matérielle qui prend en charge FIDO2, mais également l'authentification par empreinte digitale ou PIN sur votre appareil."
step4: "À partir de maintenant, ce même jeton vous sera demandé à chacune de vos connexions."
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion grâce à une clé de sécurité matérielle qui prend en charge FIDO2, ou bien en configurant l'authentification par empreinte digitale ou par code PIN sur votre appareil."
_permissions:
"read:account": "Afficher les informations du compte"
"write:account": "Mettre à jour les informations de votre compte"
@ -985,8 +1058,8 @@ _permissions:
"write:favorites": "Gérer les favoris"
"read:following": "Voir les informations de vos abonnements"
"write:following": "Abonnements/Se désabonner"
"read:messaging": "Cherche à discuter"
"write:messaging": "Contrôler le discuter"
"read:messaging": "Voir vos discussions"
"write:messaging": "Gérer les discussions"
"read:mutes": "Voir les comptes masqués"
"write:mutes": "Gérer les comptes masqués"
"write:notes": "Créer / supprimer des notes"
@ -995,10 +1068,10 @@ _permissions:
"read:reactions": "Lire les réactions"
"write:reactions": "Gérer vos réactions"
"write:votes": "Voter"
"read:pages": "Afficher la page"
"write:pages": "Mettre à jour les Pages"
"read:page-likes": "Voir les favoris sur les Pages"
"write:page-likes": "Mettre à jour les favoris sur les Pages"
"read:pages": "Voir vos pages"
"write:pages": "Gérer les pages"
"read:page-likes": "Voir les mentions « J'aime » des pages"
"write:page-likes": "Gérer les mentions « J'aime » sur les pages"
"read:user-groups": "Voir les groupes d'utilisateur·rice·s"
"write:user-groups": "Éditer les groupes des utilisateur·rice·s"
"read:channels": "Lire les canaux"
@ -1087,7 +1160,7 @@ _postForm:
channelPlaceholder: "Publier vers le canal"
_placeholders:
a: "Quoi de neuf ?"
b: "Quoi de neuf ?"
b: "Il s'est passé quelque chose ?"
c: "Quavez-vous en tête ?"
d: "Désirez-vous publier quelques mots ?"
e: "Écrivez ici"
@ -1111,31 +1184,31 @@ _exportOrImport:
blockingList: "Comptes bloqués"
userLists: "Listes"
_charts:
federationInstancesIncDec: "Variation du nombre des instances fédérées"
federationInstancesTotal: "Nombre total des instances fédérées"
federationInstancesIncDec: "Variation du nombre d'instances fédérées"
federationInstancesTotal: "Nombre total d'instances fédérées"
usersIncDec: "Variation du nombre d'utilisateur·rice·s"
usersTotal: "Nombre des utilisateur·rice·s au total"
activeUsers: "Utilisateur·rice·s actif·ve·s"
notesIncDec: "Variation du nombre des notes"
localNotesIncDec: "Variation du nombre de notes local"
remoteNotesIncDec: "Variation du nombre dnotes distant"
localNotesIncDec: "Variation du nombre de notes locales"
remoteNotesIncDec: "Variation du nombre de notes distantes"
notesTotal: "Nombre total des notes"
filesIncDec: "Variation du nombre de fichiers"
filesTotal: "Nombre de fichiers au total"
filesTotal: "Nombre total de fichiers"
storageUsageIncDec: "Variation de l'utilisation du stockage"
storageUsageTotal: "Utilisation totale du stockage"
_instanceCharts:
requests: "Requêtes"
users: "Variation du nombre d'utilisateur·rice·s"
usersTotal: "Nombre d'utilisateur·rice·s au total cumulé"
notes: "Variation du nombre des notes"
usersTotal: "Total cumulé du nombre d'utilisateur·rice·s"
notes: "Variation du nombre de notes"
notesTotal: "Nombre total cumulé des notes"
ff: "Variation des abonné·e·s"
ffTotal: "Nombre d'abonné·e·s au total cumulé"
ff: "Variation des abonné·e·s / abonnements"
ffTotal: "Total cumulé du nombre d'abonné·e·s / abonnements"
cacheSize: "Variation de la taille du cache"
cacheSizeTotal: "La taille du cache au total cumulé"
cacheSizeTotal: "Total cumulé de la taille du cache"
files: "Variation du nombre de fichiers"
filesTotal: "Nombre de fichiers au total cumulé"
filesTotal: "Total cumulé du nombre de fichiers"
_timelines:
home: "Principal"
local: "Local"
@ -1158,7 +1231,7 @@ _rooms:
default: "Par défaut"
washitsu: "Style japonnais"
_furnitures:
milk: "Lait en carton"
milk: "Brique de lait"
bed: "Lit"
low-table: "Table basse"
desk: "Bureau"
@ -1177,7 +1250,7 @@ _rooms:
book: "Livre"
book2: "Livre 2"
piano: "Piano"
facial-tissue: "Mouchoirs en papier"
facial-tissue: "Boîte de mouchoirs"
server: "Serveurs"
moon: "Lune"
corkboard: "Tableau en liège"
@ -1190,7 +1263,7 @@ _rooms:
wall-clock: "Horloge murale"
photoframe: "Cadre photo"
cube: "Cube"
tv: "Téléviseur"
tv: "Télé"
pinguin: "Pingouin"
rubik-cube: "Cube de Rubik"
poster-h: "Affiche (horizontale)"
@ -1206,13 +1279,13 @@ _rooms:
_pages:
newPage: "Créer une page"
editPage: "Modifier une page"
readPage: "Voir la source"
readPage: "Affichage de la source en cours"
created: "La page a été créée !"
updated: "La page a été mise à jour !"
deleted: "La page a bien été supprimée"
deleted: "La page a été supprimée"
pageSetting: "Paramètres de la Page"
nameAlreadyExists: "La URL de page spécifiée existe déjà"
invalidNameTitle: "La URL de la page spécifiée nest pas valide"
nameAlreadyExists: "L'URL de page spécifiée existe déjà"
invalidNameTitle: "L'URL de page spécifiée nest pas valide"
invalidNameText: "Assurez-vous quil nest pas vide"
editThisPage: "Éditer cette page"
viewSource: "Afficher la source"
@ -1227,21 +1300,21 @@ _pages:
content: "Bloc de page"
variables: "Variables"
title: "Titre"
url: "URL de page"
url: "URL de la page"
summary: "Résumé de page"
alignCenter: "Centrée"
hideTitleWhenPinned: "Masquer le titre de la page lorsque celle-ci est épinglée au profil"
font: "Police de caractères"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
eyeCatchingImageSet: "Définir une image attirante"
eyeCatchingImageRemove: "Supprimer une image attirante"
eyeCatchingImageSet: "Définir une image attractive"
eyeCatchingImageRemove: "Supprimer l'image attractive"
chooseBlock: "Ajouter un bloc"
selectType: "Choisir un type"
enterVariableName: "Veuillez entrer un nom pour votre variable"
variableNameIsAlreadyUsed: "Cette variable est déjà utilisée"
variableNameIsAlreadyUsed: "Ce nom de variable est déjà utilisé"
contentBlocks: "Contenu"
inputBlocks: "Entrée"
inputBlocks: "Blocs d'entrée"
specialBlocks: "Spécial"
blocks:
text: "Texte"
@ -1533,7 +1606,7 @@ _deck:
swapUp: "Déplacer vers le haut"
swapDown: "Déplacer vers le bas"
stackLeft: "Empiler à gauche"
popRight: "Vers la droite"
popRight: "Extraire à droite"
profile: "Profil"
_columns:
main: "Principale"

View File

@ -107,7 +107,6 @@ cacheRemoteFiles: "Tembolokkan berkas remote"
flagAsBot: "Atur akun ini sebagai Bot"
flagAsCat: "Atur akun ini sebagai kucing"
autoAcceptFollowed: "Setujui otomatis permintaan mengikuti dari pengguna yang anda ikuti"
addAcount: "Tambahkan akun"
loginFailed: "Gagal untuk masuk"
showOnRemote: "Lihat profil asli"
general: "Umum"
@ -213,6 +212,7 @@ invites: "Undang"
invitations: "Undang"
smtpUser: "Nama Pengguna"
smtpPass: "Kata sandi"
user: "Pengguna"
_email:
_follow:
title: "Sedang mengikuti"

View File

@ -47,7 +47,7 @@ deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo?
addToList: "Aggiungi alla lista"
sendMessage: "Invia messaggio"
copyUsername: "Copia nome utente"
searchUser: "Cerca Utente"
searchUser: "Cerca utente"
reply: "Rispondi"
loadMore: "Mostra di più"
showMore: "Mostra di più"
@ -136,7 +136,7 @@ flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche
flagAsCat: "Io sono un gatto"
flagAsCatDescription: "Abilita l'opzione \"Io sono un gatto\" per l'account."
autoAcceptFollowed: "Accetta automaticamente le richieste di follow da utenti che già segui"
addAcount: "Aggiungi account"
addAccount: "Aggiungi account"
loginFailed: "Accesso non riuscito"
showOnRemote: "Sfoglia sull'istanza remota"
general: "Generali"
@ -153,6 +153,9 @@ recipient: "Destinatario"
annotation: "Descrizione"
federation: "Federazione"
instances: "Istanza"
latestRequestSentAt: "Ultima richiesta inviata"
latestRequestReceivedAt: "Ultima richiesta ricevuta"
latestStatus: "Ultimo stato"
storageUsage: "Volume di dischi"
charts: "Grafici"
perHour: "All'ora"
@ -172,6 +175,7 @@ instanceInfo: "Informazioni sull'istanza"
statistics: "Statistiche"
clearQueue: "Svuota coda"
clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?"
clearQueueConfirmText: "Le note ancora non distribuite non verranno rilasciate. Solitamente, non è necessario eseguire questa operazione."
clearCachedFiles: "Svuota cache"
clearCachedFilesConfirm: "Vuoi davvero svuotare la cache da tutti i file remoti?"
blockedInstances: "Istanze bloccate"
@ -329,6 +333,7 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Abilita reCAPTCHA"
recaptchaSiteKey: "Chiave del sito"
recaptchaSecretKey: "Chiave segreta"
avoidMultiCaptchaConfirm: "Utilizzare diversi Captcha può causare interferenze. Vuoi disattivare l'altro Captcha? Puoi lasciare diversi Captcha attivi premendo \"Cancella\"."
antennas: "Antenne"
manageAntennas: "Gestore delle antenne"
name: "Nome"
@ -338,7 +343,6 @@ antennaExcludeKeywords: "Parole chiavi da escludere"
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
notifyAntenna: "Invia notifiche delle nuove note"
withFileAntenna: "Solo note con file in allegato"
serviceworker: "ServiceWorker"
enableServiceworker: "Abilita ServiceWorker"
antennaUsersDescription: "Inserisci solo un nome utente per riga"
caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
@ -436,11 +440,12 @@ youHaveNoGroups: "Nessun gruppo"
joinOrCreateGroup: "Puoi creare il tuo gruppo o essere invitat@ a gruppi che già esistono."
noHistory: "Nessuna cronologia"
signinHistory: "Cronologia di accesso all'account"
doing: "In corso..."
category: "Categoria"
tags: "Tag"
docSource: "Sorgente della scheda"
createAccount: "Crea il tuo account"
existingAcount: "Account esistente"
existingAccount: "Account esistente"
regenerate: "Generare di nuovo"
fontSize: "Dimensione carattere"
noFollowRequests: "Non hai alcuna richiesta di follow"
@ -468,6 +473,9 @@ objectStoragePrefixDesc: "I file saranno conservati sotto la directory di questo
objectStorageEndpoint: "Endpoint"
objectStorageRegion: "Region"
objectStorageUseSSL: "Usare SSL"
objectStorageUseProxy: "Usa proxy"
objectStorageUseProxyDesc: "Disabilita quest'opzione se non usi proxy per la connessione API."
objectStorageSetPublicRead: "Imposta \"visibilità pubblica\" al momento di caricare"
serverLogs: "Log del server"
deleteAll: "Cancella cronologia"
showFixedPostForm: "Visualizzare la finestra di pubblicazione in cima alla timeline"
@ -497,7 +505,7 @@ scratchpad: "ScratchPad"
output: "Uscita"
script: "Script"
disablePagesScript: "Disabilita AiScript nelle pagine"
updateRemoteUser: "Aggiornare le informazioni di utente remoto"
updateRemoteUser: "Aggiornare le informazioni di utente remot@"
deleteAllFiles: "Elimina tutti i file"
deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
removeAllFollowing: "Cancella tutti i follows"
@ -508,6 +516,10 @@ sidebar: "Barra laterale"
divider: "Linea di separazione"
addItem: "Aggiungi elemento"
rooms: "Camera"
relays: "Ripetitori"
addRelay: "Aggiungi ripetitore"
inboxUrl: "Inbox URL"
addedRelays: "Ripetitori configurati"
serviceworkerInfo: "Deve essere abilitato per le notifiche push. "
deletedNote: "Nota eliminata"
invisibleNote: "Nota invisibile"
@ -515,47 +527,77 @@ enableInfiniteScroll: "Abilita scorrimento infinito"
visibility: "Visibilità"
poll: "Sondaggio"
useCw: "Nascondere media"
enablePlayer: "Apri in lettore video"
disablePlayer: "Chiudi lettore video"
expandTweet: "Espandi tweet"
themeEditor: "Editor di temi"
description: "Descrizione"
author: "Autore"
leaveConfirm: "Ci sono delle modifiche ancora non salvate. Vuoi cancellarle?"
manage: "Gestione"
plugins: "Estensioni"
deck: "Deck"
undeck: "Esci dal deck"
useFullReactionPicker: "Usa la totalità del pannello di reazioni"
width: "Larghezza"
height: "Altezza"
large: "Grande"
medium: "Predefinito"
small: "Piccolo"
generateAccessToken: "Genera token di accesso"
permission: "Autorizzazioni "
enableAll: "Abilita tutto"
disableAll: "Disabilita tutto"
tokenRequested: "Autorizza accesso all'account"
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui."
notificationType: "Tipo di notifiche"
edit: "Modifica"
useStarForReactionFallback: "Se è sconosciuto l'emoji di reazione, usare la ★ come alternativa."
emailConfig: "Impostazioni server email"
emailServer: "Server email"
enableEmail: "Abilita consegna email"
emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica e per reimpostare la tua password"
email: "Email"
emailAddress: "Indirizzo di posta elettronica"
smtpConfig: "Impostazioni del server SMTP"
smtpHost: "Server remoto"
smtpPort: "Porta"
smtpUser: "Nome utente"
smtpPass: "Password"
emptyToDisableSmtpAuth: "Lasciare il nome utente e la password vuoti per disabilitare la verifica SMTP"
smtpSecure: "Usare la porta SSL/TLS implicito per le connessioni SMTP"
smtpSecureInfo: "Disabilitare quando è attivo STARTTLS."
testEmail: "Testare la consegna di posta elettronica"
wordMute: "Filtri parole"
userSaysSomething: "{name} ha detto qualcosa"
makeActive: "Attiva"
display: "Visualizza"
copy: "Copia"
metrics: "Statistiche"
overview: "Anteprima"
logs: "Log"
delayed: "Ritardo"
database: "Base di dati"
channel: "Canale"
create: "Crea"
notificationSetting: "Impostazioni notifiche"
notificationSettingDesc: "Seleziona il tipo di notifiche da visualizzare."
useGlobalSetting: "Usa impostazioni generali"
useGlobalSettingDesc: "Se abilitato, le impostazioni notifiche dell'account verranno utilizzate. Se disabilitato, si possono definire diverse singole impostazioni."
other: "Avanzate"
regenerateLoginToken: "Genera di nuovo un token di connessione"
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi."
fileIdOrUrl: "ID o URL del file"
chatOpenBehavior: "Comportamento della finestra di chat quando viene aperta"
behavior: "Comportamento"
abuseReports: "Segnala"
reportAbuse: "Segnala"
reportAbuseOf: "Segnala {name}"
send: "Inviare"
openInNewTab: "Apri in una nuova scheda"
openInSideView: "Apri in vista laterale"
defaultNavigationBehaviour: "Navigazione preimpostata"
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare l'account."
instanceTicker: "Informazioni sull'istanza da cui vengono le note"
waitingFor: "Aspettando {x}"
random: "Casuale"
system: "Sistema"
@ -567,6 +609,8 @@ optional: "Opzionale"
createNewClip: "Nuova clip"
public: "Pubblica"
i18nInfo: "Misskey è tradotto in diverse lingue da volontari. Anche tu puoi contribuire su {link}."
manageAccessTokens: "Gestisci token di accesso"
accountInfo: "Informazioni account"
notesCount: "Conteggio note"
repliesCount: "Numero di risposte inviate"
renotesCount: "Numero di note che hai ricondiviso"
@ -581,54 +625,143 @@ pollVotedCount: "Numero di voti ricevuti"
yes: "Sì"
no: "No"
driveFilesCount: "Numero di file nel Drive"
driveUsage: "Utilizzazione del Drive"
noCrawle: "Rifiuta l'indicizzazione dai robot."
noCrawleDescription: "Richiedi che i motori di ricerca non indicizzino la tua pagina di profilo, le tue note, pagine, ecc."
lockedAccountInfo: "A meno che non imposti la visibilità delle tue note su \"Solo ai follower\", le tue note sono visibili da tutti, anche se hai configurato l'account per confermare manualmente le richieste di follow."
alwaysMarkSensitive: "Segnare i media come sensibili per impostazione predefinita"
loadRawImages: "Visualizza le intere immagini allegate invece delle miniature."
disableShowingAnimatedImages: "Disabilita le immagini animate"
verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di accedere al collegamento per compiere la verifica."
notSet: "Non impostato"
emailVerified: "Il tuo indirizzo email è stato verificato"
noteFavoritesCount: "Conteggio note tra i preferiti"
pageLikesCount: "Numero di pagine che ti piacciono"
pageLikedCount: "Numero delle tue pagine che hanno ricevuto \"Mi piace\""
reversiCount: "Numero di partite a Reversi"
contact: "Contatti"
useSystemFont: "Usa il carattere predefinito del sistema"
clips: "Clip"
experimentalFeatures: "Funzioni sperimentali"
developer: "Sviluppatore"
makeExplorable: "Account visibile sulla pagina \"Esplora\""
makeExplorableDescription: "Se disabiliti l'opzione, il tuo account non verrà visualizzato sulla pagina \"Esplora\"."
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
duplicate: "Duplica"
left: "Sinistra"
center: "Centro"
wide: "Largo"
reloadToApplySetting: "Le tue preferenze verranno impostate dopo il ricaricamento della pagina. Vuoi ricaricare adesso?"
showTitlebar: "Visualizza la barra del titolo"
clearCache: "Svuota cache"
onlineUsersCount: "{n} utenti online"
nUsers: "{n} utenti"
nNotes: "{n}Note"
sendErrorReports: "Invia segnalazioni di errori"
sendErrorReportsDescription: "Quando abilitato, se si verifica un problema, informazioni dettagliate sugli errori verranno condivise con Misskey in modo da aiutare a migliorare la qualità del software.\nCiò include informazioni come la versione del sistema operativo, il tipo di navigatore web che usi, la cronologia delle attività, ecc."
myTheme: "I miei temi"
backgroundColor: "Sfondo"
textColor: "Testo"
saveAs: "Salva con nome"
value: "Valore"
createdAt: "Data di creazione"
updatedAt: "Aggiornato il"
saveConfirm: "Vuoi salvare le modifiche?"
deleteConfirm: "Rimuovere?"
invalidValue: "Questo non è un valore valido."
registry: "Registro"
closeAccount: "Disattiva account"
currentVersion: "Versione attuale"
latestVersion: "Ultima versione"
youAreRunningUpToDateClient: "Stai usando la versione più recente del client."
newVersionOfClientAvailable: "Una nuova versione del tuo client è disponibile."
usageAmount: "In utilizzo"
capacity: "Capacità"
inUse: "In utilizzo"
editCode: "Modifica codice"
apply: "Applica"
receiveAnnouncementFromInstance: "Ricevi i messaggi informativi dall'istanza"
emailNotification: "Eventi per notifiche via mail"
publish: "Pubblico"
inChannelSearch: "Cerca in canale"
useReactionPickerForContextMenu: "Cliccare sul tasto destro per aprire il pannello di reazioni"
typingUsers: "{users} sta(nno) scrivendo"
jumpToSpecifiedDate: "Vai alla data "
showingPastTimeline: "Stai visualizzando una vecchia timeline"
clear: "Cancella"
markAllAsRead: "Segna tutti come già letti"
goBack: "Indietro"
unlikeConfirm: "Non ti piace più?"
fullView: "Schermo intero"
quitFullView: "Esci dalla modalità a schermo intero"
addDescription: "Aggiungi descrizione"
userPagePinTip: "Qui puoi appuntare note, premendo \"Fissa sul profilo\" nel menù delle singole note."
notSpecifiedMentionWarning: "Sono menzionati account che non vengono inclusi fra i destinatari"
info: "Informazioni"
userInfo: "Informazioni utente"
unknown: "Sconosciuto"
onlineStatus: "Stato di connessione"
hideOnlineStatus: "Stato invisibile"
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare la praticità di singole funzioni, come la ricerca."
online: "Online"
offline: "Offline"
notRecommended: "Sconsigliato"
botProtection: "Protezione contro i bot"
instanceBlocking: "Istanze bloccate"
selectAccount: "Scegli account"
enabled: "Attivo"
disabled: "Inattivo"
quickAction: "Azioni rapide"
user: "Utente"
administration: "Gestione"
accounts: "Account"
switch: "Sostituisci"
noMaintainerInformationWarning: "Le informazioni amministratore non sono impostate."
noBotProtectionWarning: "Nessuna protezione impostata contro i bot."
configure: "Imposta"
postToGallery: "Pubblicare nella galleria"
gallery: "Galleria"
recentPosts: "Le più recenti"
popularPosts: "Le più visualizzate"
shareWithNote: "Condividere in nota"
expiration: "Scadenza"
middle: "Predefinito"
_gallery:
my: "Le mie pubblicazioni"
liked: "Pubblicazioni che mi piacciono"
like: "Mi piace!"
unlike: "Non mi piace più"
_email:
_follow:
title: "Ha iniziato a seguirti"
_receiveFollowRequest:
title: "Hai ricevuto una richiesta di follow"
_plugin:
install: "Installa estensioni"
installWarn: "Si prega di installare soltanto estensioni che provengono da fonti affidabili."
manage: "Gestisci estensioni"
_registry:
key: "Dati"
keys: "Dati"
domain: "Dominio"
createKey: "Crea chiave"
_aboutMisskey:
about: "Misskey è un software libero e open source, sviluppato da syuilo dal 2014."
contributors: "Principali sostenitori"
allContributors: "Tutti i sostenitori"
source: "Codice sorgente"
morePatrons: "Ci sono molti altri che ci sostengono. Grazie 🥰"
translation: "Tradurre Misskey"
donate: "Sostieni Misskey"
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
patrons: "Sostenitori"
_nsfw:
respect: "Nascondere i media segnati come sensibli"
ignore: "Visualizzare i media segnati come sensibili"
force: "Nascondere tutti i media"
_mfm:
cheatSheet: "Bigliettino MFM"
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti di Misskey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
dummy: "Il Fediverso si espande con Misskey"
mention: "Menzioni"
mentionDescription: "Si può menzionare un utente specifico digitando il suo nome utente subito dopo il segno @."
hashtag: "Hashtag"
@ -643,7 +776,9 @@ _mfm:
search: "Cerca"
blur: "Sfocatura"
font: "Tipo di carattere"
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
_reversi:
reversi: "Reversi"
gameSettings: "Impostazioni di gioco"
botSettings: "Opzioni del bot"
black: "Nero"
@ -654,6 +789,10 @@ _instanceTicker:
none: "Nascondi"
remote: "Mostra solo per gli/le utenti remotə"
always: "Mostra sempre"
_serverDisconnectedBehavior:
reload: "Ricarica automaticamente"
dialog: "Apri avviso in finestra"
quiet: "Visualizza avviso in modo discreto"
_channel:
create: "Nuovo canale"
edit: "Gerisci canale"
@ -665,12 +804,17 @@ _channel:
usersCount: "{n} partecipanti"
notesCount: "{n} note"
_sidebar:
full: "Intera"
icon: "Icone"
hide: "Nascondere"
_wordMute:
muteWords: "Parole da silenziare"
muteWords: "Parole da filtrare"
muteWordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
muteWordsDescription2: "Metti le parole chiavi tra slash per usare espressioni regolari (regexp)."
softDescription: "Nascondi della timeline note che rispondono alle condizioni impostate qui."
hardDescription: "Impedisci alla timeline di caricare le note che rispondono alle condizioni impostate qui. Inoltre, le note scompariranno in modo irreversibile, anche se le condizioni verranno successivamente rimosse."
soft: "Moderato"
hard: "Severo"
mutedNotes: "Note silenziate"
_theme:
explore: "Esplora temi"
@ -689,11 +833,15 @@ _theme:
constant: "Costante"
defaultValue: "Valore predefinito"
color: "Colore"
refConst: "Chiama costante"
key: "Chiave"
func: "Funzione"
funcKind: "Tipo di funzione"
argument: "Argomento"
darken: "Scuro"
lighten: "Chiaro"
inputConstantName: "Inserisci un nome per la costante"
deleteConstantConfirm: "Vuoi davvero eliminare la costante {const}?"
keys:
bg: "Sfondo"
fg: "Testo"
@ -710,12 +858,30 @@ _theme:
link: "Link"
hashtag: "Hashtag"
mention: "Menzioni"
mentionMe: "Menzioni (di me)"
renote: "Rinota"
divider: "Interruzione di linea"
infoBg: "Sfondo informazioni"
infoFg: "Testo di informazioni"
infoWarnBg: "Sfondo degli avvisi"
infoWarnFg: "Testo di avviso"
cwBg: "Sfondo del CW"
cwFg: "Testo del pulsante CW"
cwHoverBg: "Sfondo del pulsante CW (sorvolato)"
toastBg: "Sfondo di notifica a comparsa"
toastFg: "Testo di notifica a comparsa"
buttonBg: "Sfondo del pulsante"
buttonHoverBg: "Sfondo del pulsante (sorvolato)"
inputBorder: "Inquadra casella di testo"
listItemHoverBg: "Sfondo della voce di elenco (sorvolato)"
driveFolderBg: "Sfondo della cartella di disco"
messageBg: "Sfondo della chat"
_sfx:
note: "Nota"
noteMy: "Mia nota"
notification: "Notifiche"
chat: "Messaggi"
chatBg: "Chat (sfondo)"
antenna: "Ricezione dell'antenna"
channel: "Notifiche di canale"
_ago:
@ -748,7 +914,7 @@ _tutorial:
step4_1: "Hai pubblicato qualcosa?"
step4_2: "Se puoi visualizzare la tua nota sulla timeline, ce l'hai fatta!"
step5_1: "Adesso, cerca di seguire altre persone per vivacizzare la tua timeline. "
step5_2: "La pagina {featured} mostra le note di tendenza su questa istanza e, sfogliandole, magari toverai degli account che ti piacciono e che vorrai seguire. Oppure, potrai trovare utenti popolari usando {explore}."
step5_2: "La pagina {featured} mostra le note di tendenza su questa istanza, e magari ti aiuterà a trovare account che ti piacciono e che vorrai seguire. Oppure, potrai trovare utenti popolari usando {explore}."
step5_3: "Per seguire altrə utenti, clicca sul loro avatar per aprire la pagina di profilo dove puoi premere il pulsante \"Seguire\". "
step5_4: "Alcunə utenti scelgono di confermare manualmente le richieste di follow che ricevono, quindi a seconda delle persone potrebbe volerci un pò prima che la tua richiesta sia accolta."
step6_1: "Ora, se puoi visualizzare le note di altrə utenti sulla tua timeline, ce l'hai fatta!"
@ -757,13 +923,21 @@ _tutorial:
step7_1: "Complimenti! Sei arrivat@ alla fine dell'esercitazione di base su come usare Misskey. "
step7_2: "Se vuoi saperne di più su Misskey, puoi dare un'occhiata alla sezione {help}."
step7_3: "Da ultimo, buon divertimento su Misskey! 🚀"
_2fa:
registerDevice: "Aggiungi dispositivo"
_permissions:
"read:account": "Visualizzare le informazioni dell'account"
"write:account": "Modificare le informazioni dell'account"
"read:blocks": "Visualizza gli account bloccati"
"write:blocks": "Gestisci gli account bloccati"
"read:drive": "Aprire il Drive"
"write:drive": "Gestire il Drive"
"read:favorites": "Visualizza i tuoi preferiti"
"write:favorites": "Gestisci i tuoi preferiti"
"read:following": "Vedi le informazioni di follow"
"write:following": "Seguiti/ Smetti di seguire"
"read:messaging": "Visualizzare la chat"
"write:messaging": "Gestire la chat"
"read:mutes": "Vedi account silenziati"
"write:mutes": "Gerisci account silenziati"
"write:notes": "Creare / Eliminare note"
@ -771,10 +945,22 @@ _permissions:
"write:notifications": "Gerisci notifiche"
"read:reactions": "Vedi reazioni"
"write:reactions": "Gerisci reazioni"
"write:votes": "Votare"
"read:pages": "Visualizzare pagine"
"write:pages": "Gestire pagine"
"read:page-likes": "Visualizzare i \"Mi piace\" di pagine"
"write:page-likes": "Gestire i \"Mi piace\" di pagine"
"read:user-groups": "Vedi gruppi di utenti"
"write:user-groups": "Gestisci gruppi di utenti"
"read:channels": "Visualizza canali"
"write:channels": "Gerisci canali"
_auth:
shareAccess: "Autorizzare「{name}」ad accedere al tuo account?"
shareAccessAsk: "Vuoi davvero consentire l'accesso al tuo account a questa app'?"
permissionAsk: "Questa app richiede le seguenti autorizzazioni:"
pleaseGoBack: "Si prega di ritornare sulla app"
callback: "Ritornando sulla app"
denied: "Accesso negato"
_antennaSources:
all: "Tutte le note"
homeTimeline: "Note dagli utenti che segui"
@ -801,21 +987,40 @@ _widgets:
photos: "Foto"
digitalClock: "Orologio digitale"
federation: "Federazione"
postForm: "Finestra di pubblicazione"
slideshow: "Diapositive"
button: "Pulsante"
onlineUsers: "Utenti online"
jobQueue: "Coda di lavoro"
serverMetric: "Statistiche server"
aiscript: "Console AiScript"
_cw:
hide: "Nascondere"
show: "Mostra di più"
chars: "{count} caratteri"
files: "{count} file"
_poll:
noOnlyOneChoice: "Sono necessarie almeno 2 risposte"
choiceN: "Opzione {n}"
noMore: "Hai aggiunto il numero massimo di opzioni."
canMultipleVote: "Risposte multiple"
canMultipleVote: "Possibilità di risposte multiple"
expiration: "Scadenza"
infinite: "Permanente"
infinite: "Non scade"
at: "Seleziona data"
after: "Seleziona durata"
deadlineDate: "Data di scadenza"
deadlineTime: "h"
voted: "Votato"
deadlineTime: "Ora di scadenza"
duration: "Durata"
votesCount: "{n} voti"
totalVotes: "Totale di {n} voti"
vote: "Vota"
showResult: "Visualizza risultati"
voted: "Hai votato"
closed: "Terminato"
remainingDays: "Rimangono {d} giorni e {h} ore"
remainingHours: "Rimangono {h} ore e {m} minuti"
remainingMinutes: "Rimangono {m} minuti e {s} secondi"
remainingSeconds: "Rimangono {s} secondi"
_visibility:
public: "Pubblica"
publicDescription: "Visibile per tutti sul Fediverso"
@ -831,13 +1036,24 @@ _postForm:
replyPlaceholder: "Nota la tua risposta.."
quotePlaceholder: "Cita Nota..."
channelPlaceholder: "Pubblica in canale"
_placeholders:
a: "Che succede?"
b: "È successo qualcosa?"
c: "Che cos'hai in mente?"
d: "Vuoi dire qualcosa?"
e: "Scrivi qualcosa qui"
f: "Aspettando che scriva..."
_profile:
name: "Nome"
username: "Nome utente"
description: "Bio"
metadata: "Metadati"
youCanIncludeHashtags: "Puoi anche includere hashtag."
metadata: "Informazioni aggiuntive"
metadataEdit: "Modifica informazioni aggiuntive"
metadataDescription: "Puoi pubblicare fino a quattro informazioni aggiuntive sul profilo."
metadataLabel: "Etichetta"
metadataContent: "Contenuto"
changeAvatar: "Modifica immagine profilo"
changeBanner: "Cambia intestazione"
_exportOrImport:
allNotes: "Tutte le note"
@ -846,67 +1062,136 @@ _exportOrImport:
blockingList: "Account bloccati"
userLists: "Liste"
_charts:
federationInstancesIncDec: "Variazione del numero di istanze federate"
federationInstancesTotal: "Numero totale di istanze federate"
usersIncDec: "Variazione del numero di utenti"
usersTotal: "Numero totale di utenti"
activeUsers: "Numero di utenti attivi"
notesIncDec: "Variazione del numero di note"
localNotesIncDec: "Variazione del numero di note locali"
remoteNotesIncDec: "Variazione del numero di note distanti"
notesTotal: "Conteggio totale di note"
filesIncDec: "Variazione del numero dei file"
filesTotal: "Numero totale di file"
storageUsageIncDec: "Variazione dell'utilizzo dell'immagazzinamento"
storageUsageTotal: "Utilizzo totale dell'immagazzinamento"
_instanceCharts:
requests: "Richieste"
users: "Variazione del numero di utenti"
usersTotal: "Totale cumulativo di utenti"
notes: "Variazione del numero di note"
notesTotal: "Totale cumulato di note"
ff: "Variazione dei follow/ follower"
ffTotal: "Totale cumulato dei follow/ follower"
cacheSize: "Variazione dello spazio occupato dalla cache"
cacheSizeTotal: "Totale cumulato dello spazio occupato dalla cache"
files: "Variazione del numero di file"
filesTotal: "Totale cumulato del numero di file"
_timelines:
home: "Home"
local: "Locale"
social: "Sociale"
global: "Federata"
_rooms:
roomOf: "Camera di {user}"
addFurniture: "Disponi mobilia"
translate: "Sposta"
rotate: "Ruota"
exit: "Indietro"
remove: "Togli"
clear: "Rimuovi tutto"
clearConfirm: "Sei sicur@ di voler rimuovere tutti i mobili dalla tua camera?"
leaveConfirm: "Hai fatto modifiche ancora non salvate. Vuoi davvero uscire?"
chooseImage: "Seleziona immagine"
roomType: "Tipo di stanza"
carpetColor: "Colore del suolo"
_roomType:
default: "Predefinito"
washitsu: "Washitsu"
_furnitures:
milk: "Cartone del latte"
bed: "Letto"
low-table: "Tavolino Coffee"
low-table: "Tavolino"
desk: "Tavolo"
chair: "Sedia"
chair2: "Sedia 2"
fan: "Ventilatore"
pc: "PC"
pc: "Computer"
plant: "Pianta da appartamento"
plant2: "Pianta da appartamento2"
eraser: "Gomma"
pencil: "Matita"
pudding: "Pudding"
cardboard-box: "Scatola di cartone"
cardboard-box2: "Scatola di cartone 2"
cardboard-box3: "Scatola di cartone 3"
book: "Libro"
book2: "Libro2"
piano: "Pianoforte"
facial-tissue: "Scatola di fazzolettini"
server: "Server"
moon: "Luna"
corkboard: "Bacheca"
mousepad: "Tappetino per il mouse"
monitor: "Monitor "
keyboard: "Tastiera"
carpet-stripe: "Tappeto (a strisce)"
mat: "Zerbino"
color-box: "Libreria"
wall-clock: "Orologio da parete"
photoframe: "Cornice"
cube: "Cubo"
tv: "Televisore"
tv: "TV"
pinguin: "Pinguino"
rubik-cube: "Cubo di Rubik"
poster-h: "Poster (orizzontale)"
poster-v: "Poster (verticale)"
sofa: "Divano"
spiral: "Scale a chiocciola"
bin: "Cestino"
cup-noodle: "Noodle istantanei"
holo-display: "Visualizzazione olografica"
energy-drink: "Bevanda energetica"
doll-ai: "Bambola Ai"
banknote: "Mazzetta di banconote"
_pages:
newPage: "Crea pagina"
editPage: "Modifica pagina"
readPage: "Visualizzando fonte "
created: "Pagina creata!"
updated: "Pagina aggiornata con successo!"
deleted: "Pagina eliminata"
pageSetting: "Impostazioni pagina"
nameAlreadyExists: "Esiste già una pagina con lo stesso URL."
invalidNameTitle: "L'URL di pagina definito non è valido"
invalidNameText: "Verifica che il campo non è vuoto"
editThisPage: "Modifica questa pagina"
viewSource: "Visualizza sorgente"
viewPage: "Visualizza pagina"
like: "Mi piace"
unlike: "Togli Mi piace"
my: "Le mie pagine"
liked: "Pagine che mi piacciono"
featured: "Popolari"
contents: "Contenuto"
content: "Blocco di pagina"
variables: "Variabili"
title: "Titolo"
url: "URL della pagina"
summary: "Riassunto di pagina"
hideTitleWhenPinned: "Nascondere il titolo pagina quando è fissata in cima al profilo."
font: "Tipo di carattere"
fontSerif: "Serif"
fontSansSerif: "Sans serif"
eyeCatchingImageSet: "Imposta un'immagine attrattiva"
eyeCatchingImageRemove: "Elimina l'immagine attrattiva"
chooseBlock: "Aggiungi blocco"
selectType: "Seleziona tipo"
enterVariableName: "Digita un nome di variabile"
variableNameIsAlreadyUsed: "Esiste già una variabile con lo stesso nome"
contentBlocks: "Contenuto"
inputBlocks: "Blocchi di input"
specialBlocks: "Speciale"
blocks:
text: "Testo"
textarea: "Area di testo"
@ -916,16 +1201,20 @@ _pages:
if: "Se"
_if:
variable: "Variabili"
post: "Finestra di pubblicazione"
_post:
text: "Contenuto"
textInput: "Immissione testo"
_textInput:
name: "Nome della variabile"
text: "Titolo"
default: "Valore predefinito"
textareaInput: "Immissione testo a più righe"
_textareaInput:
name: "Nome della variabile"
text: "Titolo"
default: "Valore predefinito"
numberInput: "Immissione numerica"
_numberInput:
name: "Nome della variabile"
text: "Titolo"
@ -938,18 +1227,35 @@ _pages:
id: "ID nota"
idDescription: "Qui puoi anche incollare l'URL della nota che vuoi impostare."
detailed: "Visualizzazione dettagliata"
switch: "Interruttore"
_switch:
name: "Nome della variabile"
text: "Titolo"
default: "Valore predefinito"
counter: "Contatore"
_counter:
name: "Nome della variabile"
text: "Titolo"
inc: "Valore da aggiungere"
_button:
text: "Titolo"
colored: "Colorato"
action: "Operazione da eseguire quando viene premuto il pulsante"
_action:
dialog: "Visualizzare una finestra di dialogo"
_dialog:
content: "Contenuto"
resetRandom: "Ripristinare un numero aleatorio"
pushEvent: "Inviare evento"
_pushEvent:
event: "Nome evento"
message: "Messaggio da visualizzare quando abilitato"
variable: "Variabile da inviare"
no-variable: "Nessun contenuto"
callAiScript: "Chiamare AiScript"
_callAiScript:
functionName: "Nome della funzione"
radioButton: "Opzioni"
_radioButton:
name: "Nome della variabile"
title: "Titolo"
@ -963,6 +1269,8 @@ _pages:
list: "Liste"
blocks:
text: "Testo"
multiLineText: "Testo (a più righe)"
textList: "Lista di testo"
_strLen:
arg1: "Testo"
_strPick:
@ -1017,13 +1325,18 @@ _pages:
arg2: "B"
_if:
arg1: "Se"
arg2: "Se"
random: "Aleatorietà"
_randomPick:
arg1: "Liste"
_dailyRandomPick:
arg1: "Liste"
_seedRandom:
arg2: "Probabilità"
_seedRandomPick:
arg2: "Liste"
_DRPWPM:
arg1: "Lista di testo"
_pick:
arg1: "Liste"
_listLen:
@ -1037,13 +1350,14 @@ _pages:
types:
string: "Testo"
array: "Liste"
stringArray: "Lista di testo"
_notification:
fileUploaded: "File caricato correttamente"
youGotMention: "{name} ti ha menzionato"
youGotReply: "{name} ti ha risposto"
youGotQuote: "{name} ha citato il tuo Nota e ha detto"
youRenoted: "{name} ha rinotato"
youGotPoll: "{name} ha volluto."
youGotPoll: "{name} ha votato"
youGotMessagingMessageFromUser: "{name} ti ha mandato un messaggio"
youGotMessagingMessageFromGroup: "{name} ti ha mandato un messaggio nella chat"
youWereFollowed: "Ha iniziato a seguirti"
@ -1064,7 +1378,21 @@ _notification:
groupInvited: "Invito a un gruppo"
app: "Notifiche da applicazioni"
_deck:
alwaysShowMainColumn: "Mostra sempre la colonna principale"
columnAlign: "Allineare colonne"
columnMargin: "Margine tra le colonne"
columnHeaderHeight: "Dimensioni dell'intestazione della colonna"
addColumn: "Aggiungi colonna"
swapLeft: "Sposta a sinistra"
swapRight: "Sposta a destra"
swapUp: "Sposta in alto"
swapDown: "Sposta in basso"
stackLeft: "Impila a sinistra"
popRight: "Estrai a destra"
profile: "Profilo"
_columns:
main: "Principale"
widgets: "Widget"
notifications: "Notifiche"
tl: "Timeline"
antenna: "Antenne"

View File

@ -7,6 +7,7 @@ search: "検索"
notifications: "通知"
username: "ユーザー名"
password: "パスワード"
forgotPassword: "パスワードを忘れた"
fetchingAsApObject: "連合に照会中"
ok: "OK"
gotIt: "わかった"
@ -704,6 +705,7 @@ editCode: "コードを編集"
apply: "適用"
receiveAnnouncementFromInstance: "インスタンスからのお知らせを受け取る"
emailNotification: "メール通知"
publish: "公開"
inChannelSearch: "チャンネル内検索"
useReactionPickerForContextMenu: "右クリックでリアクションピッカーを開く"
typingUsers: "{users}が入力中"
@ -741,6 +743,30 @@ switch: "切り替え"
noMaintainerInformationWarning: "管理者情報が設定されていません。"
noBotProtectionWarning: "Bot防御が設定されていません。"
configure: "設定する"
postToGallery: "ギャラリーへ投稿"
gallery: "ギャラリー"
recentPosts: "最近の投稿"
popularPosts: "人気の投稿"
shareWithNote: "ノートで共有"
ads: "広告"
expiration: "期限"
memo: "メモ"
priority: "優先度"
high: "高"
middle: "中"
low: "低"
emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
_forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。"
contactAdmin: "このインスタンスではメールがサポートされていないため、パスワードリセットを行う場合は管理者までお問い合わせください。"
_gallery:
my: "自分の投稿"
liked: "いいねした投稿"
like: "いいね!"
unlike: "いいね解除"
_email:
_follow:

View File

@ -138,7 +138,6 @@ flagAsBotDescription: "もしこのアカウントがプログラムによって
flagAsCat: "Catやで"
flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?"
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
addAcount: "アカウント追加"
loginFailed: "ログインに失敗してしもうた…"
showOnRemote: "リモートで見る"
general: "全般"
@ -347,7 +346,6 @@ antennaExcludeKeywords: "除外キーワード"
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
notifyAntenna: "新しいノートを追加すんで"
withFileAntenna: "なんか添付されたノートだけ"
serviceworker: "ServiceWorker"
enableServiceworker: "ServiceWorkerをつこて"
antennaUsersDescription: "ユーザー名を改行で区切ったってな"
caseSensitive: "大文字と小文字は別もんや"
@ -448,7 +446,6 @@ category: "カテゴリ"
tags: "タグ"
docSource: "このドキュメントのソース"
createAccount: "アカウントを作成"
existingAcount: "既存のアカウント"
regenerate: "再生成"
fontSize: "フォントサイズ"
noFollowRequests: "フォロー申請はあらへんで"
@ -541,7 +538,6 @@ large: "大"
medium: "中"
small: "小"
edit: "編集"
emailConfig: "メールサーバー設定"
enableEmail: "メール配信を受け取る"
emailConfigInfo: "メールアドレスの確認とかパスワードリセットの時に使うで"
email: "メール"
@ -556,7 +552,7 @@ smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
testEmail: "配信テスト"
wordMute: "ワードミュート"
userSaysSomething: "{name}が何か言ったようやで"
makeActive: "アクティブにしてや"
makeActive: "使うで"
display: "表示"
copy: "コピー"
metrics: "メトリクス"
@ -619,6 +615,7 @@ textColor: "文字"
saveAs: "名前を付けて保存"
advanced: "高度"
value: "値"
createdAt: "作成した日"
updatedAt: "更新日時"
saveConfirm: "保存するで?"
deleteConfirm: "ホンマに削除するで?"
@ -641,8 +638,19 @@ typingUsers: "{users}が今書きよるで"
jumpToSpecifiedDate: "特定の日付にジャンプ"
showingPastTimeline: "過去のタイムラインを表示してるで"
clear: "クリア"
markAllAsRead: "もうみな読んでもうたわ"
goBack: "戻る"
info: "情報"
user: "ユーザー"
administration: "管理"
ads: "広告"
expiration: "期限"
memo: "メモ"
high: "高い"
middle: "中"
low: "低い"
_gallery:
unlike: "良くないわ"
_email:
_follow:
title: "フォローされたで"

View File

@ -58,6 +58,7 @@ instances: "ನಿದರ್ಶನ"
remove: "ಅಳಿಸು"
smtpUser: "ಬಳಕೆಹೆಸರು"
smtpPass: "ಗುಪ್ತಪದ"
user: "ಬಳಕೆದಾರ"
_email:
_follow:
title: "ಹಿಂಬಾಲಿಸಿದರು"

View File

@ -138,7 +138,7 @@ flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우
flagAsCat: "나는 고양이다냥"
flagAsCatDescription: "이 계정이 고양이라면 활성화 해주세요."
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
addAcount: "계정 추가"
addAccount: "계정 추가"
loginFailed: "로그인에 실패했습니다"
showOnRemote: "리모트에서 보기"
general: "일반"
@ -349,7 +349,6 @@ antennaExcludeKeywords: "제외할 키워드"
antennaKeywordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다"
notifyAntenna: "새로운 노트를 알림"
withFileAntenna: "파일이 첨부된 노트만"
serviceworker: "ServiceWorker"
enableServiceworker: "ServiceWorker 사용"
antennaUsersDescription: "유저명을 한 줄에 한 명씩 적습니다"
caseSensitive: "대소문자를 구분"
@ -453,7 +452,7 @@ category: "카테고리"
tags: "태그"
docSource: "이 문서의 소스"
createAccount: "계정 만들기"
existingAcount: "기존 계정"
existingAccount: "기존 계정"
regenerate: "재생성"
fontSize: "글자 크기"
noFollowRequests: "처리되지 않은 팔로우 요청이 없습니다"
@ -568,7 +567,7 @@ pluginTokenRequestedDescription: "이 플러그인은 여기서 설정한 권한
notificationType: "알림 유형"
edit: "편집"
useStarForReactionFallback: "알 수 없는 리액션 이모지 대신 ★ 사용"
emailConfig: "메일 서버 설정"
emailServer: "메일 서버"
enableEmail: "이메일 송신 기능 활성화"
emailConfigInfo: "가입 시 메일 주소 확인이나 비밀번호 초기화 시에 사용합니다."
email: "이메일"
@ -705,6 +704,7 @@ editCode: "코드 수정"
apply: "적용"
receiveAnnouncementFromInstance: "이 인스턴스의 알림을 이메일로 수신할게요"
emailNotification: "메일 알림"
publish: "게시"
inChannelSearch: "채널에서 검색"
useReactionPickerForContextMenu: "우클릭하여 리액션 선택기 열기"
typingUsers: "{users} 님이 입력하고 있어요.."
@ -726,8 +726,34 @@ onlineStatus: "온라인 상태"
hideOnlineStatus: "온라인 상태 숨기기"
hideOnlineStatusDescription: "온라인 상태를 숨기면, 검색과 같은 일부 기능에 영향을 미칠 수 있습니다."
online: "온라인"
active: "활동 중"
active: "최근에 활동함"
offline: "오프라인"
notRecommended: "추천하지 않음"
botProtection: "Bot 방어"
instanceBlocking: "인스턴스 차단"
selectAccount: "계정 선택"
enabled: "활성화"
disabled: "비활성화"
quickAction: "빠른 동작"
user: "유저"
administration: "관리"
accounts: "계정"
switch: "전환"
noMaintainerInformationWarning: "관리자 정보가 설정되어 있지 않습니다."
noBotProtectionWarning: "Bot 방어가 설정되어 있지 않습니다."
configure: "설정하기"
postToGallery: "갤러리에 업로드"
gallery: "갤러리"
recentPosts: "최근 포스트"
popularPosts: "인기 포스트"
shareWithNote: "노트로 공유"
expiration: "투표 기한"
middle: "보통"
_gallery:
my: "내 갤러리"
liked: "좋아요 한 갤러리"
like: "좋아요!"
unlike: "좋아요 취소"
_email:
_follow:
title: "새로운 팔로워가 있습니다"

View File

@ -1,6 +1,7 @@
---
_lang_: "język polski"
headlineMisskey: "Sieć połączona wpisami"
introMisskey: "Misskey jest serwisem mikroblogowym typu open source.\nMisskey to opensource'owy serwis mikroblogowy, w którym możesz tworzyć \"notatki\", aby dzielić się tym, co się dzieje i opowiadać wszystkim o sobie.\nMożesz również użyć funkcji \"Reakcje\", aby szybko dodać własne reakcje do notatek innych użytkowników👍.\nOdkrywaj nowy świat🚀!"
monthAndDay: "{month}-{day}"
search: "Szukaj"
notifications: "Powiadomienia"
@ -61,7 +62,9 @@ import: "Importuj"
export: "Eksportuj"
files: "Pliki"
download: "Pobierz"
driveFileDeleteConfirm: "Czy chcesz usunąć plik \"{name}\"? Zniknie również notatka, do której dołączony jest ten plik."
unfollowConfirm: "Czy na pewno chcesz przestać obserwować {name}?"
exportRequested: "Zażądałeś eksportu. Może to zająć trochę czasu. Po zakończeniu eksportu zostanie on dodany do Twoich \"dysków\"."
lists: "Listy"
noLists: "Nie masz żadnych list"
note: "Utwórz wpis"
@ -133,7 +136,6 @@ flagAsBot: "To konto jest botem"
flagAsCat: "To konto jest kotem"
flagAsCatDescription: "Przełącz tę opcję, aby konto było oznaczone jako kot."
autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników, których obserwujesz"
addAcount: "Dodaj konto"
loginFailed: "Nie udało się zalogować"
showOnRemote: "Zobacz na zdalnej instancji"
general: "Ogólne"
@ -331,7 +333,6 @@ name: "Nazwa"
antennaSource: "Źródło Anteny"
antennaExcludeKeywords: "Wykluczone słowa kluczowe"
withFileAntenna: "Filtruj tylko wpisy z załączonym plikiem"
serviceworker: "ServiceWorker"
enableServiceworker: "Włącz ServiceWorker"
antennaUsersDescription: "Wypisz po jednej nazwie użytkownika w linii"
caseSensitive: "Wielkość liter ma znaczenie"
@ -431,7 +432,6 @@ category: "Kategoria"
tags: "Tagi"
docSource: "Źródło tego dokumentu"
createAccount: "Utwórz konto"
existingAcount: "Istniejące konta"
regenerate: "Wygeneruj ponownie"
fontSize: "Rozmiar czcionki"
noFollowRequests: "Nie masz żadnych oczekujących próśb o możliwość obserwacji"
@ -540,7 +540,6 @@ pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawio
notificationType: "Rodzaj powiadomień"
edit: "Edytuj"
useStarForReactionFallback: "Użyj ★ jako zapasowego emoji, gdy emoji reakcji jest nieznane"
emailConfig: "Konfiguracja serwera e-mail"
enableEmail: "Włącz dostarczanie wiadomości e-mail"
emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji, lub gdy zapomnisz hasła"
email: "Adres e-mail"
@ -646,6 +645,12 @@ textColor: "Tekst"
value: "Wartość"
goBack: "Wróć"
info: "Informacje"
user: "Użytkownicy"
administration: "Zarządzanie"
expiration: "Ankieta kończy się"
middle: "Średnie"
_gallery:
unlike: "Cofnij polubienie"
_email:
_follow:
title: "Zaobserwował(a) Cię"

View File

@ -138,7 +138,7 @@ flagAsBotDescription: "Включите, если этот аккаунт упр
flagAsCat: "Аккаунт кота"
flagAsCatDescription: "Включите, и этот аккаунт будет помечен как кошачий."
autoAcceptFollowed: "Принимать подписчиков автоматически"
addAcount: "Добавить аккаунт"
addAccount: "Добавить учётную запись"
loginFailed: "Неудачная попытка входа"
showOnRemote: "Перейти к оригиналу на сайт"
general: "Общее"
@ -349,7 +349,6 @@ antennaExcludeKeywords: "Исключения"
antennaKeywordsDescription: "Пишите слова через пробел в одной строке, чтобы ловить их появление вместе; на отдельных строках располагайте слова, или группы слов, чтобы ловить любые из них."
notifyAntenna: "Уведомлять о новых заметках"
withFileAntenna: "Только заметки с вложениями"
serviceworker: "ServiceWorker"
enableServiceworker: "Включить ServiceWorker"
antennaUsersDescription: "Пишите каждое название аккаута на отдельной строке"
caseSensitive: "С учётом регистра"
@ -453,7 +452,7 @@ category: "Категория"
tags: "Метки"
docSource: "Источник документа"
createAccount: "Новая учётная запись"
existingAcount: "Уже существующий"
existingAccount: "Существующая учётная запись"
regenerate: "Создать повторно"
fontSize: "Размер шрифта"
noFollowRequests: "Нерассмотренные запросы на подписку отсутствуют"
@ -568,7 +567,7 @@ pluginTokenRequestedDescription: "Это расширение сможет по
notificationType: "Тип уведомления"
edit: "Изменить"
useStarForReactionFallback: "Ставить ★ в качестве реакции вместо неизвестного эмодзи"
emailConfig: "Настройки почтового сервера"
emailServer: "Сервер электронной почты"
enableEmail: "Включить обмен электронной почтой"
emailConfigInfo: "Используется для подтверждения адреса электронной почты и сброса пароля."
email: "Электронная почта"
@ -687,6 +686,7 @@ textColor: "Текст"
saveAs: "Сохранить под названием…"
advanced: "Для продвинутых"
value: "Значения"
createdAt: "Создано"
updatedAt: "Обновлено"
saveConfirm: "Сохранить изменения?"
deleteConfirm: "Удалить?"
@ -704,14 +704,56 @@ editCode: "Редактировать исходный текст"
apply: "Применить"
receiveAnnouncementFromInstance: "Получать оповещения с инстанса"
emailNotification: "Уведомления по электронной почте"
publish: "Опубликовать"
inChannelSearch: "Поиск по каналу"
useReactionPickerForContextMenu: "Открывать палитру реакций правой кнопкой"
typingUsers: "Стук клавиш. Это {users}…"
jumpToSpecifiedDate: "Перейти к заданной дате"
showingPastTimeline: "Отображается старая лента"
clear: "Очистить"
markAllAsRead: "Отметить всё как прочитанное"
goBack: "Выход"
unlikeConfirm: "В самом деле отменить «нравится»?"
fullView: "Полный вид"
quitFullView: "Закрыть полный вид"
addDescription: "Добавить описание"
userPagePinTip: "Можно добавить сюда заметки, выбрав нужную, и включив в её меню пункт «Закрепить в профиле»."
notSpecifiedMentionWarning: "В этой заметке есть упоминание тех, кто не включён в адресаты"
info: "Описание"
userInfo: "Сведения о пользователе"
unknown: "Неизвестно"
onlineStatus: "Присутствие в сети"
hideOnlineStatus: "Скрыть присутствие"
hideOnlineStatusDescription: "Сокрытие присутствия делает некоторые функции, такие как поиск, менее удобными."
online: "В сети"
active: "Действует"
offline: "Не в сети"
notRecommended: "Не рекомендуется"
botProtection: "Ботозащита"
instanceBlocking: "Блокировка инстансов"
selectAccount: "Выберите учётную запись"
enabled: "Вкл."
disabled: "Откл."
quickAction: "Быстрое действие"
user: "Пользователи"
administration: "Управление"
accounts: "Учётные записи"
switch: "Переключение"
noMaintainerInformationWarning: "Не заполнены сведения об администраторах"
noBotProtectionWarning: "Ботозащита не настроена"
configure: "Настроить"
postToGallery: "Опубликовать в галерею"
gallery: "Галерея"
recentPosts: "Недавние публикации"
popularPosts: "Популярные публикации"
shareWithNote: "Поделиться заметкой"
expiration: "Опрос длится"
middle: "Средне"
_gallery:
my: "Личная"
liked: "Понравившееся"
like: "Нравится!"
unlike: "Отменить «нравится»"
_email:
_follow:
title: "Новый подписчик"

View File

@ -138,7 +138,6 @@ flagAsBotDescription: "Ввімкніть якщо цей обліковий з
flagAsCat: "Акаунт кота"
flagAsCatDescription: "Ввімкніть, щоб позначити, що обліковий запис є котиком."
autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на яких ви підписані"
addAcount: "Додати акаунт"
loginFailed: "Не вдалося увійти"
showOnRemote: "Переглянути в оригіналі"
general: "Загальне"
@ -347,7 +346,6 @@ antennaExcludeKeywords: "Винятки"
antennaKeywordsDescription: "Розділення ключових слів пробілами для \"І\" або з нової лінійки для \"АБО\""
notifyAntenna: "Сповіщати про нові нотатки"
withFileAntenna: "Тільки нотатки з вкладеними файлами"
serviceworker: "ServiceWorker"
enableServiceworker: "Ввімкнути ServiceWorker"
antennaUsersDescription: "Список імя користувачів в стопчик"
caseSensitive: "З урахуванням регістру"
@ -450,7 +448,6 @@ category: "Категорія"
tags: "Теги"
docSource: "Джерело цього документа"
createAccount: "Створити акаунт"
existingAcount: "Існуючий акаунт"
regenerate: "Оновити"
fontSize: "Розмір шрифту"
noFollowRequests: "Немає запитів на підписку"
@ -564,7 +561,6 @@ pluginTokenRequestedDescription: "Цей плагін зможе викорис
notificationType: "Тип сповіщення"
edit: "Редагувати"
useStarForReactionFallback: "Використовувати ★ як запасний варіант, якщо емодзі реакції невідомий"
emailConfig: "Налаштування email сервера"
enableEmail: "Увімкнути функцію доставки пошти"
emailConfigInfo: "Використовується для підтвердження електронної пошти підчас реєстрації, а також для відновлення паролю."
email: "E-mail"
@ -691,6 +687,12 @@ registry: "Реєстр"
closeAccount: "Закрити обліковий запис"
goBack: "Назад"
info: "Інформація"
user: "Користувачі"
administration: "Управління"
expiration: "Опитування закінчується"
middle: "Середній"
_gallery:
unlike: "Не вподобати"
_email:
_follow:
title: "Новий підписник"

View File

@ -138,7 +138,7 @@ flagAsBotDescription: "如果此帐户由程序控制,请启用此项。启用
flagAsCat: "这个账户是Cat"
flagAsCatDescription: "如果您想表明此帐户是一只猫,请打开此标志。"
autoAcceptFollowed: "自动允许关注"
addAcount: "添加账户"
addAccount: "添加账户"
loginFailed: "登录失败"
showOnRemote: "转到所在实例显示"
general: "常规设置"
@ -349,7 +349,6 @@ antennaExcludeKeywords: "排除关键字"
antennaKeywordsDescription: "使用空格分隔会产生AND规范并且使用换行符分隔会产生OR规范"
notifyAntenna: "通知新帖子"
withFileAntenna: "仅带有附件的帖子"
serviceworker: "ServiceWorker"
enableServiceworker: "启用ServiceWorker"
antennaUsersDescription: "指定用户名,用换行符分隔"
caseSensitive: "区分大小写"
@ -453,7 +452,7 @@ category: "类别"
tags: "标签"
docSource: "文件来源"
createAccount: "注册账户"
existingAcount: "现有的帐户"
existingAccount: "现有的帐户"
regenerate: "重新生成"
fontSize: "字体大小"
noFollowRequests: "没有关注申请"
@ -568,7 +567,7 @@ pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限"
notificationType: "通知类型"
edit: "编辑"
useStarForReactionFallback: "如果回应的是未知表情符号,则使用★作为代替"
emailConfig: "邮件服务器设置"
emailServer: "邮件服务器"
enableEmail: "启用发送邮件功能"
emailConfigInfo: "用于确认电子邮件和密码重置"
email: "邮箱"
@ -705,6 +704,7 @@ editCode: "编辑代码"
apply: "应用"
receiveAnnouncementFromInstance: "从实例接收通知"
emailNotification: "邮件通知"
publish: "发布"
inChannelSearch: "频道内搜索"
useReactionPickerForContextMenu: "单击右键打开回应工具栏"
typingUsers: "{users}正在输入"
@ -728,6 +728,32 @@ hideOnlineStatusDescription: "隐藏在线状态后,可能会降低例如搜
online: "在线"
active: "活动"
offline: "离线"
notRecommended: "不推荐"
botProtection: "Bot防御"
instanceBlocking: "被阻拦的实例"
selectAccount: "选择账户"
enabled: "已启用"
disabled: "已禁用 "
quickAction: "快捷操作"
user: "用户"
administration: "管理"
accounts: "账户"
switch: "切换"
noMaintainerInformationWarning: "管理人员信息未设置。"
noBotProtectionWarning: "Bot保护未设置。"
configure: "设置"
postToGallery: "发送到图库"
gallery: "图库"
recentPosts: "最新发布"
popularPosts: "热门投稿"
shareWithNote: "在帖子中分享"
expiration: "截止时间"
middle: "中"
_gallery:
my: "我的图库"
liked: "喜欢的图片"
like: "喜欢"
unlike: "取消喜欢"
_email:
_follow:
title: "你有新的关注者"
@ -1254,7 +1280,7 @@ _pages:
viewSource: "查看源代码"
viewPage: "查看页面"
like: "赞"
unlike: "取消"
unlike: "取消喜欢"
my: "我的页面"
liked: "喜欢的页面"
featured: "热门"

View File

@ -44,7 +44,7 @@ copyLink: "複製連結"
delete: "刪除"
deleteAndEdit: "刪除並編輯"
deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有情感、轉發和回覆也將會消失。"
addToList: "新增至清單"
addToList: "加入至清單"
sendMessage: "發送訊息"
copyUsername: "複製用戶名"
searchUser: "搜尋用戶"
@ -56,7 +56,7 @@ receiveFollowRequest: "您有新的追隨請求"
followRequestAccepted: "追隨請求已接受"
mention: "提及"
mentions: "提及"
directNotes: "指定使用者發佈"
directNotes: "私訊"
importAndExport: "匯入與匯出"
import: "匯入"
export: "匯出"
@ -94,7 +94,7 @@ renote: "轉發"
unrenote: "取消轉發"
renoted: "轉發成功"
cantRenote: "無法轉發此貼文。"
cantReRenote: "無法轉發之前已經轉發過的內容"
cantReRenote: "無法轉發之前已經轉發過的內容"
quote: "引用"
pinnedNote: "已置頂的貼文"
pinned: "置頂"
@ -129,7 +129,7 @@ customEmojis: "自訂表情符號"
emoji: "表情符號"
emojiName: "表情符號名稱"
emojiUrl: "表情符號URL"
addEmoji: "新增表情符號"
addEmoji: "加入表情符號"
settingGuide: "推薦設定"
cacheRemoteFiles: "緩存非遠程檔案"
cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外連接數據。"
@ -138,7 +138,7 @@ flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。
flagAsCat: "此使用者是貓"
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
autoAcceptFollowed: "自動追隨中使用者的追隨請求"
addAcount: "新增帳戶"
addAccount: "添加帳戶"
loginFailed: "登入失敗"
showOnRemote: "轉到所在實例顯示"
general: "一般"
@ -149,7 +149,7 @@ searchWith: "搜尋: {q}"
youHaveNoLists: "你沒有任何清單"
followConfirm: "你真的要追隨{name}嗎?"
proxyAccount: "代理帳號"
proxyAccountDescription: "代理帳號是在某些情況下充當其他伺服器用戶的帳號。例如,當用戶將一個來自其他伺服器的帳號放在列表中時,由於沒有其他用戶關注該帳號,該指令不會傳送到該伺服器上,因此會由代理帳戶關注。"
proxyAccountDescription: "代理帳號是在某些情況下充當其他伺服器用戶的帳號。例如,當使用者將一個來自其他伺服器的帳號放在列表中時,由於沒有其他使用者關注該帳號,該指令不會傳送到該伺服器上,因此會由代理帳戶關注。"
host: "主機"
selectUser: "選取使用者"
recipient: "收件人"
@ -180,7 +180,7 @@ instanceInfo: "實例資訊"
statistics: "統計"
clearQueue: "清除佇列"
clearQueueConfirmTitle: "確定要清除佇列嗎?"
clearQueueConfirmText: "未發佈的帖子將不會發佈。您通常不需要確認。"
clearQueueConfirmText: "未發佈的貼文將不會發佈。您通常不需要確認。"
clearCachedFiles: "清除快取資料"
clearCachedFilesConfirm: "確定要清除所有遠端暫存資料嗎?"
blockedInstances: "已封鎖的實例"
@ -192,12 +192,12 @@ noUsers: "沒有任何使用者"
editProfile: "編輯個人檔案"
noteDeleteConfirm: "確定刪除此貼文嗎?"
pinLimitExceeded: "不能置頂更多貼文了"
intro: "Misskey 部署完成!請開設管理員帳號!"
intro: "Misskey 部署完成!請建立管理員帳號!"
done: "完成"
processing: "處理中"
preview: "預覽"
default: "預設"
noCustomEmojis: "沒有表情符號"
noCustomEmojis: "沒有自訂的表情符號"
noJobs: "沒有任務"
federating: "整合搜索中"
blocked: "已封鎖"
@ -218,7 +218,7 @@ newPasswordRetype: "確認密碼"
attachFile: "上傳附件"
more: "更多!"
featured: "精選"
usernameOrUserId: "使用者名稱或用戶ID"
usernameOrUserId: "使用者名稱或使用者ID"
noSuchUser: "使用者不存在"
lookup: "查詢"
announcements: "公告"
@ -231,7 +231,7 @@ resetAreYouSure: "確定要重設嗎?"
saved: "已儲存"
messaging: "傳送訊息"
upload: "上傳"
fromDrive: "從雲端"
fromDrive: "從雲端空間"
fromUrl: "從URL"
uploadFromUrl: "從網址上傳"
uploadFromUrlDescription: "您要上傳的文件的URL"
@ -247,7 +247,7 @@ agreeTo: "我同意{0}"
tos: "使用條款"
start: "開始"
home: "首頁"
remoteUserCaution: "由於該用戶來自遠端實例,因此資料用戶並未即時更新。"
remoteUserCaution: "由於該使用者來自遠端實例,因此資訊可能非即時的。"
activity: "動態"
images: "圖片"
birthday: "生日"
@ -273,7 +273,7 @@ folderName: "資料夾名稱"
createFolder: "新增資料夾"
renameFolder: "重新命名資料夾"
deleteFolder: "刪除資料夾"
addFile: "加附件"
addFile: "附件"
emptyDrive: "雲端硬碟為空"
emptyFolder: "資料夾為空"
unableToDelete: "無法刪除"
@ -286,11 +286,11 @@ rename: "重新命名"
avatar: "大頭貼"
banner: "橫幅"
nsfw: "敏感內容"
whenServerDisconnected: "與器的連接中斷時"
whenServerDisconnected: "與服器的連接中斷時"
disconnectedFromServer: "與伺服器中斷連線"
reload: "重新載入"
reload: "重新整理"
doNothing: "無視"
reloadConfirm: "確定要重新嘗試嗎?"
reloadConfirm: "確定要重新整理嗎?"
watch: "關注"
unwatch: "取消追隨"
accept: "接受"
@ -315,18 +315,18 @@ enableLocalTimeline: "開啟本地時間軸"
enableGlobalTimeline: "啟用公開時間軸"
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。"
registration: "註冊"
enableRegistration: "開啟新用戶註冊"
enableRegistration: "開啟新使用者註冊"
invite: "邀請"
proxyRemoteFiles: "遠端代理檔案"
proxyRemoteFilesDescription: "啟用此設置後,由於超出存儲容量而未保存或刪除的遠程文件將被本地代理,並且將生成預覽圖。這不影響器的存儲。"
driveCapacityPerLocalAccount: "每個本地用戶的雲端容量"
proxyRemoteFilesDescription: "啟用此設置後,由於超出存儲容量而未保存或刪除的遠程文件將被本地代理,並且將生成預覽圖。這不影響服器的存儲。"
driveCapacityPerLocalAccount: "每個本地用戶的雲端空間大小"
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
inMb: "以Mbps為單位"
iconUrl: "圖像URL"
bannerUrl: "橫幅圖URL"
bannerUrl: "橫幅圖URL"
basicInfo: "基本資訊"
pinnedUsers: "置頂用戶"
pinnedUsersDescription: "在「發現」頁面中使用換行標記想要置頂的用戶。"
pinnedUsersDescription: "在「發現」頁面中使用換行標記想要置頂的使用者。"
pinnedPages: "釘選頁面"
pinnedPagesDescription: "輸入要固定至實例首頁的頁面路徑,以換行符分隔。"
pinnedClipId: "置頂的摘錄ID"
@ -339,7 +339,7 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "啟用 reCAPTCHA"
recaptchaSiteKey: "網站金鑰"
recaptchaSecretKey: "金鑰"
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要禁用其他驗證方式嗎?您可以按“取消”保留多種驗證方式。"
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按“取消”保留多種驗證方式。"
antennas: "天線"
manageAntennas: "管理天線"
name: "名稱"
@ -349,7 +349,6 @@ antennaExcludeKeywords: "排除關鍵字"
antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定OR"
notifyAntenna: "通知有新貼文"
withFileAntenna: "僅帶有附件的貼文"
serviceworker: "ServiceWorker"
enableServiceworker: "開啟 ServiceWorker"
antennaUsersDescription: "指定用換行符分隔的用戶名"
caseSensitive: "區分大小寫"
@ -361,11 +360,11 @@ silence: "禁言"
silenceConfirm: "確定要禁言此用戶嗎?"
unsilence: "解除禁言"
unsilenceConfirm: "確定要解除禁言嗎?"
popularUsers: "熱門用戶"
recentlyUpdatedUsers: "最近發文的用戶"
recentlyRegisteredUsers: "新加入用戶"
recentlyDiscoveredUsers: "最近發現的用戶"
exploreUsersCount: "有{count}個用戶"
popularUsers: "熱門使用者"
recentlyUpdatedUsers: "最近發文的使用者"
recentlyRegisteredUsers: "新加入使用者"
recentlyDiscoveredUsers: "最近發現的使用者"
exploreUsersCount: "有{count}個使用者"
exploreFediverse: "探索聯邦世界"
popularTags: "熱門標籤"
userList: "清單"
@ -405,7 +404,7 @@ invites: "邀請"
groupName: "群組名稱"
members: "成員"
transfer: "轉讓"
messagingWithUser: "傳送訊息給其他用戶"
messagingWithUser: "傳送訊息給其他使用者"
messagingWithGroup: "發送訊息至群組"
title: "標題"
text: "文字"
@ -431,11 +430,11 @@ tooShort: "過短"
tooLong: "過長"
weakPassword: "密碼強度過弱"
normalPassword: "密碼強度普通"
strongPassword: "密碼強度堅強"
strongPassword: "密碼強度"
passwordMatched: "密碼一致"
passwordNotMatched: "密碼不一致"
signinWith: "以{x}登錄"
signinFailed: "登入失敗。 請檢查用戶名和密碼。"
signinFailed: "登入失敗。 請檢查使用者名稱和密碼。"
tapSecurityKey: "點擊安全密鑰"
or: "或者"
language: "語言"
@ -453,7 +452,7 @@ category: "類別"
tags: "標籤"
docSource: "文件來源"
createAccount: "建立帳戶"
existingAcount: "現有帳戶"
existingAccount: "現有帳戶"
regenerate: "再生"
fontSize: "字體大小"
noFollowRequests: "沒有要求跟隨您的申請"
@ -477,8 +476,8 @@ useObjectStorage: "使用Object Storage"
objectStorageBaseUrl: "Base URL"
objectStorageBucket: "儲存空間Bucket"
objectStoragePrefix: "前綴"
objectStorageEndpoint: "訪問網域名稱Endpoint"
objectStorageEndpointDesc: "如要使用AWS S3請留空。否則請根據伺服器要求以'<host>'或 '<host>:<port>'的形式設定訪問網域名稱Endpoint。"
objectStorageEndpoint: "端點Endpoint"
objectStorageEndpointDesc: "如要使用AWS S3請留空。否則請依照你使用的服務商的說明書進行設定,以'<host>'或 '<host>:<port>'的形式設定端點Endpoint。"
objectStorageRegion: "地域Region"
objectStorageUseSSL: "使用SSL"
objectStorageUseProxy: "使用網路代理"
@ -512,12 +511,12 @@ scratchpad: "暫存記憶體"
output: "輸出"
script: "腳本"
disablePagesScript: "停用頁面的AiScript腳本"
updateRemoteUser: "更新遠端用戶資料"
updateRemoteUser: "更新遠端使用者資訊"
deleteAllFiles: "刪除所有檔案"
deleteAllFilesConfirm: "要删除所有檔案嗎?"
removeAllFollowing: "解除所有追蹤"
removeAllFollowingDescription: "解除{host}所有的追蹤。在實例不再存在時執行。"
userSuspended: "該用戶已被凍結"
userSuspended: "該使用者已被停用"
userSilenced: "該用戶已被禁言。"
sidebar: "側邊列"
divider: "分割線"
@ -559,7 +558,7 @@ tokenRequested: "允許存取帳號"
notificationType: "通知形式"
edit: "編輯"
useStarForReactionFallback: "以★代替未知的表情符號"
emailConfig: "電子郵件伺服器設定"
emailServer: "電郵伺服器"
enableEmail: "啟用發送電郵功能"
emailConfigInfo: "用於確認電郵地址及密碼重置"
email: "電子郵件"
@ -586,9 +585,11 @@ create: "新增"
notificationSetting: "通知設定"
notificationSettingDesc: "選擇顯示通知的類型"
useGlobalSetting: "使用全域設定"
useGlobalSettingDesc: "啟用時,將使用帳戶通知設定。停用時,則可以單獨設定。"
other: "其他"
regenerateLoginToken: "重新產生登入權杖"
regenerateLoginTokenDescription: "重新產生用於登入的內部權杖。一般情況下是不需要這樣做的。一旦重產,所有裝置將會被登出。"
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多個項目。"
fileIdOrUrl: "檔案ID或URL"
chatOpenBehavior: "開啟聊天窗口時的行為"
behavior: "行為"
@ -602,6 +603,7 @@ send: "發送"
abuseMarkAsResolved: "處理完畢"
openInNewTab: "在新分頁中開啟"
openInSideView: "在側欄中開啟"
defaultNavigationBehaviour: "默認導航"
editTheseSettingsMayBreakAccount: "修改這些設定可能會毀損您的帳戶"
instanceTicker: "貼文的實例來源"
waitingFor: "等待{x}"
@ -635,13 +637,16 @@ driveUsage: "雲端硬碟使用量"
noCrawle: "拒絕搜尋引擎索引"
noCrawleDescription: "要求網路搜尋引擎不要索引你的個人資料頁、貼文及頁面等。"
lockedAccountInfo: "即使你通過了追隨者請求,除非你將貼文的可見性設定為 「追隨者」,否則任何人都能看見你的貼文。"
alwaysMarkSensitive: "默認將圖像/影像標記為敏感內容"
loadRawImages: "以原始圖檔顯示附件圖檔的縮圖"
disableShowingAnimatedImages: "不播放動態圖檔"
verificationEmailSent: "已發送驗證電子郵件。請點擊進入電子郵件中的鏈接完成驗證。"
notSet: "未設定"
emailVerified: "已成功驗證您的電郵"
noteFavoritesCount: "我的最愛貼文的數目"
pageLikesCount: "頁面被按讚次數"
pageLikedCount: "頁面被按讚次數"
reversiCount: "黑白棋對戰次數"
contact: "聯絡人"
useSystemFont: "使用系統預設的字型"
clips: "摘錄"
@ -670,6 +675,7 @@ textColor: "文字"
saveAs: "另存為..."
advanced: "進階"
value: "數值"
createdAt: "建立於"
updatedAt: "最後更新"
saveConfirm: "您要儲存變更嗎?"
deleteConfirm: "你確定要刪除嗎?"
@ -685,17 +691,58 @@ capacity: "容量"
inUse: "已使用"
editCode: "編輯代碼"
apply: "套用"
receiveAnnouncementFromInstance: "接收由本實例發出的電郵通知"
emailNotification: "郵件通知"
publish: "發佈"
inChannelSearch: "頻道内搜尋"
useReactionPickerForContextMenu: "點擊右鍵開啟回應工具欄"
typingUsers: "{users}輸入中..."
jumpToSpecifiedDate: "跳轉到特定日期"
showingPastTimeline: "顯示過往的時間線"
clear: "清除"
markAllAsRead: "全部標示為已讀"
goBack: "返回"
unlikeConfirm: "要取消按讚嗎?"
fullView: "全熒幕顯示"
quitFullView: "退出全熒幕顯示"
addDescription: "添加描述"
userPagePinTip: "在貼文的選單中選擇\"置頂\",即可置頂該貼文至您的個人檔案頁面。"
notSpecifiedMentionWarning: "此貼文有未指定的提及"
info: "資訊"
userInfo: "用戶資料"
unknown: "未知"
onlineStatus: "在線狀態"
hideOnlineStatus: "隱藏在線狀態"
hideOnlineStatusDescription: "隱藏在線狀態後,可能會降低檢索等功能的便利性。"
online: "線上"
active: "最近活躍"
offline: "離線"
notRecommended: "不推薦"
botProtection: "Bot防護"
instanceBlocking: "已封鎖的實例"
selectAccount: "選擇帳戶"
enabled: "已啟用"
disabled: "已停用"
quickAction: "快捷操作"
user: "使用者"
administration: "管理"
accounts: "帳戶"
switch: "切換"
noMaintainerInformationWarning: "尚未設定管理員信息。"
noBotProtectionWarning: "尚未設定Bot防護。"
configure: "設定"
expiration: "期限"
middle: "中"
_gallery:
unlike: "收回喜歡"
_email:
_follow:
title: "您有新的追隨者"
_receiveFollowRequest:
title: "收到追隨請求"
_plugin:
install: "安裝外掛組件"
installWarn: "請不要安裝來源不明的外掛組件。"
manage: "管理插件"
_registry:
scope: "範圍"
@ -723,7 +770,9 @@ _mfm:
mention: "提及"
mentionDescription: "透過 @+用戶名 來標示特定使用者。"
hashtag: "#tag"
hashtagDescription: "可以使用\"#\"符號後加文字表示話題標籤。"
url: "URL"
urlDescription: "可以展示URL位址。"
link: "鏈接"
bold: "粗體"
small: "縮小"
@ -797,8 +846,8 @@ _serverDisconnectedBehavior:
_channel:
create: "建立頻道"
edit: "編輯頻道"
setBanner: "設定橫幅"
removeBanner: "移除封面圖"
setBanner: "設定橫幅圖像"
removeBanner: "移除橫幅圖像"
featured: "熱門貼文"
owned: "管理中"
following: "關注中"
@ -839,6 +888,7 @@ _theme:
fg: "文本"
panel: "面板"
shadow: "陰影"
navActive: "側邊欄文本 (活動)"
navIndicator: "側邊欄指示符"
link: "鏈接"
hashtag: "#tag"
@ -856,11 +906,14 @@ _theme:
cwBg: "CW 按鈕背景"
cwFg: "CW 按鈕文本"
cwHoverBg: "CW 按鈕背景 (漂浮)"
toastBg: "通知背景"
toastFg: "通知文本"
buttonBg: "按鈕背景"
buttonHoverBg: "按鈕背景 (漂浮)"
inputBorder: "輸入框邊框"
listItemHoverBg: "列表物品背景 (漂浮)"
driveFolderBg: "雲端硬碟文件夾背景"
wallpaperOverlay: "壁紙覆蓋層"
badge: "獎章"
messageBg: "私訊背景"
accentDarken: "強調色(偏暗)"
@ -871,6 +924,7 @@ _sfx:
noteMy: "我的貼文"
notification: "通知"
chat: "傳送訊息"
chatBg: "聊天背景"
antenna: "天線接收"
channel: "頻道通知"
_ago:
@ -908,6 +962,7 @@ _tutorial:
step5_4: "如果使用者的名字旁有鎖頭的圖示,代表他們需要手動核准你的追隨請求。"
step6_1: "現在你可以在時間軸上看到其他用戶的貼文。"
step6_2: "你也可以對別人的貼文作出「情感」,作出簡單的回覆。"
step6_3: "在他人的貼文按下\"+\"圖標,即可選擇喜好的表情符號進行回應。"
step7_1: "以上為Misskey的基本操作說明教學在此告一段落。辛苦了。"
step7_2: "歡迎到{help}來瞭解更多Misskey相關介紹。"
step7_3: "那麼祝您在Misskey玩的開心~ 🚀"
@ -925,6 +980,7 @@ _permissions:
"write:drive": "編輯雲端硬碟的檔案"
"read:favorites": "瀏覽我的最愛"
"write:favorites": "編輯我的最愛列表"
"read:following": "查看追隨中的用戶資訊"
"write:following": "追隨/解除追隨"
"read:messaging": "顯示訊息"
"write:messaging": "撰寫或刪除私人訊息"
@ -991,6 +1047,7 @@ _poll:
noOnlyOneChoice: "至少需要兩個選項。"
choiceN: "選擇{n}"
noMore: "沒辦法再添加選項了"
canMultipleVote: "可以多次投票"
expiration: "期限"
infinite: "無期限"
at: "結束時間"
@ -1034,6 +1091,8 @@ _profile:
metadataEdit: "編輯進階資訊"
metadataLabel: "標籤"
metadataContent: "内容"
changeAvatar: "更換大頭貼"
changeBanner: "變更橫幅圖像"
_exportOrImport:
allNotes: "所有貼文"
followingList: "追隨中"
@ -1417,7 +1476,7 @@ _notification:
reply: "回覆"
renote: "轉發貼文"
quote: "引用"
reaction: "情感"
reaction: "反應"
pollVote: "統計已投票數"
receiveFollowRequest: "已收到追隨請求"
followRequestAccepted: "追隨請求已接受"

View File

@ -0,0 +1,40 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class gallery1611397665007 implements MigrationInterface {
name = 'gallery1611397665007'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "gallery_post" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "title" character varying(256) NOT NULL, "description" character varying(2048), "userId" character varying(32) NOT NULL, "fileIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "isSensitive" boolean NOT NULL DEFAULT false, "likedCount" integer NOT NULL DEFAULT '0', "tags" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], CONSTRAINT "PK_8e90d7b6015f2c4518881b14753" PRIMARY KEY ("id")); COMMENT ON COLUMN "gallery_post"."createdAt" IS 'The created date of the GalleryPost.'; COMMENT ON COLUMN "gallery_post"."updatedAt" IS 'The updated date of the GalleryPost.'; COMMENT ON COLUMN "gallery_post"."userId" IS 'The ID of author.'; COMMENT ON COLUMN "gallery_post"."isSensitive" IS 'Whether the post is sensitive.'`);
await queryRunner.query(`CREATE INDEX "IDX_8f1a239bd077c8864a20c62c2c" ON "gallery_post" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_f631d37835adb04792e361807c" ON "gallery_post" ("updatedAt") `);
await queryRunner.query(`CREATE INDEX "IDX_985b836dddd8615e432d7043dd" ON "gallery_post" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_3ca50563facd913c425e7a89ee" ON "gallery_post" ("fileIds") `);
await queryRunner.query(`CREATE INDEX "IDX_f2d744d9a14d0dfb8b96cb7fc5" ON "gallery_post" ("isSensitive") `);
await queryRunner.query(`CREATE INDEX "IDX_1a165c68a49d08f11caffbd206" ON "gallery_post" ("likedCount") `);
await queryRunner.query(`CREATE INDEX "IDX_05cca34b985d1b8edc1d1e28df" ON "gallery_post" ("tags") `);
await queryRunner.query(`CREATE TABLE "gallery_like" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "postId" character varying(32) NOT NULL, CONSTRAINT "PK_853ab02be39b8de45cd720cc15f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_8fd5215095473061855ceb948c" ON "gallery_like" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_df1b5f4099e99fb0bc5eae53b6" ON "gallery_like" ("userId", "postId") `);
await queryRunner.query(`ALTER TABLE "gallery_post" ADD CONSTRAINT "FK_985b836dddd8615e432d7043ddb" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "gallery_like" ADD CONSTRAINT "FK_8fd5215095473061855ceb948cf" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "gallery_like" ADD CONSTRAINT "FK_b1cb568bfe569e47b7051699fc8" FOREIGN KEY ("postId") REFERENCES "gallery_post"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "gallery_like" DROP CONSTRAINT "FK_b1cb568bfe569e47b7051699fc8"`);
await queryRunner.query(`ALTER TABLE "gallery_like" DROP CONSTRAINT "FK_8fd5215095473061855ceb948cf"`);
await queryRunner.query(`ALTER TABLE "gallery_post" DROP CONSTRAINT "FK_985b836dddd8615e432d7043ddb"`);
await queryRunner.query(`DROP INDEX "IDX_df1b5f4099e99fb0bc5eae53b6"`);
await queryRunner.query(`DROP INDEX "IDX_8fd5215095473061855ceb948c"`);
await queryRunner.query(`DROP TABLE "gallery_like"`);
await queryRunner.query(`DROP INDEX "IDX_05cca34b985d1b8edc1d1e28df"`);
await queryRunner.query(`DROP INDEX "IDX_1a165c68a49d08f11caffbd206"`);
await queryRunner.query(`DROP INDEX "IDX_f2d744d9a14d0dfb8b96cb7fc5"`);
await queryRunner.query(`DROP INDEX "IDX_3ca50563facd913c425e7a89ee"`);
await queryRunner.query(`DROP INDEX "IDX_985b836dddd8615e432d7043dd"`);
await queryRunner.query(`DROP INDEX "IDX_f631d37835adb04792e361807c"`);
await queryRunner.query(`DROP INDEX "IDX_8f1a239bd077c8864a20c62c2c"`);
await queryRunner.query(`DROP TABLE "gallery_post"`);
}
}

View File

@ -0,0 +1,20 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class passwordReset1619942102890 implements MigrationInterface {
name = 'passwordReset1619942102890'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "password_reset_request" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "token" character varying(256) NOT NULL, "userId" character varying(32) NOT NULL, CONSTRAINT "PK_fcf4b02eae1403a2edaf87fd074" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0b575fa9a4cfe638a925949285" ON "password_reset_request" ("token") `);
await queryRunner.query(`CREATE INDEX "IDX_4bb7fd4a34492ae0e6cc8d30ac" ON "password_reset_request" ("userId") `);
await queryRunner.query(`ALTER TABLE "password_reset_request" ADD CONSTRAINT "FK_4bb7fd4a34492ae0e6cc8d30ac8" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "password_reset_request" DROP CONSTRAINT "FK_4bb7fd4a34492ae0e6cc8d30ac8"`);
await queryRunner.query(`DROP INDEX "IDX_4bb7fd4a34492ae0e6cc8d30ac"`);
await queryRunner.query(`DROP INDEX "IDX_0b575fa9a4cfe638a925949285"`);
await queryRunner.query(`DROP TABLE "password_reset_request"`);
}
}

View File

@ -0,0 +1,18 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class ad1620019354680 implements MigrationInterface {
name = 'ad1620019354680'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "ad" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE NOT NULL, "place" character varying(32) NOT NULL, "priority" character varying(32) NOT NULL, "url" character varying(1024) NOT NULL, "imageUrl" character varying(1024) NOT NULL, "memo" character varying(8192) NOT NULL, CONSTRAINT "PK_0193d5ef09746e88e9ea92c634d" PRIMARY KEY ("id")); COMMENT ON COLUMN "ad"."createdAt" IS 'The created date of the Ad.'; COMMENT ON COLUMN "ad"."expiresAt" IS 'The expired date of the Ad.'`);
await queryRunner.query(`CREATE INDEX "IDX_1129c2ef687fc272df040bafaa" ON "ad" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_2da24ce20ad209f1d9dc032457" ON "ad" ("expiresAt") `);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_2da24ce20ad209f1d9dc032457"`);
await queryRunner.query(`DROP INDEX "IDX_1129c2ef687fc272df040bafaa"`);
await queryRunner.query(`DROP TABLE "ad"`);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.78.0",
"version": "12.80.3",
"codename": "indigo",
"repository": {
"type": "git",
@ -32,7 +32,6 @@
"resolutions": {
"chokidar": "^3.3.1",
"constantinople": "^4.0.1",
"gulp/gulp-cli/yargs/yargs-parser": "5.0.0-security.0",
"jsonld/rdf-canonize/node-forge": "0.10.0",
"lodash": "^4.17.20"
},
@ -47,16 +46,15 @@
"@sinonjs/fake-timers": "7.0.5",
"@syuilo/aiscript": "0.11.1",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.0",
"@types/bull": "3.15.1",
"@types/cbor": "5.0.1",
"@types/dateformat": "3.0.1",
"@types/escape-regexp": "0.0.0",
"@types/glob": "7.1.3",
"@types/gulp": "4.0.8",
"@types/gulp-rename": "2.0.0",
"@types/gulp-replace": "0.0.31",
"@types/is-url": "1.2.28",
"@types/js-yaml": "4.0.0",
"@types/js-yaml": "4.0.1",
"@types/jsdom": "16.2.10",
"@types/jsonld": "1.5.5",
"@types/katex": "0.11.0",
@ -107,31 +105,31 @@
"@typescript-eslint/parser": "4.22.0",
"@vue/compiler-sfc": "3.0.11",
"abort-controller": "3.0.0",
"apexcharts": "3.26.0",
"apexcharts": "3.26.1",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
"aws-sdk": "2.887.0",
"aws-sdk": "2.892.0",
"bcryptjs": "2.4.3",
"blurhash": "1.1.3",
"broadcast-channel": "3.5.3",
"bull": "3.22.0",
"bull": "3.22.3",
"cafy": "15.2.1",
"cbor": "7.0.5",
"chalk": "4.1.0",
"chalk": "4.1.1",
"chart.js": "2.9.4",
"cli-highlight": "2.1.11",
"commander": "7.2.0",
"concurrently": "6.0.2",
"content-disposition": "0.5.3",
"core-js": "3.10.1",
"core-js": "3.11.0",
"crc-32": "1.2.0",
"css-loader": "5.2.1",
"css-loader": "5.2.4",
"cssnano": "5.0.1",
"dateformat": "4.5.1",
"diskusage": "1.1.3",
"escape-regexp": "0.0.1",
"eslint": "7.24.0",
"eslint": "7.25.0",
"eslint-plugin-vue": "7.9.0",
"eventemitter3": "4.0.7",
"feed": "4.2.2",
@ -142,7 +140,7 @@
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-rename": "2.0.0",
"gulp-replace": "1.0.0",
"gulp-replace": "1.1.1",
"gulp-terser": "2.0.1",
"gulp-tslint": "8.1.4",
"hard-source-webpack-plugin": "0.13.1",
@ -160,7 +158,7 @@
"json5-loader": "4.0.1",
"jsonld": "4.0.1",
"jsrsasign": "8.0.20",
"katex": "0.13.2",
"katex": "0.13.3",
"koa": "2.13.1",
"koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0",
@ -172,10 +170,10 @@
"koa-views": "7.0.1",
"langmap": "0.0.16",
"lookup-dns-cache": "2.1.0",
"markdown-it": "12.0.5",
"markdown-it": "12.0.6",
"markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1",
"mfm-js": "0.16.2",
"mfm-js": "0.16.3",
"mocha": "8.3.2",
"moji": "0.5.1",
"ms": "2.1.3",
@ -188,7 +186,7 @@
"parse5": "6.0.1",
"pg": "8.6.0",
"portscanner": "2.2.0",
"postcss": "8.2.10",
"postcss": "8.2.12",
"postcss-loader": "5.2.0",
"prismjs": "1.23.0",
"probe-image-size": "7.1.0",
@ -202,7 +200,7 @@
"ratelimiter": "3.4.1",
"re2": "1.15.9",
"reconnecting-websocket": "4.4.0",
"redis": "3.1.1",
"redis": "3.1.2",
"redis-lock": "0.1.4",
"reflect-metadata": "0.1.13",
"regenerator-runtime": "0.13.7",
@ -212,7 +210,7 @@
"rimraf": "3.0.2",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.32.8",
"sass": "1.32.11",
"sass-loader": "11.0.1",
"seedrandom": "3.0.5",
"sharp": "0.28.1",
@ -228,9 +226,9 @@
"throttle-debounce": "3.0.1",
"tinycolor2": "1.4.2",
"tmp": "0.2.1",
"ts-loader": "8.1.0",
"ts-loader": "9.1.1",
"ts-node": "9.1.1",
"tsc-alias": "1.2.9",
"tsc-alias": "1.2.10",
"tsconfig-paths": "3.9.0",
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
@ -250,15 +248,16 @@
"vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1",
"web-push": "3.4.4",
"webpack": "5.33.2",
"webpack": "5.35.1",
"webpack-cli": "4.6.0",
"websocket": "1.0.34",
"ws": "7.4.4",
"ws": "7.4.5",
"xev": "2.0.1"
},
"devDependencies": {
"@types/chai": "4.2.15",
"@types/fluent-ffmpeg": "2.1.16",
"@redocly/openapi-core": "1.0.0-beta.44",
"@types/chai": "4.2.16",
"@types/fluent-ffmpeg": "2.1.17",
"chai": "4.3.4",
"cross-env": "7.0.3"
}

View File

@ -45,26 +45,15 @@ function greet() {
export async function masterMain() {
let config!: Config;
// initialize app
try {
greet();
// initialize app
config = await init();
if (config.port == null || Number.isNaN(config.port)) {
bootLogger.error('The port is not configured. Please configure port.', null, true);
process.exit(1);
}
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
bootLogger.error('You need root privileges to listen on well-known port on Linux', null, true);
process.exit(1);
}
if (!await isPortAvailable(config.port)) {
bootLogger.error(`Port ${config.port} is already in use`, null, true);
process.exit(1);
}
showEnvironment();
await showMachineInfo(bootLogger);
showNodejsVersion();
config = loadConfigBoot();
await connectDb();
await validatePort(config);
} catch (e) {
bootLogger.error('Fatal error occurred during initialization', null, true);
process.exit(1);
@ -89,14 +78,6 @@ const runningNodejsVersion = process.version.slice(1).split('.').map(x => parseI
const requiredNodejsVersion = [11, 7, 0];
const satisfyNodejsVersion = !lessThan(runningNodejsVersion, requiredNodejsVersion);
function isWellKnownPort(port: number): boolean {
return port < 1024;
}
async function isPortAvailable(port: number): Promise<boolean> {
return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed';
}
function showEnvironment(): void {
const env = process.env.NODE_ENV;
const logger = bootLogger.createSubLogger('env');
@ -110,14 +91,7 @@ function showEnvironment(): void {
logger.info(`You ${isRoot() ? '' : 'do not '}have root privileges`);
}
/**
* Init app
*/
async function init(): Promise<Config> {
showEnvironment();
await showMachineInfo(bootLogger);
function showNodejsVersion(): void {
const nodejsLogger = bootLogger.createSubLogger('nodejs');
nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`);
@ -126,7 +100,9 @@ async function init(): Promise<Config> {
nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`, null, true);
process.exit(1);
}
}
function loadConfigBoot(): Config {
const configLogger = bootLogger.createSubLogger('config');
let config;
@ -146,6 +122,10 @@ async function init(): Promise<Config> {
configLogger.succ('Loaded');
return config;
}
async function connectDb(): Promise<void> {
const dbLogger = bootLogger.createSubLogger('db');
// Try to connect to DB
@ -159,8 +139,29 @@ async function init(): Promise<Config> {
dbLogger.error(e);
process.exit(1);
}
}
return config;
async function validatePort(config: Config): Promise<void> {
const isWellKnownPort = (port: number) => port < 1024;
async function isPortAvailable(port: number): Promise<boolean> {
return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed';
}
if (config.port == null || Number.isNaN(config.port)) {
bootLogger.error('The port is not configured. Please configure port.', null, true);
process.exit(1);
}
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
bootLogger.error('You need root privileges to listen on well-known port on Linux', null, true);
process.exit(1);
}
if (!await isPortAvailable(config.port)) {
bootLogger.error(`Port ${config.port} is already in use`, null, true);
process.exit(1);
}
}
async function spawnWorkers(limit: number = 1) {

View File

@ -6,7 +6,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, PropType } from 'vue';
type Captcha = {
render(container: string | Node, options: {
@ -32,7 +32,7 @@ declare global {
export default defineComponent({
props: {
provider: {
type: String,
type: String as PropType<CaptchaProvider>,
required: true,
},
sitekey: {
@ -51,19 +51,25 @@ export default defineComponent({
},
computed: {
loaded() {
return !!window[this.provider as CaptchaProvider];
variable(): string {
switch (this.provider) {
case 'hcaptcha': return 'hcaptcha';
case 'recaptcha': return 'grecaptcha';
}
},
src() {
loaded(): boolean {
return !!window[this.variable];
},
src(): string {
const endpoint = ({
hcaptcha: 'https://hcaptcha.com/1',
recaptcha: 'https://www.recaptcha.net/recaptcha',
} as Record<PropertyKey, unknown>)[this.provider];
} as Record<CaptchaProvider, string>)[this.provider];
return `${typeof endpoint == 'string' ? endpoint : 'about:invalid'}/api.js?render=explicit`;
return `${typeof endpoint === 'string' ? endpoint : 'about:invalid'}/api.js?render=explicit`;
},
captcha() {
return window[this.provider as CaptchaProvider] || {} as unknown as Captcha;
captcha(): Captcha {
return window[this.variable] || {} as unknown as Captcha;
},
},
@ -94,7 +100,7 @@ export default defineComponent({
methods: {
reset() {
this.captcha?.reset();
if (this.captcha?.reset) this.captcha.reset();
},
requestRender() {
if (this.captcha.render && this.$refs.captcha instanceof Element) {

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { defineComponent, h, TransitionGroup } from 'vue';
import MkAd from '@client/components/global/ad.vue';
export default defineComponent({
props: {
@ -22,6 +23,11 @@ export default defineComponent({
required: false,
default: false
},
ad: {
type: Boolean,
required: false,
default: false
},
},
methods: {
@ -58,11 +64,7 @@ export default defineComponent({
if (
i != this.items.length - 1 &&
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate() &&
!item._prId_ &&
!this.items[i + 1]._prId_ &&
!item._featuredId_ &&
!this.items[i + 1]._featuredId_
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate()
) {
const separator = h('div', {
class: 'separator',
@ -86,7 +88,15 @@ export default defineComponent({
return [el, separator];
} else {
return el;
if (this.ad && item._shouldInsertAd_) {
return [h(MkAd, {
class: 'a', // advertise()
key: item.id + ':ad',
prefer: ['horizontal', 'horizontal-big'],
}), el];
} else {
return el;
}
}
}));
},
@ -95,6 +105,10 @@ export default defineComponent({
<style lang="scss">
.sqadhkmv {
> *:empty {
display: none;
}
> *:not(:last-child) {
margin-bottom: var(--margin);
}

View File

@ -81,7 +81,7 @@ export default defineComponent({
getMenu() {
return [{
text: this.$ts.rename,
icon: faICursor,
icon: 'fas fa-i-cursor',
action: this.rename
}, {
text: this.file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,

View File

@ -247,7 +247,7 @@ export default defineComponent({
}
}, null, {
text: this.$ts.rename,
icon: faICursor,
icon: 'fas fa-i-cursor',
action: this.rename
}, null, {
text: this.$ts.delete,

View File

@ -614,7 +614,7 @@ export default defineComponent({
type: 'label'
}, this.folder ? {
text: this.$ts.renameFolder,
icon: faICursor,
icon: 'fas fa-i-cursor',
action: () => { this.renameFolder(this.folder); }
} : undefined, this.folder ? {
text: this.$ts.deleteFolder,

View File

@ -35,6 +35,7 @@
class="_button"
@click="chosen(emoji, $event)"
tabindex="0"
:key="emoji"
>
<MkEmoji :emoji="emoji" :normal="true"/>
</button>
@ -104,7 +105,7 @@ export default defineComponent({
return {
emojilist: markRaw(emojilist),
getStaticImageUrl,
pinned: this.$store.state.reactions,
pinned: this.$store.reactiveState.reactions,
width: this.asReactionPicker ? this.$store.state.reactionPickerWidth : 3,
height: this.asReactionPicker ? this.$store.state.reactionPickerHeight : 2,
big: this.asReactionPicker ? isDeviceTouch : false,

View File

@ -0,0 +1,71 @@
<template>
<XModalWindow ref="dialog"
:width="370"
:height="400"
@close="$refs.dialog.close()"
@closed="$emit('closed')"
>
<template #header>{{ $ts.forgotPassword }}</template>
<form class="_monolithic_" @submit.prevent="onSubmit" v-if="$instance.enableEmail">
<div class="_section">
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
<span>{{ $ts.username }}</span>
<template #prefix>@</template>
</MkInput>
<MkInput v-model:value="email" type="email" spellcheck="false" required>
<span>{{ $ts.emailAddress }}</span>
<template #desc>{{ $ts._forgotPassword.enterEmail }}</template>
</MkInput>
<MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ $ts.send }}</MkButton>
</div>
<div class="_section">
<MkA to="/about" class="_link">{{ $ts._forgotPassword.ifNoEmail }}</MkA>
</div>
</form>
<div v-else>
{{ $ts._forgotPassword.contactAdmin }}
</div>
</XModalWindow>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XModalWindow from '@client/components/ui/modal-window.vue';
import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import * as os from '@client/os';
export default defineComponent({
components: {
XModalWindow,
MkButton,
MkInput,
},
emits: ['done', 'closed'],
data() {
return {
username: '',
email: '',
processing: false,
};
},
methods: {
async onSubmit() {
this.processing = true;
await os.apiWithDialog('request-reset-password', {
username: this.username,
email: this.email,
});
this.$emit('done');
this.$refs.dialog.close();
}
}
});
</script>

View File

@ -0,0 +1,126 @@
<template>
<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1">
<div class="thumbnail">
<ImgWithBlurhash class="img" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash"/>
</div>
<article>
<header>
<MkAvatar :user="post.user" class="avatar"/>
</header>
<footer>
<span class="title">{{ post.title }}</span>
</footer>
</article>
</MkA>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { userName } from '@client/filters/user';
import ImgWithBlurhash from '@client/components/img-with-blurhash.vue';
import * as os from '@client/os';
export default defineComponent({
components: {
ImgWithBlurhash
},
props: {
post: {
type: Object,
required: true
},
},
methods: {
userName
}
});
</script>
<style lang="scss" scoped>
.ttasepnz {
display: block;
position: relative;
height: 200px;
&:hover {
text-decoration: none;
color: var(--accent);
> .thumbnail {
transform: scale(1.1);
}
> article {
> footer {
&:before {
opacity: 1;
}
}
}
}
> .thumbnail {
width: 100%;
height: 100%;
position: absolute;
transition: all 0.5s ease;
> .img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
> article {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
> header {
position: absolute;
top: 0;
width: 100%;
padding: 12px;
box-sizing: border-box;
display: flex;
> .avatar {
margin-left: auto;
width: 32px;
height: 32px;
}
}
> footer {
position: absolute;
bottom: 0;
width: 100%;
padding: 16px;
box-sizing: border-box;
color: #fff;
text-shadow: 0 0 8px #000;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
&:before {
content: "";
display: block;
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(0, 0, 0, 0.4), transparent);
opacity: 0;
transition: opacity 0.5s ease;
}
> .title {
font-weight: bold;
}
}
}
}
</style>

View File

@ -0,0 +1,163 @@
<template>
<div class="qiivuoyo" v-if="ad">
<div class="main" :class="ad.place" v-if="!showMenu">
<a :href="ad.url" target="_blank">
<img :src="ad.imageUrl">
<button class="_button menu" @click.prevent.stop="toggleMenu"><span class="fas fa-info-circle"></span></button>
</a>
</div>
<div class="menu" v-else>
<div class="body">
<div>Ads by {{ host }}</div>
<!--<MkButton>{{ $ts.stopThisAd }}</MkButton>-->
<button class="_textButton" @click="toggleMenu">{{ $ts.close }}</button>
</div>
</div>
</div>
<div v-else></div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { instance } from '@client/instance';
import { host } from '@client/config';
import MkButton from '@client/components/ui/button.vue';
export default defineComponent({
components: {
MkButton
},
props: {
prefer: {
type: Array,
required: true
},
specify: {
type: Object,
required: false
},
},
setup(props) {
const showMenu = ref(false);
const toggleMenu = () => {
showMenu.value = !showMenu.value;
};
let ad = null;
if (props.specify) {
ad = props.specify;
} else {
let ads = instance.ads.filter(ad => props.prefer.includes(ad.place));
if (ads.length === 0) {
ads = instance.ads.filter(ad => ad.place === 'square');
}
const high = ads.filter(ad => ad.priority === 'high');
const middle = ads.filter(ad => ad.priority === 'middle');
const low = ads.filter(ad => ad.priority === 'low');
if (high.length > 0) {
ad = high[Math.floor(Math.random() * high.length)];
} else if (middle.length > 0) {
ad = middle[Math.floor(Math.random() * middle.length)];
} else if (low.length > 0) {
ad = low[Math.floor(Math.random() * low.length)];
}
}
return {
ad,
showMenu,
toggleMenu,
host,
};
}
});
</script>
<style lang="scss" scoped>
.qiivuoyo {
background-size: auto auto;
background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--ad) 8px, var(--ad) 14px );
> .main {
text-align: center;
> a {
display: inline-block;
position: relative;
vertical-align: bottom;
&:hover {
> img {
filter: contrast(120%);
}
}
> img {
display: block;
object-fit: contain;
margin: auto;
}
> .menu {
position: absolute;
top: 0;
right: 0;
background: var(--panel);
}
}
&.square {
> a ,
> a > img {
max-width: min(300px, 100%);
max-height: 300px;
}
}
&.horizontal {
padding: 8px;
> a ,
> a > img {
max-width: min(600px, 100%);
max-height: 80px;
}
}
&.horizontal-big {
padding: 8px;
> a ,
> a > img {
max-width: min(600px, 100%);
max-height: 250px;
}
}
&.vertical {
> a ,
> a > img {
max-width: min(100px, 100%);
}
}
}
> .menu {
padding: 8px;
text-align: center;
> .body {
padding: 8px;
margin: 0 auto;
max-width: 400px;
border: solid 1px var(--divider);
}
}
}
</style>

View File

@ -113,8 +113,6 @@ export default defineComponent({
> .icon {
padding-left: 2px;
font-size: .9em;
font-weight: 400;
font-style: normal;
}
> .self {

View File

@ -12,8 +12,10 @@ import url from './global/url.vue';
import i18n from './global/i18n';
import loading from './global/loading.vue';
import error from './global/error.vue';
import ad from './global/ad.vue';
export default function(app: App) {
app.component('I18n', i18n);
app.component('Mfm', mfm);
app.component('MkA', a);
app.component('MkAcct', acct);
@ -25,5 +27,5 @@ export default function(app: App) {
app.component('MkUrl', url);
app.component('MkLoading', loading);
app.component('MkError', error);
app.component('I18n', i18n);
app.component('MkAd', ad);
}

View File

@ -3,12 +3,12 @@
<div class="szkkfdyq _popup">
<div class="main">
<template v-for="item in items">
<button v-if="item.action" class="_button" @click="$event => { item.action($event); close(); }">
<button v-if="item.action" class="_button" @click="$event => { item.action($event); close(); }" v-click-anime>
<i class="icon" :class="item.icon"></i>
<div class="text">{{ item.text }}</div>
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
</button>
<MkA v-else :to="item.to" @click.passive="close()">
<MkA v-else :to="item.to" @click.passive="close()" v-click-anime>
<i class="icon" :class="item.icon"></i>
<div class="text">{{ item.text }}</div>
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
@ -16,16 +16,16 @@
</template>
</div>
<div class="sub">
<MkA to="/docs" @click.passive="close()">
<MkA to="/docs" @click.passive="close()" v-click-anime>
<i class="fas fa-question-circle icon"></i>
<div class="text">{{ $ts.help }}</div>
</MkA>
<MkA to="/about" @click.passive="close()">
<MkA to="/about" @click.passive="close()" v-click-anime>
<i class="fas fa-info-circle icon"></i>
<div class="text">{{ $t('aboutX', { x: instanceName }) }}</div>
</MkA>
<MkA to="/about-misskey" @click.passive="close()">
<i class="fas fa-info-circle icon"></i>
<MkA to="/about-misskey" @click.passive="close()" v-click-anime>
<img src="/static-assets/favicon.png" class="icon"/>
<div class="text">{{ $ts.aboutMisskey }}</div>
</MkA>
</div>
@ -101,6 +101,7 @@ export default defineComponent({
flex-direction: column;
align-items: center;
justify-content: center;
vertical-align: bottom;
width: 128px;
height: 128px;
border-radius: var(--radius);
@ -117,6 +118,7 @@ export default defineComponent({
> .icon {
font-size: 26px;
height: 32px;
}
> .text {

View File

@ -1,5 +1,5 @@
<template>
<div class="yohlumlk">
<div class="yohlumlk" v-size="{ min: [350, 500] }">
<MkAvatar class="avatar" :user="note.user"/>
<div class="main">
<XNoteHeader class="header" :note="note" :mini="true"/>
@ -50,18 +50,19 @@ export default defineComponent({
display: flex;
margin: 0;
padding: 0;
overflow: hidden;
overflow: clip;
font-size: 0.95em;
> .avatar {
@media (min-width: 350px) {
&.min-width_350px {
> .avatar {
margin: 0 10px 0 0;
width: 44px;
height: 44px;
}
}
@media (min-width: 500px) {
&.min-width_500px {
> .avatar {
margin: 0 12px 0 0;
width: 48px;
height: 48px;

View File

@ -17,7 +17,7 @@
</MkButton>
</div>
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap">
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true">
<XNote :note="note" class="_block" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/>
</XList>

View File

@ -93,7 +93,7 @@ export default defineComponent({
if (this.menu) return;
this.menu = os.modalMenu([{
text: this.$ts.renameFile,
icon: faICursor,
icon: 'fas fa-i-cursor',
action: () => { this.rename(file) }
}, {
text: file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,

View File

@ -11,6 +11,7 @@
<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
<span>{{ $ts.password }}</span>
<template #prefix><i class="fas fa-lock"></i></template>
<template #desc><button class="_textButton" @click="resetPassword">{{ $ts.forgotPassword }}</button></template>
</MkInput>
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
</div>
@ -49,8 +50,8 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { toUnicode } from 'punycode/';
import MkButton from './ui/button.vue';
import MkInput from './ui/input.vue';
import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import { apiUrl, host } from '@client/config';
import { byteify, hexify } from '@client/scripts/2fa';
import * as os from '@client/os';
@ -197,6 +198,11 @@ export default defineComponent({
this.signing = false;
});
}
},
resetPassword() {
os.popup(import('@client/components/forgot-password.vue'), {}, {
}, 'closed');
}
}
});

View File

@ -12,14 +12,16 @@ export default defineComponent({
return withDirectives(h('div', {
class: 'pxhvhrfw',
}, options.map(option => h('button', {
}, options.map(option => withDirectives(h('button', {
class: ['_button', { active: this.value === option.props.value }],
key: option.props.value,
disabled: this.value === option.props.value,
onClick: () => {
this.$emit('update:value', option.props.value);
}
}, option.children))), [
}, option.children), [
[resolveDirective('click-anime')]
]))), [
[resolveDirective('size'), { max: [500] }]
]);
}

View File

@ -139,7 +139,8 @@ export default defineComponent({
}
&.primary {
color: #fff;
font-weight: bold;
color: #fff !important;
background: var(--accent);
&:not(:disabled):hover {
@ -200,10 +201,6 @@ export default defineComponent({
min-width: 100px;
}
&.primary {
font-weight: bold;
}
> .ripples {
position: absolute;
z-index: 0;

View File

@ -199,6 +199,7 @@ export default defineComponent({
> .fade {
display: block;
position: absolute;
z-index: 10;
bottom: 0;
left: 0;
width: 100%;

View File

@ -10,8 +10,8 @@
<div v-else class="cxiknjgy">
<slot :items="items"></slot>
<div class="more" v-show="more" key="_more_">
<MkButton class="button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
<div class="more _gap" v-show="more" key="_more_">
<MkButton class="button" v-appear="($store.state.enableInfiniteScroll && !disableAutoLoad) ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
<template v-if="moreFetching"><MkLoading inline/></template>
</MkButton>
@ -38,6 +38,12 @@ export default defineComponent({
pagination: {
required: true
},
disableAutoLoad: {
type: Boolean,
required: false,
default: false,
}
},
});
</script>

View File

@ -8,33 +8,35 @@
@closed="$emit('closed')"
>
<template #header>{{ $ts.selectUser }}</template>
<div class="tbhwbxda _section">
<div class="inputs">
<MkInput v-model:value="username" class="input" @update:value="search" ref="username"><span>{{ $ts.username }}</span><template #prefix>@</template></MkInput>
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $ts.host }}</span><template #prefix>@</template></MkInput>
</div>
</div>
<div class="tbhwbxda _section result" v-if="username != '' || host != ''" :class="{ hit: users.length > 0 }">
<div class="users" v-if="users.length > 0">
<div class="user" v-for="user in users" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
</div>
<div class="tbhwbxda _monolithic_">
<div class="_section">
<div class="inputs">
<MkInput v-model:value="username" class="input" @update:value="search" ref="username"><span>{{ $ts.username }}</span><template #prefix>@</template></MkInput>
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $ts.host }}</span><template #prefix>@</template></MkInput>
</div>
</div>
<div v-else class="empty">
<span>{{ $ts.noUsers }}</span>
<div class="_section result" v-if="username != '' || host != ''" :class="{ hit: users.length > 0 }">
<div class="users" v-if="users.length > 0">
<div class="user" v-for="user in users" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
</div>
</div>
</div>
<div v-else class="empty">
<span>{{ $ts.noUsers }}</span>
</div>
</div>
</div>
<div class="tbhwbxda _section recent" v-if="username == '' && host == ''">
<div class="users">
<div class="user" v-for="user in recentUsers" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
<div class="_section recent" v-if="username == '' && host == ''">
<div class="users">
<div class="user" v-for="user in recentUsers" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
</div>
</div>
</div>
</div>
@ -122,76 +124,78 @@ export default defineComponent({
<style lang="scss" scoped>
.tbhwbxda {
display: flex;
flex-direction: column;
overflow: auto;
height: 100%;
&.result.hit {
padding: 0;
}
&.recent {
padding: 0;
}
> .inputs {
> .input {
display: inline-block;
width: 50%;
margin: 0;
}
}
> .users {
flex: 1;
> ._section {
display: flex;
flex-direction: column;
overflow: auto;
padding: 8px 0;
height: 100%;
> .user {
display: flex;
align-items: center;
padding: 8px var(--root-margin);
font-size: 14px;
&.result.hit {
padding: 0;
}
&:hover {
background: var(--X7);
&.recent {
padding: 0;
}
> .inputs {
> .input {
display: inline-block;
width: 50%;
margin: 0;
}
}
&.selected {
background: var(--accent);
color: #fff;
}
> .users {
flex: 1;
overflow: auto;
padding: 8px 0;
> * {
pointer-events: none;
user-select: none;
}
> .user {
display: flex;
align-items: center;
padding: 8px var(--root-margin);
font-size: 14px;
> .avatar {
width: 45px;
height: 45px;
}
> .body {
padding: 0 8px;
min-width: 0;
> .name {
display: block;
font-weight: bold;
&:hover {
background: var(--X7);
}
> .acct {
opacity: 0.5;
&.selected {
background: var(--accent);
color: #fff;
}
> * {
pointer-events: none;
user-select: none;
}
> .avatar {
width: 45px;
height: 45px;
}
> .body {
padding: 0 8px;
min-width: 0;
> .name {
display: block;
font-weight: bold;
}
> .acct {
opacity: 0.5;
}
}
}
}
}
> .empty {
opacity: 0.7;
text-align: center;
> .empty {
opacity: 0.7;
text-align: center;
}
}
}
</style>

View File

@ -2,7 +2,10 @@ import { Directive } from 'vue';
export default {
mounted(el, binding, vn) {
el.classList.add('_anime_bounce_standBy');
el.addEventListener('mousedown', () => {
el.classList.add('_anime_bounce_standBy');
el.classList.add('_anime_bounce_ready');
el.addEventListener('mouseleave', () => {
@ -17,6 +20,7 @@ export default {
el.addEventListener('animationend', () => {
el.classList.remove('_anime_bounce_ready');
el.classList.remove('_anime_bounce');
el.classList.add('_anime_bounce_standBy');
});
}
} as Directive;

View File

@ -1,39 +1,57 @@
<template>
<FormBase class="mmnnbwxb" v-if="meta">
<div class="_formItem logo">
<img v-if="meta.logoImageUrl" :src="meta.logoImageUrl">
<span v-else class="text">{{ instanceName }}</span>
<FormBase>
<div class="_formItem">
<div class="_formPanel fwhjspax">
<img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/>
<span class="name">{{ $instance.name || host }}</span>
</div>
</div>
<FormTextarea readonly :value="$instance.description">
</FormTextarea>
<FormGroup>
<FormKeyValueView>
<template #key>Misskey</template>
<template #value>v{{ version }}</template>
</FormKeyValueView>
<FormLink to="/about-misskey">{{ $ts.aboutMisskey }}</FormLink>
</FormGroup>
<FormGroup>
<FormKeyValueView>
<template #key>{{ $ts.administrator }}</template>
<template #value>{{ meta.maintainerName }}</template>
<template #value>{{ $instance.maintainerName }}</template>
</FormKeyValueView>
<FormKeyValueView>
<template #key>{{ $ts.contact }}</template>
<template #value>{{ meta.maintainerEmail }}</template>
<template #value>{{ $instance.maintainerEmail }}</template>
</FormKeyValueView>
</FormGroup>
<FormLink v-if="meta.tosUrl" :to="meta.tosUrl" external>{{ $ts.tos }}</FormLink>
<FormLink v-if="$instance.tosUrl" :to="$instance.tosUrl" external>{{ $ts.tos }}</FormLink>
<FormGroup v-if="stats">
<template #label>{{ $ts.statistics }}</template>
<FormKeyValueView>
<template #key>{{ $ts.users }}</template>
<template #value>{{ number(stats.originalUsersCount) }}</template>
</FormKeyValueView>
<FormKeyValueView>
<template #key>{{ $ts.notes }}</template>
<template #value>{{ number(stats.originalNotesCount) }}</template>
</FormKeyValueView>
<FormSuspense :p="initStats">
<FormGroup>
<template #label>{{ $ts.statistics }}</template>
<FormKeyValueView>
<template #key>{{ $ts.users }}</template>
<template #value>{{ number(stats.originalUsersCount) }}</template>
</FormKeyValueView>
<FormKeyValueView>
<template #key>{{ $ts.notes }}</template>
<template #value>{{ number(stats.originalNotesCount) }}</template>
</FormKeyValueView>
</FormGroup>
</FormSuspense>
<FormGroup>
<template #label>Well-known resources</template>
<FormLink :to="`/.well-known/host-meta`" external>host-meta</FormLink>
<FormLink :to="`/.well-known/host-meta.json`" external>host-meta.json</FormLink>
<FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink>
<FormLink :to="`/robots.txt`" external>robots.txt</FormLink>
<FormLink :to="`/manifest.json`" external>manifest.json</FormLink>
</FormGroup>
</FormBase>
</template>
@ -45,9 +63,12 @@ import FormLink from '@client/components/form/link.vue';
import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormKeyValueView from '@client/components/form/key-value-view.vue';
import FormTextarea from '@client/components/form/textarea.vue';
import FormSuspense from '@client/components/form/suspense.vue';
import * as os from '@client/os';
import number from '@client/filters/number';
import * as symbols from '@client/symbols';
import { host } from '@client/config';
export default defineComponent({
components: {
@ -55,6 +76,8 @@ export default defineComponent({
FormGroup,
FormLink,
FormKeyValueView,
FormTextarea,
FormSuspense,
},
data() {
@ -63,24 +86,17 @@ export default defineComponent({
title: this.$ts.instanceInfo,
icon: 'fas fa-info-circle'
},
host,
version,
instanceName,
stats: null,
initStats: () => os.api('stats', {
}).then((stats) => {
this.stats = stats;
})
}
},
computed: {
meta() {
return this.$instance;
},
},
created() {
os.api('stats').then(stats => {
this.stats = stats;
});
},
methods: {
number
}
@ -88,18 +104,20 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.mmnnbwxb {
max-width: 800px;
box-sizing: border-box;
margin: 0 auto;
.fwhjspax {
padding: 16px;
text-align: center;
> .logo {
text-align: center;
> .icon {
display: block;
margin: auto;
height: 64px;
border-radius: 8px;
}
> img {
vertical-align: bottom;
max-height: 100px;
}
> .name {
display: block;
margin-top: 12px;
}
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<FormBase>
<FormSuspense :p="init">
<FormInput v-model:value="title">
<span>{{ $ts.title }}</span>
</FormInput>
<FormTextarea v-model:value="description" :max="500">
<span>{{ $ts.description }}</span>
</FormTextarea>
<FormGroup>
<div v-for="file in files" :key="file.id" class="_formItem _formPanel wqugxsfx" :style="{ backgroundImage: file ? `url(${ file.thumbnailUrl })` : null }">
<div class="name">{{ file.name }}</div>
<button class="remove _button" @click="remove(file)" v-tooltip="$ts.remove"><i class="fas fa-times"></i></button>
</div>
<FormButton @click="selectFile" primary><i class="fas fa-plus"></i> {{ $ts.attachFile }}</FormButton>
</FormGroup>
<FormSwitch v-model:value="isSensitive">{{ $ts.markAsSensitive }}</FormSwitch>
<FormButton v-if="postId" @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
<FormButton v-else @click="save" primary><i class="fas fa-save"></i> {{ $ts.publish }}</FormButton>
<FormButton v-if="postId" @click="del" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</FormButton>
</FormSuspense>
</FormBase>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import FormButton from '@client/components/form/button.vue';
import FormInput from '@client/components/form/input.vue';
import FormTextarea from '@client/components/form/textarea.vue';
import FormSwitch from '@client/components/form/switch.vue';
import FormTuple from '@client/components/form/tuple.vue';
import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormSuspense from '@client/components/form/suspense.vue';
import { selectFile } from '@client/scripts/select-file';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
export default defineComponent({
components: {
FormButton,
FormInput,
FormTextarea,
FormSwitch,
FormBase,
FormGroup,
FormSuspense,
},
props: {
postId: {
type: String,
required: false,
default: null,
}
},
data() {
return {
[symbols.PAGE_INFO]: computed(() => this.postId ? {
title: this.$ts.edit,
icon: 'fas fa-pencil-alt'
} : {
title: this.$ts.postToGallery,
icon: 'fas fa-pencil-alt'
}),
init: null,
files: [],
description: null,
title: null,
isSensitive: false,
}
},
watch: {
postId: {
handler() {
this.init = () => this.postId ? os.api('gallery/posts/show', {
postId: this.postId
}).then(post => {
this.files = post.files;
this.title = post.title;
this.description = post.description;
this.isSensitive = post.isSensitive;
}) : Promise.resolve(null);
},
immediate: true,
}
},
methods: {
selectFile(e) {
selectFile(e.currentTarget || e.target, null, true).then(files => {
this.files = this.files.concat(files);
});
},
remove(file) {
this.files = this.files.filter(f => f.id !== file.id);
},
async save() {
if (this.postId) {
await os.apiWithDialog('gallery/posts/update', {
postId: this.postId,
title: this.title,
description: this.description,
fileIds: this.files.map(file => file.id),
isSensitive: this.isSensitive,
});
this.$router.push(`/gallery/${this.postId}`);
} else {
const post = await os.apiWithDialog('gallery/posts/create', {
title: this.title,
description: this.description,
fileIds: this.files.map(file => file.id),
isSensitive: this.isSensitive,
});
this.$router.push(`/gallery/${post.id}`);
}
},
async del() {
const { canceled } = await os.dialog({
type: 'warning',
text: this.$ts.deleteConfirm,
showCancelButton: true
});
if (canceled) return;
await os.apiWithDialog('gallery/posts/delete', {
postId: this.postId,
});
this.$router.push(`/gallery`);
}
}
});
</script>
<style lang="scss" scoped>
.wqugxsfx {
height: 200px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
position: relative;
> .name {
position: absolute;
top: 8px;
left: 9px;
padding: 8px;
background: var(--panel);
}
> .remove {
position: absolute;
top: 8px;
right: 9px;
padding: 8px;
background: var(--panel);
}
}
</style>

View File

@ -0,0 +1,152 @@
<template>
<div class="xprsixdl _root">
<MkTab v-model:value="tab" v-if="$i">
<option value="explore"><i class="fas fa-icons"></i> {{ $ts.gallery }}</option>
<option value="liked"><i class="fas fa-heart"></i> {{ $ts._gallery.liked }}</option>
<option value="my"><i class="fas fa-edit"></i> {{ $ts._gallery.my }}</option>
</MkTab>
<div v-if="tab === 'explore'">
<MkFolder class="_gap">
<template #header><i class="fas fa-clock"></i>{{ $ts.recentPosts }}</template>
<MkPagination :pagination="recentPostsPagination" #default="{items}" :disable-auto-load="true">
<div class="vfpdbgtk">
<MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
</div>
</MkPagination>
</MkFolder>
<MkFolder class="_gap">
<template #header><i class="fas fa-fire-alt"></i>{{ $ts.popularPosts }}</template>
<MkPagination :pagination="popularPostsPagination" #default="{items}" :disable-auto-load="true">
<div class="vfpdbgtk">
<MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
</div>
</MkPagination>
</MkFolder>
</div>
<div v-else-if="tab === 'liked'">
<MkPagination :pagination="likedPostsPagination" #default="{items}">
<div class="vfpdbgtk">
<MkGalleryPostPreview v-for="like in items" :post="like.post" :key="like.id" class="post"/>
</div>
</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>
<MkPagination :pagination="myPostsPagination" #default="{items}">
<div class="vfpdbgtk">
<MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
</div>
</MkPagination>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import XUserList from '@client/components/user-list.vue';
import MkFolder from '@client/components/ui/folder.vue';
import MkInput from '@client/components/ui/input.vue';
import MkButton from '@client/components/ui/button.vue';
import MkTab from '@client/components/tab.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import MkGalleryPostPreview from '@client/components/gallery-post-preview.vue';
import number from '@client/filters/number';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
export default defineComponent({
components: {
XUserList,
MkFolder,
MkInput,
MkButton,
MkTab,
MkPagination,
MkGalleryPostPreview,
},
props: {
tag: {
type: String,
required: false
}
},
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.gallery,
icon: 'fas fa-icons'
},
tab: 'explore',
recentPostsPagination: {
endpoint: 'gallery/posts',
limit: 6,
},
popularPostsPagination: {
endpoint: 'gallery/featured',
limit: 5,
},
myPostsPagination: {
endpoint: 'i/gallery/posts',
limit: 5,
},
likedPostsPagination: {
endpoint: 'i/gallery/likes',
limit: 5,
},
tags: [],
};
},
computed: {
meta() {
return this.$instance;
},
tagUsers(): any {
return {
endpoint: 'hashtags/users',
limit: 30,
params: {
tag: this.tag,
origin: 'combined',
sort: '+follower',
}
};
},
},
watch: {
tag() {
if (this.$refs.tags) this.$refs.tags.toggleContent(this.tag == null);
},
},
created() {
},
methods: {
}
});
</script>
<style lang="scss" scoped>
.xprsixdl {
max-width: 1400px;
margin: 0 auto;
}
.vfpdbgtk {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
grid-gap: 12px;
margin: 0 var(--margin);
> .post {
}
}
</style>

View File

@ -0,0 +1,282 @@
<template>
<div class="_root">
<transition name="fade" mode="out-in">
<div v-if="post" class="rkxwuolj">
<div class="files">
<div class="file" v-for="file in post.files" :key="file.id">
<img :src="file.url"/>
</div>
</div>
<div class="body _block">
<div class="title">{{ post.title }}</div>
<div class="description"><Mfm :text="post.description"/></div>
<div class="info">
<i class="fas fa-clock"></i> <MkTime :time="post.createdAt" mode="detail"/>
</div>
<div class="actions">
<div class="like">
<MkButton class="button" @click="unlike()" v-if="post.isLiked" v-tooltip="$ts._gallery.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="post.likedCount > 0">{{ post.likedCount }}</span></MkButton>
<MkButton class="button" @click="like()" v-else v-tooltip="$ts._gallery.like"><i class="far fa-heart"></i><span class="count" v-if="post.likedCount > 0">{{ post.likedCount }}</span></MkButton>
</div>
<div class="other">
<button v-if="$i && $i.id === post.user.id" class="_button" @click="edit" v-tooltip="$ts.edit" v-click-anime><i class="fas fa-pencil-alt fa-fw"></i></button>
<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
</div>
</div>
<div class="user">
<MkAvatar :user="post.user" class="avatar"/>
<div class="name">
<MkUserName :user="post.user" style="display: block;"/>
<MkAcct :user="post.user"/>
</div>
<MkFollowButton v-if="!$i || $i.id != post.user.id" :user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
</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>
<MkPagination :pagination="otherPostsPagination" #default="{items}">
<div class="sdrarzaf">
<MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
</div>
</MkPagination>
</MkContainer>
</div>
<MkError v-else-if="error" @retry="fetch()"/>
<MkLoading v-else/>
</transition>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import MkButton from '@client/components/ui/button.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
import MkContainer from '@client/components/ui/container.vue';
import ImgWithBlurhash from '@client/components/img-with-blurhash.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import MkGalleryPostPreview from '@client/components/gallery-post-preview.vue';
import MkFollowButton from '@client/components/follow-button.vue';
import { url } from '@client/config';
export default defineComponent({
components: {
MkContainer,
ImgWithBlurhash,
MkPagination,
MkGalleryPostPreview,
MkButton,
MkFollowButton,
},
props: {
postId: {
type: String,
required: true
}
},
data() {
return {
[symbols.PAGE_INFO]: computed(() => this.post ? {
title: this.post.title,
avatar: this.post.user,
path: `/gallery/${this.post.id}`,
share: {
title: this.post.title,
text: this.post.description,
},
actions: [{
icon: 'fas fa-pencil-alt',
text: this.$ts.edit,
handler: this.edit
}]
} : null),
otherPostsPagination: {
endpoint: 'users/gallery/posts',
limit: 6,
params: () => ({
userId: this.post.user.id
})
},
post: null,
error: null,
};
},
watch: {
postId: 'fetch'
},
created() {
this.fetch();
},
methods: {
fetch() {
this.post = null;
os.api('gallery/posts/show', {
postId: this.postId
}).then(post => {
this.post = post;
}).catch(e => {
this.error = e;
});
},
share() {
navigator.share({
title: this.post.title,
text: this.post.description,
url: `${url}/gallery/${this.post.id}`
});
},
shareWithNote() {
os.post({
initialText: `${this.post.title} ${url}/gallery/${this.post.id}`
});
},
like() {
os.apiWithDialog('gallery/posts/like', {
postId: this.postId,
}).then(() => {
this.post.isLiked = true;
this.post.likedCount++;
});
},
async unlike() {
const confirm = await os.dialog({
type: 'warning',
showCancelButton: true,
text: this.$ts.unlikeConfirm,
});
if (confirm.canceled) return;
os.apiWithDialog('gallery/posts/unlike', {
postId: this.postId,
}).then(() => {
this.post.isLiked = false;
this.post.likedCount--;
});
},
edit() {
this.$router.push(`/gallery/${this.post.id}/edit`);
}
}
});
</script>
<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.125s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.rkxwuolj {
> .files {
> .file {
> img {
display: block;
max-width: 100%;
max-height: 500px;
margin: 0 auto;
}
& + .file {
margin-top: 16px;
}
}
}
> .body {
padding: 32px;
> .title {
font-weight: bold;
font-size: 1.2em;
margin-bottom: 16px;
}
> .info {
margin-top: 16px;
font-size: 90%;
opacity: 0.7;
}
> .actions {
display: flex;
align-items: center;
margin-top: 16px;
padding: 16px 0 0 0;
border-top: solid 0.5px var(--divider);
> .like {
> .button {
--accent: rgb(241 97 132);
--X8: rgb(241 92 128);
--buttonBg: rgb(216 71 106 / 5%);
--buttonHoverBg: rgb(216 71 106 / 10%);
color: #ff002f;
::v-deep(.count) {
margin-left: 0.5em;
}
}
}
> .other {
margin-left: auto;
> button {
padding: 8px;
margin: 0 8px;
&:hover {
color: var(--fgHighlighted);
}
}
}
}
> .user {
margin-top: 16px;
padding: 16px 0 0 0;
border-top: solid 0.5px var(--divider);
display: flex;
align-items: center;
> .avatar {
width: 52px;
height: 52px;
}
> .name {
margin: 0 0 0 12px;
font-size: 90%;
}
> .koudoku {
margin-left: auto;
}
}
}
}
.sdrarzaf {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
grid-gap: 12px;
margin: var(--margin);
> .post {
}
}
</style>

View File

@ -147,7 +147,6 @@ import * as os from '@client/os';
import number from '@client/filters/number';
import bytes from '@client/filters/bytes';
import * as symbols from '@client/symbols';
import { url } from '@client/config';
const chartLimit = 90;
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
@ -449,7 +448,7 @@ export default defineComponent({
.fnfelxur {
padding: 16px;
> img {
> .icon {
display: block;
margin: auto;
height: 64px;

View File

@ -0,0 +1,126 @@
<template>
<div class="uqshojas">
<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
<section class="_card _gap ads" v-for="ad in ads">
<div class="_content ad">
<MkAd v-if="ad.url" :specify="ad"/>
<MkInput v-model:value="ad.url" type="url">
<span>URL</span>
</MkInput>
<MkInput v-model:value="ad.imageUrl">
<span>{{ $ts.imageUrl }}</span>
</MkInput>
<div style="margin: 32px 0;">
<MkRadio v-model="ad.place" value="square">square</MkRadio>
<MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio>
<MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio>
</div>
<div style="margin: 32px 0;">
{{ $ts.priority }}
<MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
<MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
</div>
<MkInput v-model:value="ad.expiresAt" type="date">
<span>{{ $ts.expiration }}</span>
</MkInput>
<MkTextarea v-model:value="ad.memo">
<span>{{ $ts.memo }}</span>
</MkTextarea>
<div class="buttons">
<MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
<MkButton class="button" inline @click="remove(ad)" danger><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
</div>
</div>
</section>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import MkTextarea from '@client/components/ui/textarea.vue';
import MkRadio from '@client/components/ui/radio.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
export default defineComponent({
components: {
MkButton,
MkInput,
MkTextarea,
MkRadio,
},
emits: ['info'],
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.ads,
icon: 'fas fa-audio-description'
},
ads: [],
}
},
created() {
os.api('admin/ad/list').then(ads => {
this.ads = ads;
});
},
mounted() {
this.$emit('info', this[symbols.PAGE_INFO]);
},
methods: {
add() {
this.ads.unshift({
id: null,
memo: '',
place: 'square',
priority: 'middle',
url: '',
imageUrl: null,
expiresAt: null,
});
},
remove(ad) {
os.dialog({
type: 'warning',
text: this.$t('removeAreYouSure', { x: ad.url }),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.ads = this.ads.filter(x => x != ad);
os.apiWithDialog('admin/ad/delete', {
id: ad.id
});
});
},
save(ad) {
if (ad.id == null) {
os.apiWithDialog('admin/ad/create', {
...ad,
expiresAt: new Date(ad.expiresAt).getTime()
});
} else {
os.apiWithDialog('admin/ad/update', {
...ad,
expiresAt: new Date(ad.expiresAt).getTime()
});
}
}
}
});
</script>
<style lang="scss" scoped>
.uqshojas {
margin: var(--margin);
}
</style>

View File

@ -23,6 +23,7 @@
<FormLink :active="page === 'queue'" replace to="/instance/queue"><template #icon><i class="fas fa-clipboard-list"></i></template>{{ $ts.jobQueue }}</FormLink>
<FormLink :active="page === 'files'" replace to="/instance/files"><template #icon><i class="fas fa-cloud"></i></template>{{ $ts.files }}</FormLink>
<FormLink :active="page === 'announcements'" replace to="/instance/announcements"><template #icon><i class="fas fa-broadcast-tower"></i></template>{{ $ts.announcements }}</FormLink>
<FormLink :active="page === 'ads'" replace to="/instance/ads"><template #icon><i class="fas fa-audio-description"></i></template>{{ $ts.ads }}</FormLink>
<FormLink :active="page === 'abuses'" replace to="/instance/abuses"><template #icon><i class="fas fa-exclamation-circle"></i></template>{{ $ts.abuseReports }}</FormLink>
</FormGroup>
<FormGroup>
@ -102,6 +103,7 @@ export default defineComponent({
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'));

View File

@ -25,7 +25,6 @@ export default defineComponent({
endpoint: 'notes/mentions',
limit: 10,
},
faAt
};
},

View File

@ -1,35 +1,61 @@
<template>
<div class="xcukqgmh _root" v-if="page" :key="page.id" v-size="{ max: [450] }">
<div class="_block main">
<!--
<div class="header">
<h1>{{ page.title }}</h1>
<div class="_root">
<transition name="fade" mode="out-in">
<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
<div class="_block main">
<!--
<div class="header">
<h1>{{ page.title }}</h1>
</div>
-->
<div class="banner">
<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
</div>
<div class="content">
<XPage :page="page"/>
</div>
<div class="actions">
<div class="like">
<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
</div>
<div class="other">
<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
</div>
</div>
<div class="user">
<MkAvatar :user="page.user" class="avatar"/>
<div class="name">
<MkUserName :user="page.user" style="display: block;"/>
<MkAcct :user="page.user"/>
</div>
<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>
<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" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
<button v-else @click="pin(true)" class="link _textButton">{{ $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>
<MkAd :prefer="['horizontal', 'horizontal-big']"/>
<MkContainer :max-height="300" :foldable="true" class="other">
<template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template>
<MkPagination :pagination="otherPostsPagination" #default="{items}">
<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
</MkPagination>
</MkContainer>
</div>
-->
<div class="banner">
<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
</div>
<div class="content">
<XPage :page="page"/>
<small style="display: block; opacity: 0.7; margin-top: 1em;">@{{ page.user.username }}</small>
</div>
<div class="like">
<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
</div>
<div class="links">
<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $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" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
<button v-else @click="pin(true)" class="link _textButton">{{ $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>
<MkError v-else-if="error" @retry="fetch()"/>
<MkLoading v-else/>
</transition>
</div>
</template>
@ -39,11 +65,20 @@ import XPage from '@client/components/page/page.vue';
import MkButton from '@client/components/ui/button.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
import { url } from '@client/config';
import MkFollowButton from '@client/components/follow-button.vue';
import MkContainer from '@client/components/ui/container.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import MkPagePreview from '@client/components/page-preview.vue';
export default defineComponent({
components: {
XPage,
MkButton,
MkFollowButton,
MkContainer,
MkPagination,
MkPagePreview,
},
props: {
@ -69,6 +104,14 @@ export default defineComponent({
},
} : null),
page: null,
error: null,
otherPostsPagination: {
endpoint: 'users/pages',
limit: 6,
params: () => ({
userId: this.page.user.id
})
},
};
},
@ -90,11 +133,28 @@ export default defineComponent({
methods: {
fetch() {
this.page = null;
os.api('pages/show', {
name: this.pageName,
username: this.username,
}).then(page => {
this.page = page;
}).catch(e => {
this.error = e;
});
},
share() {
navigator.share({
title: this.page.title || this.page.name,
text: this.page.summary,
url: `${url}/@${this.page.user.username}/pages/${this.page.name}`
});
},
shareWithNote() {
os.post({
initialText: `${this.page.title || this.page.name} ${url}/@${this.page.user.username}/pages/${this.page.name}`
});
},
@ -132,6 +192,15 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.125s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.xcukqgmh {
--padding: 32px;
@ -140,6 +209,8 @@ export default defineComponent({
}
> .main {
padding: var(--padding);
> .header {
padding: 16px;
@ -150,35 +221,79 @@ export default defineComponent({
> .banner {
> img {
// TODO:
display: block;
width: 100%;
height: 120px;
height: 150px;
object-fit: cover;
}
}
> .content {
padding: var(--padding);
margin-top: 16px;
padding: 16px 0 0 0;
}
> .like {
padding: var(--padding);
> .actions {
display: flex;
align-items: center;
margin-top: 16px;
padding: 16px 0 0 0;
border-top: solid 0.5px var(--divider);
> .button {
--accent: rgb(216 71 106);
--X8: rgb(241 92 128);
--buttonBg: rgb(216 71 106 / 5%);
--buttonHoverBg: rgb(216 71 106 / 10%);
> .like {
> .button {
--accent: rgb(241 97 132);
--X8: rgb(241 92 128);
--buttonBg: rgb(216 71 106 / 5%);
--buttonHoverBg: rgb(216 71 106 / 10%);
color: #ff002f;
::v-deep(.count) {
margin-left: 0.5em;
::v-deep(.count) {
margin-left: 0.5em;
}
}
}
> .other {
margin-left: auto;
> button {
padding: 8px;
margin: 0 8px;
&:hover {
color: var(--fgHighlighted);
}
}
}
}
> .user {
margin-top: 16px;
padding: 16px 0 0 0;
border-top: solid 0.5px var(--divider);
display: flex;
align-items: center;
> .avatar {
width: 52px;
height: 52px;
}
> .name {
margin: 0 0 0 12px;
font-size: 90%;
}
> .koudoku {
margin-left: auto;
}
}
> .links {
padding: var(--padding);
margin-top: 16px;
padding: 24px 0 0 0;
border-top: solid 0.5px var(--divider);
> .link {

View File

@ -0,0 +1,69 @@
<template>
<FormBase v-if="token">
<FormInput v-model:value="password" type="password">
<template #prefix><i class="fas fa-lock"></i></template>
<span>{{ $ts.newPassword }}</span>
</FormInput>
<FormButton primary @click="save">{{ $ts.save }}</FormButton>
</FormBase>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import FormLink from '@client/components/form/link.vue';
import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormInput from '@client/components/form/input.vue';
import FormButton from '@client/components/form/button.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
export default defineComponent({
components: {
FormBase,
FormGroup,
FormLink,
FormInput,
FormButton,
},
props: {
token: {
type: String,
required: false
}
},
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.resetPassword,
icon: 'fas fa-lock'
},
password: '',
}
},
mounted() {
if (this.token == null) {
os.popup(import('@client/components/forgot-password.vue'), {}, {}, 'closed');
this.$router.push('/');
}
},
methods: {
async save() {
await os.apiWithDialog('reset-password', {
token: this.token,
password: this.password,
});
this.$router.push('/');
}
}
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -157,7 +157,6 @@ export default defineComponent({
maps: maps,
form: null,
messages: [],
fasCircle, farCircle
};
},

View File

@ -10,6 +10,7 @@
</div>
<FormLink :active="page === 'accounts'" replace to="/settings/accounts"><template #icon><i class="fas fa-users"></i></template>{{ $ts.accounts }}</FormLink>
</FormGroup>
<FormInfo v-if="emailNotConfigured" warn>{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></FormInfo>
<FormGroup>
<template #label>{{ $ts.basicSettings }}</template>
<FormLink :active="page === 'profile'" replace to="/settings/profile"><template #icon><i class="fas fa-user"></i></template>{{ $ts.profile }}</FormLink>
@ -58,10 +59,13 @@ import FormLink from '@client/components/form/link.vue';
import FormGroup from '@client/components/form/group.vue';
import FormBase from '@client/components/form/base.vue';
import FormButton from '@client/components/form/button.vue';
import FormInfo from '@client/components/form/info.vue';
import { scroll } from '@client/scripts/scroll';
import { signout } from '@client/account';
import { unisonReload } from '@client/scripts/unison-reload';
import * as symbols from '@client/symbols';
import { instance } from '@client/instance';
import { $i } from '@client/account';
export default defineComponent({
components: {
@ -69,6 +73,7 @@ export default defineComponent({
FormLink,
FormGroup,
FormButton,
FormInfo,
},
props: {
@ -173,6 +178,8 @@ export default defineComponent({
}
});
const emailNotConfigured = computed(() => instance.enableEmail && ($i.email == null || !$i.emailVerified));
return {
[symbols.PAGE_INFO]: INFO,
page,
@ -182,6 +189,7 @@ export default defineComponent({
onInfo,
pageProps,
component,
emailNotConfigured,
logout: () => {
signout();
},

View File

@ -18,6 +18,7 @@
<button class="_button tab" @click="chooseList" :class="{ active: src === 'list' }" v-tooltip="$ts.lists"><i class="fas fa-list-ul"></i></button>
</div>
</div>
<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
<XTimeline ref="tl"
class="_gap"
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
@ -30,7 +31,6 @@
@after="after()"
@queue="queueUpdated"
/>
<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
</div>
</template>

View File

@ -0,0 +1,63 @@
<template>
<div>
<MkPagination :pagination="pagination" #default="{items}">
<div class="jrnovfpt">
<MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
</div>
</MkPagination>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkGalleryPostPreview from '@client/components/gallery-post-preview.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import { userPage, acct } from '../../filters/user';
export default defineComponent({
components: {
MkPagination,
MkGalleryPostPreview,
},
props: {
user: {
type: Object,
required: true
},
},
data() {
return {
pagination: {
endpoint: 'users/gallery/posts',
limit: 6,
params: () => ({
userId: this.user.id
})
},
};
},
watch: {
user() {
this.$refs.list.reload();
}
},
methods: {
userPage,
acct
}
});
</script>
<style lang="scss" scoped>
.jrnovfpt {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
grid-gap: 12px;
margin: var(--margin);
}
</style>

View File

@ -161,15 +161,15 @@
</dl>
</div>
<div class="status">
<MkA :to="userPage(user)" :class="{ active: page === 'index' }">
<MkA :to="userPage(user)" :class="{ active: page === 'index' }" v-click-anime>
<b>{{ number(user.notesCount) }}</b>
<span>{{ $ts.notes }}</span>
</MkA>
<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }" v-click-anime>
<b>{{ number(user.followingCount) }}</b>
<span>{{ $ts.following }}</span>
</MkA>
<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }" v-click-anime>
<b>{{ number(user.followersCount) }}</b>
<span>{{ $ts.followers }}</span>
</MkA>
@ -179,18 +179,22 @@
<div class="contents">
<div class="nav _gap">
<MkA :to="userPage(user)" :class="{ active: page === 'index' }" class="link">
<MkA :to="userPage(user)" :class="{ active: page === 'index' }" class="link" v-click-anime>
<i class="fas fa-comment-alt icon"></i>
<span>{{ $ts.notes }}</span>
</MkA>
<MkA :to="userPage(user, 'clips')" :class="{ active: page === 'clips' }" class="link">
<MkA :to="userPage(user, 'clips')" :class="{ active: page === 'clips' }" class="link" v-click-anime>
<i class="fas fa-paperclip icon"></i>
<span>{{ $ts.clips }}</span>
</MkA>
<MkA :to="userPage(user, 'pages')" :class="{ active: page === 'pages' }" class="link">
<MkA :to="userPage(user, 'pages')" :class="{ active: page === 'pages' }" class="link" v-click-anime>
<i class="fas fa-file-alt icon"></i>
<span>{{ $ts.pages }}</span>
</MkA>
<MkA :to="userPage(user, 'gallery')" :class="{ active: page === 'gallery' }" class="link" v-click-anime>
<i class="fas fa-icons icon"></i>
<span>{{ $ts.gallery }}</span>
</MkA>
</div>
<template v-if="page === 'index'">
@ -210,6 +214,7 @@
<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_content _gap"/>
<XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
<XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
<XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/>
</div>
</div>
<MkError v-else-if="error" @retry="fetch()"/>
@ -250,6 +255,7 @@ export default defineComponent({
XFollowList: defineAsyncComponent(() => import('./follow-list.vue')),
XClips: defineAsyncComponent(() => import('./clips.vue')),
XPages: defineAsyncComponent(() => import('./pages.vue')),
XGallery: defineAsyncComponent(() => import('./gallery.vue')),
XPhotos: defineAsyncComponent(() => import('./index.photos.vue')),
XActivity: defineAsyncComponent(() => import('./index.activity.vue')),
},
@ -770,8 +776,7 @@ export default defineComponent({
> .nav {
display: flex;
align-items: center;
//font-size: 120%;
font-weight: bold;
font-size: 90%;
> .link {
flex: 1;

View File

@ -70,6 +70,8 @@ export default defineComponent({
border-radius: var(--radius);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
overflow: hidden;
max-width: 500px;
margin: 32px auto;
> h1 {
margin: 0;

View File

@ -23,6 +23,7 @@ export const router = createRouter({
{ path: '/@:user/pages/:pageName/view-source', component: page('page-editor/page-editor'), props: route => ({ initUser: route.params.user, initPageName: route.params.pageName }) },
{ path: '/@:acct/room', props: true, component: page('room/room') },
{ path: '/settings/:page(.*)?', name: 'settings', component: page('settings/index'), props: route => ({ initialPage: route.params.page || null }) },
{ path: '/reset-password/:token?', component: page('reset-password'), props: route => ({ token: route.params.token }) },
{ path: '/announcements', component: page('announcements') },
{ path: '/about', component: page('about') },
{ path: '/about-misskey', component: page('about-misskey') },
@ -37,6 +38,10 @@ export const router = createRouter({
{ path: '/pages', name: 'pages', component: page('pages') },
{ path: '/pages/new', component: page('page-editor/page-editor') },
{ path: '/pages/edit/:pageId', component: page('page-editor/page-editor'), props: route => ({ initPageId: route.params.pageId }) },
{ path: '/gallery', component: page('gallery/index') },
{ path: '/gallery/new', component: page('gallery/edit') },
{ path: '/gallery/:postId/edit', component: page('gallery/edit'), props: route => ({ postId: route.params.postId }) },
{ path: '/gallery/:postId', component: page('gallery/post'), props: route => ({ postId: route.params.postId }) },
{ path: '/channels', component: page('channels') },
{ path: '/channels/new', component: page('channel-editor') },
{ path: '/channels/:channelId/edit', component: page('channel-editor'), props: true },

View File

@ -91,8 +91,10 @@ export default (opts) => ({
...params,
limit: this.pagination.noPaging ? (this.pagination.limit || 10) : (this.pagination.limit || 10) + 1,
}).then(items => {
for (const item of items) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
markRaw(item);
if (i === 3) item._shouldInsertAd_ = true;
}
if (!this.pagination.noPaging && (items.length > (this.pagination.limit || 10))) {
items.pop();
@ -128,8 +130,10 @@ export default (opts) => ({
untilId: this.pagination.reversed ? this.items[0].id : this.items[this.items.length - 1].id,
}),
}).then(items => {
for (const item of items) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
markRaw(item);
if (i === 10) item._shouldInsertAd_ = true;
}
if (items.length > SECOND_FETCH_LIMIT) {
items.pop();

View File

@ -18,9 +18,11 @@ export const builtinThemes = [
require('@client/themes/l-light.json5'),
require('@client/themes/l-apricot.json5'),
require('@client/themes/l-rainy.json5'),
require('@client/themes/l-vivid.json5'),
require('@client/themes/d-dark.json5'),
require('@client/themes/d-persimmon.json5'),
require('@client/themes/d-astro.json5'),
require('@client/themes/d-black.json5'),
] as Theme[];

View File

@ -97,6 +97,11 @@ export const sidebarDef = {
icon: 'fas fa-file-alt',
to: '/pages',
},
gallery: {
title: 'gallery',
icon: 'fas fa-icons',
to: '/gallery',
},
clips: {
title: 'clip',
icon: 'fas fa-paperclip',

View File

@ -62,8 +62,9 @@ export const defaultStore = markRaw(new Storage('base', {
'notifications',
'messaging',
'drive',
'-',
'followRequests',
'-',
'gallery',
'featured',
'explore',
'announcements',

View File

@ -11,6 +11,8 @@
@media (max-width: 500px) {
--margin: var(--marginHalf);
}
//--ad: rgb(255 169 0 / 10%);
}
::selection {
@ -337,7 +339,7 @@ hr {
}
._monolithic_ {
._section {
._section:not(:empty) {
box-sizing: border-box;
padding: var(--root-margin, 32px);
@ -522,13 +524,18 @@ hr {
}
._anime_bounce {
will-change: transform;
animation: bounce ease 0.7s;
animation-iteration-count: 1;
transform-origin: 50% 50%;
}
._anime_bounce_ready {
will-change: transform;
transform: scaleX(0.90) scaleY(0.90) ;
}
._anime_bounce_standBy {
transition: transform 0.1s ease;
}
@keyframes bounce{
0% {

View File

@ -0,0 +1,76 @@
{
id: '080a01c5-377d-4fbb-88cc-6bb5d04977ea',
base: 'dark',
name: 'Mi Astro',
author: 'syuilo',
props: {
bg: '#232125',
fg: '#efdab9',
cwBg: '#687390',
cwFg: '#393f4f',
link: '#78b0a0',
warn: '#ecb637',
badge: '#31b1ce',
error: '#ec4137',
focus: ':alpha<0.3<@accent',
navBg: '@panel',
navFg: '@fg',
panel: '#2a272b',
accent: '#81c08b',
header: ':alpha<0.7<@bg',
infoBg: '#253142',
infoFg: '#fff',
renote: '#659CC8',
shadow: 'rgba(0, 0, 0, 0.3)',
divider: 'rgba(255, 255, 255, 0.1)',
hashtag: '#ff9156',
mention: '#ffd152',
modalBg: 'rgba(0, 0, 0, 0.5)',
success: '#86b300',
buttonBg: 'rgba(255, 255, 255, 0.05)',
acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#707b97',
indicator: '@accent',
mentionMe: '#fb5d38',
messageBg: ':lighten<5<@bg',
navActive: '@accent',
infoWarnBg: '#42321c',
infoWarnFg: '#ffbd3e',
navHoverFg: ':lighten<17<@fg',
dateLabelFg: '@fg',
inputBorder: '#959da2',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgba(0, 0, 0, 0.12)',
accentDarken: ':darken<10<@accent',
acrylicPanel: ':alpha<0.5<@panel',
navIndicator: '@accent',
accentLighten: ':lighten<10<@accent',
buttonHoverBg: 'rgba(255, 255, 255, 0.1)',
driveFolderBg: ':alpha<0.3<@accent',
fgHighlighted: ':lighten<3<@fg',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
htmlThemeColor: '@bg',
panelHighlight: ':lighten<3<@panel',
listItemHoverBg: 'rgba(255, 255, 255, 0.03)',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
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',
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',
},
}

View File

@ -10,7 +10,7 @@
props: {
bg: '#f9f9f9',
fg: '#676767',
divider: 'rgb(223, 223, 223)',
divider: '#e8e8e8',
header: ':alpha<0.7<@panel',
navBg: '#fff',
panel: '#fff',

View File

@ -0,0 +1,82 @@
{
id: '6128c2a9-5c54-43fe-a47d-17942356470b',
name: 'Mi Vivid',
author: 'syuilo',
base: 'light',
props: {
bg: '#fafafa',
fg: '#444',
cwBg: '#b1b9c1',
cwFg: '#fff',
link: '#ff9400',
warn: '#ecb637',
badge: '#31b1ce',
error: '#ec4137',
focus: ':alpha<0.3<@accent',
navBg: '@panel',
navFg: '@fg',
panel: '#fff',
accent: '#008cff',
header: ':alpha<0.7<@panel',
infoBg: '#e5f5ff',
infoFg: '#72818a',
renote: '@accent',
shadow: 'rgba(0, 0, 0, 0.1)',
divider: 'rgba(0, 0, 0, 0.08)',
hashtag: '#92d400',
mention: '@accent',
modalBg: 'rgba(0, 0, 0, 0.3)',
success: '#86b300',
buttonBg: 'rgba(0, 0, 0, 0.05)',
acrylicBg: ':alpha<0.5<@bg',
cwHoverBg: '#bbc4ce',
indicator: '@accent',
mentionMe: '@mention',
messageBg: '@panel',
navActive: '@accent',
infoWarnBg: '#fff0db',
infoWarnFg: '#573c08',
navHoverFg: ':darken<17<@fg',
dateLabelFg: '@fg',
inputBorder: '#dae0e4',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
accentDarken: ':darken<10<@accent',
acrylicPanel: ':alpha<0.5<@panel',
navIndicator: '@accent',
accentLighten: ':lighten<10<@accent',
buttonHoverBg: 'rgba(0, 0, 0, 0.1)',
driveFolderBg: ':alpha<0.3<@accent',
fgHighlighted: ':darken<3<@fg',
fgTransparent: ':alpha<0.5<@fg',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
htmlThemeColor: '@bg',
panelHighlight: ':darken<3<@panel',
listItemHoverBg: 'rgba(0, 0, 0, 0.03)',
scrollbarHandle: 'rgba(0, 0, 0, 0.2)',
wallpaperOverlay: 'rgba(255, 255, 255, 0.5)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: '@divider',
scrollbarHandleHover: 'rgba(0, 0, 0, 0.4)',
X2: ':darken<2<@panel',
X3: 'rgba(0, 0, 0, 0.05)',
X4: 'rgba(0, 0, 0, 0.1)',
X5: 'rgba(0, 0, 0, 0.05)',
X6: 'rgba(0, 0, 0, 0.25)',
X7: 'rgba(0, 0, 0, 0.05)',
X8: ':lighten<5<@accent',
X9: ':darken<5<@accent',
X10: ':alpha<0.4<@accent',
X11: 'rgba(0, 0, 0, 0.1)',
X12: 'rgba(0, 0, 0, 0.1)',
X13: 'rgba(0, 0, 0, 0.15)',
X14: ':alpha<0.5<@navBg',
X15: ':alpha<0<@panel',
X16: ':alpha<0.7<@panel',
X17: ':alpha<0.8<@bg',
},
}

View File

@ -42,11 +42,7 @@ export default defineComponent({
if (
i != this.items.length - 1 &&
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate() &&
!item._prId_ &&
!this.items[i + 1]._prId_ &&
!item._featuredId_ &&
!this.items[i + 1]._featuredId_
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate()
) {
const separator = h('div', {
class: 'separator',

View File

@ -313,7 +313,7 @@ export default defineComponent({
}
};
if (isLink(e.target)) return;
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return;
const path = this.$route.path;
os.contextMenu([{

View File

@ -64,7 +64,7 @@ export default defineComponent({
}
};
if (isLink(e.target)) return;
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return;
const path = this.$route.path;
os.contextMenu([{

View File

@ -36,7 +36,6 @@ export default defineComponent({
endpoint: 'notes/mentions',
limit: 10,
},
faAt
}
},

View File

@ -31,8 +31,10 @@
<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
</MkA>
<div class="divider"></div>
<div class="foo">
<MkEmoji :normal="true" :no-style="true" emoji="🍮"/>
<div class="about">
<MkA class="link" to="/about" v-click-anime>
<img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" class="_ghost"/>
</MkA>
</div>
<!--<MisskeyLogo class="misskey"/>-->
</div>
@ -260,14 +262,21 @@ export default defineComponent({
}
}
> .misskey {
> .about {
fill: currentColor;
}
> .foo {
text-align: center;
padding: 8px 0 16px 0;
opacity: 0.5;
text-align: center;
> .link {
display: block;
width: 32px;
margin: 0 auto;
img {
display: block;
width: 100%;
}
}
}
> .item {

View File

@ -165,7 +165,7 @@ export default defineComponent({
}
};
if (isLink(e.target)) return;
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return;
const path = this.$route.path;
os.contextMenu([{

View File

@ -1,6 +1,7 @@
<template>
<div class="efzpzdvf">
<div class="ddiqwdnk">
<XWidgets class="widgets" :edit="editMode" :widgets="$store.reactiveState.widgets.value" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
<MkAd class="a" prefer="square"/>
<button v-if="editMode" @click="editMode = false" class="_textButton edit" style="font-size: 0.9em;"><i class="fas fa-check"></i> {{ $ts.editWidgetsExit }}</button>
<button v-else @click="editMode = true" class="_textButton edit" style="font-size: 0.9em;"><i class="fas fa-pencil-alt"></i> {{ $ts.editWidgets }}</button>
@ -56,13 +57,14 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.efzpzdvf {
.ddiqwdnk {
position: sticky;
height: min-content;
box-sizing: border-box;
padding-bottom: 8px;
> .widgets {
> .widgets,
> .a {
width: 300px;
}

View File

@ -191,7 +191,7 @@ export default defineComponent({
}
};
if (isLink(e.target)) return;
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
if (window.getSelection().toString() !== '') return;
const path = this.$route.path;
os.contextMenu([{

View File

@ -51,6 +51,8 @@ import { UserSecurityKey } from '../models/entities/user-security-key';
import { AttestationChallenge } from '../models/entities/attestation-challenge';
import { Page } from '../models/entities/page';
import { PageLike } from '../models/entities/page-like';
import { GalleryPost } from '../models/entities/gallery-post';
import { GalleryLike } from '../models/entities/gallery-like';
import { ModerationLog } from '../models/entities/moderation-log';
import { UsedUsername } from '../models/entities/used-username';
import { Announcement } from '../models/entities/announcement';
@ -68,6 +70,8 @@ import { Channel } from '../models/entities/channel';
import { ChannelFollowing } from '../models/entities/channel-following';
import { ChannelNotePining } from '../models/entities/channel-note-pining';
import { RegistryItem } from '../models/entities/registry-item';
import { Ad } from '../models/entities/ad';
import { PasswordResetRequest } from '@/models/entities/password-reset-request';
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
@ -137,6 +141,8 @@ export const entities = [
NoteUnread,
Page,
PageLike,
GalleryPost,
GalleryLike,
Log,
DriveFile,
DriveFolder,
@ -165,6 +171,8 @@ export const entities = [
ChannelFollowing,
ChannelNotePining,
RegistryItem,
Ad,
PasswordResetRequest,
...charts as any
];

View File

@ -43,7 +43,7 @@ Theme codes are saved as a JSON5 object of theme options. Themes are composed of
* `props` ... The style definitions of the theme.These will be explained in the following.
### Theme style definitions
Define the style of the theme within `props`. The keys will become CSS variables, and the value specifies the content. In addition, the default `props` options are inherited from the base theme. If this theme's `base` is `light`, they will be copied from [_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5), if it is `dark` they will be copied from [_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5). In other words, if there is for example no `panel` key contained in `props`, then the value of `panel` from the base theme will be used.
Define the style of the theme within `props`. The keys will become CSS variables names, and the value specifies the content. In addition, the default `props` options are inherited from the base theme. If this theme's `base` is `light`, they will be copied from [_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5), and if it is `dark`, they will be copied from [_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5). In other words, if there is for example no `panel` key contained in `props`, then the value of `panel` from the base theme will be used.
#### Syntax for values
* Hex colors

View File

@ -1,4 +1,4 @@
# AiScript
## funciones
デフォルトで値渡しです。
Pasando valores por defecto

View File

@ -1,74 +1,74 @@
# プラグインの作成
Misskey Webクライアントのプラグイン機能を使うと、クライアントを拡張し、様々な機能を追加できます。 ここではプラグインの作成にあたってのメタデータ定義や、AiScript APIリファレンスを掲載します。
# Création d'un plugin
En utilisant la fonction plugin du client web Misskey, vous pouvez étendre et y ajouter de nouvelles fonctionnalités. Cette page liste la définition des métadonnées et les références de l'API AIScript pour la création des plugins.
## Métadonnées
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。 メタデータは次のプロパティを含むオブジェクトです。
Les plugins doivent définir des métadonnées de plugin par défaut via le format de métadonnées AiScript. Les métadonnées sont un objet contenant les propriétés suivantes :
### name
プラグイン名
Nom du plugin.
### author
プラグイン作者
Nom de l'auteur du plugin.
### version
プラグインバージョン。数値を指定してください。
Version du plugin.Cette valeur doit être un nombre.
### description
プラグインの説明
Description du plugin.
### permissions
プラグインが要求する権限。MisskeyAPIにリクエストする際に用いられます。
Permissions requises par le plugin.Utilisé pour les requêtes de l'API Misskey.
### config
プラグインの設定情報を表すオブジェクト。 キーに設定名、値に以下のプロパティを含めます。
Un objet représentant les paramètres du plugin. Les clés représentent les noms des paramètres et les valeurs sont l'une des propriétés ci-dessous.
#### type
設定値の種類を表す文字列。以下から選択します。 string number boolean
Une chaîne de caractères représentant le type de valeur du paramètre.Sélectionnez l'une des options suivantes : string number boolean
#### label
ユーザーに表示する設定名
Nom du paramètre affiché à l'utilisateur.
#### description
設定の説明
Description du paramètre
#### default
設定のデフォルト値
Valeur par défaut du paramètre
## Références API de Misskey
AiScript標準で組み込まれているAPIは掲載しません。
L'API intégrée directement dans la norme AiScript elle-même ne sera pas répertoriée.
### Mk:dialog(title text type)
ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると info になります。
Affiche la boîte de dialogue.type peut être défini par les valeurs suivantes. info success warn error question Si elle est omise, c'est "info" qui est utilisée.
### Mk:confirm(title text type)
確認ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると question になります。 ユーザーが"OK"を選択した場合は true を、"キャンセル"を選択した場合は false が返ります。
Affiche une boîte de dialogue de confirmation.Le type peut être défini par les valeurs suivantes. info success warn error question Si elle est omise, c'est "question" qui est utilisé par défaut. Si l'utilisateur sélectionne "OK", true est renvoyé, si l'utilisateur sélectionne "Cancel", false est renvoyé.
### Mk:api(endpoint params)
Misskey APIにリクエストします。第一引数にエンドポイント名、第二引数にパラメータオブジェクトを渡します。
Envoie une requête à l'API Misskey.Le premier paramètre spécifie le point de terminaison de l'API, le second spécifie les paramètres de la requête sous forme d'objet.
### Mk:save(key value)
任意の値に任意の名前を付けて永続化します。永続化した値は、AiScriptコンテキストが終了しても残り、Mk:loadで読み取ることができます。
Fait persister une valeur arbitraire avec un nom arbitraire.La valeur persistante reste après la fin du contexte AiScript et peut être lue par Mk:load.
### Mk:load(key)
Mk:saveで永続化した指定の名前の値を読み取ります。
Lit la valeur du nom spécifié persisté par Mk:save.
### Plugin:register_post_form_action(title fn)
投稿フォームにアクションを追加します。第一引数にアクション名、第二引数にアクションが選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に投稿フォームオブジェクトが渡されます。
Ajoute une action au formulaire de soumission.Le premier argument est le nom de l'action, le second est la fonction de rappel lorsque l'action est sélectionnée. La fonction de rappel reçoit l'objet du formulaire de soumission comme premier argument.
### Plugin:register_note_action(title fn)
ノートメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。
Ajoute un élément au menu note. Le premier paramètre spécifie le nom de l'action, le second paramètre spécifie une fonction de rappel qui est exécutée lorsque cet élément est sélectionné. La fonction de rappel reçoit un objet note comme premier paramètre.
### Plugin:register_user_action(title fn)
ユーザーメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のユーザーオブジェクトが渡されます。
Ajoute un élément au menu de l'utilisateur.Le premier paramètre spécifie le nom de l'action, le second paramètre spécifie une fonction de rappel qui est exécutée lorsque cet élément est sélectionné. La fonction de rappel reçoit un objet utilisateur comme premier paramètre.
### Plugin:register_note_view_interruptor(fn)
UIに表示されるート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
Réécrit les informations de la note affichée dans l'interface utilisateur. L'objet note cible est passé comme premier argument à la fonction de rappel. La note est réécrite dans la valeur de retour de la fonction de rappel.
### Plugin:register_note_post_interruptor(fn)
ノート投稿時にノート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
Réécrit les informations de la note lors de la publication d'une note. L'objet note cible est passé comme premier argument à la fonction de rappel. La note sera réécrite dans la valeur de retour de la fonction de rappel.
### Plugin:open_url(url)
第一引数に渡されたURLをブラウザの新しいタブで開きます。
Ouvre l'URL passée comme premier argument dans un nouvel onglet du navigateur.
### Plugin:config
プラグインの設定が格納されるオブジェクト。プラグイン定義のconfigで設定したキーで値が入ります。
Un objet dans lequel la configuration du plugin est stockée.La valeur est saisie par la clé définie dans la configuration de la définition du plugin.

View File

@ -1,33 +1,33 @@
# MisskeyリバーシBotの開発
Misskeyのリバーシ機能に対応したBotの開発方法をここに記します。
# Développement du bot Reversi de Misskey
Cette page explique comment développer un bot pour la fonction Reversi de Misskey.
1. `games/reversi`ストリームに以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
1. Connectez-vous au flux `games/reversi` avec les paramètres suivants :
* `i` : Clé API pour le compte du bot
2. 対局への招待が来たら、ストリームから`invited`イベントが流れてくる
* イベントの中身に、`parent`という名前で対局へ誘ってきたユーザーの情報が含まれている
2. Lorsqu'une invitation à un jeu arrive, un événement `invited` sera lancé à partir du flux.
* Le contenu de cet événement est un attribut `parent`, qui contient des informations sur l'utilisateur qui a envoyé l'invitation.
3. `games/reversi/match`へ、`user_id`として`parent`の`id`が含まれたリクエストを送信する
3. Envoie une requête à `games/reversi/match`, où la valeur du paramètre `user_id` est l'attribut `id` de l'objet `parent` obtenu précédemment.
4. 上手くいくとゲーム情報が返ってくるので、`games/reversi-game`ストリームへ、以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
* `game`: `game`の`id`
4. Si la requête fonctionne, les informations sur le jeu seront renvoyées et vous pourrez vous connecter au flux `games/reversi-game` avec les paramètres suivants :
* `i` : Clé API pour le compte du bot
* `game`: `game` de `id`
5. この間、相手がゲームの設定を変更するとその都度`update-settings`イベントが流れてくるので、必要であれば何かしらの処理を行う
5. Pendant ce temps, l'adversaire peut modifier les paramètres du jeu. Chaque fois qu'un paramètre est modifié, le flux envoie un événement `update-settings`, donc une logique pour gérer ces événements peut être nécessaire.
6. 設定に満足したら、`{ type: 'accept' }`メッセージをストリームに送信する
6. Une fois que vous êtes satisfait·e des paramètres du jeu, envoyez le message `{ type : 'accept' }` au flux.
7. ゲームが開始すると、`started`イベントが流れてくる
* イベントの中身にはゲーム情報が含まれている
7. Lorsque le jeu commence, l'événement `started` sera envoyé.
* Les informations sur l'état du jeu seront inclus dans cet événement.
8. 石を打つには、ストリームに`{ type: 'set', pos: <位置> }`を送信する(位置の計算方法は後述)
8. Pour placer une pierre, envoyez `{ type : 'set', pos : <Position&gt ; }` au flux (voir ci-dessous pour savoir comment calculer la position).
9. 相手または自分が石を打つと、ストリームから`set`イベントが流れてくる
* `color`として石の色が含まれている
* `pos`として位置情報が含まれている
9. Lorsque votre adversaire ou vous-même placez une pierre, un événement `set` est envoyé depuis le flux.
* `color` contient la couleur de la pierre placée
* `pos` contient la position de la pierre
## 位置の計算法
8x8のマップを考える場合、各マスの位置(インデックスと呼びます)は次のようになっています:
## Calculer la position
Si nous considérons une carte 8x8, la position de chaque carré (appelée index) est la suivante :
```
+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7|
@ -38,29 +38,29 @@ Misskeyのリバーシ機能に対応したBotの開発方法をここに記し
...
```
### X,Y座標 から インデックス に変換する
### Trouver les index à partir des coordonnées X, Y
```
pos = x + (y * mapWidth)
```
`mapWidth`は、ゲーム情報の`map`から、次のようにして計算できます:
`mapWidth` est une donnée de la carte prise sur la `map` comme suit :
```
mapWidth = map[0].length
```
### インデックス から X,Y座標 に変換する
### Trouver les coordonnées X, Y depuis l'index
```
x = pos % mapWidth
y = Math.floor(pos / mapWidth)
```
## マップ情報
マップ情報は、ゲーム情報の`map`に入っています。 文字列の配列になっており、ひとつひとつの文字がマス情報を表しています。 それをもとにマップのデザインを知る事が出来ます:
* `(スペース)` ... マス無し
* `-` ... マス
* `b` ... 初期配置される黒石
* `w` ... 初期配置される白石
## Information sur la carte
Les données de la carte sont incluses dans `map` dans les données du jeu. Comme les données sont représentées sous la forme d'un tableau de chaînes de caractères, chaque caractère représente un champ. Sur la base de ces données, vous pouvez reconstruire l'état de la carte :
* `(Vide)` ... Aucun champ
* `-` ... Champ
* `b` ... La première pierre placée est noire
* `w` ... La première pierre placée est blanche
例えば、4*4の次のような単純なマップがあるとします:
Par exemple, supposons que nous ayons la carte simple suivante de 4×4 :
```text
+---+---+---+---+
| | | | |
@ -73,23 +73,23 @@ y = Math.floor(pos / mapWidth)
+---+---+---+---+
```
この場合、マップデータはこのようになります:
Dans ce cas, les données de la carte ressembleront à ceci :
```javascript
['----', '-wb-', '-bw-', '----']
```
## ユーザーにフォームを提示して対話可能Botを作成する
ユーザーとのコミュニケーションを行うため、ゲームの設定画面でユーザーにフォームを提示することができます。 例えば、Botの強さをユーザーが設定できるようにする、といったシナリオが考えられます。
## Créer un Bot interactif en présentant un formulaire à l'utilisateur.
Afin de communiquer avec l'utilisateur, un formulaire peut être présenté à l'utilisateur sur l'écran des paramètres du jeu. Par exemple, un scénario pourrait consister à permettre à l'utilisateur de définir la force du bot.
フォームを提示するには、`reversi-game`ストリームに次のメッセージを送信します:
Pour présenter le formulaire, envoyez le message suivant au flux `reversi-game` :
```javascript
{
type: 'init-form',
body: [フォームコントロールの配列]
body: [Tableau de contrôles de formulaires]
}
```
フォームコントロールの配列については今から説明します。 フォームコントロールは、次のようなオブジェクトです:
Nous allons maintenant expliquer le tableau des contrôles de formulaires. Un contrôle de formulaire est un objet qui ressemble à ce qui suit :
```javascript
{
id: 'switch1',
@ -98,10 +98,10 @@ y = Math.floor(pos / mapWidth)
value: false
}
```
`id` ... コントロールのID。 `type` ... コントロールの種類。後述します。 `label` ... コントロールと一緒に表記するテキスト。 `value` ... コントロールのデフォルト値。
`id` ... ID de l'élément de contrôle. `type` ... Le type d'élément de contrôle. Nous y reviendrons plus tard. Texte affiché à côté de l'élément de contrôle. `value` ... La valeur par défaut de l'élément de contrôle.
### フォームの操作を受け取る
ユーザーがフォームを操作すると、ストリームから`update-form`イベントが流れてきます。 イベントの中身には、コントロールのIDと、ユーザーが設定した値が含まれています。 例えば、上で示したスイッチをユーザーがオンにしたとすると、次のイベントが流れてきます:
### Gestion des interactions avec les formulaires
Lorsqu'un utilisateur interagit avec le formulaire, un événement `update-form` est envoyé par le flux. Le contenu de l'événement contient l'ID du contrôle et la valeur définie par l'utilisateur. Par exemple, si l'utilisateur allume l'interrupteur illustré ci-dessus, l'événement suivant sera diffusé :
```javascript
{
id: 'switch1',
@ -109,52 +109,52 @@ y = Math.floor(pos / mapWidth)
}
```
### フォームコントロールの種類
### Types d'éléments de contrôles de formulaires
#### Interrupteur
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
type: `switch` Affiche un interrupteur.Cette fonction est utile lorsque vous souhaitez activer ou désactiver une fonction.
##### プロパティ
`label` ... スイッチに表記するテキスト。
##### Propriétés
`label` ... Texte à marquer sur l'interrupteur.
#### ラジオボタン
type: `radio` ラジオボタンを表示します。選択肢を提示するのに有用です。例えば、Botの強さを設定させるなどです。
#### Boutons radio
type: `radio` Affiche le bouton radio.Il est utile pour proposer des options.Par exemple, pour choisir la difficulté du bot.
##### プロパティ
`items` ... ラジオボタンの選択肢。例:
##### Propriétés
`items` ... Les options des boutons radio. Par exemple :
```javascript
items: [{
label: '',
label: 'Facile',
value: 1
}, {
label: '',
label: 'Moyen',
value: 2
}, {
label: '',
label: 'Difficile',
value: 3
}]
```
#### スライダー
type: `slider` スライダーを表示します。
#### Glissière
type: `slider` Affiche une glissière.
##### プロパティ
`min` ... スライダーの下限。 `max` ... スライダーの上限。 `step` ... 入力欄で刻むステップ値。
##### Propriétés
`min` ... Limite minimum de la glissière. `max` ... Limite maximum de la glissière. `step` ... Étapes entre les valeurs de la glissière.
#### テキストボックス
type: `textbox` テキストボックスを表示します。ユーザーになにか入力させる一般的な用途に利用できます。
#### Zones de texte
type: `textbox` Affiche une zone de texte.Cette fonction peut être utilisée à des fins générales lorsque vous souhaitez que l'utilisateur tape quelque chose.
## ユーザーにメッセージを表示する
設定画面でユーザーと対話する、フォーム以外のもうひとつの方法がこれです。ユーザーになにかメッセージを表示することができます。 例えば、ユーザーがBotの対応していないモードやマップを選択したとき、警告を表示するなどです。 メッセージを表示するには、次のメッセージをストリームに送信します:
## Afficher un message à l'utilisateur
C'est un autre moyen, autre que les formulaires, d'interagir avec les utilisateurs dans l'écran de configuration.Vous pouvez afficher un message à l'intention de l'utilisateur. Par exemple, vous pouvez afficher un avertissement lorsque l'utilisateur sélectionne un mode ou une carte qui n'est pas pris en charge par le Bot. Pour afficher un message, envoyez le message suivant au flux :
```javascript
{
type: 'message',
body: {
text: 'メッセージ内容',
type: 'メッセージの種類'
text: 'contenu du message',
type: 'Type du message'
}
}
```
メッセージの種類: `success`, `info`, `warning`, `error`
Type de message : `success`, `info`, `warning`, `error`.
## 投了する
投了をするには、<a href="./api/endpoints/games/reversi/games/surrender">このエンドポイント</a>にリクエストします。
## Abandonner
Pour se rendre, faites une demande à <a href="./api/endpoints/games/reversi/games/surrender">cette terminaison</a>.

View File

@ -1,25 +1,25 @@
# API Stream
# API streaming
L'API Stream permet d'implémenter l'exécution d'opérations variées et la réception de diverses informations en temps réel. Cela concerne, par exemple, l'affichage des nouvelles publications dans les fils, la réception de nouveaux messages, les nouveaux abonnements, etc.
L'API Streaming permet d'implémenter l'exécution d'opérations variées et la réception de diverses informations en temps réel. Cela concerne, par exemple, l'affichage des nouvelles publications dans les fils, la réception de nouveaux messages, les nouveaux abonnements, etc.
## ストリームに接続する
## Se connecter aux flux
ストリーミングAPIを利用するには、まずMisskeyサーバーに**websocket**接続する必要があります。
Pour utiliser l'API de streaming, vous devez d'abord effectuer une connexion **websocket** au serveur Misskey.
以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例:
Veuillez vous connecter à l'URL suivante avec le nom de paramètre `i` et inclure les informations d'authentification dans la connexion websocket.Par exemple :
```
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
```
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
Les informations d'identification sont votre clé API ou, en cas de connexion au flux depuis votre application, le jeton d'accès de l'utilisateur.
<div class="ui info">
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</a>をご確認ください。</p>
<p><i class="fas fa-info-circle"></i> Pour obtenir des informations sur l'obtention d'accréditations, veuillez consulter <a href="./api">ce document</a>.</p>
</div>
---
認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例:
Vous pouvez omettre les informations d'authentification, mais dans ce cas, vous utiliserez le système sans vous connecter, et les informations que vous pourrez recevoir et les opérations que vous pourrez effectuer seront limitées.Par exemple :
```
%WS_URL%/streaming
@ -27,15 +27,15 @@ L'API Stream permet d'implémenter l'exécution d'opérations variées et la ré
---
ストリームに接続すると、後述するAPI操作や、投稿の購読を行ったりすることができます。 しかしまだこの段階では、例えばタイムラインへの新しい投稿を受信したりすることはできません。 それを行うには、ストリーム上で、後述する**チャンネル**に接続する必要があります。
Une fois que vous êtes connecté au flux, vous pouvez utiliser l'API comme décrit ci-dessous, ou vous abonner aux messages. Cependant, à ce stade, vous ne pouvez pas recevoir de nouveaux messages sur votre fil, par exemple. Pour ce faire, vous devez vous connecter à un **canal** sur le flux, comme décrit ci-dessous.
**ストリームでのやり取りはすべてJSONです。**
**Toutes les interactions dans le flux sont JSON.**
## Canaux
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
L'API de streaming de Misskey possède le concept de canaux.Il s'agit d'un mécanisme permettant de séparer les informations que vous envoyez et recevez. Si vous vous connectez simplement à un flux Misskey, vous ne pourrez pas encore recevoir les messages de votre timeline en temps réel. En vous connectant aux canaux du flux, vous pourrez recevoir diverses informations et en envoyer.
### チャンネルに接続する
チャンネルに接続するには、次のようなデータをJSONでストリームに送信します:
### Se connecter à un canal
Pour se connecter à un canal, envoyez les données suivantes au flux en JSON :
```json
{
@ -50,19 +50,19 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
* `channel`には接続したいチャンネル名を設定します。チャンネルの種類については後述します。
* `id`にはそのチャンネルとやり取りするための任意のIDを設定します。ストリームでは様々なメッセージが流れるので、そのメッセージがどのチャンネルからのものなのか識別する必要があるからです。このIDは、UUIDや、乱数のようなもので構いません。
* `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
Ici,
* Définissez `channel` au nom du canal auquel vous voulez vous connecter.Les types de canaux sont décrits ci-dessous.
* `id` est un identifiant arbitraire pour interagir avec ce canal.En effet, le flux contient une variété de messages, et nous devons identifier de quel canal provient le message.Cet ID peut être un UUID ou une sorte de numéro aléatoire.
* `params` sont les paramètres utilisés pour se connecter au canal.Les différents canaux nécessitent des paramètres différents pour la connexion.Lors de la connexion à un canal qui ne nécessite pas de paramètres, cette propriété peut être omise.
<div class="ui info">
<p><i class="fas fa-info-circle"></i> IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。</p>
<p><i class="fas fa-info-circle"></i> L'ID est "par connexion de canal", et non par canal. En effet, dans certains cas, plusieurs connexions sont établies sur le même canal avec des paramètres différents.</p>
</div>
### チャンネルからのメッセージを受け取る
例えばタイムラインのチャンネルなら、新しい投稿があった時にメッセージを発します。そのメッセージを受け取ることで、タイムラインに新しい投稿がされたことをリアルタイムで知ることができます。
### Recevoir des messages du canal
Par exemple, lorsqu'un événement est émis dans l'un des canaux du fil en raison de la publication d'un nouveau message.En recevant ce message, vous saurez en temps réel qu'une nouvelle publication a été faite sur votre fil.
チャンネルがメッセージを発すると、次のようなデータがJSONでストリームに流れてきます:
Lorsqu'un canal émet un message, les données suivantes sont diffusées en JSON :
```json
{
type: 'channel',
@ -76,15 +76,15 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDが設定されています。これで、このメッセージがどのチャンネルからのものなのか知ることができます。
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
Ici,
* `id` est réglé sur l'ID que vous avez défini lors de la connexion à ce canal comme décrit ci-dessus.Cela vous permettra de savoir de quel canal provient ce message.
* `type` est défini comme le type du message.Le type de message qui sera diffusé dépend du canal.
* `body` est défini comme le contenu du message.En fonction du canal, le type de message qui sera diffusé dépendra du canal.
### チャンネルに向けてメッセージを送信する
チャンネルによっては、メッセージを受け取るだけでなく、こちらから何かメッセージを送信し、何らかの操作を行える場合があります。
### Envoi d'un message à un canal
Selon le canal, il se peut que vous ne receviez pas seulement des messages, mais que vous puissiez également envoyer certains messages et effectuer certaines opérations.
チャンネルにメッセージを送信するには、次のようなデータをJSONでストリームに送信します:
Pour envoyer un message à un canal, envoyez les données suivantes au flux en JSON :
```json
{
type: 'channel',
@ -98,13 +98,13 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。これで、このメッセージがどのチャンネルに向けたものなのか識別させることができます。
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
Ici,
* `id` doit être réglé sur l'ID que vous avez défini lors de la connexion à ce canal comme décrit ci-dessus.Cela vous permettra d'identifier le canal auquel ce message est destiné.
* `type` définit le type du message.Les différents canaux acceptent différents types de messages.
* `body` est défini comme le contenu du message.Les différents canaux acceptent différents types de messages.
### チャンネルから切断する
チャンネルから切断するには、次のようなデータをJSONでストリームに送信します:
### Déconnexion d'un canal
Pour se déconnecter d'un canal, envoyez les données suivantes au flux en JSON :
```json
{
@ -115,14 +115,14 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
Ici,
* `id` doit être réglé sur l'ID que vous avez défini lors de la connexion à ce canal comme décrit ci-dessus.
## ストリームを経由してAPIリクエストする
## Faire une requête API via le flux
ストリームを経由してAPIリクエストすると、HTTPリクエストを発生させずにAPIを利用できます。そのため、コードを簡潔にできたり、パフォーマンスの向上を見込めるかもしれません。
Si vous effectuez une requête d'API via un flux, vous pouvez utiliser l'API sans générer de requête HTTP.Cela peut rendre votre code plus concis et améliorer les performances.
ストリームを経由してAPIリクエストするには、次のようなデータをJSONでストリームに送信します:
Pour effectuer une demande d'API via un flux, envoyez les données suivantes au flux en JSON :
```json
{
type: 'api',
@ -136,18 +136,18 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
}
```
ここで、
* `id`には、APIのレスポンスを識別するための、APIリクエストごとの一意なIDを設定する必要があります。UUIDや、簡単な乱数のようなもので構いません。
* `endpoint`には、あなたがリクエストしたいAPIのエンドポイントを指定します。
* `data`には、エンドポイントのパラメータを含めます。
Ici,
* `id` doit être défini comme un identifiant unique pour chaque demande d'API afin d'identifier la réponse de l'API.Il peut s'agir de quelque chose comme un UUID ou un simple nombre aléatoire.
* `endpoint` est le point de terminaison de l'API que vous voulez demander.
* `data` contient les paramètres de la terminaison.
<div class="ui info">
<p><i class="fas fa-info-circle"></i> APIのエンドポイントやパラメータについてはAPIリファレンスをご確認ください。</p>
<p><i class="fas fa-info-circle"></i> Veuillez vous reporter à la référence de l'API pour les points de terminaison et les paramètres de l'API.</p>
</div>
### レスポンスの受信
### Réception des réponses
APIへリクエストすると、レスポンスがストリームから次のような形式で流れてきます。
Lorsque vous faites une demande à l'API, la réponse viendra du flux dans le format suivant.
```json
{
@ -158,23 +158,23 @@ APIへリクエストすると、レスポンスがストリームから次の
}
```
ここで、
* `xxxxxxxxxxxxxxxx`の部分には、リクエストの際に設定された`id`が含まれています。これにより、どのリクエストに対するレスポンスなのか判別することができます。
* `body`には、レスポンスが含まれています。
Ici,
* La partie `xxxxxxxxxxxxxxxx` contient le `id` qui a été défini au moment de la demande.Cela vous permet de déterminer à quelle demande il répond.
* `body` contient la réponse.
## 投稿のキャプチャ
## Capture de message
Misskeyは投稿のキャプチャと呼ばれる仕組みを提供しています。これは、指定した投稿のイベントをストリームで受け取る機能です。
Misskey propose un mécanisme appelé post-capture.Il s'agit de la possibilité de recevoir un flux d'événements pour un message donné.
例えばタイムラインを取得してユーザーに表示したとします。ここで誰かがそのタイムラインに含まれるどれかの投稿に対してリアクションしたとします。
Par exemple, supposons une situation dans laquelle le fil est affichée pour un utilisateur.Supposons maintenant que quelqu'un réagisse à l'un des messages de ce fil.
しかし、クライアントからするとある投稿にリアクションが付いたことなどは知る由がないため、リアルタイムでリアクションをタイムライン上の投稿に反映して表示するといったことができません。
Cependant, comme le client n'a aucun moyen de savoir qu'un message a reçu une réaction, il n'est pas possible de refléter la réaction en temps réel sur le message dans le fil.
この問題を解決するために、Misskeyは投稿のキャプチャ機構を用意しています。投稿をキャプチャすると、その投稿に関するイベントを受け取ることができるため、リアルタイムでリアクションを反映させたりすることが可能になります。
Pour résoudre ce problème, Misskey fournit un mécanisme de post-capture.Lorsque vous capturez un message, vous recevez des événements liés à ce message, ce qui vous permet de refléter les réactions en temps réel.
### 投稿をキャプチャする
### Capturer un message
投稿をキャプチャするには、ストリームに次のようなメッセージを送信します:
Pour capturer un message, envoyez un message comme le suivant au flux :
```json
{
@ -185,12 +185,12 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
* `id`にキャプチャしたい投稿の`id`を設定します。
Ici,
* Définissez `id` comme l'`id` du message que vous voulez capturer.
このメッセージを送信すると、Misskeyにキャプチャを要請したことになり、以後、その投稿に関するイベントが流れてくるようになります。
Lorsque vous envoyez ce message, vous demandez à Misskey de le saisir, et les événements liés à ce message se succéderont à partir de ce moment-là.
例えば投稿にリアクションが付いたとすると、次のようなメッセージが流れてきます:
Par exemple, lorsqu'un message suscite une réaction, vous verrez apparaître un message du type suivant :
```json
{
@ -206,20 +206,20 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
* `body`内の`id`に、イベントを発生させた投稿のIDが設定されます。
* `body`内の`type`に、イベントの種類が設定されます。
* `body`内の`body`に、イベントの詳細が設定されます。
Ici,
* Le `id` dans le `body` est défini comme l'ID du post qui a déclenché l'événement.
* Le type de l'événement est défini par `type` dans `body`.
* L'attribut `body` dans `body` contient les informations sur l'événement.
#### イベントの種類
#### Type d'événements
##### `reacted`
その投稿にリアクションがされた時に発生します。
Cela se produit lorsqu'une réaction est faite à ce message.
* `reaction`に、リアクションの種類が設定されます。
* `userId`に、リアクションを行ったユーザーのIDが設定されます。
* `reaction` est défini comme le type de réaction.
* `userId` sera défini comme l'ID de l'utilisateur qui a fait la réaction.
:
Par exemple :
```json
{
type: 'noteUpdated',
@ -235,11 +235,11 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
```
##### `deleted`
その投稿が削除された時に発生します。
Cela se produit lorsque ce message est supprimé.
* `deletedAt`に、削除日時が設定されます。
* `deletedAt` est défini comme la date et l'heure de la suppression.
:
Par exemple :
```json
{
type: 'noteUpdated',
@ -254,12 +254,12 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
```
##### `pollVoted`
その投稿に添付されたアンケートに投票された時に発生します。
Déclenché lors du vote sur un sondage dans ce message.
* `choice`に、選択肢IDが設定されます。
* `userId`に、投票を行ったユーザーのIDが設定されます。
* `choice` contient l'ID du choix sélectionné.
* `userId` sera défini comme l'ID de l'utilisateur qui a voté.
:
Par exemple :
```json
{
type: 'noteUpdated',
@ -274,11 +274,11 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
### 投稿のキャプチャを解除する
### Annuler la capture de publication
その投稿がもう画面に表示されなくなったりして、その投稿に関するイベントをもう受け取る必要がなくなったときは、キャプチャの解除を申請してください。
Quand une publication n'est plus affichée et que vous n'avez plus besoin de recevoir les événements la concernant, vous pouvez demander l'annulation de la capture.
次のメッセージを送信します:
Envoyez le message suivant :
```json
{
@ -289,66 +289,66 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
}
```
ここで、
* `id`にキャプチャを解除したい投稿の`id`を設定します。
Ici,
* Définissez `id` comme le `id` du message que vous voulez annuler.
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。
Une fois que vous aurez envoyé ce message, aucun autre événement lié au message ne sera diffusé.
# チャンネル一覧
# Liste des canaux
## `main`
アカウントに関する基本的な情報が流れてきます。このチャンネルにパラメータはありません。
Les informations de base relatives au compte seront transmises ici.Il n'y a pas de paramètres pour ce canal.
### 流れてくるイベント一覧
### Liste des événements envoyés
#### `renote`
自分の投稿がRenoteされた時に発生するイベントです。自分自身の投稿をRenoteしたときは発生しません。
Cet événement est déclenché lorsque votre message est renoté.Cela ne se produit pas lorsque vous renotez votre propre message.
#### `mention`
誰かからメンションされたときに発生するイベントです。
Il s'agit d'un événement qui se produit lorsque quelqu'un fait vous mentionne.
#### `readAllNotifications`
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
Cet événement indique que toutes les notifications qui vous ont été adressées ont été lues.Cet événement peut être utilisé pour désactiver des choses comme "l'icône indiquant qu'il y a une notification" et d'autres cas.
#### `meUpdated`
自分の情報が更新されたことを表すイベントです。
Cet événement indique que vos informations ont été mises à jour.
#### `follow`
自分が誰かをフォローしたときに発生するイベントです。
Cet événement se produit lorsque vous suivez quelqu'un.
#### `unfollow`
自分が誰かのフォローを解除したときに発生するイベントです。
Cet événement se produit lorsque vous retirez quelqu'un de vos suivis.
#### `followed`
自分が誰かにフォローされたときに発生するイベントです。
Cet événement se produit lorsque vous êtes suivi par quelqu'un.
## `homeTimeline`
ホームタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
Vous verrez ce flux d'informations s'afficher sur votre fil personnel.Il n'y a pas de paramètres pour ce canal.
### 流れてくるイベント一覧
### Liste des événements envoyés
#### `note`
タイムラインに新しい投稿が流れてきたときに発生するイベントです。
Cet événement est déclenché lorsqu'un nouveau message arrive sur sur fil.
## `localTimeline`
ローカルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
Vous verrez l'information affichée sur votre fil local.Il n'y a pas de paramètres pour ce canal.
### 流れてくるイベント一覧
### Liste des événements envoyés
#### `note`
ローカルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
Cet événement est déclenché lorsqu'un nouveau message apparaît dans le fil local.
## `hybridTimeline`
ソーシャルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
Vous verrez l'information affichée sur le fil social.Il n'y a pas de paramètres pour ce canal.
### 流れてくるイベント一覧
### Liste des événements envoyés
#### `note`
ソーシャルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
Cet événement est déclenché lorsqu'un nouveau message apparaît sur votre fil social.
## `globalTimeline`
グローバルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
Vous verrez l'information s'afficher sur le fil global.Il n'y a pas de paramètres pour ce canal.
### 流れてくるイベント一覧
### Liste des événements envoyés
#### `note`
グローバルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
Cet événement est déclenché lorsqu'un nouveau message arrive sur le fil global.

View File

@ -43,7 +43,7 @@ Le code des thèmes est écrit sous forme d'objets JSON5. Les thèmes comprennen
* `props` ... Définir un style de thème.Voir les explications ci-après.
### Définir un style de thème
C'est dans `props` que vous définirez le style de thème. Les propriétés deviendront des variables CSS et les valeurs associées spécifieront le contenu de ces variables. Par ailleurs, les objets présents par défaut dans `props` sont hérités du thème de base. Ainsi, si le thème de `base` est clair `light` ce sera l'objet [_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5) ; et s'il est sombre `dark` ce sera l'objet [_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5). Cela signifie, par exemple, que s'il n'y pas de propriété `panel` définie dans les `props` du thème, alors ce sera la valeur `panel` du thème de base qui sera prise en compte.
C'est dans `props` que vous définirez le style du thème. Les clés deviendront des noms de variables CSS dont le contenu sera spécifié par les valeurs associées. Par ailleurs, les objets présents par défaut dans `props` sont hérités du thème de base. Ainsi, si le thème de `base` est `clair`, ce sera le fichier [_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5) ; et s'il est `sombre`, le fichier [_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5). En bref, s'il n'y a, par exemple, pas de clé `panel` définie dans les `props` du thème, alors ce sera la valeur `panel` du thème de base qui sera prise en compte.
#### Syntaxe des valeurs
* Codes de couleur Hex
@ -52,11 +52,11 @@ C'est dans `props` que vous définirez le style de thème. Les propriétés devi
* Ex. : `rgb(0, 255, 0)`
* Couleurs avec les valeurs RVBA : `rgba(r, g, b, a)`
* Ex. : `rgba(0, 255, 0, 0.5)`
* Faire référence aux valeurs d'autres propriétés
* Entrer `@{keyname}` pour utiliser la valeur de la propriété citée. Remplacer alors `{keyname}` par le nom de la propriété que vous souhaitez citer.
* Appeler les valeurs d'autres clés
* Entrer `@{keyname}` pour appeler la valeur d'une autre clé. Remplacer alors `{keyname}` par le nom de la clé que vous souhaitez appeler.
* Ex. : `@panel`
* Constantes (voir ci-dessous)
* Entrer `${constantname}` pour utiliser la valeur de la constante citée.Remplacer alors `{constantname}` par la nom de la constante que vous souhaitez citer.
* Entrer `${constantname}` vous permet d'appeler une constante. Remplacer alors `{constantname}` par le nom de la constante que vous souhaitez appeler.
* Ex. : `$main`
* Fonctions (voir ci-dessous)
* `:{functionname}<{argument}<{color}`

View File

@ -1,18 +1,18 @@
# デッキ
# Deck
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です。
Il deck è una delle interfacce utente disponibili.Ti consente di configurare varie colonne fianco a fianco, con molte possibilità di personalizzazione, per ottenere uno schermo più ricco in contenuti.
## カラムの追加
デッキの背景を右クリックし、「カラムを追加」して任意のカラムを追加できます。
## Aggiungere colonne
Puoi aggiungere una colonna facendo un clic destro nello sfondo del deck, poi selezionando "Aggiungi colonna".
## カラムの移動
## Spostare colonne
カラムは、ドラッグアンドドロップで他のカラムと位置を入れ替えることが出来るほか、カラムメニュー(カラムのヘッダー右クリック)から位置を移動させることもできます。
## カラムの水平分割
## Dividere colonne in orizzontale
カラムは左右だけでなく、上下に並べることもできます。 カラムメニューを開き、「左に重ねる」を選択すると、左のカラムの下に現在のカラムが移動します。 上下分割を解除するには、カラムメニューの「右に出す」を選択します。
## カラムの設定
カラムメニューの「編集」を選択するとカラムの設定を編集できます。カラムの名前を変えたり、幅を変えたりできます。
## Impostazioni colonna
Puoi modificare le impostazioni della singola colonna premendo "Modifica" nel menù di colonna. È possibile cambiare il nome e la larghezza della colonna.
## デッキの設定
デッキに関する設定は、[settings/deck](/settings/deck)で行えます。
## Impostazioni deck
Puoi trovare le opzioni d'impostazione in [settings/deck](/settings/deck).

View File

@ -15,25 +15,25 @@ Le scorciatoie da tastiera sotto citate si possono usare praticamente ovunque.
</tbody>
</table>
## 投稿にフォーカスされた状態
## Azioni riguardanti le pubblicazioni
<table>
<thead>
<tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd>, <kbd class="key">Tab</kbd></td><td>下の投稿にフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
<tr><td><kbd class="key">Q</kbd></td><td>Renoteフォームを開く</td><td><b>Q</b>uote</td></tr>
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
<tr><td><kbd class="key">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
<tr><td><kbd class="key">Del</kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">D</kbd></kbd></td><td>投稿を削除</td><td><b>D</b>elete</tr>
<tr><td><kbd class="key">M</kbd>, <kbd class="key">O</kbd></td><td>投稿に対するメニューを開く</td><td><b>M</b>ore, <b>O</b>ther</td></tr>
<tr><td><kbd class="key">S</kbd></td><td>CWで隠された部分を表示 or 隠す</td><td><b>S</b>how, <b>S</b>ee</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>フォーカスを外す</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>Sposta il focus sulla pubblicazione di sopra</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd>, <kbd class="key">Tab</kbd></td><td>Sposta il focus sulla pubblicazione di sotto</td><td>-</td></tr>
<tr><td><kbd class="key">R</kbd></td><td>Apri finestra di risposta</td><td><b>R</b>eply</td></tr>
<tr><td><kbd class="key">Q</kbd></td><td>Apri finestra Rinota</td><td><b>Q</b>uote</td></tr>
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>Rinota immediatamente (senza aprire finestra)</td><td>-</td></tr>
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>Apri finestra di reazioni</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>Usa reazione del numero corrispondente</td><td>-</td></tr>
<tr><td><kbd class="key">F</kbd>, <kbd class="key">B</kbd></td><td>Aggiungi ai preferiti</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
<tr><td><kbd class="key">Del</kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">D</kbd></kbd></td><td>Elimina pubblicazione</td><td><b>D</b>elete</tr>
<tr><td><kbd class="key">M</kbd>, <kbd class="key">O</kbd></td><td>Apri menù della nota</td><td><b>M</b>ore, <b>O</b>ther</td></tr>
<tr><td><kbd class="key">S</kbd></td><td>Visualizza o nascondi il contenuto segnato con CW</td><td><b>S</b>how, <b>S</b>ee</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>Esci dal focus</td><td>-</td></tr>
</tbody>
</table>
@ -57,12 +57,12 @@ La reazione "👍" è impostata come reazione predefinita.
<tr><th>Scorciatoia</th><th>Effetto</th><th>Accesso universale</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd></td><td>上のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd></td><td>下のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">H</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>左のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">L</kbd>, <kbd class="key">Tab</kbd></td><td>右のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key">Enter</kbd>, <kbd class="key">Space</kbd>, <kbd class="key">+</kbd></td><td>リアクション確定</td><td>-</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションで確定</td><td>-</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>リアクションするのをやめる</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd></td><td>Sposta il focus sulla reazione di sopra</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd></td><td>Sposta il focus sulla reazione di sotto</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">H</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>Sposta il focus sulla reazione a sinistra</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">L</kbd>, <kbd class="key">Tab</kbd></td><td>Sposta il focus sulla reazione a destra</td><td>-</td></tr>
<tr><td><kbd class="key">Enter</kbd>, <kbd class="key">Space</kbd>, <kbd class="key">+</kbd></td><td>Seleziona la reazione</td><td>-</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>Usa reazione del numero corrispondente </td><td>-</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>Cancella reazione</td><td>-</td></tr>
</tbody>
</table>

View File

@ -110,7 +110,7 @@ y = Math.floor(pos / mapWidth)
```
### フォームコントロールの種類
#### スイッチ
#### Interruttore
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
##### プロパティ

View File

@ -33,36 +33,36 @@ Il codice dei temi è scritto a forma di oggetti JSON5. I temi contengono gli og
```
* `id` ... テーマの一意なID。UUIDをおすすめします。
* `name` ... テーマ名
* `author` ... テーマの作者
* `desc` ... テーマの説明(オプション)
* `base` ... 明るいテーマか、暗いテーマか
* `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
* テーマはここで設定されたベーステーマを継承します。
* `props` ... テーマのスタイル定義。これから説明します。
* `id` ... Identificativo univoco del tema. È consigliato utilizzare un UUID.
* `name` ... Nome tema
* `author` ... Autore/Autrice del tema
* `desc` ... Descrizione tema (facoltativa)
* `base` ... Imposta tema chiaro o tema scuro
* Scegli `light` per impostare un tema chiaro, e `dark` per impostare un tema scuro.
* Il tema erediterà dalle caratteristiche del tema di base impostato qui.
* `props` ... Imposta uno stile di tema. (Vedi spiegazioni sotto.)
### Impostare uno stile di tema
`props`下にはテーマのスタイルを定義します。 キーがCSSの変数名になり、バリューで中身を指定します。 なお、この`props`オブジェクトはベーステーマから継承されます。 ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5)です。 つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。
Puoi configurare lo stile del tema dentro le `props`. Le chiavi diventeranno nomi di variabili CSS, il cui contenuto verrà definito dai valori associati ad esse. Inoltre, gli oggetti presenti in `props` per impostazione predefinita vengono ereditati dal tema di base. Il tema di base sarà [_light.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_light.json5) per una `base` `chiara`, e [_dark.json5](https://github.com/misskey-dev/misskey/blob/develop/src/client/themes/_dark.json5) per una `base` `scura`. Cioè, se non viene definita una chiave `panel` nelle `props` del tema, si terrà conto del valore <0>panel</0> predefinito del tema usato.
#### Sintassi dei valori
* 16進数で表された色
* : `#00ff00`
* `rgb(r, g, b)`形式で表された色
* : `rgb(0, 255, 0)`
* `rgb(r, g, b, a)`形式で表された透明度を含む色
* : `rgba(0, 255, 0, 0.5)`
* 他のキーの値の参照
* `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
* : `@panel`
* 定数(後述)の参照
* `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
* : `$main`
* 関数(後述)
* `:{関数名}<{引数}<{色}`
* Colori HEX
* Es.: `#00ff00`
* Colori `RGB(r, g, b)`
* Es.: `rgb(0, 255, 0)`
* Colori `RGBA(r, g, b, a)`
* Es.: `rgba(0, 255, 0, 0.5)`
* Chiamare valori di altre chiavi
* Inserisci `@{keyname}` per chiamare il valore di un'altra chiave. Bisogna sostituire il testo `{keyname}` col nome della chiave che vuoi chiamare.
* Es.: `@panel`
* Costanti (vedi sotto)
* Inserisci `${constantname}` per chiamare una costante.Bisogna sostituire il testo `{constantname}` col nome della costante che vuoi chiamare.
* Es.: `$main`
* Funzioni (vedi sotto)
* `:{functionname}<{argument}<{color}`
#### Costanti
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
Può essere vantaggioso usare una costante nei casi in cui non vuoi che un valore produca una variabile CSS, perché lo vuoi utilizzare come valore di un'altra variabile CSS. In tal caso, basta aggiungere `$` davanti al nome della chiave affinché non generi variabile CSS.
#### Funzioni
wip

View File

@ -11,5 +11,5 @@ Pubblicazioni degli utenti della tua istanza. Non vengono mostrate le note pubbl
## Sociale
Raggruppa le timeline "home" e "locale".
## グローバル
## Federata
Tutte le pubblicazioni ricevute dall'istanza, sia locali che altre. Non vengono mostrate le note pubblicate con lo stato "home".

View File

@ -27,4 +27,8 @@ export const kinds = [
'write:user-groups',
'read:channels',
'write:channels',
'read:gallery',
'write:gallery',
'read:gallery-likes',
'write:gallery-likes',
];

53
src/models/entities/ad.ts Normal file
View File

@ -0,0 +1,53 @@
import { Entity, Index, Column, PrimaryColumn } from 'typeorm';
import { id } from '../id';
@Entity()
export class Ad {
@PrimaryColumn(id())
public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Ad.'
})
public createdAt: Date;
@Index()
@Column('timestamp with time zone', {
comment: 'The expired date of the Ad.'
})
public expiresAt: Date;
@Column('varchar', {
length: 32, nullable: false
})
public place: string;
@Column('varchar', {
length: 32, nullable: false
})
public priority: string;
@Column('varchar', {
length: 1024, nullable: false
})
public url: string;
@Column('varchar', {
length: 1024, nullable: false
})
public imageUrl: string;
@Column('varchar', {
length: 8192, nullable: false
})
public memo: string;
constructor(data: Partial<Ad>) {
if (data == null) return;
for (const [k, v] of Object.entries(data)) {
(this as any)[k] = v;
}
}
}

View File

@ -0,0 +1,33 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
import { User } from './user';
import { id } from '../id';
import { GalleryPost } from './gallery-post';
@Entity()
@Index(['userId', 'postId'], { unique: true })
export class GalleryLike {
@PrimaryColumn(id())
public id: string;
@Column('timestamp with time zone')
public createdAt: Date;
@Index()
@Column(id())
public userId: User['id'];
@ManyToOne(type => User, {
onDelete: 'CASCADE'
})
@JoinColumn()
public user: User | null;
@Column(id())
public postId: GalleryPost['id'];
@ManyToOne(type => GalleryPost, {
onDelete: 'CASCADE'
})
@JoinColumn()
public post: GalleryPost | null;
}

View File

@ -0,0 +1,79 @@
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
import { User } from './user';
import { id } from '../id';
import { DriveFile } from './drive-file';
@Entity()
export class GalleryPost {
@PrimaryColumn(id())
public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the GalleryPost.'
})
public createdAt: Date;
@Index()
@Column('timestamp with time zone', {
comment: 'The updated date of the GalleryPost.'
})
public updatedAt: Date;
@Column('varchar', {
length: 256,
})
public title: string;
@Column('varchar', {
length: 2048, nullable: true
})
public description: string | null;
@Index()
@Column({
...id(),
comment: 'The ID of author.'
})
public userId: User['id'];
@ManyToOne(type => User, {
onDelete: 'CASCADE'
})
@JoinColumn()
public user: User | null;
@Index()
@Column({
...id(),
array: true, default: '{}'
})
public fileIds: DriveFile['id'][];
@Index()
@Column('boolean', {
default: false,
comment: 'Whether the post is sensitive.'
})
public isSensitive: boolean;
@Index()
@Column('integer', {
default: 0
})
public likedCount: number;
@Index()
@Column('varchar', {
length: 128, array: true, default: '{}'
})
public tags: string[];
constructor(data: Partial<GalleryPost>) {
if (data == null) return;
for (const [k, v] of Object.entries(data)) {
(this as any)[k] = v;
}
}
}

View File

@ -0,0 +1,30 @@
import { PrimaryColumn, Entity, Index, Column, ManyToOne, JoinColumn } from 'typeorm';
import { id } from '../id';
import { User } from './user';
@Entity()
export class PasswordResetRequest {
@PrimaryColumn(id())
public id: string;
@Column('timestamp with time zone')
public createdAt: Date;
@Index({ unique: true })
@Column('varchar', {
length: 256,
})
public token: string;
@Index()
@Column({
...id(),
})
public userId: User['id'];
@ManyToOne(type => User, {
onDelete: 'CASCADE'
})
@JoinColumn()
public user: User | null;
}

View File

@ -43,6 +43,8 @@ import { UserSecurityKey } from './entities/user-security-key';
import { HashtagRepository } from './repositories/hashtag';
import { PageRepository } from './repositories/page';
import { PageLikeRepository } from './repositories/page-like';
import { GalleryPostRepository } from './repositories/gallery-post';
import { GalleryLikeRepository } from './repositories/gallery-like';
import { ModerationLogRepository } from './repositories/moderation-logs';
import { UsedUsername } from './entities/used-username';
import { ClipRepository } from './repositories/clip';
@ -58,6 +60,8 @@ import { MutedNote } from './entities/muted-note';
import { ChannelFollowing } from './entities/channel-following';
import { ChannelNotePining } from './entities/channel-note-pining';
import { RegistryItem } from './entities/registry-item';
import { Ad } from './entities/ad';
import { PasswordResetRequest } from './entities/password-reset-request';
export const Announcements = getRepository(Announcement);
export const AnnouncementReads = getRepository(AnnouncementRead);
@ -105,6 +109,8 @@ export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository);
export const Logs = getRepository(Log);
export const Pages = getCustomRepository(PageRepository);
export const PageLikes = getCustomRepository(PageLikeRepository);
export const GalleryPosts = getCustomRepository(GalleryPostRepository);
export const GalleryLikes = getCustomRepository(GalleryLikeRepository);
export const ModerationLogs = getCustomRepository(ModerationLogRepository);
export const Clips = getCustomRepository(ClipRepository);
export const ClipNotes = getRepository(ClipNote);
@ -118,3 +124,5 @@ export const Channels = getCustomRepository(ChannelRepository);
export const ChannelFollowings = getRepository(ChannelFollowing);
export const ChannelNotePinings = getRepository(ChannelNotePining);
export const RegistryItems = getRepository(RegistryItem);
export const Ads = getRepository(Ad);
export const PasswordResetRequests = getRepository(PasswordResetRequest);

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