mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-07-31 04:15:51 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67ca3d7e71 | |||
| 2ac2e9e849 | |||
| 746269c4b1 | |||
| c059256bd6 | |||
| 2e17979abc | |||
| c2d95ebdcb | |||
| cb5de83bad | |||
| 30d87d5532 | |||
| 5c212c996a | |||
| 39e01b1dfe | |||
| fd2fe34270 | |||
| 73bcd330f7 | |||
| 23d2d191a0 | |||
| ca1bf21dcf | |||
| 1ffc53f596 | |||
| 4e38f218ec | |||
| a0d34940ff | |||
| bdddd623b6 | |||
| 29bfc9a91a | |||
| 2e596607f8 | |||
| cf89280fc5 | |||
| c0f4c47c53 | |||
| 58995e6b97 | |||
| d00ca499a3 | |||
| ec1120bdaa | |||
| 3a65728fb4 | |||
| e4c03b9f4e | |||
| b82533c4b8 | |||
| ef1cdca6f9 | |||
| 46d30f454b | |||
| b300b5b94a | |||
| 39d6aecc57 | |||
| edbe30a3df | |||
| ad4751918b | |||
| bd9041bd8f | |||
| 4dcff123df | |||
| 990be44d98 | |||
| 78d65ef3dd | |||
| 0a67d6f1a0 | |||
| e312283ea0 | |||
| e8c78e12d5 |
@@ -96,6 +96,7 @@ jobs:
|
||||
matrix:
|
||||
workspace:
|
||||
- backend
|
||||
- frontend
|
||||
- sw
|
||||
- misskey-js
|
||||
steps:
|
||||
@@ -111,7 +112,9 @@ jobs:
|
||||
cache: 'pnpm'
|
||||
- run: pnpm i --frozen-lockfile
|
||||
- run: pnpm --filter misskey-js run build
|
||||
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }}
|
||||
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'frontend' || matrix.workspace == 'sw' }}
|
||||
- run: pnpm --filter misskey-reversi run build
|
||||
if: ${{ matrix.workspace == 'backend' }}
|
||||
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'frontend' }}
|
||||
- run: pnpm --filter misskey-bubble-game run build
|
||||
if: ${{ matrix.workspace == 'frontend' }}
|
||||
- run: pnpm --filter ${{ matrix.workspace }} run typecheck
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
- チャンネルの概要画面の右上からミュートできます(リンクコピー、共有、設定と同列)
|
||||
- Enhance: Node.js 24.10.0をサポートするようになりました
|
||||
- Enhance: DockerのNode.jsが24.10.0に更新されました
|
||||
- 依存関係の更新
|
||||
|
||||
### Client
|
||||
- Feat: 画像にメタデータを含むフレームをつけられる機能
|
||||
@@ -13,12 +14,18 @@
|
||||
- Enhance: プロフィールへのリンクをユーザーポップアップのアバターに追加
|
||||
- Enhance: ユーザーのノート、フォロー、フォロワーページへのリンクをユーザーポップアップに追加
|
||||
- Enhance: プッシュ通知を行うための権限確認をより確実に行うように
|
||||
- Enhance: 投稿フォームのチュートリアルを追加
|
||||
- Enhance: 「自動でもっと見る」をほとんどの箇所で利用可能に
|
||||
- Enhance: アンテナ・リスト設定画面とタイムラインの動線を改善
|
||||
- アンテナ・リスト一覧画面の項目を選択すると、設定画面ではなくタイムラインに移動するようになりました
|
||||
- アンテナ・リストの設定画面の右上にタイムラインに移動するボタンを追加しました
|
||||
- Fix: 紙吹雪エフェクトがアニメーション設定を考慮せず常に表示される問題を修正
|
||||
- Fix: ナビゲーションバーのリアルタイムモード切替ボタンの状態をよりわかりやすく表示するように
|
||||
- Fix: ページのタイトルが長いとき、はみ出る問題を修正
|
||||
|
||||
### Server
|
||||
- Enhance: Remote Notes Cleaningが複雑度が高いノートの処理を中断せずに次のノートから再開するように
|
||||
- Fix: チャンネルの説明欄の最小文字数制約を除去
|
||||
|
||||
## 2025.10.2
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ Also, the later tasks are more indefinite and are subject to change as developme
|
||||
This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development.
|
||||
|
||||
- ~~Make the number of type errors zero (backend)~~ → Done ✔️
|
||||
- Make the number of type errors zero (frontend)
|
||||
- ~~Make the number of type errors zero (frontend)~~ → Done ✔️
|
||||
- Improve CI
|
||||
- ~~Fix tests~~ → Done ✔️
|
||||
- Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986
|
||||
|
||||
@@ -1011,6 +1011,14 @@ information: "عن"
|
||||
inMinutes: "د"
|
||||
inDays: "ي"
|
||||
widgets: "التطبيقات المُصغّرة"
|
||||
presets: "إعدادات مسبقة"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "اسم الملف"
|
||||
_imageFrameEditor:
|
||||
font: "الخط"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "دعوة"
|
||||
noHistory: "السجل فارغ"
|
||||
@@ -1397,6 +1405,9 @@ _postForm:
|
||||
replyPlaceholder: "رد على هذه الملاحظة…"
|
||||
quotePlaceholder: "اقتبس هذه الملاحظة…"
|
||||
channelPlaceholder: "انشر في قناة..."
|
||||
_howToUse:
|
||||
visibility_title: "الظهور"
|
||||
menu_title: "القائمة"
|
||||
_placeholders:
|
||||
a: "ما الذي تنوي فعله؟"
|
||||
b: "ماذا يحدث حولك ؟"
|
||||
|
||||
@@ -851,6 +851,14 @@ information: "আপনার সম্পর্কে"
|
||||
inMinutes: "মিনিট"
|
||||
inDays: "দিন"
|
||||
widgets: "উইজেটগুলি"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "ফাইলের নাম"
|
||||
_imageFrameEditor:
|
||||
header: "হেডার"
|
||||
font: "ফন্ট"
|
||||
fontSerif: "সেরিফ"
|
||||
fontSansSerif: "স্যান্স সেরিফ"
|
||||
_chat:
|
||||
invitations: "আমন্ত্রণ"
|
||||
noHistory: "কোনো ইতিহাস নেই"
|
||||
@@ -1169,6 +1177,9 @@ _postForm:
|
||||
replyPlaceholder: "নোটটির জবাব দিন..."
|
||||
quotePlaceholder: "নোটটিকে উদ্ধৃত করুন..."
|
||||
channelPlaceholder: "চ্যানেলে পোস্ট করুন..."
|
||||
_howToUse:
|
||||
visibility_title: "দৃশ্যমানতা"
|
||||
menu_title: "মেনু"
|
||||
_placeholders:
|
||||
a: "আপনি এখন কি করছেন?"
|
||||
b: "আপনার আশে পাশে কি হচ্ছে?"
|
||||
|
||||
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot trigar un temps"
|
||||
uploadNFiles: "Pujar {n} arxius"
|
||||
explore: "Explora"
|
||||
messageRead: "Vist"
|
||||
readAllChatMessages: "Marcar tots els missatges com a llegits"
|
||||
noMoreHistory: "No hi ha res més per veure"
|
||||
startChat: "Comença a xatejar "
|
||||
nUsersRead: "Vist per {n}"
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "L'enviament de notificacions ja és activat"
|
||||
pushNotificationNotSupported: "El teu navegador o la teva instància no suporta l'enviament de notificacions "
|
||||
sendPushNotificationReadMessage: "Esborrar les notificacions enviades quan s'hagin llegit"
|
||||
sendPushNotificationReadMessageCaption: "Això pot fer que el teu dispositiu consumeixi més bateria"
|
||||
pleaseAllowPushNotification: "Si us plau, permet les notificacions del navegador"
|
||||
browserPushNotificationDisabled: "No s'ha pogut obtenir permisos per les notificacions"
|
||||
browserPushNotificationDisabledDescription: "No tens permisos per enviar notificacions des de {serverName}. Activa les notificacions a la configuració del teu navegador i tornar-ho a intentar."
|
||||
windowMaximize: "Maximitzar "
|
||||
windowMinimize: "Minimitzar"
|
||||
windowRestore: "Restaurar"
|
||||
@@ -1396,6 +1400,50 @@ scheduled: "Programat"
|
||||
widgets: "Ginys"
|
||||
deviceInfo: "Informació del dispositiu"
|
||||
deviceInfoDescription: "En fer consultes tècniques influir la següent informació pot ajudar a resoldre'l més ràpidament."
|
||||
youAreAdmin: "Ets l'administrador "
|
||||
frame: "Marc"
|
||||
presets: "Predefinit"
|
||||
zeroPadding: "Sense omplir"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "Títol de l'arxiu"
|
||||
filename: "Nom del Fitxer"
|
||||
filename_without_ext: "Nom de l'arxiu sense extensió "
|
||||
year: "Any"
|
||||
month: "Mes"
|
||||
day: "Dia"
|
||||
hour: "Hora"
|
||||
minute: "Minut"
|
||||
second: "Segon"
|
||||
camera_model: "Nom de la càmera "
|
||||
camera_lens_model: "Nom de la lent"
|
||||
camera_mm: "Distància focal"
|
||||
camera_mm_35: "Distància focal (equivalent a 35 mm)"
|
||||
camera_f: "Obertura"
|
||||
camera_s: "Velocitat d'obturació"
|
||||
camera_iso: "Sensibilitat ISO"
|
||||
gps_lat: "Latitud "
|
||||
gps_long: "Longitud "
|
||||
_imageFrameEditor:
|
||||
title: "Edició de fotogrames "
|
||||
tip: "Pots decorar les imatges afegint etiquetes que continguin marcs i metadades."
|
||||
header: "Capçalera"
|
||||
footer: "Peu de pàgina "
|
||||
borderThickness: "Amplada de la vora"
|
||||
labelThickness: "Amplada de l'etiqueta "
|
||||
labelScale: "Mida de l'etiqueta "
|
||||
centered: "Alinea al centre"
|
||||
captionMain: "Peu de foto (gran)"
|
||||
captionSub: "Peu de foto (petit)"
|
||||
availableVariables: "Variables disponibles"
|
||||
withQrCode: "Codi QR"
|
||||
backgroundColor: "Color del fons"
|
||||
textColor: "Color del text"
|
||||
font: "Lletra tipogràfica"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "Sortir sense desar?"
|
||||
failedToLoadImage: "Error en carregar la imatge"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Qualitat alta"
|
||||
@@ -1498,6 +1546,8 @@ _settings:
|
||||
showUrlPreview: "Mostrar vista prèvia d'URL"
|
||||
showAvailableReactionsFirstInNote: "Mostra les reacciones que pots fer servir al damunt"
|
||||
showPageTabBarBottom: "Mostrar les pestanyes de les línies de temps a la part inferior"
|
||||
emojiPaletteBanner: "Pots registrar ajustos preestablerts com paletes perquè es mostrin permanentment al selector d'emojis, o personalitzar la configuració de visió del selector."
|
||||
enableAnimatedImages: "Activar imatges animades"
|
||||
_chat:
|
||||
showSenderName: "Mostrar el nom del remitent"
|
||||
sendOnEnter: "Introdueix per enviar"
|
||||
@@ -1515,6 +1565,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "Has de posar-li un nom al teu perfil per poder activar les còpies de seguretat automàtiques."
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "La còpia de seguretat automàtica no es troba activada en aquest dispositiu."
|
||||
backupFound: "Còpia de seguretat de la configuració trobada"
|
||||
forceBackup: "Còpia de seguretat forçada de la configuració "
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut"
|
||||
requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació."
|
||||
@@ -2530,6 +2581,20 @@ _postForm:
|
||||
replyPlaceholder: "Contestar..."
|
||||
quotePlaceholder: "Citar..."
|
||||
channelPlaceholder: "Publicar a un canal..."
|
||||
showHowToUse: "Mostrar les instruccions"
|
||||
_howToUse:
|
||||
content_title: "Cos principal"
|
||||
content_description: "Introdueix el contingut que vols publicar."
|
||||
toolbar_title: "Barra d'eines "
|
||||
toolbar_description: "Pots adjuntar arxius o enquestes, afegir anotacions o etiquetes i inserir emojis o mencions."
|
||||
account_title: "Menú del compte"
|
||||
account_description: "Pots anar canviant de comptes per publicar o veure una llista d'esborranys i les publicacions programades del teu compte."
|
||||
visibility_title: "Visibilitat"
|
||||
visibility_description: "Pots configurar la visibilitat de les teves notes."
|
||||
menu_title: "Menú"
|
||||
menu_description: "Pots fer altres accions com desar esborranys, programar publicacions i configurar reaccions."
|
||||
submit_title: "Botó per publicar"
|
||||
submit_description: "Publica les teves notes. També pots fer servir Ctrl + Enter / Cmd + Enter"
|
||||
_placeholders:
|
||||
a: "Que vols dir?..."
|
||||
b: "Alguna cosa interessant al teu voltant?..."
|
||||
@@ -2807,6 +2872,8 @@ _abuseReport:
|
||||
notifiedWebhook: "Webhook que s'ha de fer servir"
|
||||
deleteConfirm: "Segur que vols esborrar el destinatari de l'informe de moderació?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "Esborra la cua de feina"
|
||||
promoteQueue: "Tornar a intentar la feina de la cua"
|
||||
createRole: "Rol creat"
|
||||
deleteRole: "Rol esborrat"
|
||||
updateRole: "Rol actualitzat"
|
||||
@@ -3223,11 +3290,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "Mida del lunar secundari"
|
||||
polkadotSubDotDivisions: "Nombre de punts secundaris"
|
||||
leaveBlankToAccountUrl: "Si deixes aquest camp buit, es farà servir l'URL del teu compte"
|
||||
failedToLoadImage: "Error en carregar la imatge"
|
||||
_imageEffector:
|
||||
title: "Efecte"
|
||||
addEffect: "Afegeix un efecte"
|
||||
discardChangesConfirm: "Vols descartar els canvis i sortir?"
|
||||
nothingToConfigure: "No hi ha opcions de configuració disponibles"
|
||||
failedToLoadImage: "Error en carregar la imatge"
|
||||
_fxs:
|
||||
chromaticAberration: "Aberració cromàtica"
|
||||
glitch: "Glitch"
|
||||
|
||||
@@ -1110,6 +1110,15 @@ information: "Informace"
|
||||
inMinutes: "Minut"
|
||||
inDays: "Dnů"
|
||||
widgets: "Widgety"
|
||||
presets: "Předvolba"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Název souboru"
|
||||
_imageFrameEditor:
|
||||
header: "Nadpis"
|
||||
font: "Písmo"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "Pozvat"
|
||||
noHistory: "Žádná historie"
|
||||
@@ -1822,6 +1831,9 @@ _postForm:
|
||||
replyPlaceholder: "Odpovědět na tuto poznámku..."
|
||||
quotePlaceholder: "Citovat tuto poznámku..."
|
||||
channelPlaceholder: "Zveřejnit příspěvek do kanálu..."
|
||||
_howToUse:
|
||||
visibility_title: "Viditelnost"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Co máte v plánu?"
|
||||
b: "Co se děje kolem vás?"
|
||||
|
||||
@@ -1371,6 +1371,16 @@ defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bild
|
||||
inMinutes: "Minute(n)"
|
||||
inDays: "Tag(en)"
|
||||
widgets: "Widgets"
|
||||
presets: "Vorlage"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Dateiname"
|
||||
_imageFrameEditor:
|
||||
header: "Kopfzeile"
|
||||
font: "Schriftart"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "Nicht gespeicherte Änderungen verwerfen?"
|
||||
_order:
|
||||
newest: "Neueste zuerst"
|
||||
oldest: "Älteste zuerst"
|
||||
@@ -2480,6 +2490,9 @@ _postForm:
|
||||
replyPlaceholder: "Dieser Notiz antworten …"
|
||||
quotePlaceholder: "Diese Notiz zitieren …"
|
||||
channelPlaceholder: "In einen Kanal senden"
|
||||
_howToUse:
|
||||
visibility_title: "Sichtbarkeit"
|
||||
menu_title: "Menü"
|
||||
_placeholders:
|
||||
a: "Was machst du momentan?"
|
||||
b: "Was ist um dich herum los?"
|
||||
|
||||
@@ -289,6 +289,9 @@ renotes: "Κοινοποίηση σημειώματος"
|
||||
postForm: "Φόρμα δημοσίευσης"
|
||||
information: "Πληροφορίες"
|
||||
widgets: "Μαραφέτια"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Όνομα αρχείου"
|
||||
_chat:
|
||||
members: "Μέλη"
|
||||
home: "Κεντρικό"
|
||||
|
||||
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "It may take some time until the upload is complete."
|
||||
uploadNFiles: "Upload {n} files"
|
||||
explore: "Explore"
|
||||
messageRead: "Read"
|
||||
readAllChatMessages: "Mark all messages as read"
|
||||
noMoreHistory: "There is no further history"
|
||||
startChat: "Start chat"
|
||||
nUsersRead: "read by {n}"
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "Push notifications are already enabled"
|
||||
pushNotificationNotSupported: "Your browser or instance does not support push notifications"
|
||||
sendPushNotificationReadMessage: "Delete push notifications once they have been read"
|
||||
sendPushNotificationReadMessageCaption: "This may increase the power consumption of your device."
|
||||
pleaseAllowPushNotification: "Please enable push notifications in your browser"
|
||||
browserPushNotificationDisabled: "Failed to acquire permission to send notifications"
|
||||
browserPushNotificationDisabledDescription: "You do not have permission to send notifications from {serverName}. Please allow notifications in your browser settings and try again."
|
||||
windowMaximize: "Maximize"
|
||||
windowMinimize: "Minimize"
|
||||
windowRestore: "Restore"
|
||||
@@ -1396,6 +1400,50 @@ scheduled: "Scheduled"
|
||||
widgets: "Widgets"
|
||||
deviceInfo: "Device information"
|
||||
deviceInfoDescription: "When making technical inquiries, including the following information may help resolve the issue."
|
||||
youAreAdmin: "You are admin"
|
||||
frame: "Frame"
|
||||
presets: "Preset"
|
||||
zeroPadding: "Zero padding"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "File caption"
|
||||
filename: "Filename"
|
||||
filename_without_ext: "Filename without extension"
|
||||
year: "Year of photography"
|
||||
month: "Month of photogrphy"
|
||||
day: "Date of photography"
|
||||
hour: "Time the photo was taken (hour)"
|
||||
minute: "Time the photo was taken (minute)"
|
||||
second: "Time the photo was taken (second)"
|
||||
camera_model: "Camera Name"
|
||||
camera_lens_model: "Lens model"
|
||||
camera_mm: "Focal length"
|
||||
camera_mm_35: "Focal length (in 35 mm format)"
|
||||
camera_f: "Aperture (f-number)"
|
||||
camera_s: "Shutter speed"
|
||||
camera_iso: "ISO"
|
||||
gps_lat: "Latitude"
|
||||
gps_long: "Longitude"
|
||||
_imageFrameEditor:
|
||||
title: "Edit frame"
|
||||
tip: "You can decorate images by adding labels that include frames and metadata."
|
||||
header: "Header"
|
||||
footer: "Footer"
|
||||
borderThickness: "Frame width"
|
||||
labelThickness: "Label width"
|
||||
labelScale: "Label scale"
|
||||
centered: "Centered"
|
||||
captionMain: "Caption (Big)"
|
||||
captionSub: "Caption (Small)"
|
||||
availableVariables: "Supported variables"
|
||||
withQrCode: "QR Code"
|
||||
backgroundColor: "Background color"
|
||||
textColor: "Text color"
|
||||
font: "Font"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "Discard unsaved changes?"
|
||||
failedToLoadImage: "Failed to load image"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "High quality"
|
||||
@@ -1498,6 +1546,8 @@ _settings:
|
||||
showUrlPreview: "Show URL preview"
|
||||
showAvailableReactionsFirstInNote: "Show available reactions at the top."
|
||||
showPageTabBarBottom: "Show page tab bar at the bottom"
|
||||
emojiPaletteBanner: "You can register presets as palettes to display prominently in the emoji picker or customize the appearance of the picker."
|
||||
enableAnimatedImages: "Enable animated images"
|
||||
_chat:
|
||||
showSenderName: "Show sender's name"
|
||||
sendOnEnter: "Press Enter to send"
|
||||
@@ -1515,6 +1565,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "A profile name must be set to enable auto backup."
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "Settings auto backup is not enabled on this device."
|
||||
backupFound: "Settings backup is found"
|
||||
forceBackup: "Force a backup of settings"
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "Require sign-in to view contents"
|
||||
requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information."
|
||||
@@ -2530,6 +2581,20 @@ _postForm:
|
||||
replyPlaceholder: "Reply to this note..."
|
||||
quotePlaceholder: "Quote this note..."
|
||||
channelPlaceholder: "Post to a channel..."
|
||||
showHowToUse: "Show how to use this form"
|
||||
_howToUse:
|
||||
content_title: "Body"
|
||||
content_description: "Enter the content you wish to post here."
|
||||
toolbar_title: "Toolbars"
|
||||
toolbar_description: "You can attach files or poll, add annotations or hashtags, and insert emojis or mentions."
|
||||
account_title: "Account menu"
|
||||
account_description: "You can switch between accounts for posting, or view a list of drafts and scheduled posts saved to your account."
|
||||
visibility_title: "Visibility"
|
||||
visibility_description: "You can configure the visibility of your notes."
|
||||
menu_title: "Menu"
|
||||
menu_description: "You can save current content to drafts, schedule posts, set reactions, and perform other actions."
|
||||
submit_title: "Post button"
|
||||
submit_description: "Post your notes by pressing this button. You can also post using Ctrl + Enter / Cmd + Enter."
|
||||
_placeholders:
|
||||
a: "What are you up to?"
|
||||
b: "What's happening around you?"
|
||||
@@ -2807,6 +2872,8 @@ _abuseReport:
|
||||
notifiedWebhook: "Webhook to use"
|
||||
deleteConfirm: "Are you sure that you want to delete the notification recipient?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "Clear queue"
|
||||
promoteQueue: "Promote queue"
|
||||
createRole: "Role created"
|
||||
deleteRole: "Role deleted"
|
||||
updateRole: "Role updated"
|
||||
@@ -3223,11 +3290,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "Size of the secondary dot"
|
||||
polkadotSubDotDivisions: "Number of sub-dots."
|
||||
leaveBlankToAccountUrl: "Leave blank to use account URL"
|
||||
failedToLoadImage: "Failed to load image"
|
||||
_imageEffector:
|
||||
title: "Effects"
|
||||
addEffect: "Add Effects"
|
||||
discardChangesConfirm: "Are you sure you want to leave? You have unsaved changes."
|
||||
nothingToConfigure: "No configurable options available"
|
||||
failedToLoadImage: "Failed to load image"
|
||||
_fxs:
|
||||
chromaticAberration: "Chromatic Aberration"
|
||||
glitch: "Glitch"
|
||||
|
||||
+81
-13
@@ -87,7 +87,7 @@ exportRequested: "Has solicitado la exportación. Puede llevar un tiempo. Cuando
|
||||
importRequested: "Has solicitado la importación. Puede llevar un tiempo."
|
||||
lists: "Listas"
|
||||
noLists: "No tienes ninguna lista"
|
||||
note: "Notas"
|
||||
note: "Nota"
|
||||
notes: "Notas"
|
||||
following: "Siguiendo"
|
||||
followers: "Seguidores"
|
||||
@@ -129,7 +129,7 @@ clickToShow: "Haz clic para verlo"
|
||||
sensitive: "Marcado como sensible"
|
||||
add: "Agregar"
|
||||
reaction: "Reacción"
|
||||
reactions: "Reacción"
|
||||
reactions: "Reacciones"
|
||||
emojiPicker: "Selector de emojis"
|
||||
pinnedEmojisForReactionSettingDescription: "Puedes seleccionar reacciones para fijarlos en el selector"
|
||||
pinnedEmojisSettingDescription: "Puedes seleccionar emojis para fijarlos en el selector"
|
||||
@@ -251,7 +251,7 @@ noUsers: "No hay usuarios"
|
||||
editProfile: "Editar perfil"
|
||||
noteDeleteConfirm: "¿Quieres borrar esta nota?"
|
||||
pinLimitExceeded: "Ya no se pueden fijar más notas"
|
||||
done: "Terminado"
|
||||
done: "Hecho"
|
||||
processing: "Procesando..."
|
||||
preprocessing: "Preparando"
|
||||
preview: "Vista previa"
|
||||
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "Subir el fichero puede tardar un tiempo."
|
||||
uploadNFiles: "Subir {n} archivos"
|
||||
explore: "Explorar"
|
||||
messageRead: "Ya leído"
|
||||
readAllChatMessages: "Marcar todos los mensajes como leídos"
|
||||
noMoreHistory: "El historial se ha acabado"
|
||||
startChat: "Nuevo Chat"
|
||||
nUsersRead: "Leído por {n} personas"
|
||||
@@ -915,7 +916,7 @@ lastCommunication: "Última comunicación"
|
||||
resolved: "Resuelto"
|
||||
unresolved: "Sin resolver"
|
||||
breakFollow: "Eliminar seguidor"
|
||||
breakFollowConfirm: "¿Quieres dejar de seguir?"
|
||||
breakFollowConfirm: "¿De verdad quieres eliminar a este seguidor?"
|
||||
itsOn: "¡Está encendido!"
|
||||
itsOff: "¡Está apagado!"
|
||||
on: "Activado"
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "Notificaciones emergentes ya activadas"
|
||||
pushNotificationNotSupported: "El navegador o la instancia no admiten notificaciones push"
|
||||
sendPushNotificationReadMessage: "Eliminar las notificaciones push después de leer las notificaciones y los mensajes"
|
||||
sendPushNotificationReadMessageCaption: "La notificación \"{emptyPushNotificationMessage}\" aparecerá momentáneamente. Esto puede aumentar el consumo de batería del dispositivo."
|
||||
pleaseAllowPushNotification: "Por favor, permita las notificaciones y la configuración del navegador."
|
||||
browserPushNotificationDisabled: "No se ha podido obtener permiso para enviar notificaciones."
|
||||
browserPushNotificationDisabledDescription: "No tienes permiso para enviar notificaciones desde {serverName}. Permite las notificaciones en la configuración de tu navegador y vuelve a intentarlo."
|
||||
windowMaximize: "Maximizar"
|
||||
windowMinimize: "Minimizar"
|
||||
windowRestore: "Regresar"
|
||||
@@ -1153,7 +1157,7 @@ initialAccountSetting: "Configración inicial de su cuenta"
|
||||
youFollowing: "Siguiendo"
|
||||
preventAiLearning: "Rechazar el uso en el Aprendizaje de Máquinas. (IA Generativa)"
|
||||
preventAiLearningDescription: "Pedirle a las arañas (crawlers) no usar los textos publicados o imágenes en el aprendizaje automático (IA Predictiva / Generativa). Ésto se logra añadiendo una marca respuesta HTML con la cadena \"noai\" al cantenido. Una prevención total no podría lograrse sólo usando ésta marca, ya que puede ser simplemente ignorada."
|
||||
options: "Opción"
|
||||
options: "Opciones"
|
||||
specifyUser: "Especificar usuario"
|
||||
lookupConfirm: "¿Quiere informarse?"
|
||||
openTagPageConfirm: "¿Quieres abrir la página de etiquetas?"
|
||||
@@ -1263,7 +1267,7 @@ addMfmFunction: "Añadir función MFM"
|
||||
enableQuickAddMfmFunction: "Activar acceso rápido para añadir funciones MFM"
|
||||
bubbleGame: "Bubble Game"
|
||||
sfx: "Efectos de sonido"
|
||||
soundWillBePlayed: "Se reproducirán efectos sonoros"
|
||||
soundWillBePlayed: "Con música y efectos sonoros"
|
||||
showReplay: "Ver reproducción"
|
||||
replay: "Reproducir"
|
||||
replaying: "Reproduciendo"
|
||||
@@ -1390,12 +1394,56 @@ thankYouForTestingBeta: "¡Gracias por tu colaboración en la prueba de la versi
|
||||
createUserSpecifiedNote: "Mencionar al usuario (Nota Directa)"
|
||||
schedulePost: "Programar una nota"
|
||||
scheduleToPostOnX: "Programar una nota para {x}"
|
||||
scheduledToPostOnX: "La nota está programada para {x}."
|
||||
schedule: "Programado"
|
||||
scheduledToPostOnX: "La nota está programada para el {x}."
|
||||
schedule: "Programar"
|
||||
scheduled: "Programado"
|
||||
widgets: "Widgets"
|
||||
deviceInfo: "Información del dispositivo"
|
||||
deviceInfoDescription: "Al realizar consultas técnicas, incluir la siguiente información puede ayudar a resolver el problema."
|
||||
youAreAdmin: "Eres administrador."
|
||||
frame: "Marco"
|
||||
presets: "Predefinido"
|
||||
zeroPadding: "Relleno cero"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "Título del archivo"
|
||||
filename: "Nombre de archivo"
|
||||
filename_without_ext: "Nombre del archivo sin la extensión"
|
||||
year: "Año de rodaje"
|
||||
month: "Mes de rodaje"
|
||||
day: "Día de rodaje"
|
||||
hour: "Hora"
|
||||
minute: "Minuto"
|
||||
second: "Segundo"
|
||||
camera_model: "Nombre de la cámara"
|
||||
camera_lens_model: "Modelo de lente"
|
||||
camera_mm: "Distancia focal"
|
||||
camera_mm_35: "Distancia Focal (Equivalente a formato de 35mm)"
|
||||
camera_f: "Apertura de diafragma"
|
||||
camera_s: "Velocidad de Obturación"
|
||||
camera_iso: "Sensibilidad ISO"
|
||||
gps_lat: "Latitud"
|
||||
gps_long: "Longitud"
|
||||
_imageFrameEditor:
|
||||
title: "Edición de Fotograma"
|
||||
tip: "Decora tus imágenes con marcos y etiquetas que contengan metadatos."
|
||||
header: "Cabezal"
|
||||
footer: "Pie de página"
|
||||
borderThickness: "Ancho del borde"
|
||||
labelThickness: "Ancho de la etiqueta"
|
||||
labelScale: "Escala de la Etiqueta"
|
||||
centered: "Alinear al centro"
|
||||
captionMain: "Pie de foto (Grande)"
|
||||
captionSub: "Pie de foto (Pequeño)"
|
||||
availableVariables: "Variables disponibles"
|
||||
withQrCode: "Código QR"
|
||||
backgroundColor: "Color de fondo"
|
||||
textColor: "Color del texto"
|
||||
font: "Fuente"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "¿Descartar cambios no guardados?"
|
||||
failedToLoadImage: "Error al cargar la imagen"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Calidad alta"
|
||||
@@ -1498,6 +1546,7 @@ _settings:
|
||||
showUrlPreview: "Mostrar la vista previa de la URL"
|
||||
showAvailableReactionsFirstInNote: "Mostrar las reacciones disponibles en la parte superior."
|
||||
showPageTabBarBottom: "Mostrar la barra de pestañas de la página en la parte inferior."
|
||||
emojiPaletteBanner: "Puedes registrar ajustes preestablecidos como paletas para que se muestren permanentemente en el selector de emojis, o personalizar el método de visualización del selector."
|
||||
_chat:
|
||||
showSenderName: "Mostrar el nombre del remitente"
|
||||
sendOnEnter: "Intro para enviar"
|
||||
@@ -1515,6 +1564,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "Se debe establecer un nombre de perfil para activar la copia de seguridad automática."
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "La copia de seguridad automática de los ajustes no está activada en este dispositivo."
|
||||
backupFound: "Copia de seguridad de los ajustes encontrada "
|
||||
forceBackup: "Forzar una copia de seguridad de la configuración"
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "Se requiere iniciar sesión para ver el contenido"
|
||||
requireSigninToViewContentsDescription1: "Requiere iniciar sesión para ver todas las notas y otros contenidos que hayas creado. Se espera que esto evite que los rastreadores recopilen información."
|
||||
@@ -1552,7 +1602,7 @@ _bubbleGame:
|
||||
score: "Puntos"
|
||||
scoreYen: "Cantidad de dinero ganada"
|
||||
highScore: "Puntuación más alta"
|
||||
maxChain: "Número máximo de cadenas"
|
||||
maxChain: "Número máximo de combos"
|
||||
yen: "{yen} Yenes"
|
||||
estimatedQty: "{qty} Piezas"
|
||||
scoreSweets: "{onigiriQtyWithUnit} Onigiris"
|
||||
@@ -1986,7 +2036,7 @@ _role:
|
||||
isConditionalRole: "Esto es un rol condicional"
|
||||
isPublic: "Publicar rol"
|
||||
descriptionOfIsPublic: "Cualquiera puede ver los usuarios asignados a este rol. También, el perfil del usuario mostrará este rol."
|
||||
options: "Opción"
|
||||
options: "Opciones"
|
||||
policies: "Política"
|
||||
baseRole: "Rol base"
|
||||
useBaseValue: "Usar los valores del rol base"
|
||||
@@ -2470,7 +2520,7 @@ _widgets:
|
||||
digitalClock: "Reloj digital"
|
||||
unixClock: "Reloj UNIX"
|
||||
federation: "Federación"
|
||||
instanceCloud: "Nube de palabras de la instancia"
|
||||
instanceCloud: "Nube de Instancias Federadas"
|
||||
postForm: "Formulario"
|
||||
slideshow: "Diapositivas"
|
||||
button: "Botón"
|
||||
@@ -2530,6 +2580,20 @@ _postForm:
|
||||
replyPlaceholder: "Responder a esta nota"
|
||||
quotePlaceholder: "Citar esta nota"
|
||||
channelPlaceholder: "Publicar en el canal"
|
||||
showHowToUse: "Mostrar el tutorial de este formulario"
|
||||
_howToUse:
|
||||
content_title: "Cuerpo"
|
||||
content_description: "Introduce aquí el contenido que deseas publicar."
|
||||
toolbar_title: "Barras de herramientas"
|
||||
toolbar_description: "Puedes adjuntar archivos o realizar encuestas, añadir anotaciones o hashtags e insertar emojis o menciones."
|
||||
account_title: "Menú de la cuenta"
|
||||
account_description: "Puedes cambiar entre cuentas para publicar o ver una lista de borradores y publicaciones programadas guardadas en tu cuenta."
|
||||
visibility_title: "Visibilidad"
|
||||
visibility_description: "Puedes configurar la visibilidad de tus notas."
|
||||
menu_title: "Menú"
|
||||
menu_description: "Puedes realizar otras acciones, como guardar borradores, programar publicaciones y configurar reacciones."
|
||||
submit_title: "Botón de publicar"
|
||||
submit_description: "Publica tus notas pulsando este botón. También puedes publicar utilizando Ctrl + Intro / Cmd + Intro."
|
||||
_placeholders:
|
||||
a: "¿Qué haces?"
|
||||
b: "¿Te pasó algo?"
|
||||
@@ -2564,7 +2628,7 @@ _exportOrImport:
|
||||
userLists: "Listas"
|
||||
excludeMutingUsers: "Excluir usuarios silenciados"
|
||||
excludeInactiveUsers: "Excluir usuarios inactivos"
|
||||
withReplies: "Incluir respuestas de los usuarios importados en la línea de tiempo"
|
||||
withReplies: "Si el archivo no incluye información sobre si las respuestas deben incluirse en la línea de tiempo, las respuestas realizadas por el importador deben incluirse en la línea de tiempo."
|
||||
_charts:
|
||||
federation: "Federación"
|
||||
apRequest: "Pedidos"
|
||||
@@ -2807,6 +2871,8 @@ _abuseReport:
|
||||
notifiedWebhook: "Webhook a utilizar"
|
||||
deleteConfirm: "¿Estás seguro de que deseas borrar el destinatario del informe de moderación?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "Borrar la cola de trabajos"
|
||||
promoteQueue: "Reintentar el trabajo en la cola"
|
||||
createRole: "Rol creado"
|
||||
deleteRole: "Rol eliminado"
|
||||
updateRole: "Rol actualizado"
|
||||
@@ -2959,7 +3025,7 @@ _reversi:
|
||||
loopedMap: "Mapa en bucle"
|
||||
canPutEverywhere: "Las fichas se pueden poner a cualquier lugar\n"
|
||||
timeLimitForEachTurn: "Tiempo límite por jugada."
|
||||
freeMatch: "Partida libre."
|
||||
freeMatch: "Partida libre"
|
||||
lookingForPlayer: "Buscando oponente"
|
||||
gameCanceled: "La partida ha sido cancelada."
|
||||
shareToTlTheGameWhenStart: "Compartir la partida en la línea de tiempo cuando comience "
|
||||
@@ -3223,11 +3289,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "Tamaño del círculo secundario."
|
||||
polkadotSubDotDivisions: "Número de subpuntos."
|
||||
leaveBlankToAccountUrl: "Si dejas este campo en blanco, se utilizará la URL de tu cuenta."
|
||||
failedToLoadImage: "Error al cargar la imagen"
|
||||
_imageEffector:
|
||||
title: "Efecto"
|
||||
addEffect: "Añadir Efecto"
|
||||
discardChangesConfirm: "¿Ignorar cambios y salir?"
|
||||
nothingToConfigure: "No hay opciones configurables disponibles."
|
||||
failedToLoadImage: "Error al cargar la imagen"
|
||||
_fxs:
|
||||
chromaticAberration: "Aberración Cromática"
|
||||
glitch: "Glitch"
|
||||
|
||||
@@ -1274,6 +1274,15 @@ information: "Informations"
|
||||
inMinutes: "min"
|
||||
inDays: "j"
|
||||
widgets: "Widgets"
|
||||
presets: "Préréglage"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Nom du fichier"
|
||||
_imageFrameEditor:
|
||||
header: "Entête"
|
||||
font: "Police de caractères"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "Inviter"
|
||||
noHistory: "Pas d'historique"
|
||||
@@ -2037,6 +2046,9 @@ _postForm:
|
||||
replyPlaceholder: "Répondre à cette note ..."
|
||||
quotePlaceholder: "Citez cette note ..."
|
||||
channelPlaceholder: "Publier au canal…"
|
||||
_howToUse:
|
||||
visibility_title: "Visibilité"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Quoi de neuf ?"
|
||||
b: "Il s'est passé quelque chose ?"
|
||||
|
||||
@@ -1288,6 +1288,15 @@ advice: "Saran"
|
||||
inMinutes: "menit"
|
||||
inDays: "hari"
|
||||
widgets: "Widget"
|
||||
presets: "Prasetel"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Nama berkas"
|
||||
_imageFrameEditor:
|
||||
header: "Header"
|
||||
font: "Font"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans-serif"
|
||||
_chat:
|
||||
invitations: "Undang"
|
||||
history: "Riwayat obrolan"
|
||||
@@ -2240,6 +2249,9 @@ _postForm:
|
||||
replyPlaceholder: "Balas ke catatan ini..."
|
||||
quotePlaceholder: "Kutip catatan ini..."
|
||||
channelPlaceholder: "Posting ke kanal"
|
||||
_howToUse:
|
||||
visibility_title: "Visibilitas"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Sedang apa kamu saat ini?"
|
||||
b: "Apa yang terjadi di sekitarmu?"
|
||||
|
||||
Vendored
+58
@@ -6187,6 +6187,10 @@ export interface Locale extends ILocale {
|
||||
* 絵文字ピッカーに固定表示するプリセットをパレットとして登録したり、ピッカーの表示方法をカスタマイズしたりできます。
|
||||
*/
|
||||
"emojiPaletteBanner": string;
|
||||
/**
|
||||
* アニメーション画像を有効にする
|
||||
*/
|
||||
"enableAnimatedImages": string;
|
||||
"_chat": {
|
||||
/**
|
||||
* 送信者の名前を表示
|
||||
@@ -10030,6 +10034,60 @@ export interface Locale extends ILocale {
|
||||
* チャンネルに投稿...
|
||||
*/
|
||||
"channelPlaceholder": string;
|
||||
/**
|
||||
* フォームの説明を表示
|
||||
*/
|
||||
"showHowToUse": string;
|
||||
"_howToUse": {
|
||||
/**
|
||||
* 本文
|
||||
*/
|
||||
"content_title": string;
|
||||
/**
|
||||
* 投稿する内容を入力します。
|
||||
*/
|
||||
"content_description": string;
|
||||
/**
|
||||
* ツールバー
|
||||
*/
|
||||
"toolbar_title": string;
|
||||
/**
|
||||
* ファイルやアンケートの添付、注釈やハッシュタグの設定、絵文字やメンションの挿入などが行えます。
|
||||
*/
|
||||
"toolbar_description": string;
|
||||
/**
|
||||
* アカウントメニュー
|
||||
*/
|
||||
"account_title": string;
|
||||
/**
|
||||
* 投稿するアカウントを切り替えたり、アカウントに保存した下書き・予約投稿を一覧できます。
|
||||
*/
|
||||
"account_description": string;
|
||||
/**
|
||||
* 公開範囲
|
||||
*/
|
||||
"visibility_title": string;
|
||||
/**
|
||||
* ノートを公開する範囲の設定が行えます。
|
||||
*/
|
||||
"visibility_description": string;
|
||||
/**
|
||||
* メニュー
|
||||
*/
|
||||
"menu_title": string;
|
||||
/**
|
||||
* 下書きへの保存、投稿の予約、リアクションの設定など、その他のアクションが行えます。
|
||||
*/
|
||||
"menu_description": string;
|
||||
/**
|
||||
* 投稿ボタン
|
||||
*/
|
||||
"submit_title": string;
|
||||
/**
|
||||
* ノートを投稿します。Ctrl + Enter / Cmd + Enter でも投稿できます。
|
||||
*/
|
||||
"submit_description": string;
|
||||
};
|
||||
"_placeholders": {
|
||||
/**
|
||||
* いまどうしてる?
|
||||
|
||||
+93
-24
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "Il caricamento del file può richiedere tempo."
|
||||
uploadNFiles: "Caricare {n} file singolarmente"
|
||||
explore: "Esplora"
|
||||
messageRead: "Visualizzato"
|
||||
readAllChatMessages: "Segna tutti i messaggi come già letti"
|
||||
noMoreHistory: "Non c'è più cronologia da visualizzare"
|
||||
startChat: "Inizia a chattare"
|
||||
nUsersRead: "Letto da {n} persone"
|
||||
@@ -525,7 +526,7 @@ style: "Stile"
|
||||
drawer: "Drawer"
|
||||
popup: "Popup"
|
||||
showNoteActionsOnlyHover: "Mostra le azioni delle Note solo al passaggio del mouse"
|
||||
showReactionsCount: "Visualizza il numero di reazioni su una nota"
|
||||
showReactionsCount: "Visualizza la quantità di reazioni su una nota"
|
||||
noHistory: "Nessuna cronologia"
|
||||
signinHistory: "Storico degli accessi al profilo"
|
||||
enableAdvancedMfm: "Attivare i Misskey Flavoured Markdown (MFM) avanzati"
|
||||
@@ -755,19 +756,19 @@ i18nInfo: "Misskey è tradotto in diverse lingue da volontari. Anche tu puoi con
|
||||
manageAccessTokens: "Gestisci token di accesso"
|
||||
accountInfo: "Informazioni profilo"
|
||||
notesCount: "Conteggio note"
|
||||
repliesCount: "Numero di risposte inviate"
|
||||
renotesCount: "Numero di note che hai ricondiviso"
|
||||
repliedCount: "Numero di risposte ricevute"
|
||||
renotedCount: "Numero delle tue note ricondivise"
|
||||
followingCount: "Numero di Following"
|
||||
followersCount: "Numero di profili che ti seguono"
|
||||
sentReactionsCount: "Numero di reazioni inviate"
|
||||
receivedReactionsCount: "Numero di reazioni ricevute"
|
||||
pollVotesCount: "Numero di voti inviati"
|
||||
pollVotedCount: "Numero di voti ricevuti"
|
||||
repliesCount: "Quantità di risposte"
|
||||
renotesCount: "Quantità di Note ricondivise"
|
||||
repliedCount: "Quantità di risposte"
|
||||
renotedCount: "Quantità di tue Note ricondivise"
|
||||
followingCount: "Quantità di Following"
|
||||
followersCount: "Quantità di Follower"
|
||||
sentReactionsCount: "Quantità di reazioni"
|
||||
receivedReactionsCount: "Quantità di reazioni ricevute"
|
||||
pollVotesCount: "Quantità di voti"
|
||||
pollVotedCount: "Quantità di voti ricevuti"
|
||||
yes: "Sì"
|
||||
no: "No"
|
||||
driveFilesCount: "Numero di file nel Drive"
|
||||
driveFilesCount: "Quantità 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."
|
||||
@@ -781,7 +782,7 @@ verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di acced
|
||||
notSet: "Non impostato"
|
||||
emailVerified: "Il tuo indirizzo email è stato verificato"
|
||||
noteFavoritesCount: "Conteggio note tra i preferiti"
|
||||
pageLikesCount: "Numero di pagine che ti piacciono"
|
||||
pageLikesCount: "Quantità di pagine che ti piacciono"
|
||||
pageLikedCount: "Numero delle tue pagine che hanno ricevuto \"Mi piace\""
|
||||
contact: "Contatti"
|
||||
useSystemFont: "Usa il carattere predefinito del sistema"
|
||||
@@ -826,9 +827,9 @@ 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 uso"
|
||||
usageAmount: "Quantità utilizzata"
|
||||
capacity: "Capacità"
|
||||
inUse: "In uso"
|
||||
inUse: "Usata da"
|
||||
editCode: "Modifica codice"
|
||||
apply: "Applica"
|
||||
receiveAnnouncementFromInstance: "Ricevi i messaggi informativi dall'istanza"
|
||||
@@ -947,7 +948,7 @@ tablet: "Tablet"
|
||||
auto: "Automatico"
|
||||
themeColor: "Colore del tema"
|
||||
size: "Dimensioni"
|
||||
numberOfColumn: "Numero di colonne"
|
||||
numberOfColumn: "Quantità di colonne"
|
||||
searchByGoogle: "Cerca"
|
||||
instanceDefaultLightTheme: "Istanza, tema luminoso predefinito."
|
||||
instanceDefaultDarkTheme: "Istanza, tema scuro predefinito."
|
||||
@@ -984,7 +985,7 @@ isSystemAccount: "Si tratta di un profilo creato e gestito automaticamente dal s
|
||||
typeToConfirm: "Digita {x} per continuare"
|
||||
deleteAccount: "Eliminazione profilo"
|
||||
document: "Documentazione"
|
||||
numberOfPageCache: "Numero di pagine cache"
|
||||
numberOfPageCache: "Quantità di pagine in cache"
|
||||
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
|
||||
logoutConfirm: "Vuoi davvero uscire da Misskey? "
|
||||
logoutWillClearClientData: "All'uscita, la configurazione del client viene rimossa dal browser. Per ripristinarla quando si effettua nuovamente l'accesso, abilitare il backup automatico."
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "Le notifiche push sono già attivate"
|
||||
pushNotificationNotSupported: "Il client o il server non supporta le notifiche push"
|
||||
sendPushNotificationReadMessage: "Eliminare le notifiche push dopo la relativa lettura"
|
||||
sendPushNotificationReadMessageCaption: "Se possibile, verrà mostrata brevemente una notifica con il testo \"{emptyPushNotificationMessage}\". Potrebbe influire negativamente sulla durata della batteria."
|
||||
pleaseAllowPushNotification: "Per favore, acconsenti alla ricezione di notifiche nel browser"
|
||||
browserPushNotificationDisabled: "Non è stato possibile ottenere il consenso alla ricezione di notifche"
|
||||
browserPushNotificationDisabledDescription: "Non hai concesso a {serverName} di spedire notifiche. Per favore, acconsenti alla ricezione nelle impostazioni del browser e riprova."
|
||||
windowMaximize: "Ingrandisci"
|
||||
windowMinimize: "Contrai finestra"
|
||||
windowRestore: "Ripristina"
|
||||
@@ -1032,7 +1036,7 @@ cannotLoad: "Caricamento impossibile"
|
||||
numberOfProfileView: "Visualizzazioni profilo"
|
||||
like: "Mi piace!"
|
||||
unlike: "Non mi piace"
|
||||
numberOfLikes: "Numero di Like"
|
||||
numberOfLikes: "Quantità di Like"
|
||||
show: "Visualizza"
|
||||
neverShow: "Non mostrare più"
|
||||
remindMeLater: "Rimanda"
|
||||
@@ -1178,7 +1182,7 @@ createInviteCode: "Genera codice di invito"
|
||||
createWithOptions: "Genera con opzioni"
|
||||
createCount: "Conteggio inviti"
|
||||
inviteCodeCreated: "Inviti generati"
|
||||
inviteLimitExceeded: "Hai raggiunto il numero massimo di codici invito generabili."
|
||||
inviteLimitExceeded: "Hai raggiunto la quantità massima di codici invito generabili."
|
||||
createLimitRemaining: "Inviti generabili: {limit} rimanenti"
|
||||
inviteLimitResetCycle: "Alle {time}, il limite verrà ripristinato a {limit}"
|
||||
expirationDate: "Scadenza"
|
||||
@@ -1346,7 +1350,7 @@ preferenceSyncConflictChoiceCancel: "Annulla la sincronizzazione"
|
||||
paste: "Incolla"
|
||||
emojiPalette: "Tavolozza emoji"
|
||||
postForm: "Finestra di pubblicazione"
|
||||
textCount: "Il numero di caratteri"
|
||||
textCount: "Quantità di caratteri"
|
||||
information: "Informazioni"
|
||||
chat: "Chat"
|
||||
directMessage: "Chattare insieme"
|
||||
@@ -1396,6 +1400,50 @@ scheduled: "Pianificata"
|
||||
widgets: "Riquadri"
|
||||
deviceInfo: "Informazioni sul dispositivo"
|
||||
deviceInfoDescription: "Se ci contatti per ricevere supporto tecnico, ti preghiamo di includere le seguenti informazioni per aiutarci a risolvere il tuo problema."
|
||||
youAreAdmin: "Sei un amministratore"
|
||||
frame: "Cornice"
|
||||
presets: "Preimpostato"
|
||||
zeroPadding: "Al vivo"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "Didascalia dell'immagine"
|
||||
filename: "Nome dell'allegato"
|
||||
filename_without_ext: "Nome file senza estensione"
|
||||
year: "Anno di scatto"
|
||||
month: "Mese dello scatto"
|
||||
day: "Giorno dello scatto"
|
||||
hour: "Ora dello scatto"
|
||||
minute: "Minuto dello scatto"
|
||||
second: "Secondi dello scatto"
|
||||
camera_model: "Modello di fotocamera"
|
||||
camera_lens_model: "Modello della lente"
|
||||
camera_mm: "Lunghezza focale"
|
||||
camera_mm_35: "Lunghezza focale (equivalente a 35 mm)"
|
||||
camera_f: "Diaframma"
|
||||
camera_s: "Velocità otturatore"
|
||||
camera_iso: "Sensibilità ISO"
|
||||
gps_lat: "Latitudine"
|
||||
gps_long: "Longitudine"
|
||||
_imageFrameEditor:
|
||||
title: "Modifica fotogramma"
|
||||
tip: "Puoi decorare le immagini aggiungendo etichette con cornici e metadati."
|
||||
header: "Intestazione"
|
||||
footer: "Piè di pagina"
|
||||
borderThickness: "Larghezza del bordo"
|
||||
labelThickness: "Spessore etichetta"
|
||||
labelScale: "Dimensione etichetta"
|
||||
centered: "Allinea al centro"
|
||||
captionMain: "Didascalia (grande)"
|
||||
captionSub: "Didascalia (piccola)"
|
||||
availableVariables: "Variabili disponibili"
|
||||
withQrCode: "QR Code"
|
||||
backgroundColor: "Colore dello sfondo"
|
||||
textColor: "Colore del testo"
|
||||
font: "Tipo di carattere"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans serif"
|
||||
quitWithoutSaveConfirm: "Uscire senza salvare?"
|
||||
failedToLoadImage: "Impossibile caricare l'immagine"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Alta qualità"
|
||||
@@ -1406,8 +1454,8 @@ _compression:
|
||||
medium: "Taglia media"
|
||||
small: "Taglia piccola"
|
||||
_order:
|
||||
newest: "Prima i più recenti"
|
||||
oldest: "Meno recenti prima"
|
||||
newest: "Più recenti"
|
||||
oldest: "Meno recenti"
|
||||
_chat:
|
||||
messages: "Messaggi"
|
||||
noMessagesYet: "Ancora nessun messaggio"
|
||||
@@ -1498,6 +1546,7 @@ _settings:
|
||||
showUrlPreview: "Mostra anteprima dell'URL"
|
||||
showAvailableReactionsFirstInNote: "Mostra le reazioni disponibili in alto"
|
||||
showPageTabBarBottom: "Visualizza le schede della pagina nella parte inferiore"
|
||||
emojiPaletteBanner: "Puoi salvare i le emoji predefinite da appuntare in alto nel raccoglitore emoji come tavolozza e personalizzare in che modo visualizzare il raccoglitore."
|
||||
_chat:
|
||||
showSenderName: "Mostra il nome del mittente"
|
||||
sendOnEnter: "Invio spedisce"
|
||||
@@ -1515,6 +1564,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "Per abilitare i backup automatici, è necessario indicare il nome del profilo."
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "Su questo dispositivo non è stato attivato il backup automatico delle preferenze."
|
||||
backupFound: "Esiste il Backup delle preferenze"
|
||||
forceBackup: "Backup forzato delle impostazioni"
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "Per vedere il contenuto, è necessaria l'iscrizione"
|
||||
requireSigninToViewContentsDescription1: "Richiedere l'iscrizione per visualizzare tutte le Note e gli altri contenuti che hai creato. Probabilmente l'effetto è impedire la raccolta di informazioni da parte dei bot crawler."
|
||||
@@ -2522,7 +2572,7 @@ _visibility:
|
||||
followersDescription: "Visibile solo ai tuoi follower"
|
||||
specified: "Nota diretta"
|
||||
specifiedDescription: "Visibile solo ai profili menzionati"
|
||||
disableFederation: "Senza federazione"
|
||||
disableFederation: "Gestisci la federazione"
|
||||
disableFederationDescription: "Non spedire attività alle altre istanze remote"
|
||||
_postForm:
|
||||
quitInspiteOfThereAreUnuploadedFilesConfirm: "Alcuni file non sono stati caricati. Vuoi annullare l'operazione?"
|
||||
@@ -2530,6 +2580,20 @@ _postForm:
|
||||
replyPlaceholder: "Rispondi a questa nota..."
|
||||
quotePlaceholder: "Cita questa nota..."
|
||||
channelPlaceholder: "Pubblica sul canale..."
|
||||
showHowToUse: "Mostra il tutorial"
|
||||
_howToUse:
|
||||
content_title: "Testo"
|
||||
content_description: "Inserisci il contenuto che desideri pubblicare."
|
||||
toolbar_title: "Barra degli Strumenti"
|
||||
toolbar_description: "Puoi allegare file e sondaggi, aggiungere Note, hashtag, inserire emoji e menzioni."
|
||||
account_title: "Menu profilo"
|
||||
account_description: "Puoi cambiare il profilo col quale vuoi pubblicare, elencare bozze e pianificare le Note."
|
||||
visibility_title: "Visibilità"
|
||||
visibility_description: "Puoi impostare il grado di visibilità delle Note."
|
||||
menu_title: "Menù"
|
||||
menu_description: "Puoi svolgere altre azioni, come il salvataggio in bozza, i post di prenotazione, l'impostazione delle reazioni e così via."
|
||||
submit_title: "Bottone invia"
|
||||
submit_description: "Posterò un biglietto. Puoi anche fare Ctrl + Inserisci oppure Cmd + Inserisci."
|
||||
_placeholders:
|
||||
a: "Come va?"
|
||||
b: "Hai qualcosa da raccontare? Inizia pure..."
|
||||
@@ -2807,6 +2871,8 @@ _abuseReport:
|
||||
notifiedWebhook: "Webhook da usare"
|
||||
deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "Ha cancellato la coda di Attività"
|
||||
promoteQueue: "Ripeti le attività in coda"
|
||||
createRole: "Crea un Ruolo"
|
||||
deleteRole: "Elimina un Ruolo"
|
||||
updateRole: "Modifica un ruolo"
|
||||
@@ -3121,7 +3187,7 @@ _bootErrors:
|
||||
_search:
|
||||
searchScopeAll: "Tutte"
|
||||
searchScopeLocal: "Locale"
|
||||
searchScopeServer: "Specifiche del server"
|
||||
searchScopeServer: "Server specifico"
|
||||
searchScopeUser: "Profilo specifico"
|
||||
pleaseEnterServerHost: "Inserire il nome host"
|
||||
pleaseSelectUser: "Per favore, seleziona un profilo"
|
||||
@@ -3201,6 +3267,7 @@ _watermarkEditor:
|
||||
title: "Modifica la filigrana"
|
||||
cover: "Coprire tutto"
|
||||
repeat: "Disposizione"
|
||||
preserveBoundingRect: "Fai in modo da non eccedere durante la rotazione"
|
||||
opacity: "Opacità"
|
||||
scale: "Dimensioni"
|
||||
text: "Testo"
|
||||
@@ -3222,11 +3289,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "Dimensione del punto secondario"
|
||||
polkadotSubDotDivisions: "Quantità di punti secondari"
|
||||
leaveBlankToAccountUrl: "Il valore vuoto indica la URL dell'account"
|
||||
failedToLoadImage: "Impossibile caricare l'immagine"
|
||||
_imageEffector:
|
||||
title: "Effetto"
|
||||
addEffect: "Aggiungi effetto"
|
||||
discardChangesConfirm: "Scarta le modifiche ed esci?"
|
||||
nothingToConfigure: "Nessuna impostazione configurabile."
|
||||
failedToLoadImage: "Impossibile caricare l'immagine"
|
||||
_fxs:
|
||||
chromaticAberration: "Aberrazione cromatica"
|
||||
glitch: "Glitch"
|
||||
|
||||
@@ -1554,6 +1554,7 @@ _settings:
|
||||
showAvailableReactionsFirstInNote: "利用できるリアクションを先頭に表示"
|
||||
showPageTabBarBottom: "ページのタブバーを下部に表示"
|
||||
emojiPaletteBanner: "絵文字ピッカーに固定表示するプリセットをパレットとして登録したり、ピッカーの表示方法をカスタマイズしたりできます。"
|
||||
enableAnimatedImages: "アニメーション画像を有効にする"
|
||||
|
||||
_chat:
|
||||
showSenderName: "送信者の名前を表示"
|
||||
@@ -2641,6 +2642,20 @@ _postForm:
|
||||
replyPlaceholder: "このノートに返信..."
|
||||
quotePlaceholder: "このノートを引用..."
|
||||
channelPlaceholder: "チャンネルに投稿..."
|
||||
showHowToUse: "フォームの説明を表示"
|
||||
_howToUse:
|
||||
content_title: "本文"
|
||||
content_description: "投稿する内容を入力します。"
|
||||
toolbar_title: "ツールバー"
|
||||
toolbar_description: "ファイルやアンケートの添付、注釈やハッシュタグの設定、絵文字やメンションの挿入などが行えます。"
|
||||
account_title: "アカウントメニュー"
|
||||
account_description: "投稿するアカウントを切り替えたり、アカウントに保存した下書き・予約投稿を一覧できます。"
|
||||
visibility_title: "公開範囲"
|
||||
visibility_description: "ノートを公開する範囲の設定が行えます。"
|
||||
menu_title: "メニュー"
|
||||
menu_description: "下書きへの保存、投稿の予約、リアクションの設定など、その他のアクションが行えます。"
|
||||
submit_title: "投稿ボタン"
|
||||
submit_description: "ノートを投稿します。Ctrl + Enter / Cmd + Enter でも投稿できます。"
|
||||
_placeholders:
|
||||
a: "いまどうしてる?"
|
||||
b: "何かありましたか?"
|
||||
|
||||
+73
-25
@@ -220,6 +220,7 @@ silenceThisInstance: "サーバーサイレンスすんで?"
|
||||
mediaSilenceThisInstance: "サーバーをメディアサイレンス"
|
||||
operations: "操作"
|
||||
software: "ソフトウェア"
|
||||
softwareName: "ソフトウェア名"
|
||||
version: "バージョン"
|
||||
metadata: "メタデータ"
|
||||
withNFiles: "{n}個のファイル"
|
||||
@@ -252,6 +253,7 @@ noteDeleteConfirm: "このノートをほかしてええか?"
|
||||
pinLimitExceeded: "これ以上ピン留めできひん"
|
||||
done: "でけた"
|
||||
processing: "処理しとる"
|
||||
preprocessing: "準備中"
|
||||
preview: "プレビュー"
|
||||
default: "デフォルト"
|
||||
defaultValueIs: "デフォルト: {value}"
|
||||
@@ -299,13 +301,14 @@ uploadFromUrlRequested: "アップロードしたい言うといたで"
|
||||
uploadFromUrlMayTakeTime: "アップロード終わるんにちょい時間かかるかもしれへんわ。"
|
||||
explore: "みつける"
|
||||
messageRead: "もう読んだ"
|
||||
readAllChatMessages: "メッセージを全部読んだことにしとく"
|
||||
noMoreHistory: "これより昔のんはあらへんで"
|
||||
startChat: "チャットを始めよか"
|
||||
nUsersRead: "{n}人が読んでもうた"
|
||||
agreeTo: "{0}に同意したで"
|
||||
agree: "せやな"
|
||||
agreeBelow: "下記に同意したる"
|
||||
basicNotesBeforeCreateAccount: "よう読んでやってや"
|
||||
agreeBelow: "下記に同意するわ"
|
||||
basicNotesBeforeCreateAccount: "よう読んどいてや"
|
||||
termsOfService: "使うための決め事"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
@@ -325,12 +328,13 @@ dark: "ダーク"
|
||||
lightThemes: "デイゲーム"
|
||||
darkThemes: "ナイトゲーム"
|
||||
syncDeviceDarkMode: "デバイスのダークモードと一緒にする"
|
||||
switchDarkModeManuallyWhenSyncEnabledConfirm: "「{x}」がオンになってるで。同期をオフにして手動でモードを切り替えることにします?"
|
||||
switchDarkModeManuallyWhenSyncEnabledConfirm: "「{x}」がオンになってるで。同期切って手動でモード切り替える?"
|
||||
drive: "ドライブ"
|
||||
fileName: "ファイル名"
|
||||
selectFile: "ファイル選んでや"
|
||||
selectFiles: "ファイル選んでや"
|
||||
selectFolder: "フォルダ選んでや"
|
||||
unselectFolder: "フォルダーの選択を解除"
|
||||
selectFolders: "フォルダ選んでや"
|
||||
fileNotSelected: "ファイルが選択されてへんで"
|
||||
renameFile: "ファイル名をいらう"
|
||||
@@ -421,14 +425,13 @@ antennaSource: "受信ソース(このソースは食われへん)"
|
||||
antennaKeywords: "受信キーワード"
|
||||
antennaExcludeKeywords: "除外キーワード"
|
||||
antennaExcludeBots: "Botアカウントを除外"
|
||||
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
|
||||
antennaKeywordsDescription: "スペースで区切ったらAND指定で、改行で区切ったらOR指定や"
|
||||
notifyAntenna: "新しいノートを通知すんで"
|
||||
withFileAntenna: "なんか添付されたノートだけ"
|
||||
excludeNotesInSensitiveChannel: "センシティブなチャンネルのノートは入れんとくわ"
|
||||
enableServiceworker: "ブラウザにプッシュ通知が行くようにする"
|
||||
antennaUsersDescription: "ユーザー名を改行で区切ったってな"
|
||||
caseSensitive: "大文字と小文字は別もんや"
|
||||
withReplies: "返信も入れたって"
|
||||
connectedTo: "次のアカウントに繋がっとるで"
|
||||
notesAndReplies: "投稿と返信"
|
||||
withFiles: "ファイル付いとる"
|
||||
@@ -471,9 +474,9 @@ newPasswordIs: "今度のパスワードは「{password}」や"
|
||||
reduceUiAnimation: "UIの動きやアニメーションを少なする"
|
||||
share: "わけわけ"
|
||||
notFound: "見つからへんね"
|
||||
notFoundDescription: "言われたURLにはまるページはなかったで。"
|
||||
notFoundDescription: "言われたURLのページはなかったで。"
|
||||
uploadFolder: "とりあえずアップロードしたやつ置いとく所"
|
||||
markAsReadAllNotifications: "通知はもう全て読んだわっ"
|
||||
markAsReadAllNotifications: "通知はもう全部読んだわ"
|
||||
markAsReadAllUnreadNotes: "投稿は全て読んだわっ"
|
||||
markAsReadAllTalkMessages: "チャットはもうぜんぶ読んだわっ"
|
||||
help: "ヘルプ"
|
||||
@@ -554,7 +557,7 @@ showFeaturedNotesInTimeline: "タイムラインにおすすめのノートを
|
||||
objectStorage: "オブジェクトストレージ"
|
||||
useObjectStorage: "オブジェクトストレージを使う"
|
||||
objectStorageBaseUrl: "Base URL"
|
||||
objectStorageBaseUrlDesc: "参照に使うにURLやで。CDNやProxyを使用してるんならそのURL、S3: 'https://<bucket>.s3.amazonaws.com'、GCSとかなら: 'https://storage.googleapis.com/<bucket>'。"
|
||||
objectStorageBaseUrlDesc: "参照に使うURLやで。CDNやProxyを使用してるんならそのURL、S3: 'https://<bucket>.s3.amazonaws.com'、GCSとかなら: 'https://storage.googleapis.com/<bucket>'。"
|
||||
objectStorageBucket: "Bucket"
|
||||
objectStorageBucketDesc: "使ってるサービスのbucket名を選んでな"
|
||||
objectStoragePrefix: "Prefix"
|
||||
@@ -571,17 +574,19 @@ objectStorageSetPublicRead: "アップロードした時に'public-read'を設
|
||||
s3ForcePathStyleDesc: "s3ForcePathStyleを使たらバケット名をURLのホスト名やなくてパスの一部として必ず指定させるようになるで。セルフホストされたMinioとかを使うてるんやったら有効にせなあかん場合があるで。"
|
||||
serverLogs: "サーバーログ"
|
||||
deleteAll: "全部ほかす"
|
||||
showFixedPostForm: "タイムラインの上の方で投稿できるようにやってくれへん?"
|
||||
showFixedPostForm: "タイムラインの上の方で投稿できるようにするわ"
|
||||
showFixedPostFormInChannel: "タイムラインの上の方で投稿できるようにするわ(チャンネル)"
|
||||
withRepliesByDefaultForNewlyFollowed: "フォローする時、デフォルトで返信をタイムラインに含むようにしよか"
|
||||
newNoteRecived: "新しいノートがあるで"
|
||||
newNote: "新しいノートがあるで"
|
||||
sounds: "音"
|
||||
sound: "音"
|
||||
notificationSoundSettings: "通知音の設定"
|
||||
listen: "聴く"
|
||||
none: "なし"
|
||||
showInPage: "ページで表示"
|
||||
popout: "ポップアウト"
|
||||
volume: "やかましさ"
|
||||
volume: "音のでかさ"
|
||||
masterVolume: "全体のやかましさ"
|
||||
notUseSound: "音出さへん"
|
||||
useSoundOnlyWhenActive: "Misskeyがアクティブなときだけ音出す"
|
||||
@@ -597,7 +602,7 @@ nothing: "あらへん"
|
||||
installedDate: "インストールした日時"
|
||||
lastUsedDate: "最後に使った日時"
|
||||
state: "状態"
|
||||
sort: "仕分ける"
|
||||
sort: "並び替え"
|
||||
ascendingOrder: "小さい順"
|
||||
descendingOrder: "大きい順"
|
||||
scratchpad: "スクラッチパッド"
|
||||
@@ -657,9 +662,9 @@ useBlurEffectForModal: "モーダルにぼかし効果を使用"
|
||||
useFullReactionPicker: "フルフルのツッコミピッカーを使う"
|
||||
width: "幅"
|
||||
height: "高さ"
|
||||
large: "大"
|
||||
medium: "中"
|
||||
small: "小"
|
||||
large: "でかい"
|
||||
medium: "ふつう"
|
||||
small: "ちいさい"
|
||||
generateAccessToken: "アクセストークンの発行"
|
||||
permission: "権限"
|
||||
adminPermission: "管理者権限"
|
||||
@@ -684,7 +689,7 @@ smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
|
||||
smtpSecureInfo: "STARTTLS使っとる時はオフにしてや。"
|
||||
testEmail: "配信テスト"
|
||||
wordMute: "ワードミュート"
|
||||
wordMuteDescription: "指定した語句が入ってるノートを最小化するで。最小化されたノートをクリックしたら、表示できるようになるで。"
|
||||
wordMuteDescription: "指定した語句が入ってるノートをちっさくするで。ちっさくなったノートをクリックしたら中身を見れるで。"
|
||||
hardWordMute: "ハードワードミュート"
|
||||
showMutedWord: "ミュートされたワードを表示するで"
|
||||
hardWordMuteDescription: "指定した語句が入ってるノートを隠すで。ワードミュートとちゃうて、ノートは完全に表示されんようになるで。"
|
||||
@@ -718,7 +723,7 @@ behavior: "動作"
|
||||
sample: "サンプル"
|
||||
abuseReports: "通報"
|
||||
reportAbuse: "通報"
|
||||
reportAbuseRenote: "リノート苦情だすで?"
|
||||
reportAbuseRenote: "リノートの苦情出す"
|
||||
reportAbuseOf: "{name}を通報する"
|
||||
fillAbuseReportDescription: "細かい通報理由を書いてなー。対象ノートがある時はそのURLも書いといてなー。"
|
||||
abuseReported: "無事内容が送信されたみたいやで。おおきに〜。"
|
||||
@@ -768,6 +773,7 @@ lockedAccountInfo: "フォローを承認制にしとっても、ノートの公
|
||||
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にするで"
|
||||
loadRawImages: "添付画像のサムネイルをオリジナル画質にするで"
|
||||
disableShowingAnimatedImages: "アニメーション画像を再生せんとくで"
|
||||
disableShowingAnimatedImages_caption: "この設定を変えてもアニメーション画像が再生されへん時は、ブラウザとかOSのアクセシビリティ設定とか省電力設定の方が悪さしてるかもしれへんで。"
|
||||
highlightSensitiveMedia: "きわどいことをめっっちゃわかりやすくする"
|
||||
verificationEmailSent: "無事確認のメールを送れたで。メールに書いてあるリンクにアクセスして、設定を完了してなー。"
|
||||
notSet: "未設定"
|
||||
@@ -877,7 +883,7 @@ startingperiod: "始めた期間"
|
||||
memo: "メモ"
|
||||
priority: "優先度"
|
||||
high: "高い"
|
||||
middle: "中"
|
||||
middle: "ふつう"
|
||||
low: "低い"
|
||||
emailNotConfiguredWarning: "メアドの設定がされてへんで。"
|
||||
ratio: "比率"
|
||||
@@ -1014,6 +1020,9 @@ pushNotificationAlreadySubscribed: "プッシュ通知はオンになってる
|
||||
pushNotificationNotSupported: "ブラウザかサーバーがプッシュ通知に対応してないみたいやで。"
|
||||
sendPushNotificationReadMessage: "通知やメッセージが既読になったらプッシュ通知を消すで"
|
||||
sendPushNotificationReadMessageCaption: "あんたの端末の電池使う量が増えるかもしれん。"
|
||||
pleaseAllowPushNotification: "ブラウザの通知設定を許可してな"
|
||||
browserPushNotificationDisabled: "通知の送信権限が取れんかったわ"
|
||||
browserPushNotificationDisabledDescription: "今 {serverName} から通知を送るための権限が無いから、ブラウザの設定で通知を許可してもっかい試してな。"
|
||||
windowMaximize: "最大化"
|
||||
windowMinimize: "最小化"
|
||||
windowRestore: "元に戻す"
|
||||
@@ -1050,6 +1059,7 @@ permissionDeniedError: "操作が拒否されてもうた。"
|
||||
permissionDeniedErrorDescription: "このアカウントはこれやったらアカンって。"
|
||||
preset: "プリセット"
|
||||
selectFromPresets: "プリセットから選ぶ"
|
||||
custom: "カスタム"
|
||||
achievements: "実績"
|
||||
gotInvalidResponseError: "サーバー黙っとるわ、知らんけど"
|
||||
gotInvalidResponseErrorDescription: "サーバーいま日曜日。またきて月曜日。"
|
||||
@@ -1088,6 +1098,7 @@ prohibitedWordsDescription2: "スペースで区切るとAND指定、キーワ
|
||||
hiddenTags: "見えてへんハッシュタグ"
|
||||
hiddenTagsDescription: "設定したタグを最近流行りのとこに見えんようにすんで。複数設定するときは改行で区切ってな。"
|
||||
notesSearchNotAvailable: "なんかノート探せへん。"
|
||||
usersSearchNotAvailable: "ユーザーを探すことはできへんみたいや。"
|
||||
license: "ライセンス"
|
||||
unfavoriteConfirm: "ほんまに気に入らんの?"
|
||||
myClips: "自分のクリップ"
|
||||
@@ -1239,6 +1250,7 @@ releaseToRefresh: "離したらリロード"
|
||||
refreshing: "リロードしとる"
|
||||
pullDownToRefresh: "引っ張ってリロードするで"
|
||||
useGroupedNotifications: "通知をグループ分けして出すで"
|
||||
emailVerificationFailedError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。"
|
||||
cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。"
|
||||
doReaction: "ツッコむで"
|
||||
code: "コード"
|
||||
@@ -1331,22 +1343,41 @@ unmuteX: "{x}のミュートやめたる"
|
||||
redisplayAllTips: "全部の「ヒントとコツ」をもっかい見して"
|
||||
hideAllTips: "「ヒントとコツ」は全部表示せんでええ"
|
||||
defaultImageCompressionLevel_description: "低くすると画質は保てるんやけど、ファイルサイズが増えるで。<br>高くするとファイルサイズは減らせるんやけど、画質が落ちるで。"
|
||||
defaultCompressionLevel_description: "低くすると品質は保てるんやけど、ファイルサイズが増えるで。<br>高くするとファイルサイズは減らせるんやけど、品質が落ちるで。"
|
||||
inMinutes: "分"
|
||||
inDays: "日"
|
||||
safeModeEnabled: "セーフモードがオンになってるで"
|
||||
pluginsAreDisabledBecauseSafeMode: "セーフモードがオンやから、プラグインは全部無効化されてるで。"
|
||||
customCssIsDisabledBecauseSafeMode: "セーフモードがオンやから、カスタムCSSは適用されてへんで。"
|
||||
themeIsDefaultBecauseSafeMode: "セーフモードがオンの間はデフォルトのテーマを使うで。セーフモードをオフにれば元に戻るで。"
|
||||
thankYouForTestingBeta: "ベータ版使うてくれておおきに!"
|
||||
widgets: "ウィジェット"
|
||||
deviceInfoDescription: "なんか技術的なことで分からんこと聞くときは、下の情報も一緒に書いてもらえると、こっちも分かりやすいし、はよ直ると思います。"
|
||||
youAreAdmin: "あんた、管理者やで"
|
||||
presets: "プリセット"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "ファイル名"
|
||||
_imageFrameEditor:
|
||||
tip: "画像にフレームとかメタデータを入れたラベルとかを付け足していい感じにできるで。"
|
||||
header: "ヘッダー"
|
||||
font: "フォント"
|
||||
fontSerif: "セリフ"
|
||||
fontSansSerif: "サンセリフ"
|
||||
quitWithoutSaveConfirm: "保存せずに終わってもええんか?"
|
||||
failedToLoadImage: "あかん、画像読み込まれへんわ"
|
||||
_chat:
|
||||
noMessagesYet: "まだメッセージはあらへんで"
|
||||
individualChat_description: "特定のユーザーと一対一でチャットができるで。"
|
||||
individualChat_description: "特定のユーザーとサシでチャットできるで。"
|
||||
roomChat_description: "複数人でチャットできるで。\nあと、個人チャットを許可してへんユーザーとでも、相手がええって言うならチャットできるで。"
|
||||
inviteUserToChat: "ユーザーを招待してチャットを始めてみ"
|
||||
invitations: "来てや"
|
||||
noInvitations: "招待はあらへんで"
|
||||
noHistory: "履歴はないわ。"
|
||||
noRooms: "ルームはあらへんで"
|
||||
join: "入る"
|
||||
ignore: "ほっとく"
|
||||
leave: "グループから抜ける"
|
||||
members: "メンバーはん"
|
||||
home: "ホーム"
|
||||
send: "送信"
|
||||
@@ -1389,11 +1420,13 @@ _settings:
|
||||
appearanceBanner: "好みに応じた、クライアントの見た目・表示方法に関わる設定ができるで。"
|
||||
soundsBanner: "クライアントで流すサウンドの設定ができるで。"
|
||||
makeEveryTextElementsSelectable: "全部のテキスト要素を選択できるようにする"
|
||||
makeEveryTextElementsSelectable_description: "これをつけると、一部のシチュエーションでユーザビリティが低下するかもしれん。"
|
||||
makeEveryTextElementsSelectable_description: "これをつけると、場面によったら使いにくくなるかもしれん。"
|
||||
useStickyIcons: "アイコンがスクロールにひっつくようにする"
|
||||
enablePullToRefresh_description: "マウスやったら、ホイールを押し込みながらドラッグしてな。"
|
||||
realtimeMode_description: "サーバーと接続を確立して、リアルタイムでコンテンツを更新するで。通信量とバッテリーの消費が多くなるかもしれへん。"
|
||||
contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されるんやけど、そのぶんパフォーマンスが低くなるし、通信量とバッテリーの消費も増えるねん。"
|
||||
contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されるんやけど、そのぶんパフォーマンスが落ちるし、通信量とバッテリーの消費も増えるねん。"
|
||||
contentsUpdateFrequency_description2: "リアルタイムモードをつけてるんやったら、この設定がどうであれリアルタイムでコンテンツが更新されるで。"
|
||||
emojiPaletteBanner: "絵文字ピッカーに置いとくプリセットをパレットっていうので登録したり、ピッカーの見た目を変えたりできるで。"
|
||||
_preferencesProfile:
|
||||
profileNameDescription: "このデバイスはなんて呼んだらええんや?"
|
||||
_preferencesBackup:
|
||||
@@ -1487,7 +1520,7 @@ _initialTutorial:
|
||||
description: "ここでは、Misskeyのカンタンな使い方とか機能を確かめれんで。"
|
||||
_note:
|
||||
title: "ノートってなんや?"
|
||||
description: "Misskeyでの投稿は「ノート」って呼ばれてんで。ノートは順々にタイムラインに載ってて、リアルタイムで新しくなってってんで。"
|
||||
description: "Misskeyでの投稿は「ノート」って呼ばれてんで。ノートは順々にタイムラインに載ってて、リアルタイムで新しくなってくで。"
|
||||
reply: "返信もできるで。返信の返信もできるから、スレッドっぽく会話をそのまま続けれもするで。"
|
||||
renote: "そのノートを自分のタイムラインに流して共有できるで。テキスト入れて引用してもええな。"
|
||||
reaction: "ツッコミをつけることもできるで。細かいことは次のページや。"
|
||||
@@ -1507,7 +1540,7 @@ _initialTutorial:
|
||||
social: "ホームタイムラインの投稿もローカルタイムラインのも一緒に見れるで。"
|
||||
global: "繋がってる他の全サーバーからの投稿が見れるで。"
|
||||
description2: "それぞれのタイムラインは、いつでも画面上で切り替えられんねん。覚えとき。"
|
||||
description3: "その他にも、リストタイムラインとかチャンネルタイムラインとかがあんねん。詳しいのは{link}を見とき。"
|
||||
description3: "その他にも、リストタイムラインとかチャンネルタイムラインとかがあんねん。詳しいのは{link}を見ときや。"
|
||||
_postNote:
|
||||
title: "ノートの投稿設定"
|
||||
description1: "Misskeyにノートを投稿するとき、いろんなオプションが付けれるで。投稿画面はこんな感じや。"
|
||||
@@ -1543,7 +1576,7 @@ _timelineDescription:
|
||||
home: "ホームタイムラインは、あんたがフォローしとるアカウントの投稿だけ見れるで。"
|
||||
local: "ローカルタイムラインは、このサーバーにおる全員の投稿を見れるで。"
|
||||
social: "ソーシャルタイムラインは、ホームタイムラインの投稿もローカルタイムラインのも一緒に見れるで。"
|
||||
global: "グローバルタイムラインは、繋がっとる他のサーバーの投稿、全部ひっくるめて見れんで。"
|
||||
global: "グローバルタイムラインは、繋がっとる他のサーバーの投稿、全部ひっくるめて見れるで。"
|
||||
_serverRules:
|
||||
description: "新規登録前に見せる、サーバーのカンタンなルールを決めるで。内容は使うための決め事の要約がええと思うわ。"
|
||||
_serverSettings:
|
||||
@@ -1563,7 +1596,7 @@ _serverSettings:
|
||||
inquiryUrl: "問い合わせ先URL"
|
||||
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定するで。"
|
||||
openRegistration: "アカウントの作成をオープンにする"
|
||||
openRegistrationWarning: "登録を解放するのはリスクが伴うで。サーバーをいっつも監視して、なんか起きたらすぐに対応できるんやったら、オンにしてもええと思う。"
|
||||
openRegistrationWarning: "登録を解放するのはリスクあるで。サーバーをいっつも監視して、なんか起きたらすぐに対応できるんやったら、オンにしてもええと思うけどな。"
|
||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターがおらんかったら、スパムを防ぐためにこの設定は勝手に切られるで。"
|
||||
deliverSuspendedSoftwareDescription: "脆弱性とかの理由で、サーバーのソフトウェアの名前とバージョンの範囲を決めて配信を止められるで。このバージョン情報はサーバーが提供したものやから、信頼性は保証されへん。バージョン指定には semver の範囲指定が使えるねんけど、>= 2024.3.1と指定すると 2024.3.1-custom.0 みたいなカスタムバージョンが含まれへんから、>= 2024.3.1-0 みたいに prerelease を指定するとええかもしれへんな。"
|
||||
singleUserMode_description: "このサーバーを使うとるんが自分だけなんやったら、このモードを有効にすると動作がええ感じになるで。"
|
||||
@@ -1958,7 +1991,7 @@ _signup:
|
||||
emailSent: "さっき入れたメアド({email})宛に確認メールを送ったで。メールに書かれたリンク押してアカウント作るの終わらしてな。\nメールの認証リンクの期限は30分や。"
|
||||
_accountDelete:
|
||||
accountDelete: "アカウントの削除"
|
||||
mayTakeTime: "アカウント消すんはサーバーが重いんやって。やから作ったコンテンツとか上げたファイルの数が多いと消し終わるまでに時間がかかるかもしれへん。"
|
||||
mayTakeTime: "アカウント消すんはサーバーに負荷かかるんやって。やから、作ったコンテンツとか上げたファイルの数が多いと消し終わるまでに時間がかかるかもしれんわ。"
|
||||
sendEmail: "アカウントの消し終わるときは、登録してたメアドに通知するで。"
|
||||
requestAccountDelete: "アカウント削除頼む"
|
||||
started: "削除処理が始まったで。"
|
||||
@@ -2298,6 +2331,7 @@ _auth:
|
||||
scopeUser: "以下のユーザーとしていじってるで"
|
||||
pleaseLogin: "アプリにアクセスさせるんやったら、ログインしてや。"
|
||||
byClickingYouWillBeRedirectedToThisUrl: "アクセスを許したら、自動で下のURLに遷移するで"
|
||||
alreadyAuthorized: "このアプリはもうアクセスを許可してるみたいやで。"
|
||||
_antennaSources:
|
||||
all: "みんなのノート"
|
||||
homeTimeline: "フォローしとるユーザーのノート"
|
||||
@@ -2388,6 +2422,14 @@ _postForm:
|
||||
replyPlaceholder: "このノートに返信..."
|
||||
quotePlaceholder: "このノートを引用..."
|
||||
channelPlaceholder: "チャンネルに投稿..."
|
||||
_howToUse:
|
||||
toolbar_description: "ファイルとかアンケートを付けたり、注釈とかハッシュタグを書いたり、絵文字とかメンションとかを付け足したりできるで。"
|
||||
account_description: "投稿するアカウントを変えたり、アカウントに保存した下書きとか予約投稿とかを見れるで。"
|
||||
visibility_title: "公開範囲"
|
||||
visibility_description: "ノートを誰に見せたいかはここで切り替えてな。"
|
||||
menu_title: "メニュー"
|
||||
menu_description: "下書きに保存したり、投稿の予約したり、リアクションの受け入れ設定とか…なんか色々できるで。"
|
||||
submit_description: "ノートを投稿するときはここ押してな。Ctrl + Enter / Cmd + Enter でも投稿できるで。"
|
||||
_placeholders:
|
||||
a: "いまどないしとるん?"
|
||||
b: "何かあったん?"
|
||||
@@ -2533,6 +2575,8 @@ _notification:
|
||||
youReceivedFollowRequest: "フォロー許可してほしいみたいやな"
|
||||
yourFollowRequestAccepted: "フォローさせてもろたで"
|
||||
pollEnded: "アンケートの結果が出たみたいや"
|
||||
scheduledNotePosted: "予約ノートが投稿されたで"
|
||||
scheduledNotePostFailed: "予約ノート投稿できんかったで"
|
||||
newNote: "さらの投稿"
|
||||
unreadAntennaNote: "アンテナ {name}"
|
||||
roleAssigned: "ロールが付与されたで"
|
||||
@@ -2999,6 +3043,7 @@ _uploader:
|
||||
maxFileSizeIsX: "アップロードできるファイルサイズは{x}までやで。"
|
||||
tip: "ファイルはまだアップロードされてへんで。このダイアログで、アップロードする前に確認・リネーム・圧縮・クロッピングとかをできるで。準備が出来たら、「アップロード」ボタンを押してアップロードしてな。"
|
||||
_clientPerformanceIssueTip:
|
||||
title: "バッテリーようさん食うなぁと思ったら"
|
||||
makeSureDisabledAdBlocker: "アドブロッカーを切ってみてや"
|
||||
makeSureDisabledAdBlocker_description: "アドブロッカーはパフォーマンスに影響があるかもしれへん。OSの機能とかブラウザの機能・アドオンとかでアドブロッカーが有効になってないか確認してや。"
|
||||
makeSureDisabledCustomCss: "カスタムCSSを無効にしてみてや"
|
||||
@@ -3022,8 +3067,10 @@ _watermarkEditor:
|
||||
image: "画像"
|
||||
advanced: "高度"
|
||||
angle: "角度"
|
||||
failedToLoadImage: "あかん、画像読み込まれへんわ"
|
||||
_imageEffector:
|
||||
discardChangesConfirm: "変更をせんで終わるか?"
|
||||
failedToLoadImage: "あかん、画像読み込まれへんわ"
|
||||
_fxProps:
|
||||
angle: "角度"
|
||||
scale: "大きさ"
|
||||
@@ -3040,4 +3087,5 @@ _drafts:
|
||||
noDrafts: "下書きはあらへん"
|
||||
_qr:
|
||||
showTabTitle: "表示"
|
||||
shareText: "Fediverseでフォローしてな!"
|
||||
raw: "テキスト"
|
||||
|
||||
@@ -57,6 +57,10 @@ searchByGoogle: "Nadi"
|
||||
file: "Ifuyla"
|
||||
account: "Imiḍan"
|
||||
replies: "Err"
|
||||
_imageFrameEditor:
|
||||
font: "Tasefsit"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Yeṭṭafaṛ-ik·em-id"
|
||||
|
||||
@@ -651,6 +651,9 @@ renotes: "리노트"
|
||||
attach: "옇기"
|
||||
surrender: "아이예"
|
||||
information: "정보"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "파일 이럼"
|
||||
_chat:
|
||||
invitations: "초대하기"
|
||||
noHistory: "기록이 없십니다"
|
||||
|
||||
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "업로드가 완료될 때까지 시간이 소요될
|
||||
uploadNFiles: "{n}개의 파일을 업로"
|
||||
explore: "둘러보기"
|
||||
messageRead: "읽음"
|
||||
readAllChatMessages: "모든 메시지를 읽은 상태로 표시"
|
||||
noMoreHistory: "이것보다 과거의 기록이 없습니다"
|
||||
startChat: "채팅을 시작하기"
|
||||
nUsersRead: "{n}명이 읽음"
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "푸시 알림이 이미 켜져 있습니다"
|
||||
pushNotificationNotSupported: "브라우저나 서버에서 푸시 알림이 지원되지 않습니다"
|
||||
sendPushNotificationReadMessage: "푸시 알림이나 메시지를 읽은 뒤 푸시 알림을 삭제"
|
||||
sendPushNotificationReadMessageCaption: "「{emptyPushNotificationMessage}」이라는 알림이 잠깐 표시됩니다. 기기의 전력 소비량이 증가할 수 있습니다."
|
||||
pleaseAllowPushNotification: "브라우저의 알림 설정을 허가해 주십시오."
|
||||
browserPushNotificationDisabled: "알림 송신 권한 얻기에 실패했습니다."
|
||||
browserPushNotificationDisabledDescription: "{serverName}에서의 알림 송신 권한이 없습니다. 브라우저의 설정에서 알림을 허가해 다시 시도해 주십시오."
|
||||
windowMaximize: "최대화"
|
||||
windowMinimize: "최소화"
|
||||
windowRestore: "복구"
|
||||
@@ -1396,6 +1400,50 @@ scheduled: "예약"
|
||||
widgets: "위젯"
|
||||
deviceInfo: "장치 정보"
|
||||
deviceInfoDescription: "기술적 문의의 경우 아래의 정보를 병기하면 문제의 해결에 도움이 됩니다."
|
||||
youAreAdmin: "당신은 관리자입니다."
|
||||
frame: "프레임"
|
||||
presets: "프리셋"
|
||||
zeroPadding: "0으로 채우기"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "파일 설명"
|
||||
filename: "파일명"
|
||||
filename_without_ext: "확장자가 없는 파일명"
|
||||
year: "촬영한 해"
|
||||
month: "촬영한 달"
|
||||
day: "촬영한 날"
|
||||
hour: "촬영한 시각(시)"
|
||||
minute: "촬영한 시각(분)"
|
||||
second: "촬영한 시각(초)"
|
||||
camera_model: "카메라 이름"
|
||||
camera_lens_model: "렌즈 이름"
|
||||
camera_mm: "초점 거리"
|
||||
camera_mm_35: "초점 거리(35m판 환산)"
|
||||
camera_f: "조리개 조절"
|
||||
camera_s: "셔터 속도"
|
||||
camera_iso: "ISO 감도"
|
||||
gps_lat: "위도"
|
||||
gps_long: "경도"
|
||||
_imageFrameEditor:
|
||||
title: "프레임 편집"
|
||||
tip: "이미지에 프레임이나 메타 데이터를 포함한 라벨을 추가해 장식할 수 있습니다."
|
||||
header: "헤더"
|
||||
footer: "꼬리말"
|
||||
borderThickness: "테두리의 폭"
|
||||
labelThickness: "라벨의 폭"
|
||||
labelScale: "라벨의 스케일"
|
||||
centered: "중앙 정렬"
|
||||
captionMain: "캡션(대)"
|
||||
captionSub: "캡션(소)"
|
||||
availableVariables: "이용 가능한 변수"
|
||||
withQrCode: "QR 코드"
|
||||
backgroundColor: "배경색"
|
||||
textColor: "글꼴 색상"
|
||||
font: "폰트"
|
||||
fontSerif: "명조체"
|
||||
fontSansSerif: "고딕체"
|
||||
quitWithoutSaveConfirm: "보존하지 않고 종료하시겠습니까?"
|
||||
failedToLoadImage: "이미지 로드에 실패했습니다."
|
||||
_compression:
|
||||
_quality:
|
||||
high: "고품질"
|
||||
@@ -1498,6 +1546,7 @@ _settings:
|
||||
showUrlPreview: "URL 미리보기 표시"
|
||||
showAvailableReactionsFirstInNote: "이용 가능한 리액션을 선두로 표시"
|
||||
showPageTabBarBottom: "페이지의 탭 바를 아래쪽에 표시"
|
||||
emojiPaletteBanner: "이모티콘 선택기에 고정 표시되는 프리셋을 팔레트로 등록하거나 선택기의 표시 방법을 커스터마이징할 수 있습니다."
|
||||
_chat:
|
||||
showSenderName: "발신자 이름 표시"
|
||||
sendOnEnter: "엔터로 보내기"
|
||||
@@ -1515,6 +1564,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "자동 백업을 활성화하려면 프로필 이름을 설정해야 합니다."
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "이 장치에서 설정 자동 백업이 활성화되어 있지 않습니다."
|
||||
backupFound: "설정 백업이 발견되었습니다"
|
||||
forceBackup: "설정 강제 백업"
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "콘텐츠 열람을 위해 로그인을 필수로 설정하기"
|
||||
requireSigninToViewContentsDescription1: "자신이 작성한 모든 노트 등의 콘텐츠를 보기 위해 로그인을 필수로 설정합니다. 크롤러가 정보 수집하는 것을 방지하는 효과를 기대할 수 있습니다."
|
||||
@@ -2530,6 +2580,20 @@ _postForm:
|
||||
replyPlaceholder: "이 노트에 답글..."
|
||||
quotePlaceholder: "이 노트를 인용..."
|
||||
channelPlaceholder: "채널에 게시하기..."
|
||||
showHowToUse: "입력란의 설명 표시"
|
||||
_howToUse:
|
||||
content_title: "본문"
|
||||
content_description: "게시할 내용을 입력합니다."
|
||||
toolbar_title: "도구 모음"
|
||||
toolbar_description: "파일이나 설문의 첨부, 주석이나 해시태그 설정, 이모티콘이나 멘션의 삽입 등을 할 수 있습니다."
|
||||
account_title: "계정 메뉴"
|
||||
account_description: "게시할 계정을 교체하거나, 계정에 보존한 초안 및 예약 게시물을 목록으로 볼 수 있습니다."
|
||||
visibility_title: "공개 범위"
|
||||
visibility_description: "노트 공개 범위의 설정을 할 수 있습니다."
|
||||
menu_title: "메뉴"
|
||||
menu_description: "초안의 보존, 게시 예약, 리액션의 설정 등 그 외의 액션을 할 수 있습니다."
|
||||
submit_title: "게시 버튼"
|
||||
submit_description: "노트를 게시합니다. Ctrl + Enter / Cmd + Enter로도 게시할 수 있습니다."
|
||||
_placeholders:
|
||||
a: "지금 무엇을 하고 있나요?"
|
||||
b: "무슨 일이 일어나고 있나요?"
|
||||
@@ -2807,6 +2871,8 @@ _abuseReport:
|
||||
notifiedWebhook: "사용할 Webhook"
|
||||
deleteConfirm: "수신자를 삭제하시겠습니까?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "작업 대기열 비우기"
|
||||
promoteQueue: "큐의 작업을 재시도"
|
||||
createRole: "역할 생성"
|
||||
deleteRole: "역할 삭제"
|
||||
updateRole: "역할 수정"
|
||||
@@ -3223,11 +3289,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "서브 물방울의 크기"
|
||||
polkadotSubDotDivisions: "서브 물방울의 수"
|
||||
leaveBlankToAccountUrl: "빈칸일 경우 계정의 URL로 됩니다."
|
||||
failedToLoadImage: "이미지 로딩에 실패했습니다."
|
||||
_imageEffector:
|
||||
title: "이펙트"
|
||||
addEffect: "이펙트를 추가"
|
||||
discardChangesConfirm: "변경을 취소하고 종료하시겠습니까?"
|
||||
nothingToConfigure: "설정 항목이 없습니다."
|
||||
failedToLoadImage: "이미지 로딩에 실패했습니다."
|
||||
_fxs:
|
||||
chromaticAberration: "색수차"
|
||||
glitch: "글리치"
|
||||
|
||||
@@ -393,6 +393,9 @@ file: "ໄຟລ໌"
|
||||
replies: "ຕອບກັບ"
|
||||
renotes: "Renote"
|
||||
information: "ກ່ຽວກັບ"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "ຊື່ໄຟລ໌"
|
||||
_chat:
|
||||
invitations: "ເຊີນ"
|
||||
noHistory: "ບໍ່ມີປະຫວັດ"
|
||||
@@ -434,6 +437,9 @@ _visibility:
|
||||
home: "ໜ້າຫຼັກ"
|
||||
followers: "ຜູ້ຕິດຕາມ"
|
||||
specified: "ໂພສ Direct note"
|
||||
_postForm:
|
||||
_howToUse:
|
||||
menu_title: "ເມນູ"
|
||||
_profile:
|
||||
name: "ຊື່"
|
||||
username: "ຊື່ຜູ້ໃຊ້"
|
||||
|
||||
@@ -970,6 +970,9 @@ renotes: "Herdelen"
|
||||
followingOrFollower: "Gevolgd of volger"
|
||||
confirmShowRepliesAll: "Dit is een onomkeerbare operatie. Weet je zeker dat reacties op anderen van iedereen die je volgt, wil weergeven in je tijdlijn?"
|
||||
information: "Over"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Bestandsnaam"
|
||||
_chat:
|
||||
invitations: "Uitnodigen"
|
||||
noHistory: "Geen geschiedenis gevonden"
|
||||
@@ -1020,6 +1023,10 @@ _visibility:
|
||||
home: "Startpagina"
|
||||
followers: "Volgers"
|
||||
specified: "Directe notities"
|
||||
_postForm:
|
||||
_howToUse:
|
||||
visibility_title: "Zichtbaarheid"
|
||||
menu_title: "Menu"
|
||||
_profile:
|
||||
name: "Naam"
|
||||
username: "Gebruikersnaam"
|
||||
|
||||
@@ -463,6 +463,12 @@ surrender: "Avbryt"
|
||||
information: "Informasjon"
|
||||
inMinutes: "Minutter"
|
||||
inDays: "Dager"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Filnavn"
|
||||
_imageFrameEditor:
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "Inviter"
|
||||
members: "Medlemmer"
|
||||
@@ -650,6 +656,8 @@ _visibility:
|
||||
home: "Hjem"
|
||||
followers: "Følgere"
|
||||
_postForm:
|
||||
_howToUse:
|
||||
menu_title: "Meny"
|
||||
_placeholders:
|
||||
a: "Hva skjer?"
|
||||
_profile:
|
||||
|
||||
@@ -1043,6 +1043,15 @@ information: "Informacje"
|
||||
inMinutes: "minuta"
|
||||
inDays: "dzień"
|
||||
widgets: "Widżety"
|
||||
presets: "Konfiguracja"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Nazwa pliku"
|
||||
_imageFrameEditor:
|
||||
header: "Nagłówek"
|
||||
font: "Czcionka"
|
||||
fontSerif: "Szeryfowa"
|
||||
fontSansSerif: "Bezszeryfowa"
|
||||
_chat:
|
||||
invitations: "Zaproś"
|
||||
noHistory: "Brak historii"
|
||||
@@ -1393,6 +1402,9 @@ _postForm:
|
||||
replyPlaceholder: "Odpowiedz na ten wpis..."
|
||||
quotePlaceholder: "Zacytuj ten wpis…"
|
||||
channelPlaceholder: "Publikuj na kanale..."
|
||||
_howToUse:
|
||||
visibility_title: "Widoczność"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Co się dzieje?"
|
||||
b: "Co się wydarzyło?"
|
||||
|
||||
@@ -1390,6 +1390,17 @@ scheduledToPostOnX: "A nota está agendada para {x}"
|
||||
schedule: "Agendar"
|
||||
scheduled: "Agendado"
|
||||
widgets: "Widgets"
|
||||
presets: "Predefinições"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Nome do Ficheiro"
|
||||
_imageFrameEditor:
|
||||
header: "Cabeçalho"
|
||||
withQrCode: "Código QR"
|
||||
font: "Fonte"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "Descartar mudanças?"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "Qualidade alta"
|
||||
@@ -2522,6 +2533,9 @@ _postForm:
|
||||
replyPlaceholder: "Responder a essa nota..."
|
||||
quotePlaceholder: "Citar essa nota..."
|
||||
channelPlaceholder: "Postar em canal..."
|
||||
_howToUse:
|
||||
visibility_title: "Visibilidade"
|
||||
menu_title: "Menu\n"
|
||||
_placeholders:
|
||||
a: "Como vão as coisas?"
|
||||
b: "O que está rolando por aí?"
|
||||
|
||||
@@ -1215,6 +1215,10 @@ lastNDays: "Ultimele {n} zile"
|
||||
surrender: "Anulează"
|
||||
copyPreferenceId: "Copiază ID-ul preferințelor"
|
||||
information: "Despre"
|
||||
presets: "Presetate"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Nume fișier"
|
||||
_chat:
|
||||
invitations: "Invită"
|
||||
noHistory: "Nu există istoric"
|
||||
@@ -1307,6 +1311,9 @@ _postForm:
|
||||
replyPlaceholder: "Răspunde la această notă..."
|
||||
quotePlaceholder: "Citează aceasta nota..."
|
||||
channelPlaceholder: "Postează pe un canal..."
|
||||
_howToUse:
|
||||
visibility_title: "Vizibilitate"
|
||||
menu_title: "Meniu"
|
||||
_placeholders:
|
||||
a: "Ce mai faci?"
|
||||
b: "Ce se mai petrece in jurul tău?"
|
||||
|
||||
@@ -1278,6 +1278,15 @@ information: "Описание"
|
||||
inMinutes: "мин"
|
||||
inDays: "сут"
|
||||
widgets: "Виджеты"
|
||||
presets: "Шаблоны"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Имя файла"
|
||||
_imageFrameEditor:
|
||||
header: "Заголовок"
|
||||
font: "Шрифт"
|
||||
fontSerif: "Антиква (с засечками)"
|
||||
fontSansSerif: "Гротеск (без засечек)"
|
||||
_chat:
|
||||
invitations: "Пригласить"
|
||||
noHistory: "История пока пуста"
|
||||
@@ -2007,6 +2016,9 @@ _postForm:
|
||||
replyPlaceholder: "Ответ на заметку..."
|
||||
quotePlaceholder: "Пояснение к цитате..."
|
||||
channelPlaceholder: "Отправить в канал"
|
||||
_howToUse:
|
||||
visibility_title: "Видимость"
|
||||
menu_title: "Меню"
|
||||
_placeholders:
|
||||
a: "Как дела?"
|
||||
b: "Что интересного вокруг?"
|
||||
|
||||
@@ -916,6 +916,14 @@ information: "Informácie"
|
||||
inMinutes: "min"
|
||||
inDays: "dní"
|
||||
widgets: "Widgety"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Názov súboru"
|
||||
_imageFrameEditor:
|
||||
header: "Hlavička"
|
||||
font: "Písmo"
|
||||
fontSerif: "Pätkové"
|
||||
fontSansSerif: "Bezpätkové"
|
||||
_chat:
|
||||
invitations: "Pozvať"
|
||||
noHistory: "Žiadna história"
|
||||
@@ -1264,6 +1272,9 @@ _postForm:
|
||||
replyPlaceholder: "Odpoveď na túto poznámku..."
|
||||
quotePlaceholder: "Citovanie tejto poznámky..."
|
||||
channelPlaceholder: "Poslať do kanála..."
|
||||
_howToUse:
|
||||
visibility_title: "Viditeľnosť"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Čo máte v pláne?"
|
||||
b: "Čo sa deje?"
|
||||
|
||||
@@ -559,6 +559,9 @@ tryAgain: "Försök igen senare"
|
||||
signinWithPasskey: "Logga in med nyckel"
|
||||
unknownWebAuthnKey: "Okänd nyckel"
|
||||
information: "Om"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Filnamn"
|
||||
_chat:
|
||||
invitations: "Inbjudan"
|
||||
members: "Medlemmar"
|
||||
@@ -647,6 +650,9 @@ _visibility:
|
||||
home: "Hem"
|
||||
followers: "Följare"
|
||||
specified: "Direktnoter"
|
||||
_postForm:
|
||||
_howToUse:
|
||||
menu_title: "Meny"
|
||||
_profile:
|
||||
name: "Namn"
|
||||
username: "Användarnamn"
|
||||
|
||||
@@ -1390,6 +1390,17 @@ scheduledToPostOnX: "มีการกำหนดเวลาให้โพ
|
||||
schedule: "กำหนดเวลา"
|
||||
scheduled: "กำหนดเวลา"
|
||||
widgets: "วิดเจ็ต"
|
||||
presets: "พรีเซ็ต"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "ชื่อไฟล์"
|
||||
_imageFrameEditor:
|
||||
header: "ส่วนหัว"
|
||||
withQrCode: "QR โค้ด"
|
||||
font: "แบบอักษร"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "ต้องการออกโดยไม่บันทึกหรือไม่?"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "คุณภาพสูง"
|
||||
@@ -2522,6 +2533,9 @@ _postForm:
|
||||
replyPlaceholder: "ตอบกลับโน้ตนี้..."
|
||||
quotePlaceholder: "อ้างโน้ตนี้..."
|
||||
channelPlaceholder: "โพสต์ลงช่อง..."
|
||||
_howToUse:
|
||||
visibility_title: "การมองเห็น"
|
||||
menu_title: "เมนู"
|
||||
_placeholders:
|
||||
a: "ตอนนี้เป็นยังไงบ้าง?"
|
||||
b: "มีอะไรเกิดขึ้นหรือเปล่า?"
|
||||
|
||||
@@ -1379,6 +1379,16 @@ customCssIsDisabledBecauseSafeMode: "Güvenli mod etkin olduğu için özel CSS
|
||||
themeIsDefaultBecauseSafeMode: "Güvenli mod etkinken, varsayılan tema kullanılır. Güvenli modu devre dışı bırakmak bu değişiklikleri geri alır."
|
||||
thankYouForTestingBeta: "Beta sürümünü test ettiğin için teşekkür ederiz!"
|
||||
widgets: "Widget'lar"
|
||||
presets: "Ön ayar"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Dosya adı"
|
||||
_imageFrameEditor:
|
||||
header: "Başlık"
|
||||
font: "Yazı tipi"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
quitWithoutSaveConfirm: "Kaydedilmemiş değişiklikleri silmek ister misin?"
|
||||
_order:
|
||||
newest: "Önce yeni"
|
||||
oldest: "Önce eski"
|
||||
@@ -2500,6 +2510,9 @@ _postForm:
|
||||
replyPlaceholder: "Bu notu yanıtla..."
|
||||
quotePlaceholder: "Bu notu alıntı yap..."
|
||||
channelPlaceholder: "Bir kanala gönder..."
|
||||
_howToUse:
|
||||
visibility_title: "Görünürlük"
|
||||
menu_title: "Menü"
|
||||
_placeholders:
|
||||
a: "Ne yapıyorsun?"
|
||||
b: "Çevrende neler oluyor?"
|
||||
|
||||
@@ -922,6 +922,14 @@ information: "Інформація"
|
||||
inMinutes: "х"
|
||||
inDays: "д"
|
||||
widgets: "Віджети"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Ім'я файлу"
|
||||
_imageFrameEditor:
|
||||
header: "Заголовок"
|
||||
font: "Шрифт"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans serif"
|
||||
_chat:
|
||||
invitations: "Запросити"
|
||||
noHistory: "Історія порожня"
|
||||
@@ -1462,6 +1470,9 @@ _postForm:
|
||||
replyPlaceholder: "Відповідь на цю нотатку..."
|
||||
quotePlaceholder: "Прокоментуйте цю нотатку..."
|
||||
channelPlaceholder: "Опублікувати в каналі"
|
||||
_howToUse:
|
||||
visibility_title: "Видимість"
|
||||
menu_title: "Меню"
|
||||
_placeholders:
|
||||
a: "Чим займаєтесь?"
|
||||
b: "Що відбувається навколо вас?"
|
||||
|
||||
@@ -837,6 +837,14 @@ replies: "Javob berish"
|
||||
renotes: "Qayta qayd etish"
|
||||
flip: "Teskari"
|
||||
information: "Haqida"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Fayl nomi"
|
||||
_imageFrameEditor:
|
||||
header: "Sarlavha"
|
||||
font: "Shrift"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "Taklif qilish"
|
||||
noHistory: "Tarix yo'q"
|
||||
@@ -964,6 +972,10 @@ _visibility:
|
||||
home: "Bosh sahifa"
|
||||
followers: "Obunachilar"
|
||||
specified: "Bevosita"
|
||||
_postForm:
|
||||
_howToUse:
|
||||
visibility_title: "Ko'rinishi"
|
||||
menu_title: "Menyu"
|
||||
_profile:
|
||||
name: "Ism"
|
||||
username: "Foydalanuvchi nomi"
|
||||
|
||||
@@ -1223,6 +1223,15 @@ migrateOldSettings_description: "Thông thường, quá trình này diễn ra t
|
||||
inMinutes: "phút"
|
||||
inDays: "ngày"
|
||||
widgets: "Tiện ích"
|
||||
presets: "Mẫu thiết lập"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
filename: "Tên tập tin"
|
||||
_imageFrameEditor:
|
||||
header: "Ảnh bìa"
|
||||
font: "Phông chữ"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
_chat:
|
||||
invitations: "Mời"
|
||||
noHistory: "Không có dữ liệu"
|
||||
@@ -1859,6 +1868,9 @@ _postForm:
|
||||
replyPlaceholder: "Trả lời tút này"
|
||||
quotePlaceholder: "Trích dẫn tút này"
|
||||
channelPlaceholder: "Đăng lên một kênh"
|
||||
_howToUse:
|
||||
visibility_title: "Hiển thị"
|
||||
menu_title: "Menu"
|
||||
_placeholders:
|
||||
a: "Bạn đang định làm gì?"
|
||||
b: "Hôm nay bạn có gì vui?"
|
||||
|
||||
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "上传可能需要一些时间完成。"
|
||||
uploadNFiles: "上传 {n} 个文件"
|
||||
explore: "发现"
|
||||
messageRead: "已读"
|
||||
readAllChatMessages: "将所有消息标记为已读"
|
||||
noMoreHistory: "没有更多的历史记录"
|
||||
startChat: "开始聊天"
|
||||
nUsersRead: "{n}人已读"
|
||||
@@ -1396,6 +1397,44 @@ scheduled: "定时"
|
||||
widgets: "小工具"
|
||||
deviceInfo: "设备信息"
|
||||
deviceInfoDescription: "咨询技术问题时,将以下信息一并发送有助于解决问题。"
|
||||
youAreAdmin: "你是管理员"
|
||||
presets: "预设值"
|
||||
zeroPadding: "填充 0"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "文件标题"
|
||||
filename: "文件名称"
|
||||
filename_without_ext: "无扩展文件名"
|
||||
year: "拍摄年"
|
||||
month: "拍摄月"
|
||||
day: "拍摄日"
|
||||
hour: "拍摄时间(时)"
|
||||
minute: "拍摄时间(分)"
|
||||
second: "拍摄时间(秒)"
|
||||
camera_model: "相机名称"
|
||||
camera_lens_model: "镜头型号"
|
||||
camera_mm: "焦距"
|
||||
camera_f: "光圈"
|
||||
camera_s: "快门速度"
|
||||
camera_iso: "ISO"
|
||||
gps_lat: "纬度"
|
||||
gps_long: "经度"
|
||||
_imageFrameEditor:
|
||||
header: "顶栏"
|
||||
footer: "底部"
|
||||
labelScale: "标签比例"
|
||||
centered: "居中"
|
||||
captionMain: "标题(大)"
|
||||
captionSub: "标题(小)"
|
||||
availableVariables: "可用变量"
|
||||
withQrCode: "二维码"
|
||||
backgroundColor: "背景色"
|
||||
textColor: "文字色"
|
||||
font: "字体"
|
||||
fontSerif: "衬线字体"
|
||||
fontSansSerif: "无衬线字体"
|
||||
quitWithoutSaveConfirm: "不保存就退出吗?"
|
||||
failedToLoadImage: "图片加载失败"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "高质量"
|
||||
@@ -1498,6 +1537,7 @@ _settings:
|
||||
showUrlPreview: "显示 URL 预览"
|
||||
showAvailableReactionsFirstInNote: "在顶部显示可用的回应"
|
||||
showPageTabBarBottom: "在下方显示页面标签栏"
|
||||
emojiPaletteBanner: "可以将固定显示表情符号选择器的预设注册至调色板,也可以自定义表情符号选择器的显示方式。"
|
||||
_chat:
|
||||
showSenderName: "显示发送者的名字"
|
||||
sendOnEnter: "回车键发送"
|
||||
@@ -2530,6 +2570,20 @@ _postForm:
|
||||
replyPlaceholder: "回复这个帖子..."
|
||||
quotePlaceholder: "引用这个帖子..."
|
||||
channelPlaceholder: "发布到频道…"
|
||||
showHowToUse: "显示窗口说明"
|
||||
_howToUse:
|
||||
content_title: "正文"
|
||||
content_description: "在此输入要发布的内容。"
|
||||
toolbar_title: "工具栏"
|
||||
toolbar_description: "可在此添加文件和投票、设置注释和话题标签、插入表情符号和提及等。"
|
||||
account_title: "账号菜单"
|
||||
account_description: "可在此切换发帖用的账号、查看账户下保存的草稿及定时发送帖。"
|
||||
visibility_title: "可见性"
|
||||
visibility_description: "可在此设置帖子的公开范围。"
|
||||
menu_title: "菜单"
|
||||
menu_description: "可在此进行保存草稿、设置定时发帖、设置回应等其它操作。"
|
||||
submit_title: "发帖按钮"
|
||||
submit_description: "发布帖子。也可用 Ctrl + Enter / Cmd + Enter 来发帖。"
|
||||
_placeholders:
|
||||
a: "现在怎么样?"
|
||||
b: "想好发些什么了吗?"
|
||||
@@ -3223,11 +3277,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "副波点的大小"
|
||||
polkadotSubDotDivisions: "副波点的数量"
|
||||
leaveBlankToAccountUrl: "留空则为账户 URL"
|
||||
failedToLoadImage: "图片加载失败"
|
||||
_imageEffector:
|
||||
title: "效果"
|
||||
addEffect: "添加效果"
|
||||
discardChangesConfirm: "丢弃当前设置并退出?"
|
||||
nothingToConfigure: "还没有设置"
|
||||
failedToLoadImage: "图片加载失败"
|
||||
_fxs:
|
||||
chromaticAberration: "色差"
|
||||
glitch: "故障"
|
||||
|
||||
+70
-1
@@ -302,6 +302,7 @@ uploadFromUrlMayTakeTime: "還需要一些時間才能完成上傳。"
|
||||
uploadNFiles: "上傳了 {n} 個檔案"
|
||||
explore: "探索"
|
||||
messageRead: "已讀"
|
||||
readAllChatMessages: "將所有訊息標記為已讀"
|
||||
noMoreHistory: "沒有更多歷史紀錄"
|
||||
startChat: "開始聊天"
|
||||
nUsersRead: "{n} 人已讀"
|
||||
@@ -1022,6 +1023,9 @@ pushNotificationAlreadySubscribed: "推播通知啟用中"
|
||||
pushNotificationNotSupported: "瀏覽器或伺服器不支援推播通知"
|
||||
sendPushNotificationReadMessage: "如果已閱讀通知與訊息,就刪除推播通知"
|
||||
sendPushNotificationReadMessageCaption: "可能會導致裝置的電池消耗量增加。"
|
||||
pleaseAllowPushNotification: "請允許瀏覽器的通知設定"
|
||||
browserPushNotificationDisabled: "取得通知發送權限失敗"
|
||||
browserPushNotificationDisabledDescription: "您沒有權限從 {serverName} 發送通知。請在瀏覽器設定中允許通知,然後再試一次。"
|
||||
windowMaximize: "最大化"
|
||||
windowMinimize: "最小化"
|
||||
windowRestore: "復原"
|
||||
@@ -1172,6 +1176,7 @@ installed: "已安裝"
|
||||
branding: "品牌宣傳"
|
||||
enableServerMachineStats: "公佈伺服器的機器資訊"
|
||||
enableIdenticonGeneration: "啟用生成使用者的 Identicon "
|
||||
showRoleBadgesOfRemoteUsers: "顯示授予遠端使用者的角色徽章"
|
||||
turnOffToImprovePerformance: "關閉時會提高性能。"
|
||||
createInviteCode: "建立邀請碼"
|
||||
createWithOptions: "使用選項建立"
|
||||
@@ -1395,6 +1400,50 @@ scheduled: "排定"
|
||||
widgets: "小工具"
|
||||
deviceInfo: "硬體資訊"
|
||||
deviceInfoDescription: "在提出技術性諮詢時,若能同時提供以下資訊,將有助於解決問題。"
|
||||
youAreAdmin: "您是管理員"
|
||||
frame: "邊框"
|
||||
presets: "預設值"
|
||||
zeroPadding: "補零"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
caption: "檔案標題"
|
||||
filename: "檔案名稱"
|
||||
filename_without_ext: "無副檔名的檔案名稱"
|
||||
year: "拍攝年份"
|
||||
month: "拍攝月份"
|
||||
day: "拍攝日期"
|
||||
hour: "拍攝時間(小時)"
|
||||
minute: "拍攝時間(分鐘)"
|
||||
second: "拍攝時間(秒)"
|
||||
camera_model: "相機名稱"
|
||||
camera_lens_model: "鏡頭型號"
|
||||
camera_mm: "焦距"
|
||||
camera_mm_35: "焦距(換算為 35mm 底片等效焦距)"
|
||||
camera_f: "光圈"
|
||||
camera_s: "快門速度"
|
||||
camera_iso: "ISO 感光度"
|
||||
gps_lat: "緯度"
|
||||
gps_long: "經度"
|
||||
_imageFrameEditor:
|
||||
title: "編輯邊框"
|
||||
tip: "可以在圖片上添加包含邊框或 EXIF 的標籤來裝飾圖片。"
|
||||
header: "標題"
|
||||
footer: "頁尾"
|
||||
borderThickness: "邊框寬度"
|
||||
labelThickness: "標籤寬度"
|
||||
labelScale: "標籤縮放比例"
|
||||
centered: "置中對齊"
|
||||
captionMain: "標題文字(大)"
|
||||
captionSub: "標題文字(小)"
|
||||
availableVariables: "可使用的變數"
|
||||
withQrCode: "二維條碼"
|
||||
backgroundColor: "背景顏色"
|
||||
textColor: "文字顏色"
|
||||
font: "字型"
|
||||
fontSerif: "襯線體"
|
||||
fontSansSerif: "無襯線體"
|
||||
quitWithoutSaveConfirm: "不儲存就退出嗎?"
|
||||
failedToLoadImage: "圖片載入失敗"
|
||||
_compression:
|
||||
_quality:
|
||||
high: "高品質"
|
||||
@@ -1497,6 +1546,7 @@ _settings:
|
||||
showUrlPreview: "顯示網址預覽"
|
||||
showAvailableReactionsFirstInNote: "將可用的反應顯示在頂部"
|
||||
showPageTabBarBottom: "在底部顯示頁面的標籤列"
|
||||
emojiPaletteBanner: "可以將固定顯示在表情符號選擇器的預設項目註冊為調色盤,或者自訂選擇器的顯示方式。"
|
||||
_chat:
|
||||
showSenderName: "顯示發送者的名稱"
|
||||
sendOnEnter: "按下 Enter 發送訊息"
|
||||
@@ -1514,6 +1564,7 @@ _preferencesBackup:
|
||||
youNeedToNameYourProfileToEnableAutoBackup: "要啟用自動備份,必須設定檔案名稱。"
|
||||
autoPreferencesBackupIsNotEnabledForThisDevice: "此裝置未啟用自動備份設定。"
|
||||
backupFound: "找到設定的備份"
|
||||
forceBackup: "強制備份設定"
|
||||
_accountSettings:
|
||||
requireSigninToViewContents: "須登入以顯示內容"
|
||||
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
|
||||
@@ -2529,6 +2580,20 @@ _postForm:
|
||||
replyPlaceholder: "回覆此貼文..."
|
||||
quotePlaceholder: "引用此貼文..."
|
||||
channelPlaceholder: "發佈到頻道"
|
||||
showHowToUse: "顯示表單說明"
|
||||
_howToUse:
|
||||
content_title: "內文"
|
||||
content_description: "請輸入要發布的內容。"
|
||||
toolbar_title: "工具列"
|
||||
toolbar_description: "可以附加檔案或票選活動、設定註解與標籤、插入表情符號或提及等。"
|
||||
account_title: "帳號選單"
|
||||
account_description: "可以切換要發布的帳號,並查看該帳號所儲存的草稿與預約發布列表。"
|
||||
visibility_title: "可見性"
|
||||
visibility_description: "可以設定貼文的公開範圍。"
|
||||
menu_title: "選單"
|
||||
menu_description: "可以進行其他操作,例如儲存為草稿、預約發佈貼文、或設定反應等。\n"
|
||||
submit_title: "貼文按鈕"
|
||||
submit_description: "發布貼文。也可以使用 Ctrl + Enter 或 Cmd + Enter 來發布。"
|
||||
_placeholders:
|
||||
a: "今天過得如何?"
|
||||
b: "有什麼新鮮事嗎?"
|
||||
@@ -2638,7 +2703,7 @@ _pages:
|
||||
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
|
||||
font: "字型"
|
||||
fontSerif: "襯線體"
|
||||
fontSansSerif: "黑體"
|
||||
fontSansSerif: "無襯線體"
|
||||
eyeCatchingImageSet: "設定封面影像"
|
||||
eyeCatchingImageRemove: "刪除封面影像"
|
||||
chooseBlock: "新增方塊"
|
||||
@@ -2806,6 +2871,8 @@ _abuseReport:
|
||||
notifiedWebhook: "使用的 Webhook"
|
||||
deleteConfirm: "確定要刪除通知對象嗎?"
|
||||
_moderationLogTypes:
|
||||
clearQueue: "清除佇列"
|
||||
promoteQueue: "重新嘗試排程中的工作"
|
||||
createRole: "新增角色"
|
||||
deleteRole: "刪除角色 "
|
||||
updateRole: "更新角色設定"
|
||||
@@ -3222,11 +3289,13 @@ _watermarkEditor:
|
||||
polkadotSubDotRadius: "子圓點的尺寸"
|
||||
polkadotSubDotDivisions: "子圓點的數量"
|
||||
leaveBlankToAccountUrl: "若留空則使用帳戶的 URL"
|
||||
failedToLoadImage: "圖片載入失敗"
|
||||
_imageEffector:
|
||||
title: "特效"
|
||||
addEffect: "新增特效"
|
||||
discardChangesConfirm: "捨棄更改並退出嗎?"
|
||||
nothingToConfigure: "無可設定的項目"
|
||||
failedToLoadImage: "圖片載入失敗"
|
||||
_fxs:
|
||||
chromaticAberration: "色差"
|
||||
glitch: "異常雜訊效果"
|
||||
|
||||
+15
-13
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "2025.11.0-alpha.2",
|
||||
"version": "2025.11.0-beta.0",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
},
|
||||
"packageManager": "pnpm@10.18.2",
|
||||
"packageManager": "pnpm@10.20.0",
|
||||
"workspaces": [
|
||||
"packages/frontend-shared",
|
||||
"packages/frontend",
|
||||
@@ -53,30 +53,31 @@
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano": "7.1.1",
|
||||
"esbuild": "0.25.10",
|
||||
"cssnano": "7.1.2",
|
||||
"esbuild": "0.25.11",
|
||||
"execa": "9.6.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"glob": "11.0.3",
|
||||
"ignore-walk": "8.0.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"postcss": "8.5.6",
|
||||
"tar": "7.5.1",
|
||||
"tar": "7.5.2",
|
||||
"terser": "5.44.0",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.39.0",
|
||||
"@misskey-dev/eslint-plugin": "2.1.0",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/node": "24.9.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"@types/node": "24.9.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"cross-env": "10.1.0",
|
||||
"cypress": "15.4.0",
|
||||
"eslint": "9.37.0",
|
||||
"globals": "16.4.0",
|
||||
"cypress": "15.5.0",
|
||||
"eslint": "9.39.0",
|
||||
"globals": "16.5.0",
|
||||
"ncp": "2.0.0",
|
||||
"pnpm": "10.18.2",
|
||||
"pnpm": "10.20.0",
|
||||
"start-server-and-test": "2.1.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
@@ -87,7 +88,8 @@
|
||||
"@aiscript-dev/aiscript-languageserver": "-"
|
||||
},
|
||||
"ignoredBuiltDependencies": [
|
||||
"@sentry-internal/node-cpu-profiler"
|
||||
"@sentry-internal/node-cpu-profiler",
|
||||
"exifreader"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,17 +39,17 @@
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-android-arm64": "1.3.11",
|
||||
"@swc/core-darwin-arm64": "1.13.20",
|
||||
"@swc/core-darwin-x64": "1.13.20",
|
||||
"@swc/core-darwin-arm64": "1.14.0",
|
||||
"@swc/core-darwin-x64": "1.14.0",
|
||||
"@swc/core-freebsd-x64": "1.3.11",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.13.20",
|
||||
"@swc/core-linux-arm64-gnu": "1.13.20",
|
||||
"@swc/core-linux-arm64-musl": "1.13.20",
|
||||
"@swc/core-linux-x64-gnu": "1.13.20",
|
||||
"@swc/core-linux-x64-musl": "1.13.20",
|
||||
"@swc/core-win32-arm64-msvc": "1.13.20",
|
||||
"@swc/core-win32-ia32-msvc": "1.13.20",
|
||||
"@swc/core-win32-x64-msvc": "1.13.20",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.14.0",
|
||||
"@swc/core-linux-arm64-gnu": "1.14.0",
|
||||
"@swc/core-linux-arm64-musl": "1.14.0",
|
||||
"@swc/core-linux-x64-gnu": "1.14.0",
|
||||
"@swc/core-linux-x64-musl": "1.14.0",
|
||||
"@swc/core-win32-arm64-msvc": "1.14.0",
|
||||
"@swc/core-win32-ia32-msvc": "1.14.0",
|
||||
"@swc/core-win32-x64-msvc": "1.14.0",
|
||||
"@tensorflow/tfjs": "4.22.0",
|
||||
"@tensorflow/tfjs-node": "4.22.0",
|
||||
"bufferutil": "4.0.9",
|
||||
@@ -69,31 +69,31 @@
|
||||
"utf-8-validate": "6.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.908.0",
|
||||
"@aws-sdk/lib-storage": "3.908.0",
|
||||
"@aws-sdk/client-s3": "3.922.0",
|
||||
"@aws-sdk/lib-storage": "3.922.0",
|
||||
"@discordapp/twemoji": "16.0.1",
|
||||
"@fastify/accepts": "5.0.3",
|
||||
"@fastify/cookie": "11.0.2",
|
||||
"@fastify/cors": "10.1.0",
|
||||
"@fastify/express": "4.0.2",
|
||||
"@fastify/http-proxy": "10.0.2",
|
||||
"@fastify/multipart": "9.2.1",
|
||||
"@fastify/static": "8.2.0",
|
||||
"@fastify/multipart": "9.3.0",
|
||||
"@fastify/static": "8.3.0",
|
||||
"@fastify/view": "10.0.2",
|
||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@napi-rs/canvas": "0.1.80",
|
||||
"@nestjs/common": "11.1.6",
|
||||
"@nestjs/core": "11.1.6",
|
||||
"@nestjs/testing": "11.1.6",
|
||||
"@misskey-dev/summaly": "5.2.5",
|
||||
"@napi-rs/canvas": "0.1.81",
|
||||
"@nestjs/common": "11.1.8",
|
||||
"@nestjs/core": "11.1.8",
|
||||
"@nestjs/testing": "11.1.8",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@sentry/node": "10.20.0",
|
||||
"@sentry/profiling-node": "10.20.0",
|
||||
"@sentry/node": "10.22.0",
|
||||
"@sentry/profiling-node": "10.22.0",
|
||||
"@simplewebauthn/server": "12.0.0",
|
||||
"@sinonjs/fake-timers": "11.3.1",
|
||||
"@smithy/node-http-handler": "2.5.0",
|
||||
"@swc/cli": "0.7.8",
|
||||
"@swc/core": "1.13.5",
|
||||
"@swc/core": "1.14.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@types/redis-info": "3.0.3",
|
||||
"accepts": "1.3.8",
|
||||
@@ -103,7 +103,7 @@
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"body-parser": "1.20.3",
|
||||
"bullmq": "5.61.0",
|
||||
"bullmq": "5.63.0",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "9.0.2",
|
||||
"chalk": "5.6.2",
|
||||
@@ -120,12 +120,12 @@
|
||||
"file-type": "21.0.0",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"form-data": "4.0.4",
|
||||
"got": "14.5.0",
|
||||
"happy-dom": "20.0.7",
|
||||
"got": "14.6.1",
|
||||
"happy-dom": "20.0.10",
|
||||
"hpagent": "1.2.0",
|
||||
"htmlescape": "1.1.1",
|
||||
"http-link-header": "1.1.3",
|
||||
"ioredis": "5.8.1",
|
||||
"ioredis": "5.8.2",
|
||||
"ip-cidr": "4.0.2",
|
||||
"ipaddr.js": "2.2.0",
|
||||
"is-svg": "5.1.0",
|
||||
@@ -135,7 +135,7 @@
|
||||
"jsonld": "8.3.3",
|
||||
"jsrsasign": "11.1.0",
|
||||
"juice": "11.0.3",
|
||||
"meilisearch": "0.53.0",
|
||||
"meilisearch": "0.54.0",
|
||||
"mfm-js": "0.25.0",
|
||||
"microformats-parser": "2.0.4",
|
||||
"mime-types": "2.1.35",
|
||||
@@ -145,7 +145,7 @@
|
||||
"nanoid": "5.1.6",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.3.2",
|
||||
"nodemailer": "7.0.9",
|
||||
"nodemailer": "7.0.10",
|
||||
"nsfwjs": "4.2.0",
|
||||
"oauth": "0.10.2",
|
||||
"oauth2orize": "1.12.0",
|
||||
@@ -191,16 +191,16 @@
|
||||
"devDependencies": {
|
||||
"@jest/globals": "29.7.0",
|
||||
"@nestjs/platform-express": "10.4.20",
|
||||
"@sentry/vue": "10.20.0",
|
||||
"@sentry/vue": "10.22.0",
|
||||
"@simplewebauthn/types": "12.0.0",
|
||||
"@swc/jest": "0.2.39",
|
||||
"@types/accepts": "1.3.7",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/archiver": "6.0.4",
|
||||
"@types/bcryptjs": "2.4.6",
|
||||
"@types/body-parser": "1.19.6",
|
||||
"@types/color-convert": "2.0.4",
|
||||
"@types/content-disposition": "0.5.9",
|
||||
"@types/fluent-ffmpeg": "2.1.27",
|
||||
"@types/fluent-ffmpeg": "2.1.28",
|
||||
"@types/htmlescape": "1.1.3",
|
||||
"@types/http-link-header": "1.0.7",
|
||||
"@types/jest": "29.5.14",
|
||||
@@ -210,14 +210,14 @@
|
||||
"@types/jsrsasign": "10.5.15",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/ms": "0.7.34",
|
||||
"@types/node": "24.9.1",
|
||||
"@types/nodemailer": "6.4.20",
|
||||
"@types/node": "24.9.2",
|
||||
"@types/nodemailer": "6.4.21",
|
||||
"@types/oauth": "0.9.6",
|
||||
"@types/oauth2orize": "1.11.5",
|
||||
"@types/oauth2orize-pkce": "0.1.2",
|
||||
"@types/pg": "8.15.5",
|
||||
"@types/pg": "8.15.6",
|
||||
"@types/pug": "2.0.10",
|
||||
"@types/qrcode": "1.5.5",
|
||||
"@types/qrcode": "1.5.6",
|
||||
"@types/random-seed": "0.3.5",
|
||||
"@types/ratelimiter": "3.4.6",
|
||||
"@types/rename": "1.0.7",
|
||||
@@ -231,8 +231,8 @@
|
||||
"@types/vary": "1.1.3",
|
||||
"@types/web-push": "3.6.4",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"aws-sdk-client-mock": "4.1.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface PageBody {
|
||||
variables: Array<Record<string, any>>;
|
||||
script: string;
|
||||
eyeCatchingImage?: MiDriveFile | null;
|
||||
font: string;
|
||||
font: 'serif' | 'sans-serif';
|
||||
alignCenter: boolean;
|
||||
hideTitleWhenPinned: boolean;
|
||||
}
|
||||
@@ -141,7 +141,7 @@ export class PageService {
|
||||
eyeCatchingImageId: body.eyeCatchingImage === undefined ? undefined : (body.eyeCatchingImage?.id ?? null),
|
||||
});
|
||||
|
||||
console.log("page.content", page.content);
|
||||
console.log('page.content', page.content);
|
||||
|
||||
if (body.content != null) {
|
||||
const beforeReferencedNotes = this.collectReferencedNotes(page.content);
|
||||
|
||||
@@ -133,6 +133,7 @@ export class UtilityService {
|
||||
|
||||
@bindThis
|
||||
public isFederationAllowedHost(host: string): boolean {
|
||||
if (this.isSelfHost(host)) return true;
|
||||
if (this.meta.federation === 'none') return false;
|
||||
if (this.meta.federation === 'specified' && !this.meta.federationHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`))) return false;
|
||||
if (this.isBlockedHost(this.meta.blockedHosts, host)) return false;
|
||||
|
||||
@@ -111,6 +111,7 @@ export class ChannelEntityService {
|
||||
description: channel.description,
|
||||
userId: channel.userId,
|
||||
bannerUrl: bannerFile ? this.driveFileEntityService.getPublicUrl(bannerFile) : null,
|
||||
bannerId: channel.bannerId,
|
||||
pinnedNoteIds: channel.pinnedNoteIds,
|
||||
color: channel.color,
|
||||
isArchived: channel.isArchived,
|
||||
|
||||
@@ -47,7 +47,7 @@ export class MiPage {
|
||||
@Column('varchar', {
|
||||
length: 32,
|
||||
})
|
||||
public font: string;
|
||||
public font: 'serif' | 'sans-serif';
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
|
||||
@@ -40,6 +40,11 @@ export const packedChannelSchema = {
|
||||
format: 'url',
|
||||
nullable: true, optional: false,
|
||||
},
|
||||
bannerId: {
|
||||
type: 'string',
|
||||
nullable: true, optional: false,
|
||||
format: 'id',
|
||||
},
|
||||
pinnedNoteIds: {
|
||||
type: 'array',
|
||||
nullable: false, optional: false,
|
||||
|
||||
@@ -174,6 +174,7 @@ export const packedPageSchema = {
|
||||
font: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['serif', 'sans-serif'],
|
||||
},
|
||||
script: {
|
||||
type: 'string',
|
||||
|
||||
@@ -46,7 +46,7 @@ export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', minLength: 1, maxLength: 128 },
|
||||
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
|
||||
description: { type: 'string', nullable: true, maxLength: 2048 },
|
||||
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
color: { type: 'string', minLength: 1, maxLength: 16 },
|
||||
isSensitive: { type: 'boolean', nullable: true },
|
||||
|
||||
@@ -50,7 +50,7 @@ export const paramDef = {
|
||||
properties: {
|
||||
channelId: { type: 'string', format: 'misskey:id' },
|
||||
name: { type: 'string', minLength: 1, maxLength: 128 },
|
||||
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
|
||||
description: { type: 'string', nullable: true, maxLength: 2048 },
|
||||
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
isArchived: { type: 'boolean', nullable: true },
|
||||
pinnedNoteIds: {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { jest } from '@jest/globals';
|
||||
import { describe, jest } from '@jest/globals';
|
||||
import { ModuleMocker } from 'jest-mock';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as lolex from '@sinonjs/fake-timers';
|
||||
@@ -158,16 +158,75 @@ describe('RoleService', () => {
|
||||
afterEach(async () => {
|
||||
clock.uninstall();
|
||||
|
||||
/**
|
||||
* Delete meta and roleAssignment first to avoid deadlock due to schema dependencies
|
||||
* https://github.com/misskey-dev/misskey/issues/16783
|
||||
*/
|
||||
await app.get(DI.metasRepository).createQueryBuilder().delete().execute();
|
||||
await roleAssignmentsRepository.createQueryBuilder().delete().execute();
|
||||
await Promise.all([
|
||||
app.get(DI.metasRepository).createQueryBuilder().delete().execute(),
|
||||
usersRepository.createQueryBuilder().delete().execute(),
|
||||
rolesRepository.createQueryBuilder().delete().execute(),
|
||||
roleAssignmentsRepository.createQueryBuilder().delete().execute(),
|
||||
]);
|
||||
|
||||
await app.close();
|
||||
});
|
||||
|
||||
describe('getUserAssigns', () => {
|
||||
test('アサインされたロールを取得できる', async () => {
|
||||
const user = await createUser();
|
||||
const role1 = await createRole({ name: 'a' });
|
||||
const role2 = await createRole({ name: 'b' });
|
||||
|
||||
await roleService.assign(user.id, role1.id);
|
||||
await roleService.assign(user.id, role2.id);
|
||||
|
||||
const assigns = await roleService.getUserAssigns(user.id);
|
||||
expect(assigns).toHaveLength(2);
|
||||
expect(assigns.some(a => a.roleId === role1.id)).toBe(true);
|
||||
expect(assigns.some(a => a.roleId === role2.id)).toBe(true);
|
||||
});
|
||||
|
||||
test('アサインされたロールの有効/期限切れパターンを取得できる', async () => {
|
||||
const user = await createUser();
|
||||
const roleNoExpiry = await createRole({ name: 'no-expires' });
|
||||
const roleNotExpired = await createRole({ name: 'not-expired' });
|
||||
const roleExpired = await createRole({ name: 'expired' });
|
||||
|
||||
// expiresAtなし
|
||||
await roleService.assign(user.id, roleNoExpiry.id);
|
||||
|
||||
// expiresAtあり(期限切れでない)
|
||||
const future = new Date(Date.now() + 1000 * 60 * 60); // +1 hour
|
||||
await roleService.assign(user.id, roleNotExpired.id, future);
|
||||
|
||||
// expiresAtあり(期限切れ)
|
||||
await assignRole({ userId: user.id, roleId: roleExpired.id, expiresAt: new Date(Date.now() - 1000) });
|
||||
|
||||
const assigns = await roleService.getUserAssigns(user.id);
|
||||
expect(assigns.some(a => a.roleId === roleNoExpiry.id)).toBe(true);
|
||||
expect(assigns.some(a => a.roleId === roleNotExpired.id)).toBe(true);
|
||||
expect(assigns.some(a => a.roleId === roleExpired.id)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserRoles', () => {
|
||||
test('アサインされたロールとコンディショナルロールの両方が取得できる', async () => {
|
||||
const user = await createUser();
|
||||
const manualRole = await createRole({ name: 'manual role' });
|
||||
const conditionalRole = await createConditionalRole({
|
||||
id: aidx(),
|
||||
type: 'isBot',
|
||||
});
|
||||
await roleService.assign(user.id, manualRole.id);
|
||||
await roleService.assign(user.id, conditionalRole.id);
|
||||
|
||||
const roles = await roleService.getUserRoles(user.id);
|
||||
expect(roles.some(r => r.id === manualRole.id)).toBe(true);
|
||||
expect(roles.some(r => r.id === conditionalRole.id)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserPolicies', () => {
|
||||
test('instance default policies', async () => {
|
||||
const user = await createUser();
|
||||
@@ -280,6 +339,112 @@ describe('RoleService', () => {
|
||||
const resultAfter25hAgain = await roleService.getUserPolicies(user.id);
|
||||
expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true);
|
||||
});
|
||||
|
||||
test('role with no policy set', async () => {
|
||||
const user = await createUser();
|
||||
const roleWithPolicy = await createRole({
|
||||
name: 'roleWithPolicy',
|
||||
policies: {
|
||||
pinLimit: {
|
||||
useDefault: false,
|
||||
priority: 0,
|
||||
value: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const roleWithoutPolicy = await createRole({
|
||||
name: 'roleWithoutPolicy',
|
||||
policies: {}, // ポリシーが空
|
||||
});
|
||||
await roleService.assign(user.id, roleWithPolicy.id);
|
||||
await roleService.assign(user.id, roleWithoutPolicy.id);
|
||||
meta.policies = {
|
||||
pinLimit: 5,
|
||||
};
|
||||
|
||||
const result = await roleService.getUserPolicies(user.id);
|
||||
|
||||
// roleWithoutPolicy は default 値 (5) を使い、roleWithPolicy の 10 と比較して大きい方が採用される
|
||||
expect(result.pinLimit).toBe(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserBadgeRoles', () => {
|
||||
test('手動アサイン済みのバッジロールのみが返る', async () => {
|
||||
const user = await createUser();
|
||||
const badgeRole = await createRole({ name: 'badge', asBadge: true });
|
||||
const normalRole = await createRole({ name: 'normal', asBadge: false });
|
||||
|
||||
await roleService.assign(user.id, badgeRole.id);
|
||||
await roleService.assign(user.id, normalRole.id);
|
||||
|
||||
const roles = await roleService.getUserBadgeRoles(user.id);
|
||||
expect(roles.some(r => r.id === badgeRole.id)).toBe(true);
|
||||
expect(roles.some(r => r.id === normalRole.id)).toBe(false);
|
||||
});
|
||||
|
||||
test('コンディショナルなバッジロールが条件一致で返る', async () => {
|
||||
const user = await createUser({ isBot: true });
|
||||
const condBadgeRole = await createConditionalRole({
|
||||
id: aidx(),
|
||||
type: 'isBot',
|
||||
}, { asBadge: true, name: 'cond-badge' });
|
||||
const condNonBadgeRole = await createConditionalRole({
|
||||
id: aidx(),
|
||||
type: 'isBot',
|
||||
}, { asBadge: false, name: 'cond-non-badge' });
|
||||
|
||||
const roles = await roleService.getUserBadgeRoles(user.id);
|
||||
expect(roles.some(r => r.id === condBadgeRole.id)).toBe(true);
|
||||
expect(roles.some(r => r.id === condNonBadgeRole.id)).toBe(false);
|
||||
});
|
||||
|
||||
test('roleAssignedTo 条件のバッジロール: アサイン有無で変化する', async () => {
|
||||
const [user1, user2] = await Promise.all([createUser(), createUser()]);
|
||||
const manualRole = await createRole({ name: 'manual' });
|
||||
const condBadgeRole = await createConditionalRole({
|
||||
id: aidx(),
|
||||
type: 'roleAssignedTo',
|
||||
roleId: manualRole.id,
|
||||
}, { asBadge: true, name: 'assigned-badge' });
|
||||
|
||||
await roleService.assign(user2.id, manualRole.id);
|
||||
|
||||
const [roles1, roles2] = await Promise.all([
|
||||
roleService.getUserBadgeRoles(user1.id),
|
||||
roleService.getUserBadgeRoles(user2.id),
|
||||
]);
|
||||
expect(roles1.some(r => r.id === condBadgeRole.id)).toBe(false);
|
||||
expect(roles2.some(r => r.id === condBadgeRole.id)).toBe(true);
|
||||
});
|
||||
|
||||
test('期限切れのバッジロールは除外される', async () => {
|
||||
const user = await createUser();
|
||||
const roleNoExpiry = await createRole({ name: 'no-exp', asBadge: true });
|
||||
const roleNotExpired = await createRole({ name: 'not-expired', asBadge: true });
|
||||
const roleExpired = await createRole({ name: 'expired', asBadge: true });
|
||||
|
||||
// expiresAt なし
|
||||
await roleService.assign(user.id, roleNoExpiry.id);
|
||||
|
||||
// expiresAt あり(期限切れでない)
|
||||
const future = new Date(Date.now() + 1000 * 60 * 60); // +1 hour
|
||||
await roleService.assign(user.id, roleNotExpired.id, future);
|
||||
|
||||
// expiresAt あり(期限切れ)
|
||||
await assignRole({ userId: user.id, roleId: roleExpired.id, expiresAt: new Date(Date.now() - 1000) });
|
||||
|
||||
const rolesBefore = await roleService.getUserBadgeRoles(user.id);
|
||||
expect(rolesBefore.some(r => r.id === roleNoExpiry.id)).toBe(true);
|
||||
expect(rolesBefore.some(r => r.id === roleNotExpired.id)).toBe(true);
|
||||
expect(rolesBefore.some(r => r.id === roleExpired.id)).toBe(false);
|
||||
|
||||
// 時間経過で roleNotExpired を失効させる
|
||||
clock.tick('02:00:00');
|
||||
const rolesAfter = await roleService.getUserBadgeRoles(user.id);
|
||||
expect(rolesAfter.some(r => r.id === roleNoExpiry.id)).toBe(true);
|
||||
expect(rolesAfter.some(r => r.id === roleNotExpired.id)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getModeratorIds', () => {
|
||||
@@ -413,9 +578,9 @@ describe('RoleService', () => {
|
||||
expect(result).toEqual([modeUser1.id, modeUser2.id, rootUser.id]);
|
||||
});
|
||||
|
||||
test('root has moderator role', async () => {
|
||||
const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createRoot(),
|
||||
test('includeAdmins = false, includeRoot = true, excludeExpire = true', async () => {
|
||||
const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
|
||||
]);
|
||||
|
||||
const role1 = await createRole({ name: 'admin', isAdministrator: true });
|
||||
@@ -424,9 +589,11 @@ describe('RoleService', () => {
|
||||
|
||||
await Promise.all([
|
||||
assignRole({ userId: adminUser1.id, roleId: role1.id }),
|
||||
assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: modeUser1.id, roleId: role2.id }),
|
||||
assignRole({ userId: rootUser.id, roleId: role2.id }),
|
||||
assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: normalUser1.id, roleId: role3.id }),
|
||||
assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
]);
|
||||
|
||||
const result = await roleService.getModeratorIds({
|
||||
@@ -434,12 +601,12 @@ describe('RoleService', () => {
|
||||
includeRoot: true,
|
||||
excludeExpire: false,
|
||||
});
|
||||
expect(result).toEqual([modeUser1.id, rootUser.id]);
|
||||
expect(result).toEqual([modeUser1.id, modeUser2.id, rootUser.id]);
|
||||
});
|
||||
|
||||
test('root has administrator role', async () => {
|
||||
const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createRoot(),
|
||||
test('includeAdmins = true, includeRoot = true, excludeExpire = false', async () => {
|
||||
const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
|
||||
]);
|
||||
|
||||
const role1 = await createRole({ name: 'admin', isAdministrator: true });
|
||||
@@ -448,9 +615,11 @@ describe('RoleService', () => {
|
||||
|
||||
await Promise.all([
|
||||
assignRole({ userId: adminUser1.id, roleId: role1.id }),
|
||||
assignRole({ userId: rootUser.id, roleId: role1.id }),
|
||||
assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: modeUser1.id, roleId: role2.id }),
|
||||
assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: normalUser1.id, roleId: role3.id }),
|
||||
assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
]);
|
||||
|
||||
const result = await roleService.getModeratorIds({
|
||||
@@ -458,12 +627,12 @@ describe('RoleService', () => {
|
||||
includeRoot: true,
|
||||
excludeExpire: false,
|
||||
});
|
||||
expect(result).toEqual([adminUser1.id, modeUser1.id, rootUser.id]);
|
||||
expect(result).toEqual([adminUser1.id, adminUser2.id, modeUser1.id, modeUser2.id, rootUser.id]);
|
||||
});
|
||||
|
||||
test('root has moderator role(expire)', async () => {
|
||||
const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createRoot(),
|
||||
test('includeAdmins = true, includeRoot = true, excludeExpire = true', async () => {
|
||||
const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([
|
||||
createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(),
|
||||
]);
|
||||
|
||||
const role1 = await createRole({ name: 'admin', isAdministrator: true });
|
||||
@@ -472,17 +641,71 @@ describe('RoleService', () => {
|
||||
|
||||
await Promise.all([
|
||||
assignRole({ userId: adminUser1.id, roleId: role1.id }),
|
||||
assignRole({ userId: modeUser1.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: rootUser.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: modeUser1.id, roleId: role2.id }),
|
||||
assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
assignRole({ userId: normalUser1.id, roleId: role3.id }),
|
||||
assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }),
|
||||
]);
|
||||
|
||||
const result = await roleService.getModeratorIds({
|
||||
includeAdmins: false,
|
||||
includeAdmins: true,
|
||||
includeRoot: true,
|
||||
excludeExpire: true,
|
||||
});
|
||||
expect(result).toEqual([rootUser.id]);
|
||||
expect(result).toEqual([adminUser1.id, modeUser1.id, rootUser.id]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAdministratorIds', () => {
|
||||
test('should return only user IDs with administrator roles', async () => {
|
||||
const adminUser1 = await createUser();
|
||||
const adminUser2 = await createUser();
|
||||
const normalUser = await createUser();
|
||||
const moderatorUser = await createUser();
|
||||
|
||||
const adminRole = await createRole({ name: 'admin', isAdministrator: true, isModerator: false });
|
||||
const moderatorRole = await createRole({ name: 'moderator', isModerator: true, isAdministrator: false });
|
||||
const normalRole = await createRole({ name: 'normal', isAdministrator: false, isModerator: false });
|
||||
|
||||
await roleService.assign(adminUser1.id, adminRole.id);
|
||||
await roleService.assign(adminUser2.id, adminRole.id);
|
||||
await roleService.assign(moderatorUser.id, moderatorRole.id);
|
||||
await roleService.assign(normalUser.id, normalRole.id);
|
||||
|
||||
const adminIds = await roleService.getAdministratorIds();
|
||||
|
||||
// sort for deterministic order
|
||||
adminIds.sort();
|
||||
const expectedIds = [adminUser1.id, adminUser2.id].sort();
|
||||
|
||||
expect(adminIds).toEqual(expectedIds);
|
||||
});
|
||||
|
||||
test('should return an empty array if no users have administrator roles', async () => {
|
||||
const normalUser = await createUser();
|
||||
const normalRole = await createRole({ name: 'normal', isAdministrator: false });
|
||||
await roleService.assign(normalUser.id, normalRole.id);
|
||||
|
||||
const adminIds = await roleService.getAdministratorIds();
|
||||
|
||||
expect(adminIds).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should return an empty array if there are no administrator roles defined', async () => {
|
||||
await createUser(); // create user to ensure not empty db
|
||||
const adminIds = await roleService.getAdministratorIds();
|
||||
expect(adminIds).toHaveLength(0);
|
||||
});
|
||||
|
||||
// TODO: rootユーザーは現在実装に含まれていないため、テストもそれに倣う
|
||||
test('should not include the root user', async () => {
|
||||
const rootUser = await createUser();
|
||||
meta.rootUserId = rootUser.id;
|
||||
|
||||
const adminIds = await roleService.getAdministratorIds();
|
||||
|
||||
expect(adminIds).not.toContain(rootUser.id);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/node": "24.9.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"rollup": "4.52.4",
|
||||
"@types/node": "24.9.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"rollup": "4.52.5",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"estree-walker": "3.0.3",
|
||||
"magic-string": "0.30.19",
|
||||
"vite": "7.1.9"
|
||||
"magic-string": "0.30.21",
|
||||
"vite": "7.1.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@discordapp/twemoji": "16.0.1",
|
||||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/plugin-replace": "6.0.3",
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@vitejs/plugin-vue": "6.0.1",
|
||||
@@ -26,47 +26,47 @@
|
||||
"mfm-js": "0.25.0",
|
||||
"misskey-js": "workspace:*",
|
||||
"punycode.js": "2.3.1",
|
||||
"rollup": "4.52.4",
|
||||
"sass": "1.93.2",
|
||||
"shiki": "3.13.0",
|
||||
"rollup": "4.52.5",
|
||||
"sass": "1.93.3",
|
||||
"shiki": "3.14.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"uuid": "13.0.0",
|
||||
"vite": "7.1.9",
|
||||
"vite": "7.1.11",
|
||||
"vue": "3.5.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@misskey-dev/summaly": "5.2.5",
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "24.9.1",
|
||||
"@types/micromatch": "4.0.10",
|
||||
"@types/node": "24.9.2",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/runtime-core": "3.5.22",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.1.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"eslint-plugin-vue": "10.5.1",
|
||||
"fast-glob": "3.3.3",
|
||||
"happy-dom": "20.0.7",
|
||||
"happy-dom": "20.0.10",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"msw": "2.11.5",
|
||||
"msw": "2.11.6",
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.6.2",
|
||||
"start-server-and-test": "2.1.2",
|
||||
"tsx": "4.20.6",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vue-component-type-helpers": "3.1.1",
|
||||
"vue-component-type-helpers": "3.1.2",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
"vue-tsc": "3.1.1"
|
||||
"vue-tsc": "3.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import { render } from 'buraha';
|
||||
|
||||
const canvas = new OffscreenCanvas(64, 64);
|
||||
@@ -18,5 +21,5 @@ onmessage = (event) => {
|
||||
|
||||
render(event.data.hash, canvas);
|
||||
const bitmap = canvas.transferToImageBitmap();
|
||||
postMessage({ id: event.data.id, bitmap }, [bitmap]);
|
||||
self.postMessage({ id: event.data.id, bitmap }, [bitmap]);
|
||||
};
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
const canvas = globalThis.OffscreenCanvas && new OffscreenCanvas(1, 1);
|
||||
// 環境によってはOffscreenCanvasが存在しないため
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const gl = canvas?.getContext('webgl2');
|
||||
if (gl) {
|
||||
postMessage({ result: true });
|
||||
self.postMessage({ result: true });
|
||||
} else {
|
||||
postMessage({ result: false });
|
||||
self.postMessage({ result: false });
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "24.9.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"esbuild": "0.25.10",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"@types/node": "24.9.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"esbuild": "0.25.11",
|
||||
"eslint-plugin-vue": "10.5.1",
|
||||
"nodemon": "3.1.10",
|
||||
"typescript": "5.9.3",
|
||||
"vue-eslint-parser": "10.2.0"
|
||||
|
||||
@@ -33,6 +33,7 @@ export function channel(id = 'somechannelid', name = 'Some Channel', bannerUrl:
|
||||
description: null,
|
||||
userId: null,
|
||||
bannerUrl,
|
||||
bannerId: null,
|
||||
pinnedNoteIds: [],
|
||||
color: '#000',
|
||||
isArchived: false,
|
||||
|
||||
@@ -14,6 +14,7 @@ export default [
|
||||
...pluginVue.configs['flat/recommended'],
|
||||
{
|
||||
files: ['src/**/*.{ts,vue}'],
|
||||
ignores: ['**/*.stories.ts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])),
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
||||
"@misskey-dev/browser-image-resizer": "2024.1.0",
|
||||
"@rollup/plugin-json": "6.1.0",
|
||||
"@rollup/plugin-replace": "6.0.2",
|
||||
"@rollup/plugin-replace": "6.0.3",
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@sentry/vue": "10.20.0",
|
||||
"@sentry/vue": "10.22.0",
|
||||
"@syuilo/aiscript": "1.1.2",
|
||||
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
@@ -33,17 +33,17 @@
|
||||
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
|
||||
"analytics": "0.8.19",
|
||||
"astring": "1.9.0",
|
||||
"broadcast-channel": "7.1.0",
|
||||
"broadcast-channel": "7.2.0",
|
||||
"buraha": "0.0.1",
|
||||
"canvas-confetti": "1.9.3",
|
||||
"canvas-confetti": "1.9.4",
|
||||
"chart.js": "4.5.1",
|
||||
"chartjs-adapter-date-fns": "3.0.0",
|
||||
"chartjs-chart-matrix": "3.0.0",
|
||||
"chartjs-plugin-gradient": "0.6.1",
|
||||
"chartjs-plugin-zoom": "2.2.0",
|
||||
"chromatic": "13.3.0",
|
||||
"chromatic": "13.3.3",
|
||||
"compare-versions": "6.1.1",
|
||||
"cropperjs": "2.0.1",
|
||||
"cropperjs": "2.1.0",
|
||||
"date-fns": "4.1.0",
|
||||
"estree-walker": "3.0.3",
|
||||
"eventemitter3": "5.0.1",
|
||||
@@ -56,9 +56,9 @@
|
||||
"ios-haptics": "0.1.4",
|
||||
"is-file-animated": "1.0.2",
|
||||
"json5": "2.2.3",
|
||||
"magic-string": "0.30.19",
|
||||
"magic-string": "0.30.21",
|
||||
"matter-js": "0.20.0",
|
||||
"mediabunny": "1.23.0",
|
||||
"mediabunny": "1.24.2",
|
||||
"mfm-js": "0.25.0",
|
||||
"misskey-bubble-game": "workspace:*",
|
||||
"misskey-js": "workspace:*",
|
||||
@@ -67,29 +67,29 @@
|
||||
"punycode.js": "2.3.1",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qr-scanner": "1.4.2",
|
||||
"rollup": "4.52.4",
|
||||
"rollup": "4.52.5",
|
||||
"sanitize-html": "2.17.0",
|
||||
"sass": "1.93.2",
|
||||
"shiki": "3.13.0",
|
||||
"sass": "1.93.3",
|
||||
"shiki": "3.14.0",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.180.0",
|
||||
"three": "0.181.0",
|
||||
"throttle-debounce": "5.0.2",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"v-code-diff": "1.13.1",
|
||||
"vite": "7.1.9",
|
||||
"vite": "7.1.11",
|
||||
"vue": "3.5.22",
|
||||
"vuedraggable": "next",
|
||||
"wanakana": "5.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@misskey-dev/summaly": "5.2.4",
|
||||
"@misskey-dev/summaly": "5.2.5",
|
||||
"@storybook/addon-essentials": "8.6.14",
|
||||
"@storybook/addon-interactions": "8.6.14",
|
||||
"@storybook/addon-links": "9.1.10",
|
||||
"@storybook/addon-links": "9.1.16",
|
||||
"@storybook/addon-mdx-gfm": "8.6.14",
|
||||
"@storybook/addon-storysource": "8.6.14",
|
||||
"@storybook/blocks": "8.6.14",
|
||||
@@ -97,42 +97,42 @@
|
||||
"@storybook/core-events": "8.6.14",
|
||||
"@storybook/manager-api": "8.6.14",
|
||||
"@storybook/preview-api": "8.6.14",
|
||||
"@storybook/react": "9.1.10",
|
||||
"@storybook/react-vite": "9.1.10",
|
||||
"@storybook/react": "9.1.16",
|
||||
"@storybook/react-vite": "9.1.16",
|
||||
"@storybook/test": "8.6.14",
|
||||
"@storybook/theming": "8.6.14",
|
||||
"@storybook/types": "8.6.14",
|
||||
"@storybook/vue3": "9.1.10",
|
||||
"@storybook/vue3-vite": "9.1.10",
|
||||
"@storybook/vue3": "9.1.16",
|
||||
"@storybook/vue3-vite": "9.1.16",
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/canvas-confetti": "1.9.0",
|
||||
"@types/estree": "1.0.8",
|
||||
"@types/matter-js": "0.20.2",
|
||||
"@types/micromatch": "4.0.9",
|
||||
"@types/node": "24.9.1",
|
||||
"@types/micromatch": "4.0.10",
|
||||
"@types/node": "24.9.2",
|
||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||
"@types/sanitize-html": "2.16.0",
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@types/throttle-debounce": "5.0.2",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vue/compiler-core": "3.5.22",
|
||||
"@vue/runtime-core": "3.5.22",
|
||||
"acorn": "8.15.0",
|
||||
"cross-env": "10.1.0",
|
||||
"cypress": "15.4.0",
|
||||
"cypress": "15.5.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.5.0",
|
||||
"eslint-plugin-vue": "10.5.1",
|
||||
"fast-glob": "3.3.3",
|
||||
"happy-dom": "20.0.7",
|
||||
"happy-dom": "20.0.10",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
"minimatch": "10.0.3",
|
||||
"msw": "2.11.5",
|
||||
"minimatch": "10.1.1",
|
||||
"msw": "2.11.6",
|
||||
"msw-storybook-addon": "2.0.6",
|
||||
"nodemon": "3.1.10",
|
||||
"prettier": "3.6.2",
|
||||
@@ -140,15 +140,15 @@
|
||||
"react-dom": "19.2.0",
|
||||
"seedrandom": "3.0.5",
|
||||
"start-server-and-test": "2.1.2",
|
||||
"storybook": "9.1.10",
|
||||
"storybook": "9.1.16",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"tsx": "4.20.6",
|
||||
"vite-plugin-glsl": "1.5.4",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vitest": "3.2.4",
|
||||
"vitest-fetch-mock": "0.4.5",
|
||||
"vue-component-type-helpers": "3.1.1",
|
||||
"vue-component-type-helpers": "3.1.2",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
"vue-tsc": "3.1.1"
|
||||
"vue-tsc": "3.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkPagination>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts" setup generic="P extends IPaginator">
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { IPaginator } from '@/utility/paginator.js';
|
||||
import type { IPaginator, ExtractorFunction } from '@/utility/paginator.js';
|
||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
paginator: IPaginator;
|
||||
paginator: P;
|
||||
noGap?: boolean;
|
||||
extractor?: (item: any) => Misskey.entities.Channel;
|
||||
extractor?: ExtractorFunction<P, Misskey.entities.Channel>;
|
||||
}>(), {
|
||||
extractor: (item) => item,
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ export const Default = {
|
||||
};
|
||||
},
|
||||
args: {
|
||||
imageFile: file(),
|
||||
imageFile: new File([], 'image.webp', { type: 'image/webp' }),
|
||||
aspectRatio: NaN,
|
||||
},
|
||||
parameters: {
|
||||
|
||||
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkPagination :paginator="paginator" :direction="direction" :autoLoad="autoLoad" :pullToRefresh="pullToRefresh" :withControl="withControl">
|
||||
<MkPagination :paginator="paginator" :direction="direction" :autoLoad="autoLoad" :pullToRefresh="pullToRefresh" :withControl="withControl" :forceDisableInfiniteScroll="forceDisableInfiniteScroll">
|
||||
<template #empty><MkResult type="empty" :text="i18n.ts.noNotes"/></template>
|
||||
|
||||
<template #default="{ items: notes }">
|
||||
@@ -40,26 +40,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<script lang="ts" setup generic="T extends IPaginator<Misskey.entities.Note>">
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { MkPaginationOptions } from '@/components/MkPagination.vue';
|
||||
import type { IPaginator } from '@/utility/paginator.js';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { globalEvents, useGlobalEvent } from '@/events.js';
|
||||
import { useGlobalEvent } from '@/events.js';
|
||||
import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const props = withDefaults(defineProps<MkPaginationOptions & {
|
||||
paginator: T;
|
||||
noGap?: boolean;
|
||||
|
||||
direction?: 'up' | 'down' | 'both';
|
||||
autoLoad?: boolean;
|
||||
pullToRefresh?: boolean;
|
||||
withControl?: boolean;
|
||||
}>(), {
|
||||
autoLoad: true,
|
||||
direction: 'down',
|
||||
pullToRefresh: true,
|
||||
withControl: true,
|
||||
forceDisableInfiniteScroll: false,
|
||||
});
|
||||
|
||||
useGlobalEvent('noteDeleted', (noteId) => {
|
||||
|
||||
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
:leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
|
||||
:enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
|
||||
:leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
|
||||
mode="out-in"
|
||||
:mode="prefer.s.animation ? 'out-in' : undefined"
|
||||
>
|
||||
<MkLoading v-if="paginator.fetching.value"/>
|
||||
|
||||
@@ -26,14 +26,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<div v-else key="_root_" class="_gaps">
|
||||
<div v-if="direction === 'up' || direction === 'both'" v-show="upButtonVisible">
|
||||
<MkButton v-if="!upButtonLoading" :class="$style.more" primary rounded @click="upButtonClick">
|
||||
<MkButton v-if="!upButtonLoading" v-appear="shouldEnableInfiniteScroll ? upButtonClick : null" :class="$style.more" primary rounded @click="upButtonClick">
|
||||
{{ i18n.ts.loadMore }}
|
||||
</MkButton>
|
||||
<MkLoading v-else/>
|
||||
</div>
|
||||
<slot :items="getValue(paginator.items)" :fetching="paginator.fetching.value || paginator.fetchingOlder.value"></slot>
|
||||
<div v-if="direction === 'down' || direction === 'both'" v-show="downButtonVisible">
|
||||
<MkButton v-if="!downButtonLoading" :class="$style.more" primary rounded @click="downButtonClick">
|
||||
<MkButton v-if="!downButtonLoading" v-appear="shouldEnableInfiniteScroll ? downButtonClick : null" :class="$style.more" primary rounded @click="downButtonClick">
|
||||
{{ i18n.ts.loadMore }}
|
||||
</MkButton>
|
||||
<MkLoading v-else/>
|
||||
@@ -44,6 +44,24 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export type MkPaginationOptions = {
|
||||
autoLoad?: boolean;
|
||||
/**
|
||||
* ページネーションを進める方向
|
||||
* - up: 上方向
|
||||
* - down: 下方向 (default)
|
||||
* - both: 双方向
|
||||
*
|
||||
* NOTE: この方向はページネーションの方向であって、アイテムの並び順ではない
|
||||
*/
|
||||
direction?: 'up' | 'down' | 'both';
|
||||
pullToRefresh?: boolean;
|
||||
withControl?: boolean;
|
||||
forceDisableInfiniteScroll?: boolean;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup generic="T extends IPaginator">
|
||||
import { isLink } from '@@/js/is-link.js';
|
||||
import { onMounted, computed, watch, unref } from 'vue';
|
||||
@@ -56,24 +74,18 @@ import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||
import MkPaginationControl from '@/components/MkPaginationControl.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const props = withDefaults(defineProps<MkPaginationOptions & {
|
||||
paginator: T;
|
||||
|
||||
// ページネーションを進める方向
|
||||
// up: 上方向
|
||||
// down: 下方向 (default)
|
||||
// both: 双方向
|
||||
// NOTE: この方向はページネーションの方向であって、アイテムの並び順ではない
|
||||
direction?: 'up' | 'down' | 'both';
|
||||
|
||||
autoLoad?: boolean;
|
||||
pullToRefresh?: boolean;
|
||||
withControl?: boolean;
|
||||
}>(), {
|
||||
autoLoad: true,
|
||||
direction: 'down',
|
||||
pullToRefresh: true,
|
||||
withControl: false,
|
||||
forceDisableInfiniteScroll: false,
|
||||
});
|
||||
|
||||
const shouldEnableInfiniteScroll = computed(() => {
|
||||
return prefer.r.enableInfiniteScroll.value && !props.forceDisableInfiniteScroll;
|
||||
});
|
||||
|
||||
function onContextmenu(ev: MouseEvent) {
|
||||
|
||||
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<header :class="$style.header">
|
||||
<div :class="$style.headerLeft">
|
||||
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
|
||||
<button v-click-anime v-tooltip="i18n.ts.account" :class="$style.account" class="_button" @click="openAccountMenu">
|
||||
<button ref="accountMenuEl" v-click-anime v-tooltip="i18n.ts.account" :class="$style.account" class="_button" @click="openAccountMenu">
|
||||
<img :class="$style.avatar" :src="(postAccount ?? $i).avatarUrl" style="border-radius: 100%;"/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<span v-else><i class="ti ti-rocket-off"></i></span>
|
||||
</button>
|
||||
<button ref="otherSettingsButton" v-tooltip="i18n.ts.other" class="_button" :class="$style.headerRightItem" @click="showOtherSettings"><i class="ti ti-dots"></i></button>
|
||||
<button v-click-anime class="_button" :class="$style.submit" :disabled="!canPost" data-cy-open-post-form-submit @click="post">
|
||||
<button ref="submitButtonEl" v-click-anime class="_button" :class="$style.submit" :disabled="!canPost" data-cy-open-post-form-submit @click="post">
|
||||
<div :class="$style.submitInner">
|
||||
<template v-if="posted"></template>
|
||||
<template v-else-if="posting"><MkEllipsis/></template>
|
||||
@@ -60,6 +60,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<button class="_buttonPrimary" style="padding: 4px; border-radius: 8px;" @click="addVisibleUser"><i class="ti ti-plus ti-fw"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<MkInfo v-if="!store.r.tips.value.postForm" :class="$style.showHowToUse" closable @close="closeTip('postForm')">
|
||||
<button class="_textButton" @click="showTour">{{ i18n.ts._postForm.showHowToUse }}</button>
|
||||
</MkInfo>
|
||||
<MkInfo v-if="scheduledAt != null" :class="$style.scheduledAt">
|
||||
<I18n :src="i18n.ts.scheduleToPostOnX" tag="span">
|
||||
<template #x>
|
||||
@@ -89,7 +92,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkNotePreview v-if="showPreview" :class="$style.preview" :text="text" :files="files" :poll="poll ?? undefined" :useCw="useCw" :cw="cw" :user="postAccount ?? $i"/>
|
||||
<div v-if="showingOptions" style="padding: 8px 16px;">
|
||||
</div>
|
||||
<footer :class="$style.footer">
|
||||
<footer ref="footerEl" :class="$style.footer">
|
||||
<div :class="$style.footerLeft">
|
||||
<button v-tooltip="i18n.ts.attachFile + ' (' + i18n.ts.upload + ')'" class="_button" :class="$style.footerButton" @click="chooseFileFromPc"><i class="ti ti-photo-plus"></i></button>
|
||||
<button v-tooltip="i18n.ts.attachFile + ' (' + i18n.ts.fromDrive + ')'" class="_button" :class="$style.footerButton" @click="chooseFileFromDrive"><i class="ti ti-cloud-download"></i></button>
|
||||
@@ -153,6 +156,8 @@ import { DI } from '@/di.js';
|
||||
import { globalEvents } from '@/events.js';
|
||||
import { checkDragDataType, getDragData } from '@/drag-and-drop.js';
|
||||
import { useUploader } from '@/composables/use-uploader.js';
|
||||
import { startTour } from '@/utility/tour.js';
|
||||
import { closeTip } from '@/tips.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
||||
@@ -186,6 +191,9 @@ const cwInputEl = useTemplateRef('cwInputEl');
|
||||
const hashtagsInputEl = useTemplateRef('hashtagsInputEl');
|
||||
const visibilityButton = useTemplateRef('visibilityButton');
|
||||
const otherSettingsButton = useTemplateRef('otherSettingsButton');
|
||||
const accountMenuEl = useTemplateRef('accountMenuEl');
|
||||
const footerEl = useTemplateRef('footerEl');
|
||||
const submitButtonEl = useTemplateRef('submitButtonEl');
|
||||
|
||||
const posting = ref(false);
|
||||
const posted = ref(false);
|
||||
@@ -1285,6 +1293,45 @@ function cancelSchedule() {
|
||||
scheduledAt.value = null;
|
||||
}
|
||||
|
||||
function showTour() {
|
||||
if (textareaEl.value == null ||
|
||||
footerEl.value == null ||
|
||||
accountMenuEl.value == null ||
|
||||
visibilityButton.value == null ||
|
||||
otherSettingsButton.value == null ||
|
||||
submitButtonEl.value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
startTour([{
|
||||
element: textareaEl.value,
|
||||
title: i18n.ts._postForm._howToUse.content_title,
|
||||
description: i18n.ts._postForm._howToUse.content_description,
|
||||
}, {
|
||||
element: footerEl.value,
|
||||
title: i18n.ts._postForm._howToUse.toolbar_title,
|
||||
description: i18n.ts._postForm._howToUse.toolbar_description,
|
||||
}, {
|
||||
element: accountMenuEl.value,
|
||||
title: i18n.ts._postForm._howToUse.account_title,
|
||||
description: i18n.ts._postForm._howToUse.account_description,
|
||||
}, {
|
||||
element: visibilityButton.value,
|
||||
title: i18n.ts._postForm._howToUse.visibility_title,
|
||||
description: i18n.ts._postForm._howToUse.visibility_description,
|
||||
}, {
|
||||
element: otherSettingsButton.value,
|
||||
title: i18n.ts._postForm._howToUse.menu_title,
|
||||
description: i18n.ts._postForm._howToUse.menu_description,
|
||||
}, {
|
||||
element: submitButtonEl.value,
|
||||
title: i18n.ts._postForm._howToUse.submit_title,
|
||||
description: i18n.ts._postForm._howToUse.submit_description,
|
||||
}]).then(() => {
|
||||
closeTip('postForm');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.autofocus) {
|
||||
focus();
|
||||
@@ -1414,6 +1461,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: auto;
|
||||
@@ -1575,6 +1623,10 @@ html[data-color-scheme=light] .preview {
|
||||
margin: 0 20px 16px 20px;
|
||||
}
|
||||
|
||||
.showHowToUse {
|
||||
margin: 0 20px 16px 20px;
|
||||
}
|
||||
|
||||
.cw,
|
||||
.hashtags,
|
||||
.text {
|
||||
|
||||
@@ -120,6 +120,7 @@ function onPasskeyLogin(): void {
|
||||
.then((res) => {
|
||||
passkeyContext.value = res.context ?? '';
|
||||
credentialRequest.value = parseRequestOptionsFromJSON({
|
||||
// @ts-expect-error TODO: misskey-js由来の型(@simplewebauthn/types)とフロントエンド由来の型(@github/webauthn-json)が合わない
|
||||
publicKey: res.option,
|
||||
});
|
||||
|
||||
@@ -134,7 +135,7 @@ function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void {
|
||||
waiting.value = true;
|
||||
|
||||
if (doingPasskeyFromInputPage.value) {
|
||||
misskeyApi('signin-with-passkey', {
|
||||
misskeyApi<Misskey.entities.SigninWithPasskeyResponse>('signin-with-passkey', {
|
||||
credential: credential.toJSON(),
|
||||
context: passkeyContext.value,
|
||||
}).then((res) => {
|
||||
@@ -149,6 +150,7 @@ function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void {
|
||||
tryLogin({
|
||||
username: userInfo.value.username,
|
||||
password: password.value,
|
||||
// @ts-expect-error TODO: misskey-js由来の型(@simplewebauthn/types)とフロントエンド由来の型(@github/webauthn-json)が合わない
|
||||
credential: credential.toJSON(),
|
||||
});
|
||||
}
|
||||
@@ -253,6 +255,7 @@ async function tryLogin(req: Partial<Misskey.entities.SigninFlowRequest>): Promi
|
||||
case 'passkey': {
|
||||
if (webAuthnSupported()) {
|
||||
credentialRequest.value = parseRequestOptionsFromJSON({
|
||||
// @ts-expect-error TODO: misskey-js由来の型(@simplewebauthn/types)とフロントエンド由来の型(@github/webauthn-json)が合わない
|
||||
publicKey: res.authRequest,
|
||||
});
|
||||
page.value = 'passkey';
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div ref="rootEl" :class="$style.root" :style="{ zIndex }">
|
||||
<div :class="[$style.bg]"></div>
|
||||
<div ref="spotEl" :class="$style.spot"></div>
|
||||
<div ref="bodyEl" :class="$style.body" class="_panel _shadow">
|
||||
<div class="_gaps_s">
|
||||
<div><b>{{ title }}</b></div>
|
||||
<div>{{ description }}</div>
|
||||
<div class="_buttons">
|
||||
<MkButton v-if="hasPrev" small @click="prev"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton>
|
||||
<MkButton v-if="hasNext" small primary @click="next">{{ i18n.ts.next }} <i class="ti ti-arrow-right"></i></MkButton>
|
||||
<MkButton v-else small primary @click="next">{{ i18n.ts.done }} <i class="ti ti-check"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
|
||||
import { calcPopupPosition } from '@/utility/popup-position.js';
|
||||
import * as os from '@/os.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
title: string;
|
||||
description: string;
|
||||
anchorElement?: HTMLElement;
|
||||
x?: number;
|
||||
y?: number;
|
||||
direction?: 'top' | 'bottom' | 'right' | 'left';
|
||||
hasPrev: boolean;
|
||||
hasNext: boolean;
|
||||
}>(), {
|
||||
direction: 'top',
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(prev: 'prev'): void;
|
||||
(next: 'next'): void;
|
||||
}>();
|
||||
|
||||
function prev() {
|
||||
emit('prev');
|
||||
}
|
||||
|
||||
function next() {
|
||||
emit('next');
|
||||
}
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
const bodyEl = useTemplateRef('bodyEl');
|
||||
const spotEl = useTemplateRef('spotEl');
|
||||
const zIndex = os.claimZIndex('high');
|
||||
const spotX = ref(0);
|
||||
const spotY = ref(0);
|
||||
const spotWidth = ref(0);
|
||||
const spotHeight = ref(0);
|
||||
|
||||
function setPosition() {
|
||||
if (spotEl.value == null) return;
|
||||
if (bodyEl.value == null) return;
|
||||
if (props.anchorElement == null) return;
|
||||
|
||||
const rect = props.anchorElement.getBoundingClientRect();
|
||||
spotX.value = rect.left;
|
||||
spotY.value = rect.top;
|
||||
spotWidth.value = rect.width;
|
||||
spotHeight.value = rect.height;
|
||||
|
||||
const data = calcPopupPosition(bodyEl.value, {
|
||||
anchorElement: props.anchorElement,
|
||||
direction: props.direction,
|
||||
align: 'center',
|
||||
innerMargin: 16,
|
||||
x: props.x,
|
||||
y: props.y,
|
||||
});
|
||||
|
||||
bodyEl.value.style.transformOrigin = data.transformOrigin;
|
||||
bodyEl.value.style.left = data.left + 'px';
|
||||
bodyEl.value.style.top = data.top + 'px';
|
||||
}
|
||||
|
||||
let loopHandler;
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setPosition();
|
||||
|
||||
const loop = () => {
|
||||
setPosition();
|
||||
loopHandler = window.requestAnimationFrame(loop);
|
||||
};
|
||||
|
||||
loop();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.cancelAnimationFrame(loopHandler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.spot {
|
||||
--x: v-bind("spotX + 'px'");
|
||||
--y: v-bind("spotY + 'px'");
|
||||
--width: v-bind("spotWidth + 'px'");
|
||||
--height: v-bind("spotHeight + 'px'");
|
||||
--padding: 8px;
|
||||
position: absolute;
|
||||
left: calc(var(--x) - var(--padding));
|
||||
top: calc(var(--y) - var(--padding));
|
||||
width: calc(var(--width) + var(--padding) * 2);
|
||||
height: calc(var(--height) + var(--padding) * 2);
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 0 9999px #000a;
|
||||
transition: left 0.2s ease-out, top 0.2s ease-out, width 0.2s ease-out, height 0.2s ease-out;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
.body {
|
||||
position: absolute;
|
||||
padding: 16px 20px;
|
||||
box-sizing: border-box;
|
||||
width: max-content;
|
||||
max-width: min(500px, 100vw);
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 100% {
|
||||
background: color(from var(--MI_THEME-accent) srgb r g b / 0.1);
|
||||
border: 1px solid color(from var(--MI_THEME-accent) srgb r g b / 0.75);
|
||||
}
|
||||
50% {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -15,17 +15,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkPagination>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts" setup generic="P extends IPaginator">
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { IPaginator } from '@/utility/paginator.js';
|
||||
import type { IPaginator, ExtractorFunction } from '@/utility/paginator.js';
|
||||
import MkUserInfo from '@/components/MkUserInfo.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
paginator: IPaginator;
|
||||
paginator: P;
|
||||
noGap?: boolean;
|
||||
extractor?: (item: any) => Misskey.entities.UserDetailed;
|
||||
extractor?: ExtractorFunction<P, Misskey.entities.UserDetailed>;
|
||||
}>(), {
|
||||
extractor: (item) => item,
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<h1 :class="$style.mainTitle">
|
||||
<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
|
||||
<!-- <img class="logo" v-if="instance.logoImageUrl" :src="instance.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
|
||||
<span>{{ instanceName }}</span>
|
||||
<MkA to="/">{{ instanceName }}</MkA>
|
||||
</h1>
|
||||
<div :class="$style.mainAbout">
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
|
||||
@@ -19,10 +19,13 @@ export function useForm<T extends Record<string, any>>(initialState: T, save: (n
|
||||
const currentState = reactive<T>(copy(initialState));
|
||||
const previousState = reactive<T>(copy(initialState));
|
||||
|
||||
const modifiedStates = reactive<Record<keyof T, boolean>>({} as any);
|
||||
for (const key in currentState) {
|
||||
modifiedStates[key] = false;
|
||||
}
|
||||
const modifiedStates = reactive<Record<keyof T, boolean>>((() => {
|
||||
const obj: Record<keyof T, boolean> = {} as Record<keyof T, boolean>;
|
||||
for (const key in initialState) {
|
||||
obj[key] = false;
|
||||
}
|
||||
return obj;
|
||||
})());
|
||||
const modified = computed(() => Object.values(modifiedStates).some(v => v));
|
||||
const modifiedCount = computed(() => Object.values(modifiedStates).filter(v => v).length);
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
*/
|
||||
|
||||
import type { InjectionKey, Ref } from 'vue';
|
||||
import type { PageMetadata } from '@/page.js';
|
||||
import type { Router } from '@/router.js';
|
||||
|
||||
export const DI = {
|
||||
routerCurrentDepth: Symbol() as InjectionKey<number>,
|
||||
router: Symbol() as InjectionKey<Router>,
|
||||
mock: Symbol() as InjectionKey<boolean>,
|
||||
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any> | null>>,
|
||||
pageMetadata: Symbol() as InjectionKey<Ref<PageMetadata | null>>,
|
||||
viewId: Symbol() as InjectionKey<string>,
|
||||
currentStickyTop: Symbol() as InjectionKey<Ref<number>>,
|
||||
currentStickyBottom: Symbol() as InjectionKey<Ref<number>>,
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { Directive } from 'vue';
|
||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||
import { globalEvents } from '@/events.js';
|
||||
|
||||
const handlerMap = new WeakMap<any, any>();
|
||||
const handlerMap = new WeakMap<HTMLElement, () => void>();
|
||||
|
||||
export const adaptiveBorderDirective = {
|
||||
mounted(src) {
|
||||
|
||||
@@ -119,9 +119,9 @@ export const userPreviewDirective = {
|
||||
|
||||
// TODO: 新たにプロパティを作るのをやめMapを使う
|
||||
// ただメモリ的には↓の方が省メモリかもしれないので検討中
|
||||
const self = (el as any)._userPreviewDirective_ = {} as any;
|
||||
|
||||
self.preview = new UserPreview(el, binding.value);
|
||||
el._userPreviewDirective_ = {
|
||||
preview: new UserPreview(el, binding.value),
|
||||
};
|
||||
},
|
||||
|
||||
unmounted(el, binding) {
|
||||
|
||||
@@ -20,7 +20,7 @@ export type ImageCompositorFunction<PS extends ImageCompositorFunctionParams = I
|
||||
}) => void;
|
||||
};
|
||||
|
||||
export type ImageCompositorLayer<FNS extends Record<string, ImageCompositorFunction> = any> = {
|
||||
export type ImageCompositorLayer<FNS extends Record<string, ImageCompositorFunction> = Record<string, ImageCompositorFunction>> = {
|
||||
[K in keyof FNS]: {
|
||||
id: string;
|
||||
functionId: K;
|
||||
@@ -219,7 +219,7 @@ export class ImageCompositor<FNS extends Record<string, ImageCompositorFunction<
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resultTexture, 0);
|
||||
}
|
||||
|
||||
this.renderLayer(layer, preTexture, isLast);
|
||||
this.renderLayer(layer as ImageCompositorLayer, preTexture, isLast);
|
||||
|
||||
preTexture = resultTexture;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export class Pizzax<T extends StateDef> {
|
||||
private pizzaxChannel: BroadcastChannel<PizzaxChannelMessage<T>>;
|
||||
|
||||
// 簡易的にキューイングして占有ロックとする
|
||||
private currentIdbJob: Promise<any> = Promise.resolve();
|
||||
private currentIdbJob: Promise<unknown> = Promise.resolve();
|
||||
private addIdbSetJob<T>(job: () => Promise<T>) {
|
||||
const promise = this.currentIdbJob.then(job, err => {
|
||||
console.error('Pizzax failed to save data to idb!', err);
|
||||
|
||||
@@ -257,7 +257,7 @@ const {
|
||||
const user = ref(result.user);
|
||||
const info = ref(result.info);
|
||||
const ips = ref(result.ips);
|
||||
const ap = ref<any>(null);
|
||||
const ap = ref<Misskey.entities.ApGetResponse | null>(null);
|
||||
const moderator = ref(info.value.isModerator);
|
||||
const silenced = ref(info.value.isSilenced);
|
||||
const suspended = ref(info.value.isSuspended);
|
||||
|
||||
@@ -44,7 +44,7 @@ async function addRelay() {
|
||||
if (canceled || inbox == null) return;
|
||||
misskeyApi('admin/relays/add', {
|
||||
inbox,
|
||||
}).then((relay: any) => {
|
||||
}).then(() => {
|
||||
refresh();
|
||||
}).catch((err: any) => {
|
||||
os.alert({
|
||||
|
||||
@@ -198,15 +198,15 @@ async function mute() {
|
||||
const { canceled, result: period } = await os.select({
|
||||
title: i18n.ts.mutePeriod,
|
||||
items: [{
|
||||
value: 'indefinitely', text: i18n.ts.indefinitely,
|
||||
value: 'indefinitely', label: i18n.ts.indefinitely,
|
||||
}, {
|
||||
value: 'tenMinutes', text: i18n.ts.tenMinutes,
|
||||
value: 'tenMinutes', label: i18n.ts.tenMinutes,
|
||||
}, {
|
||||
value: 'oneHour', text: i18n.ts.oneHour,
|
||||
value: 'oneHour', label: i18n.ts.oneHour,
|
||||
}, {
|
||||
value: 'oneDay', text: i18n.ts.oneDay,
|
||||
value: 'oneDay', label: i18n.ts.oneDay,
|
||||
}, {
|
||||
value: 'oneWeek', text: i18n.ts.oneWeek,
|
||||
value: 'oneWeek', label: i18n.ts.oneWeek,
|
||||
}],
|
||||
default: 'indefinitely',
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkUserName :user="post.user" style="display: block;"/>
|
||||
<MkAcct :user="post.user"/>
|
||||
</div>
|
||||
<MkFollowButton v-if="!$i || $i.id != post.user.id" v-model:user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
|
||||
<!--<MkFollowButton v-if="!$i || $i.id != post.user.id" v-model:user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>-->
|
||||
</div>
|
||||
</div>
|
||||
<MkAd :preferForms="['horizontal', 'horizontal-big']"/>
|
||||
|
||||
@@ -161,7 +161,11 @@ async function _fetch_() {
|
||||
},
|
||||
raw: res.data,
|
||||
};
|
||||
} catch (err: any) {
|
||||
} catch (err) {
|
||||
if (!(err instanceof Error)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
switch (err.message.toLowerCase()) {
|
||||
case 'this theme is already installed':
|
||||
errorKV.value = {
|
||||
|
||||
@@ -36,7 +36,17 @@ misskeyApi('antennas/show', { antennaId: props.antennaId }).then((antennaRespons
|
||||
antenna.value = antennaResponse;
|
||||
});
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
const headerActions = computed(() => antenna.value ? [{
|
||||
icon: 'ti ti-timeline',
|
||||
text: i18n.ts.timeline,
|
||||
handler: () => {
|
||||
router.push('/timeline/antenna/:antennaId', {
|
||||
params: {
|
||||
antennaId: antenna.value!.id,
|
||||
},
|
||||
});
|
||||
},
|
||||
}] : []);
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
definePage(() => ({
|
||||
|
||||
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkButton :link="true" to="/my/antennas/create" primary :class="$style.add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
|
||||
|
||||
<div v-if="antennas.length > 0" class="_gaps">
|
||||
<MkA v-for="antenna in antennas" :key="antenna.id" :class="$style.antenna" :to="`/my/antennas/${antenna.id}`">
|
||||
<MkA v-for="antenna in antennas" :key="antenna.id" :class="$style.antenna" :to="`/timeline/antenna/${antenna.id}`">
|
||||
<div class="name">{{ antenna.name }}</div>
|
||||
</MkA>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton>
|
||||
|
||||
<div v-if="items.length > 0" class="_gaps">
|
||||
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`">
|
||||
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/timeline/list/${list.id}`">
|
||||
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds!.length}/${$i.policies['userEachUserListsLimit']}` }) }})</span></div>
|
||||
<MkAvatars :userIds="list.userIds!" :limit="10"/>
|
||||
</MkA>
|
||||
|
||||
@@ -26,10 +26,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #label>{{ i18n.ts.members }}</template>
|
||||
<template #caption>{{ i18n.tsx.nUsers({ n: `${list.userIds!.length}/${$i.policies['userEachUserListsLimit']}` }) }}</template>
|
||||
|
||||
<div class="_gaps_s">
|
||||
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
|
||||
<div class="_gaps">
|
||||
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()"><i class="ti ti-plus"></i> {{ i18n.ts.addUser }}</MkButton>
|
||||
|
||||
<MkPagination :paginator="membershipsPaginator" withControl>
|
||||
<MkPagination :paginator="membershipsPaginator">
|
||||
<template #default="{ items }">
|
||||
<div class="_gaps_s">
|
||||
<div v-for="item in items" :key="item.id">
|
||||
@@ -67,12 +67,13 @@ import MkInput from '@/components/MkInput.vue';
|
||||
import { userListsCache } from '@/cache.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import { mainRouter } from '@/router.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import { Paginator } from '@/utility/paginator.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const props = defineProps<{
|
||||
listId: string;
|
||||
}>();
|
||||
@@ -162,7 +163,7 @@ async function deleteList() {
|
||||
listId: list.value.id,
|
||||
});
|
||||
userListsCache.delete();
|
||||
mainRouter.push('/my/lists');
|
||||
router.push('/my/lists');
|
||||
}
|
||||
|
||||
async function updateSettings() {
|
||||
@@ -181,7 +182,17 @@ async function updateSettings() {
|
||||
|
||||
watch(() => props.listId, fetchList, { immediate: true });
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
const headerActions = computed(() => list.value ? [{
|
||||
icon: 'ti ti-timeline',
|
||||
text: i18n.ts.timeline,
|
||||
handler: () => {
|
||||
router.push('/timeline/list/:listId', {
|
||||
params: {
|
||||
listId: list.value!.id,
|
||||
},
|
||||
});
|
||||
},
|
||||
}] : []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
|
||||
<div v-if="note">
|
||||
<div v-if="showNext" class="_margin">
|
||||
<MkNotesTimeline direction="up" :withControl="false" :pullToRefresh="false" class="" :paginator="showNext === 'channel' ? nextChannelPaginator : nextUserPaginator" :noGap="true"/>
|
||||
<MkNotesTimeline direction="up" :withControl="false" :pullToRefresh="false" class="" :paginator="showNext === 'channel' ? nextChannelPaginator : nextUserPaginator" :noGap="true" :forceDisableInfiniteScroll="true" />
|
||||
</div>
|
||||
|
||||
<div class="_margin">
|
||||
|
||||
@@ -74,7 +74,35 @@ async function add() {
|
||||
if (canceled || type == null) return;
|
||||
|
||||
const id = genId();
|
||||
children.value.push({ id, type });
|
||||
|
||||
// TODO: page-editor.vueのと共通化
|
||||
if (type === 'text') {
|
||||
children.value.push({
|
||||
id,
|
||||
type,
|
||||
text: '',
|
||||
});
|
||||
} else if (type === 'section') {
|
||||
children.value.push({
|
||||
id,
|
||||
type,
|
||||
title: '',
|
||||
children: [],
|
||||
});
|
||||
} else if (type === 'image') {
|
||||
children.value.push({
|
||||
id,
|
||||
type,
|
||||
fileId: null,
|
||||
});
|
||||
} else if (type === 'note') {
|
||||
children.value.push({
|
||||
id,
|
||||
type,
|
||||
detailed: false,
|
||||
note: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -60,9 +60,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<script lang="ts" setup>
|
||||
import { computed, provide, watch, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { genId } from '@/utility/id.js';
|
||||
import { url } from '@@/js/config.js';
|
||||
import XBlocks from './page-editor.blocks.vue';
|
||||
import { genId } from '@/utility/id.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
@@ -216,7 +216,35 @@ async function add() {
|
||||
if (canceled || type == null) return;
|
||||
|
||||
const id = genId();
|
||||
content.value.push({ id, type });
|
||||
|
||||
// TODO: page-editor.el.section.vueのと共通化
|
||||
if (type === 'text') {
|
||||
content.value.push({
|
||||
id,
|
||||
type,
|
||||
text: '',
|
||||
});
|
||||
} else if (type === 'section') {
|
||||
content.value.push({
|
||||
id,
|
||||
type,
|
||||
title: '',
|
||||
children: [],
|
||||
});
|
||||
} else if (type === 'image') {
|
||||
content.value.push({
|
||||
id,
|
||||
type,
|
||||
fileId: null,
|
||||
});
|
||||
} else if (type === 'note') {
|
||||
content.value.push({
|
||||
id,
|
||||
type,
|
||||
detailed: false,
|
||||
note: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setEyeCatchingImage(img: Event) {
|
||||
|
||||
@@ -73,7 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkUserName :user="page.user" :class="$style.name"/>
|
||||
<MkAcct :user="page.user" :class="$style.acct"/>
|
||||
</MkA>
|
||||
<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user!" :inline="true" :transparent="false" :full="true" :class="$style.follow"/>
|
||||
<!--<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user!" :inline="true" :transparent="false" :full="true" :class="$style.follow"/>-->
|
||||
</div>
|
||||
<div :class="$style.pageDate">
|
||||
<div><i class="ti ti-clock"></i> {{ i18n.ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
|
||||
|
||||
@@ -60,6 +60,7 @@ import { Interpreter, Parser, utils } from '@syuilo/aiscript';
|
||||
import type { Ref } from 'vue';
|
||||
import type { AsUiComponent } from '@/aiscript/ui.js';
|
||||
import type { AsUiRoot } from '@/aiscript/ui.js';
|
||||
import type { Value } from '@syuilo/aiscript/interpreter/value.js';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
@@ -141,7 +142,7 @@ async function run() {
|
||||
switch (type) {
|
||||
case 'end': logs.value.push({
|
||||
id: Math.random(),
|
||||
text: utils.valToString(params.val, true),
|
||||
text: utils.valToString(params.val as Value, true),
|
||||
print: false,
|
||||
}); break;
|
||||
default: break;
|
||||
|
||||
@@ -603,6 +603,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
|
||||
<MkPreferenceContainer k="disableShowingAnimatedImages">
|
||||
<MkSwitch :modelValue="!disableShowingAnimatedImages" @update:modelValue="v => disableShowingAnimatedImages = !v">
|
||||
<template #label><SearchLabel>{{ i18n.ts._settings.enableAnimatedImages }}</SearchLabel></template>
|
||||
<template #caption>
|
||||
<SearchText>{{ i18n.ts.turnOffToImprovePerformance }}</SearchText>
|
||||
<div>{{ i18n.ts.disableShowingAnimatedImages_caption }}</div>
|
||||
</template>
|
||||
</MkSwitch>
|
||||
</MkPreferenceContainer>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker :keywords="['blur']">
|
||||
<MkPreferenceContainer k="useBlurEffect">
|
||||
<MkSwitch v-model="useBlurEffect">
|
||||
|
||||
@@ -7,8 +7,6 @@ import * as Misskey from 'misskey-js';
|
||||
import { markRaw } from 'vue';
|
||||
import { $i } from '@/i.js';
|
||||
import { wsOrigin } from '@@/js/config.js';
|
||||
// TODO: No WebsocketモードでStreamMockが使えそう
|
||||
//import { StreamMock } from '@/utility/stream-mock.js';
|
||||
|
||||
// heart beat interval in ms
|
||||
const HEART_BEAT_INTERVAL = 1000 * 60;
|
||||
|
||||
@@ -11,6 +11,7 @@ export const TIPS = [
|
||||
'postFormUploader',
|
||||
'clips',
|
||||
'userLists',
|
||||
'postForm',
|
||||
'tl.home',
|
||||
'tl.local',
|
||||
'tl.social',
|
||||
|
||||
@@ -8,16 +8,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<a v-if="isRoot" href="https://github.com/misskey-dev/misskey" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--MI_THEME-panel); color:var(--MI_THEME-fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
|
||||
|
||||
<div v-if="!narrow && !isRoot" :class="$style.side">
|
||||
<div :class="$style.banner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
|
||||
<div :class="$style.dashboard">
|
||||
<div :class="$style.sideBanner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
|
||||
<div :class="$style.sideDashboard">
|
||||
<MkVisitorDashboard/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="$style.main">
|
||||
<button v-if="!isRoot" :class="$style.homeButton" class="_button" @click="goHome">
|
||||
<i class="ti ti-home"></i>
|
||||
</button>
|
||||
<div v-if="narrow && !isRoot" :class="$style.header">
|
||||
<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.headerIcon"/>
|
||||
<MkA to="/" :class="$style.headerTitle">{{ instanceName }}</MkA>
|
||||
<MkButton primary rounded :class="$style.headerButton" @click="goHome">{{ i18n.ts.signup }}</MkButton>
|
||||
</div>
|
||||
<div :class="$style.content">
|
||||
<RouterView/>
|
||||
</div>
|
||||
@@ -38,6 +40,7 @@ import { i18n } from '@/i18n.js';
|
||||
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
||||
import { mainRouter } from '@/router.js';
|
||||
import { DI } from '@/di.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
||||
|
||||
@@ -93,16 +96,26 @@ onMounted(() => {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.homeButton {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
.header {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--MI_THEME-panel);
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.headerIcon {
|
||||
width: 48px;
|
||||
vertical-align: bottom;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.headerTitle {
|
||||
margin: 0 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.headerButton {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.side {
|
||||
@@ -112,7 +125,7 @@ onMounted(() => {
|
||||
background: var(--MI_THEME-accent);
|
||||
}
|
||||
|
||||
.banner {
|
||||
.sideBanner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -124,7 +137,7 @@ onMounted(() => {
|
||||
mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
.sideDashboard {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ export function uploadFile(file: File | Blob, options: {
|
||||
const driveFile = JSON.parse(ev.target.response);
|
||||
globalEvents.emit('driveFileCreated', driveFile);
|
||||
resolve(driveFile);
|
||||
}) as (ev: ProgressEvent<EventTarget>) => any;
|
||||
}) as (ev: ProgressEvent<EventTarget>) => void;
|
||||
|
||||
if (options.onProgress) {
|
||||
xhr.upload.onprogress = ev => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { FXS } from './fxs.js';
|
||||
import type { ImageCompositorFunction, ImageCompositorLayer } from '@/lib/ImageCompositor.js';
|
||||
import type { ImageCompositorFunction } from '@/lib/ImageCompositor.js';
|
||||
import { ImageCompositor } from '@/lib/ImageCompositor.js';
|
||||
|
||||
export type ImageEffectorRGB = [r: number, g: number, b: number];
|
||||
@@ -13,7 +13,7 @@ interface CommonParamDef {
|
||||
type: string;
|
||||
label?: string;
|
||||
caption?: string;
|
||||
default: any;
|
||||
default: unknown;
|
||||
}
|
||||
|
||||
interface NumberParamDef extends CommonParamDef {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ref, shallowRef, triggerRef } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { ComputedRef, Ref, ShallowRef } from 'vue';
|
||||
import type { ComputedRef, Ref, ShallowRef, UnwrapRef } from 'vue';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
|
||||
const MAX_ITEMS = 30;
|
||||
@@ -19,7 +19,12 @@ export type MisskeyEntity = {
|
||||
_shouldInsertAd_?: boolean;
|
||||
};
|
||||
|
||||
type FilterByEpRes<E extends Record<string, any>> = {
|
||||
type AbsEndpointType = {
|
||||
req: unknown;
|
||||
res: unknown;
|
||||
};
|
||||
|
||||
type FilterByEpRes<E extends Record<string, AbsEndpointType>> = {
|
||||
[K in keyof E]: E[K]['res'] extends Array<{ id: string }> ? K : never
|
||||
}[keyof E];
|
||||
export type PaginatorCompatibleEndpointPaths = FilterByEpRes<Misskey.Endpoints>;
|
||||
@@ -27,6 +32,8 @@ export type PaginatorCompatibleEndpoints = {
|
||||
[K in PaginatorCompatibleEndpointPaths]: Misskey.Endpoints[K];
|
||||
};
|
||||
|
||||
export type ExtractorFunction<P extends IPaginator, T> = (item: UnwrapRef<P['items']>[number]) => T;
|
||||
|
||||
export interface IPaginator<T = unknown, _T = T & MisskeyEntity> {
|
||||
/**
|
||||
* 外部から直接操作しないでください
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import type { Channels, StreamEvents, IStream, IChannelConnection } from 'misskey-js';
|
||||
|
||||
type AnyOf<T extends Record<any, any>> = T[keyof T];
|
||||
type OmitFirst<T extends any[]> = T extends [any, ...infer R] ? R : never;
|
||||
|
||||
/**
|
||||
* Websocket無効化時に使うStreamのモック(なにもしない)
|
||||
*/
|
||||
export class StreamMock extends EventEmitter<StreamEvents> implements IStream {
|
||||
public readonly state = 'initializing';
|
||||
|
||||
constructor(...args: ConstructorParameters<typeof Misskey.Stream>) {
|
||||
super();
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public useChannel<C extends keyof Channels>(channel: C, params?: Channels[C]['params'], name?: string): ChannelConnectionMock<Channels[C]> {
|
||||
return new ChannelConnectionMock(this, channel, name);
|
||||
}
|
||||
|
||||
public removeSharedConnection(connection: any): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public removeSharedConnectionPool(pool: any): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public disconnectToChannel(): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public send(typeOrPayload: string): void;
|
||||
public send(typeOrPayload: string, payload: any): void;
|
||||
public send(typeOrPayload: Record<string, any> | any[]): void;
|
||||
public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public ping(): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public heartbeat(): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelConnectionMock<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> implements IChannelConnection<Channel> {
|
||||
public id = '';
|
||||
public name?: string; // for debug
|
||||
public inCount = 0; // for debug
|
||||
public outCount = 0; // for debug
|
||||
public channel: string;
|
||||
|
||||
constructor(stream: IStream, ...args: OmitFirst<ConstructorParameters<typeof Misskey.ChannelConnection<Channel>>>) {
|
||||
super();
|
||||
|
||||
this.channel = args[0];
|
||||
this.name = args[1];
|
||||
}
|
||||
|
||||
public send<T extends keyof Channel['receives']>(type: T, body: Channel['receives'][T]): void {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { computed, ref, shallowRef, watch } from 'vue';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
type TourStep = {
|
||||
title: string;
|
||||
description: string;
|
||||
element: HTMLElement;
|
||||
};
|
||||
|
||||
export function startTour(steps: TourStep[]) {
|
||||
return new Promise<void>(async (resolve) => {
|
||||
const currentStepIndex = ref(0);
|
||||
const titleRef = ref(steps[0].title);
|
||||
const descriptionRef = ref(steps[0].description);
|
||||
const anchorElementRef = shallowRef<HTMLElement>(steps[0].element);
|
||||
|
||||
watch(currentStepIndex, (newIndex) => {
|
||||
const step = steps[newIndex];
|
||||
titleRef.value = step.title;
|
||||
descriptionRef.value = step.description;
|
||||
anchorElementRef.value = step.element;
|
||||
});
|
||||
|
||||
const { dispose } = os.popup(await import('@/components/MkSpot.vue').then(x => x.default), {
|
||||
title: titleRef,
|
||||
description: descriptionRef,
|
||||
anchorElement: anchorElementRef,
|
||||
hasPrev: computed(() => currentStepIndex.value > 0),
|
||||
hasNext: computed(() => currentStepIndex.value < steps.length - 1),
|
||||
}, {
|
||||
next: () => {
|
||||
if (currentStepIndex.value >= steps.length - 1) {
|
||||
dispose();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
currentStepIndex.value++;
|
||||
},
|
||||
prev: () => {
|
||||
currentStepIndex.value--;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -222,7 +222,8 @@ export class WatermarkRenderer {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw new Error(`Unrecognized layer type: ${(layer as any).type}`);
|
||||
// @ts-expect-error Should be unreachable
|
||||
throw new Error(`Unrecognized layer type: ${layer.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export const fn = defineImageCompositorFunction<Partial<{
|
||||
gl.uniform1i(u.noBBoxExpansion, params.noBoundingBoxExpansion ? 1 : 0);
|
||||
|
||||
// ウォーターマークテクスチャ
|
||||
const wm = textures.get(params.watermark);
|
||||
const wm = params.watermark ? textures.get(params.watermark) : null;
|
||||
if (wm) {
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, wm.texture);
|
||||
|
||||
@@ -24,6 +24,7 @@ import { Interpreter, Parser, utils } from '@syuilo/aiscript';
|
||||
import { useWidgetPropsManager } from './widget.js';
|
||||
import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
|
||||
import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
|
||||
import type { Value } from '@syuilo/aiscript/interpreter/value.js';
|
||||
import * as os from '@/os.js';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
|
||||
@@ -83,7 +84,7 @@ const run = async () => {
|
||||
switch (type) {
|
||||
case 'end': logs.value.push({
|
||||
id: genId(),
|
||||
text: utils.valToString(params.val, true),
|
||||
text: utils.valToString(params.val as Value, true),
|
||||
print: false,
|
||||
}); break;
|
||||
default: break;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import { render } from 'buraha';
|
||||
|
||||
const canvas = new OffscreenCanvas(64, 64);
|
||||
@@ -18,5 +21,5 @@ onmessage = (event) => {
|
||||
|
||||
render(event.data.hash, canvas);
|
||||
const bitmap = canvas.transferToImageBitmap();
|
||||
postMessage({ id: event.data.id, bitmap }, [bitmap]);
|
||||
self.postMessage({ id: event.data.id, bitmap }, [bitmap]);
|
||||
};
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
const canvas = globalThis.OffscreenCanvas && new OffscreenCanvas(1, 1);
|
||||
// 環境によってはOffscreenCanvasが存在しないため
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const gl = canvas?.getContext('webgl2');
|
||||
if (gl) {
|
||||
postMessage({ result: true });
|
||||
self.postMessage({ result: true });
|
||||
} else {
|
||||
postMessage({ result: false });
|
||||
self.postMessage({ result: false });
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"declaration": false,
|
||||
"sourceMap": false,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "Bundler",
|
||||
"removeComments": false,
|
||||
"noLib": false,
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
"lint": "pnpm typecheck && pnpm eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "24.9.1",
|
||||
"@types/node": "24.9.2",
|
||||
"@types/wawoff2": "1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||
"@typescript-eslint/parser": "8.46.1"
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user