Compare commits

..

183 Commits

Author SHA1 Message Date
syuilo
35273e53bc 10.67.0 2018-12-27 07:49:48 +09:00
syuilo
bfc458e935 Resolve #3758 2018-12-27 07:07:26 +09:00
dependabot[bot]
bb819d42f1 Update mongodb requirement from 3.1.9 to 3.1.10 (#3762)
Updates the requirements on [mongodb](https://github.com/mongodb/node-mongodb-native) to permit the latest version.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/master/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/commits/v3.1.10)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-27 05:46:42 +09:00
dependabot[bot]
5d76439224 Update sharp requirement from 0.21.0 to 0.21.1 (#3761)
Updates the requirements on [sharp](https://github.com/lovell/sharp) to permit the latest version.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Changelog](https://github.com/lovell/sharp/blob/master/docs/changelog.md)
- [Commits](https://github.com/lovell/sharp/commits/v0.21.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-27 05:46:00 +09:00
ibrokemypie
3d0b704af8 Add URI parameter to /api/meta (#3748)
* Add URI parameter to /api/meta
closes #3747

* Update fetch-meta.ts

* Update meta.ts
2018-12-27 04:50:35 +09:00
Acid Chicken (硫酸鶏)
05539ffc7b Update README.md [AUTOGEN] (#3743) 2018-12-27 01:33:19 +09:00
Aya Morisawa
c86deab69c Introduce SonarTS (#3756) 2018-12-27 01:32:31 +09:00
Aya Morisawa
21f8dbf2de Resolve #3248
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
2018-12-27 01:26:03 +09:00
MeiMei
5174e16f7b Feature to show only my posts in the user page (#3753)
* Fix #3681

* Feature to show only my posts in the user page
2018-12-26 23:11:50 +09:00
Aya Morisawa
9b746f3eb5 Make reactions removable
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>

Resolve #367, resolve #2260, close #3503
2018-12-26 23:05:47 +09:00
Aya Morisawa
dfc6ef4be6 Remove trailing whitespaces 2018-12-26 19:58:04 +09:00
Aya Morisawa
c8b45f4f42 Fix #3346
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
2018-12-26 19:39:51 +09:00
Aya Morisawa
09c57e6d03 Fix #3345
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
2018-12-26 19:24:38 +09:00
dependabot[bot]
5edb1da097 Update gulp-typescript requirement from 4.0.2 to 5.0.0 (#3496)
Updates the requirements on [gulp-typescript](https://github.com/ivogabe/gulp-typescript) to permit the latest version.
- [Release notes](https://github.com/ivogabe/gulp-typescript/releases)
- [Commits](https://github.com/ivogabe/gulp-typescript/commits/v5.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:34:28 +09:00
dependabot[bot]
b3ad3a6535 Update jsdom requirement from 13.0.0 to 13.1.0 (#3649)
Updates the requirements on [jsdom](https://github.com/jsdom/jsdom) to permit the latest version.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/master/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/commits/13.1.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:50 +09:00
dependabot[bot]
3709bb23bc Update systeminformation requirement from 3.51.3 to 3.52.2 (#3669)
Updates the requirements on [systeminformation](https://github.com/sebhildebrandt/systeminformation) to permit the latest version.
- [Release notes](https://github.com/sebhildebrandt/systeminformation/releases)
- [Changelog](https://github.com/sebhildebrandt/systeminformation/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sebhildebrandt/systeminformation/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:42 +09:00
dependabot[bot]
28be5c0b81 Update tslint requirement from 5.10.0 to 5.12.0 (#3670)
Updates the requirements on [tslint](https://github.com/palantir/tslint) to permit the latest version.
- [Release notes](https://github.com/palantir/tslint/releases)
- [Changelog](https://github.com/palantir/tslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/palantir/tslint/commits/5.12.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:34 +09:00
dependabot[bot]
60ef74047a Update @types/file-type requirement from 5.2.2 to 10.6.0 (#3671)
Updates the requirements on [@types/file-type](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:28 +09:00
dependabot[bot]
f81596c8d5 Update @types/webpack requirement from 4.4.20 to 4.4.21 (#3650)
Updates the requirements on [@types/webpack](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:20 +09:00
dependabot[bot]
075b7e3060 Update vue-cropperjs requirement from 2.2.2 to 3.0.0 (#3617)
Updates the requirements on [vue-cropperjs](https://github.com/Agontuk/vue-cropperjs) to permit the latest version.
- [Release notes](https://github.com/Agontuk/vue-cropperjs/releases)
- [Changelog](https://github.com/Agontuk/vue-cropperjs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Agontuk/vue-cropperjs/commits/v3.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:33:08 +09:00
dependabot[bot]
cc7d6198ec Update hard-source-webpack-plugin requirement from 0.12.0 to 0.13.1 (#3611)
Updates the requirements on [hard-source-webpack-plugin](https://github.com/mzgoddard/hard-source-webpack-plugin) to permit the latest version.
- [Release notes](https://github.com/mzgoddard/hard-source-webpack-plugin/releases)
- [Changelog](https://github.com/mzgoddard/hard-source-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mzgoddard/hard-source-webpack-plugin/commits/v0.13.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:32:58 +09:00
dependabot[bot]
5766c2ce1b Update @fortawesome/free-solid-svg-icons requirement from 5.5.0 to 5.6.1 (#3610)
Updates the requirements on [@fortawesome/free-solid-svg-icons](https://github.com/FortAwesome/Font-Awesome) to permit the latest version.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/commits/5.6.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:32:50 +09:00
dependabot[bot]
03fed08c03 Update @fortawesome/free-brands-svg-icons requirement (#3598)
Updates the requirements on [@fortawesome/free-brands-svg-icons](https://github.com/FortAwesome/Font-Awesome) to permit the latest version.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/commits/5.6.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-12-26 18:32:43 +09:00
Acid Chicken (硫酸鶏)
4662641feb Fix #3745 (#3746) 2018-12-26 18:32:16 +09:00
MeiMei
00e2ce9489 Fix #3715 (#3752) 2018-12-26 06:21:09 +09:00
MeiMei
c81eb49f9e Supports emoji in notifications (#3751) 2018-12-26 05:15:02 +09:00
Acid Chicken (硫酸鶏)
fa03c172f2 Fix typo 2018-12-25 20:02:37 +09:00
Acid Chicken (硫酸鶏)
89ac15b4de Fix typo
split は不規則動詞
2018-12-25 16:49:35 +09:00
Acid Chicken (硫酸鶏)
10d3b81251 Fix build fails 2018-12-25 13:39:55 +09:00
syuilo
71dceca225 Merge pull request #3648 from syuilo/l10n_develop
New Crowdin translations
2018-12-25 12:24:26 +09:00
syuilo
40de631d95 New translations ja-JP.yml (English) 2018-12-25 12:22:01 +09:00
ibrokemypie
6985c39874 Make activity view in admin scrollable (#3741)
I can't think of any reason why this isnt currently the case as the extra lines are still there, just not displayed, meaning theres no difference in performance/memory usage
Also means that sometimes entries are cut off which is weird
Also, sometimes there is reason to wish to view older entries that may have scrolled off the page/keep reading something which was pushed too far down.
2018-12-25 12:13:50 +09:00
Aya Morisawa
0938ea3964 Use join instead of reduce 2018-12-24 17:02:15 +09:00
syuilo
4b4c19b242 New translations ja-JP.yml (Korean) 2018-12-24 08:11:46 +09:00
syuilo
d8620187ec 10.66.2 2018-12-24 05:40:33 +09:00
Zero King
520849d070 Update translation placeholder (#3735) 2018-12-24 05:36:02 +09:00
syuilo
b6a028a8ed [API] Fix #3737 2018-12-24 05:31:20 +09:00
syuilo
7db799a0ac New translations ja-JP.yml (Norwegian) 2018-12-24 01:33:08 +09:00
syuilo
1ab776c867 New translations ja-JP.yml (Dutch) 2018-12-24 01:33:04 +09:00
syuilo
f4c9f63548 New translations ja-JP.yml (Japanese, Kansai) 2018-12-24 01:32:57 +09:00
syuilo
08da9d70cd New translations ja-JP.yml (Spanish) 2018-12-24 01:32:53 +09:00
syuilo
96173e5c0b New translations ja-JP.yml (Russian) 2018-12-24 01:32:48 +09:00
syuilo
b37cc70742 New translations ja-JP.yml (Portuguese) 2018-12-24 01:32:43 +09:00
syuilo
96ee4299c7 New translations ja-JP.yml (Polish) 2018-12-24 01:32:38 +09:00
syuilo
6072b02f12 New translations ja-JP.yml (Korean) 2018-12-24 01:32:33 +09:00
syuilo
6ccbca0741 New translations ja-JP.yml (Italian) 2018-12-24 01:32:29 +09:00
syuilo
360394fd5c New translations ja-JP.yml (German) 2018-12-24 01:32:24 +09:00
syuilo
dcb45aa953 New translations ja-JP.yml (French) 2018-12-24 01:32:20 +09:00
syuilo
a8fcc1aad9 New translations ja-JP.yml (English) 2018-12-24 01:32:15 +09:00
syuilo
4d69cd86f1 New translations ja-JP.yml (Chinese Simplified) 2018-12-24 01:32:11 +09:00
syuilo
6e14e58b89 New translations ja-JP.yml (Catalan) 2018-12-24 01:32:06 +09:00
Zero King
af5839bb59 Fix translation location (#3734) 2018-12-24 01:25:28 +09:00
MeiMei
a53e0d9f73 Fix error in featuredNotes (#3730) 2018-12-23 23:23:56 +09:00
MeiMei
49921f2dcf Fix: can not update remote Misskey user (#3731) 2018-12-23 23:23:17 +09:00
syuilo
70d2d61b9a New translations ja-JP.yml (French) 2018-12-23 18:11:51 +09:00
syuilo
9abaf80f6b New translations ja-JP.yml (Chinese Simplified) 2018-12-23 17:51:56 +09:00
syuilo
25948fc3c9 New translations ja-JP.yml (Chinese Simplified) 2018-12-23 17:42:42 +09:00
Zero King
6b947c2139 Fix mention links (#3728)
canonical already starts with @, so remove the extra @.
2018-12-23 14:35:18 +09:00
MeiMei
98acf919f1 ダイレクト投稿でユーザーが指定されていなかったらrejectする (#3724) 2018-12-23 04:17:42 +09:00
MeiMei
c9c2853150 ダイレクトでメンションでもユーザーを指定できるように (#3722) 2018-12-23 03:44:18 +09:00
syuilo
2bc708f8e6 Fix #3717 (#3723) 2018-12-23 03:41:28 +09:00
syuilo
874b8fc3c2 Fix indent 2018-12-23 03:31:11 +09:00
syuilo
7d6aac3431 Fix space 2018-12-23 03:27:26 +09:00
MeiMei
e2fc7decad 本文からメンション等を展開しないオプション (#3721) 2018-12-23 03:25:33 +09:00
Acid Chicken (硫酸鶏)
21bed71f5e Rename PULL_REQUEST_TEMPLATE.md to .github/PULL_REQUEST_TEMPLATE.md 2018-12-22 20:43:44 +09:00
syuilo
747a5694f8 New translations ja-JP.yml (French) 2018-12-22 13:02:00 +09:00
syuilo
479a0a2deb New translations ja-JP.yml (French) 2018-12-22 12:52:26 +09:00
syuilo
14aef6ec89 New translations ja-JP.yml (English) 2018-12-22 01:16:40 +09:00
syuilo
f0d2b3f449 New translations ja-JP.yml (English) 2018-12-22 01:02:28 +09:00
syuilo
3b974428fc 10.66.1 2018-12-22 00:59:40 +09:00
Aya Morisawa
580191fb17 Improve MFM bracket matching
Co-authored-by: syuilo <syuilotan@yahoo.co.jp>
2018-12-22 00:44:38 +09:00
MeiMei
be0cb88b6c Fix sharedInbox location (#3711)
* Fix sharedInbox location

* Perform update Following

* Fix comment
2018-12-22 00:12:34 +09:00
MeiMei
95c4e4497e Fix tag not found (#3710) 2018-12-21 21:46:50 +09:00
syuilo
2ec445f83e 10.66.0 2018-12-21 16:26:46 +09:00
syuilo
51b915428e [Client] Fix #3693 2018-12-21 16:22:34 +09:00
Acid Chicken (硫酸鶏)
1395cf89ce Feed (#3698)
* wip

* Implement feed

* Update feed.ts

* Update index.ts

* Update feed.ts
2018-12-21 11:54:39 +09:00
Aya Morisawa
2a8f984db7 Fix comment 2018-12-21 11:28:30 +09:00
MeiMei
decf2d396f Fix processing icon (#3705) 2018-12-21 02:30:49 +09:00
MeiMei
f7964da899 Fix: ap/show does not return on error (#3704) 2018-12-21 00:09:02 +09:00
MeiMei
c8607ff7b6 Tune polls/recommendation (#3703) 2018-12-20 22:56:12 +09:00
Aya Morisawa
e9f8897fe2 Refactor MFM
Co-authored-by: syuilo syuilotan@yahoo.co.jp
2018-12-20 19:42:10 +09:00
ibrokemypie
e0b107a3a0 Fix overlap of birthday label on datepicker (#3697) 2018-12-20 17:01:29 +09:00
syuilo
abf2c89931 New translations ja-JP.yml (Korean) 2018-12-20 07:51:43 +09:00
syuilo
1d3e6a7197 10.65.0 2018-12-20 04:37:47 +09:00
syuilo
288bf195e9 New translations ja-JP.yml (English) 2018-12-20 04:22:50 +09:00
syuilo
7e3cc11cc4 New translations ja-JP.yml (Norwegian) 2018-12-20 04:13:09 +09:00
syuilo
4e07e94af0 New translations ja-JP.yml (Dutch) 2018-12-20 04:13:03 +09:00
syuilo
9cb49c9204 New translations ja-JP.yml (Japanese, Kansai) 2018-12-20 04:12:59 +09:00
syuilo
580dd729e5 New translations ja-JP.yml (Spanish) 2018-12-20 04:12:54 +09:00
syuilo
49ab77c86e New translations ja-JP.yml (Russian) 2018-12-20 04:12:49 +09:00
syuilo
f98914b9f1 New translations ja-JP.yml (Portuguese) 2018-12-20 04:12:43 +09:00
syuilo
f3f3599b28 New translations ja-JP.yml (Polish) 2018-12-20 04:12:38 +09:00
syuilo
f67b1beee4 New translations ja-JP.yml (Korean) 2018-12-20 04:12:32 +09:00
syuilo
8395d0f1ba New translations ja-JP.yml (Italian) 2018-12-20 04:12:27 +09:00
syuilo
af203bee93 New translations ja-JP.yml (German) 2018-12-20 04:12:23 +09:00
syuilo
760fb79dad New translations ja-JP.yml (French) 2018-12-20 04:12:18 +09:00
syuilo
ee9d4119c2 New translations ja-JP.yml (English) 2018-12-20 04:12:13 +09:00
syuilo
90027efcbf New translations ja-JP.yml (Chinese Simplified) 2018-12-20 04:12:07 +09:00
syuilo
1848de1dc4 New translations ja-JP.yml (Catalan) 2018-12-20 04:11:58 +09:00
syuilo
1c93fcb1c4 Fix #3683 2018-12-20 04:11:10 +09:00
syuilo
e3389e7899 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-12-20 04:08:22 +09:00
syuilo
454632d785 Resolve #3687 2018-12-20 04:08:13 +09:00
syuilo
c9bca7dc85 Update CONTRIBUTING.md 2018-12-20 03:44:19 +09:00
syuilo
710ba526fa Better cw detection 2018-12-20 03:22:27 +09:00
syuilo
aa47b6732d [Doc] Clean up 2018-12-20 03:19:44 +09:00
syuilo
20f83420ca Update CONTRIBUTING.md 2018-12-20 03:02:19 +09:00
syuilo
d09a68ef11 Update CONTRIBUTING.md 2018-12-20 03:01:02 +09:00
syuilo
b545be5799 Fix wrong comment 2018-12-20 02:47:24 +09:00
MeiMei
4fc377584f Fix tag length limit from AP (#3688) 2018-12-20 02:20:56 +09:00
syuilo
a5f09c90dd [Client] Resolve #3686 2018-12-20 01:09:35 +09:00
syuilo
ba407c3eb0 New translations ja-JP.yml (French) 2018-12-20 01:03:08 +09:00
tamaina
d059d7f972 open処理中はopenの処理をしないように (#3661)
* autocomplettimeout

* fix

* fix

* Update autocomplete.ts

* Update autocomplete.ts
2018-12-20 00:02:28 +09:00
MeiMei
c03e2dfbc0 Change naming (#3678)
* Change naming

* x to a
2018-12-19 22:38:27 +09:00
MeiMei
45c5e7b967 Hide hidden contents in welcome timeline (#3682) 2018-12-19 22:18:58 +09:00
Acid Chicken (硫酸鶏)
c81a94ff75 Resolve #3676 (#3677) 2018-12-19 21:20:25 +09:00
MeiMei
acc6f54557 Update remote Emoji (#3680) 2018-12-19 21:19:43 +09:00
Aya Morisawa
8025b121af Add Predicate type 2018-12-19 17:08:09 +09:00
Aya Morisawa
78ec06bda3 Add relation types 2018-12-19 17:00:07 +09:00
syuilo
6ef83d9c59 Update deck.notes.vue 2018-12-19 11:23:46 +09:00
syuilo
fca4ceef21 [Client] デッキのTLにUIの動きを減らすオプションが適用されていなかったのを修正 2018-12-19 11:22:27 +09:00
syuilo
00f979f0e6 Fix bug 2018-12-19 11:16:29 +09:00
Aya Morisawa
556677be7a Refactor 2018-12-19 10:23:57 +09:00
Aya Morisawa
624fd093f2 Fix comment 2018-12-19 10:02:58 +09:00
Aya Morisawa
2ee438dece Add comments for prelude/array.ts 2018-12-19 09:54:45 +09:00
Aya Morisawa
534de24406 Use consistent naming convention 2018-12-19 09:14:05 +09:00
syuilo
014edce1b9 New translations ja-JP.yml (Korean) 2018-12-19 08:52:01 +09:00
syuilo
ac1f3de4c6 New translations ja-JP.yml (Norwegian) 2018-12-19 07:33:01 +09:00
syuilo
dced228cb0 New translations ja-JP.yml (Dutch) 2018-12-19 07:32:55 +09:00
syuilo
a92244cc12 New translations ja-JP.yml (Japanese, Kansai) 2018-12-19 07:32:50 +09:00
syuilo
0717688933 New translations ja-JP.yml (Spanish) 2018-12-19 07:32:43 +09:00
syuilo
87d54b7d40 New translations ja-JP.yml (Russian) 2018-12-19 07:32:36 +09:00
syuilo
ed51f5c7de New translations ja-JP.yml (Portuguese) 2018-12-19 07:32:31 +09:00
syuilo
66e2db0d52 New translations ja-JP.yml (Polish) 2018-12-19 07:32:26 +09:00
syuilo
03be4826df New translations ja-JP.yml (Korean) 2018-12-19 07:32:22 +09:00
syuilo
c9d5aef04f New translations ja-JP.yml (Italian) 2018-12-19 07:32:18 +09:00
syuilo
106cb3fe3e New translations ja-JP.yml (German) 2018-12-19 07:32:12 +09:00
syuilo
48320f8536 New translations ja-JP.yml (French) 2018-12-19 07:32:08 +09:00
syuilo
1a0845dc0a New translations ja-JP.yml (English) 2018-12-19 07:32:04 +09:00
syuilo
185d09f3ed New translations ja-JP.yml (Chinese Simplified) 2018-12-19 07:32:00 +09:00
syuilo
8e25fb6cb7 New translations ja-JP.yml (Catalan) 2018-12-19 07:31:55 +09:00
syuilo
e88ce1746d リスト関連の操作を強化
Resolve #2069
Resolve #2051
Resolve #2807
Resolve #3647
2018-12-19 07:22:01 +09:00
syuilo
b8aad35009 Fix error 2018-12-19 06:47:47 +09:00
syuilo
47bd485a39 Clean up 2018-12-19 06:09:31 +09:00
syuilo
ad869d7469 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-12-19 06:05:47 +09:00
syuilo
d15cce5337 [Client] Show more images 2018-12-19 06:05:44 +09:00
syuilo
37daff6d61 [Client] Fix #2764 2018-12-19 06:04:59 +09:00
MeiMei
5417e40f59 Send original URL for quote (#3668) 2018-12-19 05:07:54 +09:00
Acid Chicken (硫酸鶏)
0fed33bfdb Create PULL_REQUEST_TEMPLATE.md (#3552)
* Create PULL_REQUEST_TEMPLATE.md

* Update PULL_REQUEST_TEMPLATE.md
2018-12-19 04:48:49 +09:00
MeiMei
5dddc75d09 Add AP emojis endpoint (#3667) 2018-12-19 04:23:08 +09:00
syuilo
081578c604 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-12-19 01:11:08 +09:00
syuilo
6c47bf5b76 [Client] Resolve #3662 2018-12-19 01:10:53 +09:00
syuilo
936bb1bcd0 New translations ja-JP.yml (Norwegian) 2018-12-19 01:04:21 +09:00
syuilo
d5241d9a3e New translations ja-JP.yml (Dutch) 2018-12-19 01:04:15 +09:00
syuilo
05b4430c92 New translations ja-JP.yml (Japanese, Kansai) 2018-12-19 01:04:09 +09:00
syuilo
292e911de2 New translations ja-JP.yml (Spanish) 2018-12-19 01:04:04 +09:00
syuilo
1c4ba2c037 New translations ja-JP.yml (Russian) 2018-12-19 01:03:59 +09:00
syuilo
452db13d0c New translations ja-JP.yml (Portuguese) 2018-12-19 01:03:54 +09:00
syuilo
c3f64b395b New translations ja-JP.yml (Polish) 2018-12-19 01:03:49 +09:00
syuilo
3fa6bf93a4 New translations ja-JP.yml (Korean) 2018-12-19 01:03:44 +09:00
syuilo
a13d76bec5 New translations ja-JP.yml (Italian) 2018-12-19 01:03:39 +09:00
syuilo
05cee078d0 New translations ja-JP.yml (German) 2018-12-19 01:03:33 +09:00
syuilo
706d3f3f95 New translations ja-JP.yml (French) 2018-12-19 01:03:27 +09:00
syuilo
c5cf034b5d New translations ja-JP.yml (English) 2018-12-19 01:03:22 +09:00
syuilo
3a04aa93f9 New translations ja-JP.yml (Chinese Simplified) 2018-12-19 01:03:16 +09:00
syuilo
838cdbedbd New translations ja-JP.yml (Catalan) 2018-12-19 01:03:09 +09:00
MeiMei
9e85291cd3 Add example nginx configuration (#3659)
* Sample Nginx configuration

* nginxによせる

* 非Debian系ではsites-enabledがない
2018-12-19 01:00:57 +09:00
syuilo
7f77517fc8 [Client] Resolve #3658 2018-12-19 00:57:28 +09:00
syuilo
b2f288dcac [Client] Fix #3657 2018-12-19 00:45:00 +09:00
syuilo
52b59e9d7b [Client] Fix #3655 2018-12-19 00:41:53 +09:00
syuilo
80c74b1fa7 Improve readability 2018-12-19 00:40:29 +09:00
syuilo
91811ea500 Clean up 2018-12-19 00:40:13 +09:00
syuilo
57150fd910 Improve readability 2018-12-19 00:39:28 +09:00
syuilo
cddbbdf5d0 clean up 2018-12-19 00:39:04 +09:00
syuilo
423dc2349b [Client] Improve performance 2018-12-19 00:25:35 +09:00
syuilo
5229bbd55d New translations ja-JP.yml (Korean) 2018-12-18 07:55:13 +09:00
syuilo
28311b9a2b New translations ja-JP.yml (French) 2018-12-17 23:02:47 +09:00
syuilo
663d17a485 New translations ja-JP.yml (French) 2018-12-17 22:54:39 +09:00
syuilo
08d005dfd9 New translations ja-JP.yml (French) 2018-12-17 22:44:05 +09:00
syuilo
02edbc131b New translations ja-JP.yml (French) 2018-12-17 22:33:42 +09:00
syuilo
0556a2a2da Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-12-17 20:18:09 +09:00
syuilo
65d943e42a Fix #3646 2018-12-17 20:17:21 +09:00
Acid Chicken (硫酸鶏)
3bcb344ecb Re: #3457 (#3614)
* Update parser.ts

* Update user.ts

* Update search.ts

* Update parser.ts

* Update parser.ts

* Update parser.ts

* Update parser.ts

* Update parser.ts

* Update parser.ts

* Update mfm.ts

* Update parser.ts

* Merge branch 'develop' into 3440-mk2

* Fix typo

* Update parser.ts

* Update mfm.ts

* Update mfm.ts
2018-12-17 19:11:38 +09:00
Acid Chicken (硫酸鶏)
82d721d60b Refactor Reversi (#3584)
* Update core.ts

* Update core.ts

* Create functional-syntax.ts

* Update core.ts

* Update functional-syntax.ts

* Update core.ts

* Delete functional-syntax.ts
2018-12-17 19:10:38 +09:00
133 changed files with 2263 additions and 978 deletions

View File

@@ -108,13 +108,5 @@ autoAdmin: true
# port: 9200
# pass: null
# ServiceWorker
#sw:
# # Public key of VAPID
# public_key: example-sw-public-key
#
# # Private key of VAPID
# private_key: example-sw-private-key
# Clustering
#clusterLimit: 1

13
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# Summary
<!--
-
- * Please describe your changes here *
-
- If you are going to resolve some issue, please add this context.
- Resolve #ISSUE_NUMBER
-
- If you are going to fix some bug issue, please add this context.
- Fix #ISSUE_NUMBER
-
-->

View File

@@ -1,6 +1,61 @@
ChangeLog
=========
10.67.0
-------
* トークのメッセージを削除できるように
* リアクションを取り消せるように
* Misskey以外のソフトウェアからの「Like」アクティビティをプリンではなく「いいね」として扱うように
* i18nの修正
* バグ修正
* など
10.66.2
-------
* i18nの修正
* ドライブのファイル一覧取得APIでファイルサイズによるソートが機能していなかった問題を修正
* リモートユーザーの更新時に、各ピン留め投稿の取得失敗は無視するように
* リモートMisskeyユーザーの情報が登録/更新出来なくなっていたのを修正
* メンションのリンク先URLに余計な@がプリフィクスされていたのを修正
* ダイレクトでリプライする際、リプライ先のユーザーは自動的に公開先として追加するように
* ダイレクトでメンションでもユーザーを指定できるように
10.66.1
-------
* ActivityPubのsharedInboxに関して修正
* MFMでのカッコの判定を改善
* バグ修正
10.66.0
-------
* ユーザーごとのRSSフィードを提供するように
* リストのユーザーがすべて表示できない問題を修正
* デザインの調整
* パフォーマンスの改善
10.65.0
-------
* 検索で投稿やユーザーのURLを入力した際にそれをフェッチして表示するように
* リストのリネームと削除をできるように
* リストからユーザーを削除できるように
* リモートの絵文字を更新するように
* ActivityPubのための絵文字エンドポイントを実装
* 管理者がドライブのファイルのNSFWを設定できるように
* ServiceWorkerの設定を管理者ページで行えるように
* メンションの判定を改善
* リモートの投稿を引用した際にオリジナルのURLを挿入するように
* クライアントのパフォーマンス改善
* CWの内容がタブタイトルに表示されるのを修正
* アカウントを作成したときにログイン状態にならない問題を修正
* 時計の針にテーマカラーが適用されていなかったのを修正
* 一部の日時の表示が日本語で表示されていたのを修正
* プロフィールの写真欄に画像以外のファイルが含まれる問題を修正
* メンションが含まれる投稿に返信する際、フォームに予めそれらのメンションがセットされた状態にならない問題を修正
* デッキのTLにUIの動きを減らすオプションが適用されていなかったのを修正
* ログイン画面のタイムラインに隠した投稿が表示される問題を修正
* サジェストが複数開いてしまう問題を修正
* APから来たタグに登録時の長さ制限が適用されていなかったのを修正
10.64.2
-------
* UIの動きを減らすオプションが一部のアニメーションに適用されなかったのを修正

View File

@@ -25,3 +25,16 @@ Misskey uses [vue-i18n](https://github.com/kazupon/vue-i18n).
## Continuous integration
Misskey uses CircleCI for automated test.
Configuration files are located in `/.circleci`.
## Glossary
### AP
Stands for _**A**ctivity**P**ub_.
### MFM
Stands for _**M**isskey **F**lavored **M**arkdown_.
### Mk
Stands for _**M**iss**k**ey_.
### SW
Stands for _**S**ervice**W**orker_.

View File

@@ -80,7 +80,6 @@ Please see [Contribution guide](./CONTRIBUTING.md).
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/3?token-time=2145916800&token-hash=ybYtxfpte1b-rGg6Zecpys2ZdZDtwR_UNJHQjt-3eoU%3D" alt="Xeltica"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=I8lJVM8LeW6TSo5W6uIIRZ42cw83zp1wK_FsbzY0mcQ%3D" alt="mydarkstar"></td>
</tr><tr>
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
<td><a href="https://www.patreon.com/user?u=13376668">Arctic</a></td>
@@ -89,36 +88,37 @@ Please see [Contribution guide](./CONTRIBUTING.md).
<td><a href="https://www.patreon.com/Xeltica">Xeltica</a></td>
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td>
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=I8lJVM8LeW6TSo5W6uIIRZ42cw83zp1wK_FsbzY0mcQ%3D" alt="mydarkstar"></td>
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
<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/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>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
</tr><tr>
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</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>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=tB1e_r8RlZ5sFL0KV_e8dugapxatNBRK1Z3h67TO1g8%3D" alt="Gargron"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=VZUtwrjQa8Jml4twCjHYQQZ64wHEY4oIlGl7Kc-VYUQ%3D" alt="Nokotaro Takeda"></td>
<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/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
**Last updated:** Sun, 16 Dec 2018 18:32:06 UTC
**Last updated:** Tue, 25 Dec 2018 04:58:06 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@@ -0,0 +1,70 @@
# Sample nginx configuration for Misskey
#
# 1. Replace example.tld to your domain
# 2. Copy to /etc/nginx/sites-available/ and then symlink from /etc/nginx/sites-ebabled/
# or copy to /etc/nginx/conf.d/
# For WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
server {
listen 80;
listen [::]:80;
server_name example.tld;
# For SSL domain validation
root /var/www/html;
location /.well-known/acme-challenge/ { allow all; }
location /.well-known/pki-validation/ { allow all; }
location / { return 301 https://$server_name$request_uri; }
}
server {
listen 443 http2;
listen [::]:443 http2;
server_name example.tld;
ssl on;
ssl_session_cache shared:ssl_session_cache:10m;
# To use Let's Encrypt certificate
ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
# To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
#ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# SSL protocol settings
ssl_protocols TLSv1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES128-SHA;
ssl_prefer_server_ciphers on;
# Change to your upload limit
client_max_body_size 80m;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_redirect off;
# For WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Cache settings
proxy_cache cache1;
proxy_cache_lock on;
proxy_cache_use_stale updating;
add_header X-Cache $upstream_cache_status;
}
}

View File

@@ -47,16 +47,6 @@ As root:
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Install misskey dependencies.
*(optional)* Generate VAPID keys
----------------------------------------------------------------
If you want to enable ServiceWorker, you need to generate VAPID keys:
Unless you have set your global node_modules location elsewhere, you need to run this as root.
``` shell
npm install web-push -g
web-push generate-vapid-keys
```
*5.* Configure Misskey
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.

View File

@@ -47,16 +47,6 @@ En mode root :
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Télécharge la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Installez les dépendances de misskey.
*(optionnel)* Génération des clés VAPID
----------------------------------------------------------------
Si vous désirez activer ServiceWorker, vous devez générer les clés VAPID :
Unless you have set your global node_modules location elsewhere, vous devez lancer ceci en mode root.
``` shell
npm install web-push -g
web-push generate-vapid-keys
```
*5.* Création du fichier de configuration
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le `default.yml`.

View File

@@ -53,15 +53,6 @@ adduser --disabled-password --disabled-login misskey
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
5. `npm install` Misskeyの依存パッケージをインストール
*(オプション)* VAPIDキーペアの生成
----------------------------------------------------------------
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:
``` shell
npm install web-push -g
web-push generate-vapid-keys
```
*5.* 設定ファイルを作成する
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動作"
fetch-on-scroll: "スクロールで自動読み込み"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "Laden"
no-broadcasts: "Keine Broadcasts"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Zwei-Faktor-Authentifizierung"
other: "Anderes"
license: "Lizenz"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "Verhalten"
fetch-on-scroll: "Aktualisieren beim scrollen"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -8,7 +8,7 @@ common:
about: "Thank you for finding Misskey. Misskey is a <b>decentralized microblogging platform</b> born on Earth. Since it exists within the Fediverse (a universe where various social media platforms are organized), it is mutually linked with other social media platforms. Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet?"
intro:
title: "What is Misskey?"
about: "Misskey is a open-source <b>decentralized microblogging service</b>. Sophisticated fully customizable Ui, varieties of reaction for posts, free file storage providing integrated management system and other advancing functions are available. Also, network system called “Fediverse” enables us to communicate with users on other SNSs. Like, if you post something, then your posts will sent not only to Misskey but also mastodon. Just imagine that the planet is sending a microwave to other planet to communication."
about: "Misskey is an open-source <b>decentralized microblogging service</b>. Sophisticated fully customizable UI, varieties of reactions for posts, free file storage providing an integrated management system and other advanced functions are available. In addition, Misskey connects to a network system called the “Fediverse” enables us to communicate with users on other SNSs. For example, when you post something it will be sent not only to Misskey but also Mastodon and Pleroma. Just imagine that the planet is sending a radio transmission to other planet to communicate."
features: "Features"
rich-contents: "Post"
rich-contents-desc: "Just post your idea, hot topics and anything you want to share. You may want to decorate your words, attach your favorite pictures, send files including movies and create a poll - those are the things you can do on Misskey!"
@@ -335,7 +335,7 @@ common/views/components/note-menu.vue:
pin: "Pin to your profile"
unpin: "Unpin"
delete: "Delete"
delete-confirm: "Delete this post?"
delete-confirm: "Are you sure you want to delete this post?"
remote: "Show original note"
common/views/components/poll.vue:
vote-to: "Vote for '{}'"
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "Email Address"
email-verified: "Your email has been verified."
email-not-verified: "Email address is not confirmed. Please check your inbox."
common/views/components/user-list-editor.vue:
users: "User"
rename: "Rename list"
delete: "Delete list"
remove-user: "Remove from this list"
delete-are-you-sure: "Delete list \"$1\"?"
deleted: "Deleted successfully"
common/views/widgets/broadcast.vue:
fetching: "Checking"
no-broadcasts: "No announcements"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Two-factor authentication"
other: "Other"
license: "License"
mark-as-read-all-unread-notes: "Mark all posts as read"
theme: "Theme"
behaviour: "Behavior"
fetch-on-scroll: "Endless loading on scroll"
@@ -1014,7 +1022,7 @@ admin/views/instance.vue:
save: "Save"
saved: "Saved"
user-recommendation-config: "Recommended users"
enable-external-user-recommendation: "Enable to external user recommendation"
enable-external-user-recommendation: "Enable external user recommendations"
external-user-recommendation-engine: "Engine"
external-user-recommendation-engine-desc: "Example: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "Timeout"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTP Port"
smtp-user: "SMTP User"
smtp-pass: "SMTP Password"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "Enable ServiceWorker"
serviceworker-info: "Must be enabled for push notifications."
vapid-publickey: "VAPID public key"
vapid-privatekey: "VAPID private key"
vapid-info: "If you want to enable ServiceWorker, you need to generate VAPID keys. Unless you have set your global node_modules location elsewhere, you need to run this as root:"
admin/views/charts.vue:
title: "Chart"
per-day: "per Day"
@@ -1057,10 +1071,10 @@ admin/views/charts.vue:
admin/views/drive.vue:
sort:
title: "Sort"
createdAtAsc: "アップロード日時が古い順"
createdAtDesc: "アップロード日時が新しい順"
sizeAsc: "サイズが小さい順"
sizeDesc: "サイズが大きい順"
createdAtAsc: "Age - Oldest First"
createdAtDesc: "Age - Newest First"
sizeAsc: "Size - Smallest First"
sizeDesc: "Size - Largest First"
origin:
title: "Origin"
combined: "Local + Remote"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "Remote"
delete: "Delete"
deleted: "Deleted successfully"
mark-as-sensitive: "Mark as 'sensitive'"
unmark-as-sensitive: "Unmark as 'sensitive'"
admin/views/users.vue:
operation: "Operations"
username-or-userid: "Username or user ID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "Sign out"
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"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "Recuperando"
no-broadcasts: "Sin emisión"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Autenticación de Doble-Factor"
other: "Otros"
license: "Licencia"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "Acciones"
fetch-on-scroll: "Desplazamiento infinito"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -18,13 +18,13 @@ common:
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
drive: "Drive"
drive-desc: "以前投稿したことのある画像をまた投稿したくなったことはありませんかもしくは、アップロードしたファイルをフォルダ分けして整理したくなったことはありませんかMisskeyの根幹に組み込まれたドライブ機能によってそれらが解決します。ファイルの共有も簡単です。"
outro: "Découvrez vous-même les fonctionnalités de Misskey. Étant donné que Misskey est un réseaux social fédéré, vous pouvez essayer dautres instances afin de trouver vos ami·e·s si la présente instance ne vous correspond pas. Bonne chance et amusez-vous bien!"
outro: "Découvrez vous-même les fonctionnalités de Misskey. Étant donné que Misskey est un réseau social fédéré, vous pouvez essayer dautres instances afin de trouver vos amis si la présente instance ne vous correspond pas. Bonne chance et amusez-vous bien!"
adblock:
detected: "Veuillez désactiver votre bloqueur de publicités"
warning: "<strong>Misskey nutilise pas de publicités</strong>, mais quelques options peuvent être non disponibles ou fonctionneraient mal si un bloqueur de publicités est activé."
application-authorization: "Autorisations de lapplication"
close: "Fermer"
do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis."
do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte pourrait être compromis."
load-more: "Charger plus"
enter-password: "Veuillez entrer le mot de passe"
got-it: "Jai compris !"
@@ -39,18 +39,18 @@ common:
reversi-invited-by: "Invité par {} :"
notified-by: "Notifié par {} :"
reply-from: "Réponse de {} :"
quoted-by: "Cité·e par {} :"
quoted-by: "Cité par {} :"
time:
unknown: "inconnu"
future: "à linstant"
just_now: "à l'instant"
seconds_ago: "Il y a {} seconde·s"
seconds_ago: "Il y a {} seconde(s)"
minutes_ago: "Il y a {} min"
hours_ago: "Il y a {} h"
days_ago: "Il y a {} j"
weeks_ago: "Il y a {} semaines"
months_ago: "Il y a {} mois"
years_ago: "Il y a {} an·s"
years_ago: "Il y a {} an(s)"
month-and-day: "{day}-{month}"
trash: "Corbeille"
drive: "Drive"
@@ -86,10 +86,10 @@ common:
public: "Public"
home: "Principal"
home-desc: "Publier sur le fil principal uniquement"
followers: "Abonné·e·s"
followers-desc: "Publier à vos abonné·e·s uniquement"
followers: "Abonnés"
followers-desc: "Publier à vos abonnés uniquement"
specified: "Direct"
specified-desc: "Publier uniquement aux utilisateurs·rices mentionnés·es"
specified-desc: "Publier uniquement aux utilisateurs mentionnés"
private: "Privé"
local-public: "Local (Public)"
local-home: "Accueil (local uniquement)"
@@ -122,7 +122,7 @@ common:
this-setting-is-this-device-only: "Uniquement sur cet appareil"
use-os-default-emojis: "Utiliser les émojis standards du système"
do-not-use-in-production: 'Il sagit dune version de développement. Ne pas utiliser dans un environnement de production.'
is-remote-user: "Ces informations appartiennent à un·e utilisateur·rice distant·e."
is-remote-user: "Ces informations appartiennent à un utilisateur distant."
is-remote-post: "Ceci est une publication distante."
view-on-remote: " Consulter le profil complet"
renoted-by: "Renoté par {user}"
@@ -155,10 +155,10 @@ common:
version: "Version"
broadcast: "Diffusion"
notifications: "Notifications"
users: "Utilisateur·rice·s"
users: "Utilisateurs recommandés"
polls: "Sondages"
post-form: "Champs de publication"
server: "Info sur le serveur"
server: "Infos sur le serveur"
nav: "Navigation"
tips: "Conseils"
hashtags: "Hashtags"
@@ -201,12 +201,12 @@ common/views/components/games/reversi/reversi.game.vue:
can-put-everywhere: "Peut poser partout"
common/views/components/games/reversi/reversi.index.vue:
title: "Misskey Reversi"
sub-title: "Jouer à Reversi avec vos ami·e·s !"
sub-title: "Jouer à Reversi avec vos amis !"
invite: "Inviter"
rule: "Comment jouer ?"
rule-desc: "Reversi est un jeu qui se joue sur un tablier et dans lequel les joueurs placent des pions sur ce dernier, à tour de rôle avec l'adversaire. Le but du jeu est d'avoir plus de pions de sa couleur que l'adversaire à la fin de la partie, celle-ci s'achevant lorsque aucun des deux joueurs ne peut plus jouer de coup légal, généralement lorsque les 64 cases sont occupées."
mode-invite: "Inviter"
mode-invite-desc: "Inviter un·e joueur·se."
mode-invite-desc: "Inviter un joueur."
invitations: "Vous avez reçu une invitation !"
my-games: "Mes jeux"
all-games: "Tous les jeux"
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "Adresse de courrier électronique"
email-verified: "Ladresse du courrier électronique a été vérifiée."
email-not-verified: "Adresse de courriel nest pas confirmée. Veuillez vérifier votre boite de réception."
common/views/components/user-list-editor.vue:
users: "Utilisateur"
rename: "Renommer la liste"
delete: "Supprimer la liste"
remove-user: "Retirer de cette liste"
delete-are-you-sure: "Voulez-vous vraiment supprimer la liste « $1 » ?"
deleted: "Supprimé"
common/views/widgets/broadcast.vue:
fetching: "Récupération"
no-broadcasts: "Aucune annonce"
@@ -504,7 +511,7 @@ common/views/widgets/slideshow.vue:
no-image: "Il n'y a aucune image dans ce dossier"
common/views/widgets/tips.vue:
tips-line1: "<kbd>t</kbd>でタイムラインにフォーカスできます"
tips-line2: "<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます"
tips-line2: "Ouvre la fenêtre de publication en appuyant sur <kbd>p</kbd> ou <kbd>n</kbd>."
tips-line3: "Vous pouvez glisser et déposer des fichiers sur la fenêtre de la note"
tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note"
tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser-déposer"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Vérification en deux étapes"
other: "Autres"
license: "Licence"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "Thèmes"
behaviour: "Comportement"
fetch-on-scroll: "Chargement lors du défilement"
@@ -988,17 +996,17 @@ admin/views/instance.vue:
recaptcha-site-key: "Clé reCAPTCHA du site"
recaptcha-secret-key: "Clé secrète reCAPTCHA"
twitter-integration-config: "Paramètres de connexion à Twitter"
twitter-integration-info: "コールバックURLは {url} に設定します。"
twitter-integration-info: "L'URL de callback est {url}."
enable-twitter-integration: "Activer la connection à Twitter"
twitter-integration-consumer-key: "Clé du consommateur"
twitter-integration-consumer-secret: "Secret du consommateur"
github-integration-config: "Paramètres dauthentification GitHub"
github-integration-info: "コールバックURLは {url} に設定します。"
github-integration-info: "L'URL de callback est {url}."
enable-github-integration: "Activer lauthentification avec Github"
github-integration-client-id: "ID client"
github-integration-client-secret: "Secret client"
discord-integration-config: "Paramètres dauthentification Discord"
discord-integration-info: "コールバックURLは {url} に設定します。"
discord-integration-info: "L'URL de callback est {url}."
enable-discord-integration: "Activer lauthentification avec Discord"
discord-integration-client-id: "ID client"
discord-integration-client-secret: "Secret client"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "Port SMTP"
smtp-user: "Utilisateur SMTP"
smtp-pass: "Mot de passe SMTP"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "Activer ServiceWorker"
serviceworker-info: "Devrait être activé pour les notifications push."
vapid-publickey: "Clé Publique VAPID"
vapid-privatekey: "Clé privée VAPID"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "Graph"
per-day: "par jour"
@@ -1057,8 +1071,8 @@ admin/views/charts.vue:
admin/views/drive.vue:
sort:
title: "Tri"
createdAtAsc: "アップロード日時が古い順"
createdAtDesc: "アップロード日時が新しい順"
createdAtAsc: "Âge - Du plus ancien"
createdAtDesc: "Âge - Du plus récent"
sizeAsc: "Taille - Ascendant"
sizeDesc: "Taille - Volumineux en premier"
origin:
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "Distant"
delete: "Supprimer"
deleted: "Supprimé"
mark-as-sensitive: "Marquer comme sensible"
unmark-as-sensitive: "Ne pas marquer comme sensible"
admin/views/users.vue:
operation: "Actions"
username-or-userid: "Nom dutilisateur·rice ou ID utilisateur"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "Déconnexion"
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"
@@ -1512,7 +1527,7 @@ docs:
require-credential: "Ce point de communication nécessite une authentification."
require-permission: "Ce point de communication nécessite la permission {permission}."
has-limit: "Il ya un taux limite."
duration-limit: "直近{duration}ミリ秒の間のこのエンドポイントへのリクエスト数の合計が{max}を超える場合はリクエストできません。"
duration-limit: "Si vous avez envoyé plus de {max} requêtes en {duration} millisecondes, vous ne serez pas en mesure d'envoyer d'autres requêtes."
min-interval-limit: "Vous ne pourrez pas effectuer une nouvelle requête si {interval} millisecondes ne se sont pas écoulées depuis la dernière demande."
show-src: "Vous pouvez voir le code source ce point de communication."
show-src-link: "Consulter le code sur GitHub"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動作"
fetch-on-scroll: "スクロールで自動読み込み"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -519,6 +519,14 @@ common/views/components/profile-editor.vue:
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -830,6 +838,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動作"
@@ -1156,6 +1165,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
@@ -1197,6 +1212,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
@@ -1357,6 +1374,7 @@ desktop/views/pages/user/user.timeline.vue:
default: "投稿"
with-replies: "投稿と返信"
with-media: "メディア"
my-posts: "私の投稿"
empty: "このユーザーはまだ何も投稿していないようです。"
desktop/views/widgets/messaging.vue:
@@ -1625,7 +1643,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "このメールアドレスOKや"
email-not-verified: "メールアドレスが確認されとらん。メールボックスもっぺん見てくれへん?"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "見てみるわ…"
no-broadcasts: "お知らせはあらへんで"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動き"
fetch-on-scroll: "スクロールしたらもっと見せてや"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "さいなら"
sound: "サウンド"
enable-sounds: "サウンド鳴らす"
mark-as-read-all-unread-notes: "全部もう読んだわ"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされとるで"

View File

@@ -354,7 +354,7 @@ common/views/components/reaction-picker.vue:
choose-reaction: "반응 선택"
common/views/components/emoji-picker.vue:
custom-emoji: "커스텀 이모지"
people: ""
people: "사람들"
animals-and-nature: "동물 & 자연"
food-and-drink: "음식 & 음료"
activity: "활동"
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "메일 주소"
email-verified: "매일 주소가 확인되었습니다"
email-not-verified: "메일 주소가 확인되지 않았습니다. 받은 편지함을 확인하여 주시기 바랍니다."
common/views/components/user-list-editor.vue:
users: "사용자"
rename: "리스트 이름 바꾸기"
delete: "리스트 삭제"
remove-user: "이 리스트에서 제거"
delete-are-you-sure: "리스트 \"$1\"을 삭제하시겠습니까?"
deleted: "삭제하였습니다"
common/views/widgets/broadcast.vue:
fetching: "확인중"
no-broadcasts: "공지사항이 없습니다"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "2단계 인증"
other: "기타"
license: "라이선스"
mark-as-read-all-unread-notes: "모든 글을 읽은 상태로 표시"
theme: "테마"
behaviour: "동작"
fetch-on-scroll: "스크롤하여 자동으로 불러오기"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTP 포트"
smtp-user: "SMTP 사용자"
smtp-pass: "SMTP 비밀번호"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorker 사용"
serviceworker-info: "푸시알림을 수행하려면 사용해야 합니다."
vapid-publickey: "VAPID 공개키"
vapid-privatekey: "VAPID 개인키"
vapid-info: "ServiceWorker를 사용하는 경우 VAPID 키 쌍을 생성해야 합니다. 셸에서 다음과 같이 합니다:"
admin/views/charts.vue:
title: "차트"
per-day: "1일마다"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "리모트"
delete: "삭제"
deleted: "삭제하였습니다"
mark-as-sensitive: "열람주의로 설정"
unmark-as-sensitive: "열람주의 해제"
admin/views/users.vue:
operation: "작업"
username-or-userid: "사용자명 혹은 사용자 ID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "로그아웃"
sound: "소리"
enable-sounds: "소리 사용"
mark-as-read-all-unread-notes: "모든 글을 읽은 상태로 표시"
password: "비밀번호"
mobile/views/pages/user.vue:
follows-you: "당신을 팔로우합니다"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "Bezig met ophalen"
no-broadcasts: "Geen uitzendingen"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Authenticatie in twee stappen"
other: "Overig"
license: "Licentie"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "Gedrag"
fetch-on-scroll: "Ophalen bij scrollen"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "Uitloggen"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "Volgt jou"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "Henter"
no-broadcasts: "お知らせはありません"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "To-faktor autentisering"
other: "Annet"
license: "Lisens"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "Utseende"
behaviour: "Oppførsel"
fetch-on-scroll: "スクロールで自動読み込み"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "Lyder"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "Adres e-mail"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "Sprawdzanie"
no-broadcasts: "Brak transmisji"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "Uwierzytelnianie dwuetapowe"
other: "Inne"
license: "Licencja"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "Motyw"
behaviour: "Zachowanie"
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "Usuń"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "Wyloguj"
sound: "Dźwięk"
enable-sounds: "Włącz dźwięk"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "Hasło"
mobile/views/pages/user.vue:
follows-you: "Śledzi Cię"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動作"
fetch-on-scroll: "スクロールで自動読み込み"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "Sair"
sound: "Sons"
enable-sounds: "Ativar sons"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "Te segue"

View File

@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"
delete: "リストを削除"
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "二段階認証"
other: "その他"
license: "ライセンス"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "テーマ"
behaviour: "動作"
fetch-on-scroll: "スクロールで自動読み込み"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTPポート"
smtp-user: "SMTPユーザー"
smtp-pass: "SMTPパスワード"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "ServiceWorkerを有効にする"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公開鍵"
vapid-privatekey: "VAPID秘密鍵"
vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
admin/views/charts.vue:
title: "チャート"
per-day: "1日ごと"
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
remote: "リモート"
delete: "削除"
deleted: "削除しました"
mark-as-sensitive: "閲覧注意に設定"
unmark-as-sensitive: "閲覧注意を解除"
admin/views/users.vue:
operation: "操作"
username-or-userid: "ユーザー名またはユーザーID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "サインアウト"
sound: "サウンド"
enable-sounds: "サウンドを有効にする"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
password: "パスワード"
mobile/views/pages/user.vue:
follows-you: "フォローされています"

View File

@@ -113,7 +113,7 @@ common:
use-white-black-reversi-stones: "リバーシに白黒の石を使う"
verified-user: "认证用户"
disable-animated-mfm: "在帖子中禁用动画文本"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
always-show-nsfw: "总是显示 NSFW 的内容"
always-mark-nsfw: "总是用 NSFW 来标记附件"
show-full-acct: "不要从用户名中忽略主机名"
@@ -164,7 +164,7 @@ common:
hashtags: "标签"
dev: "构建应用程序失败,请再试一次。"
ai-chan-kawaii: "Ai-chan kawaii!"
you: "あなた"
you: ""
auth/views/form.vue:
share-access: "您要允许<i>{name}</i>来访问您的账户吗?"
permission-ask: "这个应用程序需要以下权限:"
@@ -298,7 +298,7 @@ common/views/components/cw-button.vue:
hide: "隐藏"
show: "查看更多"
chars: "{count}文字"
files: "{count}ファイル"
files: "{count} 个文件"
common/views/components/messaging.vue:
search-user: "查找用户"
you: "您"
@@ -405,8 +405,8 @@ common/views/components/stream-indicator.vue:
connected: "已连接"
common/views/components/integration-settings.vue:
title: "サービス連携"
connect: "接続する"
disconnect: "切断する"
connect: "接"
disconnect: "未连接"
connected-to: "次のアカウントに接続されています"
common/views/components/github-setting.vue:
description: "当您用GitHub连接Misskey账户后您将能够看到有关您自己的信息并且您将能够使用GitHub登录。"
@@ -453,7 +453,7 @@ common/views/components/profile-editor.vue:
account: "账户"
location: "位置"
description: "关于我"
language: "言"
language: "言"
birthday: "生日"
avatar: "头像"
banner: "背景"
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
email-address: "电子邮件地址"
email-verified: "电子邮件地址已验证"
email-not-verified: "电子邮件地址还没有验证哦, 请检查一下收信箱吧~"
common/views/components/user-list-editor.vue:
users: "用户"
rename: "重命名列表"
delete: "删除列表"
remove-user: "从此列表中删除"
delete-are-you-sure: "删除列表 \"$1\""
deleted: "已删除"
common/views/widgets/broadcast.vue:
fetching: "确认中"
no-broadcasts: "没有公告"
@@ -524,7 +531,7 @@ common/views/widgets/tips.vue:
tips-line24: "Misskey自2014年开始运营。"
tips-line25: "在与通知功能兼容的浏览器中您可以在Misskey未打开的情况下接收通知"
common/views/pages/404.vue:
page-not-found: "ページが見つかりませんでした"
page-not-found: "您要找的网页不存在。"
common/views/pages/follow.vue:
signed-in-as: "用 {}登录"
following: "正在关注"
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
2fa: "两步验证"
other: "其他"
license: "许可证"
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
theme: "主题"
behaviour: "行为"
fetch-on-scroll: "向下滚动时自动加载"
@@ -780,7 +788,7 @@ desktop/views/components/settings.vue:
deck-column-width: "デッキのカラムの幅"
deck-column-width-narrow: "狭"
deck-column-width-narrower: "やや狭"
deck-column-width-normal: "普通"
deck-column-width-normal: "正常"
deck-column-width-wider: "やや広"
deck-column-width-wide: "広"
sound: "声音"
@@ -877,16 +885,16 @@ common/views/components/password-settings.vue:
enter-new-password-again: "请再次输入新密码"
not-match: "新密码不匹配"
changed: "密码已更改"
failed: "パスワード変更に失敗しました"
failed: "更改密码失败"
desktop/views/components/sub-note-content.vue:
private: "这个帖子是私密的"
deleted: "帖子已删除"
media-count: "附加{}媒体"
poll: "投票"
desktop/views/components/settings.tags.vue:
title: "タグ"
query: "クエリ (省略可)"
add: "加"
title: "标签"
query: "查询 (可选)"
add: "加"
save: "保存"
desktop/views/components/taskmanager.vue:
title: "任务管理器"
@@ -970,7 +978,7 @@ admin/views/instance.vue:
instance-description: "实例介绍"
host: "主机名"
banner-url: "背景图片地址"
error-image-url: "エラー画像URL"
error-image-url: "无效的图像URL"
languages: "实例语言"
languages-desc: "您可以添加多个,以空格分隔。"
maintainer-config: "管理员信息"
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
smtp-port: "SMTP 端口"
smtp-user: "SMTP 用户名"
smtp-pass: "SMTP 密码"
serviceworker-config: "ServiceWorker"
enable-serviceworker: "启用ServiceWorker"
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
vapid-publickey: "VAPID公钥"
vapid-privatekey: "VAPID私钥"
vapid-info: "如果您想要启用ServiceWorker那么您需要生成VAPID秘钥。除非您已经在其他地方设置了全局node_modules位置否则您需要将其作为root用户运行"
admin/views/charts.vue:
title: "历史记录"
per-day: "每天"
@@ -1056,18 +1070,20 @@ admin/views/charts.vue:
network-usage: "网络流量"
admin/views/drive.vue:
sort:
title: "ソート"
title: "排序"
createdAtAsc: "アップロード日時が古い順"
createdAtDesc: "アップロード日時が新しい順"
sizeAsc: "サイズが小さい順"
sizeDesc: "サイズが大きい順"
origin:
title: "オリジン"
combined: "ローカル+リモート"
local: "ローカル"
remote: "リモート"
delete: "除"
deleted: "削除しました"
title: "源自"
combined: "本地+远程"
local: "本地"
remote: "远程"
delete: "除"
deleted: "已删除"
mark-as-sensitive: "标记为“敏感”"
unmark-as-sensitive: "取消标记为“敏感”"
admin/views/users.vue:
operation: "操作"
username-or-userid: "用户名或用户ID"
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
signout: "注销"
sound: "声音"
enable-sounds: "开启声音"
mark-as-read-all-unread-notes: "将所有帖子标记为已读"
password: "密码"
mobile/views/pages/user.vue:
follows-you: "关注您"

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.64.2",
"clientVersion": "2.0.12796",
"version": "10.67.0",
"clientVersion": "2.0.12978",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@@ -21,9 +21,9 @@
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.8",
"@fortawesome/free-brands-svg-icons": "5.5.0",
"@fortawesome/free-brands-svg-icons": "5.6.0",
"@fortawesome/free-regular-svg-icons": "5.5.0",
"@fortawesome/free-solid-svg-icons": "5.5.0",
"@fortawesome/free-solid-svg-icons": "5.6.1",
"@fortawesome/vue-fontawesome": "0.1.2",
"@koa/cors": "2.2.2",
"@prezzemolo/rap": "0.1.2",
@@ -35,7 +35,7 @@
"@types/deep-equal": "1.0.1",
"@types/double-ended-queue": "2.1.0",
"@types/elasticsearch": "5.0.29",
"@types/file-type": "5.2.2",
"@types/file-type": "10.6.0",
"@types/gulp": "3.8.36",
"@types/gulp-mocha": "0.0.32",
"@types/gulp-rename": "0.0.33",
@@ -82,7 +82,7 @@
"@types/tinycolor2": "1.4.1",
"@types/tmp": "0.0.33",
"@types/uuid": "3.4.4",
"@types/webpack": "4.4.20",
"@types/webpack": "4.4.21",
"@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
@@ -114,6 +114,7 @@
"eslint": "5.8.0",
"eslint-plugin-vue": "4.7.1",
"eventemitter3": "3.1.0",
"feed": "2.0.2",
"file-loader": "2.0.0",
"file-type": "10.6.0",
"fuckadblock": "3.2.1",
@@ -126,18 +127,18 @@
"gulp-sourcemaps": "2.6.4",
"gulp-stylus": "2.7.0",
"gulp-tslint": "8.1.3",
"gulp-typescript": "4.0.2",
"gulp-typescript": "5.0.0",
"gulp-uglify": "3.0.1",
"gulp-util": "3.0.8",
"gulp-yaml": "2.0.2",
"hard-source-webpack-plugin": "0.12.0",
"hard-source-webpack-plugin": "0.13.1",
"html-minifier": "3.5.21",
"http-signature": "1.2.0",
"insert-text-at-cursor": "0.1.1",
"is-root": "2.0.0",
"is-url": "1.2.4",
"js-yaml": "3.12.0",
"jsdom": "13.0.0",
"jsdom": "13.1.0",
"json5": "2.1.0",
"json5-loader": "1.0.1",
"katex": "0.10.0",
@@ -160,7 +161,7 @@
"mocha": "5.2.0",
"moji": "0.5.1",
"moment": "2.22.2",
"mongodb": "3.1.9",
"mongodb": "3.1.10",
"monk": "6.0.6",
"ms": "2.1.1",
"nan": "2.11.1",
@@ -192,7 +193,7 @@
"rndstr": "1.0.0",
"s-age": "1.1.2",
"seedrandom": "2.4.4",
"sharp": "0.21.0",
"sharp": "0.21.1",
"showdown": "1.9.0",
"showdown-highlightjs-extension": "0.1.2",
"speakeasy": "2.0.0",
@@ -201,7 +202,7 @@
"stylus": "0.54.5",
"stylus-loader": "3.0.2",
"summaly": "2.2.0",
"systeminformation": "3.51.3",
"systeminformation": "3.52.2",
"syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "1.1.0",
"textarea-caret": "3.1.0",
@@ -209,7 +210,8 @@
"tmp": "0.0.33",
"ts-loader": "5.3.1",
"ts-node": "7.0.1",
"tslint": "5.10.0",
"tslint": "5.12.0",
"tslint-sonarts": "1.8.0",
"typescript": "3.2.2",
"typescript-eslint-parser": "21.0.2",
"uglify-es": "3.3.9",
@@ -219,7 +221,7 @@
"vue": "2.5.17",
"vue-color": "2.7.0",
"vue-content-loading": "1.5.3",
"vue-cropperjs": "2.2.2",
"vue-cropperjs": "3.0.0",
"vue-i18n": "8.3.2",
"vue-js-modal": "1.3.27",
"vue-loader": "15.4.2",

View File

@@ -69,7 +69,7 @@ export default Vue.extend({
display block
padding 12px 16px 16px 16px
height 250px
overflow hidden
overflow auto
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--adminDashboardCardBg)
border-radius 8px

View File

@@ -39,7 +39,11 @@
</div>
</div>
<div v-show="file._open">
<ui-button @click="del(file)"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
<ui-horizon-group>
<ui-button @click="toggleSensitive(file)" v-if="file.isSensitive"><fa :icon="faEye"/> {{ $t('unmark-as-sensitive') }}</ui-button>
<ui-button @click="toggleSensitive(file)" v-else><fa :icon="faEyeSlash"/> {{ $t('mark-as-sensitive') }}</ui-button>
<ui-button @click="del(file)"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
</ui-horizon-group>
</div>
</div>
</sequential-entrance>
@@ -53,7 +57,7 @@
import Vue from 'vue';
import i18n from '../../i18n';
import { faCloud } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/drive.vue'),
@@ -66,7 +70,7 @@ export default Vue.extend({
offset: 0,
files: [],
existMore: false,
faCloud, faTrashAlt
faCloud, faTrashAlt, faEye, faEyeSlash
};
},
@@ -132,7 +136,16 @@ export default Vue.extend({
text: e.toString()
});
});
}
},
toggleSensitive(file: any) {
this.$root.api('drive/files/update', {
fileId: file.id,
isSensitive: !file.isSensitive
});
file.isSensitive = !file.isSensitive;
},
}
});
</script>

View File

@@ -57,6 +57,15 @@
</ui-horizon-group>
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<span slot="desc">{{ $t('smtp-secure-info') }}</span></ui-switch>
</section>
<section>
<header><fa :icon="faBolt"/> {{ $t('serviceworker-config') }}</header>
<ui-switch v-model="enableServiceWorker">{{ $t('enable-serviceworker') }}<span slot="desc">{{ $t('serviceworker-info') }}</span></ui-switch>
<ui-info>{{ $t('vapid-info') }}<br><code>npm i web-push -g<br>web-push generate-vapid-keys</code></ui-info>
<ui-horizon-group inputs class="fit-bottom">
<ui-input v-model="swPublicKey" :disabled="!enableServiceWorker"><i slot="icon"><fa icon="key"/></i>{{ $t('vapid-publickey') }}</ui-input>
<ui-input v-model="swPrivateKey" :disabled="!enableServiceWorker"><i slot="icon"><fa icon="key"/></i>{{ $t('vapid-privatekey') }}</ui-input>
</ui-horizon-group>
</section>
<section>
<header>summaly Proxy</header>
<ui-input v-model="summalyProxy">URL</ui-input>
@@ -126,7 +135,7 @@ import Vue from 'vue';
import i18n from '../../i18n';
import { url, host } from '../../config';
import { toUnicode } from 'punycode';
import { faHeadset, faShieldAlt, faGhost, faUserPlus } from '@fortawesome/free-solid-svg-icons';
import { faHeadset, faShieldAlt, faGhost, faUserPlus, faBolt } from '@fortawesome/free-solid-svg-icons';
import { faEnvelope as farEnvelope } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
@@ -174,7 +183,10 @@ export default Vue.extend({
smtpPort: null,
smtpUser: null,
smtpPass: null,
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope
enableServiceWorker: false,
swPublicKey: null,
swPrivateKey: null,
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt
};
},
@@ -217,6 +229,9 @@ export default Vue.extend({
this.smtpPort = meta.smtpPort;
this.smtpUser = meta.smtpUser;
this.smtpPass = meta.smtpPass;
this.enableServiceWorker = meta.enableServiceWorker;
this.swPublicKey = meta.swPublickey;
this.swPrivateKey = meta.swPrivateKey;
});
},
@@ -270,7 +285,10 @@ export default Vue.extend({
smtpHost: this.smtpHost,
smtpPort: parseInt(this.smtpPort, 10),
smtpUser: this.smtpUser,
smtpPass: this.smtpPass
smtpPass: this.smtpPass,
enableServiceWorker: this.enableServiceWorker,
swPublicKey: this.swPublicKey,
swPrivateKey: this.swPrivateKey
}).then(() => {
this.$root.dialog({
type: 'success',

View File

@@ -22,7 +22,7 @@ export default function(type, data): Notification {
case 'unreadMessagingMessage':
return {
title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] ,
title: '%i18n:common.notification.message-from%'.split('{}')[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split('{}')[1] ,
body: data.text, // TODO: getMessagingMessageSummary(data),
icon: data.user.avatarUrl
};
@@ -30,7 +30,7 @@ export default function(type, data): Notification {
case 'reversiInvited':
return {
title: '%i18n:common.notification.reversi-invited%',
body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1],
body: '%i18n:common.notification.reversi-invited-by%'.split('{}')[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split('{}')[1],
icon: data.parent.avatarUrl
};
@@ -38,21 +38,21 @@ export default function(type, data): Notification {
switch (data.type) {
case 'mention':
return {
title: '%i18n:common.notification.notified-by%'.split("{}")[0] + `${getUserName(data.user)}:` + '%i18n:common.notification.notified-by%'.split("{}")[1],
title: '%i18n:common.notification.notified-by%'.split('{}')[0] + `${getUserName(data.user)}:` + '%i18n:common.notification.notified-by%'.split('{}')[1],
body: getNoteSummary(data),
icon: data.user.avatarUrl
};
case 'reply':
return {
title: '%i18n:common.notification.reply-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.reply-from%'.split("{}")[1],
title: '%i18n:common.notification.reply-from%'.split('{}')[0] + `${getUserName(data.user)}` + '%i18n:common.notification.reply-from%'.split('{}')[1],
body: getNoteSummary(data),
icon: data.user.avatarUrl
};
case 'quote':
return {
title: '%i18n:common.notification.quoted-by%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.quoted-by%'.split("{}")[1],
title: '%i18n:common.notification.quoted-by%'.split('{}')[0] + `${getUserName(data.user)}` + '%i18n:common.notification.quoted-by%'.split('{}')[1],
body: getNoteSummary(data),
icon: data.user.avatarUrl
};

View File

@@ -15,7 +15,7 @@ export default function(sec) {
const t
= tod < 60 ? `${Math.floor(tod)} sec`
: tod < 3600 ? `${Math.floor(tod / 60)} min`
: `${Math.floor(tod / 60 / 60)}:${Math.floor((tod / 60) % 60).toString().padStart(2, "0")}`;
: `${Math.floor(tod / 60 / 60)}:${Math.floor((tod / 60) % 60).toString().padStart(2, '0')}`;
let str = '';
if (d) str += `${d}, `;

View File

@@ -3,8 +3,8 @@
export default (data: ArrayBuffer) => {
//const buf = new Buffer(data);
//const hash = crypto.createHash("md5");
//const hash = crypto.createHash('md5');
//hash.update(buf);
//return hash.digest("hex");
//return hash.digest('hex');
return '';
};

View File

@@ -80,8 +80,8 @@ export default (opts: Opts = {}) => ({
const ast = parse(this.appearNote.text);
// TODO: 再帰的にURL要素がないか調べる
return unique(ast
.filter(t => ((t.name == 'url' || t.name == 'link') && t.props.url && !t.props.silent))
.map(t => t.props.url));
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent))
.map(t => t.node.props.url));
} else {
return null;
}

View File

@@ -95,6 +95,7 @@ export default prop => ({
Vue.set(this.$_ns_target.reactionCounts, reaction, 0);
}
// Increment the count
this.$_ns_target.reactionCounts[reaction]++;
if (body.userId == this.$store.state.i.id) {
@@ -103,6 +104,26 @@ export default prop => ({
break;
}
case 'unreacted': {
const reaction = body.reaction;
if (this.$_ns_target.reactionCounts == null) {
return;
}
if (this.$_ns_target.reactionCounts[reaction] == null) {
return;
}
// Decrement the count
if (this.$_ns_target.reactionCounts[reaction] > 0) this.$_ns_target.reactionCounts[reaction]--;
if (body.userId == this.$store.state.i.id) {
Vue.set(this.$_ns_target, 'myReaction', null);
}
break;
}
case 'pollVoted': {
if (body.userId == this.$store.state.i.id) return;
const choice = body.choice;

View File

@@ -75,7 +75,7 @@ export default Vue.extend({
return this.dark ? '#fff' : '#777';
},
hHandColor(): string {
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--themeColor')).toHexString();
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--primary')).toHexString();
},
ms(): number {

View File

@@ -48,7 +48,7 @@ export default Vue.extend({
iconAndText(): any[] {
return (
(this.hasPendingFollowRequestFromYou && this.user.isLocked) ? ['hourglass-half', this.$t('request-pending')] :
(this.hasPendingFollowRequestFromYou && !this.user.isLocked) ? ['hourglass-start', this.$t('follow-processing')] :
(this.hasPendingFollowRequestFromYou && !this.user.isLocked) ? ['spinner', this.$t('follow-processing')] :
(this.isFollowing) ? ['minus', this.$t('following')] :
(!this.isFollowing && this.user.isLocked) ? ['plus', this.$t('follow-request')] :
(!this.isFollowing && !this.user.isLocked) ? ['plus', this.$t('follow')] :

View File

@@ -1,5 +1,5 @@
<template>
<router-link class="ldlomzub" :to="`/@${ canonical }`" v-user-preview="canonical">
<router-link class="ldlomzub" :to="`/${ canonical }`" v-user-preview="canonical">
<span class="me" v-if="isMe">{{ $t('@.you') }}</span>
<span class="main">
<span class="username">@{{ username }}</span>

View File

@@ -85,7 +85,7 @@ export default Vue.extend({
}
} else {
if (items[0].kind == 'file') {
alert('%i18n:only-one-file-attached%');
alert(this.$t('only-one-file-attached'));
}
}
},
@@ -107,7 +107,7 @@ export default Vue.extend({
return;
} else if (e.dataTransfer.files.length > 1) {
e.preventDefault();
alert('%i18n:only-one-file-attached%');
alert(this.$t('only-one-file-attached'));
return;
}

View File

@@ -3,9 +3,9 @@
<mk-avatar class="avatar" :user="message.user" target="_blank"/>
<div class="content">
<div class="balloon" :data-no-text="message.text == null">
<!-- <button class="delete-button" v-if="isMe" :title="$t('@.delete')">
<img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
</button> -->
<button class="delete-button" v-if="isMe" :title="$t('@.delete')" @click="del">
<img src="/assets/desktop/remove.png" alt="Delete"/>
</button>
<div class="content" v-if="!message.isDeleted">
<misskey-flavored-markdown class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
<div class="file" v-if="message.file">
@@ -16,7 +16,7 @@
</a>
</div>
</div>
<div class="content" v-if="message.isDeleted">
<div class="content" v-else>
<p class="is-deleted">{{ $t('deleted') }}</p>
</div>
</div>
@@ -52,12 +52,19 @@ export default Vue.extend({
if (this.message.text) {
const ast = parse(this.message.text);
return unique(ast
.filter(t => ((t.name == 'url' || t.name == 'link') && t.props.url && !t.silent))
.map(t => t.props.url));
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent))
.map(t => t.node.props.url));
} else {
return null;
}
}
},
methods: {
del() {
this.$root.api('messaging/messages/delete', {
messageId: this.message.id
});
}
}
});
</script>

View File

@@ -79,6 +79,7 @@ export default Vue.extend({
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
this.connection.on('deleted', this.onDeleted);
if (this.isNaked) {
window.addEventListener('scroll', this.onScroll, { passive: true });
@@ -204,6 +205,13 @@ export default Vue.extend({
}
},
onDeleted(id) {
const msg = this.messages.find(m => m.id === id);
if (msg) {
this.messages = this.messages.filter(m => m.id !== msg.id);
}
},
isBottom() {
const asobi = 64;
const current = this.isNaked

View File

@@ -1,6 +1,6 @@
import Vue, { VNode } from 'vue';
import { length } from 'stringz';
import { Node } from '../../../../../mfm/parser';
import { MfmForest } from '../../../../../mfm/parser';
import parse from '../../../../../mfm/parse';
import MkUrl from './url.vue';
import MkMention from './mention.vue';
@@ -9,16 +9,11 @@ import MkFormula from './formula.vue';
import MkGoogle from './google.vue';
import syntaxHighlight from '../../../../../mfm/syntax-highlight';
import { host } from '../../../config';
import { preorderF, countNodesF } from '../../../../../prelude/tree';
function getTextCount(tokens: Node[]): number {
const rootCount = sum(tokens.filter(x => x.name === 'text').map(x => length(x.props.text)));
const childrenCount = sum(tokens.filter(x => x.children).map(x => getTextCount(x.children)));
return rootCount + childrenCount;
}
function getChildrenCount(tokens: Node[]): number {
const countTree = tokens.filter(x => x.children).map(x => getChildrenCount(x.children));
return countTree.length + sum(countTree);
function sumTextsLength(ts: MfmForest): number {
const textNodes = preorderF(ts).filter(n => n.type === 'text');
return sum(textNodes.map(x => length(x.props.text)));
}
export default Vue.component('misskey-flavored-markdown', {
@@ -27,10 +22,6 @@ export default Vue.component('misskey-flavored-markdown', {
type: String,
required: true
},
ast: {
type: [],
required: false
},
shouldBreak: {
type: Boolean,
default: true
@@ -55,17 +46,15 @@ export default Vue.component('misskey-flavored-markdown', {
render(createElement) {
if (this.text == null || this.text == '') return;
const ast = this.ast == null ?
parse(this.text, this.plainText) : // Parse text to ast
this.ast as Node[];
const ast = parse(this.text, this.plainText);
let bigCount = 0;
let motionCount = 0;
const genEl = (ast: Node[]) => concat(ast.map((token): VNode[] => {
switch (token.name) {
const genEl = (ast: MfmForest) => concat(ast.map((token): VNode[] => {
switch (token.node.type) {
case 'text': {
const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
const text = token.node.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (this.shouldBreak) {
const x = text.split('\n')
@@ -95,7 +84,7 @@ export default Vue.component('misskey-flavored-markdown', {
case 'big': {
bigCount++;
const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;
const isLong = sumTextsLength(token.children) > 10 || countNodesF(token.children) > 5;
const isMany = bigCount > 3;
return (createElement as any)('strong', {
attrs: {
@@ -122,7 +111,7 @@ export default Vue.component('misskey-flavored-markdown', {
case 'motion': {
motionCount++;
const isLong = getTextCount(token.children) > 10 || getChildrenCount(token.children) > 5;
const isLong = sumTextsLength(token.children) > 10 || countNodesF(token.children) > 5;
const isMany = motionCount > 3;
return (createElement as any)('span', {
attrs: {
@@ -139,7 +128,7 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement(MkUrl, {
key: Math.random(),
props: {
url: token.props.url,
url: token.node.props.url,
target: '_blank',
style: 'color:var(--mfmLink);'
}
@@ -150,9 +139,9 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement('a', {
attrs: {
class: 'link',
href: token.props.url,
href: token.node.props.url,
target: '_blank',
title: token.props.url,
title: token.node.props.url,
style: 'color:var(--mfmLink);'
}
}, genEl(token.children))];
@@ -162,8 +151,8 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement(MkMention, {
key: Math.random(),
props: {
host: (token.props.host == null && this.author && this.author.host != null ? this.author.host : token.props.host) || host,
username: token.props.username
host: (token.node.props.host == null && this.author && this.author.host != null ? this.author.host : token.node.props.host) || host,
username: token.node.props.username
}
})];
}
@@ -172,10 +161,10 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement('router-link', {
key: Math.random(),
attrs: {
to: `/tags/${encodeURIComponent(token.props.hashtag)}`,
to: `/tags/${encodeURIComponent(token.node.props.hashtag)}`,
style: 'color:var(--mfmHashtag);'
}
}, `#${token.props.hashtag}`)];
}, `#${token.node.props.hashtag}`)];
}
case 'blockCode': {
@@ -184,7 +173,7 @@ export default Vue.component('misskey-flavored-markdown', {
}, [
createElement('code', {
domProps: {
innerHTML: syntaxHighlight(token.props.code)
innerHTML: syntaxHighlight(token.node.props.code)
}
})
])];
@@ -193,7 +182,7 @@ export default Vue.component('misskey-flavored-markdown', {
case 'inlineCode': {
return [createElement('code', {
domProps: {
innerHTML: syntaxHighlight(token.props.code)
innerHTML: syntaxHighlight(token.node.props.code)
}
})];
}
@@ -227,8 +216,8 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement('mk-emoji', {
key: Math.random(),
attrs: {
emoji: token.props.emoji,
name: token.props.name
emoji: token.node.props.emoji,
name: token.node.props.name
},
props: {
customEmojis: this.customEmojis || customEmojis,
@@ -242,7 +231,7 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement(MkFormula, {
key: Math.random(),
props: {
formula: token.props.formula
formula: token.node.props.formula
}
})];
}
@@ -252,13 +241,13 @@ export default Vue.component('misskey-flavored-markdown', {
return [createElement(MkGoogle, {
key: Math.random(),
props: {
q: token.props.query
q: token.node.props.query
}
})];
}
default: {
console.log('unknown ast type:', token.name);
console.log('unknown ast type:', token.node.type);
return [];
}

View File

@@ -24,7 +24,7 @@
</ui-input>
<ui-input v-model="birthday" type="date">
<span>{{ $t('birthday') }}</span>
<span slot="title">{{ $t('birthday') }}</span>
<span slot="prefix"><fa icon="birthday-cake"/></span>
</ui-input>

View File

@@ -1,16 +1,16 @@
<template>
<div class="mk-reactions-viewer">
<template v-if="reactions">
<span :class="{ reacted: note.myReaction == 'like' }" @click="react('like')" v-if="reactions.like" v-particle><mk-reaction-icon reaction="like" ref="like"/><span>{{ reactions.like }}</span></span>
<span :class="{ reacted: note.myReaction == 'love' }" @click="react('love')" v-if="reactions.love" v-particle><mk-reaction-icon reaction="love" ref="love"/><span>{{ reactions.love }}</span></span>
<span :class="{ reacted: note.myReaction == 'laugh' }" @click="react('laugh')" v-if="reactions.laugh" v-particle><mk-reaction-icon reaction="laugh" ref="laugh"/><span>{{ reactions.laugh }}</span></span>
<span :class="{ reacted: note.myReaction == 'hmm' }" @click="react('hmm')" v-if="reactions.hmm" v-particle><mk-reaction-icon reaction="hmm" ref="hmm"/><span>{{ reactions.hmm }}</span></span>
<span :class="{ reacted: note.myReaction == 'surprise' }" @click="react('surprise')" v-if="reactions.surprise" v-particle><mk-reaction-icon reaction="surprise" ref="surprise"/><span>{{ reactions.surprise }}</span></span>
<span :class="{ reacted: note.myReaction == 'congrats' }" @click="react('congrats')" v-if="reactions.congrats" v-particle><mk-reaction-icon reaction="congrats" ref="congrats"/><span>{{ reactions.congrats }}</span></span>
<span :class="{ reacted: note.myReaction == 'angry' }" @click="react('angry')" v-if="reactions.angry" v-particle><mk-reaction-icon reaction="angry" ref="angry"/><span>{{ reactions.angry }}</span></span>
<span :class="{ reacted: note.myReaction == 'confused' }" @click="react('confused')" v-if="reactions.confused" v-particle><mk-reaction-icon reaction="confused" ref="confused"/><span>{{ reactions.confused }}</span></span>
<span :class="{ reacted: note.myReaction == 'rip' }" @click="react('rip')" v-if="reactions.rip" v-particle><mk-reaction-icon reaction="rip" ref="rip"/><span>{{ reactions.rip }}</span></span>
<span :class="{ reacted: note.myReaction == 'pudding' }" @click="react('pudding')" v-if="reactions.pudding" v-particle><mk-reaction-icon reaction="pudding" ref="pudding"/><span>{{ reactions.pudding }}</span></span>
<span :class="{ reacted: note.myReaction == 'like' }" @click="toggleReaction('like')" v-if="reactions.like" v-particle><mk-reaction-icon reaction="like" ref="like"/><span>{{ reactions.like }}</span></span>
<span :class="{ reacted: note.myReaction == 'love' }" @click="toggleReaction('love')" v-if="reactions.love" v-particle><mk-reaction-icon reaction="love" ref="love"/><span>{{ reactions.love }}</span></span>
<span :class="{ reacted: note.myReaction == 'laugh' }" @click="toggleReaction('laugh')" v-if="reactions.laugh" v-particle><mk-reaction-icon reaction="laugh" ref="laugh"/><span>{{ reactions.laugh }}</span></span>
<span :class="{ reacted: note.myReaction == 'hmm' }" @click="toggleReaction('hmm')" v-if="reactions.hmm" v-particle><mk-reaction-icon reaction="hmm" ref="hmm"/><span>{{ reactions.hmm }}</span></span>
<span :class="{ reacted: note.myReaction == 'surprise' }" @click="toggleReaction('surprise')" v-if="reactions.surprise" v-particle><mk-reaction-icon reaction="surprise" ref="surprise"/><span>{{ reactions.surprise }}</span></span>
<span :class="{ reacted: note.myReaction == 'congrats' }" @click="toggleReaction('congrats')" v-if="reactions.congrats" v-particle><mk-reaction-icon reaction="congrats" ref="congrats"/><span>{{ reactions.congrats }}</span></span>
<span :class="{ reacted: note.myReaction == 'angry' }" @click="toggleReaction('angry')" v-if="reactions.angry" v-particle><mk-reaction-icon reaction="angry" ref="angry"/><span>{{ reactions.angry }}</span></span>
<span :class="{ reacted: note.myReaction == 'confused' }" @click="toggleReaction('confused')" v-if="reactions.confused" v-particle><mk-reaction-icon reaction="confused" ref="confused"/><span>{{ reactions.confused }}</span></span>
<span :class="{ reacted: note.myReaction == 'rip' }" @click="toggleReaction('rip')" v-if="reactions.rip" v-particle><mk-reaction-icon reaction="rip" ref="rip"/><span>{{ reactions.rip }}</span></span>
<span :class="{ reacted: note.myReaction == 'pudding' }" @click="toggleReaction('pudding')" v-if="reactions.pudding" v-particle><mk-reaction-icon reaction="pudding" ref="pudding"/><span>{{ reactions.pudding }}</span></span>
</template>
</div>
</template>
@@ -60,14 +60,29 @@ export default Vue.extend({
}
},
methods: {
react(reaction: string) {
this.$root.api('notes/reactions/create', {
noteId: this.note.id,
reaction: reaction
});
toggleReaction(reaction: string) {
const oldReaction = this.note.myReaction;
if (oldReaction) {
this.$root.api('notes/reactions/delete', {
noteId: this.note.id
}).then(() => {
if (oldReaction !== reaction) {
this.$root.api('notes/reactions/create', {
noteId: this.note.id,
reaction: reaction
});
}
});
} else {
this.$root.api('notes/reactions/create', {
noteId: this.note.id,
reaction: reaction
});
}
},
anime(reaction: string) {
if (this.$store.state.device.reduceMotion) return;
if (document.hidden) return;
this.$nextTick(() => {
const rect = this.$refs[reaction].$el.getBoundingClientRect();

View File

@@ -26,6 +26,7 @@ import { toUnicode } from 'punycode';
export default Vue.extend({
i18n: i18n('common/views/components/signin.vue'),
props: {
withAvatar: {
type: Boolean,
@@ -33,6 +34,7 @@ export default Vue.extend({
default: true
}
},
data() {
return {
signing: false,
@@ -45,11 +47,13 @@ export default Vue.extend({
meta: null
};
},
created() {
this.$root.getMeta().then(meta => {
this.meta = meta;
});
},
methods: {
onUsernameChange() {
this.$root.api('users/show', {
@@ -60,6 +64,7 @@ export default Vue.extend({
this.user = null;
});
},
onSubmit() {
this.signing = true;
@@ -80,8 +85,6 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.mk-signin
color #555

View File

@@ -50,6 +50,7 @@ import { toUnicode } from 'punycode';
export default Vue.extend({
i18n: i18n('common/views/components/signup.vue'),
data() {
return {
host: toUnicode(host),
@@ -64,6 +65,7 @@ export default Vue.extend({
meta: null
}
},
computed: {
shouldShowProfileUrl(): boolean {
return (this.username != '' &&
@@ -72,17 +74,20 @@ export default Vue.extend({
this.usernameState != 'max-range');
}
},
created() {
this.$root.getMeta().then(meta => {
this.meta = meta;
});
},
mounted() {
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
head.appendChild(script);
},
methods: {
onChangeUsername() {
if (this.username == '') {
@@ -111,6 +116,7 @@ export default Vue.extend({
this.usernameState = 'error';
});
},
onChangePassword() {
if (this.password == '') {
this.passwordStrength = '';
@@ -120,6 +126,7 @@ export default Vue.extend({
const strength = getPasswordStrength(this.password);
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
},
onChangePasswordRetype() {
if (this.retypedPassword == '') {
this.passwordRetypeState = null;
@@ -128,6 +135,7 @@ export default Vue.extend({
this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match';
},
onSubmit() {
this.$root.api('signup', {
username: this.username,
@@ -138,8 +146,9 @@ export default Vue.extend({
this.$root.api('signin', {
username: this.username,
password: this.password
}, true).then(() => {
location.href = '/';
}, true).then(res => {
localStorage.setItem('i', res.i);
location.reload();
});
}).catch(() => {
alert(this.$t('some-error'));
@@ -154,8 +163,6 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.mk-signup
min-width 302px
</style>

View File

@@ -33,14 +33,7 @@ export default Vue.extend({
return typeof this.time == 'string' ? new Date(this.time) : this.time;
},
absolute(): string {
const time = this._time;
return (
time.getFullYear() + '年' +
(time.getMonth() + 1) + '月' +
time.getDate() + '日' +
' ' +
time.getHours() + '時' +
time.getMinutes() + '分');
return this._time.toLocaleString();
},
relative(): string {
const time = this._time;

View File

@@ -6,6 +6,7 @@
<div class="value" ref="passwordMetar"></div>
</div>
<span class="label" ref="label"><slot></slot></span>
<span class="title" ref="title"><slot name="title"></slot></span>
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<template v-if="type != 'file'">
<input ref="input"
@@ -281,6 +282,20 @@ root(fill)
transform-origin top left
transform scale(1)
> .title
position absolute
z-index 1
top fill ? -24px : -17px
left 0 !important
pointer-events none
font-size 16px
line-height 32px
color var(--inputLabel)
pointer-events none
//will-change transform
transform-origin top left
transform scale(.75)
> input
display block
width 100%

View File

@@ -14,7 +14,7 @@
<header>
<h1>{{ title }}</h1>
</header>
<p>{{ description.length > 85 ? description.slice(0, 85) + '…' : description }}</p>
<p v-if="description">{{ description.length > 85 ? description.slice(0, 85) + '…' : description }}</p>
<footer>
<img class="icon" v-if="icon" :src="icon"/>
<p>{{ sitename }}</p>

View File

@@ -0,0 +1,150 @@
<template>
<div class="cudqjmnl">
<ui-card>
<div slot="title"><fa :icon="faList"/> {{ list.title }}</div>
<section>
<ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
<ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="faUsers"/> {{ $t('users') }}</div>
<section>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="phcqulfl" v-for="user in users">
<div>
<a :href="user | userPage">
<mk-avatar class="avatar" :user="user" :disable-link="true"/>
</a>
</div>
<div>
<header>
<b><mk-user-name :user="user"/></b>
<span class="username">@{{ user | acct }}</span>
</header>
<div>
<a @click="remove(user)">{{ $t('remove-user') }}</a>
</div>
</div>
</div>
</sequential-entrance>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faList, faICursor, faUsers } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/user-list-editor.vue'),
props: {
list: {
required: true
}
},
data() {
return {
users: [],
faList, faICursor, faTrashAlt, faUsers
};
},
mounted() {
this.fetchUsers();
},
methods: {
fetchUsers() {
this.$root.api('users/show', {
userIds: this.list.userIds
}).then(users => {
this.users = users;
});
},
rename() {
this.$root.dialog({
title: this.$t('rename'),
input: {
default: this.list.title
}
}).then(({ canceled, result: title }) => {
if (canceled) return;
this.$root.api('users/lists/update', {
listId: this.list.id,
title: title
});
});
},
del() {
this.$root.dialog({
type: 'warning',
text: this.$t('delete-are-you-sure').replace('$1', this.list.title),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('users/lists/delete', {
listId: this.list.id
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('deleted')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
});
},
remove(user: any) {
this.$root.api('users/lists/pull', {
listId: this.list.id,
userId: user.id
}).then(() => {
this.fetchUsers();
});
}
}
});
</script>
<style lang="stylus" scoped>
.cudqjmnl
.phcqulfl
display flex
padding 16px 0
border-top solid 1px var(--faceDivider)
> div:first-child
> a
> .avatar
width 64px
height 64px
> div:last-child
flex 1
padding-left 16px
@media (max-width 500px)
font-size 14px
> header
> .username
margin-left 8px
opacity 0.7
</style>

View File

@@ -16,7 +16,7 @@
</div>
</header>
<div class="text">
<misskey-flavored-markdown v-if="note.text" :text="note.text" :author="note.user" :custom-emojis="note.emojis"/>
<misskey-flavored-markdown v-if="note.text" :text="note.cw != null ? note.cw : note.text" :author="note.user" :custom-emojis="note.emojis"/>
</div>
</div>
</div>

View File

@@ -25,6 +25,7 @@ class Autocomplete {
private opts: {
model: string;
};
private opening: boolean;
private get text(): string {
return this.vm[this.opts.model];
@@ -48,6 +49,7 @@ class Autocomplete {
this.textarea = textarea;
this.vm = vm;
this.opts = opts;
this.opening = false;
}
/**
@@ -128,6 +130,8 @@ class Autocomplete {
if (type != this.currentType) {
this.close();
}
if (this.opening) return;
this.opening = true;
this.currentType = type;
//#region サジェストを表示すべき位置を計算
@@ -143,6 +147,8 @@ class Autocomplete {
this.suggestion.x = x;
this.suggestion.y = y;
this.suggestion.q = q;
this.opening = false;
} else {
const MkAutocomplete = await import('../components/autocomplete.vue').then(m => m.default);
@@ -162,6 +168,8 @@ class Autocomplete {
// 要素追加
document.body.appendChild(this.suggestion.$el);
this.opening = false;
}
}

View File

@@ -22,7 +22,7 @@
:disabled="followWait">
<template v-if="!followWait">
<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> {{ $t('request-pending') }}</template>
<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="hourglass-start"/> {{ $t('follow-processing') }}</template>
<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="spinner"/> {{ $t('follow-processing') }}</template>
<template v-else-if="user.isFollowing"><fa icon="minus"/> {{ $t('following') }}</template>
<template v-else-if="!user.isFollowing && user.isLocked"><fa icon="plus"/> {{ $t('follow-request') }}</template>
<template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> {{ $t('follow') }}</template>

View File

@@ -1,4 +1,4 @@
import { apiUrl } from '../../config';
import { apiUrl, locale } from '../../config';
import CropWindow from '../views/components/crop-window.vue';
import ProgressDialog from '../views/components/progress-dialog.vue';
@@ -9,7 +9,7 @@ export default ($root: any) => {
const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
if (!regex.test(file.name) ) {
$root.dialog({
title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
title: locale['desktop']['invalid-filetype'],
text: null
});
return reject('invalid-filetype');
@@ -17,7 +17,7 @@ export default ($root: any) => {
const w = $root.new(CropWindow, {
image: file,
title: '%i18n:desktop.avatar-crop-title%',
title: locale['desktop']['avatar-crop-title'],
aspectRatio: 1 / 1
});
@@ -27,11 +27,11 @@ export default ($root: any) => {
data.append('file', blob, file.name + '.cropped.png');
$root.api('drive/folders/find', {
name: '%i18n:desktop.avatar%'
name: locale['desktop']['avatar']
}).then(avatarFolder => {
if (avatarFolder.length === 0) {
$root.api('drive/folders/create', {
name: '%i18n:desktop.avatar%'
name: locale['desktop']['avatar']
}).then(iconFolder => {
resolve(upload(data, iconFolder));
});
@@ -52,7 +52,7 @@ export default ($root: any) => {
const upload = (data, folder) => new Promise((resolve, reject) => {
const dialog = $root.new(ProgressDialog, {
title: '%i18n:desktop.uploading-avatar%'
title: locale['desktop']['uploading-avatar']
});
document.body.appendChild(dialog.$el);
@@ -88,7 +88,7 @@ export default ($root: any) => {
});
$root.dialog({
title: '%fa:info-circle% %i18n:desktop.avatar-updated%',
title: locale['desktop']['avatar-updated'],
text: null
});
@@ -101,7 +101,7 @@ export default ($root: any) => {
? Promise.resolve(file)
: $root.$chooseDriveFile({
multiple: false,
title: '%fa:image% %i18n:desktop.choose-avatar%'
title: locale['desktop']['choose-avatar']
});
return selectedFile

View File

@@ -1,4 +1,4 @@
import { apiUrl } from '../../config';
import { apiUrl, locale } from '../../config';
import CropWindow from '../views/components/crop-window.vue';
import ProgressDialog from '../views/components/progress-dialog.vue';
@@ -9,7 +9,7 @@ export default ($root: any) => {
const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
if (!regex.test(file.name) ) {
$root.dialog({
title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
title: locale['desktop']['invalid-filetype'],
text: null
});
return reject('invalid-filetype');
@@ -17,7 +17,7 @@ export default ($root: any) => {
const w = $root.new(CropWindow, {
image: file,
title: '%i18n:desktop.banner-crop-title%',
title: locale['desktop']['banner-crop-title'],
aspectRatio: 16 / 9
});
@@ -27,11 +27,11 @@ export default ($root: any) => {
data.append('file', blob, file.name + '.cropped.png');
$root.api('drive/folders/find', {
name: '%i18n:desktop.banner%'
name: locale['desktop']['banner']
}).then(bannerFolder => {
if (bannerFolder.length === 0) {
$root.api('drive/folders/create', {
name: '%i18n:desktop.banner%'
name: locale['desktop']['banner']
}).then(iconFolder => {
resolve(upload(data, iconFolder));
});
@@ -52,7 +52,7 @@ export default ($root: any) => {
const upload = (data, folder) => new Promise((resolve, reject) => {
const dialog = $root.new(ProgressDialog, {
title: '%i18n:desktop.uploading-banner%'
title: locale['desktop']['uploading-banner']
});
document.body.appendChild(dialog.$el);
@@ -88,7 +88,7 @@ export default ($root: any) => {
});
$root.dialog({
title: '%fa:info-circle% %i18n:desktop.banner-updated%',
title: locale['desktop']['banner-updated'],
text: null
});
@@ -101,7 +101,7 @@ export default ($root: any) => {
? Promise.resolve(file)
: $root.$chooseDriveFile({
multiple: false,
title: '%fa:image% %i18n:desktop.choose-banner%'
title: locale['desktop']['choose-banner']
});
return selectedFile

View File

@@ -23,7 +23,9 @@
</router-link>
</p>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</template>
@@ -37,7 +39,9 @@
</router-link>
</p>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note.renote)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.renote.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</template>
@@ -50,7 +54,9 @@
<mk-user-name :user="notification.note.user"/>
</router-link>
</p>
<router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</router-link>
<router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
</router-link>
</div>
</template>
@@ -84,7 +90,9 @@
<mk-user-name :user="notification.note.user"/>
</router-link>
</p>
<router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</router-link>
<router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
</router-link>
</div>
</template>
@@ -96,7 +104,9 @@
<mk-user-name :user="notification.note.user"/>
</router-link>
</p>
<a class="note-preview" :href="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</a>
<a class="note-preview" :href="notification.note | notePage" :title="getNoteSummary(notification.note)">
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
</a>
</div>
</template>
@@ -107,7 +117,9 @@
<mk-user-name :user="notification.user"/>
</a></p>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</template>

View File

@@ -74,6 +74,7 @@ import { host } from '../../../config';
import { erase, unique } from '../../../../../prelude/array';
import { length } from 'stringz';
import { toASCII } from 'punycode';
import extractMentions from '../../../../../misc/extract-mentions';
export default Vue.extend({
i18n: i18n('desktop/views/components/post-form.vue'),
@@ -184,8 +185,7 @@ export default Vue.extend({
if (this.reply && this.reply.text != null) {
const ast = parse(this.reply.text);
// TODO: 新しいMFMパーサに対応
for (const x of ast.filter(t => t.type == 'mention')) {
for (const x of extractMentions(ast)) {
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
// 自分は除外
@@ -207,9 +207,8 @@ export default Vue.extend({
this.visibility = this.reply.visibility;
}
// ダイレクトへのリプライはリプライ先ユーザーを初期設定
if (this.reply && this.reply.visibility === 'specified') {
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
if (this.reply) {
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
this.visibleUsers.push(user);
});
}
@@ -236,7 +235,7 @@ export default Vue.extend({
},
methods: {
trimmedLength(text: string) {
trimmedLength(text: string) {
return length(text.trim());
},

View File

@@ -92,6 +92,7 @@
import Vue from 'vue';
import i18n from '../../../i18n';
import MkUserListsWindow from './user-lists-window.vue';
import MkUserListWindow from './user-list-window.vue';
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
import MkSettingsWindow from './settings-window.vue';
import MkDriveWindow from './drive-window.vue';
@@ -143,7 +144,9 @@ export default Vue.extend({
this.close();
const w = this.$root.new(MkUserListsWindow);
w.$once('choosen', list => {
this.$router.push(`i/lists/${ list.id }`);
this.$root.new(MkUserListWindow, {
list
});
});
},
followRequests() {

View File

@@ -14,16 +14,34 @@ export default Vue.extend({
i18n: i18n('desktop/views/components/ui.header.search.vue'),
data() {
return {
q: ''
q: '',
wait: false
};
},
methods: {
onSubmit() {
async onSubmit() {
if (this.wait) return;
const q = this.q.trim();
if (q.startsWith('@')) {
this.$router.push(`/${q}`);
} else if (q.startsWith('#')) {
this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`);
} else if (q.startsWith('https://')) {
this.wait = true;
try {
const res = await this.$root.api('ap/show', {
uri: q
});
if (res.type == 'User') {
this.$router.push(`/@${res.object.username}@${res.object.host}`);
} else if (res.type == 'Note') {
this.$router.push(`/notes/${res.object.id}`);
}
} catch (e) {
// TODO
}
this.wait = false;
} else {
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
}

View File

@@ -0,0 +1,24 @@
<template>
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
<span slot="header"><fa icon="list"/> {{ list.title }}</span>
<x-editor :list="list"/>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
import XEditor from '../../../common/views/components/user-list-editor.vue';
export default Vue.extend({
components: {
XEditor
},
props: {
list: {
required: true
}
}
});
</script>

View File

@@ -1,5 +1,5 @@
<template>
<mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
<span slot="header"><fa icon="list"/> {{ $t('title') }}</span>
<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">

View File

@@ -627,6 +627,7 @@ export default Vue.extend({
> .content
height 100%
overflow auto
&:not([flexible])
> .main > .body > .content

View File

@@ -11,7 +11,7 @@
<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/>
<!-- トランジションを有効にするとなぜかメモリリークする -->
<transition-group name="mk-notes" class="transition notes" ref="notes" tag="div">
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notes" class="transition notes" ref="notes" tag="div">
<template v-for="(note, i) in _notes">
<x-note
:note="note"
@@ -24,7 +24,7 @@
<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
</p>
</template>
</transition-group>
</component>
<footer v-if="more">
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">

View File

@@ -11,7 +11,8 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
@@ -28,7 +29,9 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note.renote)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.renote.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</div>
@@ -70,7 +73,9 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</div>

View File

@@ -3,7 +3,7 @@
<header :class="$style.header">
<h1>#{{ $route.params.tag }}</h1>
</header>
<p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ $t('no-posts-found', { q }) }}</p>
<p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ $t('no-posts-found', { q: $route.params.tag }) }}</p>
<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
</mk-ui>
</template>

View File

@@ -24,9 +24,14 @@ export default Vue.extend({
};
},
mounted() {
const image = [
'image/jpeg',
'image/png',
'image/gif'
];
this.$root.api('users/notes', {
userId: this.user.id,
withFiles: true,
fileType: image,
limit: 9,
untilDate: new Date().getTime() + 1000 * 86400 * 365
}).then(notes => {

View File

@@ -4,6 +4,7 @@
<span :data-active="mode == 'default'" @click="mode = 'default'"><fa :icon="['far', 'comment-alt']"/> {{ $t('default') }}</span>
<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'"><fa icon="comments"/> {{ $t('with-replies') }}</span>
<span :data-active="mode == 'with-media'" @click="mode = 'with-media'"><fa :icon="['far', 'images']"/> {{ $t('with-media') }}</span>
<span :data-active="mode == 'my-posts'" @click="mode = 'my-posts'"><fa icon="user"/> {{ $t('my-posts') }}</span>
</header>
<mk-notes ref="timeline" :more="existMore ? more : null">
<p class="empty" slot="empty"><fa :icon="['far', 'comments']"/>{{ $t('empty') }}</p>
@@ -65,6 +66,7 @@ export default Vue.extend({
limit: fetchLimit + 1,
untilDate: this.date ? this.date.getTime() : new Date().getTime() + 1000 * 86400 * 365,
includeReplies: this.mode == 'with-replies',
includeMyRenotes: this.mode != 'my-posts',
withFiles: this.mode == 'with-media'
}).then(notes => {
if (notes.length == fetchLimit + 1) {
@@ -85,6 +87,7 @@ export default Vue.extend({
userId: this.user.id,
limit: fetchLimit + 1,
includeReplies: this.mode == 'with-replies',
includeMyRenotes: this.mode != 'my-posts',
withFiles: this.mode == 'with-media',
untilDate: new Date((this.$refs.timeline as any).tail().createdAt).getTime()
});

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 from './mios';
import { clientVersion as version, codename, lang } from './config';
import { clientVersion as version, codename, lang, locale } from './config';
import { builtinThemes, lightTheme, applyTheme } from './theme';
import Dialog from './common/views/components/dialog.vue';
@@ -123,6 +123,7 @@ import {
faArrowLeft,
faMapMarker,
faRobot,
faHourglassHalf,
} from '@fortawesome/free-solid-svg-icons';
import {
@@ -253,6 +254,7 @@ library.add(
faArrowLeft,
faMapMarker,
faRobot,
faHourglassHalf,
farBell,
farEnvelope,
@@ -320,7 +322,7 @@ Vue.mixin({
console.info(`Misskey v${version} (${codename})`);
console.info(
'%c%i18n:common.do-not-copy-paste%',
`%c${locale['common']['do-not-copy-paste']}`,
'color: red; background: yellow; font-size: 16px; font-weight: bold;');
// BootTimer解除

View File

@@ -9,7 +9,8 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
@@ -24,7 +25,9 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note.renote)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.renote.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</div>
@@ -60,7 +63,9 @@
<mk-time :time="notification.createdAt"/>
</header>
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
<fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/>
<fa icon="quote-left"/>
<misskey-flavored-markdown :text="getNoteSummary(notification.note)" :should-break="false" :plain-text="true" :custom-emojis="notification.note.emojis"/>
<fa icon="quote-right"/>
</router-link>
</div>
</div>

View File

@@ -66,6 +66,7 @@ import { host } from '../../../config';
import { erase, unique } from '../../../../../prelude/array';
import { length } from 'stringz';
import { toASCII } from 'punycode';
import extractMentions from '../../../../../misc/extract-mentions';
export default Vue.extend({
i18n: i18n('mobile/views/components/post-form.vue'),
@@ -174,7 +175,7 @@ export default Vue.extend({
if (this.reply && this.reply.text != null) {
const ast = parse(this.reply.text);
for (const x of ast.filter(t => t.type == 'mention')) {
for (const x of extractMentions(ast)) {
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
// 自分は除外
@@ -196,9 +197,8 @@ export default Vue.extend({
this.visibility = this.reply.visibility;
}
// ダイレクトへのリプライはリプライ先ユーザーを初期設定
if (this.reply && this.reply.visibility === 'specified') {
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
if (this.reply) {
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
this.visibleUsers.push(user);
});
}

View File

@@ -60,7 +60,8 @@ export default Vue.extend({
hasGameInvitation: false,
connection: null,
aboutUrl: `/docs/${lang}/about`,
announcements: []
announcements: [],
searching: false,
};
},
@@ -95,17 +96,34 @@ export default Vue.extend({
methods: {
search() {
if (this.searching) return;
this.$root.dialog({
title: this.$t('search'),
input: true
}).then(({ canceled, result: query }) => {
}).then(async ({ canceled, result: query }) => {
if (canceled) return;
const q = query.trim();
const q = this.q.trim();
if (q.startsWith('@')) {
this.$router.push(`/${q}`);
} else if (q.startsWith('#')) {
this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`);
} else if (q.startsWith('https://')) {
this.searching = true;
try {
const res = await this.$root.api('ap/show', {
uri: q
});
if (res.type == 'User') {
this.$router.push(`/@${res.object.username}@${res.object.host}`);
} else if (res.type == 'Note') {
this.$router.push(`/notes/${res.object.id}`);
}
} catch (e) {
// TODO
}
this.searching = false;
} else {
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
}

View File

@@ -3,7 +3,7 @@
<span slot="header"><span style="margin-right:4px;"><fa icon="hashtag"/></span>{{ $route.params.tag }}</span>
<main>
<p v-if="!fetching && empty"><fa icon="search"/> {{ $t('no-posts-found', { q }) }}</p>
<p v-if="!fetching && empty"><fa icon="search"/> {{ $t('no-posts-found', { q: $route.params.tag }) }}</p>
<mk-notes ref="timeline" :more="existMore ? more : null"/>
</main>
</mk-ui>

View File

@@ -3,11 +3,7 @@
<span slot="header" v-if="!fetching"><fa icon="list"/>{{ list.title }}</span>
<main v-if="!fetching">
<ul>
<li v-for="user in users" :key="user.id"><router-link :to="user | userPage">
<mk-user-name :user="user"/>
</router-link></li>
</ul>
<x-editor :list="list"/>
</main>
</mk-ui>
</template>
@@ -15,13 +11,16 @@
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
import XEditor from '../../../common/views/components/user-list-editor.vue';
export default Vue.extend({
components: {
XEditor
},
data() {
return {
fetching: true,
list: null,
users: null
list: null
};
},
watch: {
@@ -42,12 +41,6 @@ export default Vue.extend({
this.fetching = false;
Progress.done();
this.$root.api('users/show', {
userIds: this.list.userIds
}).then(users => {
this.users = users;
});
});
}
}
@@ -55,8 +48,6 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
main
width 100%
max-width 680px

View File

@@ -26,10 +26,15 @@ export default Vue.extend({
};
},
mounted() {
const image = [
'image/jpeg',
'image/png',
'image/gif'
];
this.$root.api('users/notes', {
userId: this.user.id,
withFiles: true,
limit: 6,
fileType: image,
limit: 9,
untilDate: new Date().getTime() + 1000 * 86400 * 365
}).then(notes => {
for (const note of notes) {

View File

@@ -1,4 +1,4 @@
declare module "*.vue" {
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}

View File

@@ -39,21 +39,7 @@ export type Source = {
accesslog?: string;
/**
* Service Worker
*/
sw?: {
public_key: string;
private_key: string;
};
clusterLimit?: number;
user_recommendation?: {
external: boolean;
engine: string;
timeout: number;
};
};
/**

View File

@@ -1,4 +1,4 @@
import { count, concat } from "../../prelude/array";
import { count, concat } from '../../prelude/array';
// MISSKEY REVERSI ENGINE
@@ -76,27 +76,14 @@ export default class Reversi {
this.mapHeight = map.length;
const mapData = map.join('');
this.board = mapData.split('').map(d => {
if (d == '-') return null;
if (d == 'b') return BLACK;
if (d == 'w') return WHITE;
return undefined;
});
this.board = mapData.split('').map(d => d === '-' ? null : d === 'b' ? BLACK : d === 'w' ? WHITE : undefined);
this.map = mapData.split('').map(d => {
if (d == '-' || d == 'b' || d == 'w') return 'empty';
return 'null';
});
this.map = mapData.split('').map(d => d === '-' || d === 'b' || d === 'w' ? 'empty' : 'null');
//#endregion
// ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある
if (!this.canPutSomewhere(BLACK)) {
if (!this.canPutSomewhere(WHITE)) {
this.turn = null;
} else {
this.turn = WHITE;
}
}
if (!this.canPutSomewhere(BLACK))
this.turn = this.canPutSomewhere(WHITE) ? WHITE : null;
}
/**
@@ -117,16 +104,14 @@ export default class Reversi {
* 黒石の比率
*/
public get blackP() {
if (this.blackCount == 0 && this.whiteCount == 0) return 0;
return this.blackCount / (this.blackCount + this.whiteCount);
return this.blackCount == 0 && this.whiteCount == 0 ? 0 : this.blackCount / (this.blackCount + this.whiteCount);
}
/**
* 白石の比率
*/
public get whiteP() {
if (this.blackCount == 0 && this.whiteCount == 0) return 0;
return this.whiteCount / (this.blackCount + this.whiteCount);
return this.blackCount == 0 && this.whiteCount == 0 ? 0 : this.whiteCount / (this.blackCount + this.whiteCount);
}
public transformPosToXy(pos: number): number[] {
@@ -172,13 +157,10 @@ export default class Reversi {
private calcTurn() {
// ターン計算
if (this.canPutSomewhere(!this.prevColor)) {
this.turn = !this.prevColor;
} else if (this.canPutSomewhere(this.prevColor)) {
this.turn = this.prevColor;
} else {
this.turn = null;
}
this.turn =
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
this.canPutSomewhere(this.prevColor) ? this.prevColor :
null;
}
public undo() {
@@ -199,8 +181,7 @@ export default class Reversi {
*/
public mapDataGet(pos: number): MapPixel {
const [x, y] = this.transformPosToXy(pos);
if (x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight) return 'null';
return this.map[pos];
return x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight ? 'null' : this.map[pos];
}
/**
@@ -223,16 +204,10 @@ export default class Reversi {
* @param pos 位置
*/
public canPut(color: Color, pos: number): boolean {
// 既に石が置いてある場所には打てない
if (this.board[pos] !== null) return false;
if (this.opts.canPutEverywhere) {
// 挟んでなくても置けるモード
return this.mapDataGet(pos) == 'empty';
} else {
// 相手の石を1つでも反転させられるか
return this.effects(color, pos).length !== 0;
}
return (
this.board[pos] !== null ? false : // 既に石が置いてある場所には打てない
this.opts.canPutEverywhere ? this.mapDataGet(pos) == 'empty' : // 挟んでなくても置けるモード
this.effects(color, pos).length !== 0); // 相手の石を1つでも反転させられるか
}
/**
@@ -263,19 +238,13 @@ export default class Reversi {
[x, y] = nextPos(x, y);
// 座標が指し示す位置がボード外に出たとき
if (this.opts.loopedBoard) {
x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth;
y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight;
if (this.transformXyToPos(x, y) == initPos) {
if (this.opts.loopedBoard && this.transformXyToPos(
(x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth),
(y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight)) == initPos)
// 盤面の境界でループし、自分が石を置く位置に戻ってきたとき、挟めるようにしている (ref: Test4のマップ)
return found;
}
} else {
if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight) {
return []; // 挟めないことが確定 (盤面外に到達)
}
}
return found;
else if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight)
return []; // 挟めないことが確定 (盤面外に到達)
const pos = this.transformXyToPos(x, y);
if (this.mapDataGet(pos) === 'null') return []; // 挟めないことが確定 (配置不可能なマスに到達)
@@ -300,14 +269,9 @@ export default class Reversi {
* ゲームの勝者 (null = 引き分け)
*/
public get winner(): Color {
if (!this.isEnded) return undefined;
if (this.blackCount == this.whiteCount) return null;
if (this.opts.isLlotheo) {
return this.blackCount > this.whiteCount ? WHITE : BLACK;
} else {
return this.blackCount > this.whiteCount ? BLACK : WHITE;
}
return this.isEnded ?
this.blackCount == this.whiteCount ? null :
this.opts.isLlotheo === this.blackCount > this.whiteCount ? WHITE : BLACK :
undefined;
}
}

View File

@@ -2,10 +2,10 @@ const jsdom = require('jsdom');
const { JSDOM } = jsdom;
import config from '../config';
import { INote } from '../models/note';
import { Node } from './parser';
import { intersperse } from '../prelude/array';
import { MfmForest, MfmTree } from './parser';
export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
export default (tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
if (tokens == null) {
return null;
}
@@ -14,11 +14,11 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
const doc = window.document;
function appendChildren(children: Node[], targetElement: any): void {
for (const child of children.map(n => handlers[n.name](n))) targetElement.appendChild(child);
function appendChildren(children: MfmForest, targetElement: any): void {
for (const child of children.map(t => handlers[t.node.type](t))) targetElement.appendChild(child);
}
const handlers: { [key: string]: (token: Node) => any } = {
const handlers: { [key: string]: (token: MfmTree) => any } = {
bold(token) {
const el = doc.createElement('b');
appendChildren(token.children, el);
@@ -58,7 +58,7 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
blockCode(token) {
const pre = doc.createElement('pre');
const inner = doc.createElement('code');
inner.innerHTML = token.props.code;
inner.innerHTML = token.node.props.code;
pre.appendChild(inner);
return pre;
},
@@ -70,39 +70,39 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
},
emoji(token) {
return doc.createTextNode(token.props.emoji ? token.props.emoji : `:${token.props.name}:`);
return doc.createTextNode(token.node.props.emoji ? token.node.props.emoji : `:${token.node.props.name}:`);
},
hashtag(token) {
const a = doc.createElement('a');
a.href = `${config.url}/tags/${token.props.hashtag}`;
a.textContent = `#${token.props.hashtag}`;
a.href = `${config.url}/tags/${token.node.props.hashtag}`;
a.textContent = `#${token.node.props.hashtag}`;
a.setAttribute('rel', 'tag');
return a;
},
inlineCode(token) {
const el = doc.createElement('code');
el.textContent = token.props.code;
el.textContent = token.node.props.code;
return el;
},
math(token) {
const el = doc.createElement('code');
el.textContent = token.props.formula;
el.textContent = token.node.props.formula;
return el;
},
link(token) {
const a = doc.createElement('a');
a.href = token.props.url;
a.href = token.node.props.url;
appendChildren(token.children, a);
return a;
},
mention(token) {
const a = doc.createElement('a');
const { username, host, acct } = token.props;
const { username, host, acct } = token.node.props;
switch (host) {
case 'github.com':
a.href = `https://github.com/${username}`;
@@ -133,7 +133,7 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
text(token) {
const el = doc.createElement('span');
const nodes = (token.props.text as string).split('\n').map(x => doc.createTextNode(x));
const nodes = (token.node.props.text as string).split('\n').map(x => doc.createTextNode(x));
for (const x of intersperse('br', nodes)) {
el.appendChild(x === 'br' ? doc.createElement('br') : x);
@@ -144,15 +144,15 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
url(token) {
const a = doc.createElement('a');
a.href = token.props.url;
a.textContent = token.props.url;
a.href = token.node.props.url;
a.textContent = token.node.props.url;
return a;
},
search(token) {
const a = doc.createElement('a');
a.href = `https://www.google.com/?#q=${token.props.query}`;
a.textContent = token.props.content;
a.href = `https://www.google.com/?#q=${token.node.props.query}`;
a.textContent = token.node.props.content;
return a;
}
};

View File

@@ -1,40 +1,36 @@
import parser, { Node, plainParser } from './parser';
import parser, { plainParser, MfmForest, MfmTree } from './parser';
import * as A from '../prelude/array';
import * as S from '../prelude/string';
import { createTree, createLeaf } from '../prelude/tree';
export default (source: string, plainText = false): Node[] => {
function concatTextTrees(ts: MfmForest): MfmTree {
return createLeaf({ type: 'text', props: { text: S.concat(ts.map(x => x.node.props.text)) } });
}
function concatIfTextTrees(ts: MfmForest): MfmForest {
return ts[0].node.type === 'text' ? [concatTextTrees(ts)] : ts;
}
function concatConsecutiveTextTrees(ts: MfmForest): MfmForest {
const us = A.concat(A.groupOn(t => t.node.type, ts).map(concatIfTextTrees));
return us.map(t => createTree(t.node, concatConsecutiveTextTrees(t.children)));
}
function isEmptyTextTree(t: MfmTree): boolean {
return t.node.type == 'text' && t.node.props.text === '';
}
function removeEmptyTextNodes(ts: MfmForest): MfmForest {
return ts
.filter(t => !isEmptyTextTree(t))
.map(t => createTree(t.node, removeEmptyTextNodes(t.children)));
}
export default (source: string, plainText = false): MfmForest => {
if (source == null || source == '') {
return null;
}
let nodes: Node[] = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source);
const combineText = (es: Node[]): Node =>
({ name: 'text', props: { text: S.concat(es.map(e => e.props.text)) } });
const concatText = (nodes: Node[]): Node[] =>
A.concat(A.groupOn(x => x.name, nodes).map(es =>
es[0].name === 'text' ? [combineText(es)] : es
));
const concatTextRecursive = (es: Node[]): void => {
for (const x of es.filter(x => x.children)) {
x.children = concatText(x.children);
concatTextRecursive(x.children);
}
};
nodes = concatText(nodes);
concatTextRecursive(nodes);
const removeEmptyTextNodes = (nodes: Node[]) => {
for (const n of nodes.filter(n => n.children)) {
n.children = removeEmptyTextNodes(n.children);
}
return nodes.filter(n => !(n.name == 'text' && n.props.text == ''));
};
nodes = removeEmptyTextNodes(nodes);
return nodes;
const raw = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source) as MfmForest;
return removeEmptyTextNodes(concatConsecutiveTextTrees(raw));
};

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { capitalize, toUpperCase } from "../prelude/string";
import { capitalize, toUpperCase } from '../prelude/string';
function escape(text: string) {
return text
@@ -307,7 +307,7 @@ const elements: Element[] = [
}
];
// specify lang is todo
// TODO: specify lang
export default (source: string, lang?: string): string => {
let code = source;
let html = '';

View File

@@ -1,5 +1,5 @@
export default (acct: string) => {
if (acct.startsWith('@')) acct = acct.substr(1);
const splitted = acct.split('@', 2);
return { username: splitted[0], host: splitted[1] || null };
const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null };
};

View File

@@ -0,0 +1,9 @@
import { EmojiNode, MfmForest } from '../mfm/parser';
import { preorderF } from '../prelude/tree';
import { unique } from '../prelude/array';
export default function(mfmForest: MfmForest): string[] {
const emojiNodes = preorderF(mfmForest).filter(x => x.type === 'emoji') as EmojiNode[];
const emojis = emojiNodes.filter(x => x.props.name && x.props.name.length <= 100).map(x => x.props.name);
return unique(emojis);
}

View File

@@ -0,0 +1,9 @@
import { HashtagNode, MfmForest } from '../mfm/parser';
import { preorderF } from '../prelude/tree';
import { unique } from '../prelude/array';
export default function(mfmForest: MfmForest): string[] {
const hashtagNodes = preorderF(mfmForest).filter(x => x.type === 'hashtag') as HashtagNode[];
const hashtags = hashtagNodes.map(x => x.props.hashtag);
return unique(hashtags);
}

View File

@@ -0,0 +1,10 @@
// test is located in test/extract-mentions
import { MentionNode, MfmForest } from '../mfm/parser';
import { preorderF } from '../prelude/tree';
export default function(mfmForest: MfmForest): MentionNode['props'][] {
// TODO: 重複を削除
const mentionNodes = preorderF(mfmForest).filter(x => x.type === 'mention') as MentionNode[];
return mentionNodes.map(x => x.props);
}

View File

@@ -17,9 +17,10 @@ const defaultMeta: any = {
enableGithubIntegration: false,
enableDiscordIntegration: false,
enableExternalUserRecommendation: false,
externalUserRecommendationEngine: "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}",
externalUserRecommendationEngine: 'https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}',
externalUserRecommendationTimeout: 300000,
errorImageUrl: 'https://ai.misskey.xyz/aiart/yubitun.png'
errorImageUrl: 'https://ai.misskey.xyz/aiart/yubitun.png',
enableServiceWorker: false
};
export default async function(): Promise<IMeta> {

View File

@@ -14,7 +14,11 @@ const summarize = (note: any): string => {
let summary = '';
// 本文
summary += note.text ? note.text : '';
if (note.cw != null) {
summary += note.cw;
} else {
summary += note.text ? note.text : '';
}
// ファイルが添付されているとき
if ((note.files || []).length != 0) {

View File

@@ -15,4 +15,6 @@ export type IEmoji = {
url: string;
aliases?: string[];
updatedAt?: Date;
/** AP object id */
uri?: string;
};

View File

@@ -1,13 +0,0 @@
import * as mongo from 'mongodb';
import db from '../db/mongodb';
const MessagingHistory = db.get<IMessagingHistory>('messagingHistories');
export default MessagingHistory;
export type IMessagingHistory = {
_id: mongo.ObjectID;
updatedAt: Date;
userId: mongo.ObjectID;
partnerId: mongo.ObjectID;
messageId: mongo.ObjectID;
};

View File

@@ -7,6 +7,8 @@ import isObjectId from '../misc/is-objectid';
import { length } from 'stringz';
const MessagingMessage = db.get<IMessagingMessage>('messagingMessages');
MessagingMessage.createIndex('userId');
MessagingMessage.createIndex('recipientId');
export default MessagingMessage;
export interface IMessagingMessage {

View File

@@ -138,6 +138,19 @@ if ((config as any).user_recommendation) {
}
});
}
if ((config as any).sw) {
Meta.findOne({}).then(m => {
if (m != null && m.enableServiceWorker == null) {
Meta.update({}, {
$set: {
enableServiceWorker: true,
swPublicKey: (config as any).sw.public_key,
swPrivateKey: (config as any).sw.private_key
}
});
}
});
}
export type IMeta = {
name?: string;
@@ -223,4 +236,8 @@ export type IMeta = {
smtpPort?: number;
smtpUser?: string;
smtpPass?: string;
enableServiceWorker?: boolean;
swPublicKey?: string;
swPrivateKey?: string;
};

View File

@@ -155,7 +155,7 @@ export const isRemoteUser = (user: any): user is IRemoteUser =>
//#region Validators
export function validateUsername(username: string, remote?: boolean): boolean {
return typeof username == 'string' && (remote ? /^\w+([\w\.-]+\w+)?$/ : /^[a-zA-Z0-9_]{1,20}$/).test(username);
return typeof username == 'string' && (remote ? /^\w([\w-]*\w)?$/ : /^\w{1,20}$/).test(username);
}
export function validatePassword(password: string): boolean {

View File

@@ -1,31 +1,53 @@
export function countIf<T>(f: (x: T) => boolean, xs: T[]): number {
import { EndoRelation, Predicate } from './relation';
/**
* Count the number of elements that satisfy the predicate
*/
export function countIf<T>(f: Predicate<T>, xs: T[]): number {
return xs.filter(f).length;
}
export function count<T>(x: T, xs: T[]): number {
return countIf(y => x === y, xs);
/**
* Count the number of elements that is equal to the element
*/
export function count<T>(a: T, xs: T[]): number {
return countIf(x => x === a, xs);
}
/**
* Concatenate an array of arrays
*/
export function concat<T>(xss: T[][]): T[] {
return ([] as T[]).concat(...xss);
}
/**
* Intersperse the element between the elements of the array
* @param sep The element to be interspersed
*/
export function intersperse<T>(sep: T, xs: T[]): T[] {
return concat(xs.map(x => [sep, x])).slice(1);
}
export function erase<T>(x: T, xs: T[]): T[] {
return xs.filter(y => x !== y);
/**
* Returns the array of elements that is not equal to the element
*/
export function erase<T>(a: T, xs: T[]): T[] {
return xs.filter(x => x !== a);
}
/**
* Finds the array of all elements in the first array not contained in the second array.
* The order of result values are determined by the first array.
*/
export function difference<T>(includes: T[], excludes: T[]): T[] {
return includes.filter(x => !excludes.includes(x));
export function difference<T>(xs: T[], ys: T[]): T[] {
return xs.filter(x => !ys.includes(x));
}
/**
* Remove all but the first element from every group of equivalent elements
*/
export function unique<T>(xs: T[]): T[] {
return [...new Set(xs)];
}
@@ -38,7 +60,11 @@ export function maximum(xs: number[]): number {
return Math.max(...xs);
}
export function groupBy<T>(f: (x: T, y: T) => boolean, xs: T[]): T[][] {
/**
* Splits an array based on the equivalence relation.
* The concatenation of the result is equal to the argument.
*/
export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
const groups = [] as T[][];
for (const x of xs) {
if (groups.length !== 0 && f(groups[groups.length - 1][0], x)) {
@@ -50,10 +76,17 @@ export function groupBy<T>(f: (x: T, y: T) => boolean, xs: T[]): T[][] {
return groups;
}
/**
* Splits an array based on the equivalence relation induced by the function.
* The concatenation of the result is equal to the argument.
*/
export function groupOn<T, S>(f: (x: T) => S, xs: T[]): T[][] {
return groupBy((a, b) => f(a) === f(b), xs);
}
/**
* Compare two arrays by lexicographical order
*/
export function lessThan(xs: number[], ys: number[]): boolean {
for (let i = 0; i < Math.min(xs.length, ys.length); i++) {
if (xs[i] < ys[i]) return true;
@@ -62,7 +95,10 @@ export function lessThan(xs: number[], ys: number[]): boolean {
return xs.length < ys.length;
}
export function takeWhile<T>(f: (x: T) => boolean, xs: T[]): T[] {
/**
* Returns the longest prefix of elements that satisfy the predicate
*/
export function takeWhile<T>(f: Predicate<T>, xs: T[]): T[] {
const ys = [];
for (const x of xs) {
if (f(x)) {
@@ -73,3 +109,9 @@ export function takeWhile<T>(f: (x: T) => boolean, xs: T[]): T[] {
}
return ys;
}
export function cumulativeSum(xs: number[]): number[] {
const ys = Array.from(xs); // deep copy
for (let i = 1; i < ys.length; i++) ys[i] += ys[i - 1];
return ys;
}

5
src/prelude/relation.ts Normal file
View File

@@ -0,0 +1,5 @@
export type Predicate<T> = (a: T) => boolean;
export type Relation<T, U> = (a: T, b: U) => boolean;
export type EndoRelation<T> = Relation<T, T>;

View File

@@ -1,5 +1,5 @@
export function concat(xs: string[]): string {
return xs.reduce((a, b) => a + b, "");
return xs.join('');
}
export function capitalize(s: string): string {

36
src/prelude/tree.ts Normal file
View File

@@ -0,0 +1,36 @@
import { concat, sum } from './array';
export type Tree<T> = {
node: T,
children: Forest<T>;
};
export type Forest<T> = Tree<T>[];
export function createLeaf<T>(node: T): Tree<T> {
return { node, children: [] };
}
export function createTree<T>(node: T, children: Forest<T>): Tree<T> {
return { node, children };
}
export function hasChildren<T>(t: Tree<T>): boolean {
return t.children.length !== 0;
}
export function preorder<T>(t: Tree<T>): T[] {
return [t.node, ...preorderF(t.children)];
}
export function preorderF<T>(ts: Forest<T>): T[] {
return concat(ts.map(preorder));
}
export function countNodes<T>(t: Tree<T>): number {
return preorder(t).length;
}
export function countNodesF<T>(ts: Forest<T>): number {
return sum(ts.map(countNodes));
}

View File

@@ -2,17 +2,26 @@ const push = require('web-push');
import * as mongo from 'mongodb';
import Subscription from './models/sw-subscription';
import config from './config';
import fetchMeta from './misc/fetch-meta';
import { IMeta } from './models/meta';
if (config.sw) {
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
push.setVapidDetails(
config.url,
config.sw.public_key,
config.sw.private_key);
}
let meta: IMeta = null;
setInterval(() => {
fetchMeta().then(m => {
meta = m;
if (meta.enableServiceWorker) {
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
push.setVapidDetails(config.url,
meta.swPublicKey,
meta.swPrivateKey);
}
});
}, 3000);
export default async function(userId: mongo.ObjectID | string, type: string, body?: any) {
if (!config.sw) return;
if (!meta.enableServiceWorker) return;
if (typeof userId === 'string') {
userId = new mongo.ObjectID(userId);

View File

@@ -18,7 +18,7 @@ export default async (actor: IRemoteUser, activity: ILike) => {
throw new Error();
}
let reaction = 'pudding';
let reaction = 'like';
// 他のMisskeyインスタンスからのリアクション
if (activity._misskey_reaction && validateReaction.ok(activity._misskey_reaction)) {

View File

@@ -181,6 +181,20 @@ export async function extractEmojis(tags: ITag[], host_: string) {
});
if (exists) {
if ((tag.updated != null && exists.updatedAt == null)
|| (tag.id != null && exists.uri == null)
|| (tag.updated != null && exists.updatedAt != null && new Date(tag.updated) > exists.updatedAt)) {
return await Emoji.findOneAndUpdate({
host,
name,
}, {
$set: {
uri: tag.id,
url: tag.icon.url,
updatedAt: new Date(tag.updated),
}
});
}
return exists;
}
@@ -189,8 +203,10 @@ export async function extractEmojis(tags: ITag[], host_: string) {
return await Emoji.insert({
host,
name,
uri: tag.id,
url: tag.icon.url,
aliases: [],
updatedAt: tag.updated ? new Date(tag.updated) : undefined,
aliases: []
});
})
);

View File

@@ -18,6 +18,7 @@ import Instance from '../../../models/instance';
import getDriveFileUrl from '../../../misc/get-drive-file-url';
import { IEmoji } from '../../../models/emoji';
import { ITag } from './tag';
import Following from '../../../models/following';
const log = debug('misskey:activitypub');
@@ -164,7 +165,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
publicKeyPem: person.publicKey.publicKeyPem
},
inbox: person.inbox,
sharedInbox: person.sharedInbox,
sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
featured: person.featured,
endpoints: person.endpoints,
uri: person.id,
@@ -340,7 +341,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
$set: {
lastFetchedAt: new Date(),
inbox: person.inbox,
sharedInbox: person.sharedInbox,
sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
featured: person.featured,
avatarId: avatar ? avatar._id : null,
bannerId: banner ? banner._id : null,
@@ -368,6 +369,15 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
}
});
// 該当ユーザーが既にフォロワーになっていた場合はFollowingもアップデートする
await Following.update({
followerId: exist._id
}, {
$set: {
'_follower.sharedInbox': person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined)
}
});
await updateFeatured(exist._id).catch(err => console.log(err));
}
@@ -431,7 +441,7 @@ export async function updateFeatured(userId: mongo.ObjectID) {
await User.update({ _id: user._id }, {
$set: {
pinnedNoteIds: featuredNotes.map(note => note._id)
pinnedNoteIds: featuredNotes.filter(note => note != null).map(note => note._id)
}
});
}

View File

@@ -1,4 +1,4 @@
import { IIcon } from "./icon";
import { IIcon } from './icon';
/***
* tag (ActivityPub)

View File

@@ -1,5 +1,5 @@
import config from '../../../config';
import { ILocalUser, IRemoteUser } from "../../../models/user";
import { ILocalUser, IRemoteUser } from '../../../models/user';
export default (blocker?: ILocalUser, blockee?: IRemoteUser) => ({
type: 'Block',

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