Compare commits

...

83 Commits

Author SHA1 Message Date
syuilo
c52e30e8e0 Merge branch 'develop' 2021-08-08 23:25:21 +09:00
syuilo
0cb04ded36 12.85.0 2021-08-08 23:25:13 +09:00
syuilo
6cfad65ac7 🎨 2021-08-08 21:59:18 +09:00
syuilo
ed20805b10 New Crowdin updates (#7616)
* New translations troubleshooting.md (Indonesian)

* New translations troubleshooting.md (Chinese Traditional)

* New translations troubleshooting.md (German)

* New translations troubleshooting.md (Chinese Simplified)

* New translations troubleshooting.md (Ukrainian)

* New translations troubleshooting.md (Russian)

* New translations troubleshooting.md (Portuguese)

* New translations troubleshooting.md (Polish)

* New translations troubleshooting.md (Norwegian)

* New translations troubleshooting.md (Dutch)

* New translations troubleshooting.md (Korean)

* New translations troubleshooting.md (Italian)

* New translations report-issue.md (Korean)

* New translations report-issue.md (German)

* New translations links.md (Portuguese)

* New translations links.md (Kannada)

* New translations misskey.md (German)

* New translations misskey.md (Danish)

* New translations misskey.md (Czech)

* New translations misskey.md (Arabic)

* New translations misskey.md (Spanish)

* New translations misskey.md (French)

* New translations links.md (Japanese, Kansai)

* New translations links.md (Kabyle)

* New translations links.md (Haitian Creole)

* New translations links.md (Lojban)

* New translations misskey.md (Korean)

* New translations links.md (Uyghur)

* New translations links.md (Esperanto)

* New translations links.md (Thai)

* New translations links.md (Indonesian)

* New translations links.md (English)

* New translations links.md (Chinese Traditional)

* New translations links.md (Chinese Simplified)

* New translations links.md (Ukrainian)

* New translations links.md (Russian)

* New translations misskey.md (Italian)

* New translations misskey.md (Dutch)

* New translations report-issue.md (Danish)

* New translations misskey.md (Uyghur)

* New translations report-issue.md (Czech)

* New translations report-issue.md (Arabic)

* New translations report-issue.md (Spanish)

* New translations report-issue.md (French)

* New translations misskey.md (Japanese, Kansai)

* New translations misskey.md (Kabyle)

* New translations misskey.md (Haitian Creole)

* New translations misskey.md (Kannada)

* New translations misskey.md (Lojban)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Norwegian)

* New translations misskey.md (Thai)

* New translations misskey.md (Indonesian)

* New translations misskey.md (English)

* New translations misskey.md (Chinese Traditional)

* New translations misskey.md (Chinese Simplified)

* New translations misskey.md (Ukrainian)

* New translations misskey.md (Russian)

* New translations misskey.md (Portuguese)

* New translations misskey.md (Polish)

* New translations widgets.md (Lojban)

* New translations reaction.md (Polish)

* New translations widgets.md (Esperanto)

* New translations pages.md (Esperanto)

* New translations reaction.md (Spanish)

* New translations reaction.md (French)

* New translations pages.md (Japanese, Kansai)

* New translations pages.md (Kabyle)

* New translations pages.md (Haitian Creole)

* New translations pages.md (Kannada)

* New translations pages.md (Lojban)

* New translations pages.md (Uyghur)

* New translations pages.md (Thai)

* New translations reaction.md (Czech)

* New translations pages.md (Indonesian)

* New translations pages.md (English)

* New translations pages.md (Chinese Traditional)

* New translations pages.md (Chinese Simplified)

* New translations pages.md (Ukrainian)

* New translations pages.md (Russian)

* New translations pages.md (Portuguese)

* New translations pages.md (Polish)

* New translations pages.md (Norwegian)

* New translations reaction.md (Arabic)

* New translations reaction.md (Danish)

* New translations pages.md (Korean)

* New translations reaction.md (Indonesian)

* New translations silence.md (French)

* New translations reaction.md (Japanese, Kansai)

* New translations reaction.md (Kabyle)

* New translations reaction.md (Haitian Creole)

* New translations reaction.md (Kannada)

* New translations reaction.md (Lojban)

* New translations reaction.md (Uyghur)

* New translations reaction.md (Esperanto)

* New translations reaction.md (Thai)

* New translations reaction.md (English)

* New translations reaction.md (German)

* New translations reaction.md (Chinese Traditional)

* New translations reaction.md (Chinese Simplified)

* New translations reaction.md (Ukrainian)

* New translations reaction.md (Russian)

* New translations reaction.md (Portuguese)

* New translations reaction.md (Norwegian)

* New translations reaction.md (Dutch)

* New translations reaction.md (Korean)

* New translations reaction.md (Italian)

* New translations pages.md (Dutch)

* New translations pages.md (Italian)

* New translations silence.md (Arabic)

* New translations mute.md (Kabyle)

* New translations note.md (Italian)

* New translations note.md (German)

* New translations note.md (Danish)

* New translations note.md (Czech)

* New translations note.md (Arabic)

* New translations note.md (Spanish)

* New translations note.md (French)

* New translations mute.md (Japanese, Kansai)

* New translations mute.md (Haitian Creole)

* New translations note.md (Dutch)

* New translations mute.md (Kannada)

* New translations mute.md (Lojban)

* New translations mute.md (Uyghur)

* New translations mute.md (Esperanto)

* New translations mute.md (Thai)

* New translations mute.md (Indonesian)

* New translations mute.md (English)

* New translations mute.md (Chinese Traditional)

* New translations mute.md (Chinese Simplified)

* New translations note.md (Korean)

* New translations note.md (Norwegian)

* New translations pages.md (German)

* New translations note.md (Lojban)

* New translations pages.md (Danish)

* New translations pages.md (Czech)

* New translations pages.md (Arabic)

* New translations pages.md (Spanish)

* New translations pages.md (French)

* New translations note.md (Japanese, Kansai)

* New translations note.md (Kabyle)

* New translations note.md (Haitian Creole)

* New translations note.md (Kannada)

* New translations note.md (Uyghur)

* New translations note.md (Polish)

* New translations note.md (Esperanto)

* New translations note.md (Thai)

* New translations note.md (Indonesian)

* New translations note.md (English)

* New translations note.md (Chinese Traditional)

* New translations note.md (Chinese Simplified)

* New translations note.md (Ukrainian)

* New translations note.md (Russian)

* New translations note.md (Portuguese)

* New translations silence.md (Spanish)

* New translations silence.md (Czech)

* New translations widgets.md (Thai)

* New translations timeline.md (Portuguese)

* New translations timeline.md (Esperanto)

* New translations timeline.md (Thai)

* New translations timeline.md (Indonesian)

* New translations timeline.md (English)

* New translations timeline.md (Chinese Traditional)

* New translations timeline.md (Chinese Simplified)

* New translations timeline.md (Ukrainian)

* New translations timeline.md (Russian)

* New translations timeline.md (Polish)

* New translations timeline.md (Lojban)

* New translations timeline.md (Norwegian)

* New translations timeline.md (Dutch)

* New translations timeline.md (Korean)

* New translations timeline.md (Italian)

* New translations timeline.md (German)

* New translations timeline.md (Danish)

* New translations timeline.md (Czech)

* New translations timeline.md (Arabic)

* New translations timeline.md (Spanish)

* New translations timeline.md (Uyghur)

* New translations timeline.md (Kannada)

* New translations theme.md (Japanese, Kansai)

* New translations widgets.md (Dutch)

* New translations widgets.md (Indonesian)

* New translations widgets.md (English)

* New translations widgets.md (Chinese Traditional)

* New translations widgets.md (Chinese Simplified)

* New translations widgets.md (Ukrainian)

* New translations widgets.md (Russian)

* New translations widgets.md (Portuguese)

* New translations widgets.md (Polish)

* New translations widgets.md (Norwegian)

* New translations widgets.md (Korean)

* New translations timeline.md (Haitian Creole)

* New translations widgets.md (Italian)

* New translations widgets.md (German)

* New translations widgets.md (Danish)

* New translations widgets.md (Czech)

* New translations widgets.md (Arabic)

* New translations widgets.md (Spanish)

* New translations widgets.md (French)

* New translations timeline.md (Japanese, Kansai)

* New translations timeline.md (Kabyle)

* New translations timeline.md (French)

* New translations theme.md (Kabyle)

* New translations silence.md (Danish)

* New translations silence.md (Chinese Traditional)

* New translations silence.md (Kabyle)

* New translations silence.md (Haitian Creole)

* New translations silence.md (Kannada)

* New translations silence.md (Lojban)

* New translations silence.md (Uyghur)

* New translations silence.md (Esperanto)

* New translations silence.md (Thai)

* New translations silence.md (Indonesian)

* New translations silence.md (English)

* New translations silence.md (Chinese Simplified)

* New translations theme.md (French)

* New translations silence.md (Ukrainian)

* New translations silence.md (Russian)

* New translations silence.md (Portuguese)

* New translations silence.md (Polish)

* New translations silence.md (Norwegian)

* New translations silence.md (Dutch)

* New translations silence.md (Korean)

* New translations silence.md (Italian)

* New translations silence.md (German)

* New translations silence.md (Japanese, Kansai)

* New translations theme.md (Spanish)

* New translations theme.md (Haitian Creole)

* New translations theme.md (Ukrainian)

* New translations theme.md (Kannada)

* New translations theme.md (Lojban)

* New translations theme.md (Uyghur)

* New translations theme.md (Esperanto)

* New translations theme.md (Thai)

* New translations theme.md (Indonesian)

* New translations theme.md (English)

* New translations theme.md (Chinese Traditional)

* New translations theme.md (Chinese Simplified)

* New translations theme.md (Russian)

* New translations theme.md (Arabic)

* New translations theme.md (Portuguese)

* New translations theme.md (Polish)

* New translations theme.md (Norwegian)

* New translations theme.md (Dutch)

* New translations theme.md (Korean)

* New translations theme.md (Italian)

* New translations theme.md (German)

* New translations theme.md (Danish)

* New translations theme.md (Czech)

* New translations troubleshooting.md (Japanese, Kansai)
2021-08-08 21:39:45 +09:00
syuilo
576303cd72 Update crowdin.yml 2021-08-08 18:57:07 +09:00
syuilo
0062e084f8 New Crowdin updates (#7614)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

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

* New translations ja-JP.yml (Kabyle)

* New translations ja-JP.yml (Kabyle)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Indonesian)

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

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

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Japanese, Kansai)
2021-08-08 18:55:15 +09:00
syuilo
b90d76dcfe Update links.md 2021-08-08 18:47:57 +09:00
syuilo
c95619b2bf Update ja-JP.yml 2021-08-08 17:23:16 +09:00
syuilo
82150bd5b8 🎨 2021-08-08 16:30:30 +09:00
syuilo
9e03335ff8 Improve client 2021-08-08 13:02:58 +09:00
syuilo
b3c5c3f0ea Improve usability 2021-08-08 12:45:44 +09:00
syuilo
65858dab3e Improve client 2021-08-08 12:19:10 +09:00
syuilo
c968633d15 Update misskey.md 2021-08-07 23:43:42 +09:00
syuilo
39a8942daf 🎨 2021-08-07 22:06:50 +09:00
syuilo
7705a7928e fix bug that docs not loading 2021-08-07 20:39:27 +09:00
syuilo
d2c14b844e New Crowdin updates (#7610)
* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations mute.md (Esperanto)

* New translations stream.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations keyboard-shortcut.md (Esperanto)

* New translations timelines.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations follow.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations custom-emoji.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

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

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

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

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Indonesian)

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

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

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

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

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

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Indonesian)

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

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

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Indonesian)

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

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

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)
2021-08-07 19:25:54 +09:00
syuilo
3e45e6c165 Clean up 2021-08-07 19:21:17 +09:00
syuilo
fe8334931f user page 🎨 2021-08-07 19:19:43 +09:00
syuilo
f565c5f730 Improve chat UI (wip) 2021-08-07 19:19:31 +09:00
syuilo
c03e2febb0 🎨 2021-08-07 19:09:06 +09:00
syuilo
c2f4fb7ba7 Update troubleshooting.md 2021-08-07 18:10:33 +09:00
syuilo
5f869e5d87 Improve client 2021-08-07 17:55:16 +09:00
syuilo
65f1afc4e0 Improve docs 2021-08-07 16:54:51 +09:00
syuilo
aec2762bf1 🎨 2021-08-07 16:12:42 +09:00
syuilo
a41144a00f Improve docs 2021-08-07 15:13:38 +09:00
syuilo
aa28e8a7a6 Update stream.md 2021-08-07 14:42:51 +09:00
syuilo
a1a51ce518 Improve docs 2021-08-07 14:05:12 +09:00
syuilo
90999e0ef9 Improve docs 2021-08-07 13:56:18 +09:00
syuilo
2ceeb17056 Add doc for admin 2021-08-07 13:41:14 +09:00
syuilo
18afdd6040 Improve docs 2021-08-07 13:35:18 +09:00
syuilo
b9972ec6bd 🎨 2021-08-07 13:19:00 +09:00
syuilo
ebb53e87f3 ハッシュタグ入力エリア
Resolve #7600
2021-08-07 12:47:01 +09:00
syuilo
9f9d7325fd インスタンス一覧ページ 2021-08-07 10:24:50 +09:00
syuilo
742a005523 カスタム絵文字一覧ページ 2021-08-07 10:23:59 +09:00
syuilo
3a28c06534 🎨 2021-08-06 22:47:26 +09:00
syuilo
46d5711071 🎨 2021-08-06 22:29:19 +09:00
syuilo
48113f3afd Improve doc 2021-08-06 14:28:40 +09:00
syuilo
be29972ddf Update doc.vue 2021-08-06 13:55:26 +09:00
syuilo
49b3a83f76 Improve docs 2021-08-06 11:04:17 +09:00
syuilo
342794c728 Update mfm.md 2021-08-06 10:49:04 +09:00
syuilo
3739638c81 Improve docs 2021-08-06 03:28:47 +09:00
syuilo
401351d9c8 Improve docs 2021-08-06 02:38:45 +09:00
syuilo
6073a03967 Improve docs 2021-08-06 00:33:25 +09:00
syuilo
3e3d294188 Improve docs 2021-08-06 00:17:40 +09:00
syuilo
f6f96ae5bf Imorive client 2021-08-05 22:43:14 +09:00
syuilo
62ccb53c24 Add rainbow function for MFM 2021-08-05 21:55:41 +09:00
syuilo
e410e22980 Update misskey.md 2021-08-05 18:46:43 +09:00
syuilo
fc5ceea335 Improve doc 2021-08-05 18:34:59 +09:00
syuilo
38af8d4737 Update glossary.md 2021-08-05 16:34:24 +09:00
syuilo
33b0cab596 refactor 2021-08-05 16:34:18 +09:00
syuilo
2a47e4a1e1 Update misskey.md 2021-08-05 16:29:34 +09:00
syuilo
46f53868c5 Improve docs 2021-08-05 16:04:31 +09:00
syuilo
eac7f11aa7 Update glossary.md 2021-08-05 15:48:12 +09:00
syuilo
e219188f46 Update misskey.md 2021-08-05 15:38:20 +09:00
syuilo
3df8c701a7 Improve docs 2021-08-05 15:19:55 +09:00
syuilo
1186813c75 Update glossary.md 2021-08-05 15:08:10 +09:00
syuilo
645b6fdc8a Improve docs 2021-08-05 13:58:44 +09:00
syuilo
ae0596a729 improve docs 2021-08-05 13:43:57 +09:00
syuilo
bb5fd3c1f2 Update misskey.md 2021-08-05 13:02:44 +09:00
syuilo
532fa9c5f9 🎨 2021-08-05 12:20:27 +09:00
syuilo
80a4aa6fa6 Update misskey.md 2021-08-05 12:20:21 +09:00
syuilo
4f218f544f Update misskey.md 2021-08-05 12:14:14 +09:00
syuilo
f261f8d7d1 Update misskey.md 2021-08-05 10:45:19 +09:00
syuilo
e044d11782 Improve docs 2021-08-05 00:15:51 +09:00
syuilo
d2da459dd8 refactor 2021-08-01 14:45:40 +09:00
syuilo
b1e6a33d6b tweak style 2021-07-29 23:59:45 +09:00
syuilo
0d276d0d61 Improve usability 2021-07-29 17:10:16 +09:00
syuilo
998936651a fix style 2021-07-28 14:46:25 +09:00
syuilo
1bec25e8e6 パスワードリセットしても新しいパスワードが表示されない問題を修正 2021-07-28 14:45:56 +09:00
syuilo
f220e4183f 🎨 2021-07-27 21:37:32 +09:00
syuilo
e965b57dc2 Update PULL_REQUEST_TEMPLATE.md 2021-07-27 00:01:21 +09:00
syuilo
5e6e1e237a Merge branch 'develop' 2021-07-26 11:15:42 +09:00
syuilo
41fe364b49 12.84.3 2021-07-26 11:15:33 +09:00
syuilo
2953ba17c3 ストリーミングが不安定な問題を修正 2021-07-26 11:12:06 +09:00
syuilo
f3b3e06329 fix email notification bug 2021-07-25 13:28:33 +09:00
syuilo
98249942d5 fix bug 2021-07-25 13:07:08 +09:00
syuilo
0fc8445425 🎨 2021-07-25 12:55:17 +09:00
syuilo
943a1940e2 Merge branch 'develop' 2021-07-23 22:43:47 +09:00
syuilo
15d166e30e 12.84.2 2021-07-23 22:43:34 +09:00
syuilo
83619fda98 revert vue to 3.1.x 2021-07-23 22:43:24 +09:00
syuilo
12913a16fd Merge branch 'develop' 2021-07-23 21:37:09 +09:00
syuilo
e23ad7833d 12.84.1 2021-07-23 21:36:32 +09:00
syuilo
38aa760b57 update vue 2021-07-23 21:36:30 +09:00
1030 changed files with 36530 additions and 2626 deletions

View File

@@ -1,13 +1,32 @@
## Summary
<!-- お読みください
PRありがとうございます PRを作成する前に、以下をご確認ください:
可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。
fix / refactor / feat / enhance / perf / chore
また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。
このPRによって解決されるIssueがある場合は、そのIssue IDを本文内に記入してください。
CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。
機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。
ご協力ありがとうございます🤗
-->
<!-- README
Thank you for your PR! Before creating a PR, please check the following:
If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
fix / refactor / feat / enhance / perf / chore
Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
If there is an issue to be resolved by this PR, please include the Issue ID in the text.
Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring.
If you have added a feature or fixed a bug, please add a test case if possible.
Thanks for your cooperation 🤗
-->
<!--
-
- * Please describe your changes here *
-
- If you are going to resolve some issue, please add this context.
- Resolve #ISSUE_NUMBER
-
- If you are going to fix some bug issue, please add this context.
- Fix #ISSUE_NUMBER
-
-->
# What
<!-- このPRで何をしたのか どう変わるのか? -->
<!-- What did you do with this PR? How will it change things? -->
# Why
<!-- なぜそうするのか? どういう意図なのか? 何が困っているのか? -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
# Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->

View File

@@ -242,6 +242,9 @@ npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
作成されたスクリプトは不必要な変更を含むため除去してください。
### コネクションには`markRaw`せよ
**Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。
## その他
### HTMLのクラス名で follow という単語は使わない
広告ブロッカーで誤ってブロックされる

View File

@@ -2,6 +2,6 @@ files:
- source: /locales/ja-JP.yml
translation: /locales/%locale%.yml
update_option: update_as_unapproved
- source: /src/docs/ja-JP/*.md
translation: /src/docs/%locale%/%original_file_name%
- source: /src/docs/ja-JP/**/*.md
translation: /src/docs/%locale%/**/%original_file_name%
update_option: update_as_unapproved

