Compare commits

..

76 Commits

Author SHA1 Message Date
ade5055bc3 10.61.0 2018-12-04 01:37:05 +09:00
6e343d50f1 [MFM] Implement strike syntax
Resolve #3485
2018-12-04 01:28:21 +09:00
ce3f735654 Fix bug 2018-12-04 01:07:26 +09:00
9b5e623130 🎨 2018-12-04 01:04:53 +09:00
f0b0c5b540 🎨
Add ripple effect
2018-12-04 01:02:19 +09:00
227798300f Improve widget paging looks (#3482)
* Improve widget paging looks

* rewind when error
2018-12-03 23:14:10 +09:00
2ab8a5bc0a 10.60.4 2018-12-03 20:27:47 +09:00
c222b9ae94 Update init.ts 2018-12-03 20:26:46 +09:00
53a0f3c794 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-12-03 20:26:38 +09:00
9ff349c548 Update post-form.vue 2018-12-03 20:21:05 +09:00
0935bd4bd4 Resolve #3281 (#3479) 2018-12-03 20:11:18 +09:00
45bee7cc2f Resolve #327 2018-12-03 20:08:18 +09:00
1c86a4bc26 Refactor 2018-12-03 19:44:03 +09:00
b385cf2a9f 10.60.3 2018-12-03 09:54:14 +09:00
40d3dc454d Merge pull request #3480 from syuilo/l10n_develop
New Crowdin translations
2018-12-03 09:53:40 +09:00
8e92848495 New translations ja-JP.yml (Korean) 2018-12-03 09:52:19 +09:00
2d94a22a30 New translations ja-JP.yml (French) 2018-12-03 09:52:15 +09:00
7a5a091c25 New translations ja-JP.yml (English) 2018-12-03 09:52:08 +09:00
2baf810c71 New translations ja-JP.yml (Chinese Simplified) 2018-12-03 09:52:01 +09:00
d1ecef13ef New translations ja-JP.yml (Norwegian) 2018-12-03 09:43:22 +09:00
495fa553ad New translations ja-JP.yml (Dutch) 2018-12-03 09:43:16 +09:00
854e649ea6 New translations ja-JP.yml (Japanese, Kansai) 2018-12-03 09:43:11 +09:00
c047324b42 🎨 2018-12-03 09:43:07 +09:00
daac865c72 New translations ja-JP.yml (Spanish) 2018-12-03 09:43:07 +09:00
63d059b8d1 New translations ja-JP.yml (Russian) 2018-12-03 09:43:01 +09:00
e3075a0dc7 New translations ja-JP.yml (Portuguese) 2018-12-03 09:42:57 +09:00
6b6e597b95 New translations ja-JP.yml (Polish) 2018-12-03 09:42:51 +09:00
eb0eadad5e New translations ja-JP.yml (Korean) 2018-12-03 09:42:46 +09:00
f600fee16d New translations ja-JP.yml (Italian) 2018-12-03 09:42:40 +09:00
7b88c54aa6 New translations ja-JP.yml (German) 2018-12-03 09:42:34 +09:00
623dd57cc3 New translations ja-JP.yml (French) 2018-12-03 09:42:27 +09:00
f6edd33adb New translations ja-JP.yml (English) 2018-12-03 09:42:23 +09:00
ac20d73222 New translations ja-JP.yml (Chinese Simplified) 2018-12-03 09:42:19 +09:00
c59374d79d New translations ja-JP.yml (Catalan) 2018-12-03 09:42:13 +09:00
0d478046de Improve usability 2018-12-03 09:41:22 +09:00
f3479d1b98 Refactor 2018-12-03 09:38:43 +09:00
2fdecb8a38 🎨 2018-12-03 09:14:17 +09:00
a95c3ee557 New translations ja-JP.yml (Korean) 2018-12-03 08:12:01 +09:00
67c439c70a New translations ja-JP.yml (French) 2018-12-03 03:01:46 +09:00
b96037cffa New translations ja-JP.yml (Chinese Simplified) 2018-12-03 00:23:03 +09:00
ebd8d34552 New translations ja-JP.yml (Chinese Simplified) 2018-12-03 00:13:13 +09:00
a653d9a83e New translations ja-JP.yml (Chinese Simplified) 2018-12-03 00:11:54 +09:00
07d6894c42 Clean up 2018-12-02 23:00:06 +09:00
03588b3fd6 Merge if-statements (#3478) 2018-12-02 22:32:09 +09:00
2e83440e70 10.60.2 2018-12-02 21:20:36 +09:00
2633873fcc Fix syntax error (#3477)
src/remote/activitypub/models/person.ts(326,4): error TS1005: ',' expected.
2018-12-02 21:19:28 +09:00
5f33713f53 10.60.1 2018-12-02 21:08:20 +09:00
fe84c5010c Merge pull request #3458 from syuilo/l10n_develop
New Crowdin translations
2018-12-02 20:43:52 +09:00
7f39df0713 New translations ja-JP.yml (English) 2018-12-02 20:43:12 +09:00
928d359dd2 Use takeWhile instead of some (#3475) 2018-12-02 20:28:22 +09:00
184eb00133 Remove self-assignment (#3476) 2018-12-02 20:26:15 +09:00
e264a49b08 [Client] Resolve #2596 2018-12-02 20:24:38 +09:00
8caf853c80 Merge branches 'develop', 'develop' and 'develop' of https://github.com/syuilo/misskey into develop 2018-12-02 20:11:03 +09:00
b451c04787 Use primitive type boolean (#3474) 2018-12-02 20:10:56 +09:00
1653977392 Improve input dialog 2018-12-02 20:10:53 +09:00
a0d9def98a Simplify expressions (#3473) 2018-12-02 19:35:41 +09:00
92701e5cec Fix #3445 (#3471) 2018-12-02 19:24:57 +09:00
0b6b6a4f2f Remove unneccesary casts 2018-12-02 19:05:08 +09:00
3a2dc95850 No MFM parsing when remote note (#3470)
* Use tag for hashtag detection of remote note

* No MFM parsing when remote note
2018-12-02 18:05:33 +09:00
37fc3103f6 New translations ja-JP.yml (Norwegian) 2018-12-02 15:33:32 +09:00
b7bd1ff69f New translations ja-JP.yml (Dutch) 2018-12-02 15:33:28 +09:00
dc36134f10 New translations ja-JP.yml (Japanese, Kansai) 2018-12-02 15:33:22 +09:00
fea8821091 New translations ja-JP.yml (Spanish) 2018-12-02 15:33:17 +09:00
33faf40aca New translations ja-JP.yml (Russian) 2018-12-02 15:33:12 +09:00
4410f8d7f7 New translations ja-JP.yml (Portuguese) 2018-12-02 15:33:08 +09:00
3e6029e69d New translations ja-JP.yml (Polish) 2018-12-02 15:33:04 +09:00
96c7707e6c New translations ja-JP.yml (Korean) 2018-12-02 15:32:59 +09:00
d8e545db3c New translations ja-JP.yml (Italian) 2018-12-02 15:32:54 +09:00
a9a6ba0aed New translations ja-JP.yml (German) 2018-12-02 15:32:50 +09:00
a898c6ceab New translations ja-JP.yml (French) 2018-12-02 15:32:44 +09:00
0205c5c2d7 New translations ja-JP.yml (English) 2018-12-02 15:32:38 +09:00
f8074ab74b New translations ja-JP.yml (Chinese Simplified) 2018-12-02 15:32:34 +09:00
f15c491d5f New translations ja-JP.yml (Catalan) 2018-12-02 15:32:29 +09:00
381f2b7fdf New translations ja-JP.yml (French) 2018-12-02 05:12:02 +09:00
1c3c733c6b New translations ja-JP.yml (French) 2018-12-02 05:02:46 +09:00
9dbc9115c9 New translations ja-JP.yml (English) 2018-12-01 12:51:44 +09:00
77 changed files with 831 additions and 937 deletions

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近の投稿"
images: "画像"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert."
volume: "Lautstärke"
test: "Test"
language: "Sprache"
pick-language: "Sprache auswählen"
recommended: "Empfohlen"
auto: "Automatisch"
specify-language: "Sprache auswählen"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "Der Cache deines Benutzerkontos (Info, Beiträge, Antworten, Direktnachrichten, Einstellungen), die lokal im Browser gespeichert sind werden gelöscht.\nDu musst die Seite aktualisieren nachdem du aufgeräumt hast."
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "Sprache auswählen"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近の投稿"
images: "画像"

View File

@ -26,7 +26,7 @@ common:
close: "Close"
do-not-copy-paste: "Please do not enter or paste the code here. Account may be compromised."
load-more: "Load more"
enter-password: "パスワードを入力してください"
enter-password: "Please enter the Password"
got-it: "Got it!"
customization-tips:
title: "Customization tips"
@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{} users mentioned"
empty: "No popular hashtag trends"
common/views/components/language-settings.vue:
title: "Display Language"
pick-language: "Select a language"
recommended: "Recommended"
auto: "Auto"
specify-language: "Specify language"
info: "You need to reload the page for the changes to take effect."
common/views/components/profile-editor.vue:
title: "Profile"
name: "Name"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "Play a sound when you receive a post/message. This setting is stored in the browser."
volume: "Volume"
test: "Test"
language: "Language"
pick-language: "Select a language"
recommended: "Recommended"
auto: "Automatic"
specify-language: "Specify language"
language-desc: "You need to reload the page for the changes to take effect."
cache: "Cache"
clean-cache: "Clear cache"
cache-warn: "The cache of account info/posts/replies/messages/settings stored in the browser will be deleted. You need to reload the page after cleaning up."
@ -1008,8 +1009,8 @@ admin/views/instance.vue:
email-config-info: "Used to confirm email and password reset etc."
enable-email: "Enable email delivery"
email: "Email Address"
smtp-secure: "SMTP接続に暗黙的なSSL/TLSを使用する"
smtp-secure-info: "STARTTLS使用時はオフにします。"
smtp-secure: "Use implicit SSL/TLS in the SMTP connection"
smtp-secure-info: "Turn off STARTTLS when used that."
smtp-host: "SMTP Host"
smtp-port: "SMTP Port"
smtp-user: "SMTP User"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "Choose files"
mobile/views/pages/settings.vue:
signed-in-as: "Signed in as {}"
lang: "Language"
lang-tip: "You will need to reload the page for the changes to take effect."
recommended: "Recommended"
auto: "Auto"
specify-language: "Select your language"
design: "Design and display"
dark-mode: "Dark Mode"
i-am-under-limited-internet: "I'm in limited bandwidth"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "Block"
unblock: "Unblock"
years-old: "{age} years old"
push-to-list: "Add to list"
select-list: "Select a list"
list-pushed: "Successfully added {user} to {list}."
mobile/views/pages/user/home.vue:
recent-notes: "Recent notes"
images: "Images"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近の投稿"
images: "画像"

View File

@ -26,7 +26,7 @@ common:
close: "Fermer"
do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis."
load-more: "Charger plus"
enter-password: "パスワードを入力してください"
enter-password: "Veuillez entrer le mot de passe"
got-it: "Jai compris !"
customization-tips:
title: "Conseils de personnalisation"
@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{} utilisateurs·rices mentionnés·es"
empty: "Aucune tendance"
common/views/components/language-settings.vue:
title: "Langue "
pick-language: "Sélectionner une langue"
recommended: "Recommandé"
auto: "Automatique"
specify-language: "Spécifier la langue"
info: "Le rechargement de la page est requis afin d'appliquer les modifications."
common/views/components/profile-editor.vue:
title: "Profil"
name: "Nom"
@ -458,10 +465,10 @@ common/views/components/profile-editor.vue:
saved: "Profil mis à jour avec succès"
uploading: "En cours d'envoi …"
upload-failed: "Échec de l'envoi"
email: "メール設定"
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
email: "Paramètres de messagerie"
email-address: "Adresse de courrier électronique"
email-verified: "Ladresse du courrier électronique a été vérifiée."
email-not-verified: "Adresse de courriel nest pas confirmée. Veuillez vérifier votre boite de réception."
common/views/widgets/broadcast.vue:
fetching: "Récupération"
no-broadcasts: "Aucune annonce"
@ -736,8 +743,8 @@ desktop/views/components/settings.vue:
note-visibility: "Visibilité de la publication"
default-note-visibility: "Visibilité par défaut"
remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
web-search-engine: "ウェブ検索エンジン"
web-search-engine-desc: ": https://www.google.com/?#q={{query}}"
web-search-engine: "Moteur de recherche Web"
web-search-engine-desc: "Exemple: https://www.google.com/?#q={{query}}"
auto-popout: "Fenêtre contextuelle automatique"
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
advanced: "Paramètres avancés"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur."
volume: "Volume"
test: "Test"
language: "Langue"
pick-language: "Sélectionner une langue"
recommended: "Recommandé"
auto: "Automatique"
specify-language: "Spécifier la langue"
language-desc: "Le rechargement de la page est requis afin d'appliquer les modifications."
cache: "Cache"
clean-cache: "Nettoyage"
cache-warn: "Le nettoyage du cache du compte supprime les informations stockées dans le navigateur comme les messages, les réponses ainsi que dautres données (y compris les paramètres de configuration). Après le nettoyage, vous devez recharger la page."
@ -1004,16 +1005,16 @@ admin/views/instance.vue:
external-user-recommendation-engine-desc: "Exemple: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "Délai dexpiration"
external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)"
email-config: "メールサーバーの設定"
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
enable-email: "メール配信を有効にする"
email: "メールアドレス"
smtp-secure: "SMTP接続に暗黙的なSSL/TLSを使用する"
smtp-secure-info: "STARTTLS使用時はオフにします。"
smtp-host: "SMTPホスト"
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
email-config: "Paramètres du serveur de messagerie"
email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe."
enable-email: "Activation de la distribution du courrier"
email: "Adresse de courrier électronique"
smtp-secure: "Utiliser SSL/TLS implicitement dans la connexion SMTP"
smtp-secure-info: "Désactiver STARTTLS lorsque celui-ci est utilisé."
smtp-host: "Hôte SMTP"
smtp-port: "Port SMTP"
smtp-user: "Utilisateur SMTP"
smtp-pass: "Mot de passe SMTP"
admin/views/charts.vue:
title: "Graph"
per-day: "par jour"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "Choisissez un fichier"
mobile/views/pages/settings.vue:
signed-in-as: "Connecté·e en tant que {}"
lang: "Langue"
lang-tip: "Le rechargement de la page est requis afin d'appliquer les modifications."
recommended: "Recommandé"
auto: "Automatique"
specify-language: "Sélectionnez votre langue"
design: "Affichage et design"
dark-mode: "Mode nuit"
i-am-under-limited-internet: "J'ai un accès Internet limité"
@ -1388,8 +1384,8 @@ mobile/views/pages/settings.vue:
note-visibility: "Visibilité de la publication"
default-note-visibility: "Visibilité par défaut"
remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
web-search-engine: "ウェブ検索エンジン"
web-search-engine-desc: ": https://www.google.com/?#q={{query}}"
web-search-engine: "Moteur de recherche Web"
web-search-engine-desc: "Exemple: https://www.google.com/?#q={{query}}"
disable-via-mobile: "Ne pas mentionner que ma publication provient d'un 'périphérique mobile'"
load-raw-images: "Afficher les photos jointes en haute qualité"
load-remote-media: "Afficher les médias sur le serveur distant"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "Bloquer"
unblock: "Débloquer"
years-old: "{age} ans"
push-to-list: "Ajouter à la liste"
select-list: "Sélectionnez une liste"
list-pushed: "Vous avez ajouté {user} à la liste {list} avec succès."
mobile/views/pages/user/home.vue:
recent-notes: "Notes récentes"
images: "Images"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近の投稿"
images: "画像"

View File

@ -440,13 +440,11 @@ common/views/components/stream-indicator.vue:
reconnecting: "再接続中"
connected: "接続完了"
common/views/components/twitter-setting.vue:
description: "お使いのTwitterアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでTwitterアカウント情報が表示されるようになったり、Twitterを用いた便利なサインインを利用できるようになります。"
connected-to: "次のTwitterアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "Twitterと接続する"
common/views/components/integration-settings.vue:
title: "サービス連携"
connect: "接続する"
disconnect: "切断する"
connected-to: "次のアカウントに接続されています"
common/views/components/github-setting.vue:
description: "お使いのGitHubアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでGitHubアカウント情報が表示されるようになったり、GitHubを用いた便利なサインインを利用できるようになります。"
@ -485,12 +483,21 @@ common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
account: "アカウント"
location: "場所"
description: "自己紹介"
language: "言語"
birthday: "誕生日"
avatar: "アイコン"
banner: "バナー"
@ -870,13 +877,6 @@ desktop/views/components/settings.vue:
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1554,11 +1554,6 @@ mobile/views/pages/selectdrive.vue:
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1586,18 +1581,6 @@ mobile/views/pages/settings.vue:
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
load-raw-images: "添付された画像を高画質で表示する"
load-remote-media: "リモートサーバーのメディアを表示する"
twitter: "Twitter連携"
twitter-connect: "Twitterアカウントに接続する"
twitter-reconnect: "再接続する"
twitter-disconnect: "切断する"
github: "GitHub連携"
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
discord: "Discord連携"
discord-connect: "Discordアカウントに接続する"
discord-reconnect: "再接続する"
discord-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "流行は自分で作るんや"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージもろたとき、音鳴らしたるわ。大丈夫や、この設定はブラウザが覚えてくれとる。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語選んでや"
recommended: "おすすめ"
auto: "自動"
specify-language: "言語選んでくれ"
language-desc: "変更はページの再度読み込み後に反映されんで。"
cache: "キャッシュ"
clean-cache: "お掃除"
cache-warn: "お掃除するとな、ブラウザが覚えてくれとるアカウントのあれこれや書きかけの投稿・返信・メッセージや設定情報なんかのデータが全部飛んでいくんや。これやったらページ再読込しといてな。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイル選んでや"
mobile/views/pages/settings.vue:
signed-in-as: "あんたは橋の下で拾った{}や!"
lang: "言語"
lang-tip: "ページもっぺん読み込んだら反映したるで。"
recommended: "これええで"
auto: "勝手にやる"
specify-language: "言語選びや"
design: "見た感じ"
dark-mode: "ナイトゲームや!"
i-am-under-limited-internet: "電波と阪神がザコいんや"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロックやめたる"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近儲かりまっか?"
images: "画像"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}명이 언급함"
empty: "트렌드 없음"
common/views/components/language-settings.vue:
title: "표시 언어"
pick-language: "언어 설정"
recommended: "추천"
auto: "자동"
specify-language: "언어 지정"
info: "변경사항은 페이지를 새로고침한 뒤에 반영됩니다."
common/views/components/profile-editor.vue:
title: "프로필"
name: "이름"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "글이나 메시지를 송수신하였을 때 소리를 재생합니다. 이 설정은 브라우저에 저장됩니다."
volume: "음량"
test: "테스트"
language: "언어"
pick-language: "언어 설정"
recommended: "추천"
auto: "자동"
specify-language: "언어 지정"
language-desc: "변경사항은 페이지를 새로고침한 뒤에 반영됩니다."
cache: "캐시"
clean-cache: "지우기"
cache-warn: "지우기를 실행하면 브라우저에 저장된 계정 정보 캐시, 글이나 답글 및 메시지의 임시 저장, 그 외 데이터 (설정 정보 포함) 가 삭제 됩니다. 지우기 작업을 수행한 후 페이지를 다시 로드해야 합니다."
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "파일 선택"
mobile/views/pages/settings.vue:
signed-in-as: "{}(으)로 로그인"
lang: "언어"
lang-tip: "변경사항은 페이지를 새로고침한 뒤에 반영됩니다."
recommended: "추천"
auto: "자동"
specify-language: "언어 지정"
design: "디자인 및 표시"
dark-mode: "다크 모드"
i-am-under-limited-internet: "저는 통신 대역폭이 제한되어 있습니다"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "차단"
unblock: "차단 해제"
years-old: "{age}세"
push-to-list: "리스트에 추가"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "최근 글"
images: "이미지"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "Een geluid afspelen bij het ontvangen van een bericht. Deze instelling wordt opgeslagen in je browser."
volume: "Volume"
test: "Testen"
language: "Taal"
pick-language: "Selecteer een taal"
recommended: "Aanbevolen"
auto: "Automatisch"
specify-language: "Taal opgeven"
language-desc: "Je moet de pagina herladen om de wijzigingen toe te passen."
cache: "Cache"
clean-cache: "Opschonen"
cache-warn: "De cache van je accountinformatie/berichten/antwoorden/instellingen wordt verwijderd. Je moet de pagina herladen na het opschonen."
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "Kies een bestand"
mobile/views/pages/settings.vue:
signed-in-as: "Ingelogd als {}"
lang: "Taal"
lang-tip: "Je moet de pagina herladen om de wijzigingen toe te passen."
recommended: "Aanbevolen"
auto: "Automatisch"
specify-language: "Taal opgeven"
design: "Ontwerp en weergave"
dark-mode: "Donkere modus"
i-am-under-limited-internet: "Ik heb beperkt internet"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "Recente notities"
images: "Afbeeldingen"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "Volum"
test: "Test"
language: "Språk"
pick-language: "Velg språk"
recommended: "Anbefalt"
auto: "Automatisk"
specify-language: "Angi språk"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "Hurtiglager"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "Språk"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "Anbefalt"
auto: "Automatisk"
specify-language: "Angi språk"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "Nylige innlegg"
images: "Bilder"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "Odtwarzaj dźwięk przy wstawianiu wpisów, wysyłaniu lub otrzymywaniu wiadomości. Opcja ta jest zapamiętywana przez przeglądarkę."
volume: "Głośność"
test: "Test"
language: "Język"
pick-language: "Wybierz język"
recommended: "Zalecane"
auto: "Automatycznie"
specify-language: "Wybierz język"
language-desc: "Aby zmiany zostały uwzględnione, odśwież stronę."
cache: "Pamięć podręczna"
clean-cache: "Wyczyść"
cache-warn: "Pamięć podręczna informacji o koncie/wpisów/odpowiedzi/wiadomości/ustawień przechowywanych w przeglądarce zostanie usunięta. Będziesz musiał odświeżyć stronę po wyczyszczeniu."
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "Wybierz plik"
mobile/views/pages/settings.vue:
signed-in-as: "Zalogowany jako {}"
lang: "Język"
lang-tip: "Aby zmiany zostały uwzględnione, odśwież stronę."
recommended: "Zalecany"
auto: "Automatycznie"
specify-language: "Wybierz język"
design: "Wygląd i wyświetlanie"
dark-mode: "Tryb ciemny"
i-am-under-limited-internet: "Ograniczaj zużycie transferu"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age} lat"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "Ostatnie wpisy"
images: "Zdjęcia"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "Notas recentes"
images: "Imagens"

View File

@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/components/language-settings.vue:
title: "表示言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
info: "変更はページの再度読み込み後に反映されます。"
common/views/components/profile-editor.vue:
title: "プロフィール"
name: "名前"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
volume: "ボリューム"
test: "テスト"
language: "言語"
pick-language: "言語を選択"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
language-desc: "変更はページの再度読み込み後に反映されます。"
cache: "キャッシュ"
clean-cache: "クリーンアップ"
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "ファイルを選択"
mobile/views/pages/settings.vue:
signed-in-as: "{}としてサインイン中"
lang: "言語"
lang-tip: "変更はページの再読み込み後に反映されます。"
recommended: "推奨"
auto: "自動"
specify-language: "言語を指定"
design: "デザインと表示"
dark-mode: "ダークモード"
i-am-under-limited-internet: "私は通信を制限されている"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "ブロック"
unblock: "ブロック解除"
years-old: "{age}歳"
push-to-list: "リストに追加"
select-list: "リストを選択してください"
list-pushed: "{user}を{list}に追加しました"
mobile/views/pages/user/home.vue:
recent-notes: "最近の投稿"
images: "画像"

View File

@ -26,7 +26,7 @@ common:
close: "关闭"
do-not-copy-paste: "请不要在这里输入或粘贴代码。您帐户可能会受到损害。"
load-more: "加载更多"
enter-password: "パスワードを入力してください"
enter-password: "请输入您的密码"
got-it: "没问题"
customization-tips:
title: "客制化提示"
@ -439,6 +439,13 @@ common/views/components/visibility-chooser.vue:
common/views/components/trends.vue:
count: "{} 被提到"
empty: "没有流行的标签"
common/views/components/language-settings.vue:
title: "显示语言"
pick-language: "选择一个语言"
recommended: "推荐"
auto: "自动"
specify-language: "指定语言"
info: "你需要刷新这个页面来应用更改。"
common/views/components/profile-editor.vue:
title: "简况"
name: "名称"
@ -458,10 +465,10 @@ common/views/components/profile-editor.vue:
saved: "更新配置文件成功"
uploading: "正在上传"
upload-failed: "上传失败"
email: "メール設定"
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
email: "邮件设置"
email-address: "电子邮件地址"
email-verified: "电子邮件地址已验证"
email-not-verified: "电子邮件地址还没有验证哦, 请检查一下收信箱吧~"
common/views/widgets/broadcast.vue:
fetching: "确认中"
no-broadcasts: "没有公告"
@ -736,8 +743,8 @@ desktop/views/components/settings.vue:
note-visibility: "帖子可见性"
default-note-visibility: "默认可见性"
remember-note-visibility: "记住帖子可见性"
web-search-engine: "ウェブ検索エンジン"
web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
web-search-engine: "搜索引擎"
web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
auto-popout: "自动弹出窗口"
auto-popout-desc: "如果可用,将使用弹出显示而不是打开新窗口。 此设置存储在浏览器中。"
advanced: "更多设置"
@ -774,12 +781,6 @@ desktop/views/components/settings.vue:
enable-sounds-desc: "收到帖子/留言时播放声音。 此设置将被存储在浏览器中。"
volume: "音量"
test: "测试"
language: "语言"
pick-language: "选择一个语言"
recommended: "推荐"
auto: "自动"
specify-language: "指定语言"
language-desc: "你需要刷新这个页面来应用更改。"
cache: "缓存"
clean-cache: "清除缓存"
cache-warn: "将删除存储在浏览器中的帐户信息/帖子/回复/消息/设置的缓存。 清理完毕后需要刷新页面。"
@ -1004,16 +1005,16 @@ admin/views/instance.vue:
external-user-recommendation-engine-desc: "例如: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "超时"
external-user-recommendation-timeout-desc: "单位为毫秒 (例如300000)"
email-config: "メールサーバーの設定"
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
enable-email: "メール配信を有効にする"
email: "メールアドレス"
smtp-secure: "SMTP接続に暗黙的なSSL/TLSを使用する"
smtp-secure-info: "STARTTLS使用時はオフにします。"
smtp-host: "SMTPホスト"
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
email-config: "电子邮件服务器设置"
email-config-info: "用于确认电子邮件和密码重置等。"
enable-email: "启用电子邮件送递"
email: "电子邮件地址"
smtp-secure: "SMTP 连接中使用隐式 SSL / TLS"
smtp-secure-info: "使用时关闭 STARTTLS。"
smtp-host: "SMTP 服务器地址 (主机名)"
smtp-port: "SMTP 端口"
smtp-user: "SMTP 用户名"
smtp-pass: "SMTP 密码"
admin/views/charts.vue:
title: "历史记录"
per-day: "每天"
@ -1361,11 +1362,6 @@ mobile/views/pages/selectdrive.vue:
select-file: "选择文件"
mobile/views/pages/settings.vue:
signed-in-as: "以{}登录"
lang: "语言"
lang-tip: "你需要刷新这个页面来应用更改。"
recommended: "推荐"
auto: "自动"
specify-language: "选择语言"
design: "设计与展示"
dark-mode: "夜间模式"
i-am-under-limited-internet: "我的带宽有限"
@ -1388,8 +1384,8 @@ mobile/views/pages/settings.vue:
note-visibility: "帖子可见性"
default-note-visibility: "默认可见性"
remember-note-visibility: "记住帖子可见性"
web-search-engine: "ウェブ検索エンジン"
web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
web-search-engine: "搜索引擎"
web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
disable-via-mobile: "不要将帖子标记为“来自手机”"
load-raw-images: "以原始质量显示附加图像"
load-remote-media: "显示来自远程服务器的媒体"
@ -1434,6 +1430,9 @@ mobile/views/pages/user.vue:
block: "屏蔽"
unblock: "取消屏蔽"
years-old: "{age}岁"
push-to-list: "添加至列表"
select-list: "选择一个列表"
list-pushed: "成功添加{user}到{list}"
mobile/views/pages/user/home.vue:
recent-notes: "最近的帖子"
images: "图片"

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.60.0",
"clientVersion": "2.0.12331",
"version": "10.61.0",
"clientVersion": "2.0.12407",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@ -156,6 +156,7 @@
"koa-send": "5.0.0",
"koa-slow": "2.1.0",
"koa-views": "6.1.4",
"langmap": "0.0.16",
"loader-utils": "1.1.0",
"minio": "7.0.1",
"mkdirp": "0.5.1",

View File

@ -52,8 +52,8 @@ export default Vue.extend({
type: 'warning',
text: this.$t('_remove.are-you-sure').replace('$1', this.announcements.find((_, j) => j == i).title),
showCancelButton: true
}).then(res => {
if (!res) return;
}).then(({ canceled }) => {
if (canceled) return;
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save(true);
this.$root.dialog({

View File

@ -120,8 +120,8 @@ export default Vue.extend({
type: 'warning',
text: this.$t('remove-emoji.are-you-sure').replace('$1', emoji.name),
showCancelButton: true
}).then(res => {
if (!res) return;
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('admin/emoji/remove', {
id: emoji.id

View File

@ -50,10 +50,13 @@ export default Vue.extend({
methods: {
regenerateToken() {
this.$input({
this.$root.dialog({
title: this.$t('enter-password'),
type: 'password'
}).then(password => {
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
this.$root.api('i/regenerate_token', {
password: password
});

View File

@ -2,15 +2,17 @@
<div class="felqjxyj" :class="{ splash }">
<div class="bg" ref="bg" @click="onBgClick"></div>
<div class="main" ref="main">
<div class="icon" v-if="type" :class="type"><fa :icon="icon"/></div>
<div class="icon" v-if="!input && !select && !user" :class="type"><fa :icon="icon"/></div>
<header v-if="title" v-html="title"></header>
<div class="body" v-if="text" v-html="text"></div>
<ui-input v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></ui-input>
<ui-input v-if="user" v-model="userInputValue" autofocus @keydown="onInputKeydown"><span slot="prefix">@</span></ui-input>
<ui-select v-if="select" v-model="selectedValue">
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
</ui-select>
<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash">
<ui-button @click="ok" primary autofocus>OK</ui-button>
<ui-button @click="cancel" v-if="showCancelButton">Cancel</ui-button>
<ui-button @click="ok" primary :autofocus="!input && !select && !user">OK</ui-button>
<ui-button @click="cancel" v-if="showCancelButton || input || select || user">Cancel</ui-button>
</ui-horizon-group>
</div>
</div>
@ -20,6 +22,7 @@
import Vue from 'vue';
import * as anime from 'animejs';
import { faTimesCircle, faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
import parseAcct from "../../../../../misc/acct/parse";
export default Vue.extend({
props: {
@ -36,9 +39,15 @@ export default Vue.extend({
type: String,
required: false
},
input: {
required: false
},
select: {
required: false
},
user: {
required: false
},
showCancelButton: {
type: Boolean,
default: false
@ -51,6 +60,8 @@ export default Vue.extend({
data() {
return {
inputValue: this.input && this.input.default ? this.input.default : null,
userInputValue: null,
selectedValue: null
};
},
@ -94,10 +105,21 @@ export default Vue.extend({
},
methods: {
ok() {
const result = this.select ? this.selectedValue : true;
this.$emit('ok', result);
this.close();
async ok() {
if (this.user) {
const user = await this.$root.api('users/show', parseAcct(this.userInputValue));
if (user) {
this.$emit('ok', user);
this.close();
}
} else {
const result =
this.input ? this.inputValue :
this.select ? this.selectedValue :
true;
this.$emit('ok', result);
this.close();
}
},
cancel() {
@ -127,6 +149,14 @@ export default Vue.extend({
onBgClick() {
this.cancel();
},
onInputKeydown(e) {
if (e.which == 13) { // Enter
e.preventDefault();
e.stopPropagation();
this.ok();
}
}
}
});

View File

@ -1,64 +0,0 @@
<template>
<div class="mk-discord-setting">
<p>{{ $t('description') }}</p>
<p class="account" v-if="$store.state.i.discord" :title="`Discord ID: ${$store.state.i.discord.id}`">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<p>
<a :href="`${apiUrl}/connect/discord`" target="_blank" @click.prevent="connect">{{ $store.state.i.discord ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.discord"> or </span>
<a :href="`${apiUrl}/disconnect/discord`" target="_blank" v-if="$store.state.i.discord" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p>
<p class="id" v-if="$store.state.i.discord">Discord ID: {{ $store.state.i.discord.id }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/discord-setting.vue'),
data() {
return {
form: null,
apiUrl
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.discord && this.form)
this.form.close();
}, {
deep: true
});
},
methods: {
connect() {
this.form = window.open(apiUrl + '/connect/discord',
'discord_connect_window',
'height=570, width=520');
},
disconnect() {
window.open(apiUrl + '/disconnect/discord',
'discord_disconnect_window',
'height=570, width=520');
}
}
});
</script>
<style lang="stylus" scoped>
.mk-discord-setting
.account
border solid 1px #e1e8ed
border-radius 4px
padding 16px
a
font-weight bold
color inherit
.id
color #8899a6
</style>

View File

@ -99,23 +99,22 @@ export default Vue.extend({
this.$emit('go', game);
},
match() {
this.$input({
title: this.$t('enter-username')
}).then(username => {
this.$root.api('users/show', {
username
}).then(user => {
this.$root.api('games/reversi/match', {
userId: user.id
}).then(res => {
if (res == null) {
this.$emit('matching', user);
} else {
this.$emit('go', res);
}
});
});
async match() {
const { result: user } = await this.$root.dialog({
title: this.$t('enter-username'),
user: {
local: true
}
});
if (user == null) return;
this.$root.api('games/reversi/match', {
userId: user.id
}).then(res => {
if (res == null) {
this.$emit('matching', user);
} else {
this.$emit('go', res);
}
});
},

View File

@ -1,64 +0,0 @@
<template>
<div class="mk-github-setting">
<p>{{ $t('description') }}</p>
<p class="account" v-if="$store.state.i.github" :title="`GitHub ID: ${$store.state.i.github.id}`">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p>
<a :href="`${apiUrl}/connect/github`" target="_blank" @click.prevent="connect">{{ $store.state.i.github ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.github"> or </span>
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p>
<p class="id" v-if="$store.state.i.github">GitHub ID: {{ $store.state.i.github.id }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/github-setting.vue'),
data() {
return {
form: null,
apiUrl
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.github && this.form)
this.form.close();
}, {
deep: true
});
},
methods: {
connect() {
this.form = window.open(apiUrl + '/connect/github',
'github_connect_window',
'height=570, width=520');
},
disconnect() {
window.open(apiUrl + '/disconnect/github',
'github_disconnect_window',
'height=570, width=520');
}
}
});
</script>
<style lang="stylus" scoped>
.mk-github-setting
.account
border solid 1px #e1e8ed
border-radius 4px
padding 16px
a
font-weight bold
color inherit
.id
color #8899a6
</style>

View File

@ -0,0 +1,96 @@
<template>
<ui-card>
<div slot="title"><fa icon="share-alt"/> {{ $t('title') }}</div>
<section>
<header><fa :icon="['fab', 'twitter']"/> Twitter</header>
<p v-if="$store.state.i.twitter">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<ui-button v-if="$store.state.i.twitter" @click="disconnectTwitter">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectTwitter">{{ $t('connect') }}</ui-button>
</section>
<section>
<header><fa :icon="['fab', 'discord']"/> Discord</header>
<p v-if="$store.state.i.discord">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<ui-button v-if="$store.state.i.discord" @click="disconnectDiscord">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectDiscord">{{ $t('connect') }}</ui-button>
</section>
<section>
<header><fa :icon="['fab', 'github']"/> GitHub</header>
<p v-if="$store.state.i.github">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<ui-button v-if="$store.state.i.github" @click="disconnectGithub">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectGithub">{{ $t('connect') }}</ui-button>
</section>
</ui-card>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/integration-settings.vue'),
data() {
return {
apiUrl,
twitterForm: null,
discordForm: null,
githubForm: null,
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.twitter) {
if (this.twitterForm) this.twitterForm.close();
}
}, {
deep: true
});
},
methods: {
connectTwitter() {
this.twitterForm = window.open(apiUrl + '/connect/twitter',
'twitter_connect_window',
'height=570, width=520');
},
disconnectTwitter() {
window.open(apiUrl + '/disconnect/twitter',
'twitter_disconnect_window',
'height=570, width=520');
},
connectDiscord() {
this.discordForm = window.open(apiUrl + '/connect/discord',
'discord_connect_window',
'height=570, width=520');
},
disconnectDiscord() {
window.open(apiUrl + '/disconnect/discord',
'discord_disconnect_window',
'height=570, width=520');
},
connectGithub() {
this.githubForm = window.open(apiUrl + '/connect/github',
'github_connect_window',
'height=570, width=520');
},
disconnectGithub() {
window.open(apiUrl + '/disconnect/github',
'github_disconnect_window',
'height=570, width=520');
},
}
});
</script>
<style lang="stylus" scoped>
</style>

View File

@ -0,0 +1,54 @@
<template>
<ui-card>
<div slot="title"><fa icon="language"/> {{ $t('title') }}</div>
<section class="fit-top">
<ui-select v-model="lang" :placeholder="$t('pick-language')">
<optgroup :label="$t('recommended')">
<option value="">{{ $t('auto') }}</option>
</optgroup>
<optgroup :label="$t('specify-language')">
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
</optgroup>
</ui-select>
<ui-info>Current: <i>{{ currentLanguage }}</i></ui-info>
<ui-info warn>{{ $t('info') }}</ui-info>
</section>
</ui-card>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { langs } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/language-settings.vue'),
data() {
return {
langs,
currentLanguage: 'Unknown',
};
},
computed: {
lang: {
get() { return this.$store.state.device.lang; },
set(value) { this.$store.commit('device/set', { key: 'lang', value }); }
},
},
created() {
try {
const locale = JSON.parse(localStorage.getItem('locale') || "{}");
const localeKey = localStorage.getItem('localeKey');
this.currentLanguage = `${locale.meta.lang} (${localeKey})`;
} catch { }
},
methods: {
}
});
</script>

View File

@ -96,6 +96,10 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement('b', genEl(token.children))];
}
case 'strike': {
return [createElement('del', genEl(token.children))];
}
case 'big': {
bigCount++;
const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;

View File

@ -99,8 +99,8 @@ export default Vue.extend({
type: 'warning',
text: this.$t('delete-confirm'),
showCancelButton: true
}).then(res => {
if (!res) return;
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('notes/delete', {
noteId: this.note.id

View File

@ -11,34 +11,43 @@ import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('common/views/components/password-settings.vue'),
methods: {
reset() {
this.$input({
async reset() {
const { canceled: canceled1, result: currentPassword } = await this.$root.dialog({
title: this.$t('enter-current-password'),
type: 'password'
}).then(currentPassword => {
this.$input({
title: this.$t('enter-new-password'),
input: {
type: 'password'
}).then(newPassword => {
this.$input({
title: this.$t('enter-new-password-again'),
type: 'password'
}).then(newPassword2 => {
if (newPassword !== newPassword2) {
this.$root.dialog({
title: null,
text: this.$t('not-match')
});
return;
}
this.$root.api('i/change_password', {
currentPasword: currentPassword,
newPassword: newPassword
}).then(() => {
this.$notify(this.$t('changed'));
});
});
}
});
if (canceled1) return;
const { canceled: canceled2, result: newPassword } = await this.$root.dialog({
title: this.$t('enter-new-password'),
input: {
type: 'password'
}
});
if (canceled2) return;
const { canceled: canceled3, result: newPassword2 } = await this.$root.dialog({
title: this.$t('enter-new-password-again'),
input: {
type: 'password'
}
});
if (canceled3) return;
if (newPassword !== newPassword2) {
this.$root.dialog({
title: null,
text: this.$t('not-match')
});
return;
}
this.$root.api('i/change_password', {
currentPasword: currentPassword,
newPassword: newPassword
}).then(() => {
this.$notify(this.$t('changed'));
});
}
}

View File

@ -32,6 +32,12 @@
<span>{{ $t('description') }}</span>
</ui-textarea>
<ui-select v-model="lang">
<span slot="label">{{ $t('language') }}</span>
<span slot="icon"><fa icon="language"/></span>
<option v-for="lang in unique(Object.values(langmap).map(x => x.nativeName)).map(name => Object.keys(langmap).find(k => langmap[k].nativeName == name))" :value="lang" :key="lang">{{ langmap[lang].nativeName }}</option>
</ui-select>
<ui-input type="file" @change="onAvatarChange">
<span>{{ $t('avatar') }}</span>
<span slot="icon"><fa icon="image"/></span>
@ -87,12 +93,16 @@ import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, host } from '../../../config';
import { toUnicode } from 'punycode';
import langmap from 'langmap';
import { unique } from '../../../../../prelude/array';
export default Vue.extend({
i18n: i18n('common/views/components/profile-editor.vue'),
data() {
return {
unique,
langmap,
host: toUnicode(host),
enableEmail: false,
email: null,
@ -100,6 +110,7 @@ export default Vue.extend({
username: null,
location: null,
description: null,
lang: null,
birthday: null,
avatarId: null,
bannerId: null,
@ -137,6 +148,7 @@ export default Vue.extend({
this.username = this.$store.state.i.username;
this.location = this.$store.state.i.profile.location;
this.description = this.$store.state.i.description;
this.lang = this.$store.state.i.lang;
this.birthday = this.$store.state.i.profile.birthday;
this.avatarId = this.$store.state.i.avatarId;
this.bannerId = this.$store.state.i.bannerId;
@ -198,6 +210,7 @@ export default Vue.extend({
name: this.name || null,
location: this.location || null,
description: this.description || null,
lang: this.lang,
birthday: this.birthday || null,
avatarId: this.avatarId || undefined,
bannerId: this.bannerId || undefined,
@ -222,10 +235,13 @@ export default Vue.extend({
},
updateEmail() {
this.$input({
this.$root.dialog({
title: this.$t('@.enter-password'),
type: 'password'
}).then(password => {
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
this.$root.api('i/update_email', {
password: password,
email: this.email == '' ? null : this.email

View File

@ -1,65 +0,0 @@
<template>
<div class="mk-twitter-setting">
<p>{{ $t('description') }}</p>
<p class="account" v-if="$store.state.i.twitter" :title="`Twitter ID: ${$store.state.i.twitter.userId}`">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ $store.state.i.twitter ? this.$t('reconnect') : this.$t('connect') }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter" @click.prevent="disconnect">{{ $t('disconnect') }}</a>
</p>
<p class="id" v-if="$store.state.i.twitter">Twitter ID: {{ $store.state.i.twitter.userId }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl } from '../../../config';
export default Vue.extend({
i18n: i18n('common/views/components/twitter-setting.vue'),
data() {
return {
form: null,
apiUrl
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.twitter) {
if (this.form) this.form.close();
}
}, {
deep: true
});
},
methods: {
connect() {
this.form = window.open(apiUrl + '/connect/twitter',
'twitter_connect_window',
'height=570, width=520');
},
disconnect() {
window.open(apiUrl + '/disconnect/twitter',
'twitter_disconnect_window',
'height=570, width=520');
}
}
});
</script>
<style lang="stylus" scoped>
.mk-twitter-setting
.account
border solid 1px #e1e8ed
border-radius 4px
padding 16px
a
font-weight bold
color inherit
.id
color #8899a6
</style>

View File

@ -4,8 +4,12 @@
:class="[styl, { inline, primary }]"
:type="type"
@click="$emit('click')"
@mousedown="onMousedown"
>
<slot></slot>
<div ref="ripples" class="ripples"></div>
<div class="content">
<slot></slot>
</div>
</component>
</template>
@ -56,6 +60,47 @@ export default Vue.extend({
this.$el.focus();
});
}
},
methods: {
onMousedown(e: MouseEvent) {
function distance(p, q) {
const sqrt = Math.sqrt, pow = Math.pow;
return sqrt(pow(p.x - q.x, 2) + pow(p.y - q.y, 2));
}
function calcCircleScale(boxW, boxH, circleCenterX, circleCenterY) {
const origin = {x: circleCenterX, y: circleCenterY};
const dist1 = distance({x: 0, y: 0}, origin);
const dist2 = distance({x: boxW, y: 0}, origin);
const dist3 = distance({x: 0, y: boxH}, origin);
const dist4 = distance({x: boxW, y: boxH }, origin);
return Math.max(dist1, dist2, dist3, dist4) * 2;
}
const rect = e.target.getBoundingClientRect();
const ripple = document.createElement('div');
ripple.style.top = (e.clientY - rect.top - 1).toString() + 'px';
ripple.style.left = (e.clientX - rect.left - 1).toString() + 'px';
this.$refs.ripples.appendChild(ripple);
const circleCenterX = e.clientX - rect.left;
const circleCenterY = e.clientY - rect.top;
const scale = calcCircleScale(e.target.clientWidth, e.target.clientHeight, circleCenterX, circleCenterY);
setTimeout(() => {
ripple.style.transform = 'scale(' + (scale / 2) + ')';
}, 1);
setTimeout(() => {
ripple.style.transition = 'all 1s ease';
ripple.style.opacity = '0';
}, 1000);
setTimeout(() => {
if (this.$refs.ripples) this.$refs.ripples.removeChild(ripple);
}, 2000);
}
}
});
</script>
@ -137,4 +182,30 @@ export default Vue.extend({
&:not(:disabled):active
background var(--primaryAlpha03)
> .ripples
position absolute
z-index 0
top 0
left 0
width 100%
height 100%
border-radius 6px
overflow hidden
>>> div
position absolute
width 2px
height 2px
border-radius 100%
background rgba(0, 0, 0, 0.1)
opacity 1
transform scale(1)
transition all 0.5s cubic-bezier(0, .5, .5, 1)
&.primary > .ripples >>> div
background rgba(0, 0, 0, 0.15)
> .content
z-index 1
</style>

View File

@ -43,6 +43,7 @@ export default Vue.extend({
> *
flex 1
min-width 0 !important
> *:not(:last-child)
margin-right 16px !important

View File

@ -14,17 +14,19 @@
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
@focus="focused = true"
@blur="focused = false"
@keydown="$emit('keydown', $event)"
>
</template>
<template v-else>
<input ref="input"
type="text"
:value="placeholder"
:value="filePlaceholder"
readonly
@click="chooseFile"
>
@ -74,6 +76,15 @@ export default Vue.extend({
type: String,
required: false
},
placeholder: {
type: String,
required: false
},
autofocus: {
type: Boolean,
required: false,
default: false
},
autocomplete: {
required: false
},
@ -109,7 +120,7 @@ export default Vue.extend({
filled(): boolean {
return this.v != '' && this.v != null;
},
placeholder(): string {
filePlaceholder(): string {
if (this.type != 'file') return null;
if (this.v == null) return null;
@ -142,6 +153,12 @@ export default Vue.extend({
}
},
mounted() {
if (this.autofocus) {
this.$nextTick(() => {
this.$refs.input.focus();
});
}
this.$nextTick(() => {
if (this.$refs.prefix) {
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';

View File

@ -94,7 +94,7 @@ root(fill)
width 24px
text-align center
line-height 32px
color rgba(#000, 0.54)
color var(--inputLabel)
&:not(:empty) + .input
margin-left 28px

View File

@ -34,7 +34,6 @@ import PostFormWindow from './views/components/post-form-window.vue';
import RenoteFormWindow from './views/components/renote-form-window.vue';
import MkChooseFileFromDriveWindow from './views/components/choose-file-from-drive-window.vue';
import MkChooseFolderFromDriveWindow from './views/components/choose-folder-from-drive-window.vue';
import InputDialog from './views/components/input-dialog.vue';
import Notification from './views/components/ui-notification.vue';
import { url } from '../config';
@ -113,22 +112,6 @@ init(async (launch) => {
});
},
$input(opts) {
return new Promise<string>((res, rej) => {
const o = opts || {};
const d = this.$root.new(InputDialog, {
title: o.title,
placeholder: o.placeholder,
default: o.default,
type: o.type || 'text',
allowEmpty: o.allowEmpty
});
d.$once('done', text => {
res(text);
});
});
},
$notify(message) {
this.$root.new(Notification, {
message

View File

@ -148,12 +148,15 @@ export default Vue.extend({
},
rename() {
this.$input({
this.$root.dialog({
title: this.$t('contextmenu.rename-file'),
placeholder: this.$t('contextmenu.input-new-file-name'),
default: this.file.name,
allowEmpty: false
}).then(name => {
input: {
placeholder: this.$t('contextmenu.input-new-file-name'),
default: this.file.name,
allowEmpty: false
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$root.api('drive/files/update', {
fileId: this.file.id,
name: name

View File

@ -192,11 +192,14 @@ export default Vue.extend({
},
rename() {
this.$input({
this.$root.dialog({
title: this.$t('contextmenu.rename-folder'),
placeholder: this.$t('contextmenu.input-new-folder-name'),
default: this.folder.name
}).then(name => {
input: {
placeholder: this.$t('contextmenu.input-new-folder-name'),
default: this.folder.name
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$root.api('drive/folders/update', {
folderId: this.folder.id,
name: name

View File

@ -331,10 +331,13 @@ export default Vue.extend({
},
urlUpload() {
this.$input({
this.$root.dialog({
title: this.$t('url-upload'),
placeholder: this.$t('url-of-file')
}).then(url => {
input: {
placeholder: this.$t('url-of-file')
}
}).then(({ canceled, result: url }) => {
if (canceled) return;
this.$root.api('drive/files/upload_from_url', {
url: url,
folderId: this.folder ? this.folder.id : undefined
@ -348,10 +351,13 @@ export default Vue.extend({
},
createFolder() {
this.$input({
this.$root.dialog({
title: this.$t('create-folder'),
placeholder: this.$t('folder-name')
}).then(name => {
input: {
placeholder: this.$t('folder-name')
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$root.api('drive/folders/create', {
name: name,
parentId: this.folder ? this.folder.id : undefined

View File

@ -1,180 +0,0 @@
<template>
<mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom">
<span slot="header" :class="$style.header">
<fa icon="i-cursor"/>{{ title }}
</span>
<div :class="$style.body">
<input ref="text" v-model="text" :type="type" @keydown="onKeydown" :placeholder="placeholder"/>
</div>
<div :class="$style.actions">
<button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
<button :class="$style.ok" :disabled="!allowEmpty && text.length == 0" @click="ok">{{ $t('ok') }}</button>
</div>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('desktop/views/input-dialog.vue'),
props: {
title: {
type: String
},
placeholder: {
type: String
},
default: {
type: String
},
allowEmpty: {
default: true
},
type: {
default: 'text'
}
},
data() {
return {
done: false,
text: ''
};
},
mounted() {
if (this.default) this.text = this.default;
this.$nextTick(() => {
(this.$refs.text as any).focus();
});
},
methods: {
ok() {
if (!this.allowEmpty && this.text == '') return;
this.done = true;
(this.$refs.window as any).close();
},
cancel() {
this.done = false;
(this.$refs.window as any).close();
},
beforeClose() {
if (this.done) {
this.$emit('done', this.text);
} else {
this.$emit('canceled');
}
},
onKeydown(e) {
if (e.which == 13) { // Enter
e.preventDefault();
e.stopPropagation();
this.ok();
}
}
}
});
</script>
<style lang="stylus" module>
.header
> [data-icon]
margin-right 4px
.body
padding 16px
> input
display block
padding 8px
margin 0
width 100%
max-width 100%
min-width 100%
font-size 1em
color #333
background #fff
outline none
border solid 1px var(--primaryAlpha01)
border-radius 4px
transition border-color .3s ease
&:hover
border-color var(--primaryAlpha02)
transition border-color .1s ease
&:focus
color var(--primary)
border-color var(--primaryAlpha05)
transition border-color 0s ease
&::-webkit-input-placeholder
color var(--primaryAlpha03)
.actions
height 72px
background var(--primaryLighten95)
.ok
.cancel
display block
position absolute
bottom 16px
cursor pointer
padding 0
margin 0
width 120px
height 40px
font-size 1em
outline none
border-radius 4px
&:focus
&:after
content ""
pointer-events none
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid var(--primaryAlpha03)
border-radius 8px
&:disabled
opacity 0.7
cursor default
.ok
right 16px
color var(--primaryForeground)
background linear-gradient(to bottom, var(--primaryLighten25) 0%, var(--primaryLighten10) 100%)
border solid 1px var(--primaryLighten15)
&:not(:disabled)
font-weight bold
&:hover:not(:disabled)
background linear-gradient(to bottom, var(--primaryLighten8) 0%, var(--primaryDarken8) 100%)
border-color var(--primary)
&:active:not(:disabled)
background var(--primary)
border-color var(--primary)
.cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
</style>

View File

@ -71,7 +71,6 @@ import parse from '../../../../../mfm/parse';
import { host } from '../../../config';
import { erase, unique } from '../../../../../prelude/array';
import { length } from 'stringz';
import parseAcct from '../../../../../misc/acct/parse';
import { toASCII } from 'punycode';
export default Vue.extend({
@ -384,13 +383,12 @@ export default Vue.extend({
},
addVisibleUser() {
this.$input({
title: this.$t('enter-username')
}).then(acct => {
if (acct.startsWith('@')) acct = acct.substr(1);
this.$root.api('users/show', parseAcct(acct)).then(user => {
this.visibleUsers.push(user);
});
this.$root.dialog({
title: this.$t('enter-username'),
user: true
}).then(({ canceled, result: user }) => {
if (canceled) return;
this.visibleUsers.push(user);
});
},

View File

@ -35,10 +35,13 @@ export default Vue.extend({
},
methods: {
register() {
this.$input({
this.$root.dialog({
title: this.$t('enter-password'),
type: 'password'
}).then(password => {
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
this.$root.api('i/2fa/register', {
password: password
}).then(data => {
@ -48,10 +51,13 @@ export default Vue.extend({
},
unregister() {
this.$input({
this.$root.dialog({
title: this.$t('enter-password'),
type: 'password'
}).then(password => {
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
this.$root.api('i/2fa/unregister', {
password: password
}).then(() => {

View File

@ -16,27 +16,7 @@
<div class="pages">
<div class="profile" v-show="page == 'profile'">
<x-profile-editor/>
<ui-card>
<div slot="title"><fa :icon="['fab', 'twitter']"/> {{ $t('twitter') }}</div>
<section>
<x-twitter-setting/>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'github']"/> {{ $t('github') }}</div>
<section>
<x-github-setting/>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'discord']"/> {{ $t('discord') }}</div>
<section>
<x-discord-setting/>
</section>
</ui-card>
<x-integration-settings/>
</div>
<ui-card class="theme" v-show="page == 'theme'">
@ -169,24 +149,7 @@
</section>
</ui-card>
<ui-card class="web" v-show="page == 'web'">
<div slot="title"><fa icon="language"/> {{ $t('language') }}</div>
<section class="fit-top">
<ui-select v-model="lang" :placeholder="$t('pick-language')">
<optgroup :label="$t('recommended')">
<option value="">{{ $t('auto') }}</option>
</optgroup>
<optgroup :label="$t('specify-language')">
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
</optgroup>
</ui-select>
<div class="none ui info">
<div>Current: <i>{{ this.currentLanguage }}</i></div>
<p><fa icon="info-circle"/>{{ $t('language-desc') }}</p>
</div>
</section>
</ui-card>
<x-language-settings v-show="page == 'web'"/>
<ui-card class="web" v-show="page == 'web'">
<div slot="title"><fa :icon="['far', 'trash-alt']"/> {{ $t('cache') }}</div>
@ -309,17 +272,16 @@ import X2fa from './settings.2fa.vue';
import XApps from './settings.apps.vue';
import XSignins from './settings.signins.vue';
import XTags from './settings.tags.vue';
import XTwitterSetting from '../../../common/views/components/twitter-setting.vue';
import XGithubSetting from '../../../common/views/components/github-setting.vue';
import XDiscordSetting from '../../../common/views/components/discord-setting.vue';
import XIntegrationSettings from '../../../common/views/components/integration-settings.vue';
import XTheme from '../../../common/views/components/theme.vue';
import XDriveSettings from '../../../common/views/components/drive-settings.vue';
import XMuteAndBlock from '../../../common/views/components/mute-and-block.vue';
import XPasswordSettings from '../../../common/views/components/password-settings.vue';
import XProfileEditor from '../../../common/views/components/profile-editor.vue';
import XApiSettings from '../../../common/views/components/api-settings.vue';
import XLanguageSettings from '../../../common/views/components/language-settings.vue';
import { url, langs, clientVersion as version } from '../../../config';
import { url, clientVersion as version } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
export default Vue.extend({
@ -329,15 +291,14 @@ export default Vue.extend({
XApps,
XSignins,
XTags,
XTwitterSetting,
XGithubSetting,
XDiscordSetting,
XIntegrationSettings,
XTheme,
XDriveSettings,
XMuteAndBlock,
XPasswordSettings,
XProfileEditor,
XApiSettings,
XLanguageSettings,
},
props: {
initialPage: {
@ -350,8 +311,6 @@ export default Vue.extend({
page: this.initialPage || 'profile',
meta: null,
version,
langs,
currentLanguage: 'Unknown',
latestVersion: undefined,
checkingForUpdate: false
};
@ -412,11 +371,6 @@ export default Vue.extend({
set(value) { this.$store.commit('device/set', { key: 'soundVolume', value }); }
},
lang: {
get() { return this.$store.state.device.lang; },
set(value) { this.$store.commit('device/set', { key: 'lang', value }); }
},
preventUpdate: {
get() { return this.$store.state.device.preventUpdate; },
set(value) { this.$store.commit('device/set', { key: 'preventUpdate', value }); }
@ -556,12 +510,6 @@ export default Vue.extend({
this.$root.getMeta().then(meta => {
this.meta = meta;
});
try {
const locale = JSON.parse(localStorage.getItem('locale') || "{}");
const localeKey = localStorage.getItem('localeKey');
this.currentLanguage = `${locale.meta.lang} (${localeKey})`;
} catch { }
},
methods: {
readAllUnreadNotes() {

View File

@ -109,9 +109,11 @@ export default Vue.extend({
icon: 'plus',
text: this.$t('add-list'),
action: () => {
this.$input({
this.$root.dialog({
title: this.$t('list-name'),
}).then(async title => {
input: true
}).then(async ({ canceled, result: title }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
title
});

View File

@ -29,9 +29,11 @@ export default Vue.extend({
},
methods: {
add() {
this.$input({
this.$root.dialog({
title: this.$t('list-name'),
}).then(async title => {
input: true
}).then(async ({ canceled, result: title }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
title
});

View File

@ -167,11 +167,14 @@ export default Vue.extend({
icon: 'pencil-alt',
text: this.$t('rename'),
action: () => {
this.$input({
this.$root.dialog({
title: this.$t('rename'),
default: this.name,
allowEmpty: false
}).then(name => {
input: {
default: this.name,
allowEmpty: false
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$store.dispatch('settings/renameDeckColumn', { id: this.column.id, name });
});
}

View File

@ -252,9 +252,11 @@ export default Vue.extend({
icon: 'hashtag',
text: this.$t('@deck.hashtag'),
action: () => {
this.$input({
title: this.$t('enter-hashtag-tl-title')
}).then(title => {
this.$root.dialog({
title: this.$t('enter-hashtag-tl-title'),
input: true
}).then(({ canceled, result: title }) => {
if (canceled) return;
this.$store.dispatch('settings/addDeckColumn', {
id: uuid(),
type: 'hashtag',

View File

@ -1,7 +1,9 @@
<template>
<div class="lkafjvabenanajk17kwqpsatoushincb">
<span><fa :icon="['fab', 'discord']"/><a :href="`https://discordapp.com/users/${user.discord.id}`" target="_blank">@{{ user.discord.username }}#{{ user.discord.discriminator }}</a></span>
</div>
<a class="lkafjvabenanajk17kwqpsatoushincb" :href="`https://discordapp.com/users/${user.discord.id}`" target="_blank">
<div>
<span><fa :icon="['fab', 'discord']"/>@{{ user.discord.username }}#{{ user.discord.discriminator }}</span>
</div>
</a>
</template>
<script lang="ts">
@ -14,13 +16,13 @@ export default Vue.extend({
<style lang="stylus" scoped>
.lkafjvabenanajk17kwqpsatoushincb
padding 32px
background #7289da
border-radius 6px
margin-left 8px
color #fff
a
margin-left 8px
div
padding 32px
background #7289da
border-radius 6px
color #fff
</style>

View File

@ -1,7 +1,9 @@
<template>
<div class="aqooishiizumijmihokohinatamihoaz">
<span><fa :icon="['fab', 'github']"/><a :href="`https://github.com/${user.github.login}`" target="_blank">@{{ user.github.login }}</a></span>
</div>
<a class="aqooishiizumijmihokohinatamihoaz" :href="`https://github.com/${user.github.login}`" target="_blank">
<div>
<span><fa :icon="['fab', 'github']"/>@{{ user.github.login }}</span>
</div>
</a>
</template>
<script lang="ts">
@ -14,13 +16,13 @@ export default Vue.extend({
<style lang="stylus" scoped>
.aqooishiizumijmihokohinatamihoaz
padding 32px
background #171515
border-radius 6px
margin-left 8px
color #fff
a
margin-left 8px
div
padding 32px
background #171515
border-radius 6px
color #fff
</style>

View File

@ -77,8 +77,8 @@ export default Vue.extend({
type: 'warning',
text: this.$t('block-confirm'),
showCancelButton: true
}).then(res => {
if (!res) return;
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('blocking/create', {
userId: this.user.id

View File

@ -1,7 +1,9 @@
<template>
<div class="adsvaidqfznoartcbplullnejvxjphcn">
<span><fa :icon="['fab', 'twitter']"/><a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></span>
</div>
<a class="adsvaidqfznoartcbplullnejvxjphcn" :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">
<div>
<span><fa :icon="['fab', 'twitter']"/>@{{ user.twitter.screenName }}</span>
</div>
</a>
</template>
<script lang="ts">
@ -14,13 +16,13 @@ export default Vue.extend({
<style lang="stylus" scoped>
.adsvaidqfznoartcbplullnejvxjphcn
padding 32px
background #1a94f2
border-radius 6px
margin-left 8px
color #fff
a
margin-left 8px
div
padding 32px
background #1a94f2
border-radius 6px
color #fff
</style>

View File

@ -2,7 +2,10 @@
<div class="mkw-polls">
<mk-widget-container :show-header="!props.compact">
<template slot="header"><fa icon="chart-pie"/>{{ $t('title') }}</template>
<button slot="func" :title="$t('title')" @click="fetch"><fa icon="sync"/></button>
<button slot="func" :title="$t('title')" @click="fetch">
<fa v-if="!fetching && more" icon="arrow-right"/>
<fa v-if="!fetching && !more" icon="sync"/>
</button>
<div class="mkw-polls--body">
<div class="poll" v-if="!fetching && poll != null">
@ -32,6 +35,7 @@ export default define({
return {
poll: null,
fetching: true,
more: true,
offset: 0
};
},
@ -53,12 +57,18 @@ export default define({
}).then(notes => {
const poll = notes ? notes[0] : null;
if (poll == null) {
this.more = false;
this.offset = 0;
} else {
this.more = true;
this.offset++;
}
this.poll = poll;
this.fetching = false;
}).catch(() => {
this.poll = null;
this.fetching = false;
this.more = false;
});
}
}

View File

@ -2,7 +2,10 @@
<div class="mkw-users">
<mk-widget-container :show-header="!props.compact">
<template slot="header"><fa icon="users"/>{{ $t('title') }}</template>
<button slot="func" :title="$t('title')" @click="refresh"><fa icon="sync"/></button>
<button slot="func" :title="$t('title')" @click="refresh">
<fa v-if="!fetching && more" icon="arrow-right"/>
<fa v-if="!fetching && !more" icon="sync"/>
</button>
<div class="mkw-users--body">
<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
@ -38,6 +41,7 @@ export default define({
return {
users: [],
fetching: true,
more: true,
page: 0
};
},
@ -59,12 +63,19 @@ export default define({
}).then(users => {
this.users = users;
this.fetching = false;
}).catch(() => {
this.users = [];
this.fetching = false;
this.more = false;
this.page = 0;
});
},
refresh() {
if (this.users.length < limit) {
this.more = false;
this.page = 0;
} else {
this.more = true;
this.page++;
}
this.fetch();

View File

@ -458,10 +458,10 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS]) => void,
return x;
},
dialog(opts) {
const vm = this.new(Dialog, opts);
return new Promise((res) => {
const vm = this.new(Dialog, opts);
vm.$once('ok', result => res(result));
vm.$once('cancel', () => res(false));
vm.$once('ok', result => res({ canceled: false, result }));
vm.$once('cancel', () => res({ canceled: true }));
});
}
},

View File

@ -95,15 +95,6 @@ init((launch) => {
});
},
$input(opts) {
return new Promise<string>((res, rej) => {
const x = window.prompt(opts.title);
if (x) {
res(x);
}
});
},
$notify(message) {
alert(message);
}

View File

@ -152,7 +152,7 @@ export default Vue.extend({
text-align left
background var(--face)
border-radius 8px
box-shadow 0 0 2px rgba(#000, 0.1)
box-shadow 0 4px 16px rgba(#000, 0.1)
@media (min-width 500px)
box-shadow 0 8px 32px rgba(#000, 0.1)

View File

@ -186,7 +186,7 @@ export default Vue.extend({
overflow hidden
background var(--face)
border-radius 8px
box-shadow 0 0 2px rgba(#000, 0.1)
box-shadow 0 4px 16px rgba(#000, 0.1)
@media (min-width 500px)
box-shadow 0 8px 32px rgba(#000, 0.1)

View File

@ -62,7 +62,6 @@ import parse from '../../../../../mfm/parse';
import { host } from '../../../config';
import { erase, unique } from '../../../../../prelude/array';
import { length } from 'stringz';
import parseAcct from '../../../../../misc/acct/parse';
import { toASCII } from 'punycode';
export default Vue.extend({
@ -219,6 +218,16 @@ export default Vue.extend({
(this.$refs.text as any).focus();
},
addVisibleUser() {
this.$root.dialog({
title: this.$t('enter-username'),
user: true
}).then(({ canceled, result: user }) => {
if (canceled) return;
this.visibleUsers.push(user);
});
},
chooseFile() {
(this.$refs.file as any).click();
},

View File

@ -81,7 +81,7 @@ export default Vue.extend({
top 0
z-index 1024
width 100%
box-shadow 0 1px 0 rgba(#000, 0.075)
box-shadow 0 0px 8px rgba(0, 0, 0, 0.25)
&, *
user-select none

View File

@ -95,9 +95,13 @@ export default Vue.extend({
methods: {
search() {
const query = window.prompt(this.$t('search'));
if (query == null || query == '') return;
this.$router.push(`/search?q=${encodeURIComponent(query)}`);
this.$root.dialog({
title: this.$t('search'),
input: true
}).then(({ canceled, result: query }) => {
if (canceled) return;
this.$router.push(`/search?q=${encodeURIComponent(query)}`);
});
},
onReversiInvited() {

View File

@ -27,8 +27,8 @@ export default Vue.extend({
type: 'warning',
text: this.$t('read-all'),
showCancelButton: true
}).then(res => {
if (!res) return;
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('notifications/mark_all_as_read');
});

View File

@ -105,62 +105,9 @@
</section>
</ui-card>
<ui-card>
<div slot="title"><fa icon="language"/> {{ $t('lang') }}</div>
<x-language-settings/>
<section class="fit-top">
<ui-select v-model="lang" :placeholder="$t('auto')">
<optgroup :label="$t('recommended')">
<option value="">{{ $t('auto') }}</option>
</optgroup>
<optgroup :label="$t('specify-language')">
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
</optgroup>
</ui-select>
<div>Current: <i>{{ this.currentLanguage }}</i></div>
<p><fa icon="info-circle"/> {{ $t('lang-tip') }}</p>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'twitter']"/> {{ $t('twitter') }}</div>
<section>
<p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? this.$t('twitter-reconnect') : this.$t('twitter-connect') }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">{{ $t('twitter-disconnect') }}</a>
</p>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'github']"/> {{ $t('github') }}</div>
<section>
<p class="account" v-if="$store.state.i.github"><a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p>
<a :href="`${apiUrl}/connect/github`" target="_blank">{{ $store.state.i.github ? this.$t('github-reconnect') : this.$t('github-connect') }}</a>
<span v-if="$store.state.i.github"> or </span>
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github">{{ $t('github-disconnect') }}</a>
</p>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'discord']"/> {{ $t('discord') }}</div>
<section>
<p class="account" v-if="$store.state.i.discord"><a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<p>
<a :href="`${apiUrl}/connect/discord`" target="_blank">{{ $store.state.i.discord ? this.$t('discord-reconnect') : this.$t('discord-connect') }}</a>
<span v-if="$store.state.i.discord"> or </span>
<a :href="`${apiUrl}/disconnect/discord`" target="_blank" v-if="$store.state.i.discord">{{ $t('discord-disconnect') }}</a>
</p>
</section>
</ui-card>
<x-integration-settings/>
<x-api-settings />
@ -199,7 +146,7 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { apiUrl, clientVersion as version, codename, langs } from '../../../config';
import { apiUrl, clientVersion as version, codename } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
import XTheme from '../../../common/views/components/theme.vue';
import XDriveSettings from '../../../common/views/components/drive-settings.vue';
@ -207,6 +154,8 @@ import XMuteAndBlock from '../../../common/views/components/mute-and-block.vue';
import XPasswordSettings from '../../../common/views/components/password-settings.vue';
import XProfileEditor from '../../../common/views/components/profile-editor.vue';
import XApiSettings from '../../../common/views/components/api-settings.vue';
import XLanguageSettings from '../../../common/views/components/language-settings.vue';
import XIntegrationSettings from '../../../common/views/components/integration-settings.vue';
export default Vue.extend({
i18n: i18n('mobile/views/pages/settings.vue'),
@ -218,6 +167,8 @@ export default Vue.extend({
XPasswordSettings,
XProfileEditor,
XApiSettings,
XLanguageSettings,
XIntegrationSettings,
},
data() {
@ -225,8 +176,6 @@ export default Vue.extend({
apiUrl,
version,
codename,
langs,
currentLanguage: 'Unknown',
latestVersion: undefined,
checkingForUpdate: false
};
@ -277,11 +226,6 @@ export default Vue.extend({
set(value) { this.$store.commit('device/set', { key: 'loadRawImages', value }); }
},
lang: {
get() { return this.$store.state.device.lang; },
set(value) { this.$store.commit('device/set', { key: 'lang', value }); }
},
enableSounds: {
get() { return this.$store.state.device.enableSounds; },
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
@ -327,7 +271,6 @@ export default Vue.extend({
set(value) { this.$store.dispatch('settings/set', { key: 'showVia', value }); }
},
iLikeSushi: {
get() { return this.$store.state.settings.iLikeSushi; },
set(value) { this.$store.dispatch('settings/set', { key: 'iLikeSushi', value }); }
@ -379,14 +322,6 @@ export default Vue.extend({
},
},
created() {
try {
const locale = JSON.parse(localStorage.getItem('locale') || "{}");
const localeKey = localStorage.getItem('localeKey');
this.currentLanguage = `${locale.meta.lang} (${localeKey})`;
} catch { }
},
mounted() {
document.title = this.$t('settings');
},

View File

@ -38,9 +38,11 @@ export default Vue.extend({
},
methods: {
fn() {
this.$input({
this.$root.dialog({
title: this.$t('enter-list-name'),
}).then(async title => {
input: true
}).then(async ({ canceled, result: title }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
title
});

View File

@ -120,7 +120,7 @@ export default Vue.extend({
text: this.$t('push-to-list'),
action: async () => {
const lists = await this.$root.api('users/lists/list');
const listId = await this.$root.dialog({
const { canceled, result: listId } = await this.$root.dialog({
type: null,
title: this.$t('select-list'),
select: {
@ -130,7 +130,7 @@ export default Vue.extend({
},
showCancelButton: true
});
if (!listId) return;
if (canceled) return;
await this.$root.api('users/lists/push', {
listId: listId,
userId: this.user.id

View File

@ -31,6 +31,12 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
return el;
},
strike(token) {
const el = doc.createElement('del');
dive(token.children).forEach(child => el.appendChild(child));
return el;
},
motion(token) {
const el = doc.createElement('i');
dive(token.children).forEach(child => el.appendChild(child));

File diff suppressed because one or more lines are too long

View File

@ -48,7 +48,7 @@ export interface INotification {
/**
* 通知が読まれたかどうか
*/
isRead: Boolean;
isRead: boolean;
}
export const packMany = (

View File

@ -44,6 +44,7 @@ type IUserBase = {
wallpaperUrl?: string;
data: any;
description: string;
lang?: string;
pinnedNoteIds: mongo.ObjectID[];
/**

View File

@ -57,3 +57,15 @@ export function lessThan(xs: number[], ys: number[]): boolean {
}
return xs.length < ys.length;
}
export function takeWhile<T>(f: (x: T) => boolean, xs: T[]): T[] {
const ys = [];
for (const x of xs) {
if (f(x)) {
ys.push(x);
} else {
break;
}
}
return ys;
}

View File

@ -21,10 +21,8 @@ export default async (actor: IRemoteUser, activity: ILike) => {
let reaction = 'pudding';
// 他のMisskeyインスタンスからのリアクション
if (activity._misskey_reaction) {
if (validateReaction.ok(activity._misskey_reaction)) {
reaction = activity._misskey_reaction;
}
if (activity._misskey_reaction && validateReaction.ok(activity._misskey_reaction)) {
reaction = activity._misskey_reaction;
}
await create(actor, note, reaction);

View File

@ -10,7 +10,7 @@ import { resolvePerson, updatePerson } from './person';
import { resolveImage } from './image';
import { IRemoteUser, IUser } from '../../../models/user';
import htmlToMFM from '../../../mfm/html-to-mfm';
import Emoji from '../../../models/emoji';
import Emoji, { IEmoji } from '../../../models/emoji';
import { ITag } from './tag';
import { toUnicode } from 'punycode';
import { unique, concat, difference } from '../../../prelude/array';
@ -84,6 +84,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver);
const apHashtags = await extractHashtags(note.tag);
// 添付ファイル
// TODO: attachmentは必ずしもImageではない
// TODO: attachmentは必ずしも配列ではない
@ -108,10 +110,13 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
// テキストのパース
const text = note._misskey_content ? note._misskey_content : htmlToMFM(note.content);
await extractEmojis(note.tag, actor.host).catch(e => {
const emojis = await extractEmojis(note.tag, actor.host).catch(e => {
console.log(`extractEmojis: ${e}`);
return [] as IEmoji[];
});
const apEmojis = emojis.map(emoji => emoji.name);
// ユーザーの情報が古かったらついでに更新しておく
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
updatePerson(note.attributedTo);
@ -130,6 +135,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
visibility,
visibleUsers,
apMentions,
apHashtags,
apEmojis,
uri: note.id
}, silent);
}
@ -199,3 +206,14 @@ async function extractMentionedUsers(actor: IRemoteUser, to: string[], cc: strin
return users.filter(x => x != null);
}
function extractHashtags(tags: ITag[]) {
if (!tags) return [];
const hashtags = tags.filter(tag => tag.type === 'Hashtag' && typeof tag.name == 'string');
return hashtags.map(tag => {
const m = tag.name.match(/^#(.+)/);
return m ? m[1] : null;
}).filter(x => x != null);
}

View File

@ -164,7 +164,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
uri: person.id,
url: person.url,
isBot: isBot,
isCat: (person as any).isCat === true ? true : false
isCat: (person as any).isCat === true
}) as IRemoteUser;
} catch (e) {
// duplicate key error
@ -322,7 +322,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
url: person.url,
endpoints: person.endpoints,
isBot: object.type == 'Service',
isCat: (person as any).isCat === true ? true : false,
isCat: (person as any).isCat === true,
isLocked: person.manuallyApprovesFollowers,
createdAt: Date.parse(person.published) || null,
publicKey: {

View File

@ -63,7 +63,7 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
});
// タグを人気順に並べ替え
tags = tags.sort((a, b) => b.count - a.count);
tags.sort((a, b) => b.count - a.count);
tags = tags.slice(0, 30);

View File

@ -6,6 +6,7 @@ import acceptAllFollowRequests from '../../../../services/following/requests/acc
import { publishToFollowers } from '../../../../services/i/update';
import define from '../../define';
import getDriveFileUrl from '../../../../misc/get-drive-file-url';
const langmap = require('langmap');
export const meta = {
desc: {
@ -32,6 +33,13 @@ export const meta = {
}
},
lang: {
validator: $.str.optional.nullable.or(Object.keys(langmap)),
desc: {
'ja-JP': '言語'
}
},
location: {
validator: $.str.optional.nullable.pipe(isValidLocation),
desc: {
@ -121,6 +129,7 @@ export default define(meta, (ps, user, app) => new Promise(async (res, rej) => {
if (ps.name !== undefined) updates.name = ps.name;
if (ps.description !== undefined) updates.description = ps.description;
if (ps.lang !== undefined) updates.lang = ps.lang;
if (ps.location !== undefined) updates['profile.location'] = ps.location;
if (ps.birthday !== undefined) updates['profile.birthday'] = ps.birthday;
if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId;

View File

@ -106,9 +106,7 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
const withFiles = ps.withFiles != undefined ? ps.withFiles : ps.media;
if (withFiles) {
query.fileIds = withFiles ? { $exists: true, $ne: null } : [];
}
if (withFiles) query.fileIds = { $exists: true, $ne: null };
if (ps.poll != undefined) {
query.poll = ps.poll ? { $exists: true, $ne: null } : null;

View File

@ -30,7 +30,7 @@ async function genVars(lang: string): Promise<{ [key: string]: any }> {
const entities = glob.sync('src/docs/api/entities/**/*.yaml', { cwd });
vars['entities'] = entities.map(x => {
const _x = yaml.safeLoad(fs.readFileSync(cwd + x, 'utf-8')) as any;
const _x = yaml.safeLoad(fs.readFileSync(cwd + x, 'utf-8'));
return _x.name;
});
@ -197,7 +197,7 @@ router.get('/*/api/entities/*', async ctx => {
const lang = ctx.params[0];
const entity = ctx.params[1];
const x = yaml.safeLoad(fs.readFileSync(path.resolve(`${__dirname}/../../../src/docs/api/entities/${entity}.yaml`), 'utf-8')) as any;
const x = yaml.safeLoad(fs.readFileSync(path.resolve(`${__dirname}/../../../src/docs/api/entities/${entity}.yaml`), 'utf-8'));
await ctx.render('../../../../src/docs/api/entities/view', Object.assign(await genVars(lang), {
id: `api/entities/${entity}`,

View File

@ -98,6 +98,8 @@ type Option = {
visibility?: string;
visibleUsers?: IUser[];
apMentions?: IUser[];
apHashtags?: string[];
apEmojis?: string[];
uri?: string;
app?: IApp;
};
@ -153,16 +155,22 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
data.text = data.text.trim();
}
// Parse MFM
const tokens = data.text ? parse(data.text) : [];
const cwTokens = data.cw ? parse(data.cw) : [];
const combinedTokens = tokens.concat(cwTokens);
let tags = data.apHashtags;
let emojis = data.apEmojis;
let mentionedUsers = data.apMentions;
const tags = extractHashtags(combinedTokens);
// Parse MFM if needed
if (!tags || !emojis || !mentionedUsers) {
const tokens = data.text ? parse(data.text) : [];
const cwTokens = data.cw ? parse(data.cw) : [];
const combinedTokens = tokens.concat(cwTokens);
const emojis = extractEmojis(combinedTokens);
tags = data.apHashtags || extractHashtags(combinedTokens);
const mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens);
emojis = data.apEmojis || extractEmojis(combinedTokens);
mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens);
}
if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) {
mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));

View File

@ -702,6 +702,17 @@ describe('Text', () => {
], tokens);
});
});
describe('strike', () => {
it('simple', () => {
const tokens = analyze('~~foo~~');
assert.deepEqual([
nodeWithChildren('strike', [
text('foo')
]),
], tokens);
});
});
});
describe('toHtml', () => {