Compare commits

...

228 Commits

Author SHA1 Message Date
syuilo
c40b630530 10.38.5 2018-11-04 23:20:06 +09:00
syuilo
7fc0698ecf 🎨 2018-11-04 23:15:46 +09:00
syuilo
4f3c8b940e [API] Fix #3099 2018-11-04 23:13:35 +09:00
syuilo
1855ab60f1 Resolve #3098 2018-11-04 23:00:43 +09:00
syuilo
af4f1a7bd6 Clean up 2018-11-04 22:05:42 +09:00
Acid Chicken (硫酸鶏)
8646a9c49c Add GitHub auth (#3095) 2018-11-04 22:03:55 +09:00
syuilo
8d7c033cf5 Clean up 2018-11-04 21:21:34 +09:00
syuilo
b8900e32de 🎨 2018-11-04 21:14:17 +09:00
syuilo
d48c25d2c9 [API] Fix #3097 2018-11-04 21:11:54 +09:00
Acid Chicken (硫酸鶏)
a87c5899c5 Fix typo 2018-11-04 20:08:31 +09:00
Acid Chicken (硫酸鶏)
147ad69864 Revert "Add GitHub auth"
This reverts commit c146006476.
2018-11-04 19:22:04 +09:00
Acid Chicken (硫酸鶏)
c146006476 Add GitHub auth 2018-11-04 19:17:30 +09:00
syuilo
a0f10d7ca1 10.38.4 2018-11-04 18:38:04 +09:00
syuilo
299b91edc4 [API] Improve admin/emoji/add 2018-11-04 18:37:12 +09:00
syuilo
95c89ca6db RE: [Client] Fix bug 2018-11-04 18:36:19 +09:00
syuilo
7fe0d71e7f [Client] Fix bug 2018-11-04 18:35:55 +09:00
syuilo
fbbb506e86 🎨 2018-11-04 18:31:27 +09:00
syuilo
ec80b06a45 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-04 18:24:20 +09:00
syuilo
41e1619f1f [Client] Fix bug 2018-11-04 18:24:08 +09:00
syuilo
ba6a9c6a93 Merge pull request #3092 from syuilo/l10n_develop
New Crowdin translations
2018-11-04 18:22:19 +09:00
MeiMei
18571c52fb Fix: emoji regex (#3093) 2018-11-04 17:36:37 +09:00
syuilo
5d5dfeaa83 New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 17:11:19 +09:00
syuilo
3669d8c0f3 New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 17:01:11 +09:00
syuilo
69d72819c6 10.38.3 2018-11-04 15:18:37 +09:00
syuilo
54dcc10250 Fix bug for Mastodon(?) 2018-11-04 15:17:52 +09:00
syuilo
1edfce8f73 [Client] スマホ/タブレットからでも管理者ページを使えるように 2018-11-04 15:16:05 +09:00
syuilo
675e573a8c 🎨 2018-11-04 14:23:28 +09:00
syuilo
1080fa63a9 10.38.2 2018-11-04 11:09:31 +09:00
syuilo
8047086988 Good bye package-lock 2018-11-04 11:08:46 +09:00
syuilo
449b9f7fa0 [Client] Improve admin panel 2018-11-04 11:08:03 +09:00
syuilo
b7a15bf6ca 絵文字を作成した/更新した時にupdateAtを更新するように 2018-11-04 10:42:16 +09:00
syuilo
7c3873887d 10.38.1 2018-11-04 03:45:05 +09:00
syuilo
247ea4cf12 Merge pull request #3083 from syuilo/l10n_develop
New Crowdin translations
2018-11-04 03:44:30 +09:00
syuilo
0b7af5c669 [Client] Fix bug 2018-11-04 03:44:06 +09:00
syuilo
2b62a4e2e5 New translations ja-JP.yml (English) 2018-11-04 03:42:45 +09:00
MeiMei
65bfa3c0d6 Fix: update_client_setting (#3086) 2018-11-04 03:33:37 +09:00
syuilo
84db15694d Do not send needless emojis in note
投稿作成時に含まれている絵文字を保存しておくように

SEE: https://github.com/syuilo/misskey/pull/3085#issuecomment-435608434
2018-11-04 03:32:20 +09:00
syuilo
746189ba37 New translations ja-JP.yml (Norwegian) 2018-11-04 03:23:44 +09:00
syuilo
74e845b3ac New translations ja-JP.yml (Dutch) 2018-11-04 03:23:39 +09:00
syuilo
90fe70540e New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 03:23:36 +09:00
syuilo
f28af75191 New translations ja-JP.yml (Spanish) 2018-11-04 03:23:31 +09:00
syuilo
924bb2bc70 New translations ja-JP.yml (Russian) 2018-11-04 03:23:26 +09:00
syuilo
19d60f3d51 New translations ja-JP.yml (Portuguese) 2018-11-04 03:23:22 +09:00
syuilo
6903476868 New translations ja-JP.yml (Polish) 2018-11-04 03:23:16 +09:00
syuilo
cf0dccc209 New translations ja-JP.yml (Korean) 2018-11-04 03:23:10 +09:00
syuilo
cfd959129d New translations ja-JP.yml (Italian) 2018-11-04 03:23:06 +09:00
syuilo
819287951c New translations ja-JP.yml (German) 2018-11-04 03:23:02 +09:00
syuilo
e136193925 New translations ja-JP.yml (French) 2018-11-04 03:22:57 +09:00
syuilo
8c631864d9 New translations ja-JP.yml (English) 2018-11-04 03:22:53 +09:00
syuilo
d7d0f6ae2e New translations ja-JP.yml (Chinese Simplified) 2018-11-04 03:22:47 +09:00
syuilo
b83b3fb9d1 New translations ja-JP.yml (Catalan) 2018-11-04 03:22:43 +09:00
syuilo
dfce5bc0af [Client] Improve Emoji management page of admin panel 2018-11-04 03:18:57 +09:00
syuilo
3487ddabea [API] Implement some Emoji APIs 2018-11-04 03:18:32 +09:00
syuilo
2dbff75e7a New translations ja-JP.yml (French) 2018-11-04 02:53:30 +09:00
syuilo
02465ded9f New translations ja-JP.yml (French) 2018-11-04 02:41:50 +09:00
syuilo
ffcd387945 New translations ja-JP.yml (French) 2018-11-04 02:31:36 +09:00
syuilo
4806346707 New translations ja-JP.yml (French) 2018-11-04 02:21:09 +09:00
MeiMei
31c3f6abf7 Fix: welcome-timeline (#3084) 2018-11-04 01:49:08 +09:00
syuilo
83e47fdd60 New translations ja-JP.yml (English) 2018-11-04 01:21:56 +09:00
syuilo
340ce7fa4c 10.38.0 2018-11-04 00:26:00 +09:00
syuilo
ac86fee9b4 Merge pull request #3080 from syuilo/l10n_develop
New Crowdin translations
2018-11-04 00:13:09 +09:00
syuilo
6dfa283d7a New translations ja-JP.yml (English) 2018-11-04 00:11:31 +09:00
syuilo
0cce8a4d21 🎨 2018-11-04 00:10:13 +09:00
syuilo
1c6d9ab2ef New translations ja-JP.yml (Norwegian) 2018-11-04 00:05:11 +09:00
syuilo
6ca265e579 New translations ja-JP.yml (Dutch) 2018-11-04 00:04:59 +09:00
syuilo
c612c4bf18 New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 00:04:50 +09:00
syuilo
481a791a60 New translations ja-JP.yml (Spanish) 2018-11-04 00:04:39 +09:00
syuilo
cb516c2943 New translations ja-JP.yml (Russian) 2018-11-04 00:04:29 +09:00
syuilo
c0abd6f0c0 New translations ja-JP.yml (Portuguese) 2018-11-04 00:04:17 +09:00
syuilo
47695ed685 New translations ja-JP.yml (Polish) 2018-11-04 00:04:07 +09:00
syuilo
4ca8020ef5 New translations ja-JP.yml (Korean) 2018-11-04 00:03:56 +09:00
syuilo
bfac83d5b8 New translations ja-JP.yml (Italian) 2018-11-04 00:03:47 +09:00
syuilo
4cd2e55fd3 New translations ja-JP.yml (German) 2018-11-04 00:03:37 +09:00
syuilo
61c7e7bc48 New translations ja-JP.yml (French) 2018-11-04 00:03:28 +09:00
syuilo
bef41718e2 New translations ja-JP.yml (English) 2018-11-04 00:03:16 +09:00
syuilo
5b4b52bb97 New translations ja-JP.yml (Chinese Simplified) 2018-11-04 00:03:08 +09:00
syuilo
8901b6d774 New translations ja-JP.yml (Catalan) 2018-11-04 00:02:57 +09:00
syuilo
e3a24e9215 [Client] Improve admin panel 2018-11-03 23:57:14 +09:00
syuilo
a515c1f53e Improve API documentation 2018-11-03 22:49:36 +09:00
syuilo
2e22874dec Refactoring 2018-11-03 22:40:12 +09:00
syuilo
30f0b1c30d Add missing semicolons 2018-11-03 22:38:12 +09:00
syuilo
600aea4dbb [MFM] Fix emoji syntax parsing 2018-11-03 22:35:24 +09:00
syuilo
f5d53d784d [Client] Improve admin panel 2018-11-03 22:21:20 +09:00
syuilo
1061e1f7ae i18n 2018-11-03 22:20:09 +09:00
syuilo
1d5fc04aa6 🎨 2018-11-03 22:03:06 +09:00
syuilo
d1cf0c7998 Clean up 2018-11-03 22:01:58 +09:00
syuilo
84218abf2b [Client] Make possible to change password in mobile
モバイル版からパスワードの変更を行えるように
2018-11-03 21:53:03 +09:00
syuilo
5bebdb2511 🎨 2018-11-03 20:10:55 +09:00
syuilo
9c8e9b4165 🎨 2018-11-03 20:03:21 +09:00
syuilo
7b786bfde3 Improve usability of Admin panel 2018-11-03 19:57:44 +09:00
syuilo
42a08642a4 Misskeyのバージョンもクライアントの環境変数に突っ込むように 2018-11-03 17:04:33 +09:00
syuilo
e88f7ca7b2 [Client] Fix some charts 2018-11-03 16:44:05 +09:00
syuilo
c26ed1421b [API] Increase chart limit 2018-11-03 16:43:50 +09:00
syuilo
ed2f94a3c1 oops 2018-11-03 15:28:11 +09:00
syuilo
daba7fe87c [MFM] Fix title syntax parsing 2018-11-03 15:28:00 +09:00
syuilo
afc9caf7bf Improve performance 2018-11-03 15:21:07 +09:00
syuilo
67697a7aa6 Merge pull request #3067 from syuilo/l10n_develop
New Crowdin translations
2018-11-03 15:14:13 +09:00
syuilo
1623d9e70c 🎨 2018-11-03 15:05:00 +09:00
syuilo
c304351335 🎨 2018-11-03 13:39:17 +09:00
syuilo
c1520763c6 🎨 2018-11-03 13:30:57 +09:00
syuilo
4853bc9414 Update src/client/app/admin/views/charts.vue 2018-11-03 13:08:49 +09:00
dependabot[bot]
e7c865f8e3 Bump @types/request from 2.47.1 to 2.48.0 (#3054)
Bumps [@types/request](https://github.com/DefinitelyTyped/DefinitelyTyped) from 2.47.1 to 2.48.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:38:17 +09:00
dependabot[bot]
46cb377bc2 Bump css-loader from 1.0.0 to 1.0.1 (#3070)
Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/compare/v1.0.0...v1.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:37:54 +09:00
dependabot[bot]
373a5ba3e1 Bump @types/node from 10.12.0 to 10.12.2 (#3072)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped) from 10.12.0 to 10.12.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:37:38 +09:00
dependabot[bot]
3bedef67c8 Bump elasticsearch from 15.1.1 to 15.2.0 (#3073)
Bumps [elasticsearch](https://github.com/elastic/elasticsearch-js) from 15.1.1 to 15.2.0.
- [Release notes](https://github.com/elastic/elasticsearch-js/releases)
- [Changelog](https://github.com/elastic/elasticsearch-js/blob/master/docs/changelog.asciidoc)
- [Commits](https://github.com/elastic/elasticsearch-js/compare/v15.1.1...v15.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:37:28 +09:00
dependabot[bot]
17ea19ada8 Bump typescript from 3.1.4 to 3.1.5 (#3069)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v3.1.4...v3.1.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:37:11 +09:00
dependabot[bot]
1f5b2285fd Bump file-type from 10.2.0 to 10.3.0 (#3071)
Bumps [file-type](https://github.com/sindresorhus/file-type) from 10.2.0 to 10.3.0.
- [Release notes](https://github.com/sindresorhus/file-type/releases)
- [Commits](https://github.com/sindresorhus/file-type/compare/v10.2.0...v10.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-03 12:36:59 +09:00
syuilo
17f0001966 New translations ja-JP.yml (English) 2018-11-03 11:51:00 +09:00
syuilo
04ba09a6af New translations ja-JP.yml (Norwegian) 2018-11-03 11:43:16 +09:00
syuilo
70d2744319 New translations ja-JP.yml (Dutch) 2018-11-03 11:43:06 +09:00
syuilo
6b2f0929ec New translations ja-JP.yml (Japanese, Kansai) 2018-11-03 11:42:55 +09:00
syuilo
f2629bd3f2 New translations ja-JP.yml (Spanish) 2018-11-03 11:42:46 +09:00
syuilo
9e6c29c3c0 New translations ja-JP.yml (Russian) 2018-11-03 11:42:38 +09:00
syuilo
abda973094 New translations ja-JP.yml (Portuguese) 2018-11-03 11:42:27 +09:00
syuilo
86b08dd5bd New translations ja-JP.yml (Polish) 2018-11-03 11:42:17 +09:00
syuilo
617e331f0f New translations ja-JP.yml (Korean) 2018-11-03 11:42:06 +09:00
syuilo
cc438a9372 New translations ja-JP.yml (Italian) 2018-11-03 11:41:58 +09:00
syuilo
b0fb218bfd New translations ja-JP.yml (German) 2018-11-03 11:41:50 +09:00
syuilo
fc85a607e6 New translations ja-JP.yml (French) 2018-11-03 11:41:42 +09:00
syuilo
fb244c45e3 New translations ja-JP.yml (English) 2018-11-03 11:41:34 +09:00
syuilo
c123784c54 New translations ja-JP.yml (Chinese Simplified) 2018-11-03 11:41:24 +09:00
syuilo
342a5276fc New translations ja-JP.yml (Catalan) 2018-11-03 11:41:15 +09:00
syuilo
51a32846ee Update src/client/app/admin/views/ap-log.vue 2018-11-03 11:39:56 +09:00
syuilo
35865429a8 🎨 2018-11-03 11:39:18 +09:00
syuilo
aadd5b95b8 Improve admin dashboard 2018-11-03 11:38:00 +09:00
syuilo
f9f2ca51ac Improve stats API 2018-11-03 11:37:44 +09:00
syuilo
1cb93a8c10 🎨 2018-11-03 11:37:17 +09:00
syuilo
7e5dbb2ba5 Fix bug 2018-11-03 11:36:11 +09:00
syuilo
2772e3d80e New translations ja-JP.yml (English) 2018-11-03 03:51:41 +09:00
syuilo
223c578734 Improve admin dashboard 2018-11-03 03:30:28 +09:00
syuilo
d01315dee2 🎨 2018-11-03 03:08:41 +09:00
syuilo
7dafb4ce4c New translations ja-JP.yml (Norwegian) 2018-11-03 03:04:52 +09:00
syuilo
9671db9b14 New translations ja-JP.yml (Dutch) 2018-11-03 03:04:41 +09:00
syuilo
bec559f67c New translations ja-JP.yml (Japanese, Kansai) 2018-11-03 03:04:33 +09:00
syuilo
14053c1394 New translations ja-JP.yml (Spanish) 2018-11-03 03:04:24 +09:00
syuilo
55e4b1c828 New translations ja-JP.yml (Russian) 2018-11-03 03:04:17 +09:00
syuilo
dda3421159 New translations ja-JP.yml (Portuguese) 2018-11-03 03:04:08 +09:00
syuilo
45e7488e60 New translations ja-JP.yml (Polish) 2018-11-03 03:03:55 +09:00
syuilo
30c7bd66b7 New translations ja-JP.yml (Korean) 2018-11-03 03:03:45 +09:00
syuilo
af4f5bdac0 New translations ja-JP.yml (Italian) 2018-11-03 03:03:37 +09:00
syuilo
3d1a8cc341 New translations ja-JP.yml (German) 2018-11-03 03:03:28 +09:00
syuilo
0e52fb2544 New translations ja-JP.yml (French) 2018-11-03 03:03:18 +09:00
syuilo
e6d6c0a17c New translations ja-JP.yml (English) 2018-11-03 03:03:10 +09:00
syuilo
cfd2d47e00 New translations ja-JP.yml (Chinese Simplified) 2018-11-03 03:03:00 +09:00
syuilo
83301a879d New translations ja-JP.yml (Catalan) 2018-11-03 03:02:51 +09:00
syuilo
d7881ba129 Improve admin page 2018-11-03 03:00:23 +09:00
syuilo
b9fef1edf7 New translations ja-JP.yml (Norwegian) 2018-11-03 02:14:35 +09:00
syuilo
2c606f7b23 New translations ja-JP.yml (Dutch) 2018-11-03 02:14:27 +09:00
syuilo
03797607ed New translations ja-JP.yml (Japanese, Kansai) 2018-11-03 02:14:19 +09:00
syuilo
254b7f500d New translations ja-JP.yml (Spanish) 2018-11-03 02:14:09 +09:00
syuilo
51edd51bf2 New translations ja-JP.yml (Russian) 2018-11-03 02:14:00 +09:00
syuilo
0d403f4a3f New translations ja-JP.yml (Portuguese) 2018-11-03 02:13:52 +09:00
syuilo
0fa134addd New translations ja-JP.yml (Polish) 2018-11-03 02:13:44 +09:00
syuilo
7002270084 New translations ja-JP.yml (Korean) 2018-11-03 02:13:37 +09:00
syuilo
1c5452d047 New translations ja-JP.yml (Italian) 2018-11-03 02:13:26 +09:00
syuilo
f0d62c07bf New translations ja-JP.yml (German) 2018-11-03 02:13:18 +09:00
syuilo
496ca55bba New translations ja-JP.yml (French) 2018-11-03 02:13:11 +09:00
syuilo
79cfba226b New translations ja-JP.yml (English) 2018-11-03 02:13:00 +09:00
syuilo
f69b60dffe New translations ja-JP.yml (Chinese Simplified) 2018-11-03 02:12:51 +09:00
syuilo
513385133f New translations ja-JP.yml (Catalan) 2018-11-03 02:12:43 +09:00
syuilo
6f1e2f6636 Improve admin page 2018-11-03 02:06:34 +09:00
syuilo
8ae94c034d Update hashtags.ts 2018-11-02 23:46:57 +09:00
syuilo
cd9696f25e Update src/server/api/endpoints/aggregation/hashtags.ts 2018-11-02 23:32:40 +09:00
syuilo
d62a6bab41 Remove needless properties 2018-11-02 23:27:47 +09:00
syuilo
20df002746 🍕 2018-11-02 23:23:01 +09:00
syuilo
fa6b01546e New translations ja-JP.yml (English) 2018-11-02 23:22:06 +09:00
syuilo
91b37a6e52 New translations ja-JP.yml (Norwegian) 2018-11-02 23:14:33 +09:00
syuilo
d8171d7c8b New translations ja-JP.yml (Dutch) 2018-11-02 23:14:23 +09:00
syuilo
fa96e2daf1 New translations ja-JP.yml (Japanese, Kansai) 2018-11-02 23:14:15 +09:00
syuilo
87708c3b84 New translations ja-JP.yml (Spanish) 2018-11-02 23:14:06 +09:00
syuilo
6319023cc9 New translations ja-JP.yml (Russian) 2018-11-02 23:13:58 +09:00
syuilo
efad9d1b60 New translations ja-JP.yml (Portuguese) 2018-11-02 23:13:48 +09:00
syuilo
a1dea657fa New translations ja-JP.yml (Polish) 2018-11-02 23:13:38 +09:00
syuilo
6b1b75717b New translations ja-JP.yml (Korean) 2018-11-02 23:13:31 +09:00
syuilo
efe08e0bd3 New translations ja-JP.yml (Italian) 2018-11-02 23:13:22 +09:00
syuilo
62892c4894 New translations ja-JP.yml (German) 2018-11-02 23:13:15 +09:00
syuilo
0c2a62da11 New translations ja-JP.yml (French) 2018-11-02 23:13:07 +09:00
syuilo
5bc9e9aadd New translations ja-JP.yml (English) 2018-11-02 23:12:56 +09:00
syuilo
112c33d35b New translations ja-JP.yml (Chinese Simplified) 2018-11-02 23:12:48 +09:00
syuilo
864da3030f New translations ja-JP.yml (Catalan) 2018-11-02 23:12:38 +09:00
syuilo
f2e719b361 [Client] Admin page improved 2018-11-02 23:05:53 +09:00
syuilo
6aab515389 New translations ja-JP.yml (English) 2018-11-02 22:59:53 +09:00
syuilo
819b535ab0 [API] Implement admin/add-emoji 2018-11-02 15:04:02 +09:00
syuilo
60e95ac2ac Clean up 2018-11-02 14:53:55 +09:00
syuilo
9b94ddff0a Clean up 2018-11-02 13:49:09 +09:00
syuilo
174f8022eb Refactor 2018-11-02 13:47:44 +09:00
syuilo
ddc3c5ba68 Better index 2018-11-02 12:49:18 +09:00
syuilo
a7e6b766be Resolve #2623 2018-11-02 12:49:08 +09:00
syuilo
befc35a3ac Update src/server/api/endpoints/meta.ts 2018-11-02 12:16:03 +09:00
syuilo
2e9bbf389e Better index 2018-11-02 12:08:28 +09:00
MeiMei
80b5fda292 Remote custom emojis (#3074)
* Remote custom emojis

* んほおおおおお
2018-11-02 08:59:40 +09:00
syuilo
c48cbd95f6 Fix bug 2018-11-02 03:41:09 +09:00
syuilo
931bdc6aac Refactoring, Clean up and bug fixes 2018-11-02 03:32:24 +09:00
syuilo
7f81506c8b New translations ja-JP.yml (French) 2018-11-01 22:01:38 +09:00
syuilo
b4b9e76c8d Refactoring 2018-11-01 21:28:39 +09:00
syuilo
e5a3dcf868 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-01 21:01:55 +09:00
syuilo
825648535c Refactoring 2018-11-01 21:01:47 +09:00
Acid Chicken (硫酸鶏)
5cbc908ba3 Fix typo 2018-11-01 19:32:11 +09:00
syuilo
895cf53ee1 Fix bug 2018-11-01 18:05:14 +09:00
syuilo
e41f74e77c 10.37.0 2018-11-01 11:52:33 +09:00
syuilo
c21caad1c5 Custom emoji (#3061)
* wip

* wip

* wip
2018-11-01 11:51:49 +09:00
syuilo
86fcd3a378 Fix bug 2018-11-01 10:00:15 +09:00
syuilo
2b3687b3cb 10.36.1 2018-11-01 09:35:24 +09:00
syuilo
5d61c7c691 Refactor and use original image for banner 2018-11-01 09:30:51 +09:00
syuilo
1bb266e7c7 Update package-lock.json 2018-11-01 09:19:31 +09:00
syuilo
1fca8d322c Clean up 2018-11-01 09:19:22 +09:00
syuilo
325cd03a59 Improve performance 2018-11-01 09:08:00 +09:00
syuilo
2f7e6baa05 Clean up 2018-11-01 09:02:54 +09:00
syuilo
d252e066fe Improve performance 2018-11-01 09:00:18 +09:00
dependabot[bot]
fe7bd9ab3c Bump typescript-eslint-parser from 20.0.0 to 20.1.1 (#3057)
Bumps [typescript-eslint-parser](https://github.com/eslint/typescript-eslint-parser) from 20.0.0 to 20.1.1.
- [Release notes](https://github.com/eslint/typescript-eslint-parser/releases)
- [Changelog](https://github.com/eslint/typescript-eslint-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/typescript-eslint-parser/compare/v20.0.0...v20.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 08:24:13 +09:00
dependabot[bot]
84e3f41305 Bump ts-loader from 5.2.2 to 5.3.0 (#3055)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 5.2.2 to 5.3.0.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v5.2.2...v5.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 08:24:05 +09:00
dependabot[bot]
3e8cccad0d Bump jsdom from 12.2.0 to 13.0.0 (#3058)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 12.2.0 to 13.0.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/master/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/12.2.0...13.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 08:23:38 +09:00
Acid Chicken (硫酸鶏)
a2b94d67f7 Update README.md [AUTOGEN] (#3060) 2018-11-01 08:23:11 +09:00
dependabot[bot]
6ab61e73b0 Bump apexcharts from 2.1.6 to 2.1.9 (#3056)
Bumps [apexcharts](https://github.com/apexcharts/apexcharts.js) from 2.1.6 to 2.1.9.
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Changelog](https://github.com/apexcharts/apexcharts.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apexcharts/apexcharts.js/compare/v2.1.6...v2.1.9)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-01 08:22:53 +09:00
Acid Chicken (硫酸鶏)
051c6973af Update README.md [AUTOGEN] (#3059) 2018-11-01 08:20:56 +09:00
syuilo
806a49ec3d 10.36.0 2018-11-01 00:12:13 +09:00
syuilo
3829fe128a Update src/server/api/endpoints/users/relation.ts 2018-11-01 00:11:52 +09:00
syuilo
649177985d [API] Implement users/relation 2018-11-01 00:11:21 +09:00
syuilo
c15148b23c [API] Include detailed user information for block/mute response 2018-10-31 23:34:35 +09:00
syuilo
261a3f5d91 Better rate limitting 2018-10-31 23:03:14 +09:00
syuilo
256ba78ba5 Fix 2018-10-31 22:55:17 +09:00
syuilo
04aff8866e [MFM] Better hashtag detection 2018-10-31 22:38:05 +09:00
syuilo
1a51b98700 Refactor 2018-10-31 22:35:02 +09:00
syuilo
f64100226d Revert "Clean up"
This reverts commit 8948a0d3a4.
2018-10-31 22:10:25 +09:00
syuilo
b7805e48a6 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-10-31 22:08:27 +09:00
syuilo
0d9556620d Update package-lock.json 2018-10-31 22:08:19 +09:00
Acid Chicken (硫酸鶏)
a51828a7a2 Update test.yml (#3052) 2018-10-31 22:07:26 +09:00
Acid Chicken (硫酸鶏)
7e2009f408 Update config.yml (#3051) 2018-10-31 22:00:21 +09:00
281 changed files with 6847 additions and 22203 deletions

View File

@@ -9,6 +9,7 @@ mongodb:
db: test-misskey
user: admin
pass: ''
# __REDIS__
redis:
host: localhost
port: 6379

View File

@@ -97,14 +97,22 @@ jobs:
- run:
name: Build
command: |
docker build .
docker build . | tee docker.log
tail -n 1 docker.log | read __Successfully __built tag
- when:
condition: <<parameters.with_deploy>>
steps:
- run:
name: Deploy
command: |
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD && docker push misskey/misskey
if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ]
then
docker tag $tag misskey/misskey
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
docker push misskey/misskey
else
echo -e '\033[0;33mAborted deploying to Docker Hub\033[0;39m'
fi
workflows:
version: 2

View File

@@ -1,6 +1,3 @@
name: example-instance-name # Name of your instance
description: example-description # Description of your instance
maintainer:
name: example-maitainer-name # Your name
url: http://example.com/ # Your contact (http or mailto)
@@ -25,7 +22,7 @@ url: https://example.tld/
# +------+ |+-------------+ +----------------+|
# +---------------------------------------+
#
# You need to setup reverse proxy. (eg. Nginx)
# You need to setup reverse proxy. (eg. nginx)
# You do not define 'https' section.
# Option 2: Standalone
@@ -148,6 +145,12 @@ drive:
# consumer_key: example-twitter-consumer-key
# consumer_secret: example-twitter-consumer-secret-key
# GitHub integration
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/gh/cb
#github:
# client_id: example-github-client-id
# client_secret: example-github-client-secret
# Ghost
# Ghost account is an account used for the purpose of delegating
# followers when putting users in the list.

1
.npmrc
View File

@@ -1 +1,2 @@
save-exact = true
package-lock = false

View File

@@ -88,7 +88,7 @@ Please see [Contribution guide](./CONTRIBUTING.md).
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=qsdn0-e6yLaLI6hUX9JAkyTR6a5UdnSp7T1foniBvGQ%3D" alt="YUKIMOCHI"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/8241184/39e18850e87a449e9c9a71acb3310ebd/2?token-time=2145916800&token-hash=iUXOQzRyJDv3PJxwS7Mjwg1459dzh2trOq6NFtXu_OM%3D" alt="Acid Chicken"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/10789744/97175095d8f04c0f86225ff47cb98d40/1?token-time=2145916800&token-hash=P4BIzCX2I1CkEP66ottfhsC8Wr6BUSamjA-vq3pLqFI%3D" alt="Naoki Hirayama"></td>
@@ -98,7 +98,7 @@ Please see [Contribution guide](./CONTRIBUTING.md).
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
<td><a href="https://www.patreon.com/acid_chicken">Acid Chicken</a></td>
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
<td><a href="https://www.patreon.com/spinlock">Naoki Hirayama</a></td>
@@ -111,7 +111,7 @@ Please see [Contribution guide](./CONTRIBUTING.md).
</tr><tr>
</tr></table>
**Last updated:** Sat, 27 Oct 2018 04:36:06 UTC
**Last updated:** Wed, 31 Oct 2018 23:21:06 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "Nach links schichten"
pop-right: "Rechts andocken"
dev: "Fehler beim Erstellen der Applikation. Bitte versuche es erneut."
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,13 +875,13 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "Passwort ändern"
enter-current-password: "Derzeitiges Passwort eingeben"
enter-new-password: "Neues Passwort eingeben"
enter-new-password-again: "Neues Passwort erneut eingeben"
not-match: "Passwörter stimmen nicht überein."
changed: "Passwort geändert"
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
enter-new-password-again: "もう一度新しいパスワードを入力してください"
not-match: "新しいパスワードが一致しません"
changed: "パスワードを変更しました"
desktop/views/components/sub-note-content.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "Stack to the left"
pop-right: "Dock on the right"
dev: "Failed to create the application. Please try again."
ai-chan-kawaii: "Ai-chan kawaii!"
auth/views/form.vue:
share-access: "Would you <b>allow</b> <i>{{ app.name }}</i> to access your account?"
permission-ask: "This application requires the following permissions:"
@@ -249,7 +250,7 @@ common/views/components/games/reversi/reversi.room.vue:
this-game-is-started-soon: "The game will begin in seconds"
waiting-for-other: "Waiting for the opponent"
waiting-for-me: "Waiting for the your preparation"
waiting-for-both: "Prepareing"
waiting-for-both: "Preparing"
cancel: "Cancel"
ready: "Ready"
cancel-ready: "Cancel \"Ready\""
@@ -874,13 +875,13 @@ common/views/components/mute-and-block.vue:
block: "Blocking"
no-muted-users: "No muted users"
no-blocked-users: "No blocked users"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "Change password"
enter-current-password: "Enter the current password"
enter-new-password: "Enter the new password"
enter-new-password-again: "Enter new password again"
enter-new-password-again: "Enter the new password again"
not-match: "The new passwords do not match"
changed: "Password updated"
changed: "Password changed"
desktop/views/components/sub-note-content.vue:
private: "This post is private"
deleted: "This post has been deleted"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "Pop-out"
close: "Close"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "Dashboard"
instance: "Instance"
emoji: "Emoji"
users: "Users"
update: "Updates"
update: "Update"
announcements: "Announcements"
hashtags: "Hashtags"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Back to Misskey"
admin/views/dashboard.vue:
dashboard: "Dashboard"
all-users: "All Users"
original-users: "Users on this instance"
all-notes: "All the posts"
original-notes: "Posts on this instance"
accounts: "Accounts"
notes: "Notes"
drive: "Drive"
instances: "Instances"
this-instance: "This instance"
federated: "Federated"
invite: "Invite"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "Chart"
per-day: "per Day"
per-hour: "per Hour"
federation: "Federation"
notes: "Posts"
users: "Users"
drive: "Drive"
network: "Network"
charts:
federation-instances: "The number of instances: increase/decrease"
federation-instances-total: "Total number of instances"
notes: "The number of posts: increase/decrease (Combined)"
local-notes: "The number of posts: increase/decrease (Local)"
remote-notes: "The number of posts: increase/decrease (Remote)"
notes-total: "Total posts"
users: "The number of users: increase/decrease"
users-total: "Total users"
drive: "Capacity used as the storage: increase/decrease"
drive-total: "Total usage of Drive"
drive-files: "The number of files on the storage: increase/decrease"
drive-files-total: "Total number of files on Drive"
network-requests: "Requests"
network-time: "Response time"
network-usage: "Traffic"
admin/views/users.vue:
suspend-user: "Suspend a user"
suspend: "Suspend"
suspended: "Successfully suspended."
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "Unsuspend users"
unsuspend: "Unsuspend"
unsuspended: "The user has successfully unsuspended."
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "User account verification settings"
verify: "Verify account"
verified: "The account is now being verified"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "User account unverification settings"
unverify: "Unverify account"
unverified: "The account is now being unverified"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "Add emoji"
name: "Emoji name"
name-desc: "You can use the characters a~z 0~9 _"
aliases: "Aliases"
aliases-desc: "You can add more than one, separated by spaces."
url: "Image URL"
add: "Add"
emojis:
title: "Emojis"
update: "Update"
remove: "Remove"
admin/views/announcements.vue:
announcements: "Announcements"
desktop/views/pages/admin/admin.hashtags.vue:
save: "Save"
remove: "Remove"
add: "Add"
title: "Title"
text: "Content"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "Only media posts"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "Sounds"
enable-sounds: "Enable sounds"
mark-as-read-all-unread-notes: "Mark all posts as read"
password: "Password"
mobile/views/pages/user.vue:
follows-you: "Follows you"
following: "Following"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "A la izqda."
pop-right: "A la dcha."
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "¿Deseas <b>permitir</b> a <i>{{ app.name }}</i> acceder a tu cuenta?"
permission-ask: "La aplicación requiere los siguientes permisos:"
@@ -874,13 +875,13 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "Cambiar contraseña"
enter-current-password: "Ingresar contraseña actual"
enter-new-password: "Ingresar nueva contraseña"
enter-new-password-again: "Ingresar nueva contraseña de nuevo"
not-match: "Las nuevas contraseñas no se corresponden consigo mismas"
changed: "Contraseña actualizada"
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
enter-new-password-again: "もう一度新しいパスワードを入力してください"
not-match: "新しいパスワードが一致しません"
changed: "パスワードを変更しました"
desktop/views/components/sub-note-content.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "Vers la gauche"
pop-right: "Vers la droite"
dev: "Échec lors de la création de lapplication. Veuillez réessayer."
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "Désirez-vous <b>autoriser</b> <i>{{ app.name }}</i> à avoir accès à votre compte ?"
permission-ask: "Cette application nécessite les autorisations suivantes :"
@@ -444,7 +445,7 @@ common/views/components/profile-editor.vue:
is-cat: "Ce compte est un Chat"
is-bot: "Ce compte est un Bot"
is-locked: "Demandes dabonnements requièrent lapprobation"
careful-bot: "Botからのフォローだけ承認制にする"
careful-bot: "Les demandes dabonnements venant de Bots requièrent lapprobation"
advanced: "Avancé"
privacy: "Vie privée"
save: "Mettre à jour le profil"
@@ -501,7 +502,7 @@ common/views/widgets/tips.vue:
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
tips-line23: "Mayu est mignone avec ses sourcils."
tips-line24: "Misskey a vu le jour en 2014"
@@ -548,7 +549,7 @@ desktop/views/components/charts.vue:
drive: "Drive"
network: "Réseau"
charts:
federation-instances: "インスタンスの増減"
federation-instances: "Nombre dinstances : augmentation/diminution"
federation-instances-total: "Nombre total dinstances"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
@@ -781,7 +782,7 @@ desktop/views/components/settings.vue:
timeline: "Chronologie"
show-my-renotes: "Afficher mes republications dans le fil"
show-renoted-my-notes: "Afficher mes republications dans les fils"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
show-local-renotes: "Afficher les partages locaux sur les fils"
show-maps: "Afficher la carte"
deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "Centrer"
@@ -865,21 +866,21 @@ common/views/components/api-settings.vue:
desktop/views/components/settings.apps.vue:
no-apps: "Aucune application autorisée"
common/views/components/drive-settings.vue:
max: "容量"
max: "Maximale"
in-use: "utilisé"
stats: "Statistiques"
common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック"
mute: "ミュート"
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "Changer votre mot de passe"
mute-and-block: "Silencer / Bloquer"
mute: "Mettre en sourdine"
block: "En cours blocage"
no-muted-users: "Aucun utilisateur·rice nest mis·e en sourdine"
no-blocked-users: "Aucun utilisateur·rice nest bloqué·e"
common/views/components/password-settings.vue:
reset: "Modifier le mot de passe"
enter-current-password: "Entrez votre mot de passe actuel"
enter-new-password: "Entrez votre nouveau mot de passe"
enter-new-password: "Saisissez le nouveau mot de passe"
enter-new-password-again: "Entrez à nouveau le nouveau mot de passe"
not-match: "Le nouveau mot de passe ne correspond pas."
not-match: "Les nouveaux mots de passe ne sont pas identiques"
changed: "Mot de passe modifié avec succès"
desktop/views/components/sub-note-content.vue:
private: "cette publication est privée"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "Fermer"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "Tableau de bord"
instance: "Instance"
emoji: "Emoji"
users: "Utilisateur·rice·s"
update: "Mises à jour"
update: "Mise à jour"
announcements: "Annonces"
hashtags: "Hashtags"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Retour vers Misskey"
admin/views/dashboard.vue:
dashboard: "Tableau de bord"
all-users: "Toutes les utilisateurrices"
original-users: "Utilisateur·rice·s sur cette instance"
all-notes: "Toutes les publications"
original-notes: "Publications sur cette instance"
invite: "Invitation"
accounts: "Comptes"
notes: "Notes"
drive: "Lecteur"
instances: "Instances"
this-instance: "Cette instance"
federated: "Fédérées"
invite: "Inviter"
banner-url: "URL de la bannière"
disableRegistration: "Désactiver lenregistrement de nouveaux utilisateurs·rices"
disableRegistration: "Désactiver lenregistrement de nouveaux utilisateur·rice·s"
disableLocalTimeline: "Désactiver le fil local"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "Graph"
per-day: "par jour"
per-hour: "par heure"
federation: "Fédération"
notes: "Publications"
users: "Utilisateur·rice·s"
drive: "Lecteur"
network: "Réseau"
charts:
federation-instances: "Nombre dinstances : augmentation/diminution"
federation-instances-total: "Nombre total dinstances"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "Total des publications"
users: "Nombre dutilisateur·rice·s : augmentation/diminution"
users-total: "Nombre total des utilisateur·rice·s"
drive: "ドライブ使用量の増減"
drive-total: "Utilisation totale du lecteur"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "Nombre total de fichiers sur le lecteur"
network-requests: "Requêtes"
network-time: "Temps de réponse"
network-usage: "Traffic"
admin/views/users.vue:
suspend-user: "Suspendre un·e utilisateur·rice"
suspend: "Suspendre"
suspended: "Suspendu avec succès"
desktop/views/pages/admin/admin.unsuspend-user.vue:
suspended: "Suspendu·e avec succès."
unsuspend-user: "Lever la suspension dutilisateur·rice·s"
unsuspend: "Suspension levée"
unsuspended: "La suspension de lutilisateur·rice a été levée avec succès"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "Paramètres de vérification du compte utilisateur"
verify: "Vérification du compte"
verified: "Le compte a été vérifié"
desktop/views/pages/admin/admin.unverify-user.vue:
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "Ôter la vérification du compte"
unverified: "Ce compte n'est pas vérifié"
desktop/views/pages/admin/admin.announcements.vue:
unverified: "Ce compte n'est plus vérifié"
admin/views/emoji.vue:
add-emoji:
title: "Ajouter un émoji"
name: "Nom de lémoji"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "Aliases"
aliases-desc: "Vous pouvez définir plus dun, séparés par des espaces."
url: "URL de limage"
add: "Ajouter"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "Annonces"
desktop/views/pages/admin/admin.hashtags.vue:
save: "Enregistrer"
remove: "Supprimer"
add: "Ajouter"
title: "Titre"
text: "Contenu"
admin/views/hashtags.vue:
hided-tags: "Tags cachés"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "Les publications médias uniquement"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "Sons"
enable-sounds: "Activer les sons"
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
password: "Mot de Passe"
mobile/views/pages/user.vue:
follows-you: "Vous suit"
following: "Abonnements"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -201,6 +201,7 @@ common:
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
@@ -416,6 +417,7 @@ common/views/components/signin.vue:
signin: "サインイン"
or: "または"
signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue:
@@ -459,6 +461,14 @@ common/views/components/twitter-setting.vue:
connect: "Twitterと接続する"
disconnect: "切断する"
common/views/components/github-setting.vue:
description: "お使いのGitHubアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでGitHubアカウント情報が表示されるようになったり、GitHubを用いた便利なサインインを利用できるようになります。"
connected-to: "次のGitHubアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/uploader.vue:
waiting: "待機中"
@@ -598,32 +608,6 @@ desktop/views/components/calendar.vue:
next: "次の月"
go: "クリックして時間遡行"
desktop/views/components/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "ファイル選択中"
upload: "PCからドライブにファイルをアップロード"
@@ -981,7 +965,7 @@ common/views/components/mute-and-block.vue:
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -1069,48 +1053,98 @@ desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
desktop/views/pages/admin/admin.dashboard.vue:
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/instance.vue:
instance: "インスタンス"
instance-name: "インスタンス名"
instance-description: "インスタンスの紹介"
banner-url: "バナー画像URL"
disableRegistration: "ユーザー登録の受付を停止する"
disableLocalTimeline: "ローカルタイムラインを無効にする"
invite: "招待"
save: "保存"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
announcements: "お知らせ"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
desktop/views/pages/admin/admin.hashtags.vue:
admin/views/announcements.vue:
announcements: "お知らせ"
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
@@ -1128,12 +1162,6 @@ desktop/views/pages/deck/deck.user-column.vue:
pinned-notes: "ピン留めされた投稿"
push-to-a-list: "リストに追加"
desktop/views/pages/stats/stats.vue:
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
desktop/views/pages/welcome.vue:
about: "詳しく..."
gotit: "わかった"
@@ -1515,6 +1543,10 @@ mobile/views/pages/settings.vue:
twitter-connect: "Twitterアカウントに接続する"
twitter-reconnect: "再接続する"
twitter-disconnect: "切断する"
github: "GitHub連携"
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
update: "Misskey Update"
version: "バージョン:"
latest-version: "最新のバージョン:"
@@ -1529,6 +1561,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねんで!"
pop-right: "右に出すで!"
dev: "アプリの作成あかんかったわ。もっぺんやってみて。"
ai-chan-kawaii: "藍ちゃめっさべっぴんさんや"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?"
permission-ask: "このアプリは次の権限を要求してんで:"
@@ -743,7 +744,7 @@ desktop/views/components/settings.vue:
apps: "アプリ"
mute-and-block: "ミュート/ブロック"
blocking: "ブロック"
security: "守護神セキュリティ"
security: "セキュリティ"
signin: "こんな感じでサインインしたらしいで"
password: "パスワード"
2fa: "二段階認証"
@@ -872,13 +873,13 @@ common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック"
mute: "ミュート"
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "パスワードを変更する"
no-muted-users: "ミュートしるユーザーはおらんで"
no-blocked-users: "ブロックしるユーザーはおらんで"
common/views/components/password-settings.vue:
reset: "パスワード変える"
enter-current-password: "今のパスワードを入れてや"
enter-new-password: "さらのパスワード入れてや"
enter-new-password-again: "もういっぺんさらのパスワードを入れてや"
enter-new-password: "こんどのパスワード入れてや"
enter-new-password-again: "もっぺん入れてや"
not-match: "パスワードがおうとらん"
changed: "パスワード変えたわ"
desktop/views/components/sub-note-content.vue:
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "さいなら"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "知っといてや"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "知り合い全員や"
original-users: "ここの人らだけ"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "ワイのインスタンス"
federated: "連合"
invite: "来てや"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減(統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結した"
desktop/views/pages/admin/admin.unsuspend-user.vue:
suspended: "凍結しました"
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除した"
desktop/views/pages/admin/admin.verify-user.vue:
unsuspended: "凍結を解除しました"
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにした"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウントにせーへん"
unverify: "公式アカウントにはさせへんで"
unverified: "公式アカウントを解除したで"
desktop/views/pages/admin/admin.announcements.vue:
announcements: "知っといてや"
desktop/views/pages/admin/admin.hashtags.vue:
verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿だけや"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンド鳴らす"
mark-as-read-all-unread-notes: "全部もう読んだわ"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされとるで"
following: "フォロー"
@@ -1340,7 +1387,7 @@ mobile/views/pages/user.vue:
mute: "ミュート"
unmute: "ミュート解除"
block: "ブロック"
unblock: "ブロック解除"
unblock: "ブロックやめたる"
mobile/views/pages/user/home.vue:
recent-notes: "最近儲かりまっか?"
images: "画像"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,13 +875,13 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "Wachtwoord wijzigen"
enter-current-password: "Voer je huidige wachtwoord in"
enter-new-password: "Voer je nieuwe wachtwoord in"
enter-new-password-again: "Voer je nieuwe wachtwoord nogmaals in"
not-match: "Het nieuwe wachtwoord komt niet overeen"
changed: "Wachtwoord bijgewerkt"
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
enter-new-password-again: "もう一度新しいパスワードを入力してください"
not-match: "新しいパスワードが一致しません"
changed: "パスワードを変更しました"
desktop/views/components/sub-note-content.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "Uitvouwen"
close: "Sluiten"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "Volgt jou"
following: "Volgend"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "Til høyre"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "Lukk"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
users: "Brukere"
update: "Oppdater"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
invite: "Inviter"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "Suspender"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "Lyder"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "Følger"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "Przypnij do lewej"
pop-right: "Odepnij w prawo"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "Czy chcesz <b>zezwolić</b> <i>{{ app.name }}</i> na dostęp do Twojego konta?"
permission-ask: "Ta aplikacja wymaga następujących uprawnień:"
@@ -874,13 +875,13 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
reset: "Zmień hasło"
enter-current-password: "Wprowadź obecne hasło"
enter-new-password: "Wprowadź nowe hasło"
enter-new-password-again: "Wprowadź ponownie nowe hasło"
not-match: "Nowe hasła nie pasują do siebie"
changed: "Pomyślnie zmieniono hasło"
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
enter-new-password-again: "もう一度新しいパスワードを入力してください"
not-match: "新しいパスワードが一致しません"
changed: "パスワードを変更しました"
desktop/views/components/sub-note-content.vue:
private: "ten wpis jest prywatny"
deleted: "ten wpis został usunięty"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "Pop-out"
close: "Zamknij"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "Tylko wpisy z zawartością multimedialną"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "Śledzi Cię"
following: "Śledzeni"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "Acoplar à direita"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "Você <b>permite</b> que <i>{{ app.name }}</i> acesse sua conta?"
permission-ask: "Este aplicativo precisa das seguintes permissões:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
users: "Usuários"
update: "Actualizações"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "Todos os usuários"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "Sons"
enable-sounds: "Ativar sons"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "Te segue"
following: "Seguindo"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

View File

@@ -186,6 +186,7 @@ common:
stack-left: "左に重ねる"
pop-right: "右に出す"
dev: "アプリの作成に失敗しました。再度お試しください。"
ai-chan-kawaii: "藍ちゃかわいい"
auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
permission-ask: "このアプリは次の権限を要求しています:"
@@ -874,7 +875,7 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
desktop/views/components/settings.password.vue:
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
enter-current-password: "現在のパスワードを入力してください"
enter-new-password: "新しいパスワードを入力してください"
@@ -946,41 +947,86 @@ desktop/views/components/users-list-item.vue:
desktop/views/components/window.vue:
popout: "ポップアウト"
close: "閉じる"
desktop/views/pages/admin/admin.vue:
admin/views/index.vue:
dashboard: "ダッシュボード"
instance: "インスタンス"
emoji: "カスタム絵文字"
users: "ユーザー"
update: "更新"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
desktop/views/pages/admin/admin.dashboard.vue:
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
accounts: "アカウント"
notes: "投稿"
drive: "ドライブ"
instances: "インスタンス"
this-instance: "このインスタンス"
federated: "連合"
invite: "招待"
banner-url: "Banner URL"
disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline"
desktop/views/pages/admin/admin.suspend-user.vue:
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
admin/views/users.vue:
suspend-user: "ユーザーの凍結"
suspend: "凍結"
suspended: "凍結しました"
desktop/views/pages/admin/admin.unsuspend-user.vue:
unsuspend-user: "ユーザーの凍結の解除"
unsuspend: "凍結の解除"
unsuspended: "凍結を解除しました"
desktop/views/pages/admin/admin.verify-user.vue:
verify-user: "ユーザーの公式アカウント設定"
verify: "公式アカウントにする"
verified: "公式アカウントにしました"
desktop/views/pages/admin/admin.unverify-user.vue:
unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する"
unverified: "公式アカウントを解除しました"
desktop/views/pages/admin/admin.announcements.vue:
admin/views/emoji.vue:
add-emoji:
title: "絵文字の登録"
name: "絵文字名"
name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス"
aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL"
add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue:
announcements: "お知らせ"
desktop/views/pages/admin/admin.hashtags.vue:
save: "保存"
remove: "削除"
add: "追加"
title: "タイトル"
text: "内容"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"
desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "メディア投稿のみ"
@@ -1328,6 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"
following: "フォロー"

17556
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.35.1",
"clientVersion": "1.0.11285",
"version": "10.38.5",
"clientVersion": "1.0.11513",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@@ -61,13 +61,14 @@
"@types/mocha": "5.2.5",
"@types/mongodb": "3.1.12",
"@types/ms": "0.7.30",
"@types/node": "10.12.0",
"@types/node": "10.12.2",
"@types/oauth": "0.9.1",
"@types/portscanner": "2.1.0",
"@types/pug": "2.0.4",
"@types/qrcode": "1.3.0",
"@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.7",
"@types/request": "2.47.1",
"@types/request": "2.48.0",
"@types/request-promise-native": "1.0.15",
"@types/rimraf": "2.0.2",
"@types/seedrandom": "2.4.27",
@@ -84,35 +85,34 @@
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
"animejs": "2.2.0",
"apexcharts": "2.1.6",
"apexcharts": "2.1.9",
"autobind-decorator": "2.1.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
"bcryptjs": "2.4.3",
"bee-queue": "1.2.2",
"bootstrap-vue": "2.0.0-rc.11",
"cafy": "11.3.0",
"cafy": "12.0.0",
"chai": "4.2.0",
"chai-http": "4.2.0",
"chalk": "2.4.1",
"chart.js": "2.7.3",
"commander": "2.19.0",
"crc-32": "1.2.0",
"css-loader": "1.0.0",
"css-loader": "1.0.1",
"dateformat": "3.0.3",
"debug": "4.1.0",
"deep-equal": "1.0.1",
"deepcopy": "0.6.3",
"diskusage": "0.2.5",
"double-ended-queue": "2.1.0-0",
"elasticsearch": "15.1.1",
"elasticsearch": "15.2.0",
"emojilib": "2.3.0",
"escape-regexp": "0.0.1",
"eslint": "5.8.0",
"eslint-plugin-vue": "4.7.1",
"eventemitter3": "3.1.0",
"file-loader": "2.0.0",
"file-type": "10.2.0",
"file-type": "10.3.0",
"fuckadblock": "3.2.1",
"gulp": "3.9.1",
"gulp-cssnano": "2.1.3",
@@ -135,7 +135,7 @@
"is-root": "2.0.0",
"is-url": "1.2.4",
"js-yaml": "3.12.0",
"jsdom": "12.2.0",
"jsdom": "13.0.0",
"json5": "2.1.0",
"json5-loader": "1.0.1",
"koa": "2.6.1",
@@ -201,17 +201,16 @@
"textarea-caret": "3.1.0",
"tinycolor2": "1.4.1",
"tmp": "0.0.33",
"ts-loader": "5.2.2",
"ts-loader": "5.3.0",
"ts-node": "7.0.1",
"tslint": "5.10.0",
"typescript": "3.1.4",
"typescript-eslint-parser": "20.0.0",
"typescript": "3.1.5",
"typescript-eslint-parser": "20.1.1",
"uglify-es": "3.3.9",
"url-loader": "1.1.2",
"uuid": "3.3.2",
"v-animate-css": "0.0.2",
"vue": "2.5.17",
"vue-chartjs": "3.4.0",
"vue-color": "2.7.0",
"vue-content-loading": "1.5.3",
"vue-cropperjs": "2.2.2",

View File

@@ -230,7 +230,7 @@ export default abstract class Chart<T> {
null;
// ログ取得
const logs = await this.collection.find({
let logs = await this.collection.find({
group: group,
span: span,
date: {
@@ -245,6 +245,27 @@ export default abstract class Chart<T> {
}
});
// 要求された範囲にログがひとつもなかったら
if (logs.length == 0) {
// もっとも新しいログを持ってくる
// (すくなくともひとつログが無いと隙間埋めできないため)
const recentLog = await this.collection.findOne({
group: group,
span: span
}, {
sort: {
date: -1
},
fields: {
_id: 0
}
});
if (recentLog) {
logs = [recentLog];
}
}
// 整形
for (let i = (range - 1); i >= 0; i--) {
const current =
@@ -269,14 +290,11 @@ export default abstract class Chart<T> {
/**
* [{
* xxxxx: 1,
* yyyyy: 5
* xxxxx: 1, yyyyy: 5
* }, {
* xxxxx: 2,
* yyyyy: 6
* xxxxx: 2, yyyyy: 6
* }, {
* xxxxx: 3,
* yyyyy: 7
* xxxxx: 3, yyyyy: 7
* }]
*
* を

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46667 135.46667"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="header-icon.dark.svg"
inkscape:export-filename="C:\Users\syuilo\projects\misskey\assets\favicon\32.png"
inkscape:export-xdpi="6"
inkscape:export-ydpi="6">
<defs
id="defs2">
<inkscape:path-effect
effect="simplify"
id="path-effect5115"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
<inkscape:path-effect
effect="simplify"
id="path-effect5111"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
<inkscape:path-effect
effect="simplify"
id="path-effect5104"
is_visible="true"
steps="1"
threshold="0.000408163"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
simplifyindividualpaths="false"
simplifyJustCoalesce="false" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="114.309"
inkscape:cy="251.50613"
inkscape:document-units="px"
inkscape:current-layer="g4502"
showgrid="true"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:snap-smooth-nodes="true"
inkscape:snap-center="true"
inkscape:snap-page="true"
inkscape:window-width="1920"
inkscape:window-height="1027"
inkscape:window-x="-8"
inkscape:window-y="1072"
inkscape:window-maximized="1"
inkscape:snap-object-midpoints="true"
inkscape:snap-midpoints="true"
inkscape:object-paths="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
objecttolerance="1"
guidetolerance="1"
inkscape:snap-nodes="false"
inkscape:snap-others="false">
<inkscape:grid
type="xygrid"
id="grid4504"
spacingx="4.2333334"
spacingy="4.2333334"
empcolor="#ff3fff"
empopacity="0.25098039"
empspacing="4" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="レイヤー 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-30.809093,-111.78601)">
<g
id="g4502"
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)">
<g
style="fill-opacity:1"
transform="translate(-1.3333333e-6,-1.3439941e-6)"
id="g5125">
<g
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)"
id="text4489"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke:none;stroke-width:0.28950602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
aria-label="Mi">
<path
sodipodi:nodetypes="zccssscssccscczzzccsccsscscsccz"
inkscape:connector-curvature="0"
id="path5210"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
d="m 75.196381,231.17126 c -5.855419,0.0202 -10.885068,-3.50766 -13.2572,-7.61584 -1.266603,-1.79454 -3.772419,-2.43291 -3.807919,0 v 11.2332 c 0,4.51309 -1.645397,8.41504 -4.936191,11.70583 -3.196772,3.19677 -7.098714,4.79516 -11.705826,4.79516 -4.513089,0 -8.415031,-1.59839 -11.705825,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -61.7729 c 0,-3.47884 0.987238,-6.6286 2.961715,-9.44928 2.068499,-2.91471 4.701135,-4.9362 7.897906,-6.06447 1.786431,-0.65816 3.666885,-0.98724 5.641362,-0.98724 5.077225,0 9.308247,1.97448 12.693064,5.92343 1.786431,1.97448 2.820681,3.00873 3.102749,3.10275 0,0 13.408119,16.21319 13.78421,16.49526 0.376091,0.28206 1.480789,2.43848 4.127113,2.43848 2.646324,0 3.89218,-2.15642 4.26827,-2.43848 0.376091,-0.28207 13.784088,-16.49526 13.784088,-16.49526 0.09402,0.094 1.081261,-0.94022 2.961715,-3.10275 3.478837,-3.94895 7.756866,-5.92343 12.834096,-5.92343 1.88045,0 3.76091,0.32908 5.64136,0.98724 3.19677,1.12827 5.7824,3.14976 7.75688,6.06447 2.06849,2.82068 3.10274,5.97044 3.10274,9.44928 v 61.7729 c 0,4.51309 -1.6454,8.41504 -4.93619,11.70583 -3.19677,3.19677 -7.09871,4.79516 -11.70582,4.79516 -4.51309,0 -8.41504,-1.59839 -11.705828,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -11.2332 c -0.277898,-3.06563 -2.987588,-1.13379 -3.948953,0 -2.538613,4.70114 -7.401781,7.59567 -13.2572,7.61584 z" />
<path
inkscape:connector-curvature="0"
id="path5212"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
d="m 145.83461,185.00361 q -5.92343,0 -10.15445,-4.08999 -4.08999,-4.23102 -4.08999,-10.15445 0,-5.92343 4.08999,-10.01342 4.23102,-4.23102 10.15445,-4.23102 5.92343,0 10.15445,4.23102 4.23102,4.08999 4.23102,10.01342 0,5.92343 -4.23102,10.15445 -4.23102,4.08999 -10.15445,4.08999 z m 0.14103,2.82068 q 5.92343,0 10.01342,4.23102 4.23102,4.23102 4.23102,10.15445 v 34.83541 q 0,5.92343 -4.23102,10.15445 -4.08999,4.08999 -10.01342,4.08999 -5.92343,0 -10.15445,-4.08999 -4.23102,-4.23102 -4.23102,-10.15445 v -34.83541 q 0,-5.92343 4.23102,-10.15445 4.23102,-4.23102 10.15445,-4.23102 z" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,27 @@
/**
* Admin
*/
import VueRouter from 'vue-router';
// Style
import './style.styl';
import init from '../init';
import Index from './views/index.vue';
init(launch => {
document.title = 'Admin';
// Init router
const router = new VueRouter({
mode: 'history',
base: '/admin/',
routes: [
{ path: '/', component: Index },
]
});
// Launch the app
launch(router);
});

View File

@@ -0,0 +1,6 @@
@import "../app"
@import "../reset"
html
height 100%
background var(--bg)

View File

@@ -0,0 +1,71 @@
<template>
<div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
<ui-card>
<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div>
<section v-for="(announcement, i) in announcements" class="fit-top">
<ui-input v-model="announcement.title" @change="save">
<span>%i18n:@title%</span>
</ui-input>
<ui-textarea v-model="announcement.text">
<span>%i18n:@text%</span>
</ui-textarea>
<ui-horizon-group>
<ui-button @click="save">%fa:save R% %i18n:@save%</ui-button>
<ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
</ui-horizon-group>
</section>
<section>
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
data() {
return {
announcements: [],
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.announcements = meta.broadcasts;
});
},
methods: {
add() {
this.announcements.push({
title: '',
text: ''
});
},
remove(i) {
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save();
},
save() {
(this as any).api('admin/update-meta', {
broadcasts: this.announcements
}).then(() => {
//(this as any).os.apis.dialog({ text: `Saved` });
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>
<style lang="stylus" scoped>
.cdeuzmsthagexbkpofbmatmugjuvogfb
@media (min-width 500px)
padding 16px
</style>

View File

@@ -0,0 +1,105 @@
<template>
<div class="hyhctythnmwihguaaapnbrbszsjqxpio">
<table>
<thead>
<tr>
<th>%fa:exchange-alt% In/Out</th>
<th>%fa:server% Host</th>
<th>%fa:bolt% Activity</th>
<th>%fa:user% Actor</th>
</tr>
</thead>
<tbody>
<tr v-for="log in logs" :key="log.id">
<td :class="log.direction">{{ log.direction == 'in' ? '<' : '>' }} {{ log.direction }}</td>
<td>{{ log.host }}</td>
<td>{{ log.activity }}</td>
<td>@{{ log.actor }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
data() {
return {
logs: [],
connection: null
};
},
mounted() {
this.connection = (this as any).os.stream.useSharedConnection('apLog');
this.connection.on('log', this.onLog);
this.connection.on('logs', this.onLogs);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 50
});
},
beforeDestroy() {
this.connection.dispose();
},
methods: {
onLog(log) {
log.id = Math.random();
this.logs.unshift(log);
if (this.logs.length > 50) this.logs.pop();
},
onLogs(logs) {
logs.reverse().forEach(log => this.onLog(log));
}
}
});
</script>
<style lang="stylus" scoped>
.hyhctythnmwihguaaapnbrbszsjqxpio
display block
padding 12px 16px 16px 16px
height 250px
overflow hidden
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--adminDashboardCardBg)
border-radius 8px
> table
width 100%
max-width 100%
overflow auto
border-spacing 0
border-collapse collapse
color var(--adminDashboardCardFg)
font-size 14px
thead
border-bottom solid 1px var(--adminDashboardCardDivider)
tr
th
font-weight normal
text-align left
tbody
tr
&:nth-child(odd)
background rgba(0, 0, 0, 0.025)
th, td
padding 8px 16px
min-width 128px
td.in
color #d26755
td.out
color #55bb83
</style>

View File

@@ -0,0 +1,469 @@
<template>
<div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
<header>
<b>%fa:chart-bar R% %i18n:@title%:</b>
<select v-model="src">
<optgroup label="%i18n:@federation%">
<option value="federation-instances">%i18n:@charts.federation-instances%</option>
<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option>
</optgroup>
<optgroup label="%i18n:@users%">
<option value="users">%i18n:@charts.users%</option>
<option value="users-total">%i18n:@charts.users-total%</option>
</optgroup>
<optgroup label="%i18n:@notes%">
<option value="notes">%i18n:@charts.notes%</option>
<option value="local-notes">%i18n:@charts.local-notes%</option>
<option value="remote-notes">%i18n:@charts.remote-notes%</option>
<option value="notes-total">%i18n:@charts.notes-total%</option>
</optgroup>
<optgroup label="%i18n:@drive%">
<option value="drive-files">%i18n:@charts.drive-files%</option>
<option value="drive-files-total">%i18n:@charts.drive-files-total%</option>
<option value="drive">%i18n:@charts.drive%</option>
<option value="drive-total">%i18n:@charts.drive-total%</option>
</optgroup>
<optgroup label="%i18n:@network%">
<option value="network-requests">%i18n:@charts.network-requests%</option>
<option value="network-time">%i18n:@charts.network-time%</option>
<option value="network-usage">%i18n:@charts.network-usage%</option>
</optgroup>
</select>
<div>
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span>
</div>
</header>
<div ref="chart"></div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts';
const limit = 90;
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x);
export default Vue.extend({
data() {
return {
chart: null,
src: 'notes',
span: 'hour',
chartInstance: null
};
},
computed: {
data(): any {
if (this.chart == null) return null;
switch (this.src) {
case 'federation-instances': return this.federationInstancesChart(false);
case 'federation-instances-total': return this.federationInstancesChart(true);
case 'users': return this.usersChart(false);
case 'users-total': return this.usersChart(true);
case 'notes': return this.notesChart('combined');
case 'local-notes': return this.notesChart('local');
case 'remote-notes': return this.notesChart('remote');
case 'notes-total': return this.notesTotalChart();
case 'drive': return this.driveChart();
case 'drive-total': return this.driveTotalChart();
case 'drive-files': return this.driveFilesChart();
case 'drive-files-total': return this.driveFilesTotalChart();
case 'network-requests': return this.networkRequestsChart();
case 'network-time': return this.networkTimeChart();
case 'network-usage': return this.networkUsageChart();
}
},
stats(): any[] {
const stats =
this.span == 'day' ? this.chart.perDay :
this.span == 'hour' ? this.chart.perHour :
null;
return stats;
}
},
watch: {
src() {
this.render();
},
span() {
this.render();
}
},
async mounted() {
this.now = new Date();
const [perHour, perDay] = await Promise.all([Promise.all([
(this as any).api('charts/federation', { limit: limit, span: 'hour' }),
(this as any).api('charts/users', { limit: limit, span: 'hour' }),
(this as any).api('charts/notes', { limit: limit, span: 'hour' }),
(this as any).api('charts/drive', { limit: limit, span: 'hour' }),
(this as any).api('charts/network', { limit: limit, span: 'hour' })
]), Promise.all([
(this as any).api('charts/federation', { limit: limit, span: 'day' }),
(this as any).api('charts/users', { limit: limit, span: 'day' }),
(this as any).api('charts/notes', { limit: limit, span: 'day' }),
(this as any).api('charts/drive', { limit: limit, span: 'day' }),
(this as any).api('charts/network', { limit: limit, span: 'day' })
])]);
const chart = {
perHour: {
federation: perHour[0],
users: perHour[1],
notes: perHour[2],
drive: perHour[3],
network: perHour[4]
},
perDay: {
federation: perDay[0],
users: perDay[1],
notes: perDay[2],
drive: perDay[3],
network: perDay[4]
}
};
this.chart = chart;
this.render();
},
methods: {
setSrc(src) {
this.src = src;
},
render() {
if (this.chartInstance) {
this.chartInstance.destroy();
}
this.chartInstance = new ApexCharts(this.$refs.chart, {
chart: {
type: 'area',
height: 300,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
stroke: {
curve: 'straight',
width: 2
},
legend: {
labels: {
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
},
},
xaxis: {
type: 'datetime',
labels: {
style: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
},
axisBorder: {
color: 'rgba(0, 0, 0, 0.1)'
},
axisTicks: {
color: 'rgba(0, 0, 0, 0.1)'
},
},
yaxis: {
labels: {
formatter: this.data.bytes ? v => Vue.filter('bytes')(v, 0) : v => Vue.filter('number')(v),
style: {
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
}
},
series: this.data.series
});
this.chartInstance.render();
},
getDate(i: number) {
const y = this.now.getFullYear();
const m = this.now.getMonth();
const d = this.now.getDate();
const h = this.now.getHours();
return (
this.span == 'day' ? new Date(y, m, d - i) :
this.span == 'hour' ? new Date(y, m, d, h - i) :
null
);
},
format(arr) {
return arr.map((v, i) => ({ x: this.getDate(i).getTime(), y: v }));
},
federationInstancesChart(total: boolean): any {
return {
series: [{
data: this.format(total
? this.stats.federation.instance.total
: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))
)
}]
};
},
notesChart(type: string): any {
return {
series: [{
name: 'All',
type: 'line',
data: this.format(type == 'combined'
? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec))
: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec))
)
}, {
name: 'Renotes',
type: 'area',
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote)
: this.stats.notes[type].diffs.renote
)
}, {
name: 'Replies',
type: 'area',
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply)
: this.stats.notes[type].diffs.reply
)
}, {
name: 'Normal',
type: 'area',
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal)
: this.stats.notes[type].diffs.normal
)
}]
};
},
notesTotalChart(): any {
return {
series: [{
name: 'Combined',
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
}, {
name: 'Local',
data: this.format(this.stats.notes.local.total)
}, {
name: 'Remote',
data: this.format(this.stats.notes.remote.total)
}]
};
},
usersChart(total: boolean): any {
return {
series: [{
name: 'Combined',
data: this.format(total
? sum(this.stats.users.local.total, this.stats.users.remote.total)
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
)
}, {
name: 'Local',
data: this.format(total
? this.stats.users.local.total
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
)
}, {
name: 'Remote',
data: this.format(total
? this.stats.users.remote.total
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
)
}]
};
},
driveChart(): any {
return {
bytes: true,
series: [{
name: 'All',
data: this.format(
sum(
this.stats.drive.local.incSize,
negate(this.stats.drive.local.decSize),
this.stats.drive.remote.incSize,
negate(this.stats.drive.remote.decSize)
)
)
}, {
name: 'Local +',
data: this.format(this.stats.drive.local.incSize)
}, {
name: 'Local -',
data: this.format(negate(this.stats.drive.local.decSize))
}, {
name: 'Remote +',
data: this.format(this.stats.drive.remote.incSize)
}, {
name: 'Remote -',
data: this.format(negate(this.stats.drive.remote.decSize))
}]
};
},
driveTotalChart(): any {
return {
bytes: true,
series: [{
name: 'Combined',
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
}, {
name: 'Local',
data: this.format(this.stats.drive.local.totalSize)
}, {
name: 'Remote',
data: this.format(this.stats.drive.remote.totalSize)
}]
};
},
driveFilesChart(): any {
return {
series: [{
name: 'All',
data: this.format(
sum(
this.stats.drive.local.incCount,
negate(this.stats.drive.local.decCount),
this.stats.drive.remote.incCount,
negate(this.stats.drive.remote.decCount)
)
)
}, {
name: 'Local +',
data: this.format(this.stats.drive.local.incCount)
}, {
name: 'Local -',
data: this.format(negate(this.stats.drive.local.decCount))
}, {
name: 'Remote +',
data: this.format(this.stats.drive.remote.incCount)
}, {
name: 'Remote -',
data: this.format(negate(this.stats.drive.remote.decCount))
}]
};
},
driveFilesTotalChart(): any {
return {
series: [{
name: 'Combined',
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
}, {
name: 'Local',
data: this.format(this.stats.drive.local.totalCount)
}, {
name: 'Remote',
data: this.format(this.stats.drive.remote.totalCount)
}]
};
},
networkRequestsChart(): any {
return {
series: [{
name: 'Incoming',
data: this.format(this.stats.network.incomingRequests)
}]
};
},
networkTimeChart(): any {
const data = [];
for (let i = 0; i < limit; i++) {
data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0);
}
return {
series: [{
name: 'Avg time',
data: this.format(data)
}]
};
},
networkUsageChart(): any {
return {
bytes: true,
series: [{
name: 'Incoming',
data: this.format(this.stats.network.incomingBytes)
}, {
name: 'Outgoing',
data: this.format(this.stats.network.outgoingBytes)
}]
};
},
}
});
</script>
<style lang="stylus" scoped>
.qvgidhudpqhjttdhxubzuyrhyzgslujw
display block
flex 1
padding 32px 24px
padding-bottom 0
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face)
border-radius 8px
> header
display flex
margin 0 8px
padding 0 0 8px 0
font-size 1em
color var(--adminDashboardCardFg)
border-bottom solid 1px var(--adminDashboardCardDivider)
> b
margin-right 8px
> *:last-child
margin-left auto
*
&:not(.active)
color var(--primary)
cursor pointer
</style>

View File

@@ -0,0 +1,180 @@
<template>
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
<div>
<header>
<span>%fa:microchip% CPU <span>{{ cpuP }}%</span></span>
<span v-if="meta">{{ meta.cpu.model }}</span>
</header>
<div ref="cpu"></div>
</div>
<div>
<header>
<span>%fa:memory% MEM <span>{{ memP }}%</span></span>
<span v-if="meta"></span>
</header>
<div ref="mem"></div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as ApexCharts from 'apexcharts';
export default Vue.extend({
props: ['connection'],
data() {
return {
stats: [],
cpuChart: null,
memChart: null,
cpuP: '',
memP: '',
meta: null
};
},
watch: {
stats(stats) {
this.cpuChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: x.cpu_usage }))
}]);
this.memChart.updateSeries([{
data: stats.map((x, i) => ({ x: i, y: (x.mem.used / x.mem.total) }))
}]);
}
},
mounted() {
(this as any).os.getMeta().then(meta => {
this.meta = meta;
});
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 200
});
const chartOpts = {
chart: {
type: 'area',
height: 200,
animations: {
dynamicAnimation: {
enabled: false
}
},
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
},
stroke: {
curve: 'straight',
width: 2
},
tooltip: {
enabled: false
},
series: [{
data: []
}],
xaxis: {
type: 'numeric',
labels: {
show: false
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
min: 0,
max: 1
}
};
this.cpuChart = new ApexCharts(this.$refs.cpu, chartOpts);
this.memChart = new ApexCharts(this.$refs.mem, chartOpts);
this.cpuChart.render();
this.memChart.render();
},
beforeDestroy() {
this.connection.off('stats', this.onStats);
this.connection.off('statsLog', this.onStatsLog);
},
methods: {
onStats(stats) {
this.stats.push(stats);
if (this.stats.length > 200) this.stats.shift();
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
},
onStatsLog(statsLog) {
statsLog.reverse().forEach(stats => this.onStats(stats));
}
}
});
</script>
<style lang="stylus" scoped>
.zyknedwtlthezamcjlolyusmipqmjgxz
display flex
> div
display block
flex 1
padding 20px 12px 0 12px
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face)
border-radius 8px
&:first-child
margin-right 16px
> header
display flex
padding 0 8px
margin-bottom -16px
color var(--adminDashboardCardFg)
font-size 14px
> span
&:last-child
margin-left auto
opacity 0.7
> span
opacity 0.7
> div
margin-bottom -10px
@media (max-width 1000px)
display block
margin-bottom 26px
> div
&:first-child
margin-right 0
margin-bottom 26px
</style>

View File

@@ -0,0 +1,236 @@
<template>
<div class="obdskegsannmntldydackcpzezagxqfy">
<header v-if="meta">
<p><b>Misskey</b><span>{{ meta.version }}</span></p>
<p><b>Machine</b><span>{{ meta.machine }}</span></p>
<p><b>OS</b><span>{{ meta.os }}</span></p>
<p><b>Node</b><span>{{ meta.node }}</span></p>
<p>%i18n:common.ai-chan-kawaii%</p>
</header>
<div v-if="stats" class="stats">
<div>
<div>
<div>%fa:user%</div>
<div>
<span>%i18n:@accounts%</span>
<b class="primary">{{ stats.originalUsersCount | number }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('users')">%fa:chart-bar R%</span>
</div>
</div>
<div>
<div>
<div>%fa:pencil-alt%</div>
<div>
<span>%i18n:@notes%</span>
<b class="primary">{{ stats.originalNotesCount | number }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('notes')">%fa:chart-bar R%</span>
</div>
</div>
<div>
<div>
<div>%fa:database%</div>
<div>
<span>%i18n:@drive%</span>
<b>{{ stats.driveUsageLocal | bytes }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('drive')">%fa:chart-bar R%</span>
</div>
</div>
<div>
<div>
<div>%fa:hdd R%</div>
<div>
<span>%i18n:@instances%</span>
<b>{{ stats.instances | number }}</b>
</div>
</div>
<div>
<span>%fa:globe% %i18n:@federated%</span>
<span @click="setChartSrc('federation-instances-total')">%fa:chart-bar R%</span>
</div>
</div>
</div>
<div class="charts">
<x-charts ref="charts"/>
</div>
<div class="cpu-memory">
<x-cpu-memory :connection="connection"/>
</div>
<div class="ap">
<x-ap-log/>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import XCpuMemory from "./cpu-memory.vue";
import XCharts from "./charts.vue";
import XApLog from "./ap-log.vue";
export default Vue.extend({
components: {
XCpuMemory,
XCharts,
XApLog
},
data() {
return {
stats: null,
connection: null,
meta: null
};
},
created() {
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
(this as any).os.getMeta().then(meta => {
this.meta = meta;
});
(this as any).api('stats').then(stats => {
this.stats = stats;
});
},
beforeDestroy() {
this.connection.dispose();
},
methods: {
setChartSrc(src) {
this.$refs.charts.setSrc(src);
}
}
});
</script>
<style lang="stylus" scoped>
.obdskegsannmntldydackcpzezagxqfy
padding 16px
@media (min-width 500px)
padding 32px
> header
display flex
margin-bottom 16px
padding-bottom 16px
border-bottom solid 1px var(--adminDashboardHeaderBorder)
color var(--adminDashboardHeaderFg)
font-size 14px
white-space nowrap
@media (max-width 1000px)
display none
> p
display block
margin 0 32px 0 0
overflow hidden
text-overflow ellipsis
> b
&:after
content ':'
margin-right 8px
&:last-child
margin-left auto
margin-right 0
> .stats
display flex
justify-content space-between
margin-bottom 16px
> div
flex 1
margin-right 16px
color var(--adminDashboardCardFg)
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--adminDashboardCardBg)
border-radius 8px
&:last-child
margin-right 0
> div:first-child
display flex
align-items center
text-align center
&:last-child
margin-right 0
> div:first-child
padding 16px 24px
font-size 28px
> div:last-child
flex 1
padding 16px 32px 16px 0
text-align right
> span
font-size 70%
opacity 0.7
> b
display block
&.primary
color var(--primary)
> div:last-child
display flex
padding 6px 16px
border-top solid 1px var(--adminDashboardCardDivider)
> span
font-size 70%
opacity 0.7
&:last-child
margin-left auto
cursor pointer
@media (max-width 900px)
display grid
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr
gap 16px
> div
margin-right 0
@media (max-width 500px)
display block
> div:not(:last-child)
margin-bottom 16px
> .charts
margin-bottom 16px
> .cpu-memory
margin-bottom 16px
</style>

View File

@@ -0,0 +1,117 @@
<template>
<div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
<ui-card>
<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-input v-model="name">
<span>%i18n:@add-emoji.name%</span>
<span slot="text">%i18n:@add-emoji.name-desc%</span>
</ui-input>
<ui-input v-model="aliases">
<span>%i18n:@add-emoji.aliases%</span>
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="url">
<span>%i18n:@add-emoji.url%</span>
</ui-input>
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:grin R% %i18n:@emojis.title%</div>
<section v-for="emoji in emojis">
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
<ui-horizon-group inputs>
<ui-input v-model="emoji.name">
<span>%i18n:@add-emoji.name%</span>
</ui-input>
<ui-input v-model="emoji.aliases">
<span>%i18n:@add-emoji.aliases%</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="emoji.url">
<span>%i18n:@add-emoji.url%</span>
</ui-input>
<ui-horizon-group>
<ui-button @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button>
<ui-button @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button>
</ui-horizon-group>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
data() {
return {
name: '',
url: '',
aliases: '',
emojis: []
};
},
mounted() {
this.fetchEmojis();
},
methods: {
add() {
(this as any).api('admin/emoji/add', {
name: this.name,
url: this.url,
aliases: this.aliases.split(' ')
}).then(() => {
//(this as any).os.apis.dialog({ text: `Added` });
this.fetchEmojis();
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
},
fetchEmojis() {
(this as any).api('admin/emoji/list').then(emojis => {
emojis.forEach(e => e.aliases = (e.aliases || []).join(' '));
this.emojis = emojis;
});
},
updateEmoji(emoji) {
(this as any).api('admin/emoji/update', {
id: emoji.id,
name: emoji.name,
url: emoji.url,
aliases: emoji.aliases.split(' ')
}).then(() => {
//(this as any).os.apis.dialog({ text: `Updated` });
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
},
removeEmoji(emoji) {
(this as any).api('admin/emoji/remove', {
id: emoji.id
}).then(() => {
//(this as any).os.apis.dialog({ text: `Removed` });
this.fetchEmojis();
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>
<style lang="stylus" scoped>
.tumhkfkmgtvzljezfvmgkeurkfncshbe
@media (min-width 500px)
padding 16px
</style>

View File

@@ -1,8 +1,12 @@
<template>
<div class="jdnqwkzlnxcfftthoybjxrebyolvoucw mk-admin-card">
<header>%i18n:@hided-tags%</header>
<textarea v-model="hidedTags"></textarea>
<button class="ui" @click="save">%i18n:@save%</button>
<div>
<ui-card>
<div slot="title">%i18n:@hided-tags%</div>
<section>
<textarea class="jdnqwkzlnxcfftthoybjxrebyolvoucw" v-model="hidedTags"></textarea>
<ui-button @click="save">%i18n:@save%</ui-button>
</section>
</ui-card>
</div>
</template>
@@ -25,9 +29,9 @@ export default Vue.extend({
(this as any).api('admin/update-meta', {
hidedTags: this.hidedTags.split('\n')
}).then(() => {
(this as any).os.apis.dialog({ text: `Saved` });
//(this as any).os.apis.dialog({ text: `Saved` });
}).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` });
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
@@ -35,11 +39,8 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.jdnqwkzlnxcfftthoybjxrebyolvoucw
textarea
width 100%
min-height 300px
width 100%
min-height 300px
</style>

View File

@@ -0,0 +1,260 @@
<template>
<div class="mk-admin" :class="{ isMobile }">
<header v-show="isMobile">
<button class="nav" @click="navOpend = true">%fa:bars%</button>
<span>MisskeyMyAdmin</span>
</header>
<div class="nav-backdrop"
v-if="navOpend && isMobile"
@click="navOpend = false"
@touchstart="navOpend = false"
></div>
<nav v-show="navOpend">
<div class="mi">
<img svg-inline src="../assets/header-icon.svg"/>
</div>
<div class="me">
<img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/>
<p class="name">{{ $store.state.i | userName }}</p>
</div>
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:home .fw%%i18n:@dashboard%</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }">%fa:cog .fw%%i18n:@instance%</li>
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }">%fa:grin R .fw%%i18n:@emoji%</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
</ul>
<div class="back-to-misskey">
<a href="/">%fa:arrow-left% %i18n:@back-to-misskey%</a>
</div>
<div class="version">
<small>Misskey {{ version }}</small>
</div>
</nav>
<main>
<div v-show="page == 'dashboard'"><x-dashboard/></div>
<div v-show="page == 'instance'"><x-instance/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-show="page == 'emoji'"><x-emoji/></div>
<div v-show="page == 'announcements'"><x-announcements/></div>
<div v-show="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div>
</main>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { version } from '../../config';
import XDashboard from "./dashboard.vue";
import XInstance from "./instance.vue";
import XEmoji from "./emoji.vue";
import XAnnouncements from "./announcements.vue";
import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue";
// Detect the user agent
const ua = navigator.userAgent.toLowerCase();
const isMobile = /mobile|iphone|ipad|android/.test(ua);
export default Vue.extend({
components: {
XDashboard,
XInstance,
XEmoji,
XAnnouncements,
XHashtags,
XUsers
},
provide: {
isMobile
},
data() {
return {
page: 'dashboard',
version,
isMobile,
navOpend: !isMobile
};
},
methods: {
nav(page: string) {
this.page = page;
}
}
});
</script>
<style lang="stylus">
.mk-admin
$headerHeight = 48px
display flex
height 100%
> header
position fixed
top 0
z-index 10000
width 100%
color var(--mobileHeaderFg)
background-color var(--mobileHeaderBg)
box-shadow 0 1px 0 rgba(#000, 0.075)
&, *
user-select none
> span
display block
line-height $headerHeight
text-align center
> .nav
display block
position absolute
top 0
left 0
z-index 10001
padding 0
width $headerHeight
font-size 1.4em
line-height $headerHeight
border-right solid 1px rgba(#000, 0.1)
> [data-fa]
transition all 0.2s ease
> nav
position fixed
z-index 20001
top 0
left 0
width 250px
height 100vh
overflow auto
background #333
color #fff
> .mi
text-align center
> svg
width 24px
height 82px
vertical-align top
fill #fff
opacity 0.7
> .me
display flex
margin 0 16px 16px 16px
padding 16px 0
align-items center
border-top solid 1px #555
border-bottom solid 1px #555
> .avatar
height 48px
border-radius 100%
vertical-align middle
> .name
margin 0 16px
padding 0
color #fff
overflow hidden
text-overflow ellipsis
white-space nowrap
font-size 15px
> .back-to-misskey
margin 16px 16px 0 16px
padding 0
border-top solid 1px #555
> a
display block
padding 16px 4px
color inherit
text-decoration none
color #eee
font-size 15px
&:hover
color #fff
> [data-fa]
margin-right 6px
> .version
margin 0 16px 16px 16px
padding-top 16px
border-top solid 1px #555
text-align center
> small
opacity 0.7
> ul
margin 0
padding 0
list-style none
font-size 15px
> li
display block
padding 10px 16px
margin 0
cursor pointer
user-select none
color #eee
transition margin-left 0.2s ease
&:hover
color #fff
> [data-fa]
margin-right 6px
&.active
margin-left 8px
color var(--primary) !important
&:after
content ""
display block
position absolute
top 0
right 0
bottom 0
margin auto 0
height 0
border-top solid 16px transparent
border-right solid 16px var(--bg)
border-bottom solid 16px transparent
border-left solid 16px transparent
> .nav-backdrop
position fixed
top 0
left 0
z-index 20000
width 100%
height 100%
background var(--mobileNavBackdrop)
> main
width 100%
padding 0 0 0 250px
max-width 1300px
&.isMobile
> main
padding $headerHeight 0 0 0
</style>

View File

@@ -0,0 +1,85 @@
<template>
<div class="axbwjelsbymowqjyywpirzhdlszoncqs">
<ui-card>
<div slot="title">%fa:cog% %i18n:@instance%</div>
<section class="fit-top">
<ui-input v-model="name">%i18n:@instance-name%</ui-input>
<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea>
<ui-input v-model="bannerUrl">%i18n:@banner-url%</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@disable-registration%</div>
<section>
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
<button class="ui" @click="invite">%i18n:@invite%</button>
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@disable-local-timeline%</div>
<section>
<input type="checkbox" v-model="disableLocalTimeline" @change="updateMeta">
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
data() {
return {
disableRegistration: false,
disableLocalTimeline: false,
bannerUrl: null,
name: null,
description: null,
inviteCode: null,
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.bannerUrl = meta.bannerUrl;
this.name = meta.name;
this.description = meta.description;
});
},
methods: {
invite() {
(this as any).api('admin/invite').then(x => {
this.inviteCode = x.code;
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
},
updateMeta() {
(this as any).api('admin/update-meta', {
disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline,
bannerUrl: this.bannerUrl,
name: this.name,
description: this.description
}).then(() => {
//(this as any).os.apis.dialog({ text: `Saved` });
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>
<style lang="stylus" scoped>
.axbwjelsbymowqjyywpirzhdlszoncqs
@media (min-width 500px)
padding 16px
</style>

View File

@@ -0,0 +1,136 @@
<template>
<div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
<ui-card>
<div slot="title">%i18n:@verify-user%</div>
<section class="fit-top">
<ui-input v-model="verifyUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="verifyUser" :disabled="verifying">%i18n:@verify%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@unverify-user%</div>
<section class="fit-top">
<ui-input v-model="unverifyUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@suspend-user%</div>
<section class="fit-top">
<ui-input v-model="suspendUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="suspendUser" :disabled="suspending">%i18n:@suspend%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@unsuspend-user%</div>
<section class="fit-top">
<ui-input v-model="unsuspendUsername" type="text">
<span slot="prefix">@</span>
</ui-input>
<ui-button @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import parseAcct from "../../../../misc/acct/parse";
export default Vue.extend({
data() {
return {
verifyUsername: null,
verifying: false,
unverifyUsername: null,
unverifying: false,
suspendUsername: null,
suspending: false,
unsuspendUsername: null,
unsuspending: false
};
},
methods: {
async verifyUser() {
this.verifying = true;
const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername));
await (this as any).os.api('admin/verify-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@verified%' });
};
await process().catch(e => {
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.verifying = false;
},
async unverifyUser() {
this.unverifying = true;
const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername));
await (this as any).os.api('admin/unverify-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@unverified%' });
};
await process().catch(e => {
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.unverifying = false;
},
async suspendUser() {
this.suspending = true;
const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername));
await (this as any).os.api('admin/suspend-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@suspended%' });
};
await process().catch(e => {
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.suspending = false;
},
async unsuspendUser() {
this.unsuspending = true;
const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername));
await (this as any).os.api('admin/unsuspend-user', { userId: user.id });
//(this as any).os.apis.dialog({ text: '%i18n:@unsuspended%' });
};
await process().catch(e => {
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.unsuspending = false;
}
}
});
</script>
<style lang="stylus" scoped>
.ucnffhbtogqgscfmqcymwmmupoknpfsw
@media (min-width 500px)
padding 16px
</style>

View File

@@ -46,6 +46,7 @@
if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs';
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
//#endregion
//#region Detect the user language

View File

@@ -1,5 +1,5 @@
import MiOS from '../../mios';
import { version as current } from '../../config';
import { clientVersion as current } from '../../config';
export default async function(mios: MiOS, force = false, silent = false) {
const meta = await mios.getMeta(force);

View File

@@ -14,9 +14,10 @@
</ol>
<ol class="emojis" ref="suggests" v-if="emojis.length > 0">
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
<span class="emoji">{{ emoji.emoji }}</span>
<span class="emoji" v-if="emoji.url"><img :src="emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else>{{ emoji.emoji }}</span>
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
<span class="alias" v-if="emoji.alias">({{ emoji.alias }})</span>
<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
</li>
</ol>
</div>
@@ -27,14 +28,21 @@ import Vue from 'vue';
import * as emojilib from 'emojilib';
import contains from '../../../common/scripts/contains';
type EmojiDef = {
emoji: string;
name: string;
aliasOf?: string;
url?: string;
};
const lib = Object.entries(emojilib.lib).filter((x: any) => {
return x[1].category != 'flags';
});
const emjdb = lib.map((x: any) => ({
const emjdb: EmojiDef[] = lib.map((x: any) => ({
emoji: x[1].char,
name: x[0],
alias: null
aliasOf: null
}));
lib.forEach((x: any) => {
@@ -43,7 +51,7 @@ lib.forEach((x: any) => {
emjdb.push({
emoji: x[1].char,
name: k,
alias: x[0]
aliasOf: x[0]
});
});
}
@@ -61,7 +69,8 @@ export default Vue.extend({
hashtags: [],
emojis: [],
select: -1,
emojilib
emojilib,
emojiDb: [] as EmojiDef[]
}
},
@@ -90,6 +99,34 @@ export default Vue.extend({
},
mounted() {
//#region Construct Emoji DB
const customEmojis = (this.os.getMetaSync() || { emojis: [] }).emojis || [];
const emojiDefinitions: EmojiDef[] = [];
customEmojis.forEach(x => {
emojiDefinitions.push({
name: x.name,
emoji: `:${x.name}:`,
url: x.url
});
if (x.aliases) {
x.aliases.forEach(alias => {
emojiDefinitions.push({
name: alias,
aliasOf: x.name,
emoji: `:${x.name}:`,
url: x.url
});
});
}
});
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
this.emojiDb = emojiDefinitions.concat(emjdb);
//#endregion
this.textarea.addEventListener('keydown', this.onKeydown);
Array.from(document.querySelectorAll('body *')).forEach(el => {
@@ -169,22 +206,25 @@ export default Vue.extend({
}
} else if (this.type == 'emoji') {
const matched = [];
emjdb.some(x => {
if (x.name.indexOf(this.q) == 0 && !x.alias && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == 30;
const max = 30;
this.emojiDb.some(x => {
if (x.name.startsWith(this.q) && !x.aliasOf && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max;
});
if (matched.length < 30) {
emjdb.some(x => {
if (x.name.indexOf(this.q) == 0 && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == 30;
if (matched.length < max) {
this.emojiDb.some(x => {
if (x.name.startsWith(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max;
});
}
if (matched.length < 30) {
emjdb.some(x => {
if (x.name.indexOf(this.q) > -1 && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == 30;
if (matched.length < max) {
this.emojiDb.some(x => {
if (x.name.includes(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
return matched.length == max;
});
}
this.emojis = matched;
}
},
@@ -340,6 +380,10 @@ export default Vue.extend({
margin 0 4px 0 0
width 24px
> img
width 24px
vertical-align bottom
.name
color var(--autocompleteItemText)

View File

@@ -1,5 +1,5 @@
<template>
<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on Github">
<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on GitHub">
<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>

View File

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

View File

@@ -3,6 +3,7 @@ import Vue from 'vue';
import muteAndBlock from './mute-and-block.vue';
import error from './error.vue';
import apiSettings from './api-settings.vue';
import passwordSettings from './password-settings.vue';
import driveSettings from './drive-settings.vue';
import profileEditor from './profile-editor.vue';
import noteSkeleton from './note-skeleton.vue';
@@ -36,11 +37,13 @@ import messaging from './messaging.vue';
import messagingRoom from './messaging-room.vue';
import urlPreview from './url-preview.vue';
import twitterSetting from './twitter-setting.vue';
import githubSetting from './github-setting.vue';
import fileTypeIcon from './file-type-icon.vue';
import Reversi from './games/reversi/reversi.vue';
import welcomeTimeline from './welcome-timeline.vue';
import uiInput from './ui/input.vue';
import uiButton from './ui/button.vue';
import uiHorizonGroup from './ui/horizon-group.vue';
import uiCard from './ui/card.vue';
import uiForm from './ui/form.vue';
import uiTextarea from './ui/textarea.vue';
@@ -54,6 +57,7 @@ import formRadio from './ui/form/radio.vue';
Vue.component('mk-mute-and-block', muteAndBlock);
Vue.component('mk-error', error);
Vue.component('mk-api-settings', apiSettings);
Vue.component('mk-password-settings', passwordSettings);
Vue.component('mk-drive-settings', driveSettings);
Vue.component('mk-profile-editor', profileEditor);
Vue.component('mk-note-skeleton', noteSkeleton);
@@ -87,11 +91,13 @@ Vue.component('mk-messaging', messaging);
Vue.component('mk-messaging-room', messagingRoom);
Vue.component('mk-url-preview', urlPreview);
Vue.component('mk-twitter-setting', twitterSetting);
Vue.component('mk-github-setting', githubSetting);
Vue.component('mk-file-type-icon', fileTypeIcon);
Vue.component('mk-reversi', Reversi);
Vue.component('mk-welcome-timeline', welcomeTimeline);
Vue.component('ui-input', uiInput);
Vue.component('ui-button', uiButton);
Vue.component('ui-horizon-group', uiHorizonGroup);
Vue.component('ui-card', uiCard);
Vue.component('ui-form', uiForm);
Vue.component('ui-textarea', uiTextarea);

View File

@@ -3,7 +3,6 @@ import * as emojilib from 'emojilib';
import { length } from 'stringz';
import parse from '../../../../../mfm/parse';
import getAcct from '../../../../../misc/acct/render';
import { url } from '../../../config';
import MkUrl from './url.vue';
import MkGoogle from './google.vue';
import { concat } from '../../../../../prelude/array';
@@ -25,6 +24,9 @@ export default Vue.component('misskey-flavored-markdown', {
i: {
type: Object,
default: null
},
customEmojis: {
required: false,
}
},
@@ -186,6 +188,22 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'emoji': {
//#region カスタム絵文字
if (this.customEmojis != null) {
const customEmoji = this.customEmojis.find(e => e.name == token.emoji || (e.aliases || []).includes(token.emoji));
if (customEmoji) {
return [createElement('img', {
attrs: {
src: customEmoji.url,
alt: token.emoji,
title: token.emoji,
style: 'height: 2.5em; vertical-align: middle;'
}
})];
}
}
//#endregion
const emoji = emojilib.lib[token.emoji];
return [createElement('span', emoji ? emoji.char : token.content)];
}

View File

@@ -2,8 +2,6 @@
<span class="mk-nav">
<a :href="aboutUrl">%i18n:@about%</a>
<i></i>
<a href="/stats">%i18n:@stats%</a>
<i></i>
<a :href="repositoryUrl">%i18n:@repository%</a>
<i></i>
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>

View File

@@ -13,6 +13,7 @@
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/github`">%i18n:@signin-with-github%</a></p>
</form>
</template>

View File

@@ -1,5 +1,10 @@
<template>
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr" :is="link ? 'a' : 'button'" :class="[styl, { inline, primary }]" :type="type" @click="$emit('click')">
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr"
:is="link ? 'a' : 'button'"
:class="[styl, { inline, primary }]"
:type="type"
@click="$emit('click')"
>
<slot></slot>
</component>
</template>
@@ -7,6 +12,7 @@
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
inject: ['horizonGrouped'],
props: {
type: {
type: String,
@@ -20,7 +26,9 @@ export default Vue.extend({
inline: {
type: Boolean,
required: false,
default: false
default(): boolean {
return this.horizonGrouped;
}
},
link: {
type: Boolean,

View File

@@ -0,0 +1,35 @@
<template>
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze" :class="{ inputs }">
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
provide: {
horizonGrouped: true
},
props: {
inputs: {
type: Boolean,
required: false,
default: false
}
}
});
</script>
<style lang="stylus" scoped>
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
display flex
&.inputs
margin 32px 0
> *
flex 1
&:not(:last-child)
margin-right 16px
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="ui-input" :class="[{ focused, filled }, styl]">
<div class="ui-input" :class="[{ focused, filled, inline }, styl]">
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input">
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
@@ -41,6 +41,7 @@ import Vue from 'vue';
const getPasswordStrength = require('syuilo-password-strength');
export default Vue.extend({
inject: ['horizonGrouped'],
props: {
value: {
required: false
@@ -72,6 +73,13 @@ export default Vue.extend({
required: false,
default: false
},
inline: {
type: Boolean,
required: false,
default(): boolean {
return this.horizonGrouped;
}
},
styl: {
type: String,
required: false,
@@ -337,4 +345,8 @@ root(fill)
&:not(.fill)
root(false)
&.inline
display inline-block
margin 0
</style>

View File

@@ -14,7 +14,7 @@
</div>
</header>
<div class="text">
<misskey-flavored-markdown v-if="note.text" :text="note.text"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="note.emojis"/>
</div>
</div>
</div>

View File

@@ -222,13 +222,15 @@ class Autocomplete {
const trimmedBefore = before.substring(0, before.lastIndexOf(':'));
const after = source.substr(caret);
if (value.startsWith(':')) value = value + ' ';
// 挿入
this.text = trimmedBefore + value + after;
// キャレットを戻す
this.vm.$nextTick(() => {
this.textarea.focus();
const pos = trimmedBefore.length + 1;
const pos = trimmedBefore.length + (value.startsWith(':') ? value.length : 1);
this.textarea.setSelectionRange(pos, pos);
});
}

View File

@@ -1,6 +1,7 @@
import Vue from 'vue';
Vue.filter('bytes', (v, digits = 0) => {
if (v == null) return '?';
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
if (v == 0) return '0';
const isMinus = v < 0;

View File

@@ -1,5 +1,6 @@
import Vue from 'vue';
Vue.filter('number', (n) => {
if (n == null) return 'N/A';
return n.toLocaleString();
});

View File

@@ -3,7 +3,7 @@
</template>
<script lang="ts">
import { version, codename } from '../../../config';
import { clientVersion as version, codename } from '../../../config';
import define from '../../../common/define-widget';
export default define({
name: 'version'

View File

@@ -3,6 +3,7 @@ declare const _LANGS_: string;
declare const _THEME_COLOR_: string;
declare const _COPYRIGHT_: string;
declare const _VERSION_: string;
declare const _CLIENT_VERSION_: string;
declare const _CODENAME_: string;
declare const _ENV_: string;
@@ -18,5 +19,6 @@ export const langs = _LANGS_;
export const themeColor = _THEME_COLOR_;
export const copyright = _COPYRIGHT_;
export const version = _VERSION_;
export const clientVersion = _CLIENT_VERSION_;
export const codename = _CODENAME_;
export const env = _ENV_;

View File

@@ -23,8 +23,6 @@ import updateBanner from './api/update-banner';
import MkIndex from './views/pages/index.vue';
import MkHome from './views/pages/home.vue';
import MkDeck from './views/pages/deck/deck.vue';
import MkAdmin from './views/pages/admin/admin.vue';
import MkStats from './views/pages/stats/stats.vue';
import MkUser from './views/pages/user/user.vue';
import MkFavorites from './views/pages/favorites.vue';
import MkSelectDrive from './views/pages/selectdrive.vue';
@@ -57,8 +55,6 @@ init(async (launch) => {
{ path: '/', name: 'index', component: MkIndex },
{ path: '/home', name: 'home', component: MkHome },
{ path: '/deck', name: 'deck', component: MkDeck },
{ path: '/admin', name: 'admin', component: MkAdmin },
{ path: '/stats', name: 'stats', component: MkStats },
{ path: '/i/customize-home', component: MkHomeCustomize },
{ path: '/i/favorites', component: MkFavorites },
{ path: '/i/messaging/:user', component: MkMessagingRoom },

View File

@@ -32,9 +32,21 @@ export default Vue.extend({
this.data.forEach(d => d.total = d.notes + d.replies + d.renotes);
const peak = Math.max.apply(null, this.data.map(d => d.total));
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
const day = now.getDate();
let x = 0;
this.data.slice().reverse().forEach(d => {
this.data.slice().reverse().forEach((d, i) => {
d.x = x;
const date = new Date(year, month, day - i);
d.date = {
year: date.getFullYear(),
month: date.getMonth(),
day: date.getDate()
};
d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay();
d.v = peak == 0 ? 0 : d.total / (peak / 2);

View File

@@ -43,11 +43,17 @@ export default Vue.extend({
};
},
mounted() {
(this as any).api('aggregation/users/activity', {
(this as any).api('charts/user/notes', {
userId: this.user.id,
limit: 20 * 7
span: 'day',
limit: 7 * 20
}).then(activity => {
this.activity = activity;
this.activity = activity.diffs.normal.map((_, i) => ({
total: activity.diffs.normal[i] + activity.diffs.reply[i] + activity.diffs.renote[i],
notes: activity.diffs.normal[i],
replies: activity.diffs.reply[i],
renotes: activity.diffs.renote[i]
}));
this.fetching = false;
});
},

View File

@@ -1,42 +0,0 @@
import Vue from 'vue';
import { Line } from 'vue-chartjs';
import * as mergeOptions from 'merge-options';
export default Vue.extend({
extends: Line,
props: {
data: {
required: true
},
opts: {
required: false
}
},
watch: {
data() {
this.render();
}
},
mounted() {
this.render();
},
methods: {
render() {
this.renderChart(this.data, mergeOptions({
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
type: 'time',
distribution: 'series'
}]
},
tooltips: {
intersect: false,
mode: 'index',
position: 'nearest'
}
}, this.opts || {}));
}
}
});

View File

@@ -1,723 +0,0 @@
<template>
<div class="gkgckalzgidaygcxnugepioremxvxvpt">
<header>
<b>%i18n:@title%:</b>
<select v-model="chartType">
<optgroup label="%i18n:@federation%">
<option value="federation-instances">%i18n:@charts.federation-instances%</option>
<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option>
</optgroup>
<optgroup label="%i18n:@users%">
<option value="users">%i18n:@charts.users%</option>
<option value="users-total">%i18n:@charts.users-total%</option>
</optgroup>
<optgroup label="%i18n:@notes%">
<option value="notes">%i18n:@charts.notes%</option>
<option value="local-notes">%i18n:@charts.local-notes%</option>
<option value="remote-notes">%i18n:@charts.remote-notes%</option>
<option value="notes-total">%i18n:@charts.notes-total%</option>
</optgroup>
<optgroup label="%i18n:@drive%">
<option value="drive-files">%i18n:@charts.drive-files%</option>
<option value="drive-files-total">%i18n:@charts.drive-files-total%</option>
<option value="drive">%i18n:@charts.drive%</option>
<option value="drive-total">%i18n:@charts.drive-total%</option>
</optgroup>
<optgroup label="%i18n:@network%">
<option value="network-requests">%i18n:@charts.network-requests%</option>
<option value="network-time">%i18n:@charts.network-time%</option>
<option value="network-usage">%i18n:@charts.network-usage%</option>
</optgroup>
</select>
<div>
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span>
</div>
</header>
<div>
<x-chart v-if="chart" :data="data[0]" :opts="data[1]"/>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import XChart from './charts.chart.ts';
const colors = {
local: 'rgb(246, 88, 79)',
remote: 'rgb(65, 221, 222)',
localPlus: 'rgb(52, 178, 118)',
remotePlus: 'rgb(158, 255, 209)',
localMinus: 'rgb(255, 97, 74)',
remoteMinus: 'rgb(255, 149, 134)',
incoming: 'rgb(52, 178, 118)',
outgoing: 'rgb(255, 97, 74)',
};
const rgba = (color: string): string => {
return color.replace('rgb', 'rgba').replace(')', ', 0.1)');
};
const limit = 35;
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x);
export default Vue.extend({
components: {
XChart
},
data() {
return {
now: null,
chart: null,
chartType: 'notes',
span: 'hour'
};
},
computed: {
data(): any {
if (this.chart == null) return null;
switch (this.chartType) {
case 'federation-instances': return this.federationInstancesChart(false);
case 'federation-instances-total': return this.federationInstancesChart(true);
case 'users': return this.usersChart(false);
case 'users-total': return this.usersChart(true);
case 'notes': return this.notesChart('combined');
case 'local-notes': return this.notesChart('local');
case 'remote-notes': return this.notesChart('remote');
case 'notes-total': return this.notesTotalChart();
case 'drive': return this.driveChart();
case 'drive-total': return this.driveTotalChart();
case 'drive-files': return this.driveFilesChart();
case 'drive-files-total': return this.driveFilesTotalChart();
case 'network-requests': return this.networkRequestsChart();
case 'network-time': return this.networkTimeChart();
case 'network-usage': return this.networkUsageChart();
}
},
stats(): any[] {
const stats =
this.span == 'day' ? this.chart.perDay :
this.span == 'hour' ? this.chart.perHour :
null;
return stats;
}
},
async created() {
this.now = new Date();
const [perHour, perDay] = await Promise.all([Promise.all([
(this as any).api('charts/federation', { limit: limit, span: 'hour' }),
(this as any).api('charts/users', { limit: limit, span: 'hour' }),
(this as any).api('charts/notes', { limit: limit, span: 'hour' }),
(this as any).api('charts/drive', { limit: limit, span: 'hour' }),
(this as any).api('charts/network', { limit: limit, span: 'hour' })
]), Promise.all([
(this as any).api('charts/federation', { limit: limit, span: 'day' }),
(this as any).api('charts/users', { limit: limit, span: 'day' }),
(this as any).api('charts/notes', { limit: limit, span: 'day' }),
(this as any).api('charts/drive', { limit: limit, span: 'day' }),
(this as any).api('charts/network', { limit: limit, span: 'day' })
])]);
const chart = {
perHour: {
federation: perHour[0],
users: perHour[1],
notes: perHour[2],
drive: perHour[3],
network: perHour[4]
},
perDay: {
federation: perDay[0],
users: perDay[1],
notes: perDay[2],
drive: perDay[3],
network: perDay[4]
}
};
this.chart = chart;
},
methods: {
getDate(i: number) {
const y = this.now.getFullYear();
const m = this.now.getMonth();
const d = this.now.getDate();
const h = this.now.getHours();
return (
this.span == 'day' ? new Date(y, m, d - i) :
this.span == 'hour' ? new Date(y, m, d, h - i) :
null
);
},
format(arr) {
return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v }));
},
federationInstancesChart(total: boolean): any {
return [{
datasets: [{
label: 'Instances',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(total
? this.stats.federation.instance.total
: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec)))
}]
}];
},
notesChart(type: string): any {
return [{
datasets: [{
label: 'All',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(type == 'combined'
? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec))
: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec))
)
}, {
label: 'Renotes',
fill: true,
backgroundColor: 'rgba(161, 222, 65, 0.1)',
borderColor: '#a1de41',
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote)
: this.stats.notes[type].diffs.renote
)
}, {
label: 'Replies',
fill: true,
backgroundColor: 'rgba(247, 121, 108, 0.1)',
borderColor: '#f7796c',
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply)
: this.stats.notes[type].diffs.reply
)
}, {
label: 'Normal',
fill: true,
backgroundColor: 'rgba(65, 221, 222, 0.1)',
borderColor: '#41ddde',
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(type == 'combined'
? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal)
: this.stats.notes[type].diffs.normal
)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('number')(value);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
}
}
}
}];
},
notesTotalChart(): any {
return [{
datasets: [{
label: 'Combined',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
}, {
label: 'Local',
fill: true,
backgroundColor: rgba(colors.local),
borderColor: colors.local,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.notes.local.total)
}, {
label: 'Remote',
fill: true,
backgroundColor: rgba(colors.remote),
borderColor: colors.remote,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.notes.remote.total)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('number')(value);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
}
}
}
}];
},
usersChart(total: boolean): any {
return [{
datasets: [{
label: 'Combined',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(total
? sum(this.stats.users.local.total, this.stats.users.remote.total)
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
)
}, {
label: 'Local',
fill: true,
backgroundColor: rgba(colors.local),
borderColor: colors.local,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(total
? this.stats.users.local.total
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
)
}, {
label: 'Remote',
fill: true,
backgroundColor: rgba(colors.remote),
borderColor: colors.remote,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(total
? this.stats.users.remote.total
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('number')(value);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
}
}
}
}];
},
driveChart(): any {
return [{
datasets: [{
label: 'All',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(sum(this.stats.drive.local.incSize, negate(this.stats.drive.local.decSize), this.stats.drive.remote.incSize, negate(this.stats.drive.remote.decSize)))
}, {
label: 'Local +',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.local.incSize)
}, {
label: 'Local -',
fill: true,
backgroundColor: rgba(colors.localMinus),
borderColor: colors.localMinus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(negate(this.stats.drive.local.decSize))
}, {
label: 'Remote +',
fill: true,
backgroundColor: rgba(colors.remotePlus),
borderColor: colors.remotePlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.remote.incSize)
}, {
label: 'Remote -',
fill: true,
backgroundColor: rgba(colors.remoteMinus),
borderColor: colors.remoteMinus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(negate(this.stats.drive.remote.decSize))
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('bytes')(value, 1);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
}
}
}
}];
},
driveTotalChart(): any {
return [{
datasets: [{
label: 'Combined',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
}, {
label: 'Local',
fill: true,
backgroundColor: rgba(colors.local),
borderColor: colors.local,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.local.totalSize)
}, {
label: 'Remote',
fill: true,
backgroundColor: rgba(colors.remote),
borderColor: colors.remote,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.remote.totalSize)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('bytes')(value, 1);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
}
}
}
}];
},
driveFilesChart(): any {
return [{
datasets: [{
label: 'All',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(sum(this.stats.drive.local.incCount, negate(this.stats.drive.local.decCount), this.stats.drive.remote.incCount, negate(this.stats.drive.remote.decCount)))
}, {
label: 'Local +',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.local.incCount)
}, {
label: 'Local -',
fill: true,
backgroundColor: rgba(colors.localMinus),
borderColor: colors.localMinus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(negate(this.stats.drive.local.decCount))
}, {
label: 'Remote +',
fill: true,
backgroundColor: rgba(colors.remotePlus),
borderColor: colors.remotePlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.remote.incCount)
}, {
label: 'Remote -',
fill: true,
backgroundColor: rgba(colors.remoteMinus),
borderColor: colors.remoteMinus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(negate(this.stats.drive.remote.decCount))
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('number')(value);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
}
}
}
}];
},
driveFilesTotalChart(): any {
return [{
datasets: [{
label: 'Combined',
fill: false,
borderColor: '#555',
borderWidth: 2,
borderDash: [4, 4],
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
}, {
label: 'Local',
fill: true,
backgroundColor: rgba(colors.local),
borderColor: colors.local,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.local.totalCount)
}, {
label: 'Remote',
fill: true,
backgroundColor: rgba(colors.remote),
borderColor: colors.remote,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.drive.remote.totalCount)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('number')(value);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
}
}
}
}];
},
networkRequestsChart(): any {
return [{
datasets: [{
label: 'Incoming',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.network.incomingRequests)
}]
}];
},
networkTimeChart(): any {
const data = [];
for (let i = 0; i < limit; i++) {
data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0);
}
return [{
datasets: [{
label: 'Avg time (ms)',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(data)
}]
}];
},
networkUsageChart(): any {
return [{
datasets: [{
label: 'Incoming',
fill: true,
backgroundColor: rgba(colors.incoming),
borderColor: colors.incoming,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.network.incomingBytes)
}, {
label: 'Outgoing',
fill: true,
backgroundColor: rgba(colors.outgoing),
borderColor: colors.outgoing,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: this.format(this.stats.network.outgoingBytes)
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('bytes')(value, 1);
}
}
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
}
}
}
}];
},
}
});
</script>
<style lang="stylus" scoped>
.gkgckalzgidaygcxnugepioremxvxvpt
padding 32px
background #fff
box-shadow 0 2px 8px rgba(#000, 0.1)
*
user-select none
> header
display flex
margin 0 0 1em 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
> b
margin-right 8px
> *:last-child
margin-left auto
*
&:not(.active)
color var(--primary)
cursor pointer
> div
> *
display block
height 350px
</style>

View File

@@ -45,7 +45,7 @@
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis" />
</div>
<div class="files" v-if="p.files.length > 0">
<mk-media-list :media-list="p.files" :raw="true"/>

View File

@@ -34,7 +34,7 @@
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">

View File

@@ -23,6 +23,13 @@
<mk-twitter-setting/>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:B github% %i18n:@github%</div>
<section>
<mk-github-setting/>
</section>
</ui-card>
</div>
<ui-card class="theme" v-show="page == 'theme'">
@@ -214,7 +221,7 @@
<ui-card class="password" v-show="page == 'security'">
<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
<section>
<x-password/>
<mk-password-settings/>
</section>
</ui-card>
@@ -286,17 +293,15 @@
<script lang="ts">
import Vue from 'vue';
import XPassword from './settings.password.vue';
import X2fa from './settings.2fa.vue';
import XApps from './settings.apps.vue';
import XSignins from './settings.signins.vue';
import XTags from './settings.tags.vue';
import { url, langs, version } from '../../../config';
import { url, langs, clientVersion as version } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
export default Vue.extend({
components: {
XPassword,
X2fa,
XApps,
XSignins,

View File

@@ -4,7 +4,7 @@
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :customEmojis="note.emojis"/>
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
</div>
<details v-if="note.files.length > 0">

View File

@@ -31,7 +31,7 @@
<p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p>
</li>
<li v-if="$store.state.i.isAdmin">
<router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link>
<a href="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</a>
</li>
</ul>
<ul>

View File

@@ -1,52 +0,0 @@
<template>
<div class="qldxjjsrseehkusjuoooapmsprvfrxyl mk-admin-card">
<header>%i18n:@announcements%</header>
<textarea v-model="broadcasts" placeholder='[ { "title": "Title1", "text": "Text1" }, { "title": "Title2", "text": "Text2" } ]'></textarea>
<button class="ui" @click="save">%i18n:@save%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
data() {
return {
broadcasts: '',
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.broadcasts = JSON.stringify(meta.broadcasts, null, ' ');
});
},
methods: {
save() {
let json;
try {
json = JSON.parse(this.broadcasts);
} catch (e) {
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
return;
}
(this as any).api('admin/update-meta', {
broadcasts: json
}).then(() => {
(this as any).os.apis.dialog({ text: `Saved` });
}.catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>
<style lang="stylus" scoped>
.qldxjjsrseehkusjuoooapmsprvfrxyl
textarea
width 100%
min-height 300px
</style>

View File

@@ -1,137 +0,0 @@
<template>
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<defs>
<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
</linearGradient>
<mask :id="cpuMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
<polygon
:points="cpuPolygonPoints"
fill="#fff"
fill-opacity="0.5"/>
<polyline
:points="cpuPolylinePoints"
fill="none"
stroke="#fff"
stroke-width="1"/>
</mask>
</defs>
<rect
x="0" y="0"
:width="viewBoxX" :height="viewBoxY"
:style="`stroke: none; fill: url(#${ cpuGradientId }); mask: url(#${ cpuMaskId })`"/>
<text x="1" y="12">CPU <tspan>{{ cpuP }}%</tspan></text>
</svg>
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
<defs>
<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
</linearGradient>
<mask :id="memMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
<polygon
:points="memPolygonPoints"
fill="#fff"
fill-opacity="0.5"/>
<polyline
:points="memPolylinePoints"
fill="none"
stroke="#fff"
stroke-width="1"/>
</mask>
</defs>
<rect
x="0" y="0"
:width="viewBoxX" :height="viewBoxY"
:style="`stroke: none; fill: url(#${ memGradientId }); mask: url(#${ memMaskId })`"/>
<text x="1" y="12">MEM <tspan>{{ memP }}%</tspan></text>
</svg>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
export default Vue.extend({
props: ['connection'],
data() {
return {
viewBoxX: 200,
viewBoxY: 70,
stats: [],
cpuGradientId: uuid(),
cpuMaskId: uuid(),
memGradientId: uuid(),
memMaskId: uuid(),
cpuPolylinePoints: '',
memPolylinePoints: '',
cpuPolygonPoints: '',
memPolygonPoints: '',
cpuP: '',
memP: ''
};
},
mounted() {
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8),
length: 200
});
},
beforeDestroy() {
this.connection.off('stats', this.onStats);
this.connection.off('statsLog', this.onStatsLog);
},
methods: {
onStats(stats) {
this.stats.push(stats);
if (this.stats.length > 200) this.stats.shift();
const cpuPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - s.cpu_usage) * this.viewBoxY]);
const memPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - (s.mem.used / s.mem.total)) * this.viewBoxY]);
this.cpuPolylinePoints = cpuPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
this.memPolylinePoints = memPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.cpuPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.memPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
},
onStatsLog(statsLog) {
statsLog.reverse().forEach(stats => this.onStats(stats));
}
}
});
</script>
<style lang="stylus" scoped>
.zyknedwtlthezamcjlolyusmipqmjgxz
> svg
display block
width 50%
float left
&:first-child
padding-right 5px
&:last-child
padding-left 5px
> text
font-size 10px
fill var(--chartCaption)
> tspan
opacity 0.5
&:after
content ""
display block
clear both
</style>

View File

@@ -1,135 +0,0 @@
<template>
<div class="obdskegsannmntldydackcpzezagxqfy mk-admin-card">
<header>%i18n:@dashboard%</header>
<div v-if="stats" class="stats">
<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div>
<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div>
<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div>
<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div>
</div>
<div class="cpu-memory">
<x-cpu-memory :connection="connection"/>
</div>
<div v-if="this.$store.state.i && this.$store.state.i.isAdmin" class="form">
<div>
<label>
<p>%i18n:@banner-url%</p>
<input v-model="bannerUrl">
</label>
<button class="ui" @click="updateMeta">%i18n:@save%</button>
</div>
<div>
<label>
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
<span>%i18n:@disableRegistration%</span>
</label>
<button class="ui" @click="invite">%i18n:@invite%</button>
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
</div>
<div>
<label>
<input type="checkbox" v-model="disableLocalTimeline" @change="updateMeta">
<span>%i18n:@disableLocalTimeline%</span>
</label>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import XCpuMemory from "./admin.cpu-memory.vue";
export default Vue.extend({
components: {
XCpuMemory
},
data() {
return {
stats: null,
disableRegistration: false,
disableLocalTimeline: false,
bannerUrl: null,
inviteCode: null,
connection: null
};
},
created() {
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
(this as any).os.getMeta().then(meta => {
this.disableRegistration = meta.disableRegistration;
this.disableLocalTimeline = meta.disableLocalTimeline;
this.bannerUrl = meta.bannerUrl;
});
(this as any).api('stats').then(stats => {
this.stats = stats;
});
},
beforeDestroy() {
this.connection.dispose();
},
methods: {
invite() {
(this as any).api('admin/invite').then(x => {
this.inviteCode = x.code;
}).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
},
updateMeta() {
(this as any).api('admin/update-meta', {
disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline,
bannerUrl: this.bannerUrl
}).then(() => {
(this as any).os.apis.dialog({ text: `Saved` });
}).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>
<style lang="stylus" scoped>
.obdskegsannmntldydackcpzezagxqfy
> .stats
display flex
justify-content center
margin-bottom 16px
padding 16px
border solid 1px #eee
border-radius 8px
> div
flex 1
text-align center
> *:first-child
display block
color var(--primary)
> *:last-child
font-size 70%
> .cpu-memory
margin-bottom 16px
padding 16px
border solid 1px #eee
border-radius: 8px
> .form
> div
padding 16px
border-bottom solid 1px #eee
</style>

View File

@@ -1,57 +0,0 @@
<template>
<div class="mk-admin-card">
<header>%i18n:@suspend-user%</header>
<input v-model="username" type="text" class="ui"/>
<button class="ui" @click="suspendUser" :disabled="suspending">%i18n:@suspend%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import parseAcct from "../../../../../../misc/acct/parse";
export default Vue.extend({
data() {
return {
username: null,
suspending: false
};
},
methods: {
async suspendUser() {
this.suspending = true;
const process = async () => {
const user = await (this as any).os.api(
"users/show",
parseAcct(this.username)
);
await (this as any).os.api("admin/suspend-user", {
userId: user.id
});
(this as any).os.apis.dialog({ text: "%i18n:@suspended%" });
};
await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.suspending = false;
}
}
});
</script>
<style lang="stylus" scoped>
header
margin 10px 0
button
margin 16px 0
</style>

View File

@@ -1,58 +0,0 @@
<template>
<div class="mk-admin-card">
<header>%i18n:@unsuspend-user%</header>
<input v-model="username" type="text" class="ui"/>
<button class="ui" @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import parseAcct from "../../../../../../misc/acct/parse";
export default Vue.extend({
data() {
return {
username: null,
unsuspending: false
};
},
methods: {
async unsuspendUser() {
this.unsuspending = true;
const process = async () => {
const user = await (this as any).os.api(
"users/show",
parseAcct(this.username)
);
await (this as any).os.api("admin/unsuspend-user", {
userId: user.id
});
(this as any).os.apis.dialog({ text: "%i18n:@unsuspended%" });
};
await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.unsuspending = false;
}
}
});
</script>
<style lang="stylus" scoped>
header
margin 10px 0
button
margin 16px 0
</style>

View File

@@ -1,57 +0,0 @@
<template>
<div class="mk-admin-card">
<header>%i18n:@unverify-user%</header>
<input v-model="username" type="text" class="ui"/>
<button class="ui" @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import parseAcct from "../../../../../../misc/acct/parse";
export default Vue.extend({
data() {
return {
username: null,
unverifying: false
};
},
methods: {
async unverifyUser() {
this.unverifying = true;
const process = async () => {
const user = await (this as any).os.api(
"users/show",
parseAcct(this.username)
);
await (this as any).os.api("admin/unverify-user", {
userId: user.id
});
(this as any).os.apis.dialog({ text: "%i18n:@unverified%" });
};
await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.unverifying = false;
}
}
});
</script>
<style lang="stylus" scoped>
header
margin 10px 0
button
margin 16px 0
</style>

View File

@@ -1,57 +0,0 @@
<template>
<div class="mk-admin-card">
<header>%i18n:@verify-user%</header>
<input v-model="username" type="text" class="ui"/>
<button class="ui" @click="verifyUser" :disabled="verifying">%i18n:@verify%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import parseAcct from "../../../../../../misc/acct/parse";
export default Vue.extend({
data() {
return {
username: null,
verifying: false
};
},
methods: {
async verifyUser() {
this.verifying = true;
const process = async () => {
const user = await (this as any).os.api(
"users/show",
parseAcct(this.username)
);
await (this as any).os.api("admin/verify-user", {
userId: user.id
});
(this as any).os.apis.dialog({ text: "%i18n:@verified%" });
};
await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
});
this.verifying = false;
}
}
});
</script>
<style lang="stylus" scoped>
header
margin 10px 0
button
margin 16px 0
</style>

View File

@@ -1,140 +0,0 @@
<template>
<div class="mk-admin">
<nav>
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
@click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
@click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
@click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
</ul>
</nav>
<main>
<div v-show="page == 'dashboard'">
<x-dashboard/>
<x-charts/>
</div>
<div v-show="page == 'announcements'">
<x-announcements/>
</div>
<div v-show="page == 'hashtags'">
<x-hashtags/>
</div>
<div v-if="page == 'users'">
<x-suspend-user/>
<x-unsuspend-user/>
<x-verify-user/>
<x-unverify-user/>
</div>
<div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div>
</main>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import XDashboard from "./admin.dashboard.vue";
import XAnnouncements from "./admin.announcements.vue";
import XHashtags from "./admin.hashtags.vue";
import XSuspendUser from "./admin.suspend-user.vue";
import XUnsuspendUser from "./admin.unsuspend-user.vue";
import XVerifyUser from "./admin.verify-user.vue";
import XUnverifyUser from "./admin.unverify-user.vue";
import XCharts from "../../components/charts.vue";
export default Vue.extend({
components: {
XDashboard,
XAnnouncements,
XHashtags,
XSuspendUser,
XUnsuspendUser,
XVerifyUser,
XUnverifyUser,
XCharts
},
data() {
return {
page: 'dashboard'
};
},
methods: {
nav(page: string) {
this.page = page;
}
}
});
</script>
<style lang="stylus">
.mk-admin
display flex
height 100%
margin 32px
> nav
flex 0 0 250px
width 100%
height 100%
padding 16px 0 0 0
overflow auto
border-right solid 1px #ddd
> ul
list-style none
> li
display block
padding 10px 16px
margin 0
color #666
cursor pointer
user-select none
transition margin-left 0.2s ease
> [data-fa]
margin-right 4px
&:hover
color #555
&.active
margin-left 8px
color var(--primary) !important
> main
width 100%
padding 16px 32px
> div
> div
max-width 800px
.mk-admin-card
padding 32px
background #fff
box-shadow 0 2px 8px rgba(#000, 0.1)
&:not(:last-child)
margin-bottom 16px
> header
margin 0 0 1em 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }"
@dragenter.prevent.stop="onDragenter"
@dragover.prevent.stop="onDragover"
@dragleave="onDragleave"
@drop.prevent.stop="onDrop"
v-hotkey="keymap">
@@ -269,7 +269,7 @@ export default Vue.extend({
this.dragging = false;
},
onDragenter(e) {
onDragover(e) {
// テンポラリカラムにはドロップさせない
if (this.isTemporaryColumn) {
e.dataTransfer.dropEffect = 'none';

View File

@@ -1,65 +0,0 @@
<template>
<div class="tcrwdhwpuxrwmcttxjcsehgpagpstqey">
<div v-if="stats" class="stats">
<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div>
<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div>
<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div>
<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div>
</div>
<div>
<x-charts/>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import XCharts from "../../components/charts.vue";
export default Vue.extend({
components: {
XCharts
},
data() {
return {
stats: null
};
},
created() {
(this as any).api('stats').then(stats => {
this.stats = stats;
});
},
});
</script>
<style lang="stylus">
.tcrwdhwpuxrwmcttxjcsehgpagpstqey
width 100%
padding 16px
> .stats
display flex
justify-content center
margin 0 auto 16px auto
padding 32px
background #fff
box-shadow 0 2px 8px rgba(#000, 0.1)
> div
flex 1
text-align center
> *:first-child
display block
color var(--primary)
> *:last-child
font-size 70%
> div
max-width 950px
margin 0 auto
</style>

View File

@@ -0,0 +1,26 @@
<template>
<div class="aqooishiizumijmihokohinatamihoaz">
<span>%fa:B github%<a :href="`https://github.com/${user.github.login}`" target="_blank">@{{ user.github.login }}</a></span>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['user']
});
</script>
<style lang="stylus" scoped>
.aqooishiizumijmihokohinatamihoaz
padding 32px
background #171515
border-radius 6px
color #fff
a
margin-left 8px
color #fff
</style>

View File

@@ -2,7 +2,7 @@
<mk-ui>
<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching">
<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></div>
<div class="is-remote" v-if="user.host">%fa:exclamation-triangle% %i18n:common.is-remote-user%<a :href="user.url || user.uri" target="_blank">%i18n:common.view-on-remote%</a></div>
<main>
<div class="main">
<x-header :user="user"/>
@@ -12,14 +12,15 @@
<div class="side">
<div class="instance" v-if="!$store.getters.isSignedIn"><mk-instance/></div>
<x-profile :user="user"/>
<x-twitter :user="user" v-if="user.host === null && user.twitter"/>
<x-twitter :user="user" v-if="!user.host && user.twitter"/>
<x-github :user="user" v-if="!user.host && user.github"/>
<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
<mk-activity :user="user"/>
<x-photos :user="user"/>
<x-friends :user="user"/>
<x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
<div class="nav"><mk-nav/></div>
<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
<p v-if="!user.host">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
</div>
</main>
</div>
@@ -37,6 +38,7 @@ import XPhotos from './user.photos.vue';
import XFollowersYouKnow from './user.followers-you-know.vue';
import XFriends from './user.friends.vue';
import XTwitter from './user.twitter.vue';
import XGithub from './user.github.vue'; // ?MEM: Don't fix the intentional typo. (XGitHub -> `<x-git-hub>`)
export default Vue.extend({
components: {
@@ -46,7 +48,8 @@ export default Vue.extend({
XPhotos,
XFollowersYouKnow,
XFriends,
XTwitter
XTwitter,
XGithub // ?MEM: Don't fix the intentional typo. (see L41)
},
data() {
return {

View File

@@ -14,7 +14,7 @@ import VueHotkey from './common/hotkey';
import App from './app.vue';
import checkForUpdate from './common/scripts/check-for-update';
import MiOS, { API } from './mios';
import { version, codename, lang } from './config';
import { clientVersion as version, codename, lang } from './config';
import { builtinThemes, lightTheme, applyTheme } from './theme';
if (localStorage.getItem('theme') == null) {

View File

@@ -4,7 +4,7 @@ import { EventEmitter } from 'eventemitter3';
import * as uuid from 'uuid';
import initStore from './store';
import { apiUrl, version, lang } from './config';
import { apiUrl, clientVersion as version, lang } from './config';
import Progress from './common/scripts/loading';
import Err from './common/views/components/connect-failed.vue';
@@ -510,6 +510,14 @@ export default class MiOS extends EventEmitter {
return promise;
}
/**
* Misskeyのメタ情報を取得します
*/
@autobind
public getMetaSync() {
return this.meta ? this.meta.data : null;
}
/**
* Misskeyのメタ情報を取得します
* @param force キャッシュを無視するか否か
@@ -529,7 +537,9 @@ export default class MiOS extends EventEmitter {
// forceが有効, meta情報を保持していない or 期限切れ
if (force || this.meta == null || Date.now() - this.meta.chachedAt.getTime() > expire) {
this.isMetaFetching = true;
const meta = await this.api('meta');
const meta = await this.api('meta', {
detail: false
});
this.meta = {
data: meta,
chachedAt: new Date()

View File

@@ -1,23 +1,13 @@
<template>
<div class="mk-activity">
<svg v-if="data" ref="canvas" viewBox="0 0 30 1" preserveAspectRatio="none">
<g v-for="(d, i) in data">
<rect width="0.8" :height="d.notesH"
:x="i + 0.1" :y="1 - d.notesH - d.repliesH - d.renotesH"
fill="#41ddde"/>
<rect width="0.8" :height="d.repliesH"
:x="i + 0.1" :y="1 - d.repliesH - d.renotesH"
fill="#f7796c"/>
<rect width="0.8" :height="d.renotesH"
:x="i + 0.1" :y="1 - d.renotesH"
fill="#a1de41"/>
</g>
</svg>
<div ref="chart"></div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as ApexCharts from 'apexcharts';
export default Vue.extend({
props: ['user'],
data() {
@@ -28,19 +18,84 @@ export default Vue.extend({
};
},
mounted() {
(this as any).api('aggregation/users/activity', {
(this as any).api('charts/user/notes', {
userId: this.user.id,
limit: 30
}).then(data => {
data.forEach(d => d.total = d.notes + d.replies + d.renotes);
this.peak = Math.max.apply(null, data.map(d => d.total));
data.forEach(d => {
d.notesH = d.notes / this.peak;
d.repliesH = d.replies / this.peak;
d.renotesH = d.renotes / this.peak;
span: 'day',
limit: 21
}).then(stats => {
const normal = [];
const reply = [];
const renote = [];
const now = new Date();
const y = now.getFullYear();
const m = now.getMonth();
const d = now.getDate();
for (let i = 0; i < 21; i++) {
const x = new Date(y, m, d - i);
normal.push([
x,
stats.diffs.normal[i]
]);
reply.push([
x,
stats.diffs.reply[i]
]);
renote.push([
x,
stats.diffs.renote[i]
]);
}
const chart = new ApexCharts(this.$refs.chart, {
chart: {
type: 'bar',
stacked: true,
height: 100,
sparkline: {
enabled: true
},
},
plotOptions: {
bar: {
columnWidth: '90%',
endingShape: 'rounded'
}
},
grid: {
clipMarkers: false,
padding: {
top: 0,
right: 8,
bottom: 0,
left: 8
}
},
tooltip: {
shared: true,
intersect: false
},
series: [{
name: 'Normal',
data: normal
}, {
name: 'Reply',
data: reply
}, {
name: 'Renote',
data: renote
}],
xaxis: {
type: 'datetime',
crosshairs: {
width: 1,
opacity: 1
}
}
});
data.reverse();
this.data = data;
chart.render();
});
}
});
@@ -51,12 +106,4 @@ export default Vue.extend({
max-width 600px
margin 0 auto
> svg
display block
width 100%
height 80px
> rect
transform-origin center
</style>

View File

@@ -43,7 +43,7 @@
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis"/>
</div>
<div class="files" v-if="p.files.length > 0">
<mk-media-list :media-list="p.files" :raw="true"/>

View File

@@ -30,7 +30,7 @@
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">

View File

@@ -4,7 +4,7 @@
<span v-if="note.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :customEmojis="note.emojis"/>
<a class="rp" v-if="note.renoteId">RN: ...</a>
</div>
<details v-if="note.files.length > 0">

View File

@@ -30,7 +30,7 @@
<ul>
<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
<li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link></li>
<li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><a href="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</a></li>
<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
</ul>
</div>

View File

@@ -125,8 +125,28 @@
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:B github% %i18n:@github%</div>
<section>
<p class="account" v-if="$store.state.i.github"><a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p>
<a :href="`${apiUrl}/connect/github`" target="_blank">{{ $store.state.i.github ? '%i18n:@github-reconnect%' : '%i18n:@github-connect%' }}</a>
<span v-if="$store.state.i.github"> or </span>
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github">%i18n:@github-disconnect%</a>
</p>
</section>
</ui-card>
<mk-api-settings />
<ui-card>
<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
<section>
<mk-password-settings/>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:sync-alt% %i18n:@update%</div>
@@ -154,7 +174,7 @@
<script lang="ts">
import Vue from 'vue';
import { apiUrl, version, codename, langs } from '../../../config';
import { apiUrl, clientVersion as version, codename, langs } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
export default Vue.extend({

View File

@@ -215,5 +215,11 @@
reversiGameEmptyCell: ':lighten<2<$secondary',
reversiGameEmptyCellMyTurn: ':lighten<5<$secondary',
reversiGameEmptyCellCanPut: ':lighten<4<$secondary',
adminDashboardHeaderFg: ':alpha<0.9<$text',
adminDashboardHeaderBorder: 'rgba(0, 0, 0, 0.3)',
adminDashboardCardBg: '$secondary',
adminDashboardCardFg: '$text',
adminDashboardCardDivider: 'rgba(0, 0, 0, 0.3)',
},
}

View File

@@ -215,5 +215,11 @@
reversiGameEmptyCell: 'rgba(0, 0, 0, 0.06)',
reversiGameEmptyCellMyTurn: 'rgba(0, 0, 0, 0.12)',
reversiGameEmptyCellCanPut: 'rgba(0, 0, 0, 0.9)',
adminDashboardHeaderFg: ':alpha<0.9<$text',
adminDashboardHeaderBorder: 'rgba(0, 0, 0, 0.1)',
adminDashboardCardBg: '$secondary',
adminDashboardCardFg: '$text',
adminDashboardCardDivider: 'rgba(0, 0, 0, 0.082)',
},
}

View File

@@ -51,8 +51,6 @@ export default function load() {
if (config.maxNoteTextLength == null) config.maxNoteTextLength = 1000;
if (config.name == null) config.name = 'Misskey';
return Object.assign(config, mixin);
}

View File

@@ -18,8 +18,6 @@ export type Source = {
repository_url?: string;
feedback_url?: string;
};
name?: string;
description?: string;
languages?: string[];
welcome_bg_url?: string;
url: string;
@@ -74,6 +72,10 @@ export type Source = {
consumer_key: string;
consumer_secret: string;
};
github?: {
client_id: string;
client_secret: string;
};
github_bot?: {
hook_secret: string;
username: string;

View File

@@ -3,9 +3,9 @@
*/
export type TextElementBig = {
type: 'big'
content: string
big: string
type: 'big';
content: string;
big: string;
};
export default function(text: string) {

View File

@@ -3,9 +3,9 @@
*/
export type TextElementBold = {
type: 'bold'
content: string
bold: string
type: 'bold';
content: string;
bold: string;
};
export default function(text: string) {

View File

@@ -5,10 +5,10 @@
import genHtml from '../core/syntax-highlighter';
export type TextElementCode = {
type: 'code'
content: string
code: string
html: string
type: 'code';
content: string;
code: string;
html: string;
};
export default function(text: string) {

View File

@@ -3,13 +3,13 @@
*/
export type TextElementEmoji = {
type: 'emoji'
content: string
emoji: string
type: 'emoji';
content: string;
emoji: string;
};
export default function(text: string) {
const match = text.match(/^:([a-zA-Z0-9+-_]+):/);
const match = text.match(/^:([a-zA-Z0-9+_-]+):/);
if (!match) return null;
const emoji = match[0];
return {

View File

@@ -3,15 +3,15 @@
*/
export type TextElementHashtag = {
type: 'hashtag'
content: string
hashtag: string
type: 'hashtag';
content: string;
hashtag: string;
};
export default function(text: string, i: number) {
if (!(/^\s#[^\s\.,!\?]+/.test(text) || (i == 0 && /^#[^\s\.,!\?]+/.test(text)))) return null;
export default function(text: string, isBegin: boolean) {
if (!(/^\s#[^\s\.,!\?#]+/.test(text) || (isBegin && /^#[^\s\.,!\?#]+/.test(text)))) return null;
const isHead = text.startsWith('#');
const hashtag = text.match(/^\s?#[^\s\.,!\?]+/)[0];
const hashtag = text.match(/^\s?#[^\s\.,!\?#]+/)[0];
const res: any[] = !isHead ? [{
type: 'text',
content: text[0]

View File

@@ -5,10 +5,10 @@
import genHtml from '../core/syntax-highlighter';
export type TextElementInlineCode = {
type: 'inline-code'
content: string
code: string
html: string
type: 'inline-code';
content: string;
code: string;
html: string;
};
export default function(text: string) {

View File

@@ -3,11 +3,11 @@
*/
export type TextElementLink = {
type: 'link'
content: string
title: string
url: string
silent: boolean
type: 'link';
content: string;
title: string;
url: string;
silent: boolean;
};
export default function(text: string) {

View File

@@ -5,11 +5,11 @@ import parseAcct from '../../../misc/acct/parse';
import { toUnicode } from 'punycode';
export type TextElementMention = {
type: 'mention'
content: string
canonical: string
username: string
host: string
type: 'mention';
content: string;
canonical: string;
username: string;
host: string;
};
export default function(text: string) {

View File

@@ -3,9 +3,9 @@
*/
export type TextElementMotion = {
type: 'motion'
content: string
motion: string
type: 'motion';
content: string;
motion: string;
};
export default function(text: string) {

View File

@@ -3,14 +3,14 @@
*/
export type TextElementQuote = {
type: 'quote'
content: string
quote: string
type: 'quote';
content: string;
quote: string;
};
export default function(text: string, index: number) {
export default function(text: string, isBegin: boolean) {
const match = text.match(/^"([\s\S]+?)\n"/) || text.match(/^\n>([\s\S]+?)(\n\n|$)/) ||
(index == 0 ? text.match(/^>([\s\S]+?)(\n\n|$)/) : null);
(isBegin ? text.match(/^>([\s\S]+?)(\n\n|$)/) : null);
if (!match) return null;

View File

@@ -3,9 +3,9 @@
*/
export type TextElementSearch = {
type: 'search'
content: string
query: string
type: 'search';
content: string;
query: string;
};
export default function(text: string) {

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