View File

@@ -427,9 +427,13 @@ inUse: "مستخدم"
info: "عن"
user: "المستخدمون"
administration: "إدارة "
postToGallery: "انشر في المعرض"
gallery: "المعرض"
expiration: "ينتهي استطلاع الرأي في"
middle: "متوسط"
global: "الشامل"
_docs:
admin: "إدارة "
_email:
_follow:
title: "يتابعك"

View File

@@ -111,6 +111,7 @@ editWidgets: "Upravit widget"
editWidgetsExit: "Hotovo"
customEmojis: "Vlastní emoji"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Jméno emoji"
emojiUrl: "URL obrázku"
addEmoji: "Přidat emoji"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,19 @@
---
_lang_: "Esperanto"
headlineMisskey: "Reto ligiĝas per notoj"
introMisskey: "Bonvenon! Miskejo estas malferma kodaの分散型マイクロブログサービスです。\nBonvolu Krei「noto」、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「 reaktigoj 」機能で、皆のnotojに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
headlineMisskey: "Reto ligiĝanta per notoj"
introMisskey: "Bonvenon! Misskey (Ĉi-sekve Miskejo) estas malfermitkoda malcentriza mikrobloga servo.\nKreu \"noto\"n por ke kunhavu tion kio nun okazas aŭ ke eksendu tion kio pri vi📡\nFunkcion \"reago\" vi povas uzi kaj aldoni vian reagon pri ciu noto de ĉiu homo👍\nVolu esplori nova mondo🚀"
monthAndDay: "{day}-a/{month}"
search: "Serĉi"
notifications: "Sciigoj"
username: "Uzantonomo"
username: "Uzantnomo"
password: "Pasvorto"
forgotPassword: "Ĉu vi forgesis pasvorton?"
fetchingAsApObject: "Informpetado de fediverso..."
ok: "Okej"
fetchingAsApObject: "Informpetado de Fediverso..."
ok: "Akcepteble"
gotIt: "Mi konprenas!"
cancel: "Nuligi"
enterUsername: "Entajpu uzantonomon"
renotedBy: "Renotigojn faras {user}"
enterUsername: "Entajpu uzantnomon"
renotedBy: "Renoton faras {user}"
noNotes: "Neniu noto!"
noNotifications: "Vi ne havas sciigojn."
instance: "Ekzemplo"
@@ -22,7 +22,8 @@ basicSettings: "Ĝeneralaj agordoj"
otherSettings: "Aliaj agordoj"
openInWindow: "Malfermi en nova fenestro"
profile: "Profilo"
timeline: "Tempolinio"
timeline: "Templinio"
noAccountDescription: "Tiu uzanto ne enhavas biografion je la profilo."
login: "Ensaluti"
loggingIn: "Ensalutado..."
logout: "Elsaluti"
@@ -42,33 +43,34 @@ unpin: "Depingli"
copyContent: "Kopii enhavon"
copyLink: "Kopii ligilon"
delete: "Forviŝi"
deleteAndEdit: "Forviŝi kaj redakti"
deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forviŝi la noton? La reaktigoj, renotigoj, kaj respondoj ankaŭ forigiĝos."
addToList: "Aldoni al listo"
deleteAndEdit: "Foriginte redakti"
deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forigi la noton kaj redakti ĝin? Ĉiuj reagoj, renotoj, kaj respondoj ankaŭ foriĝos."
addToList: "Aldoni al la listo"
sendMessage: "Sendi mesaĝon"
copyUsername: "Kopii uzantonomon"
copyUsername: "Kopii uzantnomon"
searchUser: "Serĉi uzanton"
reply: "Respondi"
loadMore: "Vidu plu"
showMore: "Vidi plu"
youGotNewFollower: "Vi estas eksekvita."
loadMore: "Vidu pli"
showMore: "Vidi pli"
youGotNewFollower: "Vin eksekvis"
receiveFollowRequest: "Eksekvopeton riceviĝis."
followRequestAccepted: "La eksekvopeto akceptiĝis."
mention: "Mencioj"
mentions: "Mencioj"
directNotes: "Senperaj notoj"
mentions: "Al vi"
importAndExport: "Importaĵo / Eksportaĵo"
import: "Importi"
export: "Eksporti"
files: "Dosieroj"
download: "Elŝuti"
driveFileDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la dosieron \"{name}\"? La notoj kun la aldonaĵo ankaŭ forviŝiĝos."
unfollowConfirm: "Ĉu vi certas, ke vi volas ne plu sekvi {name}?"
driveFileDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la dosierujon {name}? Noto aldonita ĝin ankaŭ foriĝos."
unfollowConfirm: "Ĉu vi certas, ke vi volas ne plu sekvi {name}'(o)n?"
lists: "Listoj"
noLists: "Neniu listo"
note: "Elsendi noto"
notes: "Notoj"
following: "Sekvi"
following: "Sekvatoj"
followers: "Sekvantoj"
followsYou: "Sekvas vin"
followsYou: "Vin sekvas "
createList: "Kreii liston"
error: "Eraro"
somethingHappened: "Problemo okazis."
@@ -76,13 +78,15 @@ retry: "Reprovi"
enterListName: "Entajpu nomon de la listo"
privacy: "Privateco"
follow: "Sekvi"
followRequest: "Peti eksekvi"
followRequest: "Peti akcepti de vi eksekvi"
followRequests: "Eksekvopetoj"
unfollow: "Ne plu sekvi"
renote: "Renotici"
unrenote: "Forigi renotici"
cantRenote: "Tiu noto estas renototebla."
cantReRenote: "Renotigo ne estas renotigebla."
enterEmoji: "Entajpu emoĵion"
renote: "Fari renoton"
unrenote: "Malfari renoton"
renoted: "Renoton fariĝis."
cantRenote: "Tiu noto ne estas renototebla."
cantReRenote: "Oni ne povas fari renoton kiu enhavas renoto."
quote: "Citi"
pinnedNote: "Pinglita noto"
pinned: "Alpingli sur la profilo"
@@ -103,22 +107,38 @@ unblockConfirm: "Ĉu vi certas ke vi volas malbloki la uzanton?"
suspendConfirm: "Ĉu vi certas ke vi volas frostigi la uzanton?"
unsuspendConfirm: "Ĉu vi certas ke vi volas fandi la uzanton?"
selectList: "Elekti liston"
emojiUrl: "Retadreso de la emoĵio"
selectAntenna: "Elekti antenon"
selectWidget: "Elekti enestraĵon"
editWidgets: "Redakti fenestraĵon"
editWidgetsExit: "Fini la redaktadon"
customEmojis: "Personecigitaj emoĵioj"
emoji: "Emoĵio"
emojis: "Emoĵio"
emojiName: "Nomo de emoĵio"
emojiUrl: "URL de la bildo de emoĵio"
addEmoji: "Aldoni emoĵion"
cacheRemoteFiles: "Havi staplon por foraj dosieroj"
flagAsBot: "Tiu uzanto estas roboto"
flagAsCat: "Tiu uzanto estas kato"
addAccount: "Aldoni konton"
showOnRemote: "Vidi sur la transa ekzemplo"
showOnRemote: "Vidi sur la fora ekzemplo"
general: "Ĝenerala"
searchWith: "Serĉi: {q}"
youHaveNoLists: "Vi ne havas listojn."
followConfirm: "Ĉu vi certas, ke vi volas sekvi {name}'n?"
followConfirm: "Ĉu vi certas ke vi volas sekvi {name}'(o)n?"
selectUser: "Elekti uzanton"
annotation: "Komentarioj"
federation: "Fediverso"
instances: "Ekzemplo"
perHour: "Po horo"
perDay: "Po tago"
blockThisInstance: "Bloki tiu ekzemplo"
withNFiles: "{n} dosiero(j)"
disk: "Diskilo"
blockedInstances: "Blokitaj ekzemploj"
instanceInfo: "Informo pri la ekzemplo"
clearCachedFiles: "Forviŝi datumon en staplo"
clearCachedFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn transajn dosierojn en la staplo?"
blockedInstances: "Blokataj ekzemploj"
muteAndBlock: "Silentitaj / Blokitaj"
mutedUsers: "Silentigitaj uzantoj"
blockedUsers: "Blokitaj uzantoj"
@@ -131,8 +151,8 @@ federating: "Konfederado"
blocked: "Blokita"
subscribing: "Abonita"
notResponding: "Alvokato ne disponeblas"
instanceFollowing: "Sekvi ekzemplon"
instanceFollowers: "Sekvantoj de la ekzemplo"
instanceFollowing: "Sekvatoj sur la ekzemplo"
instanceFollowers: "Sekvantoj el la ekzemplo"
instanceUsers: "Uzantoj de la ekzemplo"
changePassword: "Ŝanĝi pasvorton"
currentPassword: "Aktuala pasvorto"
@@ -140,164 +160,309 @@ newPassword: "Nova pasvorto"
newPasswordRetype: "Reentajpu la novan pasvorton"
attachFile: "Aldoni dosieron"
more: "Plu!"
usernameOrUserId: "Uzantonomo aŭ ID de uzanto"
usernameOrUserId: "Uzantnomo aŭ identigilo de uzanto"
noSuchUser: "Neniuj uzantoj trovitaj."
remove: "Forviŝi"
imageUrl: "URL de bildo"
remove: "Forigi"
removed: "Forviŝis"
removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"?"
deleteAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"?"
messaging: "Babilejoj"
removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"'(o)n?"
deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'(o)n?"
messaging: "Retbabili"
upload: "Alŝuti"
fromDrive: "De la diskilo"
fromUrl: "De retadreso"
uploadFromUrl: "Aldoni de retadreso"
uploadFromUrlDescription: "Retadreso de la dosiero kiun vi volu alŝuti"
fromDrive: "De la diskingo en Miskejo"
fromUrl: "De URL"
uploadFromUrl: "Alŝuti de URL"
uploadFromUrlDescription: "URL de la dosiero kiun vi volu alŝuti"
games: "Ludoj sur Miskejo"
messageRead: "Legita"
startMessaging: "Komenci babiladon"
tos: "Kondiĉoj de Uzado"
start: "Komenciĝi"
home: "Ĉefpaĝo"
drive: "Diskilo"
home: "Hejmo"
remoteUserCaution: "Ĉi tiu Infomoj estas ne tute ekzakta pro distanca uzanto."
images: "Bildoj"
birthday: "Naskiĝtago"
registeredDate: "Registriĝdato"
drive: "Diskingo"
fileName: "Dosiernomo"
selectFile: "Elekti dosieron"
selectFiles: "Elekti dosieron"
renameFile: "Renomigi dosieron"
renameFile: "Alinomi la dosieron"
folderName: "Nomo de la dosierujo"
renameFolder: "Alinomi la dosierujon"
deleteFolder: "Forviŝi dosierujon"
addFile: "Aldoni dosieron"
emptyDrive: "La diskilo enhavas neniun."
emptyDrive: "La diskingo enhavas neniun."
unableToDelete: "Ne forigebla"
inputNewFileName: "Entajpu nova dosiernomon"
hasChildFilesOrFolders: "La dosierujo estas neforviŝebla pro tio, ke ĝi enhavas dosieron."
copyUrl: "Kopii retadreson"
inputNewFolderName: "Entajpu nova nomon de la dosierujo"
hasChildFilesOrFolders: "La dosierujo enhavas dosieron kaj ne estas forigebla."
copyUrl: "Kopii URL"
rename: "Alinomi"
avatar: "Ikono"
nsfw: "Enhavo ne estas deca por laborejo (NSFW)"
instanceName: "Nomo de la ekzemplo"
maintainerName: "Nomo de la administranto"
maintainerEmail: "Retpoŝto de la administranto"
tosUrl: "URL de kondiĉoj de uzado"
thisYear: "Ĉi-jare"
thisMonth: "Ĉi-monate"
today: "Hodiaŭ"
dayX: "{day}-a"
monthX: "{month}"
yearX: "La jaro {year}"
connectService: "Konekti"
disconnectService: "Farkonektiĝi"
driveCapacityPerLocalAccount: "Volumo po unu loka-uzanto"
driveCapacityPerRemoteAccount: "Volumo po unu transa uzanto"
driveCapacityPerLocalAccount: "Volumo de miskej-diskingo po unu loka uzanto"
driveCapacityPerRemoteAccount: "Volumo de miskej-diskingo po unu transa uzanto"
iconUrl: "URL de la ikono (retpaĝsimbolo, ktp.)"
pinnedUsers: "Alpinglita uzanto"
pinnedNotes: "Pinglita noto"
name: "Nomo"
withFileAntenna: "Nur kun aldonaĵo"
notesAndReplies: "Kun respondoj"
withFiles: "Kun aldonaĵo"
silenceConfirm: "Ĉu vi certas ke vi volas silentigi la uzanton?"
unsilenceConfirm: "Ĉu vi certas ke vi volas malsilentigi la uzanton?"
unsilenceConfirm: "Ĉu vi certas, ke vi ne plu volas ke la uzanto silentas?"
popularTags: "Popularaj kradvortoj"
userList: "Listoj"
aboutMisskey: "Pri Miskejo"
securityKeyName: "Nomo de la ŝlosilo"
passwordLessLogin: "Ensaluti sen pasvorto"
resetPassword: "Restarigi pasvorton"
newPasswordIs: "La nova pasvorto estas {password}."
cacheClear: "Forviŝi datumon en stalo"
help: "Manlibro de uzado"
inputMessageHere: "Entajpu masaĝo tie ĉi"
groupName: "Grupa nomo"
messagingWithUser: "Mesaĝado kun uzanto"
messagingWithGroup: "Mesaĝi kun grupo"
noteOf: "Noto de {user}"
noMessagesYet: "Neniu mesaĝo"
newMessageExists: "Vi ricevis novan mesaĝon."
onlyOneFileCanBeAttached: "Vi povas aldoni nur unu dosieron po unu mesaĝo."
uiLanguage: "Lingvo de la interfaco"
tags: "Etikedoj"
createAccount: "Krei konton"
existingAccount: "Ekzista konto"
noFollowRequests: "Vi ne havas eksekvopetojn."
openImageInNewTab: "Fermi la bildo sur nova tablo"
local: "Loka"
remote: "Transa"
accountSettings: "Agordoj de Konto"
numberOfDays: "Nombro de tagoj"
hideThisNote: "Kaŝi tiun noton"
deleteAllFiles: "Forvisi ĉiujn dosierojn"
objectStorageBaseUrl: "Baza URL"
deleteAll: "Forviŝi ĉiujn"
showInPage: "Vidi en paĝo"
deleteAllFiles: "Forviŝi ĉiujn dosierojn"
deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn viajn dosierojn?"
deletedNote: "Forviŝita noto"
invisibleNote: "Malpublika noto"
poll: "Balotujo"
emailServer: "Retpoŝta servilo"
email: "Retpoŝto"
emailAddress: "Retpoŝtadreso"
smtpUser: "Uzantonomo"
emailAddress: "Retpoŝta adreso"
smtpUser: "Uzantnomo"
smtpPass: "Pasvorto"
userSaysSomething: "{name} parolis ion"
display: "Vidi"
database: "Datumbazo"
channel: "Kanalo"
fileIdOrUrl: "Dosirero ID aŭ retadreso"
fileIdOrUrl: "Dosiera identigilo aŭ URL"
abuseReports: "Signali"
reportAbuse: "Signali"
reportAbuseOf: "Signali {name}'(o)n"
send: "Sendi"
i18nInfo: "Tradukojn de Misskey en diversaj lingvoj faras volontuloj. Vi povus kunlabori en tradukado sur {link}, se vi volus."
driveFilesCount: "Numero de dosieroj en la diskilo"
onlineUsersCount: "{n} uzanto(j) estas surkonektita"
i18nInfo: "Misskey estas tradukata en diversaj lingvoj far volontuloj. Oni povas kontribui por la tradukado sur {link}."
followingCount: "Numero de sekvatoj"
followersCount: "Numero de sekvantoj"
yes: "Jes"
no: "Ne"
driveFilesCount: "Numero de dosieroj en la diskingo"
noteFavoritesCount: "Numero de la preferataj notoj"
makeExplorable: "Igi videbla konto sur la paĝo \"Esplorado\""
showTitlebar: "Montri titolobredon"
clearCache: "Forviŝi datumon en staplo"
onlineUsersCount: "{n} uzanto(j) estas surlinea"
nUsers: "{n} uzanto(j)"
saveAs: "Konservi kiel…"
createdAt: "Kreita je"
updatedAt: "Laste ĝisdatigita"
deleteConfirm: "Ĉu certas forviŝi?"
closeAccount: "Forigi konton"
emailNotification: "Sciigoj per retpoŝto"
publish: "Publikigi"
inChannelSearch: "Serĉi en kanalo"
typingUsers: "{users} estas entajpanta(j)..."
online: "Surkonektita"
offline: "Forkonektita"
instanceBlocking: "Ekzempla blokado"
instanceBlocking: "Blokado de ekzemplo"
selectAccount: "Elekti konton"
user: "Uzanto"
accounts: "Kontoj"
global: "Konfederacia"
sent: "Sendi"
hashtags: "Kradvorto"
_gallery:
liked: "Ŝatitaj notoj"
_email:
_follow:
title: "Vi estas eksekvita."
title: "Vin eksekvis"
_receiveFollowRequest:
title: "Vi ricevis eksekvopeton."
_aboutMisskey:
about: "Misskey estas malferma koda programo evoluigata far syuilo ekde la 2014."
about: "Misskey estas malfermitkoda programo evoluigata de syuilo ekde la 2014."
contributors: "Precipaj kontribuantoj"
allContributors: "Ĉiuj kontribuintoj"
source: "Fontkodo"
translation: "Traduki Misskey'on"
translation: "Traduki Miskejon"
patrons: "Mecenatoj"
_mfm:
mention: "Mencioj"
url: "Retadreso"
hashtag: "Kradvorto"
url: "URL"
blockCode: "Kodo (Ujo)"
blockMath: "Formulo (Ujo)"
quote: "Citi"
emoji: "Personecigitaj emoĵioj"
search: "Serĉi"
_instanceTicker:
none: "Ne montri"
remote: "Montri al transaj uzantoj"
always: "Ĉiam montri"
_channel:
create: "Krei kanalon"
edit: "Redakti kanalon"
following: "Sekvaton"
following: "Sekvata"
_menuDisplay:
hide: "Kaŝi"
_wordMute:
muteWords: "Silentanta vorto"
mutedNotes: "Silentigataj notoj"
_theme:
keys:
hashtag: "Kradvorto"
mention: "Mencioj"
renote: "Renotici"
renote: "Fari renoton"
_sfx:
note: "Nova noto"
noteMy: "Mia noto"
notification: "Sciigoj"
chat: "Babilejoj"
channel: "Kanala sciigoj"
chat: "Retbabilejo"
chatBg: "Retbabilejo (BG)"
antenna: "Ricevo de anteno"
channel: "Sciigoj de kanalo"
_ago:
secondsAgo: "Antaŭ {n} sekundoj"
minutesAgo: "Antaŭ {n} minutoj"
hoursAgo: "Antaŭ {n} horoj"
daysAgo: "Antaŭ {n} tagoj"
weeksAgo: "Antaŭ {n} semajnoj"
monthsAgo: "Antaŭ {n} monatoj"
yearsAgo: "Antaŭ {n} jaroj"
_time:
second: "sek"
minute: "min"
hour: "hor"
day: "Tago"
_tutorial:
title: "Uzado de Miskejo"
title: "Uzado de Misskey"
step1_1: "Bonvenon."
step7_2: "Se vi volus scii pli pri Miskejon, volu rigardi la fako {help}."
_permissions:
"read:blocks": "Vidi la listo de la uzantoj kiun vi blokis."
"read:drive": "Vidi dosierojn en la diskilo"
"read:channels": "Legi kanalon"
"write:blocks": "Redakti la liston de la uzantoj kiun vi blokis."
"read:drive": "Ĉia operacio por legi la informon de dosiero en via diskingo de Miskejo"
"write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via diskingo de Miskejo"
"read:favorites": "Vidi la listo de la preferoj"
"read:following": "Vidi tion kion vi sekvas"
"write:following": "Sekvi kaj/aŭ malsekvi alian uzanton"
"read:messaging": "Vidi via retbabilado"
"write:notes": "Krei / Forviŝi noton"
"read:notifications": "Vidi sciigojn"
"read:reactions": "Vidi reagojn"
"read:pages": "Vidi via paĝojn"
"read:page-likes": "Vidi ŝatojn de paĝo"
"read:channels": "Vidi kanalojn"
_antennaSources:
homeTimeline: "Notoj far uzantoj sekvataj de vi"
_weekday:
sunday: "dimanĉo"
monday: "lundo"
tuesday: "mardo"
wednesday: "merkredo"
thursday: "ĵaŭdo"
friday: "vendredo"
saturday: "sabato"
_widgets:
notifications: "Sciigoj"
timeline: "Tempolinio"
timeline: "Templinio"
clock: "Horloĝo"
federation: "Fediverso"
onlineUsers: "Surkonektita uzanto"
_cw:
show: "Vidu plu"
show: "Vidu pli"
files: "{count} dosiero(j)"
_poll:
choiceN: "Balotilo {n}"
noMore: "Oni ne plu povas aldoni."
infinite: "Neniam"
deadlineTime: "hor"
votesCount: "{n} balotiloj"
vote: "Baloti"
closed: "Oni jam balotis ĝin"
_visibility:
publicDescription: "Via noto aperiĝos sur konfederacia tempolinio"
home: "Ĉefpaĝo"
homeDescription: "Elsendi nur sur hejma tempolinio"
publicDescription: "Via noto aperiĝos sur la konfederacia templinio"
home: "Hejmo"
homeDescription: "Elsendi nur sur la hejmtemplinio"
followers: "Sekvantoj"
followersDescription: "Elsendi nur al sekvantoj de mi"
followersDescription: "Elsendi nur al sekvantoj al mi"
localOnly: "Nur loka"
localOnlyDescription: "Nelegabla al transaj uzantoj"
localOnlyDescription: "Ne montri al transaj uzantoj"
_postForm:
channelPlaceholder: "Elsendi sur la kanalo"
replyPlaceholder: "Respondado al tiu noto..."
quotePlaceholder: "Citado tiun noton..."
channelPlaceholder: "Sendi sur la kanalo"
_profile:
username: "Uzantonomo"
name: "Nomo"
username: "Uzantnomo"
changeAvatar: "Ŝanĝi profilbildon"
_exportOrImport:
followingList: "Sekvi"
muteList: "Silentigi"
followingList: "Sekvataj"
muteList: "Silentigado"
blockingList: "Blokado"
userLists: "Listoj"
_timelines:
home: "Hejmo"
local: "Loka"
social: "Hejmo kaj loka"
social: "Sociala"
global: "Konfederacia"
_rooms:
translate: "Movi"
chooseImage: "Elekti bildon"
_furnitures:
server: "Servilo"
moon: "La luno"
_pages:
deleted: "La paĝo estas forigita."
viewPage: "Vidi via paĝojn"
my: "Miaj paĝoj"
content: "Blokado de paĝo"
url: "Retadreso de la paĝo"
chooseBlock: "Aldoni blokado"
url: "URL de paĝo"
chooseBlock: "Aldoni ujon"
blocks:
image: "Bildoj"
_post:
canvasId: "Kanvasa identigilo"
_canvas:
id: "Kanvasa identigilo"
_note:
id: "Identigilo de noto"
_button:
_action:
_pushEvent:
event: "Nomo de la evento"
script:
categories:
list: "Listoj"
@@ -317,21 +482,26 @@ _pages:
arg1: "Listoj"
types:
array: "Listoj"
stringArray: "List de teksto"
_notification:
fileUploaded: "La dosiero sukcese alŝutiĝis."
youWereFollowed: "Vi estas eksekvita."
youGotPoll: "{name} balotis"
youGotMessagingMessageFromUser: "{name} sentis mesaĝon al vi."
youWereFollowed: "Vin eksekvis"
youReceivedFollowRequest: "Vi ricevis eksekvopeton."
yourFollowRequestAccepted: "Via eksekvopeto estas akceptita."
_types:
follow: "Sekvi"
follow: "Sekvatoj"
mention: "Mencioj"
renote: "Renotici"
renote: "Fari renoton"
quote: "Citi"
reaction: "Reagoj"
receiveFollowRequest: "Eksekvopeto ricevita"
followRequestAccepted: "Eksekvopeto akceptiĝis."
_deck:
profile: "Agordaro"
_columns:
notifications: "Sciigoj"
tl: "Tempolinio"
tl: "Templinio"
list: "Listoj"
mentions: "Mencioj"
mentions: "Al vi"

