Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
69d72819c6 | |||
54dcc10250 | |||
1edfce8f73 | |||
675e573a8c | |||
1080fa63a9 | |||
8047086988 | |||
449b9f7fa0 | |||
b7a15bf6ca | |||
7c3873887d | |||
247ea4cf12 | |||
0b7af5c669 | |||
2b62a4e2e5 | |||
65bfa3c0d6 | |||
84db15694d | |||
746189ba37 | |||
74e845b3ac | |||
90fe70540e | |||
f28af75191 | |||
924bb2bc70 | |||
19d60f3d51 | |||
6903476868 | |||
cf0dccc209 | |||
cfd959129d | |||
819287951c | |||
e136193925 | |||
8c631864d9 | |||
d7d0f6ae2e | |||
b83b3fb9d1 | |||
dfce5bc0af | |||
3487ddabea | |||
2dbff75e7a | |||
02465ded9f | |||
ffcd387945 | |||
4806346707 | |||
31c3f6abf7 | |||
83e47fdd60 |
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1010,11 +1010,15 @@ admin/views/emoji.vue:
|
|||||||
add-emoji:
|
add-emoji:
|
||||||
title: "Add emoji"
|
title: "Add emoji"
|
||||||
name: "Emoji name"
|
name: "Emoji name"
|
||||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
name-desc: "You can use the characters a~z 0~9 _"
|
||||||
aliases: "Aliases"
|
aliases: "Aliases"
|
||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "You can add more than one, separated by spaces."
|
||||||
url: "Image URL"
|
url: "Image URL"
|
||||||
add: "Add"
|
add: "Add"
|
||||||
|
emojis:
|
||||||
|
title: "Emojis"
|
||||||
|
update: "Update"
|
||||||
|
remove: "Remove"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "Announcements"
|
announcements: "Announcements"
|
||||||
save: "Save"
|
save: "Save"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -445,7 +445,7 @@ common/views/components/profile-editor.vue:
|
|||||||
is-cat: "Ce compte est un Chat"
|
is-cat: "Ce compte est un Chat"
|
||||||
is-bot: "Ce compte est un Bot"
|
is-bot: "Ce compte est un Bot"
|
||||||
is-locked: "Demandes d’abonnements requièrent l’approbation"
|
is-locked: "Demandes d’abonnements requièrent l’approbation"
|
||||||
careful-bot: "Botからのフォローだけ承認制にする"
|
careful-bot: "Les demandes d’abonnements venant de Bots requièrent l’approbation"
|
||||||
advanced: "Avancé"
|
advanced: "Avancé"
|
||||||
privacy: "Vie privée"
|
privacy: "Vie privée"
|
||||||
save: "Mettre à jour le profil"
|
save: "Mettre à jour le profil"
|
||||||
@ -502,7 +502,7 @@ common/views/widgets/tips.vue:
|
|||||||
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
|
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
|
||||||
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
|
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
|
||||||
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
|
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
|
||||||
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
|
tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
|
||||||
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
|
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
|
||||||
tips-line23: "Mayu est mignone avec ses sourcils."
|
tips-line23: "Mayu est mignone avec ses sourcils."
|
||||||
tips-line24: "Misskey a vu le jour en 2014"
|
tips-line24: "Misskey a vu le jour en 2014"
|
||||||
@ -549,7 +549,7 @@ desktop/views/components/charts.vue:
|
|||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
network: "Réseau"
|
network: "Réseau"
|
||||||
charts:
|
charts:
|
||||||
federation-instances: "インスタンスの増減"
|
federation-instances: "Nombre d’instances : augmentation/diminution"
|
||||||
federation-instances-total: "Nombre total d’instances"
|
federation-instances-total: "Nombre total d’instances"
|
||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
@ -782,7 +782,7 @@ desktop/views/components/settings.vue:
|
|||||||
timeline: "Chronologie"
|
timeline: "Chronologie"
|
||||||
show-my-renotes: "Afficher mes republications dans le fil"
|
show-my-renotes: "Afficher mes republications dans le fil"
|
||||||
show-renoted-my-notes: "Afficher mes republications dans les fils"
|
show-renoted-my-notes: "Afficher mes republications dans les fils"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "Afficher les partages locaux sur les fils"
|
||||||
show-maps: "Afficher la carte"
|
show-maps: "Afficher la carte"
|
||||||
deck-column-align: "デッキのカラムの位置"
|
deck-column-align: "デッキのカラムの位置"
|
||||||
deck-column-align-center: "Centrer"
|
deck-column-align-center: "Centrer"
|
||||||
@ -866,22 +866,22 @@ common/views/components/api-settings.vue:
|
|||||||
desktop/views/components/settings.apps.vue:
|
desktop/views/components/settings.apps.vue:
|
||||||
no-apps: "Aucune application autorisée"
|
no-apps: "Aucune application autorisée"
|
||||||
common/views/components/drive-settings.vue:
|
common/views/components/drive-settings.vue:
|
||||||
max: "容量"
|
max: "Maximale"
|
||||||
in-use: "utilisé"
|
in-use: "utilisé"
|
||||||
stats: "Statistiques"
|
stats: "Statistiques"
|
||||||
common/views/components/mute-and-block.vue:
|
common/views/components/mute-and-block.vue:
|
||||||
mute-and-block: "ミュートとブロック"
|
mute-and-block: "Silencer / Bloquer"
|
||||||
mute: "ミュート"
|
mute: "Mettre en sourdine"
|
||||||
block: "ブロック"
|
block: "En cours blocage"
|
||||||
no-muted-users: "ミュートしているユーザーはいません"
|
no-muted-users: "Aucun utilisateur·rice n’est mis·e en sourdine"
|
||||||
no-blocked-users: "ブロックしているユーザーはいません"
|
no-blocked-users: "Aucun utilisateur·rice n’est bloqué·e"
|
||||||
common/views/components/password-settings.vue:
|
common/views/components/password-settings.vue:
|
||||||
reset: "パスワードを変更する"
|
reset: "Modifier le mot de passe"
|
||||||
enter-current-password: "現在のパスワードを入力してください"
|
enter-current-password: "Entrez votre mot de passe actuel"
|
||||||
enter-new-password: "新しいパスワードを入力してください"
|
enter-new-password: "Saisissez le nouveau mot de passe"
|
||||||
enter-new-password-again: "もう一度新しいパスワードを入力してください"
|
enter-new-password-again: "Entrez à nouveau le nouveau mot de passe"
|
||||||
not-match: "新しいパスワードが一致しません"
|
not-match: "Les nouveaux mots de passe ne sont pas identiques"
|
||||||
changed: "パスワードを変更しました"
|
changed: "Mot de passe modifié avec succès"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "cette publication est privée"
|
private: "cette publication est privée"
|
||||||
deleted: "cette publication a été supprimée"
|
deleted: "cette publication a été supprimée"
|
||||||
@ -948,82 +948,86 @@ desktop/views/components/window.vue:
|
|||||||
popout: "ポップアウト"
|
popout: "ポップアウト"
|
||||||
close: "Fermer"
|
close: "Fermer"
|
||||||
admin/views/index.vue:
|
admin/views/index.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "Tableau de bord"
|
||||||
instance: "インスタンス"
|
instance: "Instance"
|
||||||
emoji: "カスタム絵文字"
|
emoji: "Emoji"
|
||||||
users: "ユーザー"
|
users: "Utilisateur·rice·s"
|
||||||
update: "更新"
|
update: "Mise à jour"
|
||||||
announcements: "お知らせ"
|
announcements: "Annonces"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "Hashtags"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Retour vers Misskey"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "Tableau de bord"
|
||||||
accounts: "アカウント"
|
accounts: "Comptes"
|
||||||
notes: "投稿"
|
notes: "Notes"
|
||||||
drive: "ドライブ"
|
drive: "Lecteur"
|
||||||
instances: "インスタンス"
|
instances: "Instances"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "Cette instance"
|
||||||
federated: "連合"
|
federated: "Fédérées"
|
||||||
invite: "招待"
|
invite: "Inviter"
|
||||||
banner-url: "Banner URL"
|
banner-url: "URL de la bannière"
|
||||||
disableRegistration: "Disable new user registration"
|
disableRegistration: "Désactiver l’enregistrement de nouveaux utilisateur·rice·s"
|
||||||
disableLocalTimeline: "Disable the local timeline"
|
disableLocalTimeline: "Désactiver le fil local"
|
||||||
admin/views/charts.vue:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "Graph"
|
||||||
per-day: "1日ごと"
|
per-day: "par jour"
|
||||||
per-hour: "1時間ごと"
|
per-hour: "par heure"
|
||||||
federation: "フェデレーション"
|
federation: "Fédération"
|
||||||
notes: "投稿"
|
notes: "Publications"
|
||||||
users: "ユーザー"
|
users: "Utilisateur·rice·s"
|
||||||
drive: "ドライブ"
|
drive: "Lecteur"
|
||||||
network: "ネットワーク"
|
network: "Réseau"
|
||||||
charts:
|
charts:
|
||||||
federation-instances: "インスタンスの増減"
|
federation-instances: "Nombre d’instances : augmentation/diminution"
|
||||||
federation-instances-total: "インスタンスの積算"
|
federation-instances-total: "Nombre total d’instances"
|
||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の積算"
|
notes-total: "Total des publications"
|
||||||
users: "ユーザーの増減"
|
users: "Nombre d’utilisateur·rice·s : augmentation/diminution"
|
||||||
users-total: "ユーザーの積算"
|
users-total: "Nombre total des utilisateur·rice·s"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の積算"
|
drive-total: "Utilisation totale du lecteur"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の積算"
|
drive-files-total: "Nombre total de fichiers sur le lecteur"
|
||||||
network-requests: "リクエスト"
|
network-requests: "Requêtes"
|
||||||
network-time: "応答時間"
|
network-time: "Temps de réponse"
|
||||||
network-usage: "通信量"
|
network-usage: "Traffic"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
suspend-user: "ユーザーの凍結"
|
suspend-user: "Suspendre un·e utilisateur·rice"
|
||||||
suspend: "凍結"
|
suspend: "Suspendre"
|
||||||
suspended: "凍結しました"
|
suspended: "Suspendu·e avec succès."
|
||||||
unsuspend-user: "ユーザーの凍結の解除"
|
unsuspend-user: "Lever la suspension d’utilisateur·rice·s"
|
||||||
unsuspend: "凍結の解除"
|
unsuspend: "Suspension levée"
|
||||||
unsuspended: "凍結を解除しました"
|
unsuspended: "La suspension de l’utilisateur·rice a été levée avec succès"
|
||||||
verify-user: "ユーザーの公式アカウント設定"
|
verify-user: "Paramètres de vérification du compte utilisateur"
|
||||||
verify: "公式アカウントにする"
|
verify: "公式アカウントにする"
|
||||||
verified: "公式アカウントにしました"
|
verified: "公式アカウントにしました"
|
||||||
unverify-user: "ユーザーの公式アカウント解除"
|
unverify-user: "ユーザーの公式アカウント解除"
|
||||||
unverify: "公式アカウントを解除する"
|
unverify: "Ôter la vérification du compte"
|
||||||
unverified: "公式アカウントを解除しました"
|
unverified: "Ce compte n'est plus vérifié"
|
||||||
admin/views/emoji.vue:
|
admin/views/emoji.vue:
|
||||||
add-emoji:
|
add-emoji:
|
||||||
title: "絵文字の登録"
|
title: "Ajouter un émoji"
|
||||||
name: "絵文字名"
|
name: "Nom de l’émoji"
|
||||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||||
aliases: "エイリアス"
|
aliases: "Aliases"
|
||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "Vous pouvez définir plus d’un, séparés par des espaces."
|
||||||
url: "絵文字画像URL"
|
url: "URL de l’image"
|
||||||
add: "追加"
|
add: "Ajouter"
|
||||||
admin/views/announcements.vue:
|
emojis:
|
||||||
announcements: "お知らせ"
|
title: "絵文字一覧"
|
||||||
save: "保存"
|
update: "更新"
|
||||||
remove: "削除"
|
remove: "削除"
|
||||||
add: "追加"
|
admin/views/announcements.vue:
|
||||||
title: "タイトル"
|
announcements: "Annonces"
|
||||||
text: "内容"
|
save: "Enregistrer"
|
||||||
|
remove: "Supprimer"
|
||||||
|
add: "Ajouter"
|
||||||
|
title: "Titre"
|
||||||
|
text: "Contenu"
|
||||||
admin/views/hashtags.vue:
|
admin/views/hashtags.vue:
|
||||||
hided-tags: "Hidden Tags"
|
hided-tags: "Tags cachés"
|
||||||
desktop/views/pages/deck/deck.tl-column.vue:
|
desktop/views/pages/deck/deck.tl-column.vue:
|
||||||
is-media-only: "Les publications médias uniquement"
|
is-media-only: "Les publications médias uniquement"
|
||||||
is-media-view: "Vue média"
|
is-media-view: "Vue média"
|
||||||
@ -1370,7 +1374,7 @@ mobile/views/pages/settings.vue:
|
|||||||
sound: "Sons"
|
sound: "Sons"
|
||||||
enable-sounds: "Activer les sons"
|
enable-sounds: "Activer les sons"
|
||||||
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
|
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
|
||||||
password: "パスワード"
|
password: "Mot de Passe"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Vous suit"
|
follows-you: "Vous suit"
|
||||||
following: "Abonnements"
|
following: "Abonnements"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1142,6 +1142,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
|
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
|
|||||||
aliases-desc: "スペースで区切って複数設定できます。"
|
aliases-desc: "スペースで区切って複数設定できます。"
|
||||||
url: "絵文字画像URL"
|
url: "絵文字画像URL"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
|
emojis:
|
||||||
|
title: "絵文字一覧"
|
||||||
|
update: "更新"
|
||||||
|
remove: "削除"
|
||||||
admin/views/announcements.vue:
|
admin/views/announcements.vue:
|
||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
17362
package-lock.json
generated
17362
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.38.0",
|
"version": "10.38.3",
|
||||||
"clientVersion": "1.0.11454",
|
"clientVersion": "1.0.11490",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div>
|
<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div>
|
||||||
<section v-for="(announcement, i) in announcements" class="fit-top">
|
<section v-for="(announcement, i) in announcements" class="fit-top">
|
||||||
@ -9,10 +9,10 @@
|
|||||||
<ui-textarea v-model="announcement.text">
|
<ui-textarea v-model="announcement.text">
|
||||||
<span>%i18n:@text%</span>
|
<span>%i18n:@text%</span>
|
||||||
</ui-textarea>
|
</ui-textarea>
|
||||||
<ui-button-group>
|
<ui-horizon-group>
|
||||||
<ui-button inline @click="save">%fa:save R% %i18n:@save%</ui-button>
|
<ui-button @click="save">%fa:save R% %i18n:@save%</ui-button>
|
||||||
<ui-button inline @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
|
<ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
|
||||||
</ui-button-group>
|
</ui-horizon-group>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
|
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
|
||||||
@ -62,3 +62,10 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.cdeuzmsthagexbkpofbmatmugjuvogfb
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -34,8 +34,8 @@ export default Vue.extend({
|
|||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.useSharedConnection('apLog');
|
this.connection = (this as any).os.stream.useSharedConnection('apLog');
|
||||||
this.connection.on('stats', this.onLog);
|
this.connection.on('log', this.onLog);
|
||||||
this.connection.on('statsLog', this.onLogs);
|
this.connection.on('logs', this.onLogs);
|
||||||
this.connection.send('requestLog', {
|
this.connection.send('requestLog', {
|
||||||
id: Math.random().toString().substr(2, 8),
|
id: Math.random().toString().substr(2, 8),
|
||||||
length: 50
|
length: 50
|
||||||
@ -67,7 +67,7 @@ export default Vue.extend({
|
|||||||
height 250px
|
height 250px
|
||||||
overflow auto
|
overflow auto
|
||||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||||
background var(--face)
|
background var(--adminDashboardCardBg)
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
|
|
||||||
> table
|
> table
|
||||||
@ -76,10 +76,11 @@ export default Vue.extend({
|
|||||||
overflow auto
|
overflow auto
|
||||||
border-spacing 0
|
border-spacing 0
|
||||||
border-collapse collapse
|
border-collapse collapse
|
||||||
color #555
|
color var(--adminDashboardCardFg)
|
||||||
|
font-size 15px
|
||||||
|
|
||||||
thead
|
thead
|
||||||
border-bottom solid 2px #eee
|
border-bottom solid 2px var(--adminDashboardCardDivider)
|
||||||
|
|
||||||
tr
|
tr
|
||||||
th
|
th
|
||||||
@ -89,7 +90,7 @@ export default Vue.extend({
|
|||||||
tbody
|
tbody
|
||||||
tr
|
tr
|
||||||
&:nth-child(odd)
|
&:nth-child(odd)
|
||||||
background #fbfbfb
|
background rgba(0, 0, 0, 0.025)
|
||||||
|
|
||||||
th, td
|
th, td
|
||||||
padding 8px 16px
|
padding 8px 16px
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import * as tinycolor from 'tinycolor2';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import * as ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
const limit = 90;
|
const limit = 90;
|
||||||
@ -147,7 +148,7 @@ export default Vue.extend({
|
|||||||
this.chartInstance.destroy();
|
this.chartInstance.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chartInstance = new ApexCharts(this.$refs.chart, Object.assign({
|
this.chartInstance = new ApexCharts(this.$refs.chart, {
|
||||||
chart: {
|
chart: {
|
||||||
type: 'area',
|
type: 'area',
|
||||||
height: 300,
|
height: 300,
|
||||||
@ -168,17 +169,41 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
clipMarkers: false,
|
clipMarkers: false,
|
||||||
|
borderColor: 'rgba(0, 0, 0, 0.1)'
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
curve: 'straight',
|
curve: 'straight',
|
||||||
width: 2
|
width: 2
|
||||||
},
|
},
|
||||||
|
legend: {
|
||||||
|
labels: {
|
||||||
|
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||||
|
},
|
||||||
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
type: 'datetime'
|
type: 'datetime',
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisBorder: {
|
||||||
|
color: 'rgba(0, 0, 0, 0.1)'
|
||||||
|
},
|
||||||
|
axisTicks: {
|
||||||
|
color: 'rgba(0, 0, 0, 0.1)'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
formatter: this.data.bytes ? v => Vue.filter('bytes')(v, 0) : v => Vue.filter('number')(v),
|
||||||
|
style: {
|
||||||
|
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||||
}
|
}
|
||||||
}, this.data));
|
}
|
||||||
|
},
|
||||||
|
series: this.data.series
|
||||||
|
});
|
||||||
|
|
||||||
this.chartInstance.render();
|
this.chartInstance.render();
|
||||||
},
|
},
|
||||||
@ -286,6 +311,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
driveChart(): any {
|
driveChart(): any {
|
||||||
return {
|
return {
|
||||||
|
bytes: true,
|
||||||
series: [{
|
series: [{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
data: this.format(
|
data: this.format(
|
||||||
@ -314,6 +340,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
driveTotalChart(): any {
|
driveTotalChart(): any {
|
||||||
return {
|
return {
|
||||||
|
bytes: true,
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Combined',
|
name: 'Combined',
|
||||||
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
|
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
|
||||||
@ -396,6 +423,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
networkUsageChart(): any {
|
networkUsageChart(): any {
|
||||||
return {
|
return {
|
||||||
|
bytes: true,
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Incoming',
|
name: 'Incoming',
|
||||||
data: this.format(this.stats.network.incomingBytes)
|
data: this.format(this.stats.network.incomingBytes)
|
||||||
@ -424,8 +452,8 @@ export default Vue.extend({
|
|||||||
margin 0 8px
|
margin 0 8px
|
||||||
padding 0 0 8px 0
|
padding 0 0 8px 0
|
||||||
font-size 1em
|
font-size 1em
|
||||||
color #555
|
color var(--adminDashboardCardFg)
|
||||||
border-bottom solid 1px #eee
|
border-bottom solid 1px var(--adminDashboardCardDivider)
|
||||||
|
|
||||||
> b
|
> b
|
||||||
margin-right 8px
|
margin-right 8px
|
||||||
|
@ -79,6 +79,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
clipMarkers: false,
|
clipMarkers: false,
|
||||||
|
borderColor: 'rgba(0, 0, 0, 0.1)'
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
curve: 'straight',
|
curve: 'straight',
|
||||||
@ -153,7 +154,7 @@ export default Vue.extend({
|
|||||||
display flex
|
display flex
|
||||||
padding 0 8px
|
padding 0 8px
|
||||||
margin-bottom -16px
|
margin-bottom -16px
|
||||||
color #555
|
color var(--adminDashboardCardFg)
|
||||||
font-size 14px
|
font-size 14px
|
||||||
|
|
||||||
> span
|
> span
|
||||||
@ -167,4 +168,13 @@ export default Vue.extend({
|
|||||||
> div
|
> div
|
||||||
margin-bottom -10px
|
margin-bottom -10px
|
||||||
|
|
||||||
|
@media (max-width 1000px)
|
||||||
|
display block
|
||||||
|
margin-bottom 26px
|
||||||
|
|
||||||
|
> div
|
||||||
|
&:first-child
|
||||||
|
margin-right 0
|
||||||
|
margin-bottom 26px
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -124,14 +124,22 @@ export default Vue.extend({
|
|||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.obdskegsannmntldydackcpzezagxqfy
|
.obdskegsannmntldydackcpzezagxqfy
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 32px
|
||||||
|
|
||||||
> header
|
> header
|
||||||
display flex
|
display flex
|
||||||
margin-bottom 16px
|
margin-bottom 16px
|
||||||
padding-bottom 16px
|
padding-bottom 16px
|
||||||
border-bottom solid 1px #ccc
|
border-bottom solid 1px var(--adminDashboardHeaderBorder)
|
||||||
color #777
|
color var(--adminDashboardHeaderFg)
|
||||||
font-size 14px
|
font-size 14px
|
||||||
|
|
||||||
|
@media (max-width 1000px)
|
||||||
|
display none
|
||||||
|
|
||||||
> p
|
> p
|
||||||
display inline
|
display inline
|
||||||
margin 0 32px 0 0
|
margin 0 32px 0 0
|
||||||
@ -152,11 +160,10 @@ export default Vue.extend({
|
|||||||
|
|
||||||
> div
|
> div
|
||||||
flex 1
|
flex 1
|
||||||
max-width 300px
|
|
||||||
margin-right 16px
|
margin-right 16px
|
||||||
color var(--text)
|
color var(--adminDashboardCardFg)
|
||||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||||
background var(--face)
|
background var(--adminDashboardCardBg)
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
|
|
||||||
&:last-child
|
&:last-child
|
||||||
@ -192,7 +199,7 @@ export default Vue.extend({
|
|||||||
> div:last-child
|
> div:last-child
|
||||||
display flex
|
display flex
|
||||||
padding 6px 16px
|
padding 6px 16px
|
||||||
border-top solid 1px #eee
|
border-top solid 1px var(--adminDashboardCardDivider)
|
||||||
|
|
||||||
> span
|
> span
|
||||||
font-size 70%
|
font-size 70%
|
||||||
@ -202,6 +209,21 @@ export default Vue.extend({
|
|||||||
margin-left auto
|
margin-left auto
|
||||||
cursor pointer
|
cursor pointer
|
||||||
|
|
||||||
|
@media (max-width 900px)
|
||||||
|
display grid
|
||||||
|
grid-template-columns 1fr 1fr
|
||||||
|
grid-template-rows 1fr 1fr
|
||||||
|
gap 16px
|
||||||
|
|
||||||
|
> div
|
||||||
|
margin-right 0
|
||||||
|
|
||||||
|
@media (max-width 500px)
|
||||||
|
display block
|
||||||
|
|
||||||
|
> div:not(:last-child)
|
||||||
|
margin-bottom 16px
|
||||||
|
|
||||||
> .charts
|
> .charts
|
||||||
margin-bottom 16px
|
margin-bottom 16px
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div>
|
<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div>
|
||||||
<section class="fit-top">
|
<section class="fit-top">
|
||||||
|
<ui-horizon-group inputs>
|
||||||
<ui-input v-model="name">
|
<ui-input v-model="name">
|
||||||
<span>%i18n:@add-emoji.name%</span>
|
<span>%i18n:@add-emoji.name%</span>
|
||||||
<span slot="text">%i18n:@add-emoji.name-desc%</span>
|
<span slot="text">%i18n:@add-emoji.name-desc%</span>
|
||||||
@ -11,12 +12,37 @@
|
|||||||
<span>%i18n:@add-emoji.aliases%</span>
|
<span>%i18n:@add-emoji.aliases%</span>
|
||||||
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
|
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
|
||||||
</ui-input>
|
</ui-input>
|
||||||
|
</ui-horizon-group>
|
||||||
<ui-input v-model="url">
|
<ui-input v-model="url">
|
||||||
<span>%i18n:@add-emoji.url%</span>
|
<span>%i18n:@add-emoji.url%</span>
|
||||||
</ui-input>
|
</ui-input>
|
||||||
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button>
|
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button>
|
||||||
</section>
|
</section>
|
||||||
</ui-card>
|
</ui-card>
|
||||||
|
|
||||||
|
<ui-card>
|
||||||
|
<div slot="title">%fa:grin R% %i18n:@emojis.title%</div>
|
||||||
|
<section v-for="emoji in emojis">
|
||||||
|
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
|
||||||
|
<ui-horizon-group inputs>
|
||||||
|
<ui-input v-model="emoji.name">
|
||||||
|
<span>%i18n:@add-emoji.name%</span>
|
||||||
|
<span slot="text">%i18n:@add-emoji.name-desc%</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-input v-model="emoji.aliases">
|
||||||
|
<span>%i18n:@add-emoji.aliases%</span>
|
||||||
|
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
|
||||||
|
</ui-input>
|
||||||
|
</ui-horizon-group>
|
||||||
|
<ui-input v-model="emoji.url">
|
||||||
|
<span>%i18n:@add-emoji.url%</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-horizon-group>
|
||||||
|
<ui-button @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button>
|
||||||
|
<ui-button @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button>
|
||||||
|
</ui-horizon-group>
|
||||||
|
</section>
|
||||||
|
</ui-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -29,16 +55,54 @@ export default Vue.extend({
|
|||||||
name: '',
|
name: '',
|
||||||
url: '',
|
url: '',
|
||||||
aliases: '',
|
aliases: '',
|
||||||
|
emojis: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.fetchEmojis();
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
add() {
|
add() {
|
||||||
(this as any).api('admin/add-emoji', {
|
(this as any).api('admin/emoji/add', {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
url: this.url,
|
url: this.url,
|
||||||
aliases: this.aliases.split(' ')
|
aliases: this.aliases.split(' ')
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).os.apis.dialog({ text: `Added` });
|
(this as any).os.apis.dialog({ text: `Added` });
|
||||||
|
this.fetchEmojis();
|
||||||
|
}).catch(e => {
|
||||||
|
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchEmojis() {
|
||||||
|
(this as any).api('admin/emoji/list').then(emojis => {
|
||||||
|
emojis.forEach(e => e.aliases = (e.aliases || []).join(' '));
|
||||||
|
this.emojis = emojis;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateEmoji(emoji) {
|
||||||
|
(this as any).api('admin/emoji/update', {
|
||||||
|
id: emoji.id,
|
||||||
|
name: emoji.name,
|
||||||
|
url: emoji.url,
|
||||||
|
aliases: emoji.aliases.split(' ')
|
||||||
|
}).then(() => {
|
||||||
|
(this as any).os.apis.dialog({ text: `Updated` });
|
||||||
|
}).catch(e => {
|
||||||
|
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeEmoji(emoji) {
|
||||||
|
(this as any).api('admin/emoji/remove', {
|
||||||
|
id: emoji.id
|
||||||
|
}).then(() => {
|
||||||
|
(this as any).os.apis.dialog({ text: `Removed` });
|
||||||
|
this.fetchEmojis();
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||||
});
|
});
|
||||||
@ -46,3 +110,10 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.tumhkfkmgtvzljezfvmgkeurkfncshbe
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-admin">
|
<div class="mk-admin" :class="{ isMobile }">
|
||||||
<nav>
|
<header v-show="isMobile">
|
||||||
|
<button class="nav" @click="navOpend = true">%fa:bars%</button>
|
||||||
|
<span>MisskeyMyAdmin</span>
|
||||||
|
</header>
|
||||||
|
<div class="nav-backdrop"
|
||||||
|
v-if="navOpend && isMobile"
|
||||||
|
@click="navOpend = false"
|
||||||
|
@touchstart="navOpend = false"
|
||||||
|
></div>
|
||||||
|
<nav v-show="navOpend">
|
||||||
<div class="mi">
|
<div class="mi">
|
||||||
<img svg-inline src="../assets/header-icon.svg"/>
|
<img svg-inline src="../assets/header-icon.svg"/>
|
||||||
</div>
|
</div>
|
||||||
@ -49,6 +58,10 @@ import XAnnouncements from "./announcements.vue";
|
|||||||
import XHashtags from "./hashtags.vue";
|
import XHashtags from "./hashtags.vue";
|
||||||
import XUsers from "./users.vue";
|
import XUsers from "./users.vue";
|
||||||
|
|
||||||
|
// Detect the user agent
|
||||||
|
const ua = navigator.userAgent.toLowerCase();
|
||||||
|
const isMobile = /mobile|iphone|ipad|android/.test(ua);
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XDashboard,
|
XDashboard,
|
||||||
@ -58,10 +71,15 @@ export default Vue.extend({
|
|||||||
XHashtags,
|
XHashtags,
|
||||||
XUsers
|
XUsers
|
||||||
},
|
},
|
||||||
|
provide: {
|
||||||
|
isMobile
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
page: 'dashboard',
|
page: 'dashboard',
|
||||||
version
|
version,
|
||||||
|
isMobile,
|
||||||
|
navOpend: !isMobile
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -74,12 +92,46 @@ export default Vue.extend({
|
|||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
.mk-admin
|
.mk-admin
|
||||||
|
$headerHeight = 48px
|
||||||
|
|
||||||
display flex
|
display flex
|
||||||
height 100%
|
height 100%
|
||||||
|
|
||||||
|
> header
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
z-index 10000
|
||||||
|
width 100%
|
||||||
|
color var(--mobileHeaderFg)
|
||||||
|
background-color var(--mobileHeaderBg)
|
||||||
|
box-shadow 0 1px 0 rgba(#000, 0.075)
|
||||||
|
|
||||||
|
&, *
|
||||||
|
user-select none
|
||||||
|
|
||||||
|
> span
|
||||||
|
display block
|
||||||
|
line-height $headerHeight
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
> .nav
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
z-index 10001
|
||||||
|
padding 0
|
||||||
|
width $headerHeight
|
||||||
|
font-size 1.4em
|
||||||
|
line-height $headerHeight
|
||||||
|
border-right solid 1px rgba(#000, 0.1)
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
transition all 0.2s ease
|
||||||
|
|
||||||
> nav
|
> nav
|
||||||
position fixed
|
position fixed
|
||||||
z-index 10000
|
z-index 20001
|
||||||
top 0
|
top 0
|
||||||
left 0
|
left 0
|
||||||
width 250px
|
width 250px
|
||||||
@ -187,9 +239,22 @@ export default Vue.extend({
|
|||||||
border-bottom solid 16px transparent
|
border-bottom solid 16px transparent
|
||||||
border-left solid 16px transparent
|
border-left solid 16px transparent
|
||||||
|
|
||||||
|
> .nav-backdrop
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
z-index 20000
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background var(--mobileNavBackdrop)
|
||||||
|
|
||||||
> main
|
> main
|
||||||
width 100%
|
width 100%
|
||||||
padding 32px 32px 32px calc(32px + 250px)
|
padding 0 0 0 250px
|
||||||
max-width 1300px
|
max-width 1300px
|
||||||
|
|
||||||
|
&.isMobile
|
||||||
|
> main
|
||||||
|
padding $headerHeight 0 0 0
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="axbwjelsbymowqjyywpirzhdlszoncqs">
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%i18n:@banner-url%</div>
|
<div slot="title">%i18n:@banner-url%</div>
|
||||||
<section class="fit-top">
|
<section class="fit-top">
|
||||||
@ -60,3 +60,10 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.axbwjelsbymowqjyywpirzhdlszoncqs
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%i18n:@verify-user%</div>
|
<div slot="title">%i18n:@verify-user%</div>
|
||||||
<section class="fit-top">
|
<section class="fit-top">
|
||||||
@ -127,3 +127,10 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.ucnffhbtogqgscfmqcymwmmupoknpfsw
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -42,7 +42,7 @@ import Reversi from './games/reversi/reversi.vue';
|
|||||||
import welcomeTimeline from './welcome-timeline.vue';
|
import welcomeTimeline from './welcome-timeline.vue';
|
||||||
import uiInput from './ui/input.vue';
|
import uiInput from './ui/input.vue';
|
||||||
import uiButton from './ui/button.vue';
|
import uiButton from './ui/button.vue';
|
||||||
import uiButtonGroup from './ui/button-group.vue';
|
import uiHorizonGroup from './ui/horizon-group.vue';
|
||||||
import uiCard from './ui/card.vue';
|
import uiCard from './ui/card.vue';
|
||||||
import uiForm from './ui/form.vue';
|
import uiForm from './ui/form.vue';
|
||||||
import uiTextarea from './ui/textarea.vue';
|
import uiTextarea from './ui/textarea.vue';
|
||||||
@ -95,7 +95,7 @@ Vue.component('mk-reversi', Reversi);
|
|||||||
Vue.component('mk-welcome-timeline', welcomeTimeline);
|
Vue.component('mk-welcome-timeline', welcomeTimeline);
|
||||||
Vue.component('ui-input', uiInput);
|
Vue.component('ui-input', uiInput);
|
||||||
Vue.component('ui-button', uiButton);
|
Vue.component('ui-button', uiButton);
|
||||||
Vue.component('ui-button-group', uiButtonGroup);
|
Vue.component('ui-horizon-group', uiHorizonGroup);
|
||||||
Vue.component('ui-card', uiCard);
|
Vue.component('ui-card', uiCard);
|
||||||
Vue.component('ui-form', uiForm);
|
Vue.component('ui-form', uiForm);
|
||||||
Vue.component('ui-textarea', uiTextarea);
|
Vue.component('ui-textarea', uiTextarea);
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import Vue from 'vue';
|
|
||||||
export default Vue.extend({});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
|
|
||||||
display flex
|
|
||||||
|
|
||||||
> *
|
|
||||||
flex 1
|
|
||||||
|
|
||||||
&:not(:last-child)
|
|
||||||
margin-right 16px
|
|
||||||
</style>
|
|
@ -1,5 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr" :is="link ? 'a' : 'button'" :class="[styl, { inline, primary }]" :type="type" @click="$emit('click')">
|
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr"
|
||||||
|
:is="link ? 'a' : 'button'"
|
||||||
|
:class="[styl, { inline, primary }]"
|
||||||
|
:type="type"
|
||||||
|
@click="$emit('click')"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
@ -7,6 +12,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
inject: ['horizonGrouped'],
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -20,7 +26,9 @@ export default Vue.extend({
|
|||||||
inline: {
|
inline: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default(): boolean {
|
||||||
|
return this.horizonGrouped;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
35
src/client/app/common/views/components/ui/horizon-group.vue
Normal file
35
src/client/app/common/views/components/ui/horizon-group.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze" :class="{ inputs }">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
export default Vue.extend({
|
||||||
|
provide: {
|
||||||
|
horizonGrouped: true
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
inputs: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
|
||||||
|
display flex
|
||||||
|
|
||||||
|
&.inputs
|
||||||
|
margin 32px 0
|
||||||
|
|
||||||
|
> *
|
||||||
|
flex 1
|
||||||
|
|
||||||
|
&:not(:last-child)
|
||||||
|
margin-right 16px
|
||||||
|
</style>
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ui-input" :class="[{ focused, filled }, styl]">
|
<div class="ui-input" :class="[{ focused, filled, inline }, styl]">
|
||||||
<div class="icon" ref="icon"><slot name="icon"></slot></div>
|
<div class="icon" ref="icon"><slot name="icon"></slot></div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
|
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
|
||||||
@ -41,6 +41,7 @@ import Vue from 'vue';
|
|||||||
const getPasswordStrength = require('syuilo-password-strength');
|
const getPasswordStrength = require('syuilo-password-strength');
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
inject: ['horizonGrouped'],
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
required: false
|
required: false
|
||||||
@ -72,6 +73,13 @@ export default Vue.extend({
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
inline: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default(): boolean {
|
||||||
|
return this.horizonGrouped;
|
||||||
|
}
|
||||||
|
},
|
||||||
styl: {
|
styl: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
@ -337,4 +345,8 @@ root(fill)
|
|||||||
&:not(.fill)
|
&:not(.fill)
|
||||||
root(false)
|
root(false)
|
||||||
|
|
||||||
|
&.inline
|
||||||
|
display inline-block
|
||||||
|
margin 0
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="p.emojis"/>
|
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="note.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -215,5 +215,11 @@
|
|||||||
reversiGameEmptyCell: ':lighten<2<$secondary',
|
reversiGameEmptyCell: ':lighten<2<$secondary',
|
||||||
reversiGameEmptyCellMyTurn: ':lighten<5<$secondary',
|
reversiGameEmptyCellMyTurn: ':lighten<5<$secondary',
|
||||||
reversiGameEmptyCellCanPut: ':lighten<4<$secondary',
|
reversiGameEmptyCellCanPut: ':lighten<4<$secondary',
|
||||||
|
|
||||||
|
adminDashboardHeaderFg: ':alpha<0.9<$text',
|
||||||
|
adminDashboardHeaderBorder: 'rgba(0, 0, 0, 0.3)',
|
||||||
|
adminDashboardCardBg: '$secondary',
|
||||||
|
adminDashboardCardFg: '$text',
|
||||||
|
adminDashboardCardDivider: 'rgba(0, 0, 0, 0.3)',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -215,5 +215,11 @@
|
|||||||
reversiGameEmptyCell: 'rgba(0, 0, 0, 0.06)',
|
reversiGameEmptyCell: 'rgba(0, 0, 0, 0.06)',
|
||||||
reversiGameEmptyCellMyTurn: 'rgba(0, 0, 0, 0.12)',
|
reversiGameEmptyCellMyTurn: 'rgba(0, 0, 0, 0.12)',
|
||||||
reversiGameEmptyCellCanPut: 'rgba(0, 0, 0, 0.9)',
|
reversiGameEmptyCellCanPut: 'rgba(0, 0, 0, 0.9)',
|
||||||
|
|
||||||
|
adminDashboardHeaderFg: ':alpha<0.9<$text',
|
||||||
|
adminDashboardHeaderBorder: 'rgba(0, 0, 0, 0.1)',
|
||||||
|
adminDashboardCardBg: '$secondary',
|
||||||
|
adminDashboardCardFg: '$text',
|
||||||
|
adminDashboardCardDivider: 'rgba(0, 0, 0, 0.082)',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
|
||||||
const Emoji = db.get<IEmoji>('emoji');
|
const Emoji = db.get<IEmoji>('emoji');
|
||||||
@ -8,20 +9,10 @@ Emoji.createIndex(['name', 'host'], { unique: true });
|
|||||||
export default Emoji;
|
export default Emoji;
|
||||||
|
|
||||||
export type IEmoji = {
|
export type IEmoji = {
|
||||||
|
_id: mongo.ObjectID;
|
||||||
name: string;
|
name: string;
|
||||||
host: string;
|
host: string;
|
||||||
url: string;
|
url: string;
|
||||||
aliases?: string[];
|
aliases?: string[];
|
||||||
updatedAt?: Date;
|
updatedAt?: Date;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const packEmojis = async (
|
|
||||||
host: string,
|
|
||||||
// MeiTODO: filter
|
|
||||||
) => {
|
|
||||||
return await Emoji.find({ host }, {
|
|
||||||
fields: {
|
|
||||||
_id: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
@ -12,7 +12,7 @@ import { packMany as packFileMany, IDriveFile } from './drive-file';
|
|||||||
import Favorite from './favorite';
|
import Favorite from './favorite';
|
||||||
import Following from './following';
|
import Following from './following';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { packEmojis } from './emoji';
|
import Emoji from './emoji';
|
||||||
|
|
||||||
const Note = db.get<INote>('notes');
|
const Note = db.get<INote>('notes');
|
||||||
Note.createIndex('uri', { sparse: true, unique: true });
|
Note.createIndex('uri', { sparse: true, unique: true });
|
||||||
@ -50,6 +50,7 @@ export type INote = {
|
|||||||
text: string;
|
text: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
tagsLower: string[];
|
tagsLower: string[];
|
||||||
|
emojis: string[];
|
||||||
cw: string;
|
cw: string;
|
||||||
userId: mongo.ObjectID;
|
userId: mongo.ObjectID;
|
||||||
appId: mongo.ObjectID;
|
appId: mongo.ObjectID;
|
||||||
@ -231,7 +232,22 @@ export const pack = async (
|
|||||||
|
|
||||||
// _note._userを消す前か、_note.userを解決した後でないとホストがわからない
|
// _note._userを消す前か、_note.userを解決した後でないとホストがわからない
|
||||||
if (_note._user) {
|
if (_note._user) {
|
||||||
_note.emojis = packEmojis(_note._user.host);
|
const host = _note._user.host;
|
||||||
|
// 互換性のため。(古いMisskeyではNoteにemojisが無い)
|
||||||
|
if (_note.emojis == null) {
|
||||||
|
_note.emojis = Emoji.find({
|
||||||
|
host: host
|
||||||
|
}, {
|
||||||
|
fields: { _id: false }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_note.emojis = Emoji.find({
|
||||||
|
name: { $in: _note.emojis },
|
||||||
|
host: host
|
||||||
|
}, {
|
||||||
|
fields: { _id: false }
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename _id to id
|
// Rename _id to id
|
||||||
|
@ -4,7 +4,7 @@ import parse from '../../../mfm/parse';
|
|||||||
|
|
||||||
export default function(note: INote) {
|
export default function(note: INote) {
|
||||||
let html = toHtml(parse(note.text), note.mentionedRemoteUsers);
|
let html = toHtml(parse(note.text), note.mentionedRemoteUsers);
|
||||||
if (html == null) html = '';
|
if (html == null) html = '<p>.</p>';
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import Emoji from '../../../../models/emoji';
|
import Emoji from '../../../../../models/emoji';
|
||||||
import define from '../../define';
|
import define from '../../../define';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -28,6 +28,7 @@ export const meta = {
|
|||||||
|
|
||||||
export default define(meta, (ps) => new Promise(async (res, rej) => {
|
export default define(meta, (ps) => new Promise(async (res, rej) => {
|
||||||
await Emoji.insert({
|
await Emoji.insert({
|
||||||
|
updatedAt: new Date(),
|
||||||
name: ps.name,
|
name: ps.name,
|
||||||
host: null,
|
host: null,
|
||||||
aliases: ps.aliases,
|
aliases: ps.aliases,
|
33
src/server/api/endpoints/admin/emoji/list.ts
Normal file
33
src/server/api/endpoints/admin/emoji/list.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import Emoji from '../../../../../models/emoji';
|
||||||
|
import define from '../../../define';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
desc: {
|
||||||
|
'ja-JP': 'カスタム絵文字を取得します。'
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
requireAdmin: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
host: {
|
||||||
|
validator: $.str.optional.nullable,
|
||||||
|
default: null as any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps) => new Promise(async (res, rej) => {
|
||||||
|
const emojis = await Emoji.find({
|
||||||
|
host: ps.host
|
||||||
|
});
|
||||||
|
|
||||||
|
res(emojis.map(e => ({
|
||||||
|
id: e._id,
|
||||||
|
name: e.name,
|
||||||
|
aliases: e.aliases,
|
||||||
|
host: e.host,
|
||||||
|
url: e.url
|
||||||
|
})));
|
||||||
|
}));
|
31
src/server/api/endpoints/admin/emoji/remove.ts
Normal file
31
src/server/api/endpoints/admin/emoji/remove.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import Emoji from '../../../../../models/emoji';
|
||||||
|
import define from '../../../define';
|
||||||
|
import ID from '../../../../../misc/cafy-id';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
desc: {
|
||||||
|
'ja-JP': 'カスタム絵文字を削除します。'
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
requireAdmin: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
id: {
|
||||||
|
validator: $.type(ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps) => new Promise(async (res, rej) => {
|
||||||
|
const emoji = await Emoji.findOne({
|
||||||
|
_id: ps.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (emoji == null) return rej('emoji not found');
|
||||||
|
|
||||||
|
await Emoji.remove({ _id: emoji._id });
|
||||||
|
|
||||||
|
res();
|
||||||
|
}));
|
50
src/server/api/endpoints/admin/emoji/update.ts
Normal file
50
src/server/api/endpoints/admin/emoji/update.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import Emoji from '../../../../../models/emoji';
|
||||||
|
import define from '../../../define';
|
||||||
|
import ID from '../../../../../misc/cafy-id';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
desc: {
|
||||||
|
'ja-JP': 'カスタム絵文字を更新します。'
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
requireAdmin: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
id: {
|
||||||
|
validator: $.type(ID)
|
||||||
|
},
|
||||||
|
|
||||||
|
name: {
|
||||||
|
validator: $.str
|
||||||
|
},
|
||||||
|
|
||||||
|
url: {
|
||||||
|
validator: $.str
|
||||||
|
},
|
||||||
|
|
||||||
|
aliases: {
|
||||||
|
validator: $.arr($.str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps) => new Promise(async (res, rej) => {
|
||||||
|
const emoji = await Emoji.findOne({
|
||||||
|
_id: ps.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (emoji == null) return rej('emoji not found');
|
||||||
|
|
||||||
|
await Emoji.update({ _id: emoji._id }, {
|
||||||
|
$set: {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
name: ps.name,
|
||||||
|
aliases: ps.aliases,
|
||||||
|
url: ps.url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res();
|
||||||
|
}));
|
@ -21,7 +21,7 @@ export const meta = {
|
|||||||
|
|
||||||
export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
||||||
const x: any = {};
|
const x: any = {};
|
||||||
x[`clientSettings.${name}`] = ps.value;
|
x[`clientSettings.${ps.name}`] = ps.value;
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: x
|
$set: x
|
||||||
@ -31,7 +31,7 @@ export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
|||||||
|
|
||||||
// Publish event
|
// Publish event
|
||||||
publishMainStream(user._id, 'clientSettingUpdated', {
|
publishMainStream(user._id, 'clientSettingUpdated', {
|
||||||
key: name,
|
key: ps.name,
|
||||||
value: ps.value
|
value: ps.value
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -30,6 +30,7 @@ import { erase, unique } from '../../prelude/array';
|
|||||||
import insertNoteUnread from './unread';
|
import insertNoteUnread from './unread';
|
||||||
import registerInstance from '../register-instance';
|
import registerInstance from '../register-instance';
|
||||||
import Instance from '../../models/instance';
|
import Instance from '../../models/instance';
|
||||||
|
import { TextElementEmoji } from '../../mfm/parse/elements/emoji';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
@ -146,6 +147,8 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
|
|||||||
|
|
||||||
const tags = extractHashtags(tokens);
|
const tags = extractHashtags(tokens);
|
||||||
|
|
||||||
|
const emojis = extractEmojis(tokens);
|
||||||
|
|
||||||
const mentionedUsers = await extractMentionedUsers(tokens);
|
const mentionedUsers = await extractMentionedUsers(tokens);
|
||||||
|
|
||||||
if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) {
|
if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) {
|
||||||
@ -160,7 +163,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = await insertNote(user, data, tags, mentionedUsers);
|
const note = await insertNote(user, data, tags, emojis, mentionedUsers);
|
||||||
|
|
||||||
res(note);
|
res(note);
|
||||||
|
|
||||||
@ -371,7 +374,7 @@ async function publish(user: IUser, note: INote, noteObj: any, reply: INote, ren
|
|||||||
publishToUserLists(note, noteObj);
|
publishToUserLists(note, noteObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertNote(user: IUser, data: Option, tags: string[], mentionedUsers: IUser[]) {
|
async function insertNote(user: IUser, data: Option, tags: string[], emojis: string[], mentionedUsers: IUser[]) {
|
||||||
const insert: any = {
|
const insert: any = {
|
||||||
createdAt: data.createdAt,
|
createdAt: data.createdAt,
|
||||||
fileIds: data.files ? data.files.map(file => file._id) : [],
|
fileIds: data.files ? data.files.map(file => file._id) : [],
|
||||||
@ -382,6 +385,7 @@ async function insertNote(user: IUser, data: Option, tags: string[], mentionedUs
|
|||||||
cw: data.cw == null ? null : data.cw,
|
cw: data.cw == null ? null : data.cw,
|
||||||
tags,
|
tags,
|
||||||
tagsLower: tags.map(tag => tag.toLowerCase()),
|
tagsLower: tags.map(tag => tag.toLowerCase()),
|
||||||
|
emojis,
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
viaMobile: data.viaMobile,
|
viaMobile: data.viaMobile,
|
||||||
geo: data.geo || null,
|
geo: data.geo || null,
|
||||||
@ -449,6 +453,16 @@ function extractHashtags(tokens: ReturnType<typeof parse>): string[] {
|
|||||||
return unique(hashtags);
|
return unique(hashtags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractEmojis(tokens: ReturnType<typeof parse>): string[] {
|
||||||
|
// Extract emojis
|
||||||
|
const emojis = tokens
|
||||||
|
.filter(t => t.type == 'emoji')
|
||||||
|
.map(t => (t as TextElementEmoji).emoji)
|
||||||
|
.filter(emoji => emoji.length <= 100);
|
||||||
|
|
||||||
|
return unique(emojis);
|
||||||
|
}
|
||||||
|
|
||||||
function index(note: INote) {
|
function index(note: INote) {
|
||||||
if (note.text == null || config.elasticsearch == null) return;
|
if (note.text == null || config.elasticsearch == null) return;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user