Compare commits

...

53 Commits

Author SHA1 Message Date
247bd43ae2 12.55.0 2020-11-08 17:10:43 +09:00
a6685b1559 New Crowdin updates (#6814)
* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Kabyle)

* New translations ja-JP.yml (Kannada)

* New translations ja-JP.yml (Uyghur)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (French)
2020-11-08 17:09:42 +09:00
66c4e8064b Add bounce MFM animation 2020-11-08 17:08:51 +09:00
9d1fa3f202 autoWatch機能を削除 2020-11-08 16:49:23 +09:00
a6985d7dc7 Fix #6819 2020-11-08 16:37:51 +09:00
027c021ac9 アスタリスク3つでのtadaアニメーションを復活 2020-11-08 16:35:22 +09:00
604205ec09 MFMチートシートに数式追加 2020-11-08 16:14:49 +09:00
77db016866 MFMチートシート 2020-11-08 15:24:46 +09:00
c6a009dbae 最近使用した絵文字からリアクションピッカーに設定してある絵文字は除外するように 2020-11-08 13:58:16 +09:00
4299e3f90c スマホでデスクトップモードにできないように 2020-11-08 13:39:36 +09:00
19f4812c03 Remove outdated test 2020-11-08 12:42:13 +09:00
d01c465a8d ユーザーピッカーに最近使用したユーザーを表示するように 2020-11-08 12:40:56 +09:00
4f1409601e Respect order when userIds specified 2020-11-08 12:40:31 +09:00
52cffe0864 絵文字ピッカーで最近使用した絵文字がバグっているのを修正
あとMkEmojiをリファクタリング
2020-11-08 12:08:07 +09:00
0866d5c055 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-11-08 11:25:31 +09:00
78c08f6503 Clean up 2020-11-08 11:25:28 +09:00
27d0ac3d75 In HTML to MFM, use angle bracket if needed (#6817) 2020-11-08 00:38:50 +09:00
a8776002f3 Improve readability 2020-11-07 23:43:03 +09:00
31aa008566 Improve MFM
MFMの構文を調整 + 新しいアニメーション追加
Resolve #6816
2020-11-07 23:41:21 +09:00
9d405b4581 絵文字ピッカーでエンターしたときに検索結果の先頭のもので確定できるように 2020-11-07 21:33:36 +09:00
80c490a18b 絵文字ピッカーでAND検索に対応 2020-11-07 21:28:28 +09:00
30c9c3739f 12.54.0 2020-11-07 12:49:16 +09:00
ee0e7a09e0 Update dependencies 🚀 2020-11-07 12:48:21 +09:00
bfd9577f0d 絵文字ピッカーを開いたときに画面がスクロールするのを修正 2020-11-07 12:35:12 +09:00
0cada4ca76 New Crowdin updates (#6801)
* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)
2020-11-07 12:32:27 +09:00
a718ccc0b6 Add missing languages (#6800) 2020-11-07 12:32:08 +09:00
1fcfd8e645 ヘッダーに表示されるタブのインジケーターを実装 (#6803)
* Implemente indicators on headers

* 微調整
2020-11-07 12:31:23 +09:00
c6dd932a0b Improve usability 2020-11-07 12:30:16 +09:00
b79eed01e0 絵文字ピッカーの検索に絵文字をペーストしたとき確定されないのを修正 2020-11-07 10:56:38 +09:00
3a7dbe9764 UI切り替えがサイドバーに設置されていない場合に機能しない問題を修正 2020-11-07 10:54:52 +09:00
bef2534fa8 絵文字ピッカーを強化 + 絵文字ピッカーをリアクションピッカーとして使えるように
Resolve #5079
Resolve #3219
2020-11-07 10:43:27 +09:00
888dcd2559 画像ダイアログでスクロールが発生しないように 2020-11-07 05:00:42 +09:00
2b69fca6bd 12.53.0 2020-11-03 22:11:23 +09:00
7d088d42b4 New Crowdin updates (#6797)
* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)
2020-11-03 22:08:29 +09:00
f8ad303b13 リバーシの観戦者を表示するように
Resolve #1830
2020-11-03 22:02:55 +09:00
3c59c6fc9b Refactoring 2020-11-03 20:36:12 +09:00
7353d729d7 ヘッダーの戻るボタンがページリロードすると消える問題を修正 2020-11-03 20:28:38 +09:00
62591e0e7a リバーシのリプレイ
Related #1240
2020-11-03 19:54:35 +09:00
012f15d84b chore: β 2020-11-03 17:17:42 +09:00
e57c6f94d2 Clean up 2020-11-03 17:16:38 +09:00
40b27e8ad8 Clean up 2020-11-03 17:13:21 +09:00
055e9f21b7 wip: Desktop UI 2020-11-03 17:04:37 +09:00
d7085b17fe wip: Desktop UI 2020-11-03 17:00:47 +09:00
0d4d7c9c0c Tweak page window initial size 2020-11-03 17:00:18 +09:00
99209d36e1 Fix bug of c3ae6f3a4 2020-11-03 16:21:28 +09:00
e2a9a0ff3d Refactoring 2020-11-03 15:59:13 +09:00
ab166959a4 Improve performance 2020-11-03 15:49:31 +09:00
ab692cfa3d Fix bug of c3ae6f3a4 2020-11-03 15:44:56 +09:00
c3ae6f3a4a Refactor 2020-11-03 15:22:55 +09:00
5ef4a52bbd Improve usability of emoji page 2020-11-03 10:54:41 +09:00
582768a5e4 チャットリンクの挙動を改善 2020-11-03 10:43:50 +09:00
1852d1cc6f Improve drive 2020-11-03 10:27:00 +09:00
7a5a541a4e 相対パスでコピーされるのを修正 2020-11-03 10:06:19 +09:00
149 changed files with 2670 additions and 2012 deletions

View File

@ -285,7 +285,6 @@ unregister: "إلغاء التسجيل"
passwordLessLogin: "لِج مِن دون كلمة سرية"
resetPassword: "أعد تعيين كلمتك السرية"
newPasswordIs: "كلمتك السرية الجديدة هي {password}"
autoNoteWatch: "راقب الملاحظات تلقائيا"
share: "شارِك"
notFound: "غير موجود"
help: "المساعدة"
@ -380,6 +379,11 @@ smtpHost: "المضيف"
smtpUser: "اسم المستخدم"
smtpPass: "الكلمة السرية"
display: "المظهر"
_mfm:
mention: "أشر الى"
quote: "اقتبس"
emoji: "إيموجي مخصص"
search: "البحث"
_reversi:
total: "المجموع"
_channel:

View File

@ -373,8 +373,6 @@ unregister: "Deaktivieren"
passwordLessLogin: "Passwortloses Anmelden einrichten"
resetPassword: "Passwort zurücksetzen"
newPasswordIs: "Das neue Passwort ist \"{password}\""
autoNoteWatch: "Notizen automatisch beobachten"
autoNoteWatchDescription: "Werde über Notizen, auf die du reagiert oder geantwortet hast, informiert"
reduceUiAnimation: "Animationen der Benutzeroberfläche reduzieren"
share: "Teilen"
notFound: "Nicht gefunden"
@ -542,6 +540,7 @@ pluginInstallWarn: "Installiere nur vertrauenswürdige Plugins."
deck: "Deck"
undeck: "Deck verlassen"
useBlurEffectForModal: "Weichzeichnungseffekt für Modals verwenden"
useFullReactionPicker: "Vollständige Reaktionsauswahl nutzen"
generateAccessToken: "Zugriffstoken generieren"
permission: "Berechtigungen"
enableAll: "Alle aktivieren"
@ -602,6 +601,16 @@ instanceTicker: "Instanz-Informationen von Notizen"
waitingFor: "Warte auf {x}"
random: "Zufällig"
system: "System"
switchUi: "UI wechseln"
desktop: "Desktop"
_mfm:
mention: "Erwähnung"
hashtag: "Hashtag"
link: "Link"
center: "Bestandteile zentrieren"
quote: "Zitieren"
emoji: "Benutzerdefinierte Emojis"
search: "Suchen"
_reversi:
reversi: "Reversi"
gameSettings: "Spieleinstellungen"

View File

@ -373,8 +373,6 @@ unregister: "Unregister"
passwordLessLogin: "Set up password-less login"
resetPassword: "Reset password"
newPasswordIs: "The new password is \"{password}\""
autoNoteWatch: "Watch note automatically"
autoNoteWatchDescription: "Get notified about the notes which you reactioned or replied."
reduceUiAnimation: "Reduce UI animation"
share: "Share"
notFound: "Not found"
@ -542,6 +540,7 @@ pluginInstallWarn: "Please do not install untrustworthy plugins."
deck: "Deck"
undeck: "Leave Deck"
useBlurEffectForModal: "Use blur effect for modals"
useFullReactionPicker: "Use full-size reaction picker"
generateAccessToken: "Generate access token"
permission: "Permissions"
enableAll: "Enable all"
@ -602,6 +601,16 @@ instanceTicker: "Instance information of notes"
waitingFor: "Waiting for {x}"
random: "Random"
system: "System"
switchUi: "Switch UI"
desktop: "Desktop"
_mfm:
mention: "Mention"
hashtag: "Hashtag"
link: "Link"
center: "Center elements"
quote: "Quote"
emoji: "Custom Emoji"
search: "Search"
_reversi:
reversi: "Reversi"
gameSettings: "Game settings"

View File

@ -373,8 +373,6 @@ unregister: "Cancelar registro"
passwordLessLogin: "Iniciar sesión sin contraseña"
resetPassword: "Resetear contraseña"
newPasswordIs: "La nueva contraseña es \"{password}\""
autoNoteWatch: "Ver nota automáticamente"
autoNoteWatchDescription: "Recibe notificaciones sobre las notas de otros usuarios que a los que respondiste y reaccionaste"
reduceUiAnimation: "Reducir la animación de la UI"
share: "Compartir"
notFound: "No se encuentra"
@ -598,9 +596,57 @@ openInNewTab: "Abrir en una Nueva Pestaña"
openInSideView: "Abrir en una vista al costado"
defaultNavigationBehaviour: "Navegación por defecto"
editTheseSettingsMayBreakAccount: "Editar estas configuraciones puede dañar su cuenta."
instanceTicker: "Información de notas de la instancia"
waitingFor: "Esperando a {x}"
random: "Aleatorio"
system: "Sistema"
switchUi: "Cambiar interfaz de usuario"
desktop: "Escritorio"
_mfm:
mention: "Menciones"
hashtag: "Hashtag"
link: "Vínculo"
center: "Centrar"
quote: "Citar"
emoji: "Emojis personalizados"
search: "Buscar"
_reversi:
reversi: "Reversi"
gameSettings: "Configuración del juego"
chooseBoard: "Elegir tablero"
blackOrWhite: "Blancas/Negras"
blackIs: "{name} juega con fichas negras"
rules: "Reglas"
botSettings: "Opciones del bot"
thisGameIsStartedSoon: "El juego empezará en segundos"
waitingForOther: "Esperando el turno del adversario"
waitingForMe: "Esperando mi turno"
waitingBoth: "Prepárate"
ready: "Listo"
cancelReady: "No estoy listo"
opponentTurn: "Turno del adversario"
myTurn: "Mi turno"
turnOf: "Turno de {name}"
pastTurnOf: "Turno de {name}"
surrender: "Rendirse"
surrendered: "Por rendirse"
drawn: "Empate"
won: "{name} ha ganado"
black: "Negro"
white: "Blanco"
total: "Total"
turnCount: "Turno {count}"
myGames: "Mis juegos"
allGames: "Todos los juegos"
ended: "Finalizado"
playing: "Jugando"
isLlotheo: "El que tenga menos fichas gana (LLoTheO)"
loopedMap: "Mapa en bucle"
canPutEverywhere: "Puedes colocar donde quieras"
_instanceTicker:
none: "No mostrar"
remote: "Mostrar a usuarios remotos"
always: "Mostrar siempre"
_serverDisconnectedBehavior:
reload: "Recargar automáticamente"
dialog: "Mostrar diálogo de advertencia"

View File

@ -372,8 +372,6 @@ unregister: "Se désinscrire"
passwordLessLogin: "Connectez-vous sans mot de passe"
resetPassword: "Réinitialiser mot de passe"
newPasswordIs: "Votre nouveau mot de passe est \"{password}\""
autoNoteWatch: "Surveiller les notes automatiquement"
autoNoteWatchDescription: "Soyez informé des notes auxquelles vous avez réagi ou répondu."
reduceUiAnimation: "Réduire les animations dans linterface"
share: "Partager"
notFound: "Non trouvé"
@ -582,6 +580,14 @@ setMultipleBySeparatingWithSpace: "Vous pouvez définir plus dun, séparés p
fileIdOrUrl: "ID du fichier ou URL"
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
random: "Aléatoire"
_mfm:
mention: "Mentionner"
hashtag: "Hashtags"
link: "Lien"
center: "Centrée"
quote: "Citer"
emoji: "Émojis personnalisés"
search: "Rechercher"
_reversi:
total: "Total"
_serverDisconnectedBehavior:

View File

@ -15,17 +15,24 @@ const merge = (...args) => args.reduce((a, c) => ({
const languages = [
'ar-SA',
//'cs-CZ',
//'da-DK',
'cs-CZ',
'da-DK',
'de-DE',
'en-US',
'es-ES',
'fr-FR',
'ja-JP',
'ja-KS',
'kab-KAB',
'kn-IN',
'ko-KR',
//'nl-NL',
//'pl-PL',
'nl-NL',
'no-NO',
'pl-PL',
'pt-PT',
'ru-RU',
'ug-CN',
'uk-UA',
'zh-CN',
'zh-TW',
];

View File

@ -373,8 +373,6 @@ unregister: "登録を解除"
passwordLessLogin: "パスワード無しログイン"
resetPassword: "パスワードをリセット"
newPasswordIs: "新しいパスワードは「{password}」です"
autoNoteWatch: "ノートの自動ウォッチ"
autoNoteWatchDescription: "あなたがリアクションしたり返信したりした他のユーザーのノートに関する通知を受け取るようにします。"
reduceUiAnimation: "UIのアニメーションを減らす"
share: "共有"
notFound: "見つかりません"
@ -542,6 +540,7 @@ pluginInstallWarn: "信頼できないプラグインはインストールしな
deck: "デッキ"
undeck: "デッキ解除"
useBlurEffectForModal: "モーダルにぼかし効果を使用"
useFullReactionPicker: "フル機能リアクションピッカーを使用"
generateAccessToken: "アクセストークンの発行"
permission: "権限"
enableAll: "全て有効にする"
@ -602,6 +601,57 @@ instanceTicker: "ノートのインスタンス情報"
waitingFor: "{x}を待っています"
random: "ランダム"
system: "システム"
switchUi: "UI切り替え"
desktop: "デスクトップ"
_mfm:
cheatSheet: "MFMチートシート"
intro: "MFMは、Misskey内の様々な場所で使用できる専用のマークアップ言語です。ここでは、MFMで使用可能な構文一覧が確認できます。"
dummy: "MisskeyでFediverseの世界が広がります"
mention: "メンション"
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができます。"
hashtag: "ハッシュタグ"
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができます。"
url: "URL"
urlDescription: "URLを示すことができます。"
link: "リンク"
linkDescription: "文章の特定の範囲を、URLに紐づけることができます。"
bold: "太字"
boldDescription: "文字を太く表示して強調することができます。"
small: "目立たなく"
smallDescription: "内容を小さく・薄く表示させることができます。"
center: "中央寄せ"
centerDescription: "内容を中央寄せで表示させることができます。"
inlineCode: "コード(インライン)"
inlineCodeDescription: "プログラムなどのコードをインラインでシンタックスハイライトします。"
blockCode: "コード(ブロック)"
blockCodeDescription: "複数行のプログラムなどのコードをブロックでシンタックスハイライトします。"
inlineMath: "数式(インライン)"
inlineMathDescription: "数式(KaTeX)をインラインで表示します。"
blockMath: "数式(ブロック)"
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示します。"
quote: "引用"
quoteDescription: "内容が引用であることを示すことができます。"
emoji: "カスタム絵文字"
emojiDescription: "コロンでカスタム絵文字名を囲むと、カスタム絵文字を表示させることができます。"
search: "検索"
searchDescription: "入力済み検索ボックスを表示させることができます。"
flip: "反転"
flipDescription: "内容を上下または左右に反転させます。"
jelly: "アニメーション(びよんびよん)"
jellyDescription: "びよんびよんするアニメーションを与えます。"
tada: "アニメーション(じゃーん)"
tadaDescription: "ジャーン!という感じのアニメーションを与えます。"
jump: "アニメーション(ジャンプ)"
jumpDescription: "飛び跳ねるようなアニメーションを与えます。"
bounce: "アニメーション(バウンド)"
bounceDescription: "ぽよんぽよん弾むようなアニメーションを与えます。"
shake: "アニメーション(ぶるぶる)"
shakeDescription: "ぶるぶるするアニメーションを与えます。"
twitch: "アニメーション(ブレ)"
twitchDescription: "激しくブレるアニメーションを与えます。"
spin: "アニメーション(回転)"
spinDescription: "回転するアニメーションを与えます。"
_reversi:
reversi: "リバーシ"

View File

@ -373,8 +373,6 @@ unregister: "登録やめる"
passwordLessLogin: "パスワード無くてもログインできるようにする"
resetPassword: "パスワードをリセット"
newPasswordIs: "今度のパスワードは「{password}」や"
autoNoteWatch: "ノートを勝手に見張っとく"
autoNoteWatchDescription: "あんたがリアクションや返信した他のユーザーのノートの通知をあんたも受け取れるようになるんやで。通知欄の流れがめっちゃ早くなるで。"
reduceUiAnimation: "UIの動きやアニメーションを減らしてくれや。"
share: "わけわけ"
notFound: "見つからへんね"
@ -417,6 +415,11 @@ checking: "確認しとるで"
smtpHost: "ホスト"
smtpUser: "ユーザー名"
smtpPass: "パスワード"
_mfm:
mention: "メンション"
quote: "引用"
emoji: "カスタム絵文字"
search: "探す"
_sidebar:
icon: "アイコン"
_theme:

View File

@ -35,6 +35,9 @@ userList: "Tibdarin"
uiLanguage: "Tutlayt n wegrudem"
smtpUser: "Isem n umseqdac"
smtpPass: "Awal uffir"
_mfm:
mention: "Bder"
search: "Nadi"
_theme:
keys:
mention: "Bder"

View File

@ -56,6 +56,8 @@ instances: "ನಿದರ್ಶನ"
remove: "ಅಳಿಸು"
smtpUser: "ಬಳಕೆಹೆಸರು"
smtpPass: "ಗುಪ್ತಪದ"
_mfm:
search: "ಹುಡುಕು"
_sfx:
notification: "ಅಧಿಸೂಚನೆಗಳು"
_widgets:

View File

@ -362,8 +362,6 @@ unregister: "등록 해제"
passwordLessLogin: "비밀번호 없이 로그인"
resetPassword: "비밀번호 재설정"
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
autoNoteWatch: "노트를 자동으로 지켜보기"
autoNoteWatchDescription: "리액션하거나 답글을 남긴 다른 유저의 노트에 대한 알림을 받습니다."
reduceUiAnimation: "UI의 애니메이션을 줄이기"
share: "공유"
notFound: "찾을 수 없습니다"
@ -550,6 +548,14 @@ logs: "로그"
database: "데이터베이스"
channel: "채널"
random: "랜덤"
_mfm:
mention: "멘션"
hashtag: "해시태그"
link: "링크"
center: "가운데 정렬"
quote: "인용"
emoji: "커스텀 이모지"
search: "검색"
_reversi:
total: "합계"
_channel:

View File

@ -10,6 +10,8 @@ cancel: "Anuluj"
enterUsername: "Wprowadź nazwę użytkownika"
smtpUser: "Nazwa użytkownika"
smtpPass: "Hasło"
_mfm:
search: "Szukaj"
_sfx:
notification: "Powiadomienia"
_widgets:

View File

@ -6,12 +6,12 @@ search: "Поиск"
notifications: "Уведомления"
username: "Имя пользователя"
password: "Пароль"
fetchingAsApObject: "Приём с других сайтов"
ok: "Согласен"
gotIt: "Понятно!"
fetchingAsApObject: "Приём с других сайтов"
ok: "Окей"
gotIt: "Ясно!"
cancel: "Отмена"
enterUsername: "Введите имя пользователя"
renotedBy: "{user} передаёт"
renotedBy: "{user} передаёт"
noNotes: "Нет ни одной заметки"
noNotifications: "Нет ни одного уведомления"
instance: "Инстанс"
@ -30,16 +30,16 @@ uploading: "Загрузка..."
save: "Сохранить"
users: "Пользователи"
addUser: "Добавить пользователя"
favorite: "Избранное"
favorite: "В избранное"
favorites: "Избранное"
unfavorite: "Убрать из избранных"
unfavorite: "Убрать из избранного"
pin: "Закрепить в профиле"
unpin: "Открепить от профиля"
copyContent: "Скопировать содержимое"
copyLink: "Скопировать ссылку"
delete: "Удалить"
deleteAndEdit: "Удалить и отредактировать"
deleteAndEditConfirm: "Удалить этот пост и создать отредактированный? Все реакции, ссылки и ответы на существующий будут будут потеряны."
deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
addToList: "Добавить в список"
sendMessage: "Отправить сообщение"
copyUsername: "Скопировать имя пользователя"
@ -51,19 +51,19 @@ receiveFollowRequest: "Получен запрос на подписку"
followRequestAccepted: "Запрос на подписку принят"
mention: "Упоминание"
mentions: "Упоминания"
directNotes: "Прямые сообщения"
importAndExport: "Импорт / Экспорт"
directNotes: "Личные сообщения"
importAndExport: "Импорт и экспорт"
import: "Импорт"
export: "Экспорт"
files: "Файлы"
download: "Скачать"
driveFileDeleteConfirm: "Удалить файл {name} ? Посты с ним также будут удалены"
unfollowConfirm: "Удалить из подписок {name}?"
driveFileDeleteConfirm: "Удалить файл «{name}»? Заметки с ним также будут удалены."
unfollowConfirm: "Удалить из подписок пользователя {name}?"
exportRequested: "Вы запросили экспорт. Это может занять некоторое время. Результат будет добавлен на «Диск»."
importRequested: "Вы запросили импорт. Это может занять некоторое время."
lists: "Списки"
noLists: "Нет ни одного списка"
note: "Пост"
note: "Заметка"
notes: "Заметки"
following: "Подписки"
followers: "Подписчики"
@ -75,10 +75,10 @@ somethingHappened: "Что-то пошло не так"
retry: "Повторить попытку"
pageLoadError: "Не удалось загрузить страницу"
pageLoadErrorDescription: "Обычно это случается из-за сбоев в сети или кэша браузера. Попробуйте очистить кэш, или подождать пару минут, а потом попытаться загрузить страницу снова."
enterListName: "Введите имя списка"
enterListName: "Название списка"
privacy: "Конфиденциальность"
makeFollowManuallyApprove: "Принимать подписчиков вручную"
defaultNoteVisibility: "Видимость постов по умолчанию"
defaultNoteVisibility: "Видимость заметок по умолчанию"
follow: "Подписка"
followRequest: "Запрос на подписку"
followRequests: "Запросы на подписку"
@ -94,8 +94,8 @@ clickToShow: "Нажмите для просмотра"
sensitive: "Содержимое не для всех"
add: "Добавить"
reaction: "Реакции"
reactionSettingDescription: "Выберите, что показывать в палитре реакций"
rememberNoteVisibility: "Запоминать видимость поста"
reactionSettingDescription: "Подберите, что будет у вас в палитре реакций"
rememberNoteVisibility: "Запоминать видимость заметок"
attachCancel: "Удалить вложение"
markAsSensitive: "Отметить как «не для всех»"
unmarkAsSensitive: "Снять отметку «не для всех»"
@ -113,7 +113,7 @@ unsuspendConfirm: "Разморозить этот аккаунт?"
selectList: "Выберите список"
selectAntenna: "Выберите антенну"
selectWidget: "Выберите виджет"
editWidgets: "Редактировать виджет"
editWidgets: "Редактировать виджеты"
editWidgetsExit: "Готово"
customEmojis: "Эмодзи пользователя"
emoji: "Эмодзи"
@ -128,13 +128,13 @@ flagAsCat: "Аккаунт кота"
autoAcceptFollowed: "Принимать подписчиков автоматически"
addAcount: "Добавить аккаунт"
loginFailed: "Неудачная попытка входа"
showOnRemote: "Перейти к оригиналу на его сайт"
showOnRemote: "Перейти к оригиналу на сайт"
general: "Общее"
wallpaper: "Обои"
setWallpaper: "Установить обои"
removeWallpaper: "Удалить обои"
searchWith: "Искать в {q}"
youHaveNoLists: "У вас нет списков"
searchWith: "Найденное «{q}»"
youHaveNoLists: "У вас нет ни одного списка"
followConfirm: "Подписаться на {name}?"
proxyAccount: "Учётная запись прокси"
proxyAccountDescription: "Учетная запись прокси предназначена служить подписчиком на пользователей с других сайтов. Например, если пользователь добавит кого-то с другого сайта а список, деятельность того не отобразится, пока никто с этого же сайта не подписан на него. Чтобы это стало возможным, на него подписывается прокси."
@ -150,15 +150,15 @@ latestRequestReceivedAt: "Последний полученный запрос"
latestStatus: "Последний статус"
storageUsage: "Использовано"
charts: "Диаграммы"
perHour: "Каждый час"
perDay: "Каждый день"
perHour: "По часам"
perDay: "По дням"
stopActivityDelivery: "Остановить отправку обновлений активности"
blockThisInstance: "Блокировать этот инстанс"
operations: "Операции"
software: "Программы"
version: "Версия"
metadata: "Метаданные"
withNFiles: "файлов: {n}"
withNFiles: "Файлы, {n} шт."
monitor: "Монитор"
jobQueue: "Очередь заданий"
cpuAndMemory: "Процессор и память"
@ -189,7 +189,7 @@ noCustomEmojis: "Эмодзи пользователя отсутствуют"
noJobs: "Нет заданий"
federating: "Федерируется"
blocked: "Заблокировано"
suspended: "Приостановленный"
suspended: "Заморожено"
all: "Всё"
subscribing: "Подписка"
publishing: "Публикация"
@ -202,7 +202,7 @@ security: "Безопасность"
retypedNotMatch: "Не совпадают"
currentPassword: "Текущий пароль"
newPassword: "Новый пароль"
newPasswordRetype: "Новый пароль (повторно)"
newPasswordRetype: "Новый пароль (ещё раз)"
attachFile: "Прикрепить файлы"
more: "Ещё!"
featured: "Подборка"
@ -225,7 +225,7 @@ uploadFromUrlRequested: "Загрузка выбранного"
uploadFromUrlMayTakeTime: "Загрузка может занять некоторое время."
explore: "Обзор"
games: "Игры Misskey"
messageRead: "Прочитанных"
messageRead: "Прочитали"
noMoreHistory: "История закончилась"
startMessaging: "Отправить сообщение"
nUsersRead: "Прочитали {n}"
@ -237,7 +237,7 @@ remoteUserCaution: "Это пользователь с другого сайта
activity: "Активность"
images: "Изображения"
birthday: "День рождения"
yearsOld: "{age} лет"
yearsOld: "Возраст: {age}"
registeredDate: "Дата регистрации"
location: "Местоположение"
theme: "Тема"
@ -250,10 +250,10 @@ darkThemes: "Тёмные темы"
syncDeviceDarkMode: "Синхронизировать с темным режимом устройства"
drive: "Диск"
fileName: "Имя файла"
selectFile: "Выберите Файл"
selectFiles: "Выберите Файл"
selectFile: "Выберите файл"
selectFiles: "Выберите файлы"
selectFolder: "Выберите папку"
selectFolders: "Выберите папку"
selectFolders: "Выберите папки"
renameFile: "Переименовать файл"
folderName: "Имя папки"
createFolder: "Создать папку"
@ -265,51 +265,51 @@ emptyFolder: "Папка пуста"
unableToDelete: "Удаление невозможно"
inputNewFileName: "Введите имя нового файла"
inputNewFolderName: "Пожалуйста, введите новое имя папки!"
circularReferenceFolder: "Конечная папка - это вложенная папка, которую вы хотите переместить."
hasChildFilesOrFolders: "Эта папка не пуста и не может быть удалена."
copyUrl: "Копировать URL"
circularReferenceFolder: "Вы пытаетесь переместить папку внутрь себя."
hasChildFilesOrFolders: "В этой папке что-то есть, так что она не может быть удалена."
copyUrl: "Копировать ссылку"
rename: "Переименовать"
avatar: "Иконка"
banner: "Баннер"
avatar: "Аватар"
banner: "Шапка"
nsfw: "Содержимое не для всех"
whenServerDisconnected: "Когда соединение с сервером потеряно"
disconnectedFromServer: "Разорвано соединение с сервером"
reload: "Перезагрузить"
doNothing: "Ничего не делать"
reloadConfirm: одтвердить перезагрузку?"
reloadConfirm: "Перезагрузить ленту?"
watch: "Следить"
unwatch: "Отписаться"
accept: "Принять"
reject: "Отклонить"
normal: "Стабильно"
instanceName: "Имя экземпляра"
instanceName: "Название инстанса"
instanceDescription: "Описание инстанса"
maintainerName: "Имя администратора"
maintainerEmail: "email администратора"
tosUrl: "Пользовательское соглашение URL"
thisYear: "Текущий год"
thisMonth: "Текущий месяц"
today: "Сегодня"
dayX: "{day}дней"
monthX: "{month}месяц"
yearX: "{year}год"
pages: "Страница"
integration: "подключение"
maintainerEmail: "Электронная почта администратора"
tosUrl: "Ссылка на пользовательское соглашение"
thisYear: "Этот год"
thisMonth: "Этот месяц"
today: "Этот день"
dayX: "{day} день"
monthX: "{month} месяц"
yearX: "{year} год"
pages: "Страницы"
integration: "Интеграция"
connectSerice: "Соединение"
disconnectSerice: "Отключение"
enableLocalTimeline: "Включить локальную ленту"
enableGlobalTimeline: "Включить глобальную ленту"
disablingTimelinesInfo: "Администраторы и Модераторы всегда будут иметь доступ ко всем временным параметрам, даже если они не включены."
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам, даже если они отключены."
registration: "Регистрация"
enableRegistration: "Разрешить регистрацию"
invite: "Пригласить"
proxyRemoteFiles: "Удаленные файлы прокси"
proxyRemoteFilesDescription: "Если эта функция включена, удаленные файлы, которые (1) не хранятся локально или (2) были удалены с превышением лимита хранения, будут проксированы локально (с эскизами). Это не влияет на хранение на сервере."
driveCapacityPerLocalAccount: "Емкость диска для локального пользователя"
driveCapacityPerRemoteAccount: "Емкость диска для удаленного пользователя"
proxyRemoteFiles: "Файлы с других сайтов пускать через прокси"
proxyRemoteFilesDescription: "Когда эта настройка включена, файлы с других серверов, которые не сохранены или удалены для освобождения места, будут проксироваться локально, а так же для них будут создаваться миниатюры. Эта настройка не затрагивает хранение на сервере."
driveCapacityPerLocalAccount: "Объём диска на одного локального пользователя"
driveCapacityPerRemoteAccount: "Объём диска на одного пользователя с другого сайта"
inMb: "В мегабайтах"
iconUrl: "URL-адрес иконки"
bannerUrl: "URL-адрес изображения баннера"
iconUrl: "Ссылка на аватар"
bannerUrl: "Ссылка на изображение в шапке"
basicInfo: "Общая информация"
pinnedUsers: "Прикреплённый пользователь"
pinnedUsersDescription: "Перечислите по одному имени пользователя в строке. Пользователи, перечисленные здесь, будут привязаны к закладке \"Изучение\"."
@ -321,24 +321,24 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Включить reCAPTCHA"
recaptchaSiteKey: "Ключ сайта"
recaptchaSecretKey: "Секретный ключ"
avoidMultiCaptchaConfirm: "Использование нескольких Captchas может вызвать помехи. Хотите отключить другую Captcha? Вы можете оставить несколько Captchas включенными, нажав \"Отмена\"."
avoidMultiCaptchaConfirm: "Несколько способов проверки могут мешать друг другу. Подтвердите, если хотите отключить другие способы. Или нажмите «Отмена», чтобы оставить их включёнными."
antennas: "Антенны"
manageAntennas: "Настройки антенн"
name: "Имя"
name: "Название"
antennaSource: "Источник антенны"
antennaKeywords: "Ключевые слова"
antennaExcludeKeywords: "Исключения"
antennaKeywordsDescription: "Разделяйте пробелами для условия \"И\". Разделяйте переводом строки для \"ИЛИ\"."
notifyAntenna: "Уведомлять о новых записях"
withFileAntenna: "Включать только заметки с вложениями"
antennaKeywordsDescription: "Пишите слова через пробел в одной строке, чтобы ловить их появление вместе; на отдельных строках располагайте слова, или группы слов, чтобы ловить любые из них."
notifyAntenna: "Уведомлять о новых заметках"
withFileAntenna: "Только заметки с вложениями"
serviceworker: "ServiceWorker"
enableServiceworker: "Включить ServiceWorker"
antennaUsersDescription: "Располагать каждое имя с новой строки"
antennaUsersDescription: "Пишите каждое название аккаута на отдельной строке"
caseSensitive: "С учётом регистра"
withReplies: "Включить ответы"
withReplies: "Включая ответы"
connectedTo: "Вы подключены к следующим аккаунтам"
notesAndReplies: "Посты и ответы"
withFiles: "с файлами"
notesAndReplies: "Заметки и ответы"
withFiles: "Заметки с файлами"
silence: "Заглушить"
silenceConfirm: " Заглушить этого пользователя? Уверены?"
unsilence: "Снять глушение"
@ -364,7 +364,7 @@ administrator: "Администратор"
token: "Токен"
twoStepAuthentication: "Двухфакторная аутентификация"
moderator: "Модератор"
nUsersMentioned: "{n}указанные пользователи"
nUsersMentioned: "Упомянуло пользователей: {n}"
securityKey: "Ключ безопасности"
securityKeyName: "Имя ключа"
registerSecurityKey: "Зарегистрировать защитный ключ"
@ -372,18 +372,16 @@ lastUsed: "Последнее использование"
unregister: "Отписаться"
passwordLessLogin: "Настроить вход без пароля"
resetPassword: "Сброс пароля:"
newPasswordIs: "Новый пароль - \"{пароль}\"."
autoNoteWatch: "Автоматически просматривать записи"
autoNoteWatchDescription: "Получать уведомления о заметках других пользователей, на которые вы отреагировали или на которые вы ответили."
reduceUiAnimation: "Уменьшить анимацию в пользовательском интерфейсе."
newPasswordIs: "Новый пароль — «{password}»."
reduceUiAnimation: "Уменьшить анимацию в пользовательском интерфейсе"
share: "Поделиться"
notFound: "Не найдено"
notFoundDescription: "Страница, соответствующая указанному URL, не найдена."
notFoundDescription: "Страница по указанной ссылке не найдена"
uploadFolder: "Место загрузки по умолчанию"
cacheClear: "Очистка кэша"
markAsReadAllNotifications: "Отметить все уведомления как прочитанные"
markAsReadAllUnreadNotes: "Отметьте все сообщения как прочитанные."
markAsReadAllTalkMessages: "Отметьте все сообщения как прочитанные"
markAsReadAllUnreadNotes: "Отметить все заметки как прочитанные"
markAsReadAllTalkMessages: "Отметить все реплики как прочитанные"
help: "Помощь"
inputMessageHere: "Введите сообщение здесь"
close: "Закрыть"
@ -392,71 +390,71 @@ groups: "Группы"
createGroup: "Создать группу"
ownedGroups: "Собственные группы"
joinedGroups: "Участие в группах"
invites: "Пригласить"
invites: "Приглашения"
groupName: "Название группы"
members: "Участники"
transfer: "Перенос"
transfer: "Отдать"
messagingWithUser: "Сообщения пользователей"
messagingWithGroup: "Чат в группе"
title: "Заголовок."
title: "Заголовок"
text: "Текст"
enable: "Включить."
enable: "Включить"
next: "Дальше"
retype: "Введите повторно"
noteOf: "Посты {user}"
retype: "Введите ещё раз"
noteOf: "Что пишет {user}"
inviteToGroup: "Пригласить в группу"
maxNoteTextLength: "Максимальная длина текста"
quoteAttached: "Цитата"
quoteQuestion: "Хочешь добавить цитату?"
noMessagesYet: "Сообщений нет"
quoteQuestion: "Хотите добавить цитату?"
noMessagesYet: "Пока ни одного сообщения"
newMessageExists: "Новое сообщение"
onlyOneFileCanBeAttached: "К сообщению можно прикрепить только один файл."
signinRequired: "Пожалуйста, войдите."
invitations: "Пригласить"
onlyOneFileCanBeAttached: "К сообщению можно прикрепить только один файл"
signinRequired: "Пожалуйста, войдите"
invitations: "Приглашения"
invitationCode: "Код приглашения"
checking: "Проверка"
available: "Доступен"
available: "Доступно"
unavailable: "Не доступно"
usernameInvalidFormat: "Вы можете использовать a-z, A-Z, 0-9 и _"
usernameInvalidFormat: "Можно использовать только латинские буквы (A—Z, a—z), цифры (0—9) и знак подчёркивания (_)"
tooShort: "Слишком короткий"
tooLong: "Слишком длинный"
weakPassword: "Слабый пароль"
normalPassword: "Обычный пароль"
normalPassword: "Годный пароль"
strongPassword: "Надёжный пароль"
passwordMatched: "Подходящий пароль"
passwordNotMatched: "Пароль не совпадает"
signinWith: "Войти в систему с помощью {x}"
passwordMatched: "Совпали"
passwordNotMatched: "Не совпадают"
signinWith: "Использовать {x} для входа"
signinFailed: "Невозможно войти в систему. Введенное вами имя пользователя или пароль неверны."
tapSecurityKey: "Нажмите на свой электронный ключ"
or: "или"
uiLanguage: "Язык интерфейса"
groupInvited: "Приглашение в группу"
aboutX: "Описание {x}"
useOsNativeEmojis: "Используйте родной для ОС Emojis"
youHaveNoGroups: "Группы не найдены"
joinOrCreateGroup: "Получите приглашение присоединиться к группам или вы можете создать свою собственную группу."
noHistory: "Ничего не найдено"
useOsNativeEmojis: "Использовать эмодзи операционной системы"
youHaveNoGroups: "У вас нет ни одной группы"
joinOrCreateGroup: "Получайте приглашения в группы или создавайте свои собственные"
noHistory: "История пока пуста"
disableAnimatedMfm: "Отключение анимированной разметки MFM"
doing: "В пути"
doing: "В процессе"
category: "Категория"
tags: "Теги"
tags: "Метки"
docSource: "Источник документа"
createAccount: "Зарегистрироваться"
existingAcount: "У вас уже есть учетная запись?"
regenerate: "Восстановить"
createAccount: "Новый аккаунт"
existingAcount: "Уже существующий"
regenerate: "Создать повторно"
fontSize: "Размер шрифта"
noFollowRequests: "У вас нет никаких ожидающих ответа запросов"
noFollowRequests: "Нерассмотренные запросы на подписку отсутствуют"
openImageInNewTab: "Открыть изображение в новой вкладке"
dashboard: "Панель управления"
local: "Локальный"
remote: "Удаленный"
local: "С этого сайта"
remote: "С других сайтов"
total: "Всего"
weekOverWeekChanges: "Еженедельно"
dayOverDayChanges: "Ежедневно"
weekOverWeekChanges: "За неделю"
dayOverDayChanges: "За день"
appearance: "Внешний вид"
clientSettings: "Настройки клиента"
accountSettings: "Настройки учетной записи"
promotion: "Опубликовано"
promotion: "Продвинуто"
promote: "Продвинуть"
numberOfDays: "Количество дней"
hideThisNote: "Спрятать эту запись"
@ -480,8 +478,8 @@ objectStorageUseProxyDesc: "Отключите, если не будете ис
objectStorageSetPublicRead: "Устанавливать public-read при загрузке на сервер"
serverLogs: "Журнал сервера"
deleteAll: "Удалить всё"
showFixedPostForm: "Показывать поле для ввода новой заметки наверху ленты."
newNoteRecived: "Есть новые посты"
showFixedPostForm: "Показывать поле для ввода новой заметки наверху ленты"
newNoteRecived: "Появилась новая заметка"
sounds: "Звуки"
listen: "Слушать"
none: "Ничего"
@ -490,23 +488,23 @@ popout: "Развернуть"
volume: "Громкость"
details: "Подробнее"
chooseEmoji: "Выберите эмодзи"
unableToProcess: "Я не могу завершить операцию."
unableToProcess: "Не удаётся завершить операцию"
recentUsed: "Последние использованные"
install: "Установить"
uninstall: "Удалить"
installedApps: "Установленные приложения"
nothing: "Ничего не найдено"
nothing: "Ничего нет"
installedDate: "Дата установки"
lastUsedDate: "Дата использования"
state: "Состояние"
sort: "Сортировать"
ascendingOrder: "по возрастанию"
descendingOrder: "По убыванию"
scratchpad: "Редактор "
scratchpadDescription: "Scratchpad предоставляет экспериментальную среду для AiScript, позволяющую писать, запускать и проверять результаты кода, взаимодействующего с Misskey."
scratchpad: "Когтеточка"
scratchpadDescription: "«Когтеточка» — это место для опытов с AiScript. Здесь можно писать программы, взаимодействующие с Misskey, запускать и смотреть что из этого получается."
output: "Выходы"
script: "Скрипт"
disablePagesScript: "Отключение скриптов в Pages"
disablePagesScript: "Отключить скрипты на «Страницах»"
updateRemoteUser: "Обновить данные пользователя с его сервера"
deleteAllFiles: "Удалить все файлы"
deleteAllFilesConfirm: "Вы хотите удалить все файлы?"
@ -515,9 +513,9 @@ removeAllFollowingDescription: "Отменить все подписки с до
userSuspended: "Этот пользователь был заморожен"
userSilenced: "Этот пользователь был заглушен"
sidebar: "Боковая панель"
divider: "Разделительная полоса"
divider: "Линия-разделитель"
addItem: "Добавить элемент"
rooms: "Комнаты"
rooms: "Комната"
relays: "Ретрансляторы"
addRelay: "Добавить ретранслятор"
inboxUrl: "URL ящика входящих сообщений"
@ -529,19 +527,20 @@ enableInfiniteScroll: "Включить бесконечную прокрутк
visibility: "Видимость"
poll: "Опрос"
useCw: "Скрывать содержимое под предупреждением"
enablePlayer: "Включить плеер"
disablePlayer: "Выключить плеер"
expandTweet: "Разавернуть твит"
themeEditor: "Редактор темы"
enablePlayer: "Включить проигрыватель"
disablePlayer: "Выключить проигрыватель"
expandTweet: "Развернуть твит"
themeEditor: "Редактор темы оформления"
description: "Описание"
author: "Автор"
leaveConfirm: "Вы не сохранили изменения. Хотите выйти и потерять их?"
manage: "Управление"
plugins: "Плагины"
pluginInstallWarn: "Пожалуста, не устанавливайте плагины, которым не доверяете."
plugins: "Расширения"
pluginInstallWarn: "Пожалуста, не устанавливайте расширения, которым не доверяете"
deck: "Пульт"
undeck: "Покинуть пульт"
useBlurEffectForModal: "Размывка под формой поверх всего"
useFullReactionPicker: "Полнофункциональный выбор реакций"
generateAccessToken: "Создать токен доступа"
permission: "Разрешения"
enableAll: "Включить все"
@ -552,56 +551,66 @@ notificationType: "Тип уведомления"
edit: "Изменить"
useStarForReactionFallback: "Ставить ★ в качестве реакции вместо неизвестного эмодзи"
emailConfig: "Настройки почтового сервера"
enableEmail: "Активировать функцию доставки электронной почты"
emailConfigInfo: "Он используется для подтверждения адреса электронной почты и сброса пароля."
email: "email"
enableEmail: "Включить обмен электронной почтой"
emailConfigInfo: "Используется для подтверждения адреса электронной почты и сброса пароля."
email: "Адрес электронной почты"
smtpConfig: "Конфигурация SMTP-сервера"
smtpHost: "Хост"
smtpPort: "smtp порт"
smtpPort: "Порт"
smtpUser: "Имя пользователя"
smtpPass: "Пароль"
emptyToDisableSmtpAuth: "Вы можете отключить SMTP аутентификацию, оставив ваше имя пользователя и пароль пустыми"
emptyToDisableSmtpAuth: "Не заполняйте имя пользователя и пароль, чтобы отключить аутентификацию в SMTP."
smtpSecure: "Использовать SSL/TLS для SMTP-соединений"
smtpSecureInfo: "Выключите его при использовании STARTTLS."
testEmail: "Проверка Email"
smtpSecureInfo: "Выключите при использовании STARTTLS."
testEmail: "Проверка доставки электронной почты"
wordMute: "Скрытие слов"
userSaysSomething: "{name} что-то сообщает"
makeActive: "Активировать"
display: "Показать"
display: "Отображение"
copy: "Копировать"
metrics: "Метрика"
metrics: "Метрики"
overview: "Обзор"
logs: "Лог-файлы"
logs: "Журналы"
delayed: "Задержка"
database: "База данных"
channel: "каналы"
channel: "Каналы"
create: "Создать"
notificationSetting: "Настройки уведомлений"
notificationSettingDesc: "Выберите тип уведомлений для отображения"
useGlobalSetting: "Использовать глобальные настройки"
useGlobalSettingDesc: "Использовать глобальные настройки"
useGlobalSettingDesc: "Если включено, будут использоваться настройки учётной записи. Если включить, этот виджет можно будет настроить индивидуально."
other: "Другие"
regenerateLoginToken: "Создать новый токен для входа"
regenerateLoginTokenDescription: "Создаёт новый токен, используемый внутри программы во время входа. Обычно в этом нет необходимости. При создании все устройства будут отключены."
setMultipleBySeparatingWithSpace: "Вы можете установить несколько, разделив их пробелами."
fileIdOrUrl: "ID файла или URL-адрес"
setMultipleBySeparatingWithSpace: "Можно написать несколько через пробел"
fileIdOrUrl: "Идентификатор файла или ссылка"
chatOpenBehavior: "Поведение окна чата при открытии"
sample: "Пример"
abuseReports: "Отчеты"
reportAbuse: "Отчеты"
abuseReports: "Жалобы"
reportAbuse: "Жалоба"
reportAbuseOf: "Пожаловаться на пользователя {name}"
fillAbuseReportDescription: "Пожалуйста, заполните данные отчета. Если речь идет о конкретном сообщении, пожалуйста, укажите его URL."
abuseReported: "Содержимое отправлено. Спасибо за сообщение"
fillAbuseReportDescription: "Опишите, пожалуйста, причину жалобы подробнее. Если речь о конкретной заметке, будьте добры приложить ссылку на неё."
abuseReported: "Жалоба отправлена. Большое спасибо за информацию."
send: "Отправить"
abuseMarkAsResolved: "Отметить отчет как решенный"
abuseMarkAsResolved: "Отметить жалобу как решённую"
openInNewTab: "Открыть в новой вкладке"
openInSideView: "Открывать в боковой колонке"
defaultNavigationBehaviour: "Поведение навигации по умолчанию"
editTheseSettingsMayBreakAccount: "От изменений в этих настройках ваша учётная запись может поломаться."
instanceTicker: "Строка с инстансом в заметке"
waitingFor: "Ждём {x}"
instanceTicker: "Строка с названием инстанса в заметках"
waitingFor: "Ждём, когда {x} ответит"
random: "Случайные"
system: "Система"
switchUi: "Выбор вида"
desktop: "Стол"
_mfm:
mention: "Упоминание"
hashtag: "Хэштег"
link: "Ссылка"
center: "Выровнять элементы по центру"
quote: "Цитата"
emoji: "Эмодзи пользователя"
search: "Поиск"
_reversi:
reversi: "Реверси"
gameSettings: "Настройки игры"
@ -610,34 +619,34 @@ _reversi:
blackIs: "{name} за чёрных"
rules: "Правила"
botSettings: "Настройки бота"
thisGameIsStartedSoon: "Игра скоро начнётся"
waitingForOther: "Ожидание оппонента..."
waitingForMe: "В ожидании, когда будете готовы"
waitingBoth: "Приготовьтесь"
thisGameIsStartedSoon: "Игра скоро начнётся."
waitingForOther: "Ожидание соперника..."
waitingForMe: "В ожидании, когда будете готовы."
waitingBoth: "Приготовьтесь."
ready: "Готово"
cancelReady: "Возврат к подготовке"
opponentTurn: "Ход соперника"
myTurn: "Ваш ход"
turnOf: "Ходит {name}"
pastTurnOf: "Ходит {name}"
turnOf: "Ходит {name}."
pastTurnOf: "Ходит {name}."
surrender: "Сдаться"
surrendered: "Сдавшись"
surrendered: "Противник сдался"
drawn: "Ничья"
won: "{name} — победитель"
won: "Победитель — {name}"
black: "Чёрные"
white: "Белые"
total: "Всего"
turnCount: "Ход {count}"
myGames: "Мои игры"
myGames: "Сыгранное вами"
allGames: "Все игры"
ended: "Завершено"
ended: "Завершена"
playing: "Идёт игра"
isLlotheo: "Выигрывает меньшее число камней (LLoTheO)"
loopedMap: "Замкнутая в кольцо доска"
canPutEverywhere: "Камни можно ставить везде"
_instanceTicker:
none: "Не показывать"
remote: "Только у пользователей с других сайтов"
remote: "Только для других сайтов"
always: "Показывать всегда"
_serverDisconnectedBehavior:
reload: "Автоматическая перезагрузка"
@ -648,37 +657,37 @@ _channel:
edit: "Редактировать канал"
setBanner: "Установить баннер"
removeBanner: "Удалить баннер"
featured: "В тренде"
featured: "Из подборки"
owned: "Владелец"
following: "Читаю"
usersCount: "{n} Участники"
notesCount: "{n} Записи"
usersCount: "Участников: {n}"
notesCount: "Заметок: {n}"
_sidebar:
full: "Полный"
icon: "Иконка"
full: "Полностью"
icon: "Только значки"
hide: "Спрятать"
_wordMute:
muteWords: "Скрыть слово"
muteWordsDescription: "Разделяйте пробелами для условия \"И\". Разделяйте переводом строки для \"ИЛИ\"."
muteWordsDescription2: "Округляйте ключевые слова слэшами для использования регулярных выражений."
muteWordsDescription: "Пишите слова через пробел в одной строке, чтобы фильтровать их появление вместе; а если хотите фильтровать любое из них, пишите в отдельных строках."
muteWordsDescription2: "Здесь можно использовать регулярные выражения — просто заключите их между двумя дробными чертами (/)."
softDescription: "Соответствующие условиям заметки будут спрятаны из вашей ленты."
hardDescription: "Соответстующие условиям заметки вообще не будут попадать в вашу ленту. Даже если вы поменяете условия, отсеенные таким образом заметки уже не появятся."
soft: "Лёгкий "
hard: "Сложный"
mutedNotes: "Скрытые посты"
soft: "Мягкий"
hard: "Жёсткий"
mutedNotes: "Скрытые заметки"
_theme:
explore: "Обзор"
install: "Установить тему"
manage: "Менеджер тем"
code: "Код темы"
installed: "{name} установлено "
alreadyInstalled: "Тема уже установлена"
invalid: "Формат темы некорректный "
installed: "Тема «{name}» установлена."
alreadyInstalled: "Тема уже установлена."
invalid: "Формат темы некорректный."
make: "Создать тему"
base: "Основа"
addConstant: "Добавить константу"
constant: "Константа"
defaultValue: "Исходное содержимое"
defaultValue: "По умолчанию"
color: "Цвет"
refProp: "Ссылка на свойство"
refConst: "Ссылка на константу"
@ -686,11 +695,11 @@ _theme:
func: "Функции"
funcKind: "Тип функции"
argument: "Аргумент"
basedProp: "Указанное свойство"
basedProp: "Исходное свойство"
alpha: "Непрозрачность"
darken: "Затемнение"
lighten: "Осветление"
inputConstantName: "Введите имя для константы"
inputConstantName: "Введите имя для константы."
importInfo: "Если вы введете код темы здесь, вы можете импортировать его в редактор тем."
deleteConstantConfirm: "Вы действительно хотите удалить константу {const}?"
keys:
@ -751,7 +760,7 @@ _ago:
justNow: "Только что"
secondsAgo: "{n} с назад"
minutesAgo: "{n} мин назад"
hoursAgo: "{} часов назад"
hoursAgo: "{n} ч назад"
daysAgo: "{n} сут назад"
weeksAgo: "{n} нед. назад"
monthsAgo: "{n} мес. назад"
@ -771,7 +780,7 @@ _tutorial:
step3_1: "Успешно заполнили профиль?"
step3_2: "Что ж, теперь самое время опубликуовать заметку. Если нажать вверху страницы на изображение карандаша, появится форма для текста."
step3_3: "Напишите в неё, что хотите, и нажмите на кнопку в правом верхнем углу."
step3_4: "Ничего не приходит в голову? Как насчёт: «я новенький, пока осваиваюсь в Misskey»?"
step3_4: "Ничего не приходит в голову? Как насчёт: «Я новенький, пока осваиваюсь в Misskey»?"
step4_1: "С написанием первой заметки покончено?"
step4_2: "Отлично, теперь она должна появиться в вашей ленте."
step5_1: "А теперь самое время немного оживить ленту, подписавшись на других."
@ -848,7 +857,7 @@ _widgets:
notifications: "Уведомления"
timeline: "Лента"
calendar: "Календарь"
trends: "Популярное"
trends: "Актуальное"
clock: "Часы"
rss: "Просмотр RSS"
activity: "Активность"
@ -859,7 +868,7 @@ _widgets:
_cw:
hide: "Спрятать"
show: "Показать еще"
chars: "символов: {count}"
chars: "знаков: {count}"
files: "файлов: {count}"
_poll:
noOnlyOneChoice: "Нужно хотя бы два варианта."
@ -877,7 +886,7 @@ _poll:
totalVotes: "Голосов всего: {n}"
vote: "Проголосовать"
showResult: "Смотреть результаты"
voted: "Проголосовали"
voted: "Голос отдан"
closed: "Завершено"
remainingDays: "Осталось {d} сут {h} ч"
remainingHours: "Осталось {h} ч {m} мин"
@ -946,10 +955,10 @@ _instanceCharts:
files: "Изменения числа файлов"
filesTotal: "Суммарное количество файлов"
_timelines:
home: "Персональное"
local: "Местное"
social: "Социальное"
global: "Глобальное"
home: "Персональная"
local: "Местная"
social: "Социальная"
global: "Всеобщая"
_rooms:
roomOf: "Комната {user}"
addFurniture: "Добавить обстановку"
@ -959,7 +968,7 @@ _rooms:
remove: "Выбросить"
clear: "Очистить"
clearConfirm: "Уверены что стоит убрать всю обстановку из вашей комнаты?"
leaveConfirm: "Измнения не сохранены, правда покинуть комнату?"
leaveConfirm: "Изменения не сохранены, правда хотите покинуть комнату?"
chooseImage: "Выберите изображение"
roomType: "Стиль комнаты"
carpetColor: "Цвет ковра"
@ -1016,11 +1025,11 @@ _pages:
newPage: "Создать страницу"
editPage: "Править страницу"
readPage: "Читать страницу"
created: "Страница успешно создана"
updated: "Страница успешно обновлена"
deleted: "Страница успешно удалена"
nameAlreadyExists: "Указанный адрес страницы уже существует"
invalidNameTitle: "Указанный адрес страницы недопустим"
created: "Страница успешно создана."
updated: "Страница успешно обновлена."
deleted: "Страница успешно удалена."
nameAlreadyExists: "Указанный адрес страницы уже существует."
invalidNameTitle: "Указанный адрес страницы недопустим."
invalidNameText: "Проверьте, что не оставили поле пустым."
editThisPage: "Правка этой страницы"
viewSource: "Просмотр исходника"
@ -1033,7 +1042,7 @@ _pages:
content: "Содержимое"
variables: "Переменные"
title: "Заголовок"
url: "URL страницы"
url: "Адрес страницы"
summary: "Краткое содержание"
alignCenter: "Выровнять элементы по центру"
hideTitleWhenPinned: "Скрыть заголовок страницы при привязке к профилю"
@ -1095,7 +1104,7 @@ _pages:
inc: "Увеличивать на"
_button:
text: "Надпись"
colored: "Цветная"
colored: "Выделена цветом"
action: "Действие по нажатию"
_action:
dialog: "Показать всплывающий текст"
@ -1295,21 +1304,21 @@ _pages:
argVariables: "Аргументы"
_relayStatus:
requesting: "В ожидании одобрения"
accepted: "Одобрено"
rejected: "Отказано"
accepted: "Одобрено."
rejected: "Отказано."
_notification:
fileUploaded: "Файл успешно загружен"
youGotMention: "{name} упоминает вас"
youGotReply: "{name} отвечает вам"
youGotQuote: "{name} цитирует вас"
youRenoted: "{name} передаёт вашу заметку"
youGotPoll: "{name} участник вашего опроса"
youGotMessagingMessageFromUser: "{name} пишет вам"
youGotMessagingMessageFromGroup: "Отправлено сообщение в группу «{name}»"
youWereFollowed: "У вас новый подписчик"
youReceivedFollowRequest: "У вас новый запрос на подписку"
yourFollowRequestAccepted: "Ваш запрос на подписку одобрен"
youWereInvitedToGroup: "Приглашение в группу"
fileUploaded: "Файл успешно загружен."
youGotMention: "{name} упоминает вас."
youGotReply: "{name} отвечает вам."
youGotQuote: "{name} цитирует вас."
youRenoted: "{name} передаёт вашу заметку."
youGotPoll: "{name} участвует в вашем опросе."
youGotMessagingMessageFromUser: "{name} пишет вам."
youGotMessagingMessageFromGroup: "Новое сообщение в группе «{name}»."
youWereFollowed: "У вас новый подписчик."
youReceivedFollowRequest: "У вас новый запрос на подписку."
yourFollowRequestAccepted: "Ваш запрос на подписку одобрен."
youWereInvitedToGroup: "Вы приглашены в группу."
_types:
all: "Все"
follow: "Подписки"
@ -1321,7 +1330,7 @@ _notification:
pollVote: "Голосования"
receiveFollowRequest: "Получен запрос на подписку"
followRequestAccepted: "Запрос на подписку одобрен"
groupInvited: "Пришлашение в группы"
groupInvited: "Приглашение в группы"
app: "Уведомления из приложений"
_deck:
alwaysShowMainColumn: "Всегда показывать главную колонку"

View File

@ -1,3 +1,5 @@
---
_lang_: "ياپونچە"
search: "ئىزدەش"
_mfm:
search: "ئىزدەش"

View File

@ -36,60 +36,243 @@ unpin: "Відкріпити"
copyContent: "Скопіювати контент"
copyLink: "Скопіювати посилання"
delete: "Видалити"
deleteAndEdit: "Видалити й редагувати"
addToList: "Додати до списку"
sendMessage: "Надіслати повідомлення"
copyUsername: "Скопіювати ім’я користувача"
searchUser: "Пошук користувачів"
reply: "Відповісти"
loadMore: "Показати більше"
youGotNewFollower: "У вас новий підписник"
receiveFollowRequest: "Отримано запит на підписку"
followRequestAccepted: "Запит на підписку прийнято"
mention: "Згадка"
mentions: "Згадки"
directNotes: "Прямі повідомлення"
importAndExport: "Імпорт та експорт"
import: "Імпорт"
export: "Експорт"
files: "Файли"
download: "Завантажити"
unfollowConfirm: "Ви впевнені, що хочете відписатися від {name}?"
lists: "Списки"
noLists: "Немає списків"
note: "Дописи"
notes: "Дописи"
following: "Підписки"
followers: "Підписники"
followsYou: "Підписаний(-а) на вас"
createList: "Створити список"
manageLists: "Управління списками"
error: "Помилка"
somethingHappened: "Щось пішло не так"
retry: "Спробувати знову"
pageLoadError: "Помилка при завантаженні сторінки"
enterListName: "Введіть назву списку"
privacy: "Приватність"
follow: "Підписки"
makeFollowManuallyApprove: "Підтверджувати підписників уручну"
defaultNoteVisibility: "Видимість допису за замовчуванням"
follow: "Підписка"
followRequest: "Запит на підписку"
followRequests: "Запити на підписку"
unfollow: "Відписатися"
followRequestPending: "Очікуючі запити на підписку"
enterEmoji: "Введіть емодзі"
renote: "Поширити"
unrenote: "Відміна поширення"
quote: "Цитата"
pinnedNote: "Закріплений допис"
you: "Ви"
clickToShow: "Натисніть для перегляду"
sensitive: "NSFW"
add: "Додати"
reaction: "Реакції"
markAsSensitive: "Відмітити як NSFW"
rememberNoteVisibility: "Пам’ятати видимість дописів"
attachCancel: "Видалити вкладення"
markAsSensitive: "Позначити як NSFW"
unmarkAsSensitive: "Зняти позначку NSFW"
enterFileName: "Введіть ім'я файлу"
mute: "Ігнорувати"
unmute: "Показувати"
block: "Заблокувати"
unblock: "Розблокувати"
suspend: "Призупинити"
unsuspend: "Відновити"
blockConfirm: "Ви впевнені, що хочете заблокувати цей акаунт?"
unblockConfirm: "Ви впевнені, що хочете розблокувати цей акаунт?"
suspendConfirm: "Ви впевнені, що хочете призупинити цей акаунт?"
unsuspendConfirm: "Ви впевнені, що хочете відновити цей акаунт?"
selectList: "Виберіть список"
selectAntenna: "Виберіть антену"
selectWidget: "Виберіть віджет"
editWidgets: "Редагувати віджети"
editWidgetsExit: "Готово"
customEmojis: "Кастомні емоджі"
emoji: "Емоджі"
emojiName: "Назва емоджі"
addEmoji: "Додати емодзі"
settingGuide: "Рекомендована конфігурація"
cacheRemoteFiles: "Кешувати дані з інших інстансів"
flagAsBot: "Акаунт бота"
flagAsCat: "Акаунт кота"
autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на яких ви підписані"
addAcount: "Додати акаунт"
loginFailed: "Не вдалося увійти"
showOnRemote: "Переглянути в оригіналі"
general: "Загальне"
wallpaper: "Шпалери"
setWallpaper: "Встановити шпалери"
removeWallpaper: "Прибрати шпалери"
searchWith: "Шукати з {q}"
youHaveNoLists: "У вас немає списків"
followConfirm: "Підписатися на {name}?"
proxyAccount: "Проксі-акаунт"
host: "Хост"
selectUser: "Виберіть користувача"
recipient: "Кому"
annotation: "Коментар"
federation: "Федіверс"
instances: "Інстанс"
registeredAt: "Приєднався(-лась)"
latestRequestSentAt: "Останній запит надіслано"
latestRequestReceivedAt: "Останній запит прийнято"
latestStatus: "Останній статус"
storageUsage: "Використання простіру"
charts: "Графіки"
perHour: "Щогодини"
perDay: "Щоденно"
blockThisInstance: "Заблокувати цей інстанс"
operations: "Операції"
software: "Програмне забезпечення"
version: "Версія"
metadata: "Метадані"
withNFiles: "файли: {n}"
monitor: "Монітор"
jobQueue: "Черга завдань"
cpuAndMemory: "ЦП та пам'ять"
network: "Мережа"
disk: "Диск"
instanceInfo: "Про цей інстанс"
statistics: "Статистика"
clearQueue: "Очистити чергу"
clearCachedFiles: "Очистити кеш"
blockedInstances: "Заблоковані інстанси"
muteAndBlock: "Ігнор і блокування"
mutedUsers: "Ігноровані користувачі"
blockedUsers: "Заблоковані користувачі"
noUsers: "Немає користувачів"
editProfile: "Редагувати профіль"
noteDeleteConfirm: "Ви дійсно хочете видалити цей допис?"
pinLimitExceeded: "Більше дописів не можна закріпити"
done: "Готово"
processing: "Обробка"
preview: "Передогляд"
default: "За умовчанням"
noCustomEmojis: "Немає кастомних емоджі"
noJobs: "Немає завдань"
federating: "Федерується"
blocked: "Заблоковано"
notResponding: "Не відповідає"
changePassword: "Змінити пароль"
security: "Безпека"
currentPassword: "Поточний пароль"
newPassword: "Новий пароль"
newPasswordRetype: "Новий пароль (повторно)"
attachFile: "Вкласти файл"
more: "Бiльше!"
featured: "Виділено"
noSuchUser: "Користувача не знайдено"
lookup: "Пошук"
announcements: "Оголошення"
imageUrl: "URL зображення"
remove: "Видалити"
removed: "Видалено"
saved: "Збережено"
messaging: "Чати"
upload: "Завантажити"
fromDrive: "З диска"
fromUrl: "З URL"
uploadFromUrl: "Завантажити з URL"
explore: "Огляд"
games: "Ігри Misskey"
start: "Розпочати"
activity: "Активність"
images: "Зображення"
birthday: "День народження"
yearsOld: "{age} років"
registeredDate: "Приєднався(-лась)"
location: "Локація"
theme: "Тема"
themeForLightMode: "Світла тема"
themeForDarkMode: "Темна тема"
light: "Світла"
dark: "Темна"
lightThemes: "Світлі теми"
darkThemes: "Темні теми"
drive: "Диск"
fileName: "Ім'я файлу"
selectFile: "Вибрати файл"
selectFiles: "Вибрати файли"
selectFolder: "Вибрати теку"
selectFolders: "Вибрати теки"
renameFile: "Перейменувати файл"
folderName: "Ім'я теки"
createFolder: "Створити теку"
renameFolder: "Перейменувати теку"
deleteFolder: "Видалити теку"
addFile: "Додати файл"
copyUrl: "Копіювати URL"
rename: "Перейменувати"
avatar: "Аватар"
banner: "Банер"
nsfw: "NSFW"
reload: "Оновити"
watch: "Стежити"
unwatch: "Не стежити"
instanceName: "Назва інстансу"
maintainerName: "Ім'я адміністратора"
maintainerEmail: "Email адміністратора"
thisYear: "Рік"
thisMonth: "Місяць"
today: "День"
dayX: "{day}"
monthX: "{month}"
yearX: "{year}"
pages: "Сторінки"
connectSerice: "Під’єднатися"
disconnectSerice: "Відключитися"
exploreUsersCount: "{count} користувачів"
userList: "Списки"
showInPage: "Показати на сторінці"
smtpHost: "Хост"
smtpUser: "Ім'я користувача"
smtpPass: "Пароль"
_mfm:
mention: "Згадка"
quote: "Цитата"
emoji: "Кастомні емоджі"
search: "Пошук"
_sidebar:
icon: "Аватар"
_theme:
keys:
mention: "Згадка"
renote: "Поширити"
_sfx:
note: "Дописи"
notification: "Сповіщення"
chat: "Чати"
_antennaSources:
homeTimeline: "Дописи тих, на кого ви підписані"
_widgets:
notifications: "Сповіщення"
timeline: "Стрічка"
activity: "Активність"
federation: "Федіверс"
_cw:
show: "Показати більше"
_visibility:
home: "Головна"
followers: "Підписники"
_postForm:
replyPlaceholder: "Відповідь на допис..."
@ -100,7 +283,14 @@ _exportOrImport:
muteList: "Ігнорувати"
blockingList: "Заблокувати"
userLists: "Списки"
_rooms:
_roomType:
default: "За умовчанням"
_furnitures:
monitor: "Монітор"
_pages:
blocks:
image: "Зображення"
script:
categories:
list: "Списки"
@ -120,9 +310,12 @@ _pages:
types:
array: "Списки"
_notification:
youRenoted: "{name} поширив(ла) ваш допис"
youWereFollowed: "У вас новий підписник"
_types:
follow: "Підписки"
mention: "Згадка"
renote: "Поширити"
quote: "Цитата"
reaction: "Реакції"
_deck:

View File

@ -164,7 +164,7 @@ jobQueue: "作业队列"
cpuAndMemory: "CPU使用量"
network: "网络"
disk: "存储"
instanceInfo: "实例情报"
instanceInfo: "实例信息"
statistics: "统计"
clearQueue: "清除队列"
clearQueueConfirmTitle: "确定清除队列?"
@ -353,7 +353,7 @@ popularTags: "热门标签"
userList: "列表"
about: "关于"
aboutMisskey: "关于 Misskey"
aboutMisskeyText: "Misskey是由syuilo于2014年开发的开放源代码软件。"
aboutMisskeyText: "Misskey是由syuilo于2014年开发的开软件。"
misskeyMembers: "现在由以下成员进行开发和维护:"
misskeySource: "源代码在这里公开:"
misskeyTranslation: "与我们一同进行Misskey的翻译工作"
@ -373,8 +373,6 @@ unregister: "删除账户"
passwordLessLogin: "无密码登录"
resetPassword: "重置密码"
newPasswordIs: "新的密码是「{password}」"
autoNoteWatch: "自动关注帖子"
autoNoteWatchDescription: "让您能够收到关于「回应」和回复其他用户的帖子的通知。"
reduceUiAnimation: "减少UI动画"
share: "分享"
notFound: "未找到"
@ -542,6 +540,7 @@ pluginInstallWarn: "请不要安装不明来源的插件"
deck: "Deck"
undeck: "取消Deck"
useBlurEffectForModal: "模态框使用模糊效果"
useFullReactionPicker: "使用全功能的回应工具栏"
generateAccessToken: "生成访问令牌"
permission: "权限"
enableAll: "启用全部"
@ -602,6 +601,16 @@ instanceTicker: "帖子的实例信息"
waitingFor: "等待{x}"
random: "随机"
system: "系统"
switchUi: "切换界面"
desktop: "桌面"
_mfm:
mention: "提及"
hashtag: "话题标签"
link: "链接"
center: "居中"
quote: "引用"
emoji: "自定义Emoji"
search: "搜索"
_reversi:
reversi: "黑白棋"
gameSettings: "对局设置"

View File

@ -370,8 +370,6 @@ unregister: "刪除賬戶"
passwordLessLogin: "設置無密碼登入"
resetPassword: "重置密碼"
newPasswordIs: "新密碼為「{password}」"
autoNoteWatch: "自動追隨貼文"
autoNoteWatchDescription: "收到反應或回覆過的貼文的通知"
reduceUiAnimation: "減少介面的動態視覺"
share: "分享"
notFound: "找不到"
@ -559,6 +557,13 @@ send: "發送"
openInNewTab: "在新分頁中開啟"
random: "隨機"
system: "系統"
_mfm:
mention: "提及"
hashtag: "#tag"
link: "鏈接"
quote: "引用"
emoji: "自訂表情符號"
search: "搜尋"
_reversi:
reversi: "黑白棋"
gameSettings: "對弈設定"

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class deleteAutoWatch1604821689616 implements MigrationInterface {
name = 'deleteAutoWatch1604821689616'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "autoWatch"`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user_profile" ADD "autoWatch" boolean NOT NULL DEFAULT false`);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.52.0",
"version": "12.55.0",
"codename": "indigo",
"repository": {
"type": "git",
@ -99,51 +99,50 @@
"@types/tmp": "0.2.0",
"@types/uuid": "8.3.0",
"@types/web-push": "3.3.0",
"@types/webpack": "4.41.22",
"@types/webpack": "4.41.24",
"@types/webpack-stream": "3.2.11",
"@types/websocket": "1.0.1",
"@types/ws": "7.2.7",
"@typescript-eslint/parser": "4.4.0",
"@typescript-eslint/parser": "4.6.1",
"@vue/compiler-sfc": "3.0.2",
"abort-controller": "3.0.0",
"apexcharts": "3.22.0",
"apexcharts": "3.22.1",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
"aws-sdk": "2.770.0",
"aws-sdk": "2.787.0",
"bcryptjs": "2.4.3",
"blurhash": "1.1.3",
"bull": "3.18.0",
"bull": "3.18.1",
"cafy": "15.2.1",
"cbor": "5.1.0",
"chalk": "4.1.0",
"chart.js": "2.9.3",
"chart.js": "2.9.4",
"cli-highlight": "2.1.4",
"commander": "4.1.1",
"content-disposition": "0.5.3",
"core-js": "3.6.5",
"core-js": "3.7.0",
"crc-32": "1.2.0",
"css-loader": "5.0.0",
"css-loader": "5.0.1",
"cssnano": "4.1.10",
"dateformat": "3.0.3",
"deep-entries": "3.1.0",
"diskusage": "1.1.3",
"double-ended-queue": "2.1.0-0",
"escape-regexp": "0.0.1",
"eslint": "7.11.0",
"eslint": "7.12.1",
"eslint-plugin-vue": "7.1.0",
"eventemitter3": "4.0.7",
"feed": "4.2.1",
"fibers": "5.0.0",
"file-type": "16.0.0",
"file-type": "16.0.1",
"fluent-ffmpeg": "2.1.2",
"glob": "7.1.6",
"got": "11.7.0",
"got": "11.8.0",
"gulp": "4.0.2",
"gulp-rename": "2.0.0",
"gulp-replace": "1.0.0",
"gulp-sourcemaps": "2.6.5",
"gulp-terser": "1.4.0",
"gulp-tslint": "8.1.4",
"gulp-typescript": "6.0.0-alpha.1",
"hard-source-webpack-plugin": "0.13.1",
@ -176,24 +175,24 @@
"lookup-dns-cache": "2.1.0",
"markdown-it": "11.0.1",
"markdown-it-anchor": "6.0.0",
"mocha": "8.1.3",
"mocha": "8.2.1",
"moji": "0.5.1",
"ms": "2.1.2",
"multer": "1.4.2",
"nested-property": "4.0.0",
"node-fetch": "2.6.1",
"nodemailer": "6.4.13",
"nodemailer": "6.4.15",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
"p-cancelable": "2.0.0",
"parse5": "6.0.1",
"parsimmon": "1.16.0",
"pg": "8.4.1",
"pg": "8.4.2",
"portscanner": "2.2.0",
"postcss": "8.1.3",
"postcss": "8.1.6",
"postcss-loader": "4.0.4",
"prismjs": "1.22.0",
"probe-image-size": "5.0.0",
"probe-image-size": "6.0.0",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
"pug": "2.0.4",
@ -215,8 +214,8 @@
"rimraf": "3.0.2",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.27.0",
"sass-loader": "10.0.4",
"sass": "1.29.0",
"sass-loader": "10.0.5",
"seedrandom": "3.0.5",
"sharp": "0.26.2",
"speakeasy": "2.0.0",
@ -224,18 +223,18 @@
"style-loader": "2.0.0",
"summaly": "2.4.0",
"syslog-pro": "1.0.0",
"systeminformation": "4.27.10",
"systeminformation": "4.28.1",
"syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0",
"three": "0.117.1",
"tinycolor2": "1.4.2",
"tmp": "0.2.1",
"ts-loader": "8.0.6",
"ts-loader": "8.0.9",
"ts-node": "9.0.0",
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
"typeorm": "0.2.28",
"typescript": "4.0.3",
"typeorm": "0.2.29",
"typescript": "4.0.5",
"ulid": "2.3.0",
"url-loader": "4.1.1",
"uuid": "8.3.1",
@ -244,7 +243,7 @@
"vue-color": "2.7.1",
"vue-draggable-next": "1.0.8",
"vue-i18n": "9.0.0-beta.6",
"vue-json-pretty": "1.7.0",
"vue-json-pretty": "1.7.1",
"vue-loader": "16.0.0-beta.8",
"vue-prism-editor": "1.2.2",
"vue-router": "4.0.0-beta.13",
@ -253,8 +252,8 @@
"vuex": "4.0.0-beta.4",
"vuex-persistedstate": "3.1.0",
"web-push": "3.4.4",
"webpack": "5.3.2",
"webpack-cli": "4.1.0",
"webpack": "5.4.0",
"webpack-cli": "4.2.0",
"websocket": "1.0.32",
"ws": "7.3.1",
"xev": "2.0.1"

View File

@ -28,7 +28,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import { emojilist } from '../../misc/emojilist';
import contains from '@/scripts/contains';
import { twemojiSvgBase } from '../../misc/twemoji-base';
@ -124,7 +124,6 @@ export default defineComponent({
emojis: [],
items: [],
select: -1,
emojilist,
emojiDb: [] as EmojiDef[]
}
},
@ -178,7 +177,7 @@ export default defineComponent({
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
this.emojiDb = emojiDefinitions.concat(emjdb);
this.emojiDb = markRaw(emojiDefinitions.concat(emjdb));
//#endregion
this.textarea.addEventListener('keydown', this.onKeydown);

View File

@ -0,0 +1,70 @@
<template>
<XModalWindow ref="dialog"
:width="800"
:height="500"
:with-ok-button="true"
:ok-button-disabled="(type === 'file') && (selected.length === 0)"
@click="cancel()"
@close="cancel()"
@ok="ok()"
@closed="$emit('closed')"
>
<template #header>
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
</template>
<XDrive :multiple="multiple" @changeSelection="onChangeSelection" @selected="ok()" :select="type"/>
</XModalWindow>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XDrive from './drive.vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import number from '@/filters/number';
export default defineComponent({
components: {
XDrive,
XModalWindow,
},
props: {
type: {
type: String,
required: false,
default: 'file'
},
multiple: {
type: Boolean,
default: false
}
},
emits: ['done', 'closed'],
data() {
return {
selected: []
};
},
methods: {
ok() {
this.$emit('done', this.selected);
this.$refs.dialog.close();
},
cancel() {
this.$emit('done');
this.$refs.dialog.close();
},
onChangeSelection(xs) {
this.selected = xs;
},
number
}
});
</script>

View File

@ -1,72 +1,44 @@
<template>
<XModalWindow ref="dialog"
:width="800"
:height="500"
:with-ok-button="true"
:ok-button-disabled="(type === 'file') && (selected.length === 0)"
@click="cancel()"
@close="cancel()"
@ok="ok()"
<XWindow ref="window"
:initial-width="800"
:initial-height="500"
:can-resize="true"
@closed="$emit('closed')"
>
<template #header>
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
{{ $t('drive') }}
</template>
<div>
<XDrive :multiple="multiple" @changeSelection="onChangeSelection" @selected="ok()" :select="type"/>
</div>
</XModalWindow>
<XDrive :initial-folder="initialFolder"/>
</XWindow>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XDrive from './drive.vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import number from '@/filters/number';
import XWindow from '@/components/ui/window.vue';
export default defineComponent({
components: {
XDrive,
XModalWindow,
XWindow,
},
props: {
type: {
type: String,
required: false,
default: 'file'
initialFolder: {
type: Object,
required: false
},
multiple: {
type: Boolean,
default: false
}
},
emits: ['done', 'closed'],
emits: ['closed'],
data() {
return {
selected: []
};
},
methods: {
ok() {
this.$emit('done', this.selected);
this.$refs.dialog.close();
},
cancel() {
this.$emit('done');
this.$refs.dialog.close();
},
onChangeSelection(xs) {
this.selected = xs;
},
number
}
});
</script>

View File

@ -2,6 +2,7 @@
<div class="rghtznwe"
:class="{ draghover }"
@click="onClick"
@contextmenu.stop="onContextmenu"
@mouseover="onMouseover"
@mouseout="onMouseout"
@dragover.prevent.stop="onDragover"
@ -27,8 +28,9 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { faFolder, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
import { faFolder, faFolderOpen, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons';
import * as os from '@/os';
import { faICursor } from '@fortawesome/free-solid-svg-icons';
export default defineComponent({
props: {
@ -241,6 +243,28 @@ export default defineComponent({
value: this.folder.id
});
},
onContextmenu(e) {
os.contextMenu([{
text: this.$t('openInWindow'),
icon: faWindowRestore,
action: () => {
os.popup(import('./drive-window.vue'), {
initialFolder: this.folder
}, {
}, 'closed');
}
}, null, {
text: this.$t('rename'),
icon: faICursor,
action: this.rename
}, null, {
text: this.$t('delete'),
icon: faTrashAlt,
danger: true,
action: this.deleteFolder
}], e);
},
}
});
</script>

View File

@ -64,7 +64,7 @@ export default defineComponent({
},
props: {
initFolder: {
initialFolder: {
type: Object,
required: false
},
@ -151,8 +151,8 @@ export default defineComponent({
this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated);
this.connection.on('folderDeleted', this.onStreamDriveFolderDeleted);
if (this.initFolder) {
this.move(this.initFolder);
if (this.initialFolder) {
this.move(this.initialFolder);
} else {
this.fetch();
}
@ -639,6 +639,10 @@ export default defineComponent({
<style lang="scss" scoped>
.yfudmmck {
display: flex;
flex-direction: column;
height: 100%;
> nav {
display: block;
z-index: 2;
@ -698,6 +702,7 @@ export default defineComponent({
}
> .main {
flex: 1;
overflow: auto;
&, * {

View File

@ -1,75 +1,104 @@
<template>
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="omfetrab _popup">
<header>
<button v-for="(category, i) in categories"
class="_button"
@click="go(category)"
:class="{ active: category.isActive }"
:key="i"
>
<Fa :icon="category.icon" fixed-width/>
</button>
</header>
<input ref="search" class="search" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()" autofocus>
<div class="emojis">
<template v-if="categories[0].isActive">
<header class="category"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
<div class="list">
<button v-for="emoji in ($store.state.device.recentEmojis || [])"
<section class="result">
<div v-if="searchResultCustom.length > 0">
<button v-for="emoji in searchResultCustom"
class="_button"
:title="emoji.name"
@click="chosen(emoji)"
@click="chosen(emoji, $event)"
:key="emoji"
tabindex="0"
>
<MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/>
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button>
</div>
<header class="category"><Fa :icon="faAsterisk" fixed-width/> {{ $t('customEmojis') }}</header>
</template>
<template v-if="categories.find(x => x.isActive).name">
<div class="list">
<button v-for="emoji in emojilist.filter(e => e.category === categories.find(x => x.isActive).name)"
<div v-if="searchResultUnicode.length > 0">
<button v-for="emoji in searchResultUnicode"
class="_button"
:title="emoji.name"
@click="chosen(emoji)"
@click="chosen(emoji, $event)"
:key="emoji.name"
tabindex="0"
>
<MkEmoji :emoji="emoji.char"/>
</button>
</div>
</section>
<div class="index">
<section>
<div>
<button v-for="emoji in pinned"
class="_button"
@click="chosen(emoji, $event)"
tabindex="0"
>
<MkEmoji :emoji="emoji" :normal="true"/>
</button>
</div>
</section>
<section>
<header class="_acrylic"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
<div>
<button v-for="emoji in $store.state.device.recentlyUsedEmojis"
class="_button"
@click="chosen(emoji, $event)"
:key="emoji"
>
<MkEmoji :emoji="emoji" :normal="true"/>
</button>
</div>
</section>
<div class="arrow"><Fa :icon="faChevronDown"/></div>
</div>
<section v-for="category in customEmojiCategories" :key="'custom:' + category" class="custom">
<header class="_acrylic" v-appear="() => visibleCategories[category] = true">{{ category || $t('other') }}</header>
<div v-if="visibleCategories[category]">
<button v-for="emoji in customEmojis.filter(e => e.category === category)"
class="_button"
:title="emoji.name"
@click="chosen(emoji, $event)"
:key="emoji.name"
>
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button>
</div>
</section>
<section v-for="category in categories" :key="category.name" class="unicode">
<header class="_acrylic" v-appear="() => category.isActive = true"><Fa :icon="category.icon" fixed-width/> {{ category.name }}</header>
<div v-if="category.isActive">
<button v-for="emoji in emojilist.filter(e => e.category === category.name)"
class="_button"
:title="emoji.name"
@click="chosen(emoji, $event)"
:key="emoji.name"
>
<MkEmoji :emoji="emoji.char"/>
</button>
</div>
</template>
<template v-else>
<div v-for="(key, i) in Object.keys(customEmojis)" :key="i">
<header class="sub" v-if="key">{{ key }}</header>
<div class="list">
<button v-for="emoji in customEmojis[key]"
class="_button"
:title="emoji.name"
@click="chosen(emoji)"
:key="emoji.name"
>
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button>
</div>
</div>
</template>
</section>
</div>
</div>
</MkModal>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import { emojilist } from '../../misc/emojilist';
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser } from '@fortawesome/free-solid-svg-icons';
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
import { groupByX } from '../../prelude/array';
import MkModal from '@/components/ui/modal.vue';
import Particle from '@/components/particle.vue';
import * as os from '@/os';
export default defineComponent({
components: {
@ -80,20 +109,26 @@ export default defineComponent({
src: {
required: false
},
overridePinned: {
required: false
},
},
emits: ['done', 'closed'],
data() {
return {
emojilist,
emojilist: markRaw(emojilist),
getStaticImageUrl,
customEmojis: {},
faGlobe, faHistory,
pinned: this.overridePinned || this.$store.state.settings.reactions,
customEmojiCategories: this.$store.getters['instance/emojiCategories'],
customEmojis: this.$store.state.instance.meta.emojis,
visibleCategories: {},
q: null,
searchResultCustom: [],
searchResultUnicode: [],
faGlobe, faHistory, faChevronDown,
categories: [{
icon: faAsterisk,
isActive: true
}, {
name: 'face',
icon: faLaugh,
isActive: false
@ -134,38 +169,209 @@ export default defineComponent({
};
},
created() {
let local = this.$store.state.instance.meta.emojis;
local = groupByX(local, (x: any) => x.category || '');
this.customEmojis = local;
watch: {
q() {
if (this.q == null || this.q === '') {
this.searchResultCustom = [];
this.searchResultUnicode = [];
return;
}
const q = this.q.replace(/:/g, '');
const searchCustom = () => {
const max = 8;
const emojis = this.customEmojis;
const matches = new Set();
const exactMatch = emojis.find(e => e.name === q);
if (exactMatch) matches.add(exactMatch);
if (q.includes(' ')) { // AND検索
const keywords = q.split(' ');
// 名前にキーワードが含まれている
for (const emoji of emojis) {
if (keywords.every(keyword => emoji.name.includes(keyword))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
// 名前またはエイリアスにキーワードが含まれている
for (const emoji of emojis) {
if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.aliases.some(alias => alias.includes(keyword)))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
} else {
for (const emoji of emojis) {
if (emoji.name.startsWith(q)) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.aliases.some(alias => alias.startsWith(q))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.name.includes(q)) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.aliases.some(alias => alias.includes(q))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
}
return matches;
};
const searchUnicode = () => {
const max = 8;
const emojis = this.emojilist;
const matches = new Set();
const exactMatch = emojis.find(e => e.name === q);
if (exactMatch) matches.add(exactMatch);
if (q.includes(' ')) { // AND検索
const keywords = q.split(' ');
// 名前にキーワードが含まれている
for (const emoji of emojis) {
if (keywords.every(keyword => emoji.name.includes(keyword))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
// 名前またはエイリアスにキーワードが含まれている
for (const emoji of emojis) {
if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.keywords.some(alias => alias.includes(keyword)))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
} else {
for (const emoji of emojis) {
if (emoji.name.startsWith(q)) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.keywords.some(keyword => keyword.startsWith(q))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.name.includes(q)) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
if (matches.size >= max) return matches;
for (const emoji of emojis) {
if (emoji.keywords.some(keyword => keyword.includes(q))) {
matches.add(emoji);
if (matches.size >= max) break;
}
}
}
return matches;
};
this.searchResultCustom = Array.from(searchCustom());
this.searchResultUnicode = Array.from(searchUnicode());
}
},
mounted() {
this.$refs.search.focus({
preventScroll: true
});
},
methods: {
go(category: any) {
this.goCategory(category.name);
getKey(emoji: any) {
return typeof emoji === 'string' ? emoji : (emoji.char || `:${emoji.name}:`);
},
goCategory(name: string) {
let matched = false;
for (const c of this.categories) {
c.isActive = c.name === name;
if (c.isActive) {
matched = true;
}
chosen(emoji: any, ev) {
if (ev) {
const el = ev.currentTarget || ev.target;
const rect = el.getBoundingClientRect();
const x = rect.left + (el.clientWidth / 2);
const y = rect.top + (el.clientHeight / 2);
os.popup(Particle, { x, y }, {}, 'end');
}
if (!matched) {
this.categories[0].isActive = true;
}
},
chosen(emoji: any) {
const getKey = (emoji: any) => emoji.char || `:${emoji.name}:`;
let recents = this.$store.state.device.recentEmojis || [];
recents = recents.filter((e: any) => getKey(e) !== getKey(emoji));
recents.unshift(emoji)
this.$store.commit('device/set', { key: 'recentEmojis', value: recents.splice(0, 16) });
this.$emit('done', getKey(emoji));
const key = this.getKey(emoji);
this.$emit('done', key);
this.$refs.modal.close();
// 最近使った絵文字更新
if (!this.pinned.includes(key)) {
let recents = this.$store.state.device.recentlyUsedEmojis;
recents = recents.filter((e: any) => e !== key);
recents.unshift(key);
this.$store.commit('device/set', { key: 'recentlyUsedEmojis', value: recents.splice(0, 16) });
}
},
paste(event) {
const paste = (event.clipboardData || window.clipboardData).getData('text');
if (this.done(paste)) {
event.preventDefault();
}
},
done(query) {
if (query == null) query = this.q;
if (query == null) return;
const q = query.replace(/:/g, '');
const exactMatchCustom = this.customEmojis.find(e => e.name === q);
if (exactMatchCustom) {
this.chosen(exactMatchCustom);
return true;
}
const exactMatchUnicode = this.emojilist.find(e => e.char === q || e.name === q);
if (exactMatchUnicode) {
this.chosen(exactMatchUnicode);
return true;
}
if (this.searchResultCustom.length > 0) {
this.chosen(this.searchResultCustom[0]);
return true;
}
if (this.searchResultUnicode.length > 0) {
this.chosen(this.searchResultUnicode[0]);
return true;
}
},
}
});
@ -174,85 +380,108 @@ export default defineComponent({
<style lang="scss" scoped>
.omfetrab {
width: 350px;
contain: content;
> header {
display: flex;
> button {
flex: 1;
padding: 10px 0;
font-size: 16px;
transition: color 0.2s ease;
&:hover {
color: var(--fgHighlighted);
transition: color 0s;
}
&.active {
color: var(--accent);
transition: color 0s;
}
}
> .search {
width: 100%;
padding: 12px;
box-sizing: border-box;
font-size: 1em;
outline: none;
border: none;
background: transparent;
color: var(--fg);
}
> .emojis {
height: 300px;
$height: 300px;
height: $height;
overflow-y: auto;
overflow-x: hidden;
> header.category {
position: sticky;
top: 0;
left: 0;
z-index: 1;
padding: 8px;
background: var(--panel);
font-size: 12px;
}
header.sub {
padding: 4px 8px;
font-size: 12px;
}
div.list {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
gap: 4px;
padding: 8px;
> button {
position: relative;
padding: 0;
> .index {
min-height: $height;
position: relative;
border-bottom: solid 1px var(--divider);
> .arrow {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 16px 0;
text-align: center;
opacity: 0.5;
pointer-events: none;
}
}
&:before {
content: '';
display: block;
width: 1px;
height: 0;
padding-bottom: 100%;
}
section {
> header {
position: sticky;
top: 0;
left: 0;
z-index: 1;
padding: 8px;
font-size: 12px;
}
> div {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
gap: 4px;
padding: 8px;
> button {
position: relative;
padding: 0;
width: 100%;
&:focus {
outline: solid 2px var(--focus);
z-index: 1;
}
&:before {
content: '';
display: block;
width: 1px;
height: 0;
padding-bottom: 100%;
}
&:hover {
> * {
transform: scale(1.2);
transition: transform 0s;
}
}
&:hover {
> * {
transform: scale(1.2);
transition: transform 0s;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
font-size: 28px;
transition: transform 0.2s ease;
pointer-events: none;
}
}
}
> * {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
font-size: 28px;
transition: transform 0.2s ease;
pointer-events: none;
}
&.result {
border-bottom: solid 1px var(--divider);
}
&.unicode {
min-height: 384px;
}
&.custom {
min-height: 64px;
}
}
}

View File

@ -2,7 +2,7 @@
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt"/>
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt"/>
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
<span v-else>:{{ name }}:</span>
<span v-else>{{ emoji }}</span>
</template>
<script lang="ts">
@ -12,13 +12,9 @@ import { twemojiSvgBase } from '../../misc/twemoji-base';
export default defineComponent({
props: {
name: {
type: String,
required: false
},
emoji: {
type: String,
required: false
required: true
},
normal: {
type: Boolean,
@ -49,6 +45,10 @@ export default defineComponent({
},
computed: {
isCustom(): boolean {
return this.emoji.startsWith(':');
},
alt(): string {
return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
},
@ -68,8 +68,8 @@ export default defineComponent({
watch: {
ce: {
handler() {
if (this.name) {
const customEmoji = this.ce.find(x => x.name == this.name);
if (this.isCustom) {
const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
if (customEmoji) {
this.customEmoji = customEmoji;
this.url = this.$store.state.device.disableShowingAnimatedImages
@ -83,7 +83,7 @@ export default defineComponent({
},
created() {
if (!this.name) {
if (!this.isCustom) {
this.char = this.emoji;
}

View File

@ -41,10 +41,13 @@ export default defineComponent({
<style lang="scss" scoped>
.xubzgfga {
max-width: 1024px;
display: flex;
flex-direction: column;
height: 100%;
> header,
> footer {
align-self: center;
display: inline-block;
padding: 6px 9px;
font-size: 90%;
@ -60,7 +63,10 @@ export default defineComponent({
> img {
display: block;
max-width: 100%;
flex: 1;
min-height: 0;
object-fit: contain;
width: 100%;
cursor: zoom-out;
image-orientation: from-image;
}

View File

@ -46,7 +46,7 @@ export default defineComponent({
if (!document.body.contains(this.$el)) return;
if (this.close) return;
const { dispose } = os.popup(await import('@/components/url-preview-popup.vue'), {
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
url: this.url,
source: this.$el
});

View File

@ -77,9 +77,61 @@ export default defineComponent({
}, genEl(token.children));
}
case 'big': {
return h('strong', {
style: `display: inline-block; font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: anime-tada 1s linear infinite both;' : ''),
case 'fn': {
// TODO: CSSを文字列で組み立てていくと token.node.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる
let style;
switch (token.node.props.name) {
case 'tada': {
style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
break;
}
case 'jelly': {
const speed = token.node.props.args.speed || '1s';
style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
break;
}
case 'twitch': {
const speed = token.node.props.args.speed || '0.5s';
style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
break;
}
case 'shake': {
const speed = token.node.props.args.speed || '0.5s';
style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
break;
}
case 'spin': {
const direction =
token.node.props.args.left ? 'reverse' :
token.node.props.args.alternate ? 'alternate' :
'normal';
const anime =
token.node.props.args.x ? 'mfm-spinX' :
token.node.props.args.y ? 'mfm-spinY' :
'mfm-spin';
const speed = token.node.props.args.speed || '1.5s';
style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
break;
}
case 'jump': {
style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
break;
}
case 'bounce': {
style = this.$store.state.device.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
break;
}
case 'flip': {
const transform =
(token.node.props.args.h && token.node.props.args.v) ? 'scale(-1, -1)' :
token.node.props.args.v ? 'scaleY(-1)' :
'scaleX(-1)';
style = `transform: ${transform};`;
break;
}
}
return h('span', {
style: 'display: inline-block;' + style,
}, genEl(token.children));
}
@ -95,48 +147,6 @@ export default defineComponent({
}, genEl(token.children))];
}
case 'motion': {
return h('span', {
style: 'display: inline-block;' + (this.$store.state.device.animatedMfm ? 'animation: anime-rubberBand 1s linear infinite both;' : ''),
}, genEl(token.children));
}
case 'spin': {
const direction =
token.node.props.attr == 'left' ? 'reverse' :
token.node.props.attr == 'alternate' ? 'alternate' :
'normal';
const style = this.$store.state.device.animatedMfm
? `animation: anime-spin 1.5s linear infinite; animation-direction: ${direction};` : '';
return h('span', {
style: 'display: inline-block;' + style
}, genEl(token.children));
}
case 'jump': {
return h('span', {
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-jump 0.75s linear infinite;' : 'display: inline-block;'
}, genEl(token.children));
}
case 'flip': {
return h('span', {
style: 'display: inline-block; transform: scaleX(-1);'
}, genEl(token.children));
}
case 'twitch': {
return h('span', {
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-twitch 0.5s ease infinite;' : 'display: inline-block;'
}, genEl(token.children));
}
case 'shake': {
return h('span', {
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-shake 0.5s ease infinite;' : 'display: inline-block;'
}, genEl(token.children));
}
case 'url': {
return [h(MkUrl, {
key: Math.random(),
@ -198,17 +208,10 @@ export default defineComponent({
}
}
case 'title': {
return [h('div', {
class: 'title'
}, genEl(token.children))];
}
case 'emoji': {
return [h(MkEmoji, {
key: Math.random(),
emoji: token.node.props.emoji,
name: token.node.props.name,
emoji: token.node.props.name ? `:${token.node.props.name}:` : token.node.props.emoji,
customEmojis: this.customEmojis,
normal: this.plain
})];

View File

@ -13,6 +13,103 @@ export default defineComponent({
});
</script>
<style lang="scss">
@keyframes mfm-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes mfm-spinX {
0% { transform: perspective(128px) rotateX(0deg); }
100% { transform: perspective(128px) rotateX(360deg); }
}
@keyframes mfm-spinY {
0% { transform: perspective(128px) rotateY(0deg); }
100% { transform: perspective(128px) rotateY(360deg); }
}
@keyframes mfm-jump {
0% { transform: translateY(0); }
25% { transform: translateY(-16px); }
50% { transform: translateY(0); }
75% { transform: translateY(-8px); }
100% { transform: translateY(0); }
}
@keyframes mfm-bounce {
0% { transform: translateY(0) scale(1, 1); }
25% { transform: translateY(-16px) scale(1, 1); }
50% { transform: translateY(0) scale(1, 1); }
75% { transform: translateY(0) scale(1.5, 0.75); }
100% { transform: translateY(0) scale(1, 1); }
}
// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
// let css = '';
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
@keyframes mfm-twitch {
0% { transform: translate(7px, -2px) }
5% { transform: translate(-3px, 1px) }
10% { transform: translate(-7px, -1px) }
15% { transform: translate(0px, -1px) }
20% { transform: translate(-8px, 6px) }
25% { transform: translate(-4px, -3px) }
30% { transform: translate(-4px, -6px) }
35% { transform: translate(-8px, -8px) }
40% { transform: translate(4px, 6px) }
45% { transform: translate(-3px, 1px) }
50% { transform: translate(2px, -10px) }
55% { transform: translate(-7px, 0px) }
60% { transform: translate(-2px, 4px) }
65% { transform: translate(3px, -8px) }
70% { transform: translate(6px, 7px) }
75% { transform: translate(-7px, -2px) }
80% { transform: translate(-7px, -8px) }
85% { transform: translate(9px, 3px) }
90% { transform: translate(-3px, -2px) }
95% { transform: translate(-10px, 2px) }
100% { transform: translate(-2px, -6px) }
}
// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
// let css = '';
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
@keyframes mfm-shake {
0% { transform: translate(-3px, -1px) rotate(-8deg) }
5% { transform: translate(0px, -1px) rotate(-10deg) }
10% { transform: translate(1px, -3px) rotate(0deg) }
15% { transform: translate(1px, 1px) rotate(11deg) }
20% { transform: translate(-2px, 1px) rotate(1deg) }
25% { transform: translate(-1px, -2px) rotate(-2deg) }
30% { transform: translate(-1px, 2px) rotate(-3deg) }
35% { transform: translate(2px, 1px) rotate(6deg) }
40% { transform: translate(-2px, -3px) rotate(-9deg) }
45% { transform: translate(0px, -1px) rotate(-12deg) }
50% { transform: translate(1px, 2px) rotate(10deg) }
55% { transform: translate(0px, -3px) rotate(8deg) }
60% { transform: translate(1px, -1px) rotate(8deg) }
65% { transform: translate(0px, -1px) rotate(-7deg) }
70% { transform: translate(-1px, -3px) rotate(6deg) }
75% { transform: translate(0px, -2px) rotate(4deg) }
80% { transform: translate(-2px, -1px) rotate(3deg) }
85% { transform: translate(1px, -3px) rotate(-10deg) }
90% { transform: translate(1px, 0px) rotate(3deg) }
95% { transform: translate(-2px, 0px) rotate(-3deg) }
100% { transform: translate(2px, 1px) rotate(2deg) }
}
@keyframes mfm-rubberBand {
from { transform: scale3d(1, 1, 1); }
30% { transform: scale3d(1.25, 0.75, 1); }
40% { transform: scale3d(0.75, 1.25, 1); }
50% { transform: scale3d(1.15, 0.85, 1); }
65% { transform: scale3d(0.95, 1.05, 1); }
75% { transform: scale3d(1.05, 0.95, 1); }
to { transform: scale3d(1, 1, 1); }
}
</style>
<style lang="scss" scoped>
.havbbuyv {
white-space: pre-wrap;
@ -42,10 +139,5 @@ export default defineComponent({
word-break: break-all;
padding: 4px 6px;
}
::v-deep(.title) {
text-align: center;
border-bottom: solid 1px var(--divider);
}
}
</style>

View File

@ -498,20 +498,36 @@ export default defineComponent({
react(viaKeyboard = false) {
pleaseLogin();
this.blur();
os.popup(defineAsyncComponent(() => import('@/components/reaction-picker.vue')), {
showFocus: viaKeyboard,
src: this.$refs.reactButton,
}, {
done: reaction => {
if (reaction) {
os.api('notes/reactions/create', {
noteId: this.appearNote.id,
reaction: reaction
});
}
this.focus();
},
}, 'closed');
if (this.$store.state.device.useFullReactionPicker) {
os.popup(import('@/components/emoji-picker.vue'), {
src: this.$refs.reactButton,
}, {
done: reaction => {
if (reaction) {
os.api('notes/reactions/create', {
noteId: this.appearNote.id,
reaction: reaction
});
}
this.focus();
},
}, 'closed');
} else {
os.popup(import('@/components/reaction-picker.vue'), {
showFocus: viaKeyboard,
src: this.$refs.reactButton,
}, {
done: reaction => {
if (reaction) {
os.api('notes/reactions/create', {
noteId: this.appearNote.id,
reaction: reaction
});
}
this.focus();
},
}, 'closed');
}
},
reactDirectly(reaction) {
@ -644,7 +660,7 @@ export default defineComponent({
text: this.$t('reportAbuse'),
action: () => {
const u = `${url}/notes/${this.appearNote.id}`;
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
os.popup(import('@/components/abuse-report-window.vue'), {
user: this.appearNote.user,
initialComment: `Note: ${u}\n-----\n`
}, {}, 'closed');

View File

@ -1,6 +1,6 @@
<template>
<XWindow ref="window"
:initial-width="400"
:initial-width="700"
:initial-height="500"
:can-resize="true"
:close-right="true"
@ -28,6 +28,7 @@ import XHeader from '@/ui/_common_/header.vue';
import { popout } from '@/scripts/popout';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import { resolve } from '@/router';
import { url } from '@/config';
export default defineComponent({
components: {
@ -43,14 +44,14 @@ export default defineComponent({
provide() {
return {
navHook: (url) => {
this.navigate(url);
navHook: (path) => {
this.navigate(path);
}
};
},
props: {
initialUrl: {
initialPath: {
type: String,
required: true,
},
@ -70,7 +71,7 @@ export default defineComponent({
data() {
return {
pageInfo: null,
url: this.initialUrl,
path: this.initialPath,
component: this.initialComponent,
props: this.initialProps,
history: [],
@ -79,10 +80,14 @@ export default defineComponent({
},
computed: {
url(): string {
return url + this.path;
},
contextmenu() {
return [{
type: 'label',
text: this.url,
text: this.path,
}, {
icon: faExpandAlt,
text: this.$t('showInPage'),
@ -91,7 +96,7 @@ export default defineComponent({
icon: faColumns,
text: this.$t('openInSideView'),
action: () => {
this.sideViewHook(this.url);
this.sideViewHook(this.path);
this.$refs.window.close();
}
} : undefined, {
@ -123,10 +128,10 @@ export default defineComponent({
}
},
navigate(url, record = true) {
if (record) this.history.push(this.url);
this.url = url;
const { component, props } = resolve(url);
navigate(path, record = true) {
if (record) this.history.push(this.path);
this.path = path;
const { component, props } = resolve(path);
this.component = component;
this.props = props;
},
@ -136,12 +141,12 @@ export default defineComponent({
},
expand() {
this.$router.push(this.url);
this.$router.push(this.path);
this.$refs.window.close();
},
popout() {
popout(this.url, this.$el);
popout(this.path, this.$el);
this.$refs.window.close();
},
},

View File

@ -378,13 +378,13 @@ export default defineComponent({
this.saveDraft();
},
async setVisibility() {
setVisibility() {
if (this.channel) {
// TODO: information dialog
return;
}
os.popup(await import('./visibility-picker.vue'), {
os.popup(import('./visibility-picker.vue'), {
currentVisibility: this.visibility,
currentLocalOnly: this.localOnly,
src: this.$refs.visibilityButton

View File

@ -1,9 +1,9 @@
<template>
<MkEmoji :emoji="reaction.startsWith(':') ? null : reaction" :name="reaction.startsWith(':') ? reaction.substr(1, reaction.length - 2) : null" :customEmojis="customEmojis" :is-reaction="true" :normal="true" :no-style="noStyle"/>
<MkEmoji :emoji="reaction" :custom-emojis="customEmojis" :is-reaction="true" :normal="true" :no-style="noStyle"/>
</template>
<script lang="ts">
import { defineComponent } from 'vue';import * as os from '@/os';
import { defineComponent } from 'vue';
export default defineComponent({
props: {

View File

@ -11,14 +11,11 @@
<transition name="nav">
<nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
<div>
<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
<button class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/>
</button>
<button class="item _button index active" @click="top()" v-if="$route.name === 'index'">
<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
</button>
<MkA class="item index" active-class="active" to="/" exact v-else>
<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
<MkA class="item index" active-class="active" to="/" exact>
<Fa :icon="faHome" fixed-width/><span class="text">{{ $t('timeline') }}</span>
</MkA>
<template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div>
@ -28,7 +25,7 @@
</component>
</template>
<div class="divider"></div>
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu">
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.state.i.isAdmin || $store.state.i.isModerator" @click="oepnInstanceMenu">
<Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
</button>
<button class="item _button" @click="more">
@ -74,7 +71,6 @@ export default defineComponent({
},
otherNavItemIndicated(): boolean {
if (!this.$store.getters.isSignedIn) return false;
for (const def in this.menuDef) {
if (this.menu.includes(def)) continue;
if (this.menuDef[def].indicated) return true;
@ -120,10 +116,6 @@ export default defineComponent({
this.showing = true;
},
top() {
window.scroll({ top: 0, behavior: 'smooth' });
},
search() {
if (this.searching) return;
@ -257,8 +249,8 @@ export default defineComponent({
}], ev.currentTarget || ev.target);
},
async addAcount() {
os.popup(await import('./signin-dialog.vue'), {}, {
addAcount() {
os.popup(import('./signin-dialog.vue'), {}, {
done: res => {
this.$store.dispatch('addAcount', res);
os.success();
@ -266,8 +258,8 @@ export default defineComponent({
}, 'closed');
},
async createAccount() {
os.popup(await import('./signup-dialog.vue'), {}, {
createAccount() {
os.popup(import('./signup-dialog.vue'), {}, {
done: res => {
this.$store.dispatch('addAcount', res);
this.switchAccountWithToken(res.i);
@ -275,7 +267,7 @@ export default defineComponent({
}, 'closed');
},
async switchAccount(account: any) {
switchAccount(account: any) {
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
this.switchAccountWithToken(token);
},

View File

@ -119,8 +119,8 @@ export default defineComponent({
os.popups.value = os.popups.value.filter(x => x !== p);
};
const showReq = async req => {
os.popup(await import('./taskmanager.api-window.vue'), {
const showReq = req => {
os.popup(import('./taskmanager.api-window.vue'), {
req: req
}, {
}, 'closed');

View File

@ -10,7 +10,8 @@ import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } f
import * as os from '@/os';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import { router } from '@/router';
import { deckmode, url } from '@/config';
import { ui, url } from '@/config';
import { popout } from '@/scripts/popout';
export default defineComponent({
inject: {
@ -87,11 +88,23 @@ export default defineComponent({
}], e);
},
window() {
os.pageWindow(this.to);
},
popout() {
popout(this.to);
},
nav() {
if (this.to.startsWith('/my/messaging')) {
if (this.$store.state.device.chatOpenBehavior === 'window') return this.window();
if (this.$store.state.device.chatOpenBehavior === 'popout') return this.popout();
}
if (this.behavior) {
if (this.behavior === 'window') {
os.pageWindow(this.to);
return;
return this.window();
}
}
@ -99,15 +112,20 @@ export default defineComponent({
this.navHook(this.to);
} else {
if (this.$store.state.device.defaultSideView && this.sideViewHook && this.to !== '/') {
this.sideViewHook(this.to);
return;
return this.sideViewHook(this.to);
}
if (this.$store.state.device.deckNavWindow && deckmode && this.to !== '/') {
os.pageWindow(this.to);
return;
if (this.$store.state.device.deckNavWindow && (ui === 'deck') && this.to !== '/') {
return this.window();
}
if (ui === 'desktop') {
return this.window();
}
this.$router.push(this.to);
if (this.$router.currentRoute.value.path === this.to) {
window.scroll({ top: 0, behavior: 'smooth' });
} else {
this.$router.push(this.to);
}
}
}
}

View File

@ -23,11 +23,11 @@
<span>{{ item.text }}</span>
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
</a>
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item">
<button v-else-if="item.type === 'user'" @click="clicked(item.action, $event)" :tabindex="i" class="_button item">
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
</button>
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :class="{ danger: item.danger }">
<button v-else @click="clicked(item.action, $event)" :tabindex="i" class="_button item" :class="{ danger: item.danger }">
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
<span>{{ item.text }}</span>
@ -115,8 +115,8 @@ export default defineComponent({
}
},
methods: {
clicked(fn) {
fn();
clicked(fn, ev) {
fn(ev);
this.close();
},
close() {

View File

@ -1,5 +1,5 @@
<template>
<div class="cxiknjgy" :class="{ autoMargin }">
<div class="cxiknjgy">
<slot :items="items"></slot>
<div class="empty" v-if="empty" key="_empty_">
<slot name="empty"></slot>
@ -31,24 +31,12 @@ export default defineComponent({
pagination: {
required: true
},
autoMargin: {
required: false,
default: true
}
},
});
</script>
<style lang="scss" scoped>
.cxiknjgy {
&.autoMargin > *:not(:last-child) {
margin-bottom: 16px;
@media (max-width: 500px) {
margin-bottom: 8px;
}
}
> .more > .button {
margin-left: auto;
margin-right: auto;

View File

@ -71,7 +71,7 @@ export default defineComponent({
if (!document.body.contains(this.$el)) return;
if (this.close) return;
const { dispose } = os.popup(await import('@/components/url-preview-popup.vue'), {
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
url: this.url,
source: this.$el
});

View File

@ -14,10 +14,10 @@
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $t('host') }}</span><template #prefix>@</template></MkInput>
</div>
</div>
<div class="tbhwbxda _section" :style="users.length > 0 ? 'padding: 0;' : ''">
<div class="tbhwbxda _section result" v-if="username != '' || host != ''" :class="{ hit: users.length > 0 }">
<div class="users" v-if="users.length > 0">
<div class="user" v-for="user in users" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar" :disable-link="true"/>
<MkAvatar :user="user" class="avatar"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
@ -28,6 +28,17 @@
<span>{{ $t('noUsers') }}</span>
</div>
</div>
<div class="tbhwbxda _section recent" v-if="username == '' && host == ''">
<div class="users">
<div class="user" v-for="user in recentUsers" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" class="avatar"/>
<div class="body">
<MkUserName :user="user" class="name"/>
<MkAcct :user="user" class="acct"/>
</div>
</div>
</div>
</div>
</XModalWindow>
</template>
@ -53,18 +64,23 @@ export default defineComponent({
return {
username: '',
host: '',
recentUsers: [],
users: [],
selected: null,
faTimes, faCheck
};
},
mounted() {
async mounted() {
this.focus();
this.$nextTick(() => {
this.focus();
});
this.recentUsers = await os.api('users/show', {
userIds: this.$store.state.device.recentlyUsedUsers
});
},
methods: {
@ -90,6 +106,12 @@ export default defineComponent({
ok() {
this.$emit('ok', this.selected);
this.$refs.dialog.close();
// 最近使ったユーザー更新
let recents = this.$store.state.device.recentlyUsedUsers;
recents = recents.filter(x => x !== this.selected.id);
recents.unshift(this.selected.id);
this.$store.commit('device/set', { key: 'recentlyUsedUsers', value: recents.splice(0, 16) });
},
cancel() {
@ -107,6 +129,14 @@ export default defineComponent({
overflow: auto;
height: 100%;
&.result.hit {
padding: 0;
}
&.recent {
padding: 0;
}
> .inputs {
> .input {
display: inline-block;

View File

@ -13,5 +13,5 @@ export const langs = _LANGS_;
export const getLocale = async () => Object.fromEntries((await entries(clientDb.i18n)) as [string, string][]);
export const version = _VERSION_;
export const instanceName = siteName === 'Misskey' ? host : siteName;
export const deckmode = localStorage.getItem('deckmode') === 'true';
export const ui = localStorage.getItem('ui');
export const debug = localStorage.getItem('debug') === 'true';

View File

@ -23,13 +23,13 @@ export default {
}
};
const show = async e => {
const show = e => {
if (!document.body.contains(el)) return;
if (self._close) return;
if (self.text == null) return;
const showing = ref(true);
popup(await import('@/components/ui/tooltip.vue'), {
popup(import('@/components/ui/tooltip.vue'), {
showing,
text: self.text,
source: el

View File

@ -18,13 +18,13 @@ export class UserPreview {
}
@autobind
private async show() {
private show() {
if (!document.body.contains(this.el)) return;
if (this.promise) return;
const showing = ref(true);
popup(await import('@/components/user-preview.vue'), {
popup(import('@/components/user-preview.vue'), {
showing,
q: this.user,
source: this.el

View File

@ -4,13 +4,13 @@
import '@/style.scss';
import { createApp, defineAsyncComponent } from 'vue';
import { createApp } from 'vue';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import widgets from './widgets';
import directives from './directives';
import components from '@/components';
import { version, apiUrl, deckmode } from '@/config';
import { version, apiUrl, ui } from '@/config';
import { store } from './store';
import { router } from './router';
import { applyTheme } from '@/scripts/theme';
@ -154,7 +154,8 @@ stream.init(store.state.i);
const app = createApp(await (
window.location.search === '?zen' ? import('@/ui/zen.vue') :
!store.getters.isSignedIn ? import('@/ui/visitor.vue') :
deckmode ? import('@/ui/deck.vue') :
ui === 'deck' ? import('@/ui/deck.vue') :
ui === 'desktop' ? import('@/ui/desktop.vue') :
import('@/ui/default.vue')
).then(x => x.default));

View File

@ -147,7 +147,9 @@ export const popups = ref([]) as Ref<{
props: Record<string, any>;
}[]>;
export function popup(component: Component | typeof import('*.vue'), props: Record<string, any>, events = {}, disposeEvent?: string) {
export async function popup(component: Component | typeof import('*.vue') | Promise<Component | typeof import('*.vue')>, props: Record<string, any>, events = {}, disposeEvent?: string) {
if (component.then) component = await component;
if (isModule(component)) component = component.default;
markRaw(component);
@ -177,10 +179,10 @@ export function popup(component: Component | typeof import('*.vue'), props: Reco
};
}
export function pageWindow(url: string) {
const { component, props } = resolve(url);
popup(defineAsyncComponent(() => import('@/components/page-window.vue')), {
initialUrl: url,
export function pageWindow(path: string) {
const { component, props } = resolve(path);
popup(import('@/components/page-window.vue'), {
initialPath: path,
initialComponent: markRaw(component),
initialProps: props,
}, {}, 'closed');
@ -188,7 +190,7 @@ export function pageWindow(url: string) {
export function dialog(props: Record<string, any>) {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/dialog.vue')), props, {
popup(import('@/components/dialog.vue'), props, {
done: result => {
resolve(result ? result : { canceled: true });
},
@ -202,7 +204,7 @@ export function success() {
setTimeout(() => {
showing.value = false;
}, 1000);
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
popup(import('@/components/waiting-dialog.vue'), {
success: true,
showing: showing
}, {
@ -214,7 +216,7 @@ export function success() {
export function waiting() {
return new Promise((resolve, reject) => {
const showing = ref(true);
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
popup(import('@/components/waiting-dialog.vue'), {
success: false,
showing: showing
}, {
@ -225,7 +227,7 @@ export function waiting() {
export function form(title, form) {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/form-dialog.vue')), { title, form }, {
popup(import('@/components/form-dialog.vue'), { title, form }, {
done: result => {
resolve(result);
},
@ -235,7 +237,7 @@ export function form(title, form) {
export async function selectUser() {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/user-select-dialog.vue')), {}, {
popup(import('@/components/user-select-dialog.vue'), {}, {
ok: user => {
resolve(user);
},
@ -245,7 +247,7 @@ export async function selectUser() {
export async function selectDriveFile(multiple: boolean) {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/drive-window.vue')), {
popup(import('@/components/drive-select-dialog.vue'), {
type: 'file',
multiple
}, {
@ -260,7 +262,7 @@ export async function selectDriveFile(multiple: boolean) {
export async function selectDriveFolder(multiple: boolean) {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/drive-window.vue')), {
popup(import('@/components/drive-select-dialog.vue'), {
type: 'folder',
multiple
}, {
@ -275,7 +277,7 @@ export async function selectDriveFolder(multiple: boolean) {
export async function pickEmoji(src?: HTMLElement) {
return new Promise((resolve, reject) => {
popup(defineAsyncComponent(() => import('@/components/emoji-picker.vue')), {
popup(import('@/components/emoji-picker.vue'), {
src
}, {
done: emoji => {
@ -287,7 +289,8 @@ export async function pickEmoji(src?: HTMLElement) {
export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
return new Promise((resolve, reject) => {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/ui/modal-menu.vue')), {
let dispose;
popup(import('@/components/ui/modal-menu.vue'), {
items,
src,
align: options?.align,
@ -297,6 +300,8 @@ export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: s
resolve();
dispose();
},
}).then(res => {
dispose = res.dispose;
});
});
}
@ -304,7 +309,8 @@ export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: s
export function contextMenu(items: any[], ev: MouseEvent) {
ev.preventDefault();
return new Promise((resolve, reject) => {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/ui/context-menu.vue')), {
let dispose;
popup(import('@/components/ui/context-menu.vue'), {
items,
ev,
}, {
@ -312,6 +318,8 @@ export function contextMenu(items: any[], ev: MouseEvent) {
resolve();
dispose();
},
}).then(res => {
dispose = res.dispose;
});
});
}
@ -323,11 +331,14 @@ export function post(props: Record<string, any>) {
// Vueが渡されたコンポーネントに内部的に__propsというプロパティを生やす影響で、
// 複数のpost formを開いたときに場合によってはエラーになる
// もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
const { dispose } = popup(MkPostFormDialog, props, {
let dispose;
popup(MkPostFormDialog, props, {
closed: () => {
resolve();
dispose();
},
}).then(res => {
dispose = res.dispose;
});
});
}

View File

@ -22,10 +22,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('error'),
icon: faExclamationTriangle
}]
title: this.$t('error'),
icon: faExclamationTriangle
},
faExclamationTriangle
};

View File

@ -87,10 +87,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('aboutMisskey'),
icon: null
}]
title: this.$t('aboutMisskey'),
icon: null
},
version,
faInfoCircle

View File

@ -37,10 +37,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('about'),
icon: faInfoCircle
}]
title: this.$t('about'),
icon: faInfoCircle
},
version,
serverInfo: null,

View File

@ -1,7 +1,7 @@
<template>
<div class="_section">
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content" ref="list">
<section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id">
<section class="_card announcement _vMargin" v-for="(announcement, i) in items" :key="announcement.id">
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
<div class="_content">
<Mfm :text="announcement.text"/>
@ -31,10 +31,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('announcements'),
icon: faBroadcastTower
}]
title: this.$t('announcements'),
icon: faBroadcastTower
},
pagination: {
endpoint: 'announcements',

View File

@ -41,10 +41,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: 'API console',
icon: faTerminal
}]
title: 'API console',
icon: faTerminal
},
endpoint: '',

View File

@ -51,10 +51,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('installedApps'),
icon: faPlug,
}],
title: this.$t('installedApps'),
icon: faPlug,
},
pagination: {
endpoint: 'i/apps',

View File

@ -46,15 +46,11 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.channelId ? {
header: [{
title: this.$t('_channel.edit'),
icon: faSatelliteDish,
}],
title: this.$t('_channel.edit'),
icon: faSatelliteDish,
} : {
header: [{
title: this.$t('_channel.create'),
icon: faSatelliteDish,
}],
title: this.$t('_channel.create'),
icon: faSatelliteDish,
}),
channel: null,
name: null,

View File

@ -54,10 +54,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.channel ? {
header: [{
title: this.channel.name,
icon: faSatelliteDish,
}],
title: this.channel.name,
icon: faSatelliteDish,
} : null),
channel: null,
showBanner: true,

View File

@ -43,10 +43,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('channel'),
icon: faSatelliteDish
}]
title: this.$t('channel'),
icon: faSatelliteDish
},
tab: 'featured',
featuredPagination: {

View File

@ -43,10 +43,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.title,
icon: faFileAlt
}],
title: this.title,
icon: faFileAlt
},
faFileAlt,
title: '',

View File

@ -21,10 +21,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('help'),
icon: faQuestionCircle
}],
title: this.$t('help'),
icon: faQuestionCircle
},
docs: [],
faQuestionCircle

View File

@ -18,10 +18,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: computed(() => this.folder ? this.folder.name : this.$t('drive')),
icon: faCloud,
}],
title: computed(() => this.folder ? this.folder.name : this.$t('drive')),
icon: faCloud,
action: {
icon: faEllipsisH,
handler: this.menu

View File

@ -93,10 +93,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('explore'),
icon: faHashtag
}],
title: this.$t('explore'),
icon: faHashtag
},
pinnedUsers: { endpoint: 'pinned-users' },
popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {

View File

@ -19,10 +19,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('favorites'),
icon: faStar
}]
title: this.$t('favorites'),
icon: faStar
},
pagination: {
endpoint: 'i/favorites',

View File

@ -18,10 +18,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('featured'),
icon: faFireAlt
}],
title: this.$t('featured'),
icon: faFireAlt
},
pagination: {
endpoint: 'notes/featured',

View File

@ -44,10 +44,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('followRequests'),
icon: faUserClock,
}],
title: this.$t('followRequests'),
icon: faUserClock,
},
pagination: {
endpoint: 'following/requests/list',

View File

@ -33,7 +33,7 @@
</div>
-->
<MkPagination :pagination="pagination" #default="{items}" ref="reports" :auto-margin="false" style="margin-top: var(--margin);">
<MkPagination :pagination="pagination" #default="{items}" ref="reports" style="margin-top: var(--margin);">
<div class="bcekxzvu _card _vMargin" v-for="report in items" :key="report.id">
<div class="_content target">
<MkAvatar class="avatar" :user="report.targetUser"/>
@ -84,10 +84,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('abuseReports'),
icon: faExclamationCircle
}],
title: this.$t('abuseReports'),
icon: faExclamationCircle
},
searchUsername: '',
searchHost: '',

View File

@ -45,10 +45,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('announcements'),
icon: faBroadcastTower
}]
title: this.$t('announcements'),
icon: faBroadcastTower
},
announcements: [],
faBroadcastTower, faSave, faTrashAlt, faPlus

View File

@ -5,7 +5,7 @@
</div>
<div class="_section">
<div class="_content local" v-if="tab === 'local'">
<div class="local" v-if="tab === 'local'">
<MkButton primary @click="add" style="margin: 0 auto var(--margin) auto;"><Fa :icon="faPlus"/> {{ $t('addEmoji') }}</MkButton>
<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
<MkPagination :pagination="pagination" ref="emojis">
@ -24,7 +24,7 @@
</MkPagination>
</div>
<div class="_content remote" v-else-if="tab === 'remote'">
<div class="remote" v-else-if="tab === 'remote'">
<MkInput v-model:value="queryRemote" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
<MkInput v-model:value="host" :debounce="true"><span>{{ $t('host') }}</span></MkInput>
<MkPagination :pagination="remotePagination" ref="remoteEmojis">
@ -68,10 +68,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('customEmojis'),
icon: faLaugh
}],
title: this.$t('customEmojis'),
icon: faLaugh,
action: {
icon: faPlus,
handler: this.add
@ -83,14 +81,14 @@ export default defineComponent({
host: '',
pagination: {
endpoint: 'admin/emoji/list',
limit: 15,
limit: 30,
params: computed(() => ({
query: (this.query && this.query !== '') ? this.query : null
}))
},
remotePagination: {
endpoint: 'admin/emoji/list-remote',
limit: 15,
limit: 30,
params: computed(() => ({
query: (this.queryRemote && this.queryRemote !== '') ? this.queryRemote : null,
host: (this.host && this.host !== '') ? this.host : null
@ -113,8 +111,8 @@ export default defineComponent({
os.promiseDialog(promise);
},
async edit(emoji) {
os.popup(await import('./emoji-edit-dialog.vue'), {
edit(emoji) {
os.popup(import('./emoji-edit-dialog.vue'), {
emoji: emoji
}, {
done: result => {

View File

@ -79,10 +79,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('federation'),
icon: faGlobe
}],
title: this.$t('federation'),
icon: faGlobe
},
host: '',
state: 'federating',

View File

@ -84,8 +84,8 @@ export default defineComponent({
Progress.done();
},
async showUser() {
os.popup(await import('./user-dialog.vue'), {
showUser() {
os.popup(import('./user-dialog.vue'), {
userId: this.file.userId
}, {}, 'closed');
},

View File

@ -34,7 +34,7 @@
<span>{{ $t('type') }}</span>
</MkInput>
</div>
<MkPagination :pagination="pagination" #default="{items}" class="urempief" ref="files" :auto-margin="false">
<MkPagination :pagination="pagination" #default="{items}" class="urempief" ref="files">
<button class="file _panel _button _vMargin" v-for="file in items" :key="file.id" @click="show(file, $event)">
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
<div class="body">
@ -84,10 +84,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('files'),
icon: faCloud
}],
title: this.$t('files'),
icon: faCloud
},
q: null,
origin: 'local',
@ -131,8 +129,8 @@ export default defineComponent({
});
},
async show(file, ev) {
os.popup(await import('./file-dialog.vue'), {
show(file, ev) {
os.popup(import('./file-dialog.vue'), {
fileId: file.id
}, {}, 'closed');
},

View File

@ -86,7 +86,7 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
tabs: [{
id: 'index',
title: null,
tooltip: this.$t('instance'),

View File

@ -49,10 +49,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('serverLogs'),
icon: faStream
}]
title: this.$t('serverLogs'),
icon: faStream
},
logs: [],
logLevel: 'all',

View File

@ -31,10 +31,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('jobQueue'),
icon: faExchangeAlt,
}],
title: this.$t('jobQueue'),
icon: faExchangeAlt,
},
connection: os.stream.useSharedConnection('queueStats'),
faExchangeAlt, faTrashAlt

View File

@ -38,10 +38,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('relays'),
icon: faProjectDiagram,
}],
title: this.$t('relays'),
icon: faProjectDiagram,
},
relays: [],
inbox: '',

View File

@ -257,10 +257,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('instance'),
icon: faCog,
}],
title: this.$t('instance'),
icon: faCog,
},
url,
proxyAccount: null,

View File

@ -52,7 +52,7 @@
</MkInput>
</div>
<MkPagination :pagination="pagination" #default="{items}" class="users" ref="users" :auto-margin="false">
<MkPagination :pagination="pagination" #default="{items}" class="users" ref="users">
<button class="user _panel _button _vMargin" v-for="user in items" :key="user.id" @click="show(user)">
<MkAvatar class="avatar" :user="user" :disable-link="true"/>
<div class="body">
@ -101,10 +101,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('users'),
icon: faUsers
}],
title: this.$t('users'),
icon: faUsers,
action: {
icon: faSearch,
handler: this.searchUser
@ -206,8 +204,8 @@ export default defineComponent({
});
},
async show(user) {
os.popup(await import('./user-dialog.vue'), {
show(user) {
os.popup(import('./user-dialog.vue'), {
userId: user.id
}, {}, 'closed');
},

View File

@ -18,10 +18,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('mentions'),
icon: faAt
}],
title: this.$t('mentions'),
icon: faAt
},
pagination: {
endpoint: 'notes/mentions',

View File

@ -18,10 +18,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('directNotes'),
icon: faEnvelope
}],
title: this.$t('directNotes'),
icon: faEnvelope
},
pagination: {
endpoint: 'notes/mentions',

View File

@ -53,10 +53,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('messaging'),
icon: faComments
}]
title: this.$t('messaging'),
icon: faComments
},
fetching: true,
moreFetching: false,

View File

@ -62,19 +62,15 @@ const Component = defineComponent({
data() {
return {
INFO: computed(() => !this.fetching ? this.user ? {
header: [{
userName: this.user,
avatar: this.user,
}],
userName: this.user,
avatar: this.user,
action: {
icon: faEllipsisH,
handler: this.menu,
},
} : {
header: [{
title: this.group.name,
icon: faUsers
}],
title: this.group.name,
icon: faUsers,
action: {
icon: faEllipsisH,
handler: this.menu,
@ -311,20 +307,20 @@ const Component = defineComponent({
},
menu(ev) {
const url = this.groupId ? `/my/messaging/group/${this.groupId}` : `/my/messaging/${this.userAcct}`;
const path = this.groupId ? `/my/messaging/group/${this.groupId}` : `/my/messaging/${this.userAcct}`;
os.modalMenu([this.inWindow ? undefined : {
text: this.$t('openInWindow'),
icon: faWindowMaximize,
action: () => {
os.pageWindow(url);
os.pageWindow(path);
this.$router.back();
},
}, this.inWindow ? undefined : {
text: this.$t('popout'),
icon: faExternalLinkAlt,
action: () => {
popout(url);
popout(path);
this.$router.back();
},
}], ev.currentTarget || ev.target);

View File

@ -0,0 +1,269 @@
<template>
<div class="mwysmxbg">
<div class="_section">
<div class="_content">
<p>{{ $t('_mfm.intro') }}</p>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.mention') }}</div>
<div class="_content">
<p>{{ $t('_mfm.mentionDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_mention"/>
<MkTextarea v-model:value="preview_mention"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.hashtag') }}</div>
<div class="_content">
<p>{{ $t('_mfm.hashtagDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_hashtag"/>
<MkTextarea v-model:value="preview_hashtag"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.url') }}</div>
<div class="_content">
<p>{{ $t('_mfm.urlDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_url"/>
<MkTextarea v-model:value="preview_url"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.link') }}</div>
<div class="_content">
<p>{{ $t('_mfm.linkDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_link"/>
<MkTextarea v-model:value="preview_link"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.emoji') }}</div>
<div class="_content">
<p>{{ $t('_mfm.emojiDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_emoji"/>
<MkTextarea v-model:value="preview_emoji"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.bold') }}</div>
<div class="_content">
<p>{{ $t('_mfm.boldDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_bold"/>
<MkTextarea v-model:value="preview_bold"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.small') }}</div>
<div class="_content">
<p>{{ $t('_mfm.smallDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_small"/>
<MkTextarea v-model:value="preview_small"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.quote') }}</div>
<div class="_content">
<p>{{ $t('_mfm.quoteDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_quote"/>
<MkTextarea v-model:value="preview_quote"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.center') }}</div>
<div class="_content">
<p>{{ $t('_mfm.centerDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_center"/>
<MkTextarea v-model:value="preview_center"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.inlineCode') }}</div>
<div class="_content">
<p>{{ $t('_mfm.inlineCodeDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_inlineCode"/>
<MkTextarea v-model:value="preview_inlineCode"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.blockCode') }}</div>
<div class="_content">
<p>{{ $t('_mfm.blockCodeDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_blockCode"/>
<MkTextarea v-model:value="preview_blockCode"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.inlineMath') }}</div>
<div class="_content">
<p>{{ $t('_mfm.inlineMathDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_inlineMath"/>
<MkTextarea v-model:value="preview_inlineMath"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.search') }}</div>
<div class="_content">
<p>{{ $t('_mfm.searchDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_search"/>
<MkTextarea v-model:value="preview_search"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.flip') }}</div>
<div class="_content">
<p>{{ $t('_mfm.flipDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_flip"/>
<MkTextarea v-model:value="preview_flip"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.jelly') }}</div>
<div class="_content">
<p>{{ $t('_mfm.jellyDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_jelly"/>
<MkTextarea v-model:value="preview_jelly"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.tada') }}</div>
<div class="_content">
<p>{{ $t('_mfm.tadaDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_tada"/>
<MkTextarea v-model:value="preview_tada"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.jump') }}</div>
<div class="_content">
<p>{{ $t('_mfm.jumpDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_jump"/>
<MkTextarea v-model:value="preview_jump"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.bounce') }}</div>
<div class="_content">
<p>{{ $t('_mfm.bounceDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_bounce"/>
<MkTextarea v-model:value="preview_bounce"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.spin') }}</div>
<div class="_content">
<p>{{ $t('_mfm.spinDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_spin"/>
<MkTextarea v-model:value="preview_spin"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.shake') }}</div>
<div class="_content">
<p>{{ $t('_mfm.shakeDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_shake"/>
<MkTextarea v-model:value="preview_shake"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $t('_mfm.twitch') }}</div>
<div class="_content">
<p>{{ $t('_mfm.twitchDescription') }}</p>
<div class="preview _panel">
<Mfm :text="preview_twitch"/>
<MkTextarea v-model:value="preview_twitch"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
import MkTextarea from '@/components/ui/textarea.vue';
export default defineComponent({
components: {
MkTextarea
},
data() {
return {
INFO: {
title: this.$t('_mfm.cheatSheet'),
icon: faQuestionCircle,
},
preview_mention: '@example',
preview_hashtag: '#test',
preview_url: `https://example.com`,
preview_link: `[${this.$t('_mfm.dummy')}](https://example.com)`,
preview_emoji: `:${this.$store.state.instance.meta.emojis[0].name}:`,
preview_bold: `**${this.$t('_mfm.dummy')}**`,
preview_small: `<small>${this.$t('_mfm.dummy')}</small>`,
preview_center: `<center>${this.$t('_mfm.dummy')}</center>`,
preview_inlineCode: '`<: "Hello, world!"`',
preview_blockCode: '```\n~ (#i, 100) {\n\t<: ? ((i % 15) = 0) "FizzBuzz"\n\t\t.? ((i % 3) = 0) "Fizz"\n\t\t.? ((i % 5) = 0) "Buzz"\n\t\t. i\n}\n```',
preview_inlineMath: '\\(x= \\frac{-b\' \\pm \\sqrt{(b\')^2-ac}}{a}\\)',
preview_quote: `> ${this.$t('_mfm.dummy')}`,
preview_search: `${this.$t('_mfm.dummy')} 検索`,
preview_jelly: `[jelly 🍮]`,
preview_tada: `[tada 🍮]`,
preview_jump: `[jump 🍮]`,
preview_bounce: `[bounce 🍮]`,
preview_shake: `[shake 🍮]`,
preview_twitch: `[twitch 🍮]`,
preview_spin: `[spin 🍮] [spin.left 🍮] [spin.alternate 🍮]\n[spin.x 🍮] [spin.x,left 🍮] [spin.x,alternate 🍮]\n[spin.y 🍮] [spin.y,left 🍮] [spin.y,alternate 🍮]`,
preview_flip: `[flip ${this.$t('_mfm.dummy')}]\n[flip.v ${this.$t('_mfm.dummy')}]\n[flip.h,v ${this.$t('_mfm.dummy')}]`,
}
},
});
</script>
<style lang="scss" scoped>
.mwysmxbg {
.preview {
padding: 16px;
}
}
</style>

View File

@ -29,10 +29,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('manageAntennas'),
icon: faSatellite
}],
title: this.$t('manageAntennas'),
icon: faSatellite,
action: {
icon: faPlus,
handler: this.create

View File

@ -48,10 +48,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.group ? {
header: [{
title: this.group.name,
icon: faUsers,
}],
title: this.group.name,
icon: faUsers,
} : null),
group: null,
users: [],

View File

@ -63,10 +63,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('groups'),
icon: faUsers
}],
title: this.$t('groups'),
icon: faUsers
},
tab: 'owned',
ownedPagination: {

View File

@ -26,10 +26,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('manageLists'),
icon: faListUl
}],
title: this.$t('manageLists'),
icon: faListUl,
action: {
icon: faPlus,
handler: this.create

View File

@ -47,10 +47,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.list ? {
header: [{
title: this.list.name,
icon: faListUl,
}],
title: this.list.name,
icon: faListUl,
} : null),
list: null,
users: [],

View File

@ -16,10 +16,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('notFound'),
icon: faExclamationTriangle
}]
title: this.$t('notFound'),
icon: faExclamationTriangle
},
}
},

View File

@ -51,10 +51,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.note ? {
header: [{
title: this.$t('note'),
avatar: this.note.user,
}],
title: this.$t('note'),
avatar: this.note.user,
} : null),
note: null,
hasPrev: false,

View File

@ -21,10 +21,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('notifications'),
icon: faBell
}]
title: this.$t('notifications'),
icon: faBell
},
};
},

View File

@ -57,10 +57,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.page ? {
header: [{
title: computed(() => this.page.title || this.page.name),
avatar: this.page.user,
}],
title: computed(() => this.page.title || this.page.name),
avatar: this.page.user,
} : null),
page: null,
faHeartS, faHeartR

View File

@ -35,10 +35,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('pages'),
icon: faStickyNote
}],
title: this.$t('pages'),
icon: faStickyNote,
action: {
icon: faPlus,
handler: this.create

View File

@ -11,7 +11,7 @@
<Mfm :key="'past-turn-of:' + turnUser().name" :text="$t('_reversi.pastTurnOf', { name: turnUser().name })" :plain="true" :custom-emojis="turnUser().emojis"/>
</p>
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn()">{{ $t('_reversi.opponentTurn') }}<MkEllipsis/></p>
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: anime-tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p>
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p>
<p class="result" v-if="game.isEnded && logPos == logs.length">
<template v-if="game.winner">
<Mfm :key="'won'" :text="$t('_reversi.won', { name: game.winner.name })" :plain="true" :custom-emojis="game.winner.emojis"/>
@ -57,17 +57,18 @@
<p class="status"><b>{{ $t('_reversi.turnCount', { count: logPos }) }}</b> {{ $t('_reversi.black') }}:{{ o.blackCount }} {{ $t('_reversi.white') }}:{{ o.whiteCount }} {{ $t('_reversi.total') }}:{{ o.blackCount + o.whiteCount }}</p>
<div class="actions" v-if="!game.isEnded && iAmPlayer">
<MkButton @click="surrender">{{ $t('_reversi.surrender') }}</MkButton>
<MkButton @click="surrender" inline>{{ $t('_reversi.surrender') }}</MkButton>
</div>
<div class="player" v-if="game.isEnded">
<span>{{ logPos }} / {{ logs.length }}</span>
<!-- TODO <ui-horizon-group> -->
<MkButton @click="logPos = 0" :disabled="logPos == 0"><fa :icon="faAngleDoubleLeft"/></MkButton>
<MkButton @click="logPos--" :disabled="logPos == 0"><fa :icon="faAngleLeft"/></MkButton>
<MkButton @click="logPos++" :disabled="logPos == logs.length"><fa :icon="faAngleRight"/></MkButton>
<MkButton @click="logPos = logs.length" :disabled="logPos == logs.length"><fa :icon="faAngleDoubleRight"/></MkButton>
<!-- TODO </ui-horizon-group> -->
<div class="buttons" v-if="!autoplaying">
<MkButton inline @click="logPos = 0" :disabled="logPos == 0"><fa :icon="faAngleDoubleLeft"/></MkButton>
<MkButton inline @click="logPos--" :disabled="logPos == 0"><fa :icon="faAngleLeft"/></MkButton>
<MkButton inline @click="logPos++" :disabled="logPos == logs.length"><fa :icon="faAngleRight"/></MkButton>
<MkButton inline @click="logPos = logs.length" :disabled="logPos == logs.length"><fa :icon="faAngleDoubleRight"/></MkButton>
</div>
<MkButton @click="autoplay()" :disabled="autoplaying" style="margin: var(--margin) auto 0 auto;"><fa :icon="faPlay"/></MkButton>
</div>
<div class="info">
@ -75,12 +76,16 @@
<p v-if="game.loopedBoard">{{ $t('_reversi.loopedMap') }}</p>
<p v-if="game.canPutEverywhere">{{ $t('_reversi.canPutEverywhere') }}</p>
</div>
<div class="watchers">
<MkAvatar v-for="user in watchers" :key="user.id" :user="user" class="avatar"/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons';
import { faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight, faPlay } from '@fortawesome/free-solid-svg-icons';
import { faCircle as fasCircle } from '@fortawesome/free-solid-svg-icons';
import { faCircle as farCircle } from '@fortawesome/free-regular-svg-icons';
import * as CRC32 from 'crc-32';
@ -112,8 +117,9 @@ export default defineComponent({
o: null as Reversi,
logs: [],
logPos: 0,
watchers: [],
pollingClock: null,
faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight, fasCircle, farCircle
faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight, fasCircle, farCircle, faPlay
};
},
@ -197,12 +203,14 @@ export default defineComponent({
this.connection.on('set', this.onSet);
this.connection.on('rescue', this.onRescue);
this.connection.on('ended', this.onEnded);
this.connection.on('watchers', this.onWatchers);
},
beforeUnmount() {
this.connection.off('set', this.onSet);
this.connection.off('rescue', this.onRescue);
this.connection.off('ended', this.onEnded);
this.connection.off('watchers', this.onWatchers);
clearInterval(this.pollingClock);
},
@ -308,11 +316,44 @@ export default defineComponent({
this.$forceUpdate();
},
onWatchers(users) {
this.watchers = users;
},
surrender() {
os.api('games/reversi/games/surrender', {
gameId: this.game.id
});
},
autoplay() {
this.autoplaying = true;
this.logPos = 0;
setTimeout(() => {
this.logPos = 1;
let i = 1;
let previousLog = this.game.logs[0];
const tick = () => {
const log = this.game.logs[i];
const time = new Date(log.at).getTime() - new Date(previousLog.at).getTime()
setTimeout(() => {
i++;
this.logPos++;
previousLog = log;
if (i < this.game.logs.length) {
tick();
} else {
this.autoplaying = false;
}
}, time);
};
tick();
}, 1000);
}
}
});
</script>
@ -467,6 +508,27 @@ export default defineComponent({
margin: 0 8px;
min-width: 70px;
}
> .buttons {
display: flex;
> * {
flex: 1;
}
}
}
> .watchers {
padding: 0 0 16px 0;
&:empty {
display: none;
}
> .avatar {
width: 32px;
height: 32px;
}
}
}
</style>

View File

@ -27,10 +27,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('_reversi.reversi'),
icon: faGamepad
}]
title: this.$t('_reversi.reversi'),
icon: faGamepad
},
game: null,
connection: null,

View File

@ -76,10 +76,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('_reversi.reversi'),
icon: faGamepad
}]
title: this.$t('_reversi.reversi'),
icon: faGamepad
},
games: [],
gamesFetching: true,

View File

@ -82,10 +82,8 @@ export default defineComponent({
data() {
return {
INFO: computed(() => this.user ? {
header: [{
title: this.$t('room'),
avatar: this.user,
}],
title: this.$t('room'),
avatar: this.user,
} : null),
user: null,
objectSelected: false,

View File

@ -44,10 +44,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('scratchpad'),
icon: faTerminal,
}],
title: this.$t('scratchpad'),
icon: faTerminal,
},
code: '',
logs: [],

View File

@ -20,10 +20,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('searchWith', { q: this.$route.query.q }),
icon: faSearch
}],
title: this.$t('searchWith', { q: this.$route.query.q }),
icon: faSearch
},
pagination: {
endpoint: 'notes/search',

View File

@ -28,10 +28,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: 'API',
icon: faKey
}]
title: 'API',
icon: faKey
},
isDesktop: window.innerWidth >= 1100,
};
@ -42,8 +40,8 @@ export default defineComponent({
},
methods: {
async generateToken() {
os.popup(await import('@/components/token-generate-window.vue'), {}, {
generateToken() {
os.popup(import('@/components/token-generate-window.vue'), {}, {
done: async result => {
const { name, permissions } = result;
const { token } = await os.api('miauth/gen-token', {

View File

@ -107,10 +107,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('general'),
icon: faCogs
}]
title: this.$t('general'),
icon: faCogs
},
langs,
lang: localStorage.getItem('lang'),

View File

@ -55,10 +55,8 @@ export default defineComponent({
setup(props, context) {
const INFO = ref({
header: [{
title: i18n.global.t('settings'),
icon: faCog
}]
title: i18n.global.t('settings'),
icon: faCog
});
const narrow = ref(false);
const view = ref(null);

View File

@ -41,10 +41,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('integration'),
icon: faShareAlt
}]
title: this.$t('integration'),
icon: faShareAlt
},
apiUrl,
twitterForm: null,

View File

@ -49,10 +49,8 @@ export default defineComponent({
data() {
return {
INFO: {
header: [{
title: this.$t('muteAndBlock'),
icon: faBan
}]
title: this.$t('muteAndBlock'),
icon: faBan
},
tab: 'mute',
mutingPagination: {

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