View File

@@ -127,6 +127,7 @@ editWidgets: "Editar widgets"
editWidgetsExit: "Terminar edición"
customEmojis: "Emojis personalizados"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Nombre del emoji"
emojiUrl: "URL de la imágen del emoji"
addEmoji: "Agregar emoji"
@@ -665,6 +666,10 @@ administration: "Administrar"
expiration: "Termina el"
middle: "Mediano"
global: "Global"
sent: "Enviar"
hashtags: "Hashtag"
_docs:
admin: "Administrar"
_ad:
back: "Deseleccionar"
_gallery:

View File

@@ -128,6 +128,7 @@ editWidgets: "Modifier les widgets"
editWidgetsExit: "Valider les modifications"
customEmojis: "Émojis personnalisés"
emoji: "Émoji"
emojis: "Émoji"
emojiName: "Nom de lémoji"
emojiUrl: "URL de lémoji"
addEmoji: "Ajouter un émoji"
@@ -528,6 +529,7 @@ removeAllFollowing: "Retenir tous les abonnements"
removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Veuillez lancer cette action uniquement si linstance nexiste plus."
userSuspended: "Cet·te utilisateur·rice a été suspendu·e."
userSilenced: "Cette utilisateur·trice a été mis·e en sourdine."
menu: "Menu"
divider: "Séparateur"
addItem: "Ajouter un élément"
rooms: "Chambre"
@@ -760,7 +762,19 @@ middle: "Moyen"
low: "Basse"
emailNotConfiguredWarning: "Vous n'avez pas configuré d'adresse e-mail."
ratio: "Ratio"
customCss: "CSS personnalisé"
customCssWarn: "Utilisez cette fonctionnalité uniquement si vous savez exactement ce que vous faites. Une configuration inadaptée peut empêcher le client de s'exécuter normalement."
global: "Global"
squareAvatars: "Avatars carrés"
sent: "Envoyer"
hashtags: "Hashtags"
troubleshooting: "Résolution de problèmes"
_docs:
continueReading: "Lire plus"
features: "Fonctionnalités"
generalTopics: "Sujets généraux"
advancedTopics: "Sujets avancés"
admin: "Gestion"
_ad:
back: "Retour"
reduceFrequencyOfThisAd: "Voir cette publicité moins souvent"
@@ -859,6 +873,8 @@ _mfm:
blurDescription: "Le contenu peut être flouté ; il sera visible en le survolant avec le curseur."
font: "Police de caractères"
fontDescription: "Il est possible de choisir la police."
rainbow: "Arc-en-ciel"
rainbowDescription: "Permet d'afficher le contenu en couleurs arc-en-ciel."
_reversi:
reversi: "Reversi"
gameSettings: "Réglages de la partie"
@@ -911,6 +927,9 @@ _channel:
usersCount: "{n} Participant·e·s"
notesCount: "{n} Notes"
_menuDisplay:
sideFull: "Latéral"
sideIcon: "Latéral (icônes)"
top: "Haut de page"
hide: "Masquer"
_wordMute:
muteWords: "Mots à filtrer"
@@ -1590,11 +1609,11 @@ _notification:
youWereInvitedToGroup: "Invité·e au groupe"
_types:
all: "Toutes"
follow: "Abonnements"
follow: "Nouvel·le abonné·e"
mention: "Mentions"
reply: "Réponses"
renote: "Partager"
quote: "Citer"
renote: "Renotes"
quote: "Citations"
reaction: "Réactions"
pollVote: "Votes dans des sondages"
receiveFollowRequest: "Demande d'abonnement reçue"

View File

@@ -128,6 +128,7 @@ editWidgets: "Sunting gawit"
editWidgetsExit: "Selesai"
customEmojis: "Emoji kustom"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Nama emoji"
emojiUrl: "URL Emoji"
addEmoji: "Tambahkan emoji"
@@ -528,6 +529,7 @@ removeAllFollowing: "Tahan semua mengikuti"
removeAllFollowingDescription: "Batal mengikuti semua akun dari {host}. Mohon jalankan ini ketika instansi sudah tidak ada lagi."
userSuspended: "Pengguna ini telah dibekukan."
userSilenced: "Pengguna ini telah dibungkam."
menu: "Menu"
divider: "Pembagi"
addItem: "Tambahkan item"
rooms: "Ruang"
@@ -760,7 +762,14 @@ middle: "Sedang"
low: "Rendah"
emailNotConfiguredWarning: "Alamat surel tidak disetel."
ratio: "Rasio"
customCss: "Custom CSS"
customCssWarn: "Pengaturan ini seharusnya digunakan jika kamu tahu cara kerjanya. Memasukkan nilai yang tidak tepat dapat menyebabkan klien tidak berfungsi semestinya."
global: "Global"
squareAvatars: "Tampilkan avatar sebagai persegi"
sent: "Kirim"
hashtags: "Tagar"
_docs:
admin: "Manajemen"
_ad:
back: "Kembali"
reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit"
@@ -911,6 +920,9 @@ _channel:
usersCount: "{n} Partisipan"
notesCount: "terdapat {n} catatan"
_menuDisplay:
sideFull: "Horisontal"
sideIcon: "Horisontal (Ikon)"
top: "Atas"
hide: "Sembunyikan"
_wordMute:
muteWords: "Kata yang dibisukan"

View File

@@ -127,6 +127,7 @@ editWidgets: "Modifica i widget"
editWidgetsExit: "Modifica fine"
customEmojis: "Emoji personalizzati"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Nome dell'emoji"
emojiUrl: "URL dell'emoji"
addEmoji: "Aggiungi un emoji"
@@ -741,6 +742,13 @@ low: "Bassa"
emailNotConfiguredWarning: "Non hai impostato nessun indirizzo e-mail."
ratio: "Rapporto"
global: "Federata"
sent: "Inviare"
hashtags: "Hashtag"
troubleshooting: "Risoluzione problemi"
_docs:
continueReading: "Leggi di più"
features: "Funzionalità"
admin: "Gestione"
_ad:
back: "Indietro"
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
@@ -799,6 +807,7 @@ _mfm:
blur: "Sfocatura"
font: "Tipo di carattere"
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
rainbow: "Arcobaleno"
_reversi:
reversi: "Reversi"
gameSettings: "Impostazioni di gioco"
@@ -1386,12 +1395,12 @@ _notification:
youWereInvitedToGroup: "Invitat@ al gruppo"
_types:
all: "Tutto"
follow: "Follows"
follow: "Nuovə follower"
mention: "Menzioni"
reply: "Rispondi"
reply: "Risposte"
renote: "Rinota"
quote: "Cita"
reaction: "Reazione"
reaction: "Reazioni"
pollVote: "Voti ricevuti"
receiveFollowRequest: "Richiesta di follow ricevuta"
followRequestAccepted: "Richiesta di follow accettata"

View File

@@ -128,6 +128,7 @@ editWidgets: "ウィジェットを編集"
editWidgetsExit: "編集を終了"
customEmojis: "カスタム絵文字"
emoji: "絵文字"
emojis: "絵文字"
emojiName: "絵文字名"
emojiUrl: "絵文字画像URL"
addEmoji: "絵文字を追加"
@@ -765,6 +766,18 @@ customCss: "カスタムCSS"
customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。"
global: "グローバル"
squareAvatars: "アイコンを四角形で表示"
sent: "送信"
received: "受信"
searchResult: "検索結果"
hashtags: "ハッシュタグ"
troubleshooting: "トラブルシューティング"
_docs:
continueReading: "続きを読む"
features: "機能"
generalTopics: "一般的なトピック"
advancedTopics: "高度なトピック"
admin: "管理"
_ad:
back: "戻る"
@@ -872,6 +885,8 @@ _mfm:
blurDescription: "内容をぼかすことができます。ポインターを上に乗せるとはっきり見えるようになります。"
font: "フォント"
fontDescription: "内容のフォントを指定することができます。"
rainbow: "レインボー"
rainbowDescription: "内容をレインボーにします。"
_reversi:
reversi: "リバーシ"

View File

@@ -127,6 +127,7 @@ editWidgets: "ウィジェットをいじる"
editWidgetsExit: "編集終ったで"
customEmojis: "カスタム絵文字"
emoji: "絵文字"
emojis: "絵文字"
emojiName: "絵文字名"
emojiUrl: "絵文字画像URL"
addEmoji: "絵文字を追加"
@@ -647,6 +648,10 @@ high: "高い"
middle: "中"
low: "低い"
global: "グローバル"
sent: "送信"
hashtags: "ハッシュタグ"
_docs:
admin: "管理"
_ad:
back: "戻る"
_gallery:

View File

@@ -7,7 +7,9 @@ username: "Isem n umseqdac"
password: "Awal uffir"
ok: "IH"
settings: "Iɣewwaṛen"
otherSettings: "Iɣewwaren nniḍen"
profile: "Amaɣnu"
signup: "Jerred"
save: "Sekles"
delete: "Kkes"
addToList: "Rnu ɣer tebdart"
@@ -27,15 +29,31 @@ followers: "Imeḍfaṛen"
followsYou: "Yeṭṭafaṛ-ik·em-id"
createList: "Snulfu-d tabdart"
enterListName: "Isem n tebdart"
privacy: "Tabaḍnit"
follow: "Ḍfeṛ"
you: "Kečči·mmi"
selectList: "Fren tabdart"
youHaveNoLists: "Ulac ɣur-k·m ula d yiwet n tabdart"
security: "Taɣellist"
remove: "Kkes"
userList: "Tibdarin"
securityKey: "Tasarutt n tɣellist"
securityKeyName: "Isem n tsarutt"
signinRequired: "Ttxil jerred"
signinWith: "Tuqqna s {x}"
tapSecurityKey: "Sekcem tasarutt-ik·im n tɣellist"
uiLanguage: "Tutlayt n wegrudem"
accountSettings: "Iɣewwaṛen n umiḍan"
plugins: "Izegrar"
email: "Imayl"
emailAddress: "Tansa imayl"
smtpUser: "Isem n umseqdac"
smtpPass: "Awal uffir"
other: "Wiyyaḍ"
accountInfo: "Talɣut n umiḍan"
emailNotification: "Ilɣa imayl"
selectAccount: "Fren amiḍan"
accounts: "Imiḍan"
_email:
_follow:
title: "Yeṭṭafaṛ-ik·em-id"
@@ -48,6 +66,8 @@ _theme:
mention: "Bder"
_sfx:
notification: "Ilɣuyen"
_permissions:
"write:account": "Ẓreg talɣut n umiḍan-ik·im"
_widgets:
notifications: "Ilɣuyen"
_cw:

View File

@@ -128,6 +128,7 @@ editWidgets: "위젯 편집"
editWidgetsExit: "편집 종료"
customEmojis: "커스텀 이모지"
emoji: "이모지"
emojis: "이모지"
emojiName: "이모지 이름"
emojiUrl: "이모지 URL"
addEmoji: "이모지 추가"
@@ -528,6 +529,7 @@ removeAllFollowing: "모든 팔로잉 해제"
removeAllFollowingDescription: "{host}(으)로부터 모든 팔로잉을 해제합니다. 해당 인스턴스가 더 이상 존재하지 않게 된 경우 등에 실행해 주세요."
userSuspended: "이 계정은 정지된 상태입니다."
userSilenced: "이 계정은 사일런스된 상태입니다."
menu: "메뉴"
divider: "구분선"
addItem: "항목 추가"
rooms: "방"
@@ -760,7 +762,21 @@ middle: "보통"
low: "낮음"
emailNotConfiguredWarning: "메일 주소가 설정되어 있지 않습니다."
ratio: "비율"
customCss: "CSS 사용자화"
customCssWarn: "이 설정은 기능을 알고 있는 경우에만 사용해야 합니다. 잘못된 값을 입력하면 클라이언트가 정상적으로 작동하지 않을 수 있습니다."
global: "글로벌"
squareAvatars: "프로필 아이콘을 사각형으로 표시"
sent: "전송"
received: "수신"
searchResult: "검색 결과"
hashtags: "해시태그"
troubleshooting: "트러블 슈팅"
_docs:
continueReading: "계속 읽기"
features: "기능"
generalTopics: "일반 주제"
advancedTopics: "심화 주제"
admin: "관리"
_ad:
back: "뒤로"
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
@@ -859,6 +875,8 @@ _mfm:
blurDescription: "내용이 흐리게 보입니다. 마우스를 위에 올려두면 내용이 보입니다."
font: "폰트"
fontDescription: "내용의 글꼴을 지정할 수 있습니다."
rainbow: "무지개"
rainbowDescription: "내용을 무지개로 표시합니다."
_reversi:
reversi: "리버시"
gameSettings: "대국 설정"
@@ -911,6 +929,9 @@ _channel:
usersCount: "{n}명 참여 중"
notesCount: "{n}노트"
_menuDisplay:
sideFull: "가로"
sideIcon: "가로(아이콘)"
top: "상단"
hide: "숨기기"
_wordMute:
muteWords: "뮤트할 단어"

View File

@@ -128,6 +128,7 @@ editWidgets: "Edytuj widżet"
editWidgetsExit: "Gotowe"
customEmojis: "Niestandardowe emoji"
emoji: "Emoji"
emojis: "Emoji"
emojiName: "Nazwa emoji"
emojiUrl: "Adres URL emoji"
addEmoji: "Dodaj emoji"
@@ -735,6 +736,10 @@ low: "Niski"
emailNotConfiguredWarning: "Nie podano adresu e-mail"
ratio: "Stosunek"
global: "Globalna"
sent: "Wyślij"
hashtags: "Hashtag"
_docs:
admin: "Zarządzanie"
_ad:
back: "Wróć"
reduceFrequencyOfThisAd: "Pokazuj tę reklamę rzadziej"

View File

@@ -128,6 +128,7 @@ editWidgets: "Редактировать виджеты"
editWidgetsExit: "Готово"
customEmojis: "Эмодзи пользователя"
emoji: "Эмодзи"
emojis: "Эмодзи"
emojiName: "Название эмодзи"
emojiUrl: "URL эмодзи"
addEmoji: "Добавить эмодзи"
@@ -761,6 +762,14 @@ low: "Низкий"
emailNotConfiguredWarning: "Не указан адрес электронной почты"
ratio: "Соотношение"
global: "Всеобщая"
sent: "Отправить"
hashtags: "Хэштег"
_docs:
continueReading: "Читать подробнее"
features: "Возможности"
generalTopics: "Основные темы"
advancedTopics: "Дополнительные темы"
admin: "Управление"
_ad:
back: "Выход"
reduceFrequencyOfThisAd: "Реже показывать эту рекламу"
@@ -859,6 +868,8 @@ _mfm:
blurDescription: "Размывает текст до нечитаемости, будто его поместили за матовое стекло. Наведение указателя мыши на размытый текст возвращает чёткость."
font: "Шрифт"
fontDescription: "Так можно писать произвольным шрифтом."
rainbow: "Радуга"
rainbowDescription: "Заставлять содержимое отображаться в цветах радуги."
_reversi:
reversi: "Реверси"
gameSettings: "Настройки игры"
@@ -911,6 +922,9 @@ _channel:
usersCount: "Участников: {n}"
notesCount: "Заметок: {n}"
_menuDisplay:
sideFull: "Сторона"
sideIcon: "Сторона (иконки)"
top: "Вверх"
hide: "Спрятать"
_wordMute:
muteWords: "Скрыть слово"

