Compare commits
183 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
35273e53bc | ||
![]() |
bfc458e935 | ||
![]() |
bb819d42f1 | ||
![]() |
5d76439224 | ||
![]() |
3d0b704af8 | ||
![]() |
05539ffc7b | ||
![]() |
c86deab69c | ||
![]() |
21f8dbf2de | ||
![]() |
5174e16f7b | ||
![]() |
9b746f3eb5 | ||
![]() |
dfc6ef4be6 | ||
![]() |
c8b45f4f42 | ||
![]() |
09c57e6d03 | ||
![]() |
5edb1da097 | ||
![]() |
b3ad3a6535 | ||
![]() |
3709bb23bc | ||
![]() |
28be5c0b81 | ||
![]() |
60ef74047a | ||
![]() |
f81596c8d5 | ||
![]() |
075b7e3060 | ||
![]() |
cc7d6198ec | ||
![]() |
5766c2ce1b | ||
![]() |
03fed08c03 | ||
![]() |
4662641feb | ||
![]() |
00e2ce9489 | ||
![]() |
c81eb49f9e | ||
![]() |
fa03c172f2 | ||
![]() |
89ac15b4de | ||
![]() |
10d3b81251 | ||
![]() |
71dceca225 | ||
![]() |
40de631d95 | ||
![]() |
6985c39874 | ||
![]() |
0938ea3964 | ||
![]() |
4b4c19b242 | ||
![]() |
d8620187ec | ||
![]() |
520849d070 | ||
![]() |
b6a028a8ed | ||
![]() |
7db799a0ac | ||
![]() |
1ab776c867 | ||
![]() |
f4c9f63548 | ||
![]() |
08da9d70cd | ||
![]() |
96173e5c0b | ||
![]() |
b37cc70742 | ||
![]() |
96ee4299c7 | ||
![]() |
6072b02f12 | ||
![]() |
6ccbca0741 | ||
![]() |
360394fd5c | ||
![]() |
dcb45aa953 | ||
![]() |
a8fcc1aad9 | ||
![]() |
4d69cd86f1 | ||
![]() |
6e14e58b89 | ||
![]() |
af5839bb59 | ||
![]() |
a53e0d9f73 | ||
![]() |
49921f2dcf | ||
![]() |
70d2d61b9a | ||
![]() |
9abaf80f6b | ||
![]() |
25948fc3c9 | ||
![]() |
6b947c2139 | ||
![]() |
98acf919f1 | ||
![]() |
c9c2853150 | ||
![]() |
2bc708f8e6 | ||
![]() |
874b8fc3c2 | ||
![]() |
7d6aac3431 | ||
![]() |
e2fc7decad | ||
![]() |
21bed71f5e | ||
![]() |
747a5694f8 | ||
![]() |
479a0a2deb | ||
![]() |
14aef6ec89 | ||
![]() |
f0d2b3f449 | ||
![]() |
3b974428fc | ||
![]() |
580191fb17 | ||
![]() |
be0cb88b6c | ||
![]() |
95c4e4497e | ||
![]() |
2ec445f83e | ||
![]() |
51b915428e | ||
![]() |
1395cf89ce | ||
![]() |
2a8f984db7 | ||
![]() |
decf2d396f | ||
![]() |
f7964da899 | ||
![]() |
c8607ff7b6 | ||
![]() |
e9f8897fe2 | ||
![]() |
e0b107a3a0 | ||
![]() |
abf2c89931 | ||
![]() |
1d3e6a7197 | ||
![]() |
288bf195e9 | ||
![]() |
7e3cc11cc4 | ||
![]() |
4e07e94af0 | ||
![]() |
9cb49c9204 | ||
![]() |
580dd729e5 | ||
![]() |
49ab77c86e | ||
![]() |
f98914b9f1 | ||
![]() |
f3f3599b28 | ||
![]() |
f67b1beee4 | ||
![]() |
8395d0f1ba | ||
![]() |
af203bee93 | ||
![]() |
760fb79dad | ||
![]() |
ee9d4119c2 | ||
![]() |
90027efcbf | ||
![]() |
1848de1dc4 | ||
![]() |
1c93fcb1c4 | ||
![]() |
e3389e7899 | ||
![]() |
454632d785 | ||
![]() |
c9bca7dc85 | ||
![]() |
710ba526fa | ||
![]() |
aa47b6732d | ||
![]() |
20f83420ca | ||
![]() |
d09a68ef11 | ||
![]() |
b545be5799 | ||
![]() |
4fc377584f | ||
![]() |
a5f09c90dd | ||
![]() |
ba407c3eb0 | ||
![]() |
d059d7f972 | ||
![]() |
c03e2dfbc0 | ||
![]() |
45c5e7b967 | ||
![]() |
c81a94ff75 | ||
![]() |
acc6f54557 | ||
![]() |
8025b121af | ||
![]() |
78ec06bda3 | ||
![]() |
6ef83d9c59 | ||
![]() |
fca4ceef21 | ||
![]() |
00f979f0e6 | ||
![]() |
556677be7a | ||
![]() |
624fd093f2 | ||
![]() |
2ee438dece | ||
![]() |
534de24406 | ||
![]() |
014edce1b9 | ||
![]() |
ac1f3de4c6 | ||
![]() |
dced228cb0 | ||
![]() |
a92244cc12 | ||
![]() |
0717688933 | ||
![]() |
87d54b7d40 | ||
![]() |
ed51f5c7de | ||
![]() |
66e2db0d52 | ||
![]() |
03be4826df | ||
![]() |
c9d5aef04f | ||
![]() |
106cb3fe3e | ||
![]() |
48320f8536 | ||
![]() |
1a0845dc0a | ||
![]() |
185d09f3ed | ||
![]() |
8e25fb6cb7 | ||
![]() |
e88ce1746d | ||
![]() |
b8aad35009 | ||
![]() |
47bd485a39 | ||
![]() |
ad869d7469 | ||
![]() |
d15cce5337 | ||
![]() |
37daff6d61 | ||
![]() |
5417e40f59 | ||
![]() |
0fed33bfdb | ||
![]() |
5dddc75d09 | ||
![]() |
081578c604 | ||
![]() |
6c47bf5b76 | ||
![]() |
936bb1bcd0 | ||
![]() |
d5241d9a3e | ||
![]() |
05b4430c92 | ||
![]() |
292e911de2 | ||
![]() |
1c4ba2c037 | ||
![]() |
452db13d0c | ||
![]() |
c3f64b395b | ||
![]() |
3fa6bf93a4 | ||
![]() |
a13d76bec5 | ||
![]() |
05cee078d0 | ||
![]() |
706d3f3f95 | ||
![]() |
c5cf034b5d | ||
![]() |
3a04aa93f9 | ||
![]() |
838cdbedbd | ||
![]() |
9e85291cd3 | ||
![]() |
7f77517fc8 | ||
![]() |
b2f288dcac | ||
![]() |
52b59e9d7b | ||
![]() |
80c74b1fa7 | ||
![]() |
91811ea500 | ||
![]() |
57150fd910 | ||
![]() |
cddbbdf5d0 | ||
![]() |
423dc2349b | ||
![]() |
5229bbd55d | ||
![]() |
28311b9a2b | ||
![]() |
663d17a485 | ||
![]() |
08d005dfd9 | ||
![]() |
02edbc131b | ||
![]() |
0556a2a2da | ||
![]() |
65d943e42a | ||
![]() |
3bcb344ecb | ||
![]() |
82d721d60b |
@@ -108,13 +108,5 @@ autoAdmin: true
|
|||||||
# port: 9200
|
# port: 9200
|
||||||
# pass: null
|
# 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
|
# Clustering
|
||||||
#clusterLimit: 1
|
#clusterLimit: 1
|
||||||
|
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal 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
|
||||||
|
-
|
||||||
|
-->
|
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,6 +1,61 @@
|
|||||||
ChangeLog
|
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
|
10.64.2
|
||||||
-------
|
-------
|
||||||
* UIの動きを減らすオプションが一部のアニメーションに適用されなかったのを修正
|
* UIの動きを減らすオプションが一部のアニメーションに適用されなかったのを修正
|
||||||
|
@@ -25,3 +25,16 @@ Misskey uses [vue-i18n](https://github.com/kazupon/vue-i18n).
|
|||||||
## Continuous integration
|
## Continuous integration
|
||||||
Misskey uses CircleCI for automated test.
|
Misskey uses CircleCI for automated test.
|
||||||
Configuration files are located in `/.circleci`.
|
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_.
|
||||||
|
10
README.md
10
README.md
@@ -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/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/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/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>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
|
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=13376668">Arctic</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/Xeltica">Xeltica</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</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/gutfuckllc">gutfuckllc</a></td>
|
||||||
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
|
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<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://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/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/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/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/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/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>
|
</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=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/user?u=13039004">nemu</a></td>
|
||||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</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/acid_chicken">Acid Chicken</a></td>
|
||||||
<td><a href="https://www.patreon.com/hiratake">Hiratake</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/spinlock">Naoki Hirayama</a></td>
|
||||||
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<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/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/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>
|
<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>
|
</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/mastodon">Gargron</a></td>
|
||||||
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</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>
|
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
**Last updated:** Sun, 16 Dec 2018 18:32:06 UTC
|
**Last updated:** Tue, 25 Dec 2018 04:58:06 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
70
docs/examples/misskey.nginx
Normal file
70
docs/examples/misskey.nginx
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -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)
|
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.
|
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
|
*5.* Configure Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
|
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
|
||||||
|
@@ -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)
|
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.
|
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
|
*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`.
|
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le `default.yml`.
|
||||||
|
@@ -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)を確認
|
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の依存パッケージをインストール
|
5. `npm install` Misskeyの依存パッケージをインストール
|
||||||
|
|
||||||
*(オプション)* VAPIDキーペアの生成
|
|
||||||
----------------------------------------------------------------
|
|
||||||
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:
|
|
||||||
|
|
||||||
``` shell
|
|
||||||
npm install web-push -g
|
|
||||||
web-push generate-vapid-keys
|
|
||||||
```
|
|
||||||
|
|
||||||
*5.* 設定ファイルを作成する
|
*5.* 設定ファイルを作成する
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
|
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "確認中"
|
fetching: "確認中"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Laden"
|
fetching: "Laden"
|
||||||
no-broadcasts: "Keine Broadcasts"
|
no-broadcasts: "Keine Broadcasts"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Zwei-Faktor-Authentifizierung"
|
2fa: "Zwei-Faktor-Authentifizierung"
|
||||||
other: "Anderes"
|
other: "Anderes"
|
||||||
license: "Lizenz"
|
license: "Lizenz"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "Verhalten"
|
behaviour: "Verhalten"
|
||||||
fetch-on-scroll: "Aktualisieren beim scrollen"
|
fetch-on-scroll: "Aktualisieren beim scrollen"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -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?"
|
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:
|
intro:
|
||||||
title: "What is Misskey?"
|
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"
|
features: "Features"
|
||||||
rich-contents: "Post"
|
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!"
|
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"
|
pin: "Pin to your profile"
|
||||||
unpin: "Unpin"
|
unpin: "Unpin"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
delete-confirm: "Delete this post?"
|
delete-confirm: "Are you sure you want to delete this post?"
|
||||||
remote: "Show original note"
|
remote: "Show original note"
|
||||||
common/views/components/poll.vue:
|
common/views/components/poll.vue:
|
||||||
vote-to: "Vote for '{}'"
|
vote-to: "Vote for '{}'"
|
||||||
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "Email Address"
|
email-address: "Email Address"
|
||||||
email-verified: "Your email has been verified."
|
email-verified: "Your email has been verified."
|
||||||
email-not-verified: "Email address is not confirmed. Please check your inbox."
|
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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Checking"
|
fetching: "Checking"
|
||||||
no-broadcasts: "No announcements"
|
no-broadcasts: "No announcements"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Two-factor authentication"
|
2fa: "Two-factor authentication"
|
||||||
other: "Other"
|
other: "Other"
|
||||||
license: "License"
|
license: "License"
|
||||||
|
mark-as-read-all-unread-notes: "Mark all posts as read"
|
||||||
theme: "Theme"
|
theme: "Theme"
|
||||||
behaviour: "Behavior"
|
behaviour: "Behavior"
|
||||||
fetch-on-scroll: "Endless loading on scroll"
|
fetch-on-scroll: "Endless loading on scroll"
|
||||||
@@ -1014,7 +1022,7 @@ admin/views/instance.vue:
|
|||||||
save: "Save"
|
save: "Save"
|
||||||
saved: "Saved"
|
saved: "Saved"
|
||||||
user-recommendation-config: "Recommended users"
|
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: "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-engine-desc: "Example : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
||||||
external-user-recommendation-timeout: "Timeout"
|
external-user-recommendation-timeout: "Timeout"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTP Port"
|
smtp-port: "SMTP Port"
|
||||||
smtp-user: "SMTP User"
|
smtp-user: "SMTP User"
|
||||||
smtp-pass: "SMTP Password"
|
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:
|
admin/views/charts.vue:
|
||||||
title: "Chart"
|
title: "Chart"
|
||||||
per-day: "per Day"
|
per-day: "per Day"
|
||||||
@@ -1057,10 +1071,10 @@ admin/views/charts.vue:
|
|||||||
admin/views/drive.vue:
|
admin/views/drive.vue:
|
||||||
sort:
|
sort:
|
||||||
title: "Sort"
|
title: "Sort"
|
||||||
createdAtAsc: "アップロード日時が古い順"
|
createdAtAsc: "Age - Oldest First"
|
||||||
createdAtDesc: "アップロード日時が新しい順"
|
createdAtDesc: "Age - Newest First"
|
||||||
sizeAsc: "サイズが小さい順"
|
sizeAsc: "Size - Smallest First"
|
||||||
sizeDesc: "サイズが大きい順"
|
sizeDesc: "Size - Largest First"
|
||||||
origin:
|
origin:
|
||||||
title: "Origin"
|
title: "Origin"
|
||||||
combined: "Local + Remote"
|
combined: "Local + Remote"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "Remote"
|
remote: "Remote"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
deleted: "Deleted successfully"
|
deleted: "Deleted successfully"
|
||||||
|
mark-as-sensitive: "Mark as 'sensitive'"
|
||||||
|
unmark-as-sensitive: "Unmark as 'sensitive'"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "Operations"
|
operation: "Operations"
|
||||||
username-or-userid: "Username or user ID"
|
username-or-userid: "Username or user ID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "Sign out"
|
signout: "Sign out"
|
||||||
sound: "Sounds"
|
sound: "Sounds"
|
||||||
enable-sounds: "Enable sounds"
|
enable-sounds: "Enable sounds"
|
||||||
mark-as-read-all-unread-notes: "Mark all posts as read"
|
|
||||||
password: "Password"
|
password: "Password"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Follows you"
|
follows-you: "Follows you"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Recuperando"
|
fetching: "Recuperando"
|
||||||
no-broadcasts: "Sin emisión"
|
no-broadcasts: "Sin emisión"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Autenticación de Doble-Factor"
|
2fa: "Autenticación de Doble-Factor"
|
||||||
other: "Otros"
|
other: "Otros"
|
||||||
license: "Licencia"
|
license: "Licencia"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "Acciones"
|
behaviour: "Acciones"
|
||||||
fetch-on-scroll: "Desplazamiento infinito"
|
fetch-on-scroll: "Desplazamiento infinito"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -18,13 +18,13 @@ common:
|
|||||||
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
|
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
drive-desc: "以前投稿したことのある画像をまた投稿したくなったことはありませんか?もしくは、アップロードしたファイルをフォルダ分けして整理したくなったことはありませんか?Misskeyの根幹に組み込まれたドライブ機能によってそれらが解決します。ファイルの共有も簡単です。"
|
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 d’autres 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 d’autres instances afin de trouver vos amis si la présente instance ne vous correspond pas. Bonne chance et amusez-vous bien !"
|
||||||
adblock:
|
adblock:
|
||||||
detected: "Veuillez désactiver votre bloqueur de publicités"
|
detected: "Veuillez désactiver votre bloqueur de publicités"
|
||||||
warning: "<strong>Misskey n’utilise pas de publicités</strong>, mais quelques options peuvent être non disponibles ou fonctionneraient mal si un bloqueur de publicités est activé."
|
warning: "<strong>Misskey n’utilise 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 l’application"
|
application-authorization: "Autorisations de l’application"
|
||||||
close: "Fermer"
|
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"
|
load-more: "Charger plus"
|
||||||
enter-password: "Veuillez entrer le mot de passe"
|
enter-password: "Veuillez entrer le mot de passe"
|
||||||
got-it: "J’ai compris !"
|
got-it: "J’ai compris !"
|
||||||
@@ -39,18 +39,18 @@ common:
|
|||||||
reversi-invited-by: "Invité par {} :"
|
reversi-invited-by: "Invité par {} :"
|
||||||
notified-by: "Notifié par {} :"
|
notified-by: "Notifié par {} :"
|
||||||
reply-from: "Réponse de {} :"
|
reply-from: "Réponse de {} :"
|
||||||
quoted-by: "Cité·e par {} :"
|
quoted-by: "Cité par {} :"
|
||||||
time:
|
time:
|
||||||
unknown: "inconnu"
|
unknown: "inconnu"
|
||||||
future: "à l’instant"
|
future: "à l’instant"
|
||||||
just_now: "à l'instant"
|
just_now: "à l'instant"
|
||||||
seconds_ago: "Il y a {} seconde·s"
|
seconds_ago: "Il y a {} seconde(s)"
|
||||||
minutes_ago: "Il y a {} min"
|
minutes_ago: "Il y a {} min"
|
||||||
hours_ago: "Il y a {} h"
|
hours_ago: "Il y a {} h"
|
||||||
days_ago: "Il y a {} j"
|
days_ago: "Il y a {} j"
|
||||||
weeks_ago: "Il y a {} semaines"
|
weeks_ago: "Il y a {} semaines"
|
||||||
months_ago: "Il y a {} mois"
|
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}"
|
month-and-day: "{day}-{month}"
|
||||||
trash: "Corbeille"
|
trash: "Corbeille"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
@@ -86,10 +86,10 @@ common:
|
|||||||
public: "Public"
|
public: "Public"
|
||||||
home: "Principal"
|
home: "Principal"
|
||||||
home-desc: "Publier sur le fil principal uniquement"
|
home-desc: "Publier sur le fil principal uniquement"
|
||||||
followers: "Abonné·e·s"
|
followers: "Abonnés"
|
||||||
followers-desc: "Publier à vos abonné·e·s uniquement"
|
followers-desc: "Publier à vos abonnés uniquement"
|
||||||
specified: "Direct"
|
specified: "Direct"
|
||||||
specified-desc: "Publier uniquement aux utilisateurs·rices mentionnés·es"
|
specified-desc: "Publier uniquement aux utilisateurs mentionnés"
|
||||||
private: "Privé"
|
private: "Privé"
|
||||||
local-public: "Local (Public)"
|
local-public: "Local (Public)"
|
||||||
local-home: "Accueil (local uniquement)"
|
local-home: "Accueil (local uniquement)"
|
||||||
@@ -122,7 +122,7 @@ common:
|
|||||||
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
||||||
use-os-default-emojis: "Utiliser les émojis standards du système"
|
use-os-default-emojis: "Utiliser les émojis standards du système"
|
||||||
do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.'
|
do-not-use-in-production: 'Il s’agit d’une 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."
|
is-remote-post: "Ceci est une publication distante."
|
||||||
view-on-remote: " Consulter le profil complet"
|
view-on-remote: " Consulter le profil complet"
|
||||||
renoted-by: "Renoté par {user}"
|
renoted-by: "Renoté par {user}"
|
||||||
@@ -155,10 +155,10 @@ common:
|
|||||||
version: "Version"
|
version: "Version"
|
||||||
broadcast: "Diffusion"
|
broadcast: "Diffusion"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
users: "Utilisateur·rice·s"
|
users: "Utilisateurs recommandés"
|
||||||
polls: "Sondages"
|
polls: "Sondages"
|
||||||
post-form: "Champs de publication"
|
post-form: "Champs de publication"
|
||||||
server: "Info sur le serveur"
|
server: "Infos sur le serveur"
|
||||||
nav: "Navigation"
|
nav: "Navigation"
|
||||||
tips: "Conseils"
|
tips: "Conseils"
|
||||||
hashtags: "Hashtags"
|
hashtags: "Hashtags"
|
||||||
@@ -201,12 +201,12 @@ common/views/components/games/reversi/reversi.game.vue:
|
|||||||
can-put-everywhere: "Peut poser partout"
|
can-put-everywhere: "Peut poser partout"
|
||||||
common/views/components/games/reversi/reversi.index.vue:
|
common/views/components/games/reversi/reversi.index.vue:
|
||||||
title: "Misskey Reversi"
|
title: "Misskey Reversi"
|
||||||
sub-title: "Jouer à Reversi avec vos ami·e·s !"
|
sub-title: "Jouer à Reversi avec vos amis !"
|
||||||
invite: "Inviter"
|
invite: "Inviter"
|
||||||
rule: "Comment jouer ?"
|
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."
|
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: "Inviter"
|
||||||
mode-invite-desc: "Inviter un·e joueur·se."
|
mode-invite-desc: "Inviter un joueur."
|
||||||
invitations: "Vous avez reçu une invitation !"
|
invitations: "Vous avez reçu une invitation !"
|
||||||
my-games: "Mes jeux"
|
my-games: "Mes jeux"
|
||||||
all-games: "Tous les jeux"
|
all-games: "Tous les jeux"
|
||||||
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "Adresse de courrier électronique"
|
email-address: "Adresse de courrier électronique"
|
||||||
email-verified: "L’adresse du courrier électronique a été vérifiée."
|
email-verified: "L’adresse du courrier électronique a été vérifiée."
|
||||||
email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception."
|
email-not-verified: "Adresse de courriel n’est 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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Récupération"
|
fetching: "Récupération"
|
||||||
no-broadcasts: "Aucune annonce"
|
no-broadcasts: "Aucune annonce"
|
||||||
@@ -504,7 +511,7 @@ common/views/widgets/slideshow.vue:
|
|||||||
no-image: "Il n'y a aucune image dans ce dossier"
|
no-image: "Il n'y a aucune image dans ce dossier"
|
||||||
common/views/widgets/tips.vue:
|
common/views/widgets/tips.vue:
|
||||||
tips-line1: "<kbd>t</kbd>でタイムラインにフォーカスできます"
|
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-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-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"
|
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"
|
2fa: "Vérification en deux étapes"
|
||||||
other: "Autres"
|
other: "Autres"
|
||||||
license: "Licence"
|
license: "Licence"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "Thèmes"
|
theme: "Thèmes"
|
||||||
behaviour: "Comportement"
|
behaviour: "Comportement"
|
||||||
fetch-on-scroll: "Chargement lors du défilement"
|
fetch-on-scroll: "Chargement lors du défilement"
|
||||||
@@ -988,17 +996,17 @@ admin/views/instance.vue:
|
|||||||
recaptcha-site-key: "Clé reCAPTCHA du site"
|
recaptcha-site-key: "Clé reCAPTCHA du site"
|
||||||
recaptcha-secret-key: "Clé secrète reCAPTCHA"
|
recaptcha-secret-key: "Clé secrète reCAPTCHA"
|
||||||
twitter-integration-config: "Paramètres de connexion à Twitter"
|
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"
|
enable-twitter-integration: "Activer la connection à Twitter"
|
||||||
twitter-integration-consumer-key: "Clé du consommateur"
|
twitter-integration-consumer-key: "Clé du consommateur"
|
||||||
twitter-integration-consumer-secret: "Secret du consommateur"
|
twitter-integration-consumer-secret: "Secret du consommateur"
|
||||||
github-integration-config: "Paramètres d’authentification GitHub"
|
github-integration-config: "Paramètres d’authentification GitHub"
|
||||||
github-integration-info: "コールバックURLは {url} に設定します。"
|
github-integration-info: "L'URL de callback est {url}."
|
||||||
enable-github-integration: "Activer l’authentification avec Github"
|
enable-github-integration: "Activer l’authentification avec Github"
|
||||||
github-integration-client-id: "ID client"
|
github-integration-client-id: "ID client"
|
||||||
github-integration-client-secret: "Secret client"
|
github-integration-client-secret: "Secret client"
|
||||||
discord-integration-config: "Paramètres d’authentification Discord"
|
discord-integration-config: "Paramètres d’authentification Discord"
|
||||||
discord-integration-info: "コールバックURLは {url} に設定します。"
|
discord-integration-info: "L'URL de callback est {url}."
|
||||||
enable-discord-integration: "Activer l’authentification avec Discord"
|
enable-discord-integration: "Activer l’authentification avec Discord"
|
||||||
discord-integration-client-id: "ID client"
|
discord-integration-client-id: "ID client"
|
||||||
discord-integration-client-secret: "Secret client"
|
discord-integration-client-secret: "Secret client"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "Port SMTP"
|
smtp-port: "Port SMTP"
|
||||||
smtp-user: "Utilisateur SMTP"
|
smtp-user: "Utilisateur SMTP"
|
||||||
smtp-pass: "Mot de passe 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:
|
admin/views/charts.vue:
|
||||||
title: "Graph"
|
title: "Graph"
|
||||||
per-day: "par jour"
|
per-day: "par jour"
|
||||||
@@ -1057,8 +1071,8 @@ admin/views/charts.vue:
|
|||||||
admin/views/drive.vue:
|
admin/views/drive.vue:
|
||||||
sort:
|
sort:
|
||||||
title: "Tri"
|
title: "Tri"
|
||||||
createdAtAsc: "アップロード日時が古い順"
|
createdAtAsc: "Âge - Du plus ancien"
|
||||||
createdAtDesc: "アップロード日時が新しい順"
|
createdAtDesc: "Âge - Du plus récent"
|
||||||
sizeAsc: "Taille - Ascendant"
|
sizeAsc: "Taille - Ascendant"
|
||||||
sizeDesc: "Taille - Volumineux en premier"
|
sizeDesc: "Taille - Volumineux en premier"
|
||||||
origin:
|
origin:
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "Distant"
|
remote: "Distant"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
deleted: "Supprimé"
|
deleted: "Supprimé"
|
||||||
|
mark-as-sensitive: "Marquer comme sensible"
|
||||||
|
unmark-as-sensitive: "Ne pas marquer comme sensible"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "Actions"
|
operation: "Actions"
|
||||||
username-or-userid: "Nom d’utilisateur·rice ou ID utilisateur"
|
username-or-userid: "Nom d’utilisateur·rice ou ID utilisateur"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "Déconnexion"
|
signout: "Déconnexion"
|
||||||
sound: "Sons"
|
sound: "Sons"
|
||||||
enable-sounds: "Activer les sons"
|
enable-sounds: "Activer les sons"
|
||||||
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
|
|
||||||
password: "Mot de Passe"
|
password: "Mot de Passe"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Vous suit"
|
follows-you: "Vous suit"
|
||||||
@@ -1512,7 +1527,7 @@ docs:
|
|||||||
require-credential: "Ce point de communication nécessite une authentification."
|
require-credential: "Ce point de communication nécessite une authentification."
|
||||||
require-permission: "Ce point de communication nécessite la permission {permission}."
|
require-permission: "Ce point de communication nécessite la permission {permission}."
|
||||||
has-limit: "Il y’a un taux limite."
|
has-limit: "Il y’a 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."
|
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: "Vous pouvez voir le code source ce point de communication."
|
||||||
show-src-link: "Consulter le code sur GitHub"
|
show-src-link: "Consulter le code sur GitHub"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "確認中"
|
fetching: "確認中"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -519,6 +519,14 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "確認中"
|
fetching: "確認中"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -830,6 +838,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
|
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
@@ -1156,6 +1165,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
@@ -1197,6 +1212,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
|
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
@@ -1357,6 +1374,7 @@ desktop/views/pages/user/user.timeline.vue:
|
|||||||
default: "投稿"
|
default: "投稿"
|
||||||
with-replies: "投稿と返信"
|
with-replies: "投稿と返信"
|
||||||
with-media: "メディア"
|
with-media: "メディア"
|
||||||
|
my-posts: "私の投稿"
|
||||||
empty: "このユーザーはまだ何も投稿していないようです。"
|
empty: "このユーザーはまだ何も投稿していないようです。"
|
||||||
|
|
||||||
desktop/views/widgets/messaging.vue:
|
desktop/views/widgets/messaging.vue:
|
||||||
@@ -1625,7 +1643,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
|
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "このメールアドレスOKや!"
|
email-verified: "このメールアドレスOKや!"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "見てみるわ…"
|
fetching: "見てみるわ…"
|
||||||
no-broadcasts: "お知らせはあらへんで"
|
no-broadcasts: "お知らせはあらへんで"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "動き"
|
behaviour: "動き"
|
||||||
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "さいなら"
|
signout: "さいなら"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンド鳴らす"
|
enable-sounds: "サウンド鳴らす"
|
||||||
mark-as-read-all-unread-notes: "全部もう読んだわ"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされとるで"
|
follows-you: "フォローされとるで"
|
||||||
|
@@ -354,7 +354,7 @@ common/views/components/reaction-picker.vue:
|
|||||||
choose-reaction: "반응 선택"
|
choose-reaction: "반응 선택"
|
||||||
common/views/components/emoji-picker.vue:
|
common/views/components/emoji-picker.vue:
|
||||||
custom-emoji: "커스텀 이모지"
|
custom-emoji: "커스텀 이모지"
|
||||||
people: "명"
|
people: "사람들"
|
||||||
animals-and-nature: "동물 & 자연"
|
animals-and-nature: "동물 & 자연"
|
||||||
food-and-drink: "음식 & 음료"
|
food-and-drink: "음식 & 음료"
|
||||||
activity: "활동"
|
activity: "활동"
|
||||||
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "메일 주소"
|
email-address: "메일 주소"
|
||||||
email-verified: "매일 주소가 확인되었습니다"
|
email-verified: "매일 주소가 확인되었습니다"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "확인중"
|
fetching: "확인중"
|
||||||
no-broadcasts: "공지사항이 없습니다"
|
no-broadcasts: "공지사항이 없습니다"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "2단계 인증"
|
2fa: "2단계 인증"
|
||||||
other: "기타"
|
other: "기타"
|
||||||
license: "라이선스"
|
license: "라이선스"
|
||||||
|
mark-as-read-all-unread-notes: "모든 글을 읽은 상태로 표시"
|
||||||
theme: "테마"
|
theme: "테마"
|
||||||
behaviour: "동작"
|
behaviour: "동작"
|
||||||
fetch-on-scroll: "스크롤하여 자동으로 불러오기"
|
fetch-on-scroll: "스크롤하여 자동으로 불러오기"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTP 포트"
|
smtp-port: "SMTP 포트"
|
||||||
smtp-user: "SMTP 사용자"
|
smtp-user: "SMTP 사용자"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "차트"
|
title: "차트"
|
||||||
per-day: "1일마다"
|
per-day: "1일마다"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "리모트"
|
remote: "리모트"
|
||||||
delete: "삭제"
|
delete: "삭제"
|
||||||
deleted: "삭제하였습니다"
|
deleted: "삭제하였습니다"
|
||||||
|
mark-as-sensitive: "열람주의로 설정"
|
||||||
|
unmark-as-sensitive: "열람주의 해제"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "작업"
|
operation: "작업"
|
||||||
username-or-userid: "사용자명 혹은 사용자 ID"
|
username-or-userid: "사용자명 혹은 사용자 ID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "로그아웃"
|
signout: "로그아웃"
|
||||||
sound: "소리"
|
sound: "소리"
|
||||||
enable-sounds: "소리 사용"
|
enable-sounds: "소리 사용"
|
||||||
mark-as-read-all-unread-notes: "모든 글을 읽은 상태로 표시"
|
|
||||||
password: "비밀번호"
|
password: "비밀번호"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "당신을 팔로우합니다"
|
follows-you: "당신을 팔로우합니다"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Bezig met ophalen"
|
fetching: "Bezig met ophalen"
|
||||||
no-broadcasts: "Geen uitzendingen"
|
no-broadcasts: "Geen uitzendingen"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Authenticatie in twee stappen"
|
2fa: "Authenticatie in twee stappen"
|
||||||
other: "Overig"
|
other: "Overig"
|
||||||
license: "Licentie"
|
license: "Licentie"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "Gedrag"
|
behaviour: "Gedrag"
|
||||||
fetch-on-scroll: "Ophalen bij scrollen"
|
fetch-on-scroll: "Ophalen bij scrollen"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "Uitloggen"
|
signout: "Uitloggen"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Volgt jou"
|
follows-you: "Volgt jou"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Henter"
|
fetching: "Henter"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "To-faktor autentisering"
|
2fa: "To-faktor autentisering"
|
||||||
other: "Annet"
|
other: "Annet"
|
||||||
license: "Lisens"
|
license: "Lisens"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "Utseende"
|
theme: "Utseende"
|
||||||
behaviour: "Oppførsel"
|
behaviour: "Oppførsel"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "Lyder"
|
sound: "Lyder"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "Adres e-mail"
|
email-address: "Adres e-mail"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Sprawdzanie"
|
fetching: "Sprawdzanie"
|
||||||
no-broadcasts: "Brak transmisji"
|
no-broadcasts: "Brak transmisji"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Uwierzytelnianie dwuetapowe"
|
2fa: "Uwierzytelnianie dwuetapowe"
|
||||||
other: "Inne"
|
other: "Inne"
|
||||||
license: "Licencja"
|
license: "Licencja"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "Motyw"
|
theme: "Motyw"
|
||||||
behaviour: "Zachowanie"
|
behaviour: "Zachowanie"
|
||||||
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
|
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "Usuń"
|
delete: "Usuń"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "Wyloguj"
|
signout: "Wyloguj"
|
||||||
sound: "Dźwięk"
|
sound: "Dźwięk"
|
||||||
enable-sounds: "Włącz dźwięk"
|
enable-sounds: "Włącz dźwięk"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "Hasło"
|
password: "Hasło"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Śledzi Cię"
|
follows-you: "Śledzi Cię"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "確認中"
|
fetching: "確認中"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "Sair"
|
signout: "Sair"
|
||||||
sound: "Sons"
|
sound: "Sons"
|
||||||
enable-sounds: "Ativar sons"
|
enable-sounds: "Ativar sons"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "Te segue"
|
follows-you: "Te segue"
|
||||||
|
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "確認中"
|
fetching: "確認中"
|
||||||
no-broadcasts: "お知らせはありません"
|
no-broadcasts: "お知らせはありません"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTPポート"
|
smtp-port: "SMTPポート"
|
||||||
smtp-user: "SMTPユーザー"
|
smtp-user: "SMTPユーザー"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "チャート"
|
title: "チャート"
|
||||||
per-day: "1日ごと"
|
per-day: "1日ごと"
|
||||||
@@ -1068,6 +1082,8 @@ admin/views/drive.vue:
|
|||||||
remote: "リモート"
|
remote: "リモート"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
deleted: "削除しました"
|
deleted: "削除しました"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "ユーザー名またはユーザーID"
|
username-or-userid: "ユーザー名またはユーザーID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "サインアウト"
|
signout: "サインアウト"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされています"
|
||||||
|
@@ -113,7 +113,7 @@ common:
|
|||||||
use-white-black-reversi-stones: "リバーシに白黒の石を使う"
|
use-white-black-reversi-stones: "リバーシに白黒の石を使う"
|
||||||
verified-user: "认证用户"
|
verified-user: "认证用户"
|
||||||
disable-animated-mfm: "在帖子中禁用动画文本"
|
disable-animated-mfm: "在帖子中禁用动画文本"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
|
||||||
always-show-nsfw: "总是显示 NSFW 的内容"
|
always-show-nsfw: "总是显示 NSFW 的内容"
|
||||||
always-mark-nsfw: "总是用 NSFW 来标记附件"
|
always-mark-nsfw: "总是用 NSFW 来标记附件"
|
||||||
show-full-acct: "不要从用户名中忽略主机名"
|
show-full-acct: "不要从用户名中忽略主机名"
|
||||||
@@ -164,7 +164,7 @@ common:
|
|||||||
hashtags: "标签"
|
hashtags: "标签"
|
||||||
dev: "构建应用程序失败,请再试一次。"
|
dev: "构建应用程序失败,请再试一次。"
|
||||||
ai-chan-kawaii: "Ai-chan kawaii!"
|
ai-chan-kawaii: "Ai-chan kawaii!"
|
||||||
you: "あなた"
|
you: "您"
|
||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "您要允许<i>{name}</i>来访问您的账户吗?"
|
share-access: "您要允许<i>{name}</i>来访问您的账户吗?"
|
||||||
permission-ask: "这个应用程序需要以下权限:"
|
permission-ask: "这个应用程序需要以下权限:"
|
||||||
@@ -298,7 +298,7 @@ common/views/components/cw-button.vue:
|
|||||||
hide: "隐藏"
|
hide: "隐藏"
|
||||||
show: "查看更多"
|
show: "查看更多"
|
||||||
chars: "{count}文字"
|
chars: "{count}文字"
|
||||||
files: "{count}ファイル"
|
files: "{count} 个文件"
|
||||||
common/views/components/messaging.vue:
|
common/views/components/messaging.vue:
|
||||||
search-user: "查找用户"
|
search-user: "查找用户"
|
||||||
you: "您"
|
you: "您"
|
||||||
@@ -405,8 +405,8 @@ common/views/components/stream-indicator.vue:
|
|||||||
connected: "已连接"
|
connected: "已连接"
|
||||||
common/views/components/integration-settings.vue:
|
common/views/components/integration-settings.vue:
|
||||||
title: "サービス連携"
|
title: "サービス連携"
|
||||||
connect: "接続する"
|
connect: "连接"
|
||||||
disconnect: "切断する"
|
disconnect: "未连接"
|
||||||
connected-to: "次のアカウントに接続されています"
|
connected-to: "次のアカウントに接続されています"
|
||||||
common/views/components/github-setting.vue:
|
common/views/components/github-setting.vue:
|
||||||
description: "当您用GitHub连接Misskey账户后,您将能够看到有关您自己的信息,并且您将能够使用GitHub登录。"
|
description: "当您用GitHub连接Misskey账户后,您将能够看到有关您自己的信息,并且您将能够使用GitHub登录。"
|
||||||
@@ -453,7 +453,7 @@ common/views/components/profile-editor.vue:
|
|||||||
account: "账户"
|
account: "账户"
|
||||||
location: "位置"
|
location: "位置"
|
||||||
description: "关于我"
|
description: "关于我"
|
||||||
language: "言語"
|
language: "语言"
|
||||||
birthday: "生日"
|
birthday: "生日"
|
||||||
avatar: "头像"
|
avatar: "头像"
|
||||||
banner: "背景"
|
banner: "背景"
|
||||||
@@ -471,6 +471,13 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "电子邮件地址"
|
email-address: "电子邮件地址"
|
||||||
email-verified: "电子邮件地址已验证"
|
email-verified: "电子邮件地址已验证"
|
||||||
email-not-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:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "确认中"
|
fetching: "确认中"
|
||||||
no-broadcasts: "没有公告"
|
no-broadcasts: "没有公告"
|
||||||
@@ -524,7 +531,7 @@ common/views/widgets/tips.vue:
|
|||||||
tips-line24: "Misskey自2014年开始运营。"
|
tips-line24: "Misskey自2014年开始运营。"
|
||||||
tips-line25: "在与通知功能兼容的浏览器中,您可以在Misskey未打开的情况下接收通知"
|
tips-line25: "在与通知功能兼容的浏览器中,您可以在Misskey未打开的情况下接收通知"
|
||||||
common/views/pages/404.vue:
|
common/views/pages/404.vue:
|
||||||
page-not-found: "ページが見つかりませんでした"
|
page-not-found: "您要找的网页不存在。"
|
||||||
common/views/pages/follow.vue:
|
common/views/pages/follow.vue:
|
||||||
signed-in-as: "用 {}登录"
|
signed-in-as: "用 {}登录"
|
||||||
following: "正在关注"
|
following: "正在关注"
|
||||||
@@ -737,6 +744,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "两步验证"
|
2fa: "两步验证"
|
||||||
other: "其他"
|
other: "其他"
|
||||||
license: "许可证"
|
license: "许可证"
|
||||||
|
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||||
theme: "主题"
|
theme: "主题"
|
||||||
behaviour: "行为"
|
behaviour: "行为"
|
||||||
fetch-on-scroll: "向下滚动时自动加载"
|
fetch-on-scroll: "向下滚动时自动加载"
|
||||||
@@ -780,7 +788,7 @@ desktop/views/components/settings.vue:
|
|||||||
deck-column-width: "デッキのカラムの幅"
|
deck-column-width: "デッキのカラムの幅"
|
||||||
deck-column-width-narrow: "狭"
|
deck-column-width-narrow: "狭"
|
||||||
deck-column-width-narrower: "やや狭"
|
deck-column-width-narrower: "やや狭"
|
||||||
deck-column-width-normal: "普通"
|
deck-column-width-normal: "正常"
|
||||||
deck-column-width-wider: "やや広"
|
deck-column-width-wider: "やや広"
|
||||||
deck-column-width-wide: "広"
|
deck-column-width-wide: "広"
|
||||||
sound: "声音"
|
sound: "声音"
|
||||||
@@ -877,16 +885,16 @@ common/views/components/password-settings.vue:
|
|||||||
enter-new-password-again: "请再次输入新密码"
|
enter-new-password-again: "请再次输入新密码"
|
||||||
not-match: "新密码不匹配"
|
not-match: "新密码不匹配"
|
||||||
changed: "密码已更改"
|
changed: "密码已更改"
|
||||||
failed: "パスワード変更に失敗しました"
|
failed: "更改密码失败"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "这个帖子是私密的"
|
private: "这个帖子是私密的"
|
||||||
deleted: "帖子已删除"
|
deleted: "帖子已删除"
|
||||||
media-count: "附加{}媒体"
|
media-count: "附加{}媒体"
|
||||||
poll: "投票"
|
poll: "投票"
|
||||||
desktop/views/components/settings.tags.vue:
|
desktop/views/components/settings.tags.vue:
|
||||||
title: "タグ"
|
title: "标签"
|
||||||
query: "クエリ (省略可)"
|
query: "查询 (可选)"
|
||||||
add: "追加"
|
add: "添加"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
desktop/views/components/taskmanager.vue:
|
desktop/views/components/taskmanager.vue:
|
||||||
title: "任务管理器"
|
title: "任务管理器"
|
||||||
@@ -970,7 +978,7 @@ admin/views/instance.vue:
|
|||||||
instance-description: "实例介绍"
|
instance-description: "实例介绍"
|
||||||
host: "主机名"
|
host: "主机名"
|
||||||
banner-url: "背景图片地址"
|
banner-url: "背景图片地址"
|
||||||
error-image-url: "エラー画像URL"
|
error-image-url: "无效的图像URL"
|
||||||
languages: "实例语言"
|
languages: "实例语言"
|
||||||
languages-desc: "您可以添加多个,以空格分隔。"
|
languages-desc: "您可以添加多个,以空格分隔。"
|
||||||
maintainer-config: "管理员信息"
|
maintainer-config: "管理员信息"
|
||||||
@@ -1029,6 +1037,12 @@ admin/views/instance.vue:
|
|||||||
smtp-port: "SMTP 端口"
|
smtp-port: "SMTP 端口"
|
||||||
smtp-user: "SMTP 用户名"
|
smtp-user: "SMTP 用户名"
|
||||||
smtp-pass: "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:
|
admin/views/charts.vue:
|
||||||
title: "历史记录"
|
title: "历史记录"
|
||||||
per-day: "每天"
|
per-day: "每天"
|
||||||
@@ -1056,18 +1070,20 @@ admin/views/charts.vue:
|
|||||||
network-usage: "网络流量"
|
network-usage: "网络流量"
|
||||||
admin/views/drive.vue:
|
admin/views/drive.vue:
|
||||||
sort:
|
sort:
|
||||||
title: "ソート"
|
title: "排序"
|
||||||
createdAtAsc: "アップロード日時が古い順"
|
createdAtAsc: "アップロード日時が古い順"
|
||||||
createdAtDesc: "アップロード日時が新しい順"
|
createdAtDesc: "アップロード日時が新しい順"
|
||||||
sizeAsc: "サイズが小さい順"
|
sizeAsc: "サイズが小さい順"
|
||||||
sizeDesc: "サイズが大きい順"
|
sizeDesc: "サイズが大きい順"
|
||||||
origin:
|
origin:
|
||||||
title: "オリジン"
|
title: "源自"
|
||||||
combined: "ローカル+リモート"
|
combined: "本地+远程"
|
||||||
local: "ローカル"
|
local: "本地"
|
||||||
remote: "リモート"
|
remote: "远程"
|
||||||
delete: "削除"
|
delete: "删除"
|
||||||
deleted: "削除しました"
|
deleted: "已删除"
|
||||||
|
mark-as-sensitive: "标记为“敏感”"
|
||||||
|
unmark-as-sensitive: "取消标记为“敏感”"
|
||||||
admin/views/users.vue:
|
admin/views/users.vue:
|
||||||
operation: "操作"
|
operation: "操作"
|
||||||
username-or-userid: "用户名或用户ID"
|
username-or-userid: "用户名或用户ID"
|
||||||
@@ -1430,7 +1446,6 @@ mobile/views/pages/settings.vue:
|
|||||||
signout: "注销"
|
signout: "注销"
|
||||||
sound: "声音"
|
sound: "声音"
|
||||||
enable-sounds: "开启声音"
|
enable-sounds: "开启声音"
|
||||||
mark-as-read-all-unread-notes: "将所有帖子标记为已读"
|
|
||||||
password: "密码"
|
password: "密码"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "关注您"
|
follows-you: "关注您"
|
||||||
|
30
package.json
30
package.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.64.2",
|
"version": "10.67.0",
|
||||||
"clientVersion": "2.0.12796",
|
"clientVersion": "2.0.12978",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.8",
|
"@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-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",
|
"@fortawesome/vue-fontawesome": "0.1.2",
|
||||||
"@koa/cors": "2.2.2",
|
"@koa/cors": "2.2.2",
|
||||||
"@prezzemolo/rap": "0.1.2",
|
"@prezzemolo/rap": "0.1.2",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"@types/deep-equal": "1.0.1",
|
"@types/deep-equal": "1.0.1",
|
||||||
"@types/double-ended-queue": "2.1.0",
|
"@types/double-ended-queue": "2.1.0",
|
||||||
"@types/elasticsearch": "5.0.29",
|
"@types/elasticsearch": "5.0.29",
|
||||||
"@types/file-type": "5.2.2",
|
"@types/file-type": "10.6.0",
|
||||||
"@types/gulp": "3.8.36",
|
"@types/gulp": "3.8.36",
|
||||||
"@types/gulp-mocha": "0.0.32",
|
"@types/gulp-mocha": "0.0.32",
|
||||||
"@types/gulp-rename": "0.0.33",
|
"@types/gulp-rename": "0.0.33",
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
"@types/tinycolor2": "1.4.1",
|
"@types/tinycolor2": "1.4.1",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"@types/uuid": "3.4.4",
|
"@types/uuid": "3.4.4",
|
||||||
"@types/webpack": "4.4.20",
|
"@types/webpack": "4.4.21",
|
||||||
"@types/webpack-stream": "3.2.10",
|
"@types/webpack-stream": "3.2.10",
|
||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
@@ -114,6 +114,7 @@
|
|||||||
"eslint": "5.8.0",
|
"eslint": "5.8.0",
|
||||||
"eslint-plugin-vue": "4.7.1",
|
"eslint-plugin-vue": "4.7.1",
|
||||||
"eventemitter3": "3.1.0",
|
"eventemitter3": "3.1.0",
|
||||||
|
"feed": "2.0.2",
|
||||||
"file-loader": "2.0.0",
|
"file-loader": "2.0.0",
|
||||||
"file-type": "10.6.0",
|
"file-type": "10.6.0",
|
||||||
"fuckadblock": "3.2.1",
|
"fuckadblock": "3.2.1",
|
||||||
@@ -126,18 +127,18 @@
|
|||||||
"gulp-sourcemaps": "2.6.4",
|
"gulp-sourcemaps": "2.6.4",
|
||||||
"gulp-stylus": "2.7.0",
|
"gulp-stylus": "2.7.0",
|
||||||
"gulp-tslint": "8.1.3",
|
"gulp-tslint": "8.1.3",
|
||||||
"gulp-typescript": "4.0.2",
|
"gulp-typescript": "5.0.0",
|
||||||
"gulp-uglify": "3.0.1",
|
"gulp-uglify": "3.0.1",
|
||||||
"gulp-util": "3.0.8",
|
"gulp-util": "3.0.8",
|
||||||
"gulp-yaml": "2.0.2",
|
"gulp-yaml": "2.0.2",
|
||||||
"hard-source-webpack-plugin": "0.12.0",
|
"hard-source-webpack-plugin": "0.13.1",
|
||||||
"html-minifier": "3.5.21",
|
"html-minifier": "3.5.21",
|
||||||
"http-signature": "1.2.0",
|
"http-signature": "1.2.0",
|
||||||
"insert-text-at-cursor": "0.1.1",
|
"insert-text-at-cursor": "0.1.1",
|
||||||
"is-root": "2.0.0",
|
"is-root": "2.0.0",
|
||||||
"is-url": "1.2.4",
|
"is-url": "1.2.4",
|
||||||
"js-yaml": "3.12.0",
|
"js-yaml": "3.12.0",
|
||||||
"jsdom": "13.0.0",
|
"jsdom": "13.1.0",
|
||||||
"json5": "2.1.0",
|
"json5": "2.1.0",
|
||||||
"json5-loader": "1.0.1",
|
"json5-loader": "1.0.1",
|
||||||
"katex": "0.10.0",
|
"katex": "0.10.0",
|
||||||
@@ -160,7 +161,7 @@
|
|||||||
"mocha": "5.2.0",
|
"mocha": "5.2.0",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"moment": "2.22.2",
|
"moment": "2.22.2",
|
||||||
"mongodb": "3.1.9",
|
"mongodb": "3.1.10",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.11.1",
|
"nan": "2.11.1",
|
||||||
@@ -192,7 +193,7 @@
|
|||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"seedrandom": "2.4.4",
|
"seedrandom": "2.4.4",
|
||||||
"sharp": "0.21.0",
|
"sharp": "0.21.1",
|
||||||
"showdown": "1.9.0",
|
"showdown": "1.9.0",
|
||||||
"showdown-highlightjs-extension": "0.1.2",
|
"showdown-highlightjs-extension": "0.1.2",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
@@ -201,7 +202,7 @@
|
|||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
"stylus-loader": "3.0.2",
|
"stylus-loader": "3.0.2",
|
||||||
"summaly": "2.2.0",
|
"summaly": "2.2.0",
|
||||||
"systeminformation": "3.51.3",
|
"systeminformation": "3.52.2",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"terser-webpack-plugin": "1.1.0",
|
"terser-webpack-plugin": "1.1.0",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
@@ -209,7 +210,8 @@
|
|||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"ts-loader": "5.3.1",
|
"ts-loader": "5.3.1",
|
||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.10.0",
|
"tslint": "5.12.0",
|
||||||
|
"tslint-sonarts": "1.8.0",
|
||||||
"typescript": "3.2.2",
|
"typescript": "3.2.2",
|
||||||
"typescript-eslint-parser": "21.0.2",
|
"typescript-eslint-parser": "21.0.2",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
@@ -219,7 +221,7 @@
|
|||||||
"vue": "2.5.17",
|
"vue": "2.5.17",
|
||||||
"vue-color": "2.7.0",
|
"vue-color": "2.7.0",
|
||||||
"vue-content-loading": "1.5.3",
|
"vue-content-loading": "1.5.3",
|
||||||
"vue-cropperjs": "2.2.2",
|
"vue-cropperjs": "3.0.0",
|
||||||
"vue-i18n": "8.3.2",
|
"vue-i18n": "8.3.2",
|
||||||
"vue-js-modal": "1.3.27",
|
"vue-js-modal": "1.3.27",
|
||||||
"vue-loader": "15.4.2",
|
"vue-loader": "15.4.2",
|
||||||
|
@@ -69,7 +69,7 @@ export default Vue.extend({
|
|||||||
display block
|
display block
|
||||||
padding 12px 16px 16px 16px
|
padding 12px 16px 16px 16px
|
||||||
height 250px
|
height 250px
|
||||||
overflow hidden
|
overflow auto
|
||||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||||
background var(--adminDashboardCardBg)
|
background var(--adminDashboardCardBg)
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
|
@@ -39,7 +39,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="file._open">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</sequential-entrance>
|
</sequential-entrance>
|
||||||
@@ -53,7 +57,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import { faCloud } from '@fortawesome/free-solid-svg-icons';
|
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({
|
export default Vue.extend({
|
||||||
i18n: i18n('admin/views/drive.vue'),
|
i18n: i18n('admin/views/drive.vue'),
|
||||||
@@ -66,7 +70,7 @@ export default Vue.extend({
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
files: [],
|
files: [],
|
||||||
existMore: false,
|
existMore: false,
|
||||||
faCloud, faTrashAlt
|
faCloud, faTrashAlt, faEye, faEyeSlash
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,7 +136,16 @@ export default Vue.extend({
|
|||||||
text: e.toString()
|
text: e.toString()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
toggleSensitive(file: any) {
|
||||||
|
this.$root.api('drive/files/update', {
|
||||||
|
fileId: file.id,
|
||||||
|
isSensitive: !file.isSensitive
|
||||||
|
});
|
||||||
|
|
||||||
|
file.isSensitive = !file.isSensitive;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -57,6 +57,15 @@
|
|||||||
</ui-horizon-group>
|
</ui-horizon-group>
|
||||||
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<span slot="desc">{{ $t('smtp-secure-info') }}</span></ui-switch>
|
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<span slot="desc">{{ $t('smtp-secure-info') }}</span></ui-switch>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<header>summaly Proxy</header>
|
<header>summaly Proxy</header>
|
||||||
<ui-input v-model="summalyProxy">URL</ui-input>
|
<ui-input v-model="summalyProxy">URL</ui-input>
|
||||||
@@ -126,7 +135,7 @@ import Vue from 'vue';
|
|||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import { url, host } from '../../config';
|
import { url, host } from '../../config';
|
||||||
import { toUnicode } from 'punycode';
|
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';
|
import { faEnvelope as farEnvelope } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
@@ -174,7 +183,10 @@ export default Vue.extend({
|
|||||||
smtpPort: null,
|
smtpPort: null,
|
||||||
smtpUser: null,
|
smtpUser: null,
|
||||||
smtpPass: 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.smtpPort = meta.smtpPort;
|
||||||
this.smtpUser = meta.smtpUser;
|
this.smtpUser = meta.smtpUser;
|
||||||
this.smtpPass = meta.smtpPass;
|
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,
|
smtpHost: this.smtpHost,
|
||||||
smtpPort: parseInt(this.smtpPort, 10),
|
smtpPort: parseInt(this.smtpPort, 10),
|
||||||
smtpUser: this.smtpUser,
|
smtpUser: this.smtpUser,
|
||||||
smtpPass: this.smtpPass
|
smtpPass: this.smtpPass,
|
||||||
|
enableServiceWorker: this.enableServiceWorker,
|
||||||
|
swPublicKey: this.swPublicKey,
|
||||||
|
swPrivateKey: this.swPrivateKey
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
@@ -22,7 +22,7 @@ export default function(type, data): Notification {
|
|||||||
|
|
||||||
case 'unreadMessagingMessage':
|
case 'unreadMessagingMessage':
|
||||||
return {
|
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),
|
body: data.text, // TODO: getMessagingMessageSummary(data),
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
};
|
};
|
||||||
@@ -30,7 +30,7 @@ export default function(type, data): Notification {
|
|||||||
case 'reversiInvited':
|
case 'reversiInvited':
|
||||||
return {
|
return {
|
||||||
title: '%i18n:common.notification.reversi-invited%',
|
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
|
icon: data.parent.avatarUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,21 +38,21 @@ export default function(type, data): Notification {
|
|||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case 'mention':
|
case 'mention':
|
||||||
return {
|
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),
|
body: getNoteSummary(data),
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'reply':
|
case 'reply':
|
||||||
return {
|
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),
|
body: getNoteSummary(data),
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'quote':
|
case 'quote':
|
||||||
return {
|
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),
|
body: getNoteSummary(data),
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
};
|
};
|
||||||
|
@@ -15,7 +15,7 @@ export default function(sec) {
|
|||||||
const t
|
const t
|
||||||
= tod < 60 ? `${Math.floor(tod)} sec`
|
= tod < 60 ? `${Math.floor(tod)} sec`
|
||||||
: tod < 3600 ? `${Math.floor(tod / 60)} min`
|
: 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 = '';
|
let str = '';
|
||||||
if (d) str += `${d}, `;
|
if (d) str += `${d}, `;
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
export default (data: ArrayBuffer) => {
|
export default (data: ArrayBuffer) => {
|
||||||
//const buf = new Buffer(data);
|
//const buf = new Buffer(data);
|
||||||
//const hash = crypto.createHash("md5");
|
//const hash = crypto.createHash('md5');
|
||||||
//hash.update(buf);
|
//hash.update(buf);
|
||||||
//return hash.digest("hex");
|
//return hash.digest('hex');
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
@@ -80,8 +80,8 @@ export default (opts: Opts = {}) => ({
|
|||||||
const ast = parse(this.appearNote.text);
|
const ast = parse(this.appearNote.text);
|
||||||
// TODO: 再帰的にURL要素がないか調べる
|
// TODO: 再帰的にURL要素がないか調べる
|
||||||
return unique(ast
|
return unique(ast
|
||||||
.filter(t => ((t.name == 'url' || t.name == 'link') && t.props.url && !t.props.silent))
|
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent))
|
||||||
.map(t => t.props.url));
|
.map(t => t.node.props.url));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -95,6 +95,7 @@ export default prop => ({
|
|||||||
Vue.set(this.$_ns_target.reactionCounts, reaction, 0);
|
Vue.set(this.$_ns_target.reactionCounts, reaction, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment the count
|
||||||
this.$_ns_target.reactionCounts[reaction]++;
|
this.$_ns_target.reactionCounts[reaction]++;
|
||||||
|
|
||||||
if (body.userId == this.$store.state.i.id) {
|
if (body.userId == this.$store.state.i.id) {
|
||||||
@@ -103,6 +104,26 @@ export default prop => ({
|
|||||||
break;
|
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': {
|
case 'pollVoted': {
|
||||||
if (body.userId == this.$store.state.i.id) return;
|
if (body.userId == this.$store.state.i.id) return;
|
||||||
const choice = body.choice;
|
const choice = body.choice;
|
||||||
|
@@ -75,7 +75,7 @@ export default Vue.extend({
|
|||||||
return this.dark ? '#fff' : '#777';
|
return this.dark ? '#fff' : '#777';
|
||||||
},
|
},
|
||||||
hHandColor(): string {
|
hHandColor(): string {
|
||||||
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--themeColor')).toHexString();
|
return tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--primary')).toHexString();
|
||||||
},
|
},
|
||||||
|
|
||||||
ms(): number {
|
ms(): number {
|
||||||
|
@@ -48,7 +48,7 @@ export default Vue.extend({
|
|||||||
iconAndText(): any[] {
|
iconAndText(): any[] {
|
||||||
return (
|
return (
|
||||||
(this.hasPendingFollowRequestFromYou && this.user.isLocked) ? ['hourglass-half', this.$t('request-pending')] :
|
(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) ? ['minus', this.$t('following')] :
|
||||||
(!this.isFollowing && this.user.isLocked) ? ['plus', this.$t('follow-request')] :
|
(!this.isFollowing && this.user.isLocked) ? ['plus', this.$t('follow-request')] :
|
||||||
(!this.isFollowing && !this.user.isLocked) ? ['plus', this.$t('follow')] :
|
(!this.isFollowing && !this.user.isLocked) ? ['plus', this.$t('follow')] :
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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="me" v-if="isMe">{{ $t('@.you') }}</span>
|
||||||
<span class="main">
|
<span class="main">
|
||||||
<span class="username">@{{ username }}</span>
|
<span class="username">@{{ username }}</span>
|
||||||
|
@@ -85,7 +85,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (items[0].kind == 'file') {
|
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;
|
return;
|
||||||
} else if (e.dataTransfer.files.length > 1) {
|
} else if (e.dataTransfer.files.length > 1) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
alert('%i18n:only-one-file-attached%');
|
alert(this.$t('only-one-file-attached'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,9 +3,9 @@
|
|||||||
<mk-avatar class="avatar" :user="message.user" target="_blank"/>
|
<mk-avatar class="avatar" :user="message.user" target="_blank"/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="balloon" :data-no-text="message.text == null">
|
<div class="balloon" :data-no-text="message.text == null">
|
||||||
<!-- <button class="delete-button" v-if="isMe" :title="$t('@.delete')">
|
<button class="delete-button" v-if="isMe" :title="$t('@.delete')" @click="del">
|
||||||
<img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
|
<img src="/assets/desktop/remove.png" alt="Delete"/>
|
||||||
</button> -->
|
</button>
|
||||||
<div class="content" v-if="!message.isDeleted">
|
<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"/>
|
<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">
|
<div class="file" v-if="message.file">
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" v-if="message.isDeleted">
|
<div class="content" v-else>
|
||||||
<p class="is-deleted">{{ $t('deleted') }}</p>
|
<p class="is-deleted">{{ $t('deleted') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,12 +52,19 @@ export default Vue.extend({
|
|||||||
if (this.message.text) {
|
if (this.message.text) {
|
||||||
const ast = parse(this.message.text);
|
const ast = parse(this.message.text);
|
||||||
return unique(ast
|
return unique(ast
|
||||||
.filter(t => ((t.name == 'url' || t.name == 'link') && t.props.url && !t.silent))
|
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent))
|
||||||
.map(t => t.props.url));
|
.map(t => t.node.props.url));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
del() {
|
||||||
|
this.$root.api('messaging/messages/delete', {
|
||||||
|
messageId: this.message.id
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -79,6 +79,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
this.connection.on('read', this.onRead);
|
this.connection.on('read', this.onRead);
|
||||||
|
this.connection.on('deleted', this.onDeleted);
|
||||||
|
|
||||||
if (this.isNaked) {
|
if (this.isNaked) {
|
||||||
window.addEventListener('scroll', this.onScroll, { passive: true });
|
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() {
|
isBottom() {
|
||||||
const asobi = 64;
|
const asobi = 64;
|
||||||
const current = this.isNaked
|
const current = this.isNaked
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import Vue, { VNode } from 'vue';
|
import Vue, { VNode } from 'vue';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { Node } from '../../../../../mfm/parser';
|
import { MfmForest } from '../../../../../mfm/parser';
|
||||||
import parse from '../../../../../mfm/parse';
|
import parse from '../../../../../mfm/parse';
|
||||||
import MkUrl from './url.vue';
|
import MkUrl from './url.vue';
|
||||||
import MkMention from './mention.vue';
|
import MkMention from './mention.vue';
|
||||||
@@ -9,16 +9,11 @@ import MkFormula from './formula.vue';
|
|||||||
import MkGoogle from './google.vue';
|
import MkGoogle from './google.vue';
|
||||||
import syntaxHighlight from '../../../../../mfm/syntax-highlight';
|
import syntaxHighlight from '../../../../../mfm/syntax-highlight';
|
||||||
import { host } from '../../../config';
|
import { host } from '../../../config';
|
||||||
|
import { preorderF, countNodesF } from '../../../../../prelude/tree';
|
||||||
|
|
||||||
function getTextCount(tokens: Node[]): number {
|
function sumTextsLength(ts: MfmForest): number {
|
||||||
const rootCount = sum(tokens.filter(x => x.name === 'text').map(x => length(x.props.text)));
|
const textNodes = preorderF(ts).filter(n => n.type === 'text');
|
||||||
const childrenCount = sum(tokens.filter(x => x.children).map(x => getTextCount(x.children)));
|
return sum(textNodes.map(x => length(x.props.text)));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vue.component('misskey-flavored-markdown', {
|
export default Vue.component('misskey-flavored-markdown', {
|
||||||
@@ -27,10 +22,6 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
ast: {
|
|
||||||
type: [],
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
shouldBreak: {
|
shouldBreak: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
@@ -55,17 +46,15 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
render(createElement) {
|
render(createElement) {
|
||||||
if (this.text == null || this.text == '') return;
|
if (this.text == null || this.text == '') return;
|
||||||
|
|
||||||
const ast = this.ast == null ?
|
const ast = parse(this.text, this.plainText);
|
||||||
parse(this.text, this.plainText) : // Parse text to ast
|
|
||||||
this.ast as Node[];
|
|
||||||
|
|
||||||
let bigCount = 0;
|
let bigCount = 0;
|
||||||
let motionCount = 0;
|
let motionCount = 0;
|
||||||
|
|
||||||
const genEl = (ast: Node[]) => concat(ast.map((token): VNode[] => {
|
const genEl = (ast: MfmForest) => concat(ast.map((token): VNode[] => {
|
||||||
switch (token.name) {
|
switch (token.node.type) {
|
||||||
case 'text': {
|
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) {
|
if (this.shouldBreak) {
|
||||||
const x = text.split('\n')
|
const x = text.split('\n')
|
||||||
@@ -95,7 +84,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
|
|
||||||
case 'big': {
|
case 'big': {
|
||||||
bigCount++;
|
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;
|
const isMany = bigCount > 3;
|
||||||
return (createElement as any)('strong', {
|
return (createElement as any)('strong', {
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -122,7 +111,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
|
|
||||||
case 'motion': {
|
case 'motion': {
|
||||||
motionCount++;
|
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;
|
const isMany = motionCount > 3;
|
||||||
return (createElement as any)('span', {
|
return (createElement as any)('span', {
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -139,7 +128,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement(MkUrl, {
|
return [createElement(MkUrl, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
props: {
|
props: {
|
||||||
url: token.props.url,
|
url: token.node.props.url,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
style: 'color:var(--mfmLink);'
|
style: 'color:var(--mfmLink);'
|
||||||
}
|
}
|
||||||
@@ -150,9 +139,9 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement('a', {
|
return [createElement('a', {
|
||||||
attrs: {
|
attrs: {
|
||||||
class: 'link',
|
class: 'link',
|
||||||
href: token.props.url,
|
href: token.node.props.url,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
title: token.props.url,
|
title: token.node.props.url,
|
||||||
style: 'color:var(--mfmLink);'
|
style: 'color:var(--mfmLink);'
|
||||||
}
|
}
|
||||||
}, genEl(token.children))];
|
}, genEl(token.children))];
|
||||||
@@ -162,8 +151,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement(MkMention, {
|
return [createElement(MkMention, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
props: {
|
props: {
|
||||||
host: (token.props.host == null && this.author && this.author.host != null ? this.author.host : token.props.host) || host,
|
host: (token.node.props.host == null && this.author && this.author.host != null ? this.author.host : token.node.props.host) || host,
|
||||||
username: token.props.username
|
username: token.node.props.username
|
||||||
}
|
}
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
@@ -172,10 +161,10 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement('router-link', {
|
return [createElement('router-link', {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
attrs: {
|
attrs: {
|
||||||
to: `/tags/${encodeURIComponent(token.props.hashtag)}`,
|
to: `/tags/${encodeURIComponent(token.node.props.hashtag)}`,
|
||||||
style: 'color:var(--mfmHashtag);'
|
style: 'color:var(--mfmHashtag);'
|
||||||
}
|
}
|
||||||
}, `#${token.props.hashtag}`)];
|
}, `#${token.node.props.hashtag}`)];
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'blockCode': {
|
case 'blockCode': {
|
||||||
@@ -184,7 +173,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
}, [
|
}, [
|
||||||
createElement('code', {
|
createElement('code', {
|
||||||
domProps: {
|
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': {
|
case 'inlineCode': {
|
||||||
return [createElement('code', {
|
return [createElement('code', {
|
||||||
domProps: {
|
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', {
|
return [createElement('mk-emoji', {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
attrs: {
|
attrs: {
|
||||||
emoji: token.props.emoji,
|
emoji: token.node.props.emoji,
|
||||||
name: token.props.name
|
name: token.node.props.name
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
customEmojis: this.customEmojis || customEmojis,
|
customEmojis: this.customEmojis || customEmojis,
|
||||||
@@ -242,7 +231,7 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement(MkFormula, {
|
return [createElement(MkFormula, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
props: {
|
props: {
|
||||||
formula: token.props.formula
|
formula: token.node.props.formula
|
||||||
}
|
}
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
@@ -252,13 +241,13 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement(MkGoogle, {
|
return [createElement(MkGoogle, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
props: {
|
props: {
|
||||||
q: token.props.query
|
q: token.node.props.query
|
||||||
}
|
}
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
console.log('unknown ast type:', token.name);
|
console.log('unknown ast type:', token.node.type);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
</ui-input>
|
</ui-input>
|
||||||
|
|
||||||
<ui-input v-model="birthday" type="date">
|
<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>
|
<span slot="prefix"><fa icon="birthday-cake"/></span>
|
||||||
</ui-input>
|
</ui-input>
|
||||||
|
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-reactions-viewer">
|
<div class="mk-reactions-viewer">
|
||||||
<template v-if="reactions">
|
<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 == '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="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 == '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="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 == '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="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 == '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="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 == '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="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 == '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="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 == '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="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 == '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="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 == '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="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 == 'pudding' }" @click="toggleReaction('pudding')" v-if="reactions.pudding" v-particle><mk-reaction-icon reaction="pudding" ref="pudding"/><span>{{ reactions.pudding }}</span></span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -60,14 +60,29 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
react(reaction: string) {
|
toggleReaction(reaction: string) {
|
||||||
this.$root.api('notes/reactions/create', {
|
const oldReaction = this.note.myReaction;
|
||||||
noteId: this.note.id,
|
if (oldReaction) {
|
||||||
reaction: reaction
|
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) {
|
anime(reaction: string) {
|
||||||
if (this.$store.state.device.reduceMotion) return;
|
if (this.$store.state.device.reduceMotion) return;
|
||||||
|
if (document.hidden) return;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const rect = this.$refs[reaction].$el.getBoundingClientRect();
|
const rect = this.$refs[reaction].$el.getBoundingClientRect();
|
||||||
|
@@ -26,6 +26,7 @@ import { toUnicode } from 'punycode';
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/signin.vue'),
|
i18n: i18n('common/views/components/signin.vue'),
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
withAvatar: {
|
withAvatar: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -33,6 +34,7 @@ export default Vue.extend({
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
signing: false,
|
signing: false,
|
||||||
@@ -45,11 +47,13 @@ export default Vue.extend({
|
|||||||
meta: null
|
meta: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.$root.getMeta().then(meta => {
|
this.$root.getMeta().then(meta => {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onUsernameChange() {
|
onUsernameChange() {
|
||||||
this.$root.api('users/show', {
|
this.$root.api('users/show', {
|
||||||
@@ -60,6 +64,7 @@ export default Vue.extend({
|
|||||||
this.user = null;
|
this.user = null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.signing = true;
|
this.signing = true;
|
||||||
|
|
||||||
@@ -80,8 +85,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.mk-signin
|
.mk-signin
|
||||||
color #555
|
color #555
|
||||||
|
|
||||||
|
@@ -50,6 +50,7 @@ import { toUnicode } from 'punycode';
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/signup.vue'),
|
i18n: i18n('common/views/components/signup.vue'),
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
host: toUnicode(host),
|
host: toUnicode(host),
|
||||||
@@ -64,6 +65,7 @@ export default Vue.extend({
|
|||||||
meta: null
|
meta: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
shouldShowProfileUrl(): boolean {
|
shouldShowProfileUrl(): boolean {
|
||||||
return (this.username != '' &&
|
return (this.username != '' &&
|
||||||
@@ -72,17 +74,20 @@ export default Vue.extend({
|
|||||||
this.usernameState != 'max-range');
|
this.usernameState != 'max-range');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.$root.getMeta().then(meta => {
|
this.$root.getMeta().then(meta => {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
const head = document.getElementsByTagName('head')[0];
|
const head = document.getElementsByTagName('head')[0];
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
|
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
|
||||||
head.appendChild(script);
|
head.appendChild(script);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onChangeUsername() {
|
onChangeUsername() {
|
||||||
if (this.username == '') {
|
if (this.username == '') {
|
||||||
@@ -111,6 +116,7 @@ export default Vue.extend({
|
|||||||
this.usernameState = 'error';
|
this.usernameState = 'error';
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangePassword() {
|
onChangePassword() {
|
||||||
if (this.password == '') {
|
if (this.password == '') {
|
||||||
this.passwordStrength = '';
|
this.passwordStrength = '';
|
||||||
@@ -120,6 +126,7 @@ export default Vue.extend({
|
|||||||
const strength = getPasswordStrength(this.password);
|
const strength = getPasswordStrength(this.password);
|
||||||
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
|
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangePasswordRetype() {
|
onChangePasswordRetype() {
|
||||||
if (this.retypedPassword == '') {
|
if (this.retypedPassword == '') {
|
||||||
this.passwordRetypeState = null;
|
this.passwordRetypeState = null;
|
||||||
@@ -128,6 +135,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match';
|
this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match';
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.$root.api('signup', {
|
this.$root.api('signup', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
@@ -138,8 +146,9 @@ export default Vue.extend({
|
|||||||
this.$root.api('signin', {
|
this.$root.api('signin', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password
|
password: this.password
|
||||||
}, true).then(() => {
|
}, true).then(res => {
|
||||||
location.href = '/';
|
localStorage.setItem('i', res.i);
|
||||||
|
location.reload();
|
||||||
});
|
});
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
alert(this.$t('some-error'));
|
alert(this.$t('some-error'));
|
||||||
@@ -154,8 +163,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.mk-signup
|
.mk-signup
|
||||||
min-width 302px
|
min-width 302px
|
||||||
</style>
|
</style>
|
||||||
|
@@ -33,14 +33,7 @@ export default Vue.extend({
|
|||||||
return typeof this.time == 'string' ? new Date(this.time) : this.time;
|
return typeof this.time == 'string' ? new Date(this.time) : this.time;
|
||||||
},
|
},
|
||||||
absolute(): string {
|
absolute(): string {
|
||||||
const time = this._time;
|
return this._time.toLocaleString();
|
||||||
return (
|
|
||||||
time.getFullYear() + '年' +
|
|
||||||
(time.getMonth() + 1) + '月' +
|
|
||||||
time.getDate() + '日' +
|
|
||||||
' ' +
|
|
||||||
time.getHours() + '時' +
|
|
||||||
time.getMinutes() + '分');
|
|
||||||
},
|
},
|
||||||
relative(): string {
|
relative(): string {
|
||||||
const time = this._time;
|
const time = this._time;
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
<div class="value" ref="passwordMetar"></div>
|
<div class="value" ref="passwordMetar"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="label" ref="label"><slot></slot></span>
|
<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>
|
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
|
||||||
<template v-if="type != 'file'">
|
<template v-if="type != 'file'">
|
||||||
<input ref="input"
|
<input ref="input"
|
||||||
@@ -281,6 +282,20 @@ root(fill)
|
|||||||
transform-origin top left
|
transform-origin top left
|
||||||
transform scale(1)
|
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
|
> input
|
||||||
display block
|
display block
|
||||||
width 100%
|
width 100%
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
<header>
|
<header>
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
</header>
|
</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>
|
<footer>
|
||||||
<img class="icon" v-if="icon" :src="icon"/>
|
<img class="icon" v-if="icon" :src="icon"/>
|
||||||
<p>{{ sitename }}</p>
|
<p>{{ sitename }}</p>
|
||||||
|
150
src/client/app/common/views/components/user-list-editor.vue
Normal file
150
src/client/app/common/views/components/user-list-editor.vue
Normal 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>
|
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="text">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -25,6 +25,7 @@ class Autocomplete {
|
|||||||
private opts: {
|
private opts: {
|
||||||
model: string;
|
model: string;
|
||||||
};
|
};
|
||||||
|
private opening: boolean;
|
||||||
|
|
||||||
private get text(): string {
|
private get text(): string {
|
||||||
return this.vm[this.opts.model];
|
return this.vm[this.opts.model];
|
||||||
@@ -48,6 +49,7 @@ class Autocomplete {
|
|||||||
this.textarea = textarea;
|
this.textarea = textarea;
|
||||||
this.vm = vm;
|
this.vm = vm;
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
|
this.opening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,6 +130,8 @@ class Autocomplete {
|
|||||||
if (type != this.currentType) {
|
if (type != this.currentType) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
|
if (this.opening) return;
|
||||||
|
this.opening = true;
|
||||||
this.currentType = type;
|
this.currentType = type;
|
||||||
|
|
||||||
//#region サジェストを表示すべき位置を計算
|
//#region サジェストを表示すべき位置を計算
|
||||||
@@ -143,6 +147,8 @@ class Autocomplete {
|
|||||||
this.suggestion.x = x;
|
this.suggestion.x = x;
|
||||||
this.suggestion.y = y;
|
this.suggestion.y = y;
|
||||||
this.suggestion.q = q;
|
this.suggestion.q = q;
|
||||||
|
|
||||||
|
this.opening = false;
|
||||||
} else {
|
} else {
|
||||||
const MkAutocomplete = await import('../components/autocomplete.vue').then(m => m.default);
|
const MkAutocomplete = await import('../components/autocomplete.vue').then(m => m.default);
|
||||||
|
|
||||||
@@ -162,6 +168,8 @@ class Autocomplete {
|
|||||||
|
|
||||||
// 要素追加
|
// 要素追加
|
||||||
document.body.appendChild(this.suggestion.$el);
|
document.body.appendChild(this.suggestion.$el);
|
||||||
|
|
||||||
|
this.opening = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
:disabled="followWait">
|
:disabled="followWait">
|
||||||
<template v-if="!followWait">
|
<template v-if="!followWait">
|
||||||
<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> {{ $t('request-pending') }}</template>
|
<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"><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-request') }}</template>
|
||||||
<template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> {{ $t('follow') }}</template>
|
<template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> {{ $t('follow') }}</template>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { apiUrl } from '../../config';
|
import { apiUrl, locale } from '../../config';
|
||||||
import CropWindow from '../views/components/crop-window.vue';
|
import CropWindow from '../views/components/crop-window.vue';
|
||||||
import ProgressDialog from '../views/components/progress-dialog.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)$');
|
const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
|
||||||
if (!regex.test(file.name) ) {
|
if (!regex.test(file.name) ) {
|
||||||
$root.dialog({
|
$root.dialog({
|
||||||
title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
|
title: locale['desktop']['invalid-filetype'],
|
||||||
text: null
|
text: null
|
||||||
});
|
});
|
||||||
return reject('invalid-filetype');
|
return reject('invalid-filetype');
|
||||||
@@ -17,7 +17,7 @@ export default ($root: any) => {
|
|||||||
|
|
||||||
const w = $root.new(CropWindow, {
|
const w = $root.new(CropWindow, {
|
||||||
image: file,
|
image: file,
|
||||||
title: '%i18n:desktop.avatar-crop-title%',
|
title: locale['desktop']['avatar-crop-title'],
|
||||||
aspectRatio: 1 / 1
|
aspectRatio: 1 / 1
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ export default ($root: any) => {
|
|||||||
data.append('file', blob, file.name + '.cropped.png');
|
data.append('file', blob, file.name + '.cropped.png');
|
||||||
|
|
||||||
$root.api('drive/folders/find', {
|
$root.api('drive/folders/find', {
|
||||||
name: '%i18n:desktop.avatar%'
|
name: locale['desktop']['avatar']
|
||||||
}).then(avatarFolder => {
|
}).then(avatarFolder => {
|
||||||
if (avatarFolder.length === 0) {
|
if (avatarFolder.length === 0) {
|
||||||
$root.api('drive/folders/create', {
|
$root.api('drive/folders/create', {
|
||||||
name: '%i18n:desktop.avatar%'
|
name: locale['desktop']['avatar']
|
||||||
}).then(iconFolder => {
|
}).then(iconFolder => {
|
||||||
resolve(upload(data, iconFolder));
|
resolve(upload(data, iconFolder));
|
||||||
});
|
});
|
||||||
@@ -52,7 +52,7 @@ export default ($root: any) => {
|
|||||||
|
|
||||||
const upload = (data, folder) => new Promise((resolve, reject) => {
|
const upload = (data, folder) => new Promise((resolve, reject) => {
|
||||||
const dialog = $root.new(ProgressDialog, {
|
const dialog = $root.new(ProgressDialog, {
|
||||||
title: '%i18n:desktop.uploading-avatar%'
|
title: locale['desktop']['uploading-avatar']
|
||||||
});
|
});
|
||||||
document.body.appendChild(dialog.$el);
|
document.body.appendChild(dialog.$el);
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ export default ($root: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$root.dialog({
|
$root.dialog({
|
||||||
title: '%fa:info-circle% %i18n:desktop.avatar-updated%',
|
title: locale['desktop']['avatar-updated'],
|
||||||
text: null
|
text: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export default ($root: any) => {
|
|||||||
? Promise.resolve(file)
|
? Promise.resolve(file)
|
||||||
: $root.$chooseDriveFile({
|
: $root.$chooseDriveFile({
|
||||||
multiple: false,
|
multiple: false,
|
||||||
title: '%fa:image% %i18n:desktop.choose-avatar%'
|
title: locale['desktop']['choose-avatar']
|
||||||
});
|
});
|
||||||
|
|
||||||
return selectedFile
|
return selectedFile
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { apiUrl } from '../../config';
|
import { apiUrl, locale } from '../../config';
|
||||||
import CropWindow from '../views/components/crop-window.vue';
|
import CropWindow from '../views/components/crop-window.vue';
|
||||||
import ProgressDialog from '../views/components/progress-dialog.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)$');
|
const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
|
||||||
if (!regex.test(file.name) ) {
|
if (!regex.test(file.name) ) {
|
||||||
$root.dialog({
|
$root.dialog({
|
||||||
title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
|
title: locale['desktop']['invalid-filetype'],
|
||||||
text: null
|
text: null
|
||||||
});
|
});
|
||||||
return reject('invalid-filetype');
|
return reject('invalid-filetype');
|
||||||
@@ -17,7 +17,7 @@ export default ($root: any) => {
|
|||||||
|
|
||||||
const w = $root.new(CropWindow, {
|
const w = $root.new(CropWindow, {
|
||||||
image: file,
|
image: file,
|
||||||
title: '%i18n:desktop.banner-crop-title%',
|
title: locale['desktop']['banner-crop-title'],
|
||||||
aspectRatio: 16 / 9
|
aspectRatio: 16 / 9
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ export default ($root: any) => {
|
|||||||
data.append('file', blob, file.name + '.cropped.png');
|
data.append('file', blob, file.name + '.cropped.png');
|
||||||
|
|
||||||
$root.api('drive/folders/find', {
|
$root.api('drive/folders/find', {
|
||||||
name: '%i18n:desktop.banner%'
|
name: locale['desktop']['banner']
|
||||||
}).then(bannerFolder => {
|
}).then(bannerFolder => {
|
||||||
if (bannerFolder.length === 0) {
|
if (bannerFolder.length === 0) {
|
||||||
$root.api('drive/folders/create', {
|
$root.api('drive/folders/create', {
|
||||||
name: '%i18n:desktop.banner%'
|
name: locale['desktop']['banner']
|
||||||
}).then(iconFolder => {
|
}).then(iconFolder => {
|
||||||
resolve(upload(data, iconFolder));
|
resolve(upload(data, iconFolder));
|
||||||
});
|
});
|
||||||
@@ -52,7 +52,7 @@ export default ($root: any) => {
|
|||||||
|
|
||||||
const upload = (data, folder) => new Promise((resolve, reject) => {
|
const upload = (data, folder) => new Promise((resolve, reject) => {
|
||||||
const dialog = $root.new(ProgressDialog, {
|
const dialog = $root.new(ProgressDialog, {
|
||||||
title: '%i18n:desktop.uploading-banner%'
|
title: locale['desktop']['uploading-banner']
|
||||||
});
|
});
|
||||||
document.body.appendChild(dialog.$el);
|
document.body.appendChild(dialog.$el);
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ export default ($root: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$root.dialog({
|
$root.dialog({
|
||||||
title: '%fa:info-circle% %i18n:desktop.banner-updated%',
|
title: locale['desktop']['banner-updated'],
|
||||||
text: null
|
text: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export default ($root: any) => {
|
|||||||
? Promise.resolve(file)
|
? Promise.resolve(file)
|
||||||
: $root.$chooseDriveFile({
|
: $root.$chooseDriveFile({
|
||||||
multiple: false,
|
multiple: false,
|
||||||
title: '%fa:image% %i18n:desktop.choose-banner%'
|
title: locale['desktop']['choose-banner']
|
||||||
});
|
});
|
||||||
|
|
||||||
return selectedFile
|
return selectedFile
|
||||||
|
@@ -23,7 +23,9 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -37,7 +39,9 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -50,7 +54,9 @@
|
|||||||
<mk-user-name :user="notification.note.user"/>
|
<mk-user-name :user="notification.note.user"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -84,7 +90,9 @@
|
|||||||
<mk-user-name :user="notification.note.user"/>
|
<mk-user-name :user="notification.note.user"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -96,7 +104,9 @@
|
|||||||
<mk-user-name :user="notification.note.user"/>
|
<mk-user-name :user="notification.note.user"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -107,7 +117,9 @@
|
|||||||
<mk-user-name :user="notification.user"/>
|
<mk-user-name :user="notification.user"/>
|
||||||
</a></p>
|
</a></p>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -74,6 +74,7 @@ import { host } from '../../../config';
|
|||||||
import { erase, unique } from '../../../../../prelude/array';
|
import { erase, unique } from '../../../../../prelude/array';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { toASCII } from 'punycode';
|
import { toASCII } from 'punycode';
|
||||||
|
import extractMentions from '../../../../../misc/extract-mentions';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('desktop/views/components/post-form.vue'),
|
i18n: i18n('desktop/views/components/post-form.vue'),
|
||||||
@@ -184,8 +185,7 @@ export default Vue.extend({
|
|||||||
if (this.reply && this.reply.text != null) {
|
if (this.reply && this.reply.text != null) {
|
||||||
const ast = parse(this.reply.text);
|
const ast = parse(this.reply.text);
|
||||||
|
|
||||||
// TODO: 新しいMFMパーサに対応
|
for (const x of extractMentions(ast)) {
|
||||||
for (const x of ast.filter(t => t.type == 'mention')) {
|
|
||||||
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
||||||
|
|
||||||
// 自分は除外
|
// 自分は除外
|
||||||
@@ -207,9 +207,8 @@ export default Vue.extend({
|
|||||||
this.visibility = this.reply.visibility;
|
this.visibility = this.reply.visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ダイレクトへのリプライはリプライ先ユーザーを初期設定
|
if (this.reply) {
|
||||||
if (this.reply && this.reply.visibility === 'specified') {
|
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
|
||||||
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
|
|
||||||
this.visibleUsers.push(user);
|
this.visibleUsers.push(user);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -236,7 +235,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
trimmedLength(text: string) {
|
trimmedLength(text: string) {
|
||||||
return length(text.trim());
|
return length(text.trim());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -92,6 +92,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import MkUserListsWindow from './user-lists-window.vue';
|
import MkUserListsWindow from './user-lists-window.vue';
|
||||||
|
import MkUserListWindow from './user-list-window.vue';
|
||||||
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
||||||
import MkSettingsWindow from './settings-window.vue';
|
import MkSettingsWindow from './settings-window.vue';
|
||||||
import MkDriveWindow from './drive-window.vue';
|
import MkDriveWindow from './drive-window.vue';
|
||||||
@@ -143,7 +144,9 @@ export default Vue.extend({
|
|||||||
this.close();
|
this.close();
|
||||||
const w = this.$root.new(MkUserListsWindow);
|
const w = this.$root.new(MkUserListsWindow);
|
||||||
w.$once('choosen', list => {
|
w.$once('choosen', list => {
|
||||||
this.$router.push(`i/lists/${ list.id }`);
|
this.$root.new(MkUserListWindow, {
|
||||||
|
list
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
followRequests() {
|
followRequests() {
|
||||||
|
@@ -14,16 +14,34 @@ export default Vue.extend({
|
|||||||
i18n: i18n('desktop/views/components/ui.header.search.vue'),
|
i18n: i18n('desktop/views/components/ui.header.search.vue'),
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
q: ''
|
q: '',
|
||||||
|
wait: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSubmit() {
|
async onSubmit() {
|
||||||
|
if (this.wait) return;
|
||||||
|
|
||||||
const q = this.q.trim();
|
const q = this.q.trim();
|
||||||
if (q.startsWith('@')) {
|
if (q.startsWith('@')) {
|
||||||
this.$router.push(`/${q}`);
|
this.$router.push(`/${q}`);
|
||||||
} else if (q.startsWith('#')) {
|
} else if (q.startsWith('#')) {
|
||||||
this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`);
|
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 {
|
} else {
|
||||||
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
|
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
|
||||||
}
|
}
|
||||||
|
24
src/client/app/desktop/views/components/user-list-window.vue
Normal file
24
src/client/app/desktop/views/components/user-list-window.vue
Normal 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>
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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>
|
<span slot="header"><fa icon="list"/> {{ $t('title') }}</span>
|
||||||
|
|
||||||
<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">
|
<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">
|
||||||
|
@@ -627,6 +627,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
> .content
|
> .content
|
||||||
height 100%
|
height 100%
|
||||||
|
overflow auto
|
||||||
|
|
||||||
&:not([flexible])
|
&:not([flexible])
|
||||||
> .main > .body > .content
|
> .main > .body > .content
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/>
|
<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">
|
<template v-for="(note, i) in _notes">
|
||||||
<x-note
|
<x-note
|
||||||
:note="note"
|
:note="note"
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
|
<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</transition-group>
|
</component>
|
||||||
|
|
||||||
<footer v-if="more">
|
<footer v-if="more">
|
||||||
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||||
|
@@ -11,7 +11,8 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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"/>
|
<fa icon="quote-right"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +29,9 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,7 +73,9 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
<h1>#{{ $route.params.tag }}</h1>
|
<h1>#{{ $route.params.tag }}</h1>
|
||||||
</header>
|
</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-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -24,9 +24,14 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
const image = [
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif'
|
||||||
|
];
|
||||||
this.$root.api('users/notes', {
|
this.$root.api('users/notes', {
|
||||||
userId: this.user.id,
|
userId: this.user.id,
|
||||||
withFiles: true,
|
fileType: image,
|
||||||
limit: 9,
|
limit: 9,
|
||||||
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
<span :data-active="mode == 'default'" @click="mode = 'default'"><fa :icon="['far', 'comment-alt']"/> {{ $t('default') }}</span>
|
<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-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 == '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>
|
</header>
|
||||||
<mk-notes ref="timeline" :more="existMore ? more : null">
|
<mk-notes ref="timeline" :more="existMore ? more : null">
|
||||||
<p class="empty" slot="empty"><fa :icon="['far', 'comments']"/>{{ $t('empty') }}</p>
|
<p class="empty" slot="empty"><fa :icon="['far', 'comments']"/>{{ $t('empty') }}</p>
|
||||||
@@ -65,6 +66,7 @@ export default Vue.extend({
|
|||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilDate: this.date ? this.date.getTime() : new Date().getTime() + 1000 * 86400 * 365,
|
untilDate: this.date ? this.date.getTime() : new Date().getTime() + 1000 * 86400 * 365,
|
||||||
includeReplies: this.mode == 'with-replies',
|
includeReplies: this.mode == 'with-replies',
|
||||||
|
includeMyRenotes: this.mode != 'my-posts',
|
||||||
withFiles: this.mode == 'with-media'
|
withFiles: this.mode == 'with-media'
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
@@ -85,6 +87,7 @@ export default Vue.extend({
|
|||||||
userId: this.user.id,
|
userId: this.user.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
includeReplies: this.mode == 'with-replies',
|
includeReplies: this.mode == 'with-replies',
|
||||||
|
includeMyRenotes: this.mode != 'my-posts',
|
||||||
withFiles: this.mode == 'with-media',
|
withFiles: this.mode == 'with-media',
|
||||||
untilDate: new Date((this.$refs.timeline as any).tail().createdAt).getTime()
|
untilDate: new Date((this.$refs.timeline as any).tail().createdAt).getTime()
|
||||||
});
|
});
|
||||||
|
@@ -14,7 +14,7 @@ import VueHotkey from './common/hotkey';
|
|||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
import checkForUpdate from './common/scripts/check-for-update';
|
import checkForUpdate from './common/scripts/check-for-update';
|
||||||
import MiOS from './mios';
|
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 { builtinThemes, lightTheme, applyTheme } from './theme';
|
||||||
import Dialog from './common/views/components/dialog.vue';
|
import Dialog from './common/views/components/dialog.vue';
|
||||||
|
|
||||||
@@ -123,6 +123,7 @@ import {
|
|||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faMapMarker,
|
faMapMarker,
|
||||||
faRobot,
|
faRobot,
|
||||||
|
faHourglassHalf,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -253,6 +254,7 @@ library.add(
|
|||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faMapMarker,
|
faMapMarker,
|
||||||
faRobot,
|
faRobot,
|
||||||
|
faHourglassHalf,
|
||||||
|
|
||||||
farBell,
|
farBell,
|
||||||
farEnvelope,
|
farEnvelope,
|
||||||
@@ -320,7 +322,7 @@ Vue.mixin({
|
|||||||
|
|
||||||
console.info(`Misskey v${version} (${codename})`);
|
console.info(`Misskey v${version} (${codename})`);
|
||||||
console.info(
|
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;');
|
'color: red; background: yellow; font-size: 16px; font-weight: bold;');
|
||||||
|
|
||||||
// BootTimer解除
|
// BootTimer解除
|
||||||
|
@@ -9,7 +9,8 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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"/>
|
<fa icon="quote-right"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,7 +25,9 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,7 +63,9 @@
|
|||||||
<mk-time :time="notification.createdAt"/>
|
<mk-time :time="notification.createdAt"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">
|
<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>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -66,6 +66,7 @@ import { host } from '../../../config';
|
|||||||
import { erase, unique } from '../../../../../prelude/array';
|
import { erase, unique } from '../../../../../prelude/array';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { toASCII } from 'punycode';
|
import { toASCII } from 'punycode';
|
||||||
|
import extractMentions from '../../../../../misc/extract-mentions';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('mobile/views/components/post-form.vue'),
|
i18n: i18n('mobile/views/components/post-form.vue'),
|
||||||
@@ -174,7 +175,7 @@ export default Vue.extend({
|
|||||||
if (this.reply && this.reply.text != null) {
|
if (this.reply && this.reply.text != null) {
|
||||||
const ast = parse(this.reply.text);
|
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}`;
|
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
||||||
|
|
||||||
// 自分は除外
|
// 自分は除外
|
||||||
@@ -196,9 +197,8 @@ export default Vue.extend({
|
|||||||
this.visibility = this.reply.visibility;
|
this.visibility = this.reply.visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ダイレクトへのリプライはリプライ先ユーザーを初期設定
|
if (this.reply) {
|
||||||
if (this.reply && this.reply.visibility === 'specified') {
|
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
|
||||||
this.$root.api('users/show', { userId: this.reply.userId }).then(user => {
|
|
||||||
this.visibleUsers.push(user);
|
this.visibleUsers.push(user);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,8 @@ export default Vue.extend({
|
|||||||
hasGameInvitation: false,
|
hasGameInvitation: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
aboutUrl: `/docs/${lang}/about`,
|
aboutUrl: `/docs/${lang}/about`,
|
||||||
announcements: []
|
announcements: [],
|
||||||
|
searching: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -95,17 +96,34 @@ export default Vue.extend({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
search() {
|
search() {
|
||||||
|
if (this.searching) return;
|
||||||
|
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
title: this.$t('search'),
|
title: this.$t('search'),
|
||||||
input: true
|
input: true
|
||||||
}).then(({ canceled, result: query }) => {
|
}).then(async ({ canceled, result: query }) => {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
const q = query.trim();
|
const q = this.q.trim();
|
||||||
if (q.startsWith('@')) {
|
if (q.startsWith('@')) {
|
||||||
this.$router.push(`/${q}`);
|
this.$router.push(`/${q}`);
|
||||||
} else if (q.startsWith('#')) {
|
} else if (q.startsWith('#')) {
|
||||||
this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`);
|
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 {
|
} else {
|
||||||
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
|
this.$router.push(`/search?q=${encodeURIComponent(q)}`);
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<span slot="header"><span style="margin-right:4px;"><fa icon="hashtag"/></span>{{ $route.params.tag }}</span>
|
<span slot="header"><span style="margin-right:4px;"><fa icon="hashtag"/></span>{{ $route.params.tag }}</span>
|
||||||
|
|
||||||
<main>
|
<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"/>
|
<mk-notes ref="timeline" :more="existMore ? more : null"/>
|
||||||
</main>
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
|
@@ -3,11 +3,7 @@
|
|||||||
<span slot="header" v-if="!fetching"><fa icon="list"/>{{ list.title }}</span>
|
<span slot="header" v-if="!fetching"><fa icon="list"/>{{ list.title }}</span>
|
||||||
|
|
||||||
<main v-if="!fetching">
|
<main v-if="!fetching">
|
||||||
<ul>
|
<x-editor :list="list"/>
|
||||||
<li v-for="user in users" :key="user.id"><router-link :to="user | userPage">
|
|
||||||
<mk-user-name :user="user"/>
|
|
||||||
</router-link></li>
|
|
||||||
</ul>
|
|
||||||
</main>
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
@@ -15,13 +11,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Progress from '../../../common/scripts/loading';
|
import Progress from '../../../common/scripts/loading';
|
||||||
|
import XEditor from '../../../common/views/components/user-list-editor.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XEditor
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fetching: true,
|
fetching: true,
|
||||||
list: null,
|
list: null
|
||||||
users: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -42,12 +41,6 @@ export default Vue.extend({
|
|||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
|
|
||||||
Progress.done();
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
main
|
main
|
||||||
width 100%
|
width 100%
|
||||||
max-width 680px
|
max-width 680px
|
||||||
|
@@ -26,10 +26,15 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
const image = [
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif'
|
||||||
|
];
|
||||||
this.$root.api('users/notes', {
|
this.$root.api('users/notes', {
|
||||||
userId: this.user.id,
|
userId: this.user.id,
|
||||||
withFiles: true,
|
fileType: image,
|
||||||
limit: 6,
|
limit: 9,
|
||||||
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
untilDate: new Date().getTime() + 1000 * 86400 * 365
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
|
2
src/client/app/v.d.ts
vendored
2
src/client/app/v.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
declare module "*.vue" {
|
declare module '*.vue' {
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
export default Vue;
|
export default Vue;
|
||||||
}
|
}
|
||||||
|
@@ -39,21 +39,7 @@ export type Source = {
|
|||||||
|
|
||||||
accesslog?: string;
|
accesslog?: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* Service Worker
|
|
||||||
*/
|
|
||||||
sw?: {
|
|
||||||
public_key: string;
|
|
||||||
private_key: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
clusterLimit?: number;
|
clusterLimit?: number;
|
||||||
|
|
||||||
user_recommendation?: {
|
|
||||||
external: boolean;
|
|
||||||
engine: string;
|
|
||||||
timeout: number;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { count, concat } from "../../prelude/array";
|
import { count, concat } from '../../prelude/array';
|
||||||
|
|
||||||
// MISSKEY REVERSI ENGINE
|
// MISSKEY REVERSI ENGINE
|
||||||
|
|
||||||
@@ -76,27 +76,14 @@ export default class Reversi {
|
|||||||
this.mapHeight = map.length;
|
this.mapHeight = map.length;
|
||||||
const mapData = map.join('');
|
const mapData = map.join('');
|
||||||
|
|
||||||
this.board = mapData.split('').map(d => {
|
this.board = mapData.split('').map(d => d === '-' ? null : d === 'b' ? BLACK : d === 'w' ? WHITE : undefined);
|
||||||
if (d == '-') return null;
|
|
||||||
if (d == 'b') return BLACK;
|
|
||||||
if (d == 'w') return WHITE;
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.map = mapData.split('').map(d => {
|
this.map = mapData.split('').map(d => d === '-' || d === 'b' || d === 'w' ? 'empty' : 'null');
|
||||||
if (d == '-' || d == 'b' || d == 'w') return 'empty';
|
|
||||||
return 'null';
|
|
||||||
});
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある
|
// ゲームが始まった時点で片方の色の石しかないか、始まった時点で勝敗が決定するようなマップの場合がある
|
||||||
if (!this.canPutSomewhere(BLACK)) {
|
if (!this.canPutSomewhere(BLACK))
|
||||||
if (!this.canPutSomewhere(WHITE)) {
|
this.turn = this.canPutSomewhere(WHITE) ? WHITE : null;
|
||||||
this.turn = null;
|
|
||||||
} else {
|
|
||||||
this.turn = WHITE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,16 +104,14 @@ export default class Reversi {
|
|||||||
* 黒石の比率
|
* 黒石の比率
|
||||||
*/
|
*/
|
||||||
public get blackP() {
|
public get blackP() {
|
||||||
if (this.blackCount == 0 && this.whiteCount == 0) return 0;
|
return this.blackCount == 0 && this.whiteCount == 0 ? 0 : this.blackCount / (this.blackCount + this.whiteCount);
|
||||||
return this.blackCount / (this.blackCount + this.whiteCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 白石の比率
|
* 白石の比率
|
||||||
*/
|
*/
|
||||||
public get whiteP() {
|
public get whiteP() {
|
||||||
if (this.blackCount == 0 && this.whiteCount == 0) return 0;
|
return this.blackCount == 0 && this.whiteCount == 0 ? 0 : this.whiteCount / (this.blackCount + this.whiteCount);
|
||||||
return this.whiteCount / (this.blackCount + this.whiteCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public transformPosToXy(pos: number): number[] {
|
public transformPosToXy(pos: number): number[] {
|
||||||
@@ -172,13 +157,10 @@ export default class Reversi {
|
|||||||
|
|
||||||
private calcTurn() {
|
private calcTurn() {
|
||||||
// ターン計算
|
// ターン計算
|
||||||
if (this.canPutSomewhere(!this.prevColor)) {
|
this.turn =
|
||||||
this.turn = !this.prevColor;
|
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
|
||||||
} else if (this.canPutSomewhere(this.prevColor)) {
|
this.canPutSomewhere(this.prevColor) ? this.prevColor :
|
||||||
this.turn = this.prevColor;
|
null;
|
||||||
} else {
|
|
||||||
this.turn = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo() {
|
public undo() {
|
||||||
@@ -199,8 +181,7 @@ export default class Reversi {
|
|||||||
*/
|
*/
|
||||||
public mapDataGet(pos: number): MapPixel {
|
public mapDataGet(pos: number): MapPixel {
|
||||||
const [x, y] = this.transformPosToXy(pos);
|
const [x, y] = this.transformPosToXy(pos);
|
||||||
if (x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight) return 'null';
|
return x < 0 || y < 0 || x >= this.mapWidth || y >= this.mapHeight ? 'null' : this.map[pos];
|
||||||
return this.map[pos];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,16 +204,10 @@ export default class Reversi {
|
|||||||
* @param pos 位置
|
* @param pos 位置
|
||||||
*/
|
*/
|
||||||
public canPut(color: Color, pos: number): boolean {
|
public canPut(color: Color, pos: number): boolean {
|
||||||
// 既に石が置いてある場所には打てない
|
return (
|
||||||
if (this.board[pos] !== null) return false;
|
this.board[pos] !== null ? false : // 既に石が置いてある場所には打てない
|
||||||
|
this.opts.canPutEverywhere ? this.mapDataGet(pos) == 'empty' : // 挟んでなくても置けるモード
|
||||||
if (this.opts.canPutEverywhere) {
|
this.effects(color, pos).length !== 0); // 相手の石を1つでも反転させられるか
|
||||||
// 挟んでなくても置けるモード
|
|
||||||
return this.mapDataGet(pos) == 'empty';
|
|
||||||
} else {
|
|
||||||
// 相手の石を1つでも反転させられるか
|
|
||||||
return this.effects(color, pos).length !== 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,19 +238,13 @@ export default class Reversi {
|
|||||||
[x, y] = nextPos(x, y);
|
[x, y] = nextPos(x, y);
|
||||||
|
|
||||||
// 座標が指し示す位置がボード外に出たとき
|
// 座標が指し示す位置がボード外に出たとき
|
||||||
if (this.opts.loopedBoard) {
|
if (this.opts.loopedBoard && this.transformXyToPos(
|
||||||
x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth;
|
(x = ((x % this.mapWidth) + this.mapWidth) % this.mapWidth),
|
||||||
y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight;
|
(y = ((y % this.mapHeight) + this.mapHeight) % this.mapHeight)) == initPos)
|
||||||
|
|
||||||
if (this.transformXyToPos(x, y) == initPos) {
|
|
||||||
// 盤面の境界でループし、自分が石を置く位置に戻ってきたとき、挟めるようにしている (ref: Test4のマップ)
|
// 盤面の境界でループし、自分が石を置く位置に戻ってきたとき、挟めるようにしている (ref: Test4のマップ)
|
||||||
return found;
|
return found;
|
||||||
}
|
else if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight)
|
||||||
} else {
|
return []; // 挟めないことが確定 (盤面外に到達)
|
||||||
if (x == -1 || y == -1 || x == this.mapWidth || y == this.mapHeight) {
|
|
||||||
return []; // 挟めないことが確定 (盤面外に到達)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pos = this.transformXyToPos(x, y);
|
const pos = this.transformXyToPos(x, y);
|
||||||
if (this.mapDataGet(pos) === 'null') return []; // 挟めないことが確定 (配置不可能なマスに到達)
|
if (this.mapDataGet(pos) === 'null') return []; // 挟めないことが確定 (配置不可能なマスに到達)
|
||||||
@@ -300,14 +269,9 @@ export default class Reversi {
|
|||||||
* ゲームの勝者 (null = 引き分け)
|
* ゲームの勝者 (null = 引き分け)
|
||||||
*/
|
*/
|
||||||
public get winner(): Color {
|
public get winner(): Color {
|
||||||
if (!this.isEnded) return undefined;
|
return this.isEnded ?
|
||||||
|
this.blackCount == this.whiteCount ? null :
|
||||||
if (this.blackCount == this.whiteCount) return null;
|
this.opts.isLlotheo === this.blackCount > this.whiteCount ? WHITE : BLACK :
|
||||||
|
undefined;
|
||||||
if (this.opts.isLlotheo) {
|
|
||||||
return this.blackCount > this.whiteCount ? WHITE : BLACK;
|
|
||||||
} else {
|
|
||||||
return this.blackCount > this.whiteCount ? BLACK : WHITE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,10 @@ const jsdom = require('jsdom');
|
|||||||
const { JSDOM } = jsdom;
|
const { JSDOM } = jsdom;
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { INote } from '../models/note';
|
import { INote } from '../models/note';
|
||||||
import { Node } from './parser';
|
|
||||||
import { intersperse } from '../prelude/array';
|
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) {
|
if (tokens == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -14,11 +14,11 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
|
|||||||
|
|
||||||
const doc = window.document;
|
const doc = window.document;
|
||||||
|
|
||||||
function appendChildren(children: Node[], targetElement: any): void {
|
function appendChildren(children: MfmForest, targetElement: any): void {
|
||||||
for (const child of children.map(n => handlers[n.name](n))) targetElement.appendChild(child);
|
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) {
|
bold(token) {
|
||||||
const el = doc.createElement('b');
|
const el = doc.createElement('b');
|
||||||
appendChildren(token.children, el);
|
appendChildren(token.children, el);
|
||||||
@@ -58,7 +58,7 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
|
|||||||
blockCode(token) {
|
blockCode(token) {
|
||||||
const pre = doc.createElement('pre');
|
const pre = doc.createElement('pre');
|
||||||
const inner = doc.createElement('code');
|
const inner = doc.createElement('code');
|
||||||
inner.innerHTML = token.props.code;
|
inner.innerHTML = token.node.props.code;
|
||||||
pre.appendChild(inner);
|
pre.appendChild(inner);
|
||||||
return pre;
|
return pre;
|
||||||
},
|
},
|
||||||
@@ -70,39 +70,39 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
|
|||||||
},
|
},
|
||||||
|
|
||||||
emoji(token) {
|
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) {
|
hashtag(token) {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
a.href = `${config.url}/tags/${token.props.hashtag}`;
|
a.href = `${config.url}/tags/${token.node.props.hashtag}`;
|
||||||
a.textContent = `#${token.props.hashtag}`;
|
a.textContent = `#${token.node.props.hashtag}`;
|
||||||
a.setAttribute('rel', 'tag');
|
a.setAttribute('rel', 'tag');
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
|
|
||||||
inlineCode(token) {
|
inlineCode(token) {
|
||||||
const el = doc.createElement('code');
|
const el = doc.createElement('code');
|
||||||
el.textContent = token.props.code;
|
el.textContent = token.node.props.code;
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
math(token) {
|
math(token) {
|
||||||
const el = doc.createElement('code');
|
const el = doc.createElement('code');
|
||||||
el.textContent = token.props.formula;
|
el.textContent = token.node.props.formula;
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
link(token) {
|
link(token) {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
a.href = token.props.url;
|
a.href = token.node.props.url;
|
||||||
appendChildren(token.children, a);
|
appendChildren(token.children, a);
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
|
|
||||||
mention(token) {
|
mention(token) {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
const { username, host, acct } = token.props;
|
const { username, host, acct } = token.node.props;
|
||||||
switch (host) {
|
switch (host) {
|
||||||
case 'github.com':
|
case 'github.com':
|
||||||
a.href = `https://github.com/${username}`;
|
a.href = `https://github.com/${username}`;
|
||||||
@@ -133,7 +133,7 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
|
|||||||
|
|
||||||
text(token) {
|
text(token) {
|
||||||
const el = doc.createElement('span');
|
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)) {
|
for (const x of intersperse('br', nodes)) {
|
||||||
el.appendChild(x === 'br' ? doc.createElement('br') : x);
|
el.appendChild(x === 'br' ? doc.createElement('br') : x);
|
||||||
@@ -144,15 +144,15 @@ export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUser
|
|||||||
|
|
||||||
url(token) {
|
url(token) {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
a.href = token.props.url;
|
a.href = token.node.props.url;
|
||||||
a.textContent = token.props.url;
|
a.textContent = token.node.props.url;
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
|
|
||||||
search(token) {
|
search(token) {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
a.href = `https://www.google.com/?#q=${token.props.query}`;
|
a.href = `https://www.google.com/?#q=${token.node.props.query}`;
|
||||||
a.textContent = token.props.content;
|
a.textContent = token.node.props.content;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -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 A from '../prelude/array';
|
||||||
import * as S from '../prelude/string';
|
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 == '') {
|
if (source == null || source == '') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodes: Node[] = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source);
|
const raw = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source) as MfmForest;
|
||||||
|
return removeEmptyTextNodes(concatConsecutiveTextTrees(raw));
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
import { capitalize, toUpperCase } from "../prelude/string";
|
import { capitalize, toUpperCase } from '../prelude/string';
|
||||||
|
|
||||||
function escape(text: string) {
|
function escape(text: string) {
|
||||||
return text
|
return text
|
||||||
@@ -307,7 +307,7 @@ const elements: Element[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// specify lang is todo
|
// TODO: specify lang
|
||||||
export default (source: string, lang?: string): string => {
|
export default (source: string, lang?: string): string => {
|
||||||
let code = source;
|
let code = source;
|
||||||
let html = '';
|
let html = '';
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
export default (acct: string) => {
|
export default (acct: string) => {
|
||||||
if (acct.startsWith('@')) acct = acct.substr(1);
|
if (acct.startsWith('@')) acct = acct.substr(1);
|
||||||
const splitted = acct.split('@', 2);
|
const split = acct.split('@', 2);
|
||||||
return { username: splitted[0], host: splitted[1] || null };
|
return { username: split[0], host: split[1] || null };
|
||||||
};
|
};
|
||||||
|
9
src/misc/extract-emojis.ts
Normal file
9
src/misc/extract-emojis.ts
Normal 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);
|
||||||
|
}
|
9
src/misc/extract-hashtags.ts
Normal file
9
src/misc/extract-hashtags.ts
Normal 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);
|
||||||
|
}
|
10
src/misc/extract-mentions.ts
Normal file
10
src/misc/extract-mentions.ts
Normal 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);
|
||||||
|
}
|
@@ -17,9 +17,10 @@ const defaultMeta: any = {
|
|||||||
enableGithubIntegration: false,
|
enableGithubIntegration: false,
|
||||||
enableDiscordIntegration: false,
|
enableDiscordIntegration: false,
|
||||||
enableExternalUserRecommendation: 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,
|
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> {
|
export default async function(): Promise<IMeta> {
|
||||||
|
@@ -14,7 +14,11 @@ const summarize = (note: any): string => {
|
|||||||
let summary = '';
|
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) {
|
if ((note.files || []).length != 0) {
|
||||||
|
@@ -15,4 +15,6 @@ export type IEmoji = {
|
|||||||
url: string;
|
url: string;
|
||||||
aliases?: string[];
|
aliases?: string[];
|
||||||
updatedAt?: Date;
|
updatedAt?: Date;
|
||||||
|
/** AP object id */
|
||||||
|
uri?: string;
|
||||||
};
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -7,6 +7,8 @@ import isObjectId from '../misc/is-objectid';
|
|||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
|
|
||||||
const MessagingMessage = db.get<IMessagingMessage>('messagingMessages');
|
const MessagingMessage = db.get<IMessagingMessage>('messagingMessages');
|
||||||
|
MessagingMessage.createIndex('userId');
|
||||||
|
MessagingMessage.createIndex('recipientId');
|
||||||
export default MessagingMessage;
|
export default MessagingMessage;
|
||||||
|
|
||||||
export interface IMessagingMessage {
|
export interface IMessagingMessage {
|
||||||
|
@@ -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 = {
|
export type IMeta = {
|
||||||
name?: string;
|
name?: string;
|
||||||
@@ -223,4 +236,8 @@ export type IMeta = {
|
|||||||
smtpPort?: number;
|
smtpPort?: number;
|
||||||
smtpUser?: string;
|
smtpUser?: string;
|
||||||
smtpPass?: string;
|
smtpPass?: string;
|
||||||
|
|
||||||
|
enableServiceWorker?: boolean;
|
||||||
|
swPublicKey?: string;
|
||||||
|
swPrivateKey?: string;
|
||||||
};
|
};
|
||||||
|
@@ -155,7 +155,7 @@ export const isRemoteUser = (user: any): user is IRemoteUser =>
|
|||||||
|
|
||||||
//#region Validators
|
//#region Validators
|
||||||
export function validateUsername(username: string, remote?: boolean): boolean {
|
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 {
|
export function validatePassword(password: string): boolean {
|
||||||
|
@@ -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;
|
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[] {
|
export function concat<T>(xss: T[][]): T[] {
|
||||||
return ([] as T[]).concat(...xss);
|
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[] {
|
export function intersperse<T>(sep: T, xs: T[]): T[] {
|
||||||
return concat(xs.map(x => [sep, x])).slice(1);
|
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.
|
* 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.
|
* The order of result values are determined by the first array.
|
||||||
*/
|
*/
|
||||||
export function difference<T>(includes: T[], excludes: T[]): T[] {
|
export function difference<T>(xs: T[], ys: T[]): T[] {
|
||||||
return includes.filter(x => !excludes.includes(x));
|
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[] {
|
export function unique<T>(xs: T[]): T[] {
|
||||||
return [...new Set(xs)];
|
return [...new Set(xs)];
|
||||||
}
|
}
|
||||||
@@ -38,7 +60,11 @@ export function maximum(xs: number[]): number {
|
|||||||
return Math.max(...xs);
|
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[][];
|
const groups = [] as T[][];
|
||||||
for (const x of xs) {
|
for (const x of xs) {
|
||||||
if (groups.length !== 0 && f(groups[groups.length - 1][0], x)) {
|
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;
|
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[][] {
|
export function groupOn<T, S>(f: (x: T) => S, xs: T[]): T[][] {
|
||||||
return groupBy((a, b) => f(a) === f(b), xs);
|
return groupBy((a, b) => f(a) === f(b), xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two arrays by lexicographical order
|
||||||
|
*/
|
||||||
export function lessThan(xs: number[], ys: number[]): boolean {
|
export function lessThan(xs: number[], ys: number[]): boolean {
|
||||||
for (let i = 0; i < Math.min(xs.length, ys.length); i++) {
|
for (let i = 0; i < Math.min(xs.length, ys.length); i++) {
|
||||||
if (xs[i] < ys[i]) return true;
|
if (xs[i] < ys[i]) return true;
|
||||||
@@ -62,7 +95,10 @@ export function lessThan(xs: number[], ys: number[]): boolean {
|
|||||||
return xs.length < ys.length;
|
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 = [];
|
const ys = [];
|
||||||
for (const x of xs) {
|
for (const x of xs) {
|
||||||
if (f(x)) {
|
if (f(x)) {
|
||||||
@@ -73,3 +109,9 @@ export function takeWhile<T>(f: (x: T) => boolean, xs: T[]): T[] {
|
|||||||
}
|
}
|
||||||
return ys;
|
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
5
src/prelude/relation.ts
Normal 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>;
|
@@ -1,5 +1,5 @@
|
|||||||
export function concat(xs: string[]): string {
|
export function concat(xs: string[]): string {
|
||||||
return xs.reduce((a, b) => a + b, "");
|
return xs.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function capitalize(s: string): string {
|
export function capitalize(s: string): string {
|
||||||
|
36
src/prelude/tree.ts
Normal file
36
src/prelude/tree.ts
Normal 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));
|
||||||
|
}
|
@@ -2,17 +2,26 @@ const push = require('web-push');
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import Subscription from './models/sw-subscription';
|
import Subscription from './models/sw-subscription';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
|
import fetchMeta from './misc/fetch-meta';
|
||||||
|
import { IMeta } from './models/meta';
|
||||||
|
|
||||||
if (config.sw) {
|
let meta: IMeta = null;
|
||||||
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
|
|
||||||
push.setVapidDetails(
|
setInterval(() => {
|
||||||
config.url,
|
fetchMeta().then(m => {
|
||||||
config.sw.public_key,
|
meta = m;
|
||||||
config.sw.private_key);
|
|
||||||
}
|
if (meta.enableServiceWorker) {
|
||||||
|
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
|
||||||
|
push.setVapidDetails(config.url,
|
||||||
|
meta.swPublicKey,
|
||||||
|
meta.swPrivateKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
export default async function(userId: mongo.ObjectID | string, type: string, body?: any) {
|
export default async function(userId: mongo.ObjectID | string, type: string, body?: any) {
|
||||||
if (!config.sw) return;
|
if (!meta.enableServiceWorker) return;
|
||||||
|
|
||||||
if (typeof userId === 'string') {
|
if (typeof userId === 'string') {
|
||||||
userId = new mongo.ObjectID(userId);
|
userId = new mongo.ObjectID(userId);
|
||||||
|
@@ -18,7 +18,7 @@ export default async (actor: IRemoteUser, activity: ILike) => {
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
let reaction = 'pudding';
|
let reaction = 'like';
|
||||||
|
|
||||||
// 他のMisskeyインスタンスからのリアクション
|
// 他のMisskeyインスタンスからのリアクション
|
||||||
if (activity._misskey_reaction && validateReaction.ok(activity._misskey_reaction)) {
|
if (activity._misskey_reaction && validateReaction.ok(activity._misskey_reaction)) {
|
||||||
|
@@ -181,6 +181,20 @@ export async function extractEmojis(tags: ITag[], host_: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (exists) {
|
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;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,8 +203,10 @@ export async function extractEmojis(tags: ITag[], host_: string) {
|
|||||||
return await Emoji.insert({
|
return await Emoji.insert({
|
||||||
host,
|
host,
|
||||||
name,
|
name,
|
||||||
|
uri: tag.id,
|
||||||
url: tag.icon.url,
|
url: tag.icon.url,
|
||||||
aliases: [],
|
updatedAt: tag.updated ? new Date(tag.updated) : undefined,
|
||||||
|
aliases: []
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@@ -18,6 +18,7 @@ import Instance from '../../../models/instance';
|
|||||||
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
||||||
import { IEmoji } from '../../../models/emoji';
|
import { IEmoji } from '../../../models/emoji';
|
||||||
import { ITag } from './tag';
|
import { ITag } from './tag';
|
||||||
|
import Following from '../../../models/following';
|
||||||
|
|
||||||
const log = debug('misskey:activitypub');
|
const log = debug('misskey:activitypub');
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
|
|||||||
publicKeyPem: person.publicKey.publicKeyPem
|
publicKeyPem: person.publicKey.publicKeyPem
|
||||||
},
|
},
|
||||||
inbox: person.inbox,
|
inbox: person.inbox,
|
||||||
sharedInbox: person.sharedInbox,
|
sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||||
featured: person.featured,
|
featured: person.featured,
|
||||||
endpoints: person.endpoints,
|
endpoints: person.endpoints,
|
||||||
uri: person.id,
|
uri: person.id,
|
||||||
@@ -340,7 +341,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
|
|||||||
$set: {
|
$set: {
|
||||||
lastFetchedAt: new Date(),
|
lastFetchedAt: new Date(),
|
||||||
inbox: person.inbox,
|
inbox: person.inbox,
|
||||||
sharedInbox: person.sharedInbox,
|
sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||||
featured: person.featured,
|
featured: person.featured,
|
||||||
avatarId: avatar ? avatar._id : null,
|
avatarId: avatar ? avatar._id : null,
|
||||||
bannerId: banner ? banner._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));
|
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 }, {
|
await User.update({ _id: user._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
pinnedNoteIds: featuredNotes.map(note => note._id)
|
pinnedNoteIds: featuredNotes.filter(note => note != null).map(note => note._id)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { IIcon } from "./icon";
|
import { IIcon } from './icon';
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* tag (ActivityPub)
|
* tag (ActivityPub)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
import { ILocalUser, IRemoteUser } from "../../../models/user";
|
import { ILocalUser, IRemoteUser } from '../../../models/user';
|
||||||
|
|
||||||
export default (blocker?: ILocalUser, blockee?: IRemoteUser) => ({
|
export default (blocker?: ILocalUser, blockee?: IRemoteUser) => ({
|
||||||
type: 'Block',
|
type: 'Block',
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user