View File

@@ -127,6 +127,7 @@ editWidgets: "Редагувати віджети"
editWidgetsExit: "Готово"
customEmojis: "Кастомні емоджі"
emoji: "Емоджі"
emojis: "Емоджі"
emojiName: "Назва емоджі"
emojiUrl: "URL емодзі"
addEmoji: "Додати емодзі"
@@ -689,6 +690,10 @@ administration: "Управління"
expiration: "Опитування закінчується"
middle: "Середній"
global: "Глобальна"
sent: "Відправити"
hashtags: "Хештеґ"
_docs:
admin: "Управління"
_ad:
back: "Назад"
_gallery:

View File

@@ -128,6 +128,7 @@ editWidgets: "编辑小工具"
editWidgetsExit: "完成编辑"
customEmojis: "自定义表情符号"
emoji: "表情符号"
emojis: "表情符号"
emojiName: "表情符号名称"
emojiUrl: "表情符号地址"
addEmoji: "添加表情符号"
@@ -765,6 +766,17 @@ customCss: "自定义 CSS"
customCssWarn: "这些设置必须有相关的基础知识,不当的配置可能导致客户端无法正常使用!"
global: "全局"
squareAvatars: "显示方形头像图标"
sent: "发送"
received: "收取"
searchResult: "搜索结果"
hashtags: "话题标签"
troubleshooting: "故障排除"
_docs:
continueReading: "继续阅读"
features: "特性"
generalTopics: "通常提示"
advancedTopics: "进阶提示"
admin: "管理"
_ad:
back: "返回"
reduceFrequencyOfThisAd: "减少此广告的频率"
@@ -863,6 +875,8 @@ _mfm:
blurDescription: "产生模糊效果。将鼠标指针放在上面即可将内容显示出来。"
font: "字体"
fontDescription: "可以设置内容所使用的字体。"
rainbow: "彩虹"
rainbowDescription: "用彩虹色来显示内容。"
_reversi:
reversi: "黑白棋"
gameSettings: "对局设置"

View File

@@ -128,6 +128,7 @@ editWidgets: "編輯小工具"
editWidgetsExit: "完成"
customEmojis: "自訂表情符號"
emoji: "表情符號"
emojis: "表情符號"
emojiName: "表情符號名稱"
emojiUrl: "表情符號URL"
addEmoji: "加入表情符號"
@@ -751,6 +752,10 @@ low: "低"
emailNotConfiguredWarning: "沒有設定電子郵件地址"
ratio: "%"
global: "公開"
sent: "發送"
hashtags: "#tag"
_docs:
admin: "管理"
_ad:
back: "返回"
reduceFrequencyOfThisAd: "降低此廣告的頻率 "

View File

@@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.84.0",
"version": "12.85.0",
"codename": "indigo",
"repository": {
"type": "git",
@@ -101,7 +101,7 @@
"@types/websocket": "1.0.3",
"@types/ws": "7.4.6",
"@typescript-eslint/parser": "4.28.3",
"@vue/compiler-sfc": "3.2.0-beta.2",
"@vue/compiler-sfc": "3.1.5",
"abort-controller": "3.0.0",
"apexcharts": "3.27.2",
"autobind-decorator": "2.4.0",
@@ -238,7 +238,7 @@
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.0",
"vue": "3.2.0-beta.2",
"vue": "3.1.5",
"vue-color": "2.8.1",
"vue-json-pretty": "1.8.1",
"vue-loader": "16.3.1",

View File

@@ -10,9 +10,9 @@
</template>
<div class="dpvffvvy _monolithic_">
<div class="_section">
<MkTextarea v-model:value="comment">
<span>{{ $ts.details }}</span>
<template #desc>{{ $ts.fillAbuseReportDescription }}</template>
<MkTextarea v-model="comment">
<template #label>{{ $ts.details }}</template>
<template #caption>{{ $ts.fillAbuseReportDescription }}</template>
</MkTextarea>
</div>
<div class="_section">

View File

@@ -14,8 +14,8 @@
</div>
<header v-if="title"><Mfm :text="title"/></header>
<div class="body" v-if="text"><Mfm :text="text"/></div>
<MkInput v-if="input" v-model:value="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></MkInput>
<MkSelect v-if="select" v-model:value="selectedValue" autofocus>
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></MkInput>
<MkSelect v-if="select" v-model="selectedValue" autofocus>
<template v-if="select.items">
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
</template>

View File

@@ -114,7 +114,7 @@ export default defineComponent({
if (this.selectMode) {
this.$emit('chosen', this.file);
} else {
os.modalMenu(this.getMenu(), ev.currentTarget || ev.target);
os.popupMenu(this.getMenu(), ev.currentTarget || ev.target);
}
},

View File

@@ -10,6 +10,7 @@
<span class="separator" v-if="folder != null"><i class="fas fa-angle-right"></i></span>
<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
</div>
<button @click="showMenu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
</nav>
<div class="main" :class="{ uploading: uploadings.length > 0, fetching }"
ref="main"
@@ -46,7 +47,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import XNavFolder from './drive.nav-folder.vue';
import XFolder from './drive.folder.vue';
import XFile from './drive.file.vue';
@@ -139,7 +140,7 @@ export default defineComponent({
});
}
this.connection = os.stream.useChannel('drive');
this.connection = markRaw(os.stream.useChannel('drive'));
this.connection.on('fileCreated', this.onStreamDriveFileCreated);
this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
@@ -627,8 +628,12 @@ export default defineComponent({
}];
},
onContextmenu(e) {
os.contextMenu(this.getMenu(), e);
showMenu(ev) {
os.popupMenu(this.getMenu(), ev.currentTarget || ev.target);
},
onContextmenu(ev) {
os.contextMenu(this.getMenu(), ev);
},
}
});
@@ -641,7 +646,7 @@ export default defineComponent({
height: 100%;
> nav {
display: block;
display: flex;
z-index: 2;
width: 100%;
padding: 0 8px;
@@ -696,6 +701,10 @@ export default defineComponent({
}
}
}
> .menu {
margin-left: auto;
}
}
> .main {

View File

@@ -1,17 +1,17 @@
<template>
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" :front="true" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen" ref="picker"/>
</MkModal>
<MkPopup ref="popup" :manual-showing="manualShowing" :src="src" :front="true" @click="$refs.popup.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkEmojiPicker class="_shadow" :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen" ref="picker"/>
</MkPopup>
</template>
<script lang="ts">
import { defineComponent, markRaw } from 'vue';
import MkModal from '@client/components/ui/modal.vue';
import MkPopup from '@client/components/ui/popup.vue';
import MkEmojiPicker from '@client/components/emoji-picker.vue';
export default defineComponent({
components: {
MkModal,
MkPopup,
MkEmojiPicker,
},
@@ -33,7 +33,7 @@ export default defineComponent({
},
},
emits: ['done', 'closed'],
emits: ['done', 'close', 'closed'],
data() {
return {
@@ -44,7 +44,7 @@ export default defineComponent({
methods: {
chosen(emoji: any) {
this.$emit('done', emoji);
this.$refs.modal.close();
this.$refs.popup.close();
},
opening() {

View File

@@ -28,7 +28,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import * as os from '@client/os';
export default defineComponent({
@@ -71,7 +71,7 @@ export default defineComponent({
},
mounted() {
this.connection = os.stream.useChannel('main');
this.connection = markRaw(os.stream.useChannel('main'));
this.connection.on('follow', this.onFollowChange);
this.connection.on('unfollow', this.onFollowChange);

View File

@@ -9,14 +9,14 @@
<form class="_monolithic_" @submit.prevent="onSubmit" v-if="$instance.enableEmail">
<div class="_section">
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
<span>{{ $ts.username }}</span>
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
<template #label>{{ $ts.username }}</template>
<template #prefix>@</template>
</MkInput>
<MkInput v-model:value="email" type="email" spellcheck="false" required>
<span>{{ $ts.emailAddress }}</span>
<template #desc>{{ $ts._forgotPassword.enterEmail }}</template>
<MkInput v-model="email" type="email" spellcheck="false" required>
<template #label>{{ $ts.emailAddress }}</template>
<template #caption>{{ $ts._forgotPassword.enterEmail }}</template>
</MkInput>
<MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ $ts.send }}</MkButton>

View File

@@ -117,6 +117,11 @@ export default defineComponent({
75% { transform: scale3d(1.05, 0.95, 1); }
to { transform: scale3d(1, 1, 1); }
}
@keyframes mfm-rainbow {
0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
}
</style>
<style lang="scss" scoped>

View File

@@ -1,7 +1,7 @@
<template>
<div class="zbcjwnqg" style="margin-top: -8px;">
<div class="selects" style="display: flex;">
<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
<optgroup :label="$ts.federation">
<option value="federation-instances">{{ $ts._charts.federationInstancesIncDec }}</option>
<option value="federation-instances-total">{{ $ts._charts.federationInstancesTotal }}</option>
@@ -24,7 +24,7 @@
<option value="drive-total">{{ $ts._charts.storageUsageTotal }}</option>
</optgroup>
</MkSelect>
<MkSelect v-model:value="chartSpan" style="margin: 0;">
<MkSelect v-model="chartSpan" style="margin: 0;">
<option value="hour">{{ $ts.perHour }}</option>
<option value="day">{{ $ts.perDay }}</option>
</MkSelect>

View File

@@ -165,6 +165,10 @@ export default defineComponent({
class: '_mfm_blur_',
}, genEl(token.children));
}
case 'rainbow': {
style = this.$store.state.animatedMfm ? 'animation: mfm-rainbow 1s linear infinite;' : '';
break;
}
}
if (style == null) {
return h('span', {}, ['[', token.props.name, ...genEl(token.children), ']']);

View File

@@ -2,12 +2,9 @@
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
<div class="hrmcaedk _popup _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
<div class="header" @contextmenu="onContextmenu">
<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
<span class="title">
<XHeader :info="pageInfo" :with-back="false"/>
<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="$refs.modal.close()"/>
</span>
<button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button>
</div>
<div class="body _flat_">
<keep-alive>
@@ -177,35 +174,19 @@ export default defineComponent({
flex-shrink: 0;
box-shadow: 0px 1px var(--divider);
> button {
height: $height;
width: $height;
@media (max-width: 500px) {
height: $height-narrow;
width: $height-narrow;
}
}
> .title {
flex: 1;
line-height: $height;
padding-left: 32px;
height: $height;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
@media (max-width: 500px) {
line-height: $height-narrow;
height: $height-narrow;
padding-left: 16px;
}
}
> button + .title {
padding-left: 0;
}
}
> .body {

View File

@@ -454,7 +454,7 @@ export default defineComponent({
renote(viaKeyboard = false) {
pleaseLogin();
this.blur();
os.modalMenu([{
os.popupMenu([{
text: this.$ts.renote,
icon: 'fas fa-retweet',
action: () => {
@@ -743,14 +743,14 @@ export default defineComponent({
},
menu(viaKeyboard = false) {
os.modalMenu(this.getMenu(), this.$refs.menuButton, {
os.popupMenu(this.getMenu(), this.$refs.menuButton, {
viaKeyboard
}).then(this.focus);
},
showRenoteMenu(viaKeyboard = false) {
if (!this.isMyRenote) return;
os.modalMenu([{
os.popupMenu([{
text: this.$ts.unrenote,
icon: 'fas fa-trash-alt',
danger: true,
@@ -794,7 +794,7 @@ export default defineComponent({
async clip() {
const clips = await os.api('clips/list');
os.modalMenu([{
os.popupMenu([{
icon: 'fas fa-plus',
text: this.$ts.createNew,
action: async () => {

View File

@@ -24,8 +24,8 @@
<script lang="ts">
import { defineComponent } from 'vue';
import notePage from '../filters/note';
import { userPage } from '../filters/user';
import notePage from '@client/filters/note';
import { userPage } from '@client/filters/user';
import * as os from '@client/os';
export default defineComponent({

View File

@@ -429,7 +429,7 @@ export default defineComponent({
renote(viaKeyboard = false) {
pleaseLogin();
this.blur();
os.modalMenu([{
os.popupMenu([{
text: this.$ts.renote,
icon: 'fas fa-retweet',
action: () => {
@@ -718,14 +718,14 @@ export default defineComponent({
},
menu(viaKeyboard = false) {
os.modalMenu(this.getMenu(), this.$refs.menuButton, {
os.popupMenu(this.getMenu(), this.$refs.menuButton, {
viaKeyboard
}).then(this.focus);
},
showRenoteMenu(viaKeyboard = false) {
if (!this.isMyRenote) return;
os.modalMenu([{
os.popupMenu([{
text: this.$ts.unrenote,
icon: 'fas fa-trash-alt',
danger: true,
@@ -769,7 +769,7 @@ export default defineComponent({
async clip() {
const clips = await os.api('clips/list');
os.modalMenu([{
os.popupMenu([{
icon: 'fas fa-plus',
text: this.$ts.createNew,
action: async () => {

View File

@@ -11,16 +11,16 @@
<template #header>{{ $ts.notificationSetting }}</template>
<div class="_monolithic_">
<div v-if="showGlobalToggle" class="_section">
<MkSwitch v-model:value="useGlobalSetting">
<MkSwitch v-model="useGlobalSetting">
{{ $ts.useGlobalSetting }}
<template #desc>{{ $ts.useGlobalSettingDesc }}</template>
<template #caption>{{ $ts.useGlobalSettingDesc }}</template>
</MkSwitch>
</div>
<div v-if="!useGlobalSetting" class="_section">
<MkInfo>{{ $ts.notificationSettingDesc }}</MkInfo>
<MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton>
<MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton>
<MkSwitch v-for="type in notificationTypes" :key="type" v-model:value="typesMap[type]">{{ $t(`_notification._types.${type}`) }}</MkSwitch>
<MkSwitch v-for="type in notificationTypes" :key="type" v-model="typesMap[type]">{{ $t(`_notification._types.${type}`) }}</MkSwitch>
</div>
</div>
</XModalWindow>

View File

@@ -58,12 +58,12 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import { getNoteSummary } from '@/misc/get-note-summary';
import XReactionIcon from './reaction-icon.vue';
import MkFollowButton from './follow-button.vue';
import notePage from '../filters/note';
import { userPage } from '../filters/user';
import notePage from '@client/filters/note';
import { userPage } from '@client/filters/user';
import { i18n } from '@client/i18n';
import * as os from '@client/os';
@@ -109,7 +109,7 @@ export default defineComponent({
this.readObserver.observe(this.$el);
this.connection = os.stream.useChannel('main');
this.connection = markRaw(os.stream.useChannel('main'));
this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el));
}
},

View File

@@ -21,7 +21,7 @@
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { defineComponent, PropType, markRaw } from 'vue';
import paging from '@client/scripts/paging';
import XNotification from './notification.vue';
import XList from './date-separated-list.vue';
@@ -89,7 +89,7 @@ export default defineComponent({
},
mounted() {
this.connection = os.stream.useChannel('main');
this.connection = markRaw(os.stream.useChannel('main'));
this.connection.on('notification', this.onNotification);
},

View File

@@ -16,7 +16,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { userName } from '../filters/user';
import { userName } from '@client/filters/user';
import * as os from '@client/os';
export default defineComponent({

View File

@@ -3,16 +3,12 @@
:initial-width="500"
:initial-height="500"
:can-resize="true"
:close-right="true"
:close-button="false"
:contextmenu="contextmenu"
@closed="$emit('closed')"
>
<template #header>
<XHeader :info="pageInfo" :with-back="false"/>
</template>
<template #buttons>
<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()"/>
</template>
<div class="yrolvcoq _flat_">
<component :is="component" v-bind="props" :ref="changePage"/>
@@ -139,6 +135,10 @@ export default defineComponent({
this.navigate(this.history.pop(), false);
},
close() {
this.$refs.window.close();
},
expand() {
this.$router.push(this.path);
this.$refs.window.close();
@@ -155,6 +155,5 @@ export default defineComponent({
<style lang="scss" scoped>
.yrolvcoq {
min-height: 100%;
background: var(--bg);
}
</style>

View File

@@ -1,6 +1,8 @@
<template>
<div>
<MkInput class="kudkigyw" :value="value" @update:value="updateValue($event)" type="number">{{ hpml.interpolate(block.text) }}</MkInput>
<MkInput class="kudkigyw" :model-value="value" @update:modelValue="updateValue($event)" type="number">
<template #label>{{ hpml.interpolate(block.text) }}</template>
</MkInput>
</div>
</template>

View File

@@ -1,6 +1,6 @@
<template>
<div class="ngbfujlo">
<MkTextarea :value="text" readonly style="margin: 0;"></MkTextarea>
<MkTextarea :model-value="text" readonly style="margin: 0;"></MkTextarea>
<MkButton class="button" primary @click="post()" :disabled="posting || posted">
<i v-if="posted" class="fas fa-check"></i>
<i v-else class="fas fa-paper-plane"></i>

View File

@@ -1,6 +1,6 @@
<template>
<div class="hkcxmtwj">
<MkSwitch :value="value" @update:value="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkSwitch>
<MkSwitch :model-value="value" @update:modelValue="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkSwitch>
</div>
</template>

View File

@@ -1,6 +1,8 @@
<template>
<div>
<MkInput class="kudkigyw" :value="value" @update:value="updateValue($event)" type="text">{{ hpml.interpolate(block.text) }}</MkInput>
<MkInput class="kudkigyw" :model-value="value" @update:modelValue="updateValue($event)" type="text">
<template #label>{{ hpml.interpolate(block.text) }}</template>
</MkInput>
</div>
</template>

View File

@@ -1,6 +1,8 @@
<template>
<div>
<MkTextarea :value="value" @update:value="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkTextarea>
<MkTextarea :model-value="value" @update:modelValue="updateValue($event)">
<template #label>{{ hpml.interpolate(block.text) }}</template>
</MkTextarea>
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<MkTextarea :value="text" readonly></MkTextarea>
<MkTextarea :model-value="text" readonly></MkTextarea>
</template>
<script lang="ts">

View File

@@ -5,8 +5,8 @@
</p>
<ul ref="choices">
<li v-for="(choice, i) in choices" :key="i">
<MkInput class="input" :value="choice" @update:value="onInput(i, $event)">
<span>{{ $t('_poll.choiceN', { n: i + 1 }) }}</span>
<MkInput class="input" :model-value="choice" @update:modelValue="onInput(i, $event)">
<template #label>{{ $t('_poll.choiceN', { n: i + 1 }) }}</template>
</MkInput>
<button @click="remove(i)" class="_button">
<i class="fas fa-times"></i>
@@ -16,27 +16,27 @@
<MkButton class="add" v-if="choices.length < 10" @click="add">{{ $ts.add }}</MkButton>
<MkButton class="add" v-else disabled>{{ $ts._poll.noMore }}</MkButton>
<section>
<MkSwitch v-model:value="multiple">{{ $ts._poll.canMultipleVote }}</MkSwitch>
<MkSwitch v-model="multiple">{{ $ts._poll.canMultipleVote }}</MkSwitch>
<div>
<MkSelect v-model:value="expiration">
<MkSelect v-model="expiration">
<template #label>{{ $ts._poll.expiration }}</template>
<option value="infinite">{{ $ts._poll.infinite }}</option>
<option value="at">{{ $ts._poll.at }}</option>
<option value="after">{{ $ts._poll.after }}</option>
</MkSelect>
<section v-if="expiration === 'at'">
<MkInput v-model:value="atDate" type="date" class="input">
<span>{{ $ts._poll.deadlineDate }}</span>
<MkInput v-model="atDate" type="date" class="input">
<template #label>{{ $ts._poll.deadlineDate }}</template>
</MkInput>
<MkInput v-model:value="atTime" type="time" class="input">
<span>{{ $ts._poll.deadlineTime }}</span>
<MkInput v-model="atTime" type="time" class="input">
<template #label>{{ $ts._poll.deadlineTime }}</template>
</MkInput>
</section>
<section v-if="expiration === 'after'">
<MkInput v-model:value="after" type="number" class="input">
<span>{{ $ts._poll.duration }}</span>
<MkInput v-model="after" type="number" class="input">
<template #label>{{ $ts._poll.duration }}</template>
</MkInput>
<MkSelect v-model:value="unit">
<MkSelect v-model="unit">
<option value="second">{{ $ts._time.second }}</option>
<option value="minute">{{ $ts._time.minute }}</option>
<option value="hour">{{ $ts._time.hour }}</option>

View File

@@ -112,7 +112,7 @@ export default defineComponent({
showFileMenu(file, ev: MouseEvent) {
if (this.menu) return;
this.menu = os.modalMenu([{
this.menu = os.popupMenu([{
text: this.$ts.renameFile,
icon: 'fas fa-i-cursor',
action: () => { this.rename(file) }

View File

@@ -37,6 +37,7 @@
<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" />
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
<footer>
@@ -44,9 +45,13 @@
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><i class="fas fa-eye-slash"></i></button>
<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><i class="fas fa-at"></i></button>
<button class="_button" @click="withHashtags = !withHashtags" v-tooltip="$ts.hashtags"><i class="fas fa-hashtag"></i></button>
<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><i class="fas fa-laugh-squint"></i></button>
<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><i class="fas fa-plug"></i></button>
</footer>
<datalist id="hashtags">
<option v-for="hashtag in recentHashtags" :value="hashtag" :key="hashtag"/>
</datalist>
</div>
</div>
</template>
@@ -67,10 +72,11 @@ import { Autocomplete } from '@client/scripts/autocomplete';
import { noteVisibilities } from '../../types';
import * as os from '@client/os';
import { selectFile } from '@client/scripts/select-file';
import { notePostInterruptors, postFormActions } from '@client/store';
import { defaultStore, notePostInterruptors, postFormActions } from '@client/store';
import { isMobile } from '@client/scripts/is-mobile';
import { throttle } from 'throttle-debounce';
import MkInfo from '@client/components/ui/info.vue';
import { defaultStore } from '@client/store';
export default defineComponent({
components: {
@@ -212,7 +218,10 @@ export default defineComponent({
max(): number {
return this.$instance ? this.$instance.maxNoteTextLength : 1000;
}
},
withHashtags: defaultStore.makeGetterSetter('postFormWithHashtags'),
hashtags: defaultStore.makeGetterSetter('postFormHashtags'),
},
watch: {
@@ -303,6 +312,7 @@ export default defineComponent({
// TODO: detach when unmount
new Autocomplete(this.$refs.text, this, { model: 'text' });
new Autocomplete(this.$refs.cw, this, { model: 'cw' });
new Autocomplete(this.$refs.hashtags, this, { model: 'hashtags' });
this.$nextTick(() => {
// 書きかけの投稿を復元
@@ -605,6 +615,11 @@ export default defineComponent({
viaMobile: isMobile
};
if (this.withHashtags) {
const hashtags = this.hashtags.trim().split(' ').map(x => x.startsWith('#') ? x : '#' + x).join(' ');
data.text = data.text ? `${data.text} ${hashtags}` : hashtags;
}
// plugin
if (notePostInterruptors.length > 0) {
for (const interruptor of notePostInterruptors) {
@@ -618,8 +633,8 @@ export default defineComponent({
this.$nextTick(() => {
this.deleteDraft();
this.$emit('posted');
if (this.text && this.text != '') {
const hashtags = mfm.parse(this.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
if (data.text && data.text != '') {
const hashtags = mfm.parse(data.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
}
@@ -649,7 +664,7 @@ export default defineComponent({
},
showActions(ev) {
os.modalMenu(postFormActions.map(action => ({
os.popupMenu(postFormActions.map(action => ({
text: action.title,
action: () => {
action.handler({
@@ -785,6 +800,7 @@ export default defineComponent({
}
> .cw,
> .hashtags,
> .text {
display: block;
box-sizing: border-box;
@@ -813,6 +829,13 @@ export default defineComponent({
border-bottom: solid 0.5px var(--divider);
}
> .hashtags {
z-index: 1;
padding-top: 8px;
padding-bottom: 8px;
border-top: solid 0.5px var(--divider);
}
> .text {
max-width: 100%;
min-width: 100%;
@@ -872,6 +895,7 @@ export default defineComponent({
}
> .cw,
> .hashtags,
> .text {
padding: 0 16px;
}

View File

@@ -1,10 +1,10 @@
<template>
<div class="_card">
<div class="_content">
<MkInput v-model:value="text">
<span>Text</span>
<MkInput v-model="text">
<template #label>Text</template>
</MkInput>
<MkSwitch v-model:value="flag">
<MkSwitch v-model="flag">
<span>Switch is now {{ flag ? 'on' : 'off' }}</span>
</MkSwitch>
<div style="margin: 32px 0;">
@@ -93,7 +93,7 @@ export default defineComponent({
},
async openMenu(ev) {
os.modalMenu([{
os.popupMenu([{
type: 'label',
text: 'Fruits'
}, {

View File

@@ -3,15 +3,13 @@
<div class="auth _section">
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
<div class="normal-signin" v-if="!totpLogin">
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:value="onUsernameChange">
<span>{{ $ts.username }}</span>
<MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange">
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
</MkInput>
<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
<span>{{ $ts.password }}</span>
<MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
<template #prefix><i class="fas fa-lock"></i></template>
<template #desc><button class="_textButton" @click="resetPassword">{{ $ts.forgotPassword }}</button></template>
<template #caption><button class="_textButton" @click="resetPassword" type="button">{{ $ts.forgotPassword }}</button></template>
</MkInput>
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
</div>
@@ -27,12 +25,12 @@
</div>
<div class="twofa-group totp-group">
<p style="margin-bottom:0;">{{ $ts.twoStepAuthentication }}</p>
<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="user && user.usePasswordLessLogin" required>
<span>{{ $ts.password }}</span>
<MkInput v-model="password" type="password" :with-password-toggle="true" v-if="user && user.usePasswordLessLogin" required>
<template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template>
</MkInput>
<MkInput v-model:value="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
<span>{{ $ts.token }}</span>
<MkInput v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
<template #label>{{ $ts.token }}</template>
<template #prefix><i class="fas fa-gavel"></i></template>
</MkInput>
<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>

View File

@@ -1,39 +1,39 @@
<template>
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
<template v-if="meta">
<MkInput v-if="meta.disableRegistration" v-model:value="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
<span>{{ $ts.invitationCode }}</span>
<MkInput v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
<template #label>{{ $ts.invitationCode }}</template>
<template #prefix><i class="fas fa-key"></i></template>
</MkInput>
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:value="onChangeUsername">
<span>{{ $ts.username }}</span>
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername">
<template #label>{{ $ts.username }}</template>
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
<template #desc>
<template #caption>
<span v-if="usernameState == 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span>
<span v-if="usernameState == 'ok'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span>
<span v-if="usernameState == 'unavailable'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span>
<span v-if="usernameState == 'error'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span>
<span v-if="usernameState == 'invalid-format'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span>
<span v-if="usernameState == 'min-range'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span>
<span v-if="usernameState == 'max-range'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
<span v-if="usernameState == 'ok'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span>
<span v-if="usernameState == 'unavailable'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span>
<span v-if="usernameState == 'error'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span>
<span v-if="usernameState == 'invalid-format'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span>
<span v-if="usernameState == 'min-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span>
<span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
</template>
</MkInput>
<MkInput v-model:value="password" type="password" :autocomplete="Math.random()" required @update:value="onChangePassword">
<span>{{ $ts.password }}</span>
<MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword">
<template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template>
<template #desc>
<p v-if="passwordStrength == 'low'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.weakPassword }}</p>
<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.normalPassword }}</p>
<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</p>
<template #caption>
<span v-if="passwordStrength == 'low'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.weakPassword }}</span>
<span v-if="passwordStrength == 'medium'" style="color: var(--warn)"><i class="fas fa-check fa-fw"></i> {{ $ts.normalPassword }}</span>
<span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span>
</template>
</MkInput>
<MkInput v-model:value="retypedPassword" type="password" :autocomplete="Math.random()" required @update:value="onChangePasswordRetype">
<span>{{ $ts.password }} ({{ $ts.retype }})</span>
<MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype">
<template #label>{{ $ts.password }} ({{ $ts.retype }})</template>
<template #prefix><i class="fas fa-lock"></i></template>
<template #desc>
<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.passwordMatched }}</p>
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</p>
<template #caption>
<span v-if="passwordRetypeState == 'match'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.passwordMatched }}</span>
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span>
</template>
</MkInput>
<label v-if="meta.tosUrl" class="tou">

View File

@@ -3,7 +3,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, markRaw } from 'vue';
import XNotes from './notes.vue';
import * as os from '@client/os';
import * as sound from '@client/scripts/sound';
@@ -92,33 +92,33 @@ export default defineComponent({
this.query = {
antennaId: this.antenna
};
this.connection = os.stream.useChannel('antenna', {
this.connection = markRaw(os.stream.useChannel('antenna', {
antennaId: this.antenna
});
}));
this.connection.on('note', prepend);
} else if (this.src == 'home') {
endpoint = 'notes/timeline';
this.connection = os.stream.useChannel('homeTimeline');
this.connection = markRaw(os.stream.useChannel('homeTimeline'));
this.connection.on('note', prepend);
this.connection2 = os.stream.useChannel('main');
this.connection2 = markRaw(os.stream.useChannel('main'));
this.connection2.on('follow', onChangeFollowing);
this.connection2.on('unfollow', onChangeFollowing);
} else if (this.src == 'local') {
endpoint = 'notes/local-timeline';
this.connection = os.stream.useChannel('localTimeline');
this.connection = markRaw(os.stream.useChannel('localTimeline'));
this.connection.on('note', prepend);
} else if (this.src == 'social') {
endpoint = 'notes/hybrid-timeline';
this.connection = os.stream.useChannel('hybridTimeline');
this.connection = markRaw(os.stream.useChannel('hybridTimeline'));
this.connection.on('note', prepend);
} else if (this.src == 'global') {
endpoint = 'notes/global-timeline';
this.connection = os.stream.useChannel('globalTimeline');
this.connection = markRaw(os.stream.useChannel('globalTimeline'));
this.connection.on('note', prepend);
} else if (this.src == 'mentions') {
endpoint = 'notes/mentions';
this.connection = os.stream.useChannel('main');
this.connection = markRaw(os.stream.useChannel('main'));
this.connection.on('mention', prepend);
} else if (this.src == 'directs') {
endpoint = 'notes/mentions';
@@ -130,16 +130,16 @@ export default defineComponent({
prepend(note);
}
};
this.connection = os.stream.useChannel('main');
this.connection = markRaw(os.stream.useChannel('main'));
this.connection.on('mention', onNote);
} else if (this.src == 'list') {
endpoint = 'notes/user-list-timeline';
this.query = {
listId: this.list
};
this.connection = os.stream.useChannel('userList', {
this.connection = markRaw(os.stream.useChannel('userList', {
listId: this.list
});
}));
this.connection.on('note', prepend);
this.connection.on('userAdded', onUserAdded);
this.connection.on('userRemoved', onUserRemoved);
@@ -148,9 +148,9 @@ export default defineComponent({
this.query = {
channelId: this.channel
};
this.connection = os.stream.useChannel('channel', {
this.connection = markRaw(os.stream.useChannel('channel', {
channelId: this.channel
});
}));
this.connection.on('note', prepend);
}

View File

@@ -14,13 +14,15 @@
<MkInfo warn>{{ information }}</MkInfo>
</div>
<div class="_section">
<MkInput v-model:value="name">{{ $ts.name }}</MkInput>
<MkInput v-model="name">
<template #label>{{ $ts.name }}</template>
</MkInput>
</div>
<div class="_section">
<div style="margin-bottom: 16px;"><b>{{ $ts.permission }}</b></div>
<MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton>
<MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton>
<MkSwitch v-for="kind in (initialPermissions || kinds)" :key="kind" v-model:value="permissions[kind]">{{ $t(`_permissions.${kind}`) }}</MkSwitch>
<MkSwitch v-for="kind in (initialPermissions || kinds)" :key="kind" v-model="permissions[kind]">{{ $t(`_permissions.${kind}`) }}</MkSwitch>
</div>
</XModalWindow>
</template>

View File

@@ -1,6 +1,6 @@
<template>
<component class="bghgjjyj _button"
:is="link ? 'a' : 'button'"
:is="link ? 'MkA' : 'button'"
:class="{ inline, primary, danger, full }"
:type="type"
@click="$emit('click', $event)"
@@ -115,6 +115,7 @@ export default defineComponent({
z-index: 1; // 他コンポーネントのbox-shadowに隠されないようにするため
display: block;
min-width: 100px;
width: max-content;
padding: 8px 14px;
text-align: center;
font-weight: normal;
@@ -125,6 +126,7 @@ export default defineComponent({
background: var(--buttonBg);
border-radius: 999px;
overflow: hidden;
box-sizing: border-box;
&:not(:disabled):hover {
background: var(--buttonHoverBg);
@@ -140,7 +142,7 @@ export default defineComponent({
&.primary {
font-weight: bold;
color: #fff !important;
color: var(--fgOnAccent) !important;
background: var(--accent);
&:not(:disabled):hover {

View File

@@ -99,9 +99,12 @@ export default defineComponent({
z-index: 10;
position: sticky;
top: var(--stickyTop, 0px);
background: var(--panel);
/* TODO panelの半透明バージョンをプログラマティックに作りたい
background: var(--X17);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(20px);
*/
> .title {
margin: 0;

View File

@@ -1,32 +1,9 @@
<template>
<div class="juejbjww" :class="{ focused, filled, inline, disabled }">
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input">
<span class="label" ref="labelEl"><slot></slot></span>
<span class="title" ref="title">
<slot name="title"></slot>
<span class="warning" v-if="invalid"><i class="fas fa-exclamation-circle"></i>{{ $refs.input.validationMessage }}</span>
</span>
<div class="matxzzsk">
<div class="label" @click="focus"><slot name="label"></slot></div>
<div class="input" :class="{ inline, disabled, focused }">
<div class="prefix" ref="prefixEl"><slot name="prefix"></slot></div>
<input v-if="debounce" ref="inputEl"
v-debounce="500"
:type="type"
v-model.lazy="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
:step="step"
@focus="focused = true"
@blur="focused = false"
@keydown="onKeydown($event)"
@input="onInput"
:list="id"
>
<input v-else ref="inputEl"
<input ref="inputEl"
:type="type"
v-model="v"
:disabled="disabled"
@@ -48,23 +25,25 @@
</datalist>
<div class="suffix" ref="suffixEl"><slot name="suffix"></slot></div>
</div>
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
<div class="desc _caption"><slot name="desc"></slot></div>
<div class="caption"><slot name="caption"></slot></div>
<MkButton v-if="manualSave && changed" @click="updated" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
import debounce from 'v-debounce';
import * as os from '@client/os';
import MkButton from './button.vue';
import { debounce } from 'throttle-debounce';
export default defineComponent({
directives: {
debounce
components: {
MkButton,
},
props: {
value: {
required: false
modelValue: {
required: true
},
type: {
type: String,
@@ -104,9 +83,6 @@ export default defineComponent({
step: {
required: false
},
debounce: {
required: false
},
datalist: {
type: Array,
required: false,
@@ -116,15 +92,23 @@ export default defineComponent({
required: false,
default: false
},
save: {
type: Function,
debounce: {
type: Boolean,
required: false,
default: false
},
manualSave: {
type: Boolean,
required: false,
default: false
},
},
emits: ['change', 'keydown', 'enter'],
emits: ['change', 'keydown', 'enter', 'update:modelValue'],
setup(props, context) {
const { value, type, autofocus } = toRefs(props);
const v = ref(value.value);
const { modelValue, type, autofocus } = toRefs(props);
const v = ref(modelValue.value);
const id = Math.random().toString(); // TODO: uuid?
const focused = ref(false);
const changed = ref(false);
@@ -133,7 +117,6 @@ export default defineComponent({
const inputEl = ref(null);
const prefixEl = ref(null);
const suffixEl = ref(null);
const labelEl = ref(null);
const focus = () => inputEl.value.focus();
const onInput = (ev) => {
@@ -148,15 +131,28 @@ export default defineComponent({
}
};
watch(value, newValue => {
const updated = () => {
changed.value = false;
if (type?.value === 'number') {
context.emit('update:modelValue', parseFloat(v.value));
} else {
context.emit('update:modelValue', v.value);
}
};
const debouncedUpdated = debounce(1000, updated);
watch(modelValue, newValue => {
v.value = newValue;
});
watch(v, newValue => {
if (type?.value === 'number') {
context.emit('update:value', parseFloat(newValue));
} else {
context.emit('update:value', newValue);
if (!props.manualSave) {
if (props.debounce) {
debouncedUpdated();
} else {
updated();
}
}
invalid.value = inputEl.value.validity.badInput;
@@ -172,7 +168,6 @@ export default defineComponent({
// 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
const clock = setInterval(() => {
if (prefixEl.value) {
labelEl.value.style.left = (prefixEl.value.offsetLeft + prefixEl.value.offsetWidth) + 'px';
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
@@ -200,148 +195,78 @@ export default defineComponent({
inputEl,
prefixEl,
suffixEl,
labelEl,
focus,
onInput,
onKeydown,
updated,
};
},
});
</script>
<style lang="scss" scoped>
.juejbjww {
position: relative;
margin: 32px 0;
.matxzzsk {
margin: 1.5em 0;
&:not(.inline):first-child {
margin-top: 8px;
> .label {
font-size: 0.85em;
padding: 0 0 8px 12px;
user-select: none;
&:empty {
display: none;
}
}
&:not(.inline):last-child {
margin-bottom: 8px;
}
> .caption {
font-size: 0.8em;
padding: 8px 0 0 12px;
color: var(--fgTransparentWeak);
> .icon {
position: absolute;
top: 0;
left: 0;
width: 24px;
text-align: center;
line-height: 32px;
&:not(:empty) + .input {
margin-left: 28px;
&:empty {
display: none;
}
}
> .input {
$height: 42px;
position: relative;
&:before {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: var(--inputBorder);
}
&:after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: var(--accent);
opacity: 0;
transform: scaleX(0.12);
transition: border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
will-change: border opacity transform;
}
> .label {
position: absolute;
z-index: 1;
top: 0;
left: 0;
pointer-events: none;
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
transition-duration: 0.3s;
font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
//will-change transform
transform-origin: top left;
transform: scale(1);
}
> .title {
position: absolute;
z-index: 1;
top: -17px;
left: 0 !important;
pointer-events: none;
font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
//will-change transform
transform-origin: top left;
transform: scale(.75);
white-space: nowrap;
width: 133%;
overflow: hidden;
text-overflow: ellipsis;
> .warning {
margin-left: 0.5em;
color: var(--infoWarnFg);
> svg {
margin-right: 0.1em;
}
}
}
> input {
$height: 32px;
appearance: none;
-webkit-appearance: none;
display: block;
height: $height;
width: 100%;
margin: 0;
padding: 0;
padding: 0 12px;
font: inherit;
font-weight: normal;
font-size: 1em;
line-height: $height;
color: var(--inputText);
background: transparent;
border: none;
border-radius: 0;
color: var(--fg);
background: var(--panel);
border: solid 1px var(--inputBorder);
border-radius: 6px;
outline: none;
box-shadow: none;
box-sizing: border-box;
transition: border-color 0.1s ease-out;
&[type='file'] {
display: none;
&:hover {
border-color: var(--inputBorderHover);
}
}
> .prefix,
> .suffix {
display: block;
display: flex;
align-items: center;
position: absolute;
z-index: 1;
top: 0;
padding: 0 12px;
font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
height: $height;
pointer-events: none;
&:empty {
@@ -360,67 +285,33 @@ export default defineComponent({
> .prefix {
left: 0;
padding-right: 4px;
padding-right: 6px;
}
> .suffix {
right: 0;
padding-left: 4px;
}
}
> .save {
margin: 6px 0 0 0;
font-size: 0.8em;
}
> .desc {
margin: 6px 0 0 0;
&:empty {
display: none;
padding-left: 6px;
}
* {
&.inline {
display: inline-block;
margin: 0;
}
}
&.focused {
> .input {
&:after {
opacity: 1;
transform: scaleX(1);
}
> .label {
color: var(--accent);
&.focused {
> input {
border-color: var(--accent);
//box-shadow: 0 0 0 4px var(--focus);
}
}
}
&.focused,
&.filled {
> .input {
> .label {
top: -17px;
left: 0 !important;
transform: scale(0.75);
&.disabled {
opacity: 0.7;
&, * {
cursor: not-allowed !important;
}
}
}
&.inline {
display: inline-block;
margin: 0;
}
&.disabled {
opacity: 0.7;
&, * {
cursor: not-allowed !important;
}
}
}
</style>

View File

@@ -171,13 +171,13 @@ export default defineComponent({
}
&:hover {
color: #fff;
color: var(--fgOnAccent);
background: var(--accent);
text-decoration: none;
}
&:active {
color: #fff;
color: var(--fgOnAccent);
background: var(--accentDarken);
}

View File

@@ -1,19 +1,20 @@
<template>
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkMenu :items="items" :align="align" @close="$refs.modal.close()" class="_popup"/>
</MkModal>
<MkPopup ref="popup" :src="src" @closed="$emit('closed')">
<MkMenu :items="items" :align="align" @close="$refs.popup.close()" class="_popup _shadow"/>
</MkPopup>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkModal from './modal.vue';
import MkPopup from './popup.vue';
import MkMenu from './menu.vue';
export default defineComponent({
components: {
MkModal,
MkPopup,
MkMenu,
},
props: {
items: {
type: Array,
@@ -31,17 +32,7 @@ export default defineComponent({
required: false
},
},
emits: ['closed'],
computed: {
keymap(): any {
return {
'esc': () => this.$refs.modal.close(),
};
},
},
emits: ['close', 'closed'],
});
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,213 @@
<template>
<transition :name="$store.state.animation ? 'popup-menu' : ''" :duration="$store.state.animation ? 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" class="ccczpooj" :class="{ front, fixed, top: position === 'top' }" ref="content" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<slot></slot>
</div>
</transition>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null;
const position = window.getComputedStyle(el).getPropertyValue('position');
if (position === 'fixed') {
return el;
} else {
return getFixedContainer(el.parentElement);
}
}
export default defineComponent({
props: {
manualShowing: {
type: Boolean,
required: false,
default: null,
},
srcCenter: {
type: Boolean,
required: false
},
src: {
type: Object as PropType<HTMLElement>,
required: false,
},
position: {
required: false
},
front: {
type: Boolean,
required: false,
default: false,
}
},
emits: ['opening', 'click', 'esc', 'close', 'closed'],
data() {
return {
showing: true,
fixed: false,
transformOrigin: 'center',
contentClicking: false,
};
},
mounted() {
this.$watch('src', () => {
if (this.src) {
this.src.style.pointerEvents = 'none';
}
this.fixed = getFixedContainer(this.src) != null;
this.$nextTick(() => {
this.align();
});
}, { immediate: true });
this.$nextTick(() => {
const popover = this.$refs.content as any;
new ResizeObserver((entries, observer) => {
this.align();
}).observe(popover);
});
document.addEventListener('mousedown', this.onDocumentClick, { passive: true });
},
beforeUnmount() {
document.removeEventListener('mousedown', this.onDocumentClick);
},
methods: {
align() {
if (this.src == null) return;
const popover = this.$refs.content as any;
if (popover == null) return;
const rect = this.src.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
let left;
let top;
if (this.srcCenter) {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.src.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + (this.src.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
} else {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.src.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + this.src.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (this.fixed) {
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
}
if (top + height > window.innerHeight) {
top = window.innerHeight - height;
}
} else {
if (left + width - window.pageXOffset > window.innerWidth) {
left = window.innerWidth - width + window.pageXOffset - 1;
}
if (top + height - window.pageYOffset > window.innerHeight) {
top = window.innerHeight - height + window.pageYOffset - 1;
}
}
if (top < 0) {
top = 0;
}
if (left < 0) {
left = 0;
}
if (top > rect.top + (this.fixed ? 0 : window.pageYOffset)) {
this.transformOrigin = 'center top';
} else {
this.transformOrigin = 'center';
}
popover.style.left = left + 'px';
popover.style.top = top + 'px';
},
childRendered() {
// モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する
const content = this.$refs.content.children[0];
content.addEventListener('mousedown', e => {
this.contentClicking = true;
window.addEventListener('mouseup', e => {
// click イベントより先に mouseup イベントが発生するかもしれないのでちょっと待つ
setTimeout(() => {
this.contentClicking = false;
}, 100);
}, { passive: true, once: true });
}, { passive: true });
},
close() {
if (this.src) this.src.style.pointerEvents = 'auto';
this.showing = false;
this.$emit('close');
},
onClosed() {
this.$emit('closed');
},
onDocumentClick(ev) {
const flyoutElement = this.$refs.content;
let targetElement = ev.target;
do {
if (targetElement === flyoutElement) {
return;
}
targetElement = targetElement.parentNode;
} while (targetElement);
this.close();
}
}
});
</script>
<style lang="scss" scoped>
.popup-menu-enter-active {
transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important;
}
.popup-menu-leave-active {
transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), transform 0.2s cubic-bezier(0.4, 0, 1, 1) !important;
}
.popup-menu-enter-from, .popup-menu-leave-to {
pointer-events: none;
opacity: 0;
transform: scale(0.9);
}
.ccczpooj {
position: absolute;
z-index: 10000;
&.fixed {
position: fixed;
}
&.front {
z-index: 20000;
}
}
</style>

View File

@@ -1,185 +1,218 @@
<template>
<div class="eiipwacr" :class="{ focused, disabled, filled, inline }">
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input" @click="focus">
<span class="label" ref="label"><slot name="label"></slot></span>
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<select ref="input"
<div class="vblkjoeq">
<div class="label" @click="focus"><slot name="label"></slot></div>
<div class="input" :class="{ inline, disabled, focused }">
<div class="prefix" ref="prefixEl"><slot name="prefix"></slot></div>
<select ref="inputEl"
v-model="v"
:required="required"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
@focus="focused = true"
@blur="focused = false"
@input="onInput"
>
<slot></slot>
</select>
<div class="suffix">
<slot name="suffix">
<i class="fas fa-chevron-down"></i>
</slot>
</div>
<div class="suffix" ref="suffixEl"><i class="fas fa-chevron-down"></i></div>
</div>
<div class="text"><slot name="text"></slot></div>
<div class="caption"><slot name="caption"></slot></div>
<MkButton v-if="manualSave && changed" @click="updated" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
import MkButton from './button.vue';
export default defineComponent({
components: {
MkButton,
},
props: {
value: {
required: false
modelValue: {
required: true
},
required: {
type: Boolean,
required: false
},
readonly: {
type: Boolean,
required: false
},
disabled: {
type: Boolean,
required: false
},
placeholder: {
type: String,
required: false
},
autofocus: {
type: Boolean,
required: false,
default: false
},
inline: {
type: Boolean,
required: false,
default: false
},
manualSave: {
type: Boolean,
required: false,
default: false
},
},
data() {
emits: ['change', 'update:modelValue'],
setup(props, context) {
const { modelValue, autofocus } = toRefs(props);
const v = ref(modelValue.value);
const focused = ref(false);
const changed = ref(false);
const invalid = ref(false);
const filled = computed(() => v.value !== '' && v.value != null);
const inputEl = ref(null);
const prefixEl = ref(null);
const suffixEl = ref(null);
const focus = () => inputEl.value.focus();
const onInput = (ev) => {
changed.value = true;
context.emit('change', ev);
};
const updated = () => {
changed.value = false;
context.emit('update:modelValue', v.value);
};
watch(modelValue, newValue => {
v.value = newValue;
});
watch(v, newValue => {
if (!props.manualSave) {
updated();
}
invalid.value = inputEl.value.validity.badInput;
});
onMounted(() => {
nextTick(() => {
if (autofocus.value) {
focus();
}
// このコンポーネントが作成された時、非表示状態である場合がある
// 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
const clock = setInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100);
onUnmounted(() => {
clearInterval(clock);
});
});
});
return {
focused: false,
v,
focused,
invalid,
changed,
filled,
inputEl,
prefixEl,
suffixEl,
focus,
onInput,
updated,
};
},
computed: {
v: {
get() {
return this.value;
},
set(v) {
this.$emit('update:value', v);
}
},
filled(): boolean {
return true;
}
},
mounted() {
if (this.$refs.prefix) {
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
}
},
methods: {
focus() {
this.$refs.input.focus();
}
}
});
</script>
<style lang="scss" scoped>
.eiipwacr {
position: relative;
margin: 32px 0;
.vblkjoeq {
margin: 1.5em 0;
&:not(.inline):first-child {
margin-top: 8px;
> .label {
font-size: 0.85em;
padding: 0 0 8px 12px;
user-select: none;
&:empty {
display: none;
}
}
&:not(.inline):last-child {
margin-bottom: 8px;
}
> .caption {
font-size: 0.8em;
padding: 8px 0 0 12px;
color: var(--fgTransparentWeak);
> .icon {
position: absolute;
top: 0;
left: 0;
width: 24px;
text-align: center;
line-height: 32px;
&:not(:empty) + .input {
margin-left: 28px;
&:empty {
display: none;
}
}
> .input {
display: flex;
$height: 42px;
position: relative;
&:before {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: var(--inputBorder);
}
&:after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: var(--accent);
opacity: 0;
transform: scaleX(0.12);
transition: border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
will-change: border opacity transform;
}
> .label {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
transition-duration: 0.3s;
font-size: 1em;
line-height: 32px;
pointer-events: none;
//will-change transform
transform-origin: top left;
transform: scale(1);
}
> select {
appearance: none;
-webkit-appearance: none;
display: block;
flex: 1;
height: $height;
width: 100%;
padding: 0;
margin: 0;
padding: 0 12px;
font: inherit;
font-weight: normal;
font-size: 1em;
height: 32px;
background: none;
border: none;
border-radius: 0;
color: var(--fg);
background: var(--panel);
border: solid 1px var(--inputBorder);
border-radius: 6px;
outline: none;
box-shadow: none;
appearance: none;
-webkit-appearance: none;
color: var(--fg);
box-sizing: border-box;
cursor: pointer;
transition: border-color 0.1s ease-out;
option,
optgroup {
color: var(--fg);
background: var(--bg);
&:hover {
border-color: var(--inputBorderHover);
}
}
> .prefix,
> .suffix {
display: block;
align-self: center;
justify-self: center;
display: flex;
align-items: center;
position: absolute;
z-index: 1;
top: 0;
padding: 0 12px;
font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
height: $height;
pointer-events: none;
&:empty {
@@ -187,53 +220,41 @@ export default defineComponent({
}
> * {
display: block;
display: inline-block;
min-width: 16px;
max-width: 150px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
> .prefix {
padding-right: 4px;
left: 0;
padding-right: 6px;
}
> .suffix {
padding-left: 4px;
}
}
> .text {
margin: 6px 0;
font-size: 0.8em;
&:empty {
display: none;
right: 0;
padding-left: 6px;
}
* {
&.inline {
display: inline-block;
margin: 0;
}
}
&.focused {
> .input {
&:after {
opacity: 1;
transform: scaleX(1);
}
> .label {
color: var(--accent);
&.focused {
> select {
border-color: var(--accent);
}
}
}
&.focused,
&.filled {
> .input {
> .label {
top: -17px;
left: 0 !important;
transform: scale(0.75);
&.disabled {
opacity: 0.7;
&, * {
cursor: not-allowed !important;
}
}
}

View File

@@ -18,7 +18,7 @@
</span>
<span class="label">
<span><slot></slot></span>
<p><slot name="desc"></slot></p>
<p><slot name="caption"></slot></p>
</span>
</div>
</template>
@@ -28,7 +28,7 @@ import { defineComponent } from 'vue';
export default defineComponent({
props: {
value: {
modelValue: {
type: Boolean,
default: false
},
@@ -39,13 +39,13 @@ export default defineComponent({
},
computed: {
checked(): boolean {
return this.value;
return this.modelValue;
}
},
methods: {
toggle() {
if (this.disabled) return;
this.$emit('update:value', !this.checked);
this.$emit('update:modelValue', !this.checked);
}
}
});
@@ -136,7 +136,7 @@ export default defineComponent({
> p {
margin: 0;
opacity: 0.7;
color: var(--fgTransparentWeak);
font-size: 90%;
}
}

View File

@@ -1,30 +1,45 @@
<template>
<div class="adhpbeos" :class="{ focused, filled, tall, pre }">
<div class="input">
<span class="label" ref="label"><slot></slot></span>
<textarea ref="input" :class="{ code, _monospace: code }"
:value="value"
<div class="adhpbeos">
<div class="label" @click="focus"><slot name="label"></slot></div>
<div class="input" :class="{ disabled, focused, tall, pre }">
<textarea ref="inputEl"
:class="{ code, _monospace: code }"
v-model="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="!code"
@input="onInput"
:spellcheck="spellcheck"
@focus="focused = true"
@blur="focused = false"
@keydown="onKeydown($event)"
@input="onInput"
></textarea>
</div>
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $ts.save }}</button>
<div class="desc _caption"><slot name="desc"></slot></div>
<div class="caption"><slot name="caption"></slot></div>
<MkButton v-if="manualSave && changed" @click="updated" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
import MkButton from './button.vue';
import { debounce } from 'throttle-debounce';
export default defineComponent({
components: {
MkButton,
},
props: {
value: {
modelValue: {
required: true
},
type: {
type: String,
required: false
},
required: {
@@ -35,14 +50,29 @@ export default defineComponent({
type: Boolean,
required: false
},
disabled: {
type: Boolean,
required: false
},
pattern: {
type: String,
required: false
},
autocomplete: {
placeholder: {
type: String,
required: false
},
autofocus: {
type: Boolean,
required: false,
default: false
},
autocomplete: {
required: false
},
spellcheck: {
required: false
},
code: {
type: Boolean,
required: false
@@ -57,169 +87,164 @@ export default defineComponent({
required: false,
default: false
},
save: {
type: Function,
debounce: {
type: Boolean,
required: false,
default: false
},
manualSave: {
type: Boolean,
required: false,
default: false
},
},
data() {
emits: ['change', 'keydown', 'enter', 'update:modelValue'],
setup(props, context) {
const { modelValue, autofocus } = toRefs(props);
const v = ref(modelValue.value);
const focused = ref(false);
const changed = ref(false);
const invalid = ref(false);
const filled = computed(() => v.value !== '' && v.value != null);
const inputEl = ref(null);
const focus = () => inputEl.value.focus();
const onInput = (ev) => {
changed.value = true;
context.emit('change', ev);
};
const onKeydown = (ev: KeyboardEvent) => {
context.emit('keydown', ev);
if (ev.code === 'Enter') {
context.emit('enter');
}
};
const updated = () => {
changed.value = false;
context.emit('update:modelValue', v.value);
};
const debouncedUpdated = debounce(1000, updated);
watch(modelValue, newValue => {
v.value = newValue;
});
watch(v, newValue => {
if (!props.manualSave) {
if (props.debounce) {
debouncedUpdated();
} else {
updated();
}
}
invalid.value = inputEl.value.validity.badInput;
});
onMounted(() => {
nextTick(() => {
if (autofocus.value) {
focus();
}
});
});
return {
focused: false,
changed: false,
}
v,
focused,
invalid,
changed,
filled,
inputEl,
focus,
onInput,
onKeydown,
updated,
};
},
computed: {
filled(): boolean {
return this.value != '' && this.value != null;
}
},
methods: {
focus() {
this.$refs.input.focus();
},
onInput(ev) {
this.changed = true;
this.$emit('update:value', ev.target.value);
}
}
});
</script>
<style lang="scss" scoped>
.adhpbeos {
margin: 42px 0 32px 0;
position: relative;
margin: 1.5em 0;
&:first-child {
margin-top: 16px;
> .label {
font-size: 0.85em;
padding: 0 0 8px 12px;
user-select: none;
&:empty {
display: none;
}
}
&:last-child {
margin-bottom: 0;
> .caption {
font-size: 0.8em;
padding: 8px 0 0 12px;
color: var(--fgTransparentWeak);
&:empty {
display: none;
}
}
> .input {
position: relative;
&:before {
content: '';
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: none;
border: solid 1px var(--inputBorder);
border-radius: 3px;
pointer-events: none;
}
&:after {
content: '';
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: none;
border: solid 2px var(--accent);
border-radius: 3px;
opacity: 0;
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}
> .label {
position: absolute;
top: 6px;
left: 12px;
pointer-events: none;
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
transition-duration: 0.3s;
font-size: 1em;
line-height: 32px;
pointer-events: none;
//will-change transform
transform-origin: top left;
transform: scale(1);
}
> textarea {
appearance: none;
-webkit-appearance: none;
display: block;
width: 100%;
min-width: 100%;
max-width: 100%;
min-height: 130px;
margin: 0;
padding: 12px;
box-sizing: border-box;
font: inherit;
font-weight: normal;
font-size: 1em;
background: transparent;
border: none;
border-radius: 0;
color: var(--fg);
background: var(--panel);
border: solid 1px var(--inputBorder);
border-radius: 6px;
outline: none;
box-shadow: none;
color: var(--fg);
box-sizing: border-box;
transition: border-color 0.1s ease-out;
&.code {
tab-size: 2;
&:hover {
border-color: var(--inputBorderHover);
}
}
}
> .save {
margin: 6px 0 0 0;
font-size: 0.8em;
}
> .desc {
margin: 6px 0 0 0;
&:empty {
display: none;
}
* {
margin: 0;
}
}
&.focused {
> .input {
&:after {
opacity: 1;
}
> .label {
color: var(--accent);
&.focused {
> textarea {
border-color: var(--accent);
}
}
}
&.focused,
&.filled {
> .input {
> .label {
top: -24px;
left: 0 !important;
transform: scale(0.75);
&.disabled {
opacity: 0.7;
&, * {
cursor: not-allowed !important;
}
}
}
&.tall {
> .input {
&.tall {
> textarea {
min-height: 200px;
}
}
}
&.pre {
> .input {
&.pre {
> textarea {
white-space: pre;
}

View File

@@ -3,15 +3,11 @@
<div class="ebkgocck" :class="{ front }" v-if="showing">
<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
<div class="header" :class="{ mini }" @contextmenu.prevent.stop="onContextmenu">
<slot v-if="closeRight" name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
<button v-else class="_button" @click="close()"><i class="fas fa-times"></i></button>
<button v-if="closeButton" class="_button" @click="close()"><i class="fas fa-times"></i></button>
<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
<slot name="header"></slot>
</span>
<button v-if="closeRight" class="_button" @click="close()"><i class="fas fa-times"></i></button>
<slot v-else name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
</div>
<div class="body" v-if="padding">
<div class="_section">
@@ -86,10 +82,10 @@ export default defineComponent({
required: false,
default: false,
},
closeRight: {
closeButton: {
type: Boolean,
required: false,
default: false,
default: true,
},
mini: {
type: Boolean,

View File

@@ -31,7 +31,7 @@
import { defineComponent } from 'vue';
import { parseAcct } from '@/misc/acct';
import MkFollowButton from './follow-button.vue';
import { userPage } from '../filters/user';
import { userPage } from '@client/filters/user';
export default defineComponent({
components: {

View File

@@ -18,7 +18,7 @@
import { defineComponent } from 'vue';
import paging from '@client/scripts/paging';
import MkUserInfo from './user-info.vue';
import { userPage } from '../filters/user';
import { userPage } from '@client/filters/user';
export default defineComponent({
components: {

View File

@@ -35,7 +35,7 @@
import { defineComponent } from 'vue';
import { parseAcct } from '@/misc/acct';
import MkFollowButton from './follow-button.vue';
import { userPage } from '../filters/user';
import { userPage } from '@client/filters/user';
import * as os from '@client/os';
export default defineComponent({

View File

@@ -10,9 +10,15 @@
<template #header>{{ $ts.selectUser }}</template>
<div class="tbhwbxda _monolithic_">
<div class="_section">
<div class="inputs">
<MkInput v-model:value="username" class="input" @update:value="search" ref="username"><span>{{ $ts.username }}</span><template #prefix>@</template></MkInput>
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $ts.host }}</span><template #prefix>@</template></MkInput>
<div class="_inputSplit _inputNoTopMargin _inputNoBottomMargin">
<MkInput v-model="username" class="input" @update:modelValue="search" ref="username">
<template #label>{{ $ts.username }}</template>
<template #prefix>@</template>
</MkInput>
<MkInput v-model="host" class="input" @update:modelValue="search">
<template #label>{{ $ts.host }}</template>
<template #prefix>@</template>
</MkInput>
</div>
</div>
<div class="_section result" v-if="username != '' || host != ''" :class="{ hit: users.length > 0 }">
@@ -138,14 +144,6 @@ export default defineComponent({
padding: 0;
}
> .inputs {
> .input {
display: inline-block;
width: 50%;
margin: 0;
}
}
> .users {
flex: 1;
overflow: auto;

View File

@@ -28,7 +28,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import paging from '@client/scripts/paging';
import { userPage } from '../filters/user';
import { userPage } from '@client/filters/user';
export default defineComponent({
mixins: [

View File

@@ -2,7 +2,7 @@
<div class="vjoppmmu">
<template v-if="edit">
<header>
<MkSelect v-model:value="widgetAdderSelected" style="margin-bottom: var(--margin)">
<MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)">
<template #label>{{ $ts.selectWidget }}</template>
<option v-for="widget in widgetDefs" :value="widget" :key="widget">{{ $t(`_widgets.${widget}`) }}</option>
</MkSelect>

View File

@@ -6,7 +6,7 @@ import '@client/style.scss';
import * as Sentry from '@sentry/browser';
import { Integrations } from '@sentry/tracing';
import { computed, createApp, watch } from 'vue';
import { computed, createApp, watch, markRaw } from 'vue';
import widgets from '@client/widgets';
import directives from '@client/directives';
@@ -282,7 +282,7 @@ if ($i) {
}
}
const main = stream.useChannel('main', null, 'System');
const main = markRaw(stream.useChannel('main', null, 'System'));
// 自分の情報が更新されたとき
main.on('meUpdated', i => {

View File

@@ -113,6 +113,16 @@ export const menuDef = {
icon: 'fas fa-satellite-dish',
to: '/channels',
},
federation: {
title: 'federation',
icon: 'fas fa-globe',
to: '/federation',
},
emojis: {
title: 'emojis',
icon: 'fas fa-laugh',
to: '/emojis',
},
games: {
title: 'games',
icon: 'fas fa-gamepad',
@@ -133,7 +143,7 @@ export const menuDef = {
title: 'switchUi',
icon: 'fas fa-columns',
action: (ev) => {
os.modalMenu([{
os.popupMenu([{
text: i18n.locale.default,
action: () => {
localStorage.setItem('ui', 'default');

View File

@@ -368,10 +368,10 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea:
});
}
export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
export function popupMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
return new Promise((resolve, reject) => {
let dispose;
popup(import('@client/components/ui/modal-menu.vue'), {
popup(import('@client/components/ui/popup-menu.vue'), {
items,
src,
align: options?.align,

View File

@@ -1,11 +1,11 @@
<template>
<transition :name="$store.state.animation ? 'zoom' : ''" appear>
<div class="_section">
<div class="mjndxjch _content">
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
<p><i class="fas fa-exclamation-triangle"></i> {{ $ts.pageLoadError }}</p>
<p>{{ $ts.pageLoadErrorDescription }}</p>
</div>
<div class="mjndxjch">
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
<p><b><i class="fas fa-exclamation-triangle"></i> {{ $ts.pageLoadError }}</b></p>
<p>{{ $ts.pageLoadErrorDescription }}</p>
<p><MkA to="/docs/general/troubleshooting" class="_link">{{ $ts.troubleshooting }}</MkA></p>
<p v-if="error" class="error">ERROR: {{ error }}</p>
</div>
</transition>
</template>
@@ -19,6 +19,11 @@ export default defineComponent({
components: {
MkButton,
},
props: {
error: {
required: false,
}
},
data() {
return {
[symbols.PAGE_INFO]: {
@@ -32,10 +37,11 @@ export default defineComponent({
<style lang="scss" scoped>
.mjndxjch {
padding: 32px;
text-align: center;
> p {
margin: 0 0 8px 0;
margin: 0 0 12px 0;
}
> .button {
@@ -45,8 +51,12 @@ export default defineComponent({
> img {
vertical-align: bottom;
height: 128px;
margin-bottom: 16px;
margin-bottom: 24px;
border-radius: 16px;
}
> .error {
opacity: 0.7;
}
}
</style>

View File

@@ -272,7 +272,7 @@ export default defineComponent({
showTypeMenu(e: MouseEvent) {
return new Promise<ThemeValue>((resolve) => {
os.modalMenu([{
os.popupMenu([{
text: this.$ts._theme.defaultValue,
action: () => resolve(null),
}, {

View File

@@ -1,13 +1,13 @@
<template>
<div class="_root">
<div class="_block" style="padding: 24px;">
<MkInput v-model:value="endpoint" :datalist="endpoints" @update:value="onEndpointChange()">
<span>Endpoint</span>
<MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()">
<template #label>Endpoint</template>
</MkInput>
<MkTextarea v-model:value="body" code>
<span>Params (JSON or JSON5)</span>
<MkTextarea v-model="body" code>
<template #label>Params (JSON or JSON5)</template>
</MkTextarea>
<MkSwitch v-model:value="withCredential">
<MkSwitch v-model="withCredential">
With credential
</MkSwitch>
<MkButton primary full @click="send" :disabled="sending">
@@ -16,8 +16,8 @@
</MkButton>
</div>
<div v-if="res" class="_block" style="padding: 24px;">
<MkTextarea v-model:value="res" code readonly tall>
<span>Response</span>
<MkTextarea v-model="res" code readonly tall>
<template #label>Response</template>
</MkTextarea>
</div>
</div>

View File

@@ -2,9 +2,13 @@
<div>
<div class="_section">
<div class="_content">
<MkInput v-model:value="name">{{ $ts.name }}</MkInput>
<MkInput v-model="name">
<template #label>{{ $ts.name }}</template>
</MkInput>
<MkTextarea v-model:value="description">{{ $ts.description }}</MkTextarea>
<MkTextarea v-model="description">
<template #label>{{ $ts.description }}</template>
</MkTextarea>
<div class="banner">
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>

View File

@@ -79,7 +79,7 @@ export default defineComponent({
methods: {
menu(ev) {
os.modalMenu([this.isOwned ? {
os.popupMenu([this.isOwned ? {
icon: 'fas fa-pencil-alt',
text: this.$ts.edit,
action: async () => {

View File

@@ -1,9 +1,11 @@
<template>
<div class="qyqbqfal" v-size="{ max: [500] }">
<div class="title">{{ title }}</div>
<div class="body" v-html="body"></div>
<div class="footer">
<MkLink :url="`https://github.com/misskey-dev/misskey/blob/master/src/docs/${lang}/${doc}.md`" class="at">{{ $ts.docSource }}</MkLink>
<div class="main">
<div class="title">{{ title }}</div>
<div class="body" v-html="body"></div>
<div class="footer">
<MkLink :url="`https://github.com/misskey-dev/misskey/blob/master/src/docs/${lang}/${doc}.md`" class="at">{{ $ts.docSource }}</MkLink>
</div>
</div>
</div>
</template>
@@ -62,6 +64,10 @@ export default defineComponent({
fetchDoc() {
fetch(`${url}/doc-assets/${lang}/${this.doc}.md`).then(res => res.text()).then(md => {
this.parse(md);
}).catch(() => {
fetch(`${url}/doc-assets/ja-JP/${this.doc}.md`).then(res => res.text()).then(md => {
this.parse(md);
});
});
},
@@ -105,102 +111,129 @@ export default defineComponent({
<style lang="scss" scoped>
.qyqbqfal {
padding: 32px;
max-width: 800px;
margin: 0 auto;
background: var(--panel);
line-height: 1.5;
&.max-width_500px {
padding: 16px;
}
> .title {
font-size: 1.5em;
font-weight: bold;
padding: 0 0 0.75em 0;
margin: 0 0 1em 0;
border-bottom: solid 2px var(--divider);
}
> .main {
max-width: 800px;
margin: 0 auto;
> .body {
> *:first-child {
margin-top: 0;
> .title {
font-size: 1.5em;
font-weight: bold;
padding: 0 0 0.75em 0;
margin: 0 0 1em 0;
border-bottom: solid 2px var(--divider);
}
> *:last-child {
margin-bottom: 0;
}
> .body {
> *:first-child {
margin-top: 0;
}
::v-deep(a) {
color: var(--link);
}
> *:last-child {
margin-bottom: 0;
}
::v-deep(blockquote) {
display: block;
margin: 8px;
padding: 6px 0 6px 12px;
color: var(--fg);
border-left: solid 3px var(--fg);
opacity: 0.7;
::v-deep(a) {
color: var(--link);
}
p {
margin: 0;
::v-deep(blockquote) {
display: block;
margin: 8px;
padding: 6px 0 6px 12px;
color: var(--fg);
border-left: solid 3px var(--fg);
opacity: 0.7;
p {
margin: 0;
}
}
::v-deep(h2) {
font-size: 1.25em;
padding: 0 0 0.5em 0;
margin: 1.5em 0 1em 0;
border-bottom: solid 0.5px var(--divider);
}
::v-deep(h3) {
margin: 1.25em 0 0.5em 0;
}
::v-deep(table) {
width: 100%;
max-width: 100%;
overflow: auto;
}
::v-deep(kbd.group) {
display: inline-block;
padding: 2px;
border: 1px solid var(--divider);
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
::v-deep(kbd.key) {
display: inline-block;
padding: 6px 8px;
border: solid 0.5px var(--divider);
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
::v-deep(code) {
display: inline-block;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
tab-size: 2;
background: #272822;
color: #f8f8f2;
border-radius: 6px;
padding: 4px 6px;
}
::v-deep(pre) {
background: #272822;
color: #f8f8f2;
border-radius: 6px;
padding: 12px 16px;
> code {
padding: 0;
}
}
::v-deep(.info) {
font-size: 90%;
background: var(--infoBg);
color: var(--infoFg);
padding: 1em;
margin: 0.75em 0;
border-radius: 6px;
}
::v-deep(.warn) {
font-size: 90%;
background: var(--infoWarnBg);
color: var(--infoWarnFg);
padding: 1em;
margin: 0.75em 0;
border-radius: 6px;
}
}
::v-deep(h2) {
font-size: 1.25em;
padding: 0 0 0.5em 0;
margin: 1.5em 0 1em 0;
border-bottom: solid 0.5px var(--divider);
> .footer {
padding: 1.5em 0 0 0;
margin: 1.5em 0 0 0;
border-top: solid 2px var(--divider);
}
::v-deep(table) {
width: 100%;
max-width: 100%;
overflow: auto;
}
::v-deep(kbd.group) {
display: inline-block;
padding: 2px;
border: 1px solid var(--divider);
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
::v-deep(kbd.key) {
display: inline-block;
padding: 6px 8px;
border: solid 0.5px var(--divider);
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
::v-deep(code) {
display: inline-block;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
tab-size: 2;
background: #272822;
color: #f8f8f2;
border-radius: 6px;
padding: 4px 6px;
}
::v-deep(pre) {
background: #272822;
color: #f8f8f2;
border-radius: 6px;
padding: 12px 16px;
> code {
padding: 0;
}
}
}
> .footer {
padding: 1.5em 0 0 0;
margin: 1.5em 0 0 0;
border-top: solid 2px var(--divider);
}
}
</style>

View File

@@ -1,14 +1,50 @@
<template>
<div>
<main class="_section">
<div class="_content">
<ul>
<li v-for="doc in docs" :key="doc.path">
<MkA :to="`/docs/${doc.path}`">{{ doc.title }}</MkA>
</li>
</ul>
<div class="vtaihdtm">
<div class="search">
<MkInput v-model="query" :debounce="true" type="search" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search">
<template #prefix><i class="fas fa-search"></i></template>
</MkInput>
</div>
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</main>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.admin }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('admin/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div>
</template>
@@ -16,8 +52,15 @@
import { defineComponent } from 'vue';
import { url, lang } from '@client/config';
import * as symbols from '@client/symbols';
import MkFolder from '@client/components/ui/folder.vue';
import MkInput from '@client/components/ui/input.vue';
export default defineComponent({
components: {
MkFolder,
MkInput,
},
data() {
return {
[symbols.PAGE_INFO]: {
@@ -25,13 +68,72 @@ export default defineComponent({
icon: 'fas fa-question-circle'
},
docs: [],
query: null,
}
},
watch: {
query() {
fetch(`${url}/docs.json?lang=${lang}&q=${this.query}`).then(res => res.json()).then(docs => {
this.docs = docs;
});
}
},
created() {
fetch(`${url}/docs.json?lang=${lang}`).then(res => res.json()).then(docs => {
this.docs = docs;
fetch(`${url}/docs.json?lang=ja-JP`).then(res => res.json()).then(jaDocs => {
fetch(`${url}/docs.json?lang=${lang}`).then(res => res.json()).then(docs => {
this.docs = jaDocs.map(doc => {
const exist = docs.find(d => d.path === doc.path);
return exist || doc;
});
});
});
},
});
</script>
<style lang="scss" scoped>
.vtaihdtm {
background: var(--panel);
> .search {
padding: 16px;
}
.docs {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: 0 16px 16px 16px;
> .doc {
display: inline-block;
padding: 16px;
border: solid 1px var(--divider);
border-radius: 6px;
&:hover {
border: solid 1px var(--accent);
text-decoration: none;
}
> .title {
font-weight: bold;
}
> .summary {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9em;
}
> .read {
color: var(--link);
font-size: 0.9em;
}
}
}
}
</style>

View File

@@ -20,7 +20,6 @@ export default defineComponent({
[symbols.PAGE_INFO]: {
title: computed(() => this.folder ? this.folder.name : this.$ts.drive),
icon: 'fas fa-cloud',
menu: () => this.$refs.drive.getMenu()
},
folder: null,
};

151
src/client/pages/emojis.vue Normal file
View File

@@ -0,0 +1,151 @@
<template>
<div class="driuhtrh">
<div class="query">
<MkInput v-model="q" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search">
<template #prefix><i class="fas fa-search"></i></template>
</MkInput>
</div>
<div class="emojis">
<MkFolder v-if="searchEmojis">
<template #header>{{ $ts.searchResult }}</template>
<div class="zuvgdzyt">
<button v-for="emoji in searchEmojis" :key="emoji.name" class="emoji _button" @click="menu(emoji, $event)">
<img :src="emoji.url" class="img" :alt="emoji.name"/>
<div class="body">
<div class="name _monospace">{{ emoji.name }}</div>
<div class="info">{{ emoji.aliases.join(' ') }}</div>
</div>
</button>
</div>
</MkFolder>
<MkFolder v-for="category in customEmojiCategories" :key="category">
<template #header>{{ category || $ts.other }}</template>
<div class="zuvgdzyt">
<button v-for="emoji in customEmojis.filter(e => e.category === category)" :key="emoji.name" class="emoji _button" @click="menu(emoji, $event)">
<img :src="emoji.url" class="img" :alt="emoji.name"/>
<div class="body">
<div class="name _monospace">{{ emoji.name }}</div>
<div class="info">{{ emoji.aliases.join(' ') }}</div>
</div>
</button>
</div>
</MkFolder>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import MkSelect from '@client/components/ui/select.vue';
import MkFolder from '@client/components/ui/folder.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
import { emojiCategories } from '@client/instance';
import copyToClipboard from '@client/scripts/copy-to-clipboard';
export default defineComponent({
components: {
MkButton,
MkInput,
MkSelect,
MkFolder,
},
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.customEmojis,
icon: 'fas fa-laugh'
},
q: '',
customEmojiCategories: emojiCategories,
customEmojis: this.$instance.emojis,
searchEmojis: null,
}
},
watch: {
q() {
if (this.q === '' || this.q == null) {
this.searchEmojis = null;
return;
}
this.searchEmojis = this.customEmojis.filter(e => e.name.includes(this.q) || e.aliases.includes(this.q));
}
},
methods: {
menu(emoji, ev) {
os.popupMenu([{
type: 'label',
text: ':' + emoji.name + ':',
}, {
text: this.$ts.copy,
icon: 'fas fa-copy',
action: () => {
copyToClipboard(`:${emoji.name}:`);
os.success();
}
}], ev.currentTarget || ev.target);
}
}
});
</script>
<style lang="scss" scoped>
.driuhtrh {
> .query {
background: var(--bg);
padding: 16px;
}
> .emojis {
.zuvgdzyt {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
grid-gap: 12px;
margin: 0 var(--margin) var(--margin) var(--margin);
> .emoji {
display: flex;
align-items: center;
padding: 12px;
text-align: left;
border: solid 1px var(--divider);
border-radius: 8px;
&:hover {
border-color: var(--accent);
}
> .img {
width: 42px;
height: 42px;
}
> .body {
padding: 0 0 0 8px;
white-space: nowrap;
overflow: hidden;
> .name {
text-overflow: ellipsis;
overflow: hidden;
}
> .info {
opacity: 0.5;
font-size: 0.9em;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
}
}
}
</style>

View File

@@ -2,7 +2,10 @@
<div class="lznhrdub _root">
<div>
<div class="_isolated">
<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.searchUser }}</span></MkInput>
<MkInput v-model="query" :debounce="true" type="search">
<template #prefix><i class="fas fa-search"></i></template>
<template #label>{{ $ts.searchUser }}</template>
</MkInput>
</div>
<XUserList v-if="query" class="_gap" :pagination="searchPagination" ref="search"/>

View File

@@ -1,9 +1,12 @@
<template>
<div class="enuoauvw">
<div class="taeiyria">
<div class="query">
<MkInput v-model:value="host" :debounce="true"><span>{{ $ts.host }}</span></MkInput>
<div class="inputs" style="display: flex;">
<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
<MkInput v-model="host" :debounce="true" class="_inputNoTopMargin">
<template #prefix><i class="fas fa-search"></i></template>
<template #label>{{ $ts.host }}</template>
</MkInput>
<div class="_inputSplit _inputNoBottomMargin">
<MkSelect v-model="state">
<template #label>{{ $ts.state }}</template>
<option value="all">{{ $ts.all }}</option>
<option value="federating">{{ $ts.federating }}</option>
@@ -13,7 +16,7 @@
<option value="blocked">{{ $ts.blocked }}</option>
<option value="notResponding">{{ $ts.notResponding }}</option>
</MkSelect>
<MkSelect v-model:value="sort" style="margin: 0; flex: 1;">
<MkSelect v-model="sort">
<template #label>{{ $ts.sort }}</template>
<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option>
<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option>
@@ -38,16 +41,53 @@
</div>
<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state">
<div class="ppgwaixt _block" v-for="instance in items" :key="instance.id" @click="info(instance)">
<div class="host"><i class="fas fa-circle indicator" :class="getStatus(instance)"></i><b>{{ instance.host }}</b></div>
<div class="status">
<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span>
<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span>
<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span>
<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span>
<span class="lastCommunicatedAt"><i class="fas fa-exchange-alt icon"></i><MkTime :time="instance.lastCommunicatedAt"/></span>
<span class="latestStatus"><i class="fas fa-traffic-light icon"></i>{{ instance.latestStatus || '-' }}</span>
</div>
<div class="dqokceoi">
<MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`">
<div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div>
<div class="table">
<div class="cell">
<div class="key">{{ $ts.registeredAt }}</div>
<div class="value"><MkTime :time="instance.caughtAt"/></div>
</div>
<div class="cell">
<div class="key">{{ $ts.software }}</div>
<div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div>
</div>
<div class="cell">
<div class="key">{{ $ts.version }}</div>
<div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div>
</div>
<div class="cell">
<div class="key">{{ $ts.users }}</div>
<div class="value">{{ instance.usersCount }}</div>
</div>
<div class="cell">
<div class="key">{{ $ts.notes }}</div>
<div class="value">{{ instance.notesCount }}</div>
</div>
<div class="cell">
<div class="key">{{ $ts.sent }}</div>
<div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div>
</div>
<div class="cell">
<div class="key">{{ $ts.received }}</div>
<div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div>
</div>
</div>
<div class="footer">
<span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span>
<span class="pubSub">
<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span>
<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span>
<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span>
<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span>
</span>
<span class="right">
<span class="latestStatus">{{ instance.latestStatus || '-' }}</span>
<span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span>
</span>
</div>
</MkA>
</div>
</MkPagination>
</div>
@@ -59,7 +99,6 @@ import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import MkSelect from '@client/components/ui/select.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import MkInstanceInfo from './instance.vue';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
@@ -117,69 +156,107 @@ export default defineComponent({
methods: {
getStatus(instance) {
if (instance.isSuspended) return 'off';
if (instance.isNotResponding) return 'red';
return 'green';
if (instance.isSuspended) return 'suspended';
if (instance.isNotResponding) return 'error';
return 'alive';
},
info(instance) {
os.popup(MkInstanceInfo, {
instance: instance
}, {}, 'closed');
}
}
});
</script>
<style lang="scss" scoped>
.enuoauvw {
.taeiyria {
> .query {
margin: var(--margin);
background: var(--bg);
padding: 16px;
}
}
.ppgwaixt {
cursor: pointer;
.dqokceoi {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
padding: 16px;
&:hover {
color: var(--accent);
}
> .instance {
padding: 16px;
border: solid 1px var(--divider);
border-radius: 6px;
> .host {
> .indicator {
font-size: 70%;
vertical-align: baseline;
margin-right: 4px;
&:hover {
border: solid 1px var(--accent);
text-decoration: none;
}
&.green {
color: #49c5ba;
}
> .host {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.yellow {
color: #c5a549;
}
&.red {
color: #c54949;
}
&.off {
color: rgba(0, 0, 0, 0.5);
> img {
width: 18px;
height: 18px;
margin-right: 6px;
vertical-align: middle;
}
}
}
> .status {
display: flex;
align-items: center;
font-size: 90%;
> .table {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
grid-gap: 6px;
margin: 6px 0;
font-size: 70%;
> span {
flex: 1;
> .icon {
margin-right: 6px;
> .cell {
> .key, > .value {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
> .key {
opacity: 0.7;
}
> .value {
}
}
}
> .footer {
display: flex;
align-items: center;
> .status {
&.suspended {
opacity: 0.5;
}
&.error {
color: var(--error);
}
&.alive {
color: var(--success);
}
}
> .pubSub {
margin-left: 8px;
}
> .right {
margin-left: auto;
font-size: 0.9em;
> .latestStatus {
border: solid 1px var(--divider);
border-radius: 4px;
margin: 0 8px;
padding: 0 4px;
}
}
}
}

View File

@@ -32,7 +32,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import MkPagination from '@client/components/ui/pagination.vue';
import { userPage, acct } from '../filters/user';
import { userPage, acct } from '@client/filters/user';
import * as os from '@client/os';
import * as symbols from '@client/symbols';

View File

@@ -62,7 +62,7 @@
<div class="_formLabel">{{ $ts.statistics }}</div>
<div class="_formPanel cmhjzshl">
<div class="selects">
<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
<option value="requests">{{ $ts._instanceCharts.requests }}</option>
<option value="users">{{ $ts._instanceCharts.users }}</option>
<option value="users-total">{{ $ts._instanceCharts.usersTotal }}</option>
@@ -75,7 +75,7 @@
<option value="drive-files">{{ $ts._instanceCharts.files }}</option>
<option value="drive-files-total">{{ $ts._instanceCharts.filesTotal }}</option>
</MkSelect>
<MkSelect v-model:value="chartSpan" style="margin: 0;">
<MkSelect v-model="chartSpan" style="margin: 0;">
<option value="hour">{{ $ts.perHour }}</option>
<option value="day">{{ $ts.perDay }}</option>
</MkSelect>

View File

@@ -3,19 +3,19 @@
<div class="_section reports">
<div class="_content">
<div class="inputs" style="display: flex;">
<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
<MkSelect v-model="state" style="margin: 0; flex: 1;">
<template #label>{{ $ts.state }}</template>
<option value="all">{{ $ts.all }}</option>
<option value="unresolved">{{ $ts.unresolved }}</option>
<option value="resolved">{{ $ts.resolved }}</option>
</MkSelect>
<MkSelect v-model:value="targetUserOrigin" style="margin: 0; flex: 1;">
<MkSelect v-model="targetUserOrigin" style="margin: 0; flex: 1;">
<template #label>{{ $ts.targetUserOrigin }}</template>
<option value="combined">{{ $ts.all }}</option>
<option value="local">{{ $ts.local }}</option>
<option value="remote">{{ $ts.remote }}</option>
</MkSelect>
<MkSelect v-model:value="reporterOrigin" style="margin: 0; flex: 1;">
<MkSelect v-model="reporterOrigin" style="margin: 0; flex: 1;">
<template #label>{{ $ts.reporterOrigin }}</template>
<option value="combined">{{ $ts.all }}</option>
<option value="local">{{ $ts.local }}</option>
@@ -68,7 +68,7 @@ import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import MkSelect from '@client/components/ui/select.vue';
import MkPagination from '@client/components/ui/pagination.vue';
import { acct } from '../../filters/user';
import { acct } from '@client/filters/user';
import * as os from '@client/os';
import * as symbols from '@client/symbols';

View File

@@ -4,11 +4,11 @@
<section class="_card _gap ads" v-for="ad in ads">
<div class="_content ad">
<MkAd v-if="ad.url" :specify="ad"/>
<MkInput v-model:value="ad.url" type="url">
<span>URL</span>
<MkInput v-model="ad.url" type="url">
<template #label>URL</template>
</MkInput>
<MkInput v-model:value="ad.imageUrl">
<span>{{ $ts.imageUrl }}</span>
<MkInput v-model="ad.imageUrl">
<template #label>{{ $ts.imageUrl }}</template>
</MkInput>
<div style="margin: 32px 0;">
<MkRadio v-model="ad.place" value="square">square</MkRadio>
@@ -23,14 +23,14 @@
<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
</div>
-->
<MkInput v-model:value="ad.ratio" type="number">
<span>{{ $ts.ratio }}</span>
<MkInput v-model="ad.ratio" type="number">
<template #label>{{ $ts.ratio }}</template>
</MkInput>
<MkInput v-model:value="ad.expiresAt" type="date">
<span>{{ $ts.expiration }}</span>
<MkInput v-model="ad.expiresAt" type="date">
<template #label>{{ $ts.expiration }}</template>
</MkInput>
<MkTextarea v-model:value="ad.memo">
<span>{{ $ts.memo }}</span>
<MkTextarea v-model="ad.memo">
<template #label>{{ $ts.memo }}</template>
</MkTextarea>
<div class="buttons">
<MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>

View File

@@ -3,14 +3,14 @@
<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
<section class="_card _gap announcements" v-for="announcement in announcements">
<div class="_content announcement">
<MkInput v-model:value="announcement.title">
<span>{{ $ts.title }}</span>
<MkInput v-model="announcement.title">
<template #label>{{ $ts.title }}</template>
</MkInput>
<MkTextarea v-model:value="announcement.text">
<span>{{ $ts.text }}</span>
<MkTextarea v-model="announcement.text">
<template #label>{{ $ts.text }}</template>
</MkTextarea>
<MkInput v-model:value="announcement.imageUrl">
<span>{{ $ts.imageUrl }}</span>
<MkInput v-model="announcement.imageUrl">
<template #label>{{ $ts.imageUrl }}</template>
</MkInput>
<p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
<div class="buttons">

View File

@@ -11,11 +11,15 @@
<div class="_monolithic_">
<div class="yigymqpb _section">
<img :src="emoji.url" class="img"/>
<MkInput v-model:value="name"><span>{{ $ts.name }}</span></MkInput>
<MkInput v-model:value="category" :datalist="categories"><span>{{ $ts.category }}</span></MkInput>
<MkInput v-model:value="aliases">
<span>{{ $ts.tags }}</span>
<template #desc>{{ $ts.setMultipleBySeparatingWithSpace }}</template>
<MkInput v-model="name">
<template #label>{{ $ts.name }}</template>
</MkInput>
<MkInput v-model="category" :datalist="categories">
<template #label>{{ $ts.category }}</template>
</MkInput>
<MkInput v-model="aliases">
<template #label>{{ $ts.tags }}</template>
<template #caption>{{ $ts.setMultipleBySeparatingWithSpace }}</template>
</MkInput>
<MkButton danger @click="del()"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
</div>

View File

@@ -7,7 +7,10 @@
<div class="local" v-if="tab === 'local'">
<MkButton primary @click="add" style="margin: var(--margin) auto;"><i class="fas fa-plus"></i> {{ $ts.addEmoji }}</MkButton>
<MkInput v-model:value="query" :debounce="true" type="search" style="margin: var(--margin);"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.search }}</span></MkInput>
<MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);">
<template #prefix><i class="fas fa-search"></i></template>
<template #label>{{ $ts.search }}</template>
</MkInput>
<MkPagination :pagination="pagination" ref="emojis">
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
<template #default="{items}">
@@ -25,8 +28,13 @@
</div>
<div class="remote" v-else-if="tab === 'remote'">
<MkInput v-model:value="queryRemote" :debounce="true" type="search" style="margin: var(--margin);"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.search }}</span></MkInput>
<MkInput v-model:value="host" :debounce="true" style="margin: var(--margin);"><span>{{ $ts.host }}</span></MkInput>
<MkInput v-model="queryRemote" :debounce="true" type="search" style="margin: var(--margin);">
<template #prefix><i class="fas fa-search"></i></template>
<template #label>{{ $ts.search }}</template>
</MkInput>
<MkInput v-model="host" :debounce="true" style="margin: var(--margin);">
<template #label>{{ $ts.host }}</template>
</MkInput>
<MkPagination :pagination="remotePagination" ref="remoteEmojis">
<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
<template #default="{items}">
@@ -138,7 +146,7 @@ export default defineComponent({
},
remoteMenu(emoji, ev) {
os.modalMenu([{
os.popupMenu([{
type: 'label',
text: ':' + emoji.name + ':',
}, {

View File

@@ -16,7 +16,7 @@
</div>
<div class="_section">
<div class="_content">
<MkSwitch @update:value="toggleIsSensitive" v-model:value="isSensitive">NSFW</MkSwitch>
<MkSwitch @update:modelValue="toggleIsSensitive" v-model="isSensitive">NSFW</MkSwitch>
</div>
</div>
<div class="_section">

View File

@@ -9,8 +9,8 @@
<div class="_section lookup">
<div class="_title"><i class="fas fa-search"></i> {{ $ts.lookup }}</div>
<div class="_content">
<MkInput class="target" v-model:value="q" type="text" @enter="find()">
<span>{{ $ts.fileIdOrUrl }}</span>
<MkInput class="target" v-model="q" type="text" @enter="find()">
<template #label>{{ $ts.fileIdOrUrl }}</template>
</MkInput>
<MkButton @click="find()" primary><i class="fas fa-search"></i> {{ $ts.lookup }}</MkButton>
</div>
@@ -19,19 +19,19 @@
<div class="_section">
<div class="_content">
<div class="inputs" style="display: flex;">
<MkSelect v-model:value="origin" style="margin: 0; flex: 1;">
<MkSelect v-model="origin" style="margin: 0; flex: 1;">
<template #label>{{ $ts.instance }}</template>
<option value="combined">{{ $ts.all }}</option>
<option value="local">{{ $ts.local }}</option>
<option value="remote">{{ $ts.remote }}</option>
</MkSelect>
<MkInput v-model:value="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params().origin === 'local'">
<span>{{ $ts.host }}</span>
<MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params().origin === 'local'">
<template #label>{{ $ts.host }}</template>
</MkInput>
</div>
<div class="inputs" style="display: flex; padding-top: 1.2em;">
<MkInput v-model:value="type" :debounce="true" type="search" style="margin: 0; flex: 1;">
<span>{{ $ts.type }}</span>
<MkInput v-model="type" :debounce="true" type="search" style="margin: 0; flex: 1;">
<template #label>{{ $ts.type }}</template>
</MkInput>
</div>
<MkPagination :pagination="pagination" #default="{items}" class="urempief" ref="files">

View File

@@ -100,7 +100,7 @@ export default defineComponent({
case 'overview': return defineAsyncComponent(() => import('./overview.vue'));
case 'users': return defineAsyncComponent(() => import('./users.vue'));
case 'emojis': return defineAsyncComponent(() => import('./emojis.vue'));
case 'federation': return defineAsyncComponent(() => import('./federation.vue'));
case 'federation': return defineAsyncComponent(() => import('../federation.vue'));
case 'queue': return defineAsyncComponent(() => import('./queue.vue'));
case 'files': return defineAsyncComponent(() => import('./files.vue'));
case 'announcements': return defineAsyncComponent(() => import('./announcements.vue'));
@@ -167,7 +167,7 @@ export default defineComponent({
};
const lookup = (ev) => {
os.modalMenu([{
os.popupMenu([{
text: i18n.locale.user,
icon: 'fas fa-user',
action: () => {

View File

@@ -77,7 +77,7 @@
<div class="header">
<span class="label">{{ $ts.charts }}</span>
<div class="selects">
<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
<option value="requests">{{ $ts._instanceCharts.requests }}</option>
<option value="users">{{ $ts._instanceCharts.users }}</option>
<option value="users-total">{{ $ts._instanceCharts.usersTotal }}</option>
@@ -90,7 +90,7 @@
<option value="drive-files">{{ $ts._instanceCharts.files }}</option>
<option value="drive-files-total">{{ $ts._instanceCharts.filesTotal }}</option>
</MkSelect>
<MkSelect v-model:value="chartSpan" style="margin: 0;">
<MkSelect v-model="chartSpan" style="margin: 0;">
<option value="hour">{{ $ts.perHour }}</option>
<option value="day">{{ $ts.perDay }}</option>
</MkSelect>
@@ -102,8 +102,8 @@
</div>
<div class="operations section">
<span class="label">{{ $ts.operations }}</span>
<MkSwitch v-model:value="isSuspended" class="switch">{{ $ts.stopActivityDelivery }}</MkSwitch>
<MkSwitch :value="isBlocked" class="switch" @update:value="changeBlock">{{ $ts.blockThisInstance }}</MkSwitch>
<MkSwitch v-model="isSuspended" class="switch">{{ $ts.stopActivityDelivery }}</MkSwitch>
<MkSwitch :model-value="isBlocked" class="switch" @update:modelValue="changeBlock">{{ $ts.blockThisInstance }}</MkSwitch>
<details>
<summary>{{ $ts.deleteAllFiles }}</summary>
<MkButton @click="deleteAllFiles()" style="margin: 0.5em 0 0.5em 0;"><i class="fas fa-trash-alt"></i> {{ $ts.deleteAllFiles }}</MkButton>
@@ -131,8 +131,8 @@ import MkSelect from '@client/components/ui/select.vue';
import MkButton from '@client/components/ui/button.vue';
import MkSwitch from '@client/components/ui/switch.vue';
import MkInfo from '@client/components/ui/info.vue';
import bytes from '../../filters/bytes';
import number from '../../filters/number';
import bytes from '@client/filters/bytes';
import number from '@client/filters/number';
import * as os from '@client/os';
const chartLimit = 90;

View File

@@ -1,10 +1,10 @@
<template>
<div class="_section">
<div class="_inputs">
<MkInput v-model:value="logDomain" :debounce="true">
<span>{{ $ts.domain }}</span>
<MkInput v-model="logDomain" :debounce="true">
<template #label>{{ $ts.domain }}</template>
</MkInput>
<MkSelect v-model:value="logLevel">
<MkSelect v-model="logLevel">
<template #label>Level</template>
<option value="all">All</option>
<option value="info">Info</option>

View File

@@ -60,8 +60,8 @@ import MkContainer from '@client/components/ui/container.vue';
import MkFolder from '@client/components/ui/folder.vue';
import MkwFederation from '../../widgets/federation.vue';
import { version, url } from '@client/config';
import bytes from '../../filters/bytes';
import number from '../../filters/number';
import bytes from '@client/filters/bytes';
import number from '@client/filters/number';
import MkInstanceInfo from './instance.vue';
const alpha = (hex, a) => {
@@ -90,7 +90,7 @@ export default defineComponent({
stats: null,
serverInfo: null,
connection: null,
queueConnection: os.stream.useChannel('queueStats'),
queueConnection: markRaw(os.stream.useChannel('queueStats')),
memUsage: 0,
chartCpuMem: null,
chartNet: null,
@@ -121,7 +121,7 @@ export default defineComponent({
os.api('admin/server-info', {}).then(res => {
this.serverInfo = res;
this.connection = os.stream.useChannel('serverStats');
this.connection = markRaw(os.stream.useChannel('serverStats'));
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {

View File

@@ -62,8 +62,8 @@ import MkInput from '@client/components/ui/input.vue';
import MkContainer from '@client/components/ui/container.vue';
import MkFolder from '@client/components/ui/folder.vue';
import { version, url } from '@client/config';
import bytes from '../../filters/bytes';
import number from '../../filters/number';
import bytes from '@client/filters/bytes';
import number from '@client/filters/number';
import MkInstanceInfo from './instance.vue';
import XMetrics from './metrics.vue';
import * as os from '@client/os';

View File

@@ -29,7 +29,7 @@
<script lang="ts">
import { defineComponent, markRaw } from 'vue';
import Chart from 'chart.js';
import number from '../../filters/number';
import number from '@client/filters/number';
const alpha = (hex, a) => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;

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