Compare commits

...

174 Commits

Author SHA1 Message Date
syuilo
f87981eeee 2.25.2 2018-06-04 19:59:07 +09:00
syuilo
761ae807db Fix bug 2018-06-03 19:53:57 +09:00
syuilo
5e967e24ff ✌️ 2018-06-03 19:39:02 +09:00
syuilo
70ac07d60e 🎨 2018-06-03 07:34:34 +09:00
syuilo
255c07d1ab 2.25.1 2018-06-03 04:51:58 +09:00
syuilo
0aa9201770 2.25.0 2018-06-02 19:23:17 +09:00
syuilo
534e43f72d Fix bug 2018-06-02 19:19:58 +09:00
syuilo
8f50080647 Merge pull request #1673 from syuilo/l10n_master
New Crowdin translations
2018-06-02 17:05:18 +09:00
syuilo
cdc70875e5 New translations ja.yml (English) 2018-06-02 16:51:10 +09:00
syuilo
e6962d6fab New translations ja.yml (English) 2018-06-02 16:41:22 +09:00
syuilo
3703563939 New translations ja.yml (Portuguese) 2018-06-02 16:31:39 +09:00
syuilo
e81b145735 New translations ja.yml (Korean) 2018-06-02 16:31:37 +09:00
syuilo
7f4145ee56 New translations ja.yml (Polish) 2018-06-02 16:31:35 +09:00
syuilo
3967cf40b3 New translations ja.yml (Chinese Simplified) 2018-06-02 16:31:33 +09:00
syuilo
84b0d56c4c New translations ja.yml (Italian) 2018-06-02 16:31:32 +09:00
syuilo
e081d8d4ca New translations ja.yml (Russian) 2018-06-02 16:31:30 +09:00
syuilo
b6ad7149d8 New translations ja.yml (English) 2018-06-02 16:31:28 +09:00
syuilo
0f36f60cb4 New translations ja.yml (Spanish) 2018-06-02 16:31:26 +09:00
syuilo
1284eef9e2 New translations ja.yml (German) 2018-06-02 16:31:24 +09:00
syuilo
dec264ee6a New translations ja.yml (French) 2018-06-02 16:31:22 +09:00
syuilo
e25e1d88d6 Merge pull request #1671 from syuilo/locked-account
Locked account
2018-06-02 16:28:08 +09:00
syuilo
60a7f7f146 wip 2018-06-02 16:27:24 +09:00
syuilo
897f7a031d wip 2018-06-02 16:13:32 +09:00
syuilo
4feff8835c wip 2018-06-02 16:01:32 +09:00
syuilo
8dfd892b71 wip 2018-06-02 15:51:43 +09:00
syuilo
9e8cfd76c8 wip 2018-06-02 13:40:28 +09:00
syuilo
a6a4bb6599 wip 2018-06-02 13:36:29 +09:00
syuilo
5ca8a0d886 wip 2018-06-02 13:34:53 +09:00
syuilo
6840496791 wip 2018-06-02 13:14:54 +09:00
syuilo
0128831649 wip 2018-06-02 13:11:28 +09:00
syuilo
56fa24e401 wip 2018-06-02 12:58:56 +09:00
syuilo
e011870a60 Merge pull request #1672 from Angristan/patch-1
Update build docs
2018-06-02 03:54:10 +09:00
Angristan
8d78ee08c1 Cover multiple cases 2018-06-01 20:52:47 +02:00
Angristan
2752319e50 Update build docs
Fix #1474
2018-06-01 20:24:30 +02:00
syuilo
a26c19cbd2 wip 2018-06-02 00:51:20 +09:00
syuilo
f14571dc42 wip 2018-06-02 00:38:31 +09:00
syuilo
484d17f53f wip 2018-06-02 00:15:17 +09:00
syuilo
924119651a Merge branch 'master' into locked-account 2018-06-01 23:37:19 +09:00
syuilo
c6d49dacbc Merge pull request #1670 from syuilo/l10n_master
New Crowdin translations
2018-06-01 23:36:22 +09:00
syuilo
0be790fa31 wip 2018-06-01 21:55:27 +09:00
syuilo
b7f6eb8290 New translations ja.yml (English) 2018-06-01 16:29:25 +09:00
syuilo
f1bda0b2e1 New translations ja.yml (English) 2018-06-01 16:12:22 +09:00
syuilo
bae44b4708 wip 2018-06-01 01:12:02 +09:00
syuilo
35115607bc wip 2018-06-01 00:42:37 +09:00
syuilo
51255bb446 wip 2018-05-31 22:56:02 +09:00
syuilo
bd758a156e wip 2018-05-31 18:34:15 +09:00
syuilo
51929fb607 typo 2018-05-31 18:11:28 +09:00
syuilo
9599a31239 wip 2018-05-31 18:08:47 +09:00
syuilo
9fdb125960 Merge pull request #1668 from syuilo/l10n_master
New Crowdin translations
2018-05-31 17:38:49 +09:00
syuilo
534c0a6001 New translations ja.yml (English) 2018-05-31 17:31:23 +09:00
syuilo
58bfcfda91 New translations ja.yml (English) 2018-05-31 17:21:36 +09:00
syuilo
8d0802f05d New translations ja.yml (English) 2018-05-31 17:12:41 +09:00
syuilo
5cd8c5d229 New translations ja.yml (English) 2018-05-31 17:02:48 +09:00
syuilo
fa3c4436d9 New translations ja.yml (English) 2018-05-31 16:52:27 +09:00
syuilo
d32d95918c 🎨 2018-05-31 16:44:11 +09:00
syuilo
34899757d5 New translations ja.yml (English) 2018-05-31 16:41:32 +09:00
syuilo
111dbdcd7f Fix 2018-05-31 16:38:05 +09:00
syuilo
0c38509f1c New translations ja.yml (Polish) 2018-05-31 04:21:47 +09:00
syuilo
652aa1f69b New translations ja.yml (German) 2018-05-31 00:33:22 +09:00
syuilo
dc380c38da New translations ja.yml (German) 2018-05-31 00:23:33 +09:00
syuilo
8555e04f50 New translations ja.yml (German) 2018-05-31 00:13:36 +09:00
syuilo
c23bbf81f1 2.24.3 2018-05-30 23:08:26 +09:00
syuilo
7dd7de8ff6 Update endpoints.ts 2018-05-30 23:05:24 +09:00
syuilo
2ca8bafde3 Merge pull request #1664 from syuilo/l10n_master
New Crowdin translations
2018-05-30 22:08:38 +09:00
syuilo
79f6c3f1ca New translations ja.yml (Portuguese) 2018-05-30 21:23:17 +09:00
syuilo
fce0b315cf New translations ja.yml (Korean) 2018-05-30 21:23:14 +09:00
syuilo
56c7a8f2e4 New translations ja.yml (Polish) 2018-05-30 21:23:10 +09:00
syuilo
5ef2f157f2 New translations ja.yml (Chinese Simplified) 2018-05-30 21:23:08 +09:00
syuilo
738afbe475 New translations ja.yml (Italian) 2018-05-30 21:23:06 +09:00
syuilo
791a81a4c7 New translations ja.yml (Russian) 2018-05-30 21:23:03 +09:00
syuilo
aa82d7a2c9 New translations ja.yml (English) 2018-05-30 21:23:01 +09:00
syuilo
f57d2e54d2 New translations ja.yml (Spanish) 2018-05-30 21:22:58 +09:00
syuilo
fea1a2e51b New translations ja.yml (German) 2018-05-30 21:22:55 +09:00
syuilo
bda5347f1e New translations ja.yml (French) 2018-05-30 21:22:53 +09:00
syuilo
98d9c37922 Merge pull request #1665 from m4sk1n/patch-1
fix typo
2018-05-30 21:21:59 +09:00
syuilo
e3bde41a25 New translations ja.yml (Polish) 2018-05-30 21:14:46 +09:00
Marcin Mikołajczak
5fb2f7749d fix typo 2018-05-30 12:13:51 +00:00
syuilo
a56bdf2372 New translations ja.yml (Polish) 2018-05-30 21:05:48 +09:00
syuilo
9d991df32f New translations ja.yml (English) 2018-05-30 21:05:45 +09:00
syuilo
c4a3f89d1c New translations ja.yml (English) 2018-05-30 20:51:48 +09:00
syuilo
ea223bab51 Fix bug 2018-05-30 18:13:20 +09:00
syuilo
dd94392317 2.24.2 2018-05-30 05:02:56 +09:00
syuilo
baa2845916 Merge pull request #1663 from syuilo/l10n_master
New Crowdin translations
2018-05-30 05:02:17 +09:00
syuilo
97ae4ea13e New translations ja.yml (English) 2018-05-30 05:00:58 +09:00
syuilo
d1c5f0c70f New translations ja.yml (Portuguese) 2018-05-30 04:51:38 +09:00
syuilo
95bff3005f New translations ja.yml (Korean) 2018-05-30 04:51:36 +09:00
syuilo
c0b06496b1 New translations ja.yml (Polish) 2018-05-30 04:51:34 +09:00
syuilo
2105e1f259 New translations ja.yml (Chinese Simplified) 2018-05-30 04:51:32 +09:00
syuilo
e546414c2f New translations ja.yml (Italian) 2018-05-30 04:51:30 +09:00
syuilo
1f4660a930 New translations ja.yml (Russian) 2018-05-30 04:51:28 +09:00
syuilo
a2165c2e01 New translations ja.yml (English) 2018-05-30 04:51:26 +09:00
syuilo
1af920739f New translations ja.yml (Spanish) 2018-05-30 04:51:24 +09:00
syuilo
868e8228f0 New translations ja.yml (German) 2018-05-30 04:51:22 +09:00
syuilo
2bbc74560d New translations ja.yml (French) 2018-05-30 04:51:20 +09:00
syuilo
5d2caa456d 🎨 2018-05-30 04:46:50 +09:00
syuilo
9069a99a15 wip 2018-05-30 04:45:27 +09:00
syuilo
fa56a44d85 🎨 2018-05-30 04:07:23 +09:00
syuilo
248acaee75 2.24.1 2018-05-30 00:16:03 +09:00
syuilo
ef75f12abe Fix bug 2018-05-30 00:15:32 +09:00
syuilo
854814c226 2.24.0 2018-05-29 23:57:25 +09:00
syuilo
b6a322f447 Merge branch 'master' of https://github.com/syuilo/misskey 2018-05-29 23:56:52 +09:00
syuilo
161b9602f4 Fix bug 2018-05-29 23:56:44 +09:00
syuilo
62669bff07 Merge pull request #1662 from syuilo/l10n_master
New Crowdin translations
2018-05-29 23:55:19 +09:00
syuilo
02bd299714 New translations ja.yml (English) 2018-05-29 23:52:22 +09:00
syuilo
f71dabfbfa New translations ja.yml (Portuguese) 2018-05-29 23:45:17 +09:00
syuilo
8d31cedafc New translations ja.yml (Korean) 2018-05-29 23:45:11 +09:00
syuilo
a88d6c1c47 New translations ja.yml (Polish) 2018-05-29 23:45:09 +09:00
syuilo
d35a13fc0b New translations ja.yml (Chinese Simplified) 2018-05-29 23:45:05 +09:00
syuilo
8e4029c1cd New translations ja.yml (Italian) 2018-05-29 23:44:59 +09:00
syuilo
9a9f852540 New translations ja.yml (Russian) 2018-05-29 23:44:57 +09:00
syuilo
c66497a4de New translations ja.yml (English) 2018-05-29 23:44:55 +09:00
syuilo
1f9ecbf0be New translations ja.yml (Spanish) 2018-05-29 23:44:53 +09:00
syuilo
423a6f7013 New translations ja.yml (German) 2018-05-29 23:44:51 +09:00
syuilo
ef0ca38362 New translations ja.yml (French) 2018-05-29 23:44:48 +09:00
syuilo
ae9bfd69b0 Add analog clock widget 2018-05-29 23:13:39 +09:00
syuilo
3d231c3456 Fix 2018-05-29 22:56:05 +09:00
syuilo
95d0d0047a 時計をSVG化 2018-05-29 22:43:03 +09:00
syuilo
d05aee19f2 2.23.2 2018-05-29 21:46:30 +09:00
syuilo
125765faa6 Fix bug 2018-05-29 21:46:02 +09:00
syuilo
70c0b1d8c0 🎨 2018-05-29 19:13:49 +09:00
syuilo
72e8660ae3 🎨 2018-05-29 19:03:03 +09:00
syuilo
2127bf32c2 2.23.1 2018-05-29 17:11:48 +09:00
syuilo
2b9acc239e Fix bug 2018-05-29 17:10:59 +09:00
syuilo
47a6188097 2.23.0 2018-05-29 15:43:24 +09:00
syuilo
8abce1469a Merge pull request #1661 from syuilo/l10n_master
New Crowdin translations
2018-05-29 15:43:01 +09:00
syuilo
8a2bee2136 New translations ja.yml (Portuguese) 2018-05-29 15:42:20 +09:00
syuilo
e7a532f0cc New translations ja.yml (Korean) 2018-05-29 15:42:17 +09:00
syuilo
2cb1678577 New translations ja.yml (Polish) 2018-05-29 15:42:15 +09:00
syuilo
d249bc6575 New translations ja.yml (Chinese Simplified) 2018-05-29 15:42:13 +09:00
syuilo
e409b45873 New translations ja.yml (Italian) 2018-05-29 15:42:10 +09:00
syuilo
f2d26c1909 New translations ja.yml (Russian) 2018-05-29 15:42:08 +09:00
syuilo
898e3d7138 New translations ja.yml (English) 2018-05-29 15:42:06 +09:00
syuilo
78cc0f7b6f New translations ja.yml (Spanish) 2018-05-29 15:42:04 +09:00
syuilo
b14ca6a464 New translations ja.yml (German) 2018-05-29 15:42:02 +09:00
syuilo
4691c1259a New translations ja.yml (French) 2018-05-29 15:42:00 +09:00
syuilo
69f07cb015 Fix bug 2018-05-29 15:41:49 +09:00
syuilo
a426f4c7bd nanka iroiro 2018-05-29 15:38:48 +09:00
syuilo
3430a2d093 New translations ja.yml (English) 2018-05-29 15:31:19 +09:00
syuilo
4ecc8c799d 🎨 2018-05-29 15:21:03 +09:00
syuilo
fa02a58fc4 New translations ja.yml (Portuguese) 2018-05-29 14:51:25 +09:00
syuilo
2905d172b8 New translations ja.yml (Korean) 2018-05-29 14:51:23 +09:00
syuilo
5f6e5e4c8b New translations ja.yml (Polish) 2018-05-29 14:51:21 +09:00
syuilo
d68c2a0170 New translations ja.yml (Chinese Simplified) 2018-05-29 14:51:19 +09:00
syuilo
76c7ad5e24 New translations ja.yml (Italian) 2018-05-29 14:51:17 +09:00
syuilo
1cf65a0145 New translations ja.yml (Russian) 2018-05-29 14:51:16 +09:00
syuilo
0c8602f1d5 New translations ja.yml (English) 2018-05-29 14:51:14 +09:00
syuilo
2dc4990804 New translations ja.yml (Spanish) 2018-05-29 14:51:12 +09:00
syuilo
47ecd2e900 New translations ja.yml (German) 2018-05-29 14:51:10 +09:00
syuilo
01d8e9cf4e New translations ja.yml (French) 2018-05-29 14:51:08 +09:00
syuilo
da52f980c4 ✌️ 2018-05-29 14:42:29 +09:00
syuilo
366b7ef946 🎨 2018-05-29 14:22:15 +09:00
syuilo
0e7c0fd528 2.22.3 2018-05-29 13:22:29 +09:00
syuilo
fb28b238cf Add workaround for Safari bug 2018-05-29 13:21:38 +09:00
syuilo
b375bbc75c 2.22.2 2018-05-29 11:53:59 +09:00
syuilo
74ebd6e4a0 Merge branch 'master' of https://github.com/syuilo/misskey 2018-05-29 11:53:35 +09:00
syuilo
72f2b92d4f ✌️ 2018-05-29 11:53:28 +09:00
syuilo
178eeec041 Merge pull request #1660 from syuilo/l10n_master
New Crowdin translations
2018-05-29 11:53:03 +09:00
syuilo
7ff950b5e3 New translations ja.yml (English) 2018-05-29 11:50:50 +09:00
syuilo
11409b723e 🎨 2018-05-29 11:45:01 +09:00
syuilo
a59c8b4f57 New translations ja.yml (Portuguese) 2018-05-29 11:41:13 +09:00
syuilo
690e273257 New translations ja.yml (Korean) 2018-05-29 11:41:11 +09:00
syuilo
0133a1ba97 New translations ja.yml (Polish) 2018-05-29 11:41:09 +09:00
syuilo
809b0e67a6 New translations ja.yml (Chinese Simplified) 2018-05-29 11:41:08 +09:00
syuilo
a702271efd New translations ja.yml (Italian) 2018-05-29 11:41:06 +09:00
syuilo
ec4f8ddd3e New translations ja.yml (Russian) 2018-05-29 11:41:04 +09:00
syuilo
839f66c82f New translations ja.yml (English) 2018-05-29 11:41:02 +09:00
syuilo
9ae2775452 New translations ja.yml (Spanish) 2018-05-29 11:41:00 +09:00
syuilo
c9818358ee New translations ja.yml (German) 2018-05-29 11:40:58 +09:00
syuilo
6e3a88ffcb New translations ja.yml (French) 2018-05-29 11:40:56 +09:00
syuilo
4c54d68fad Darken 2018-05-29 11:38:24 +09:00
syuilo
c351ba7820 Fix 2018-05-29 11:36:45 +09:00
syuilo
3c2d72f611 Fix bug 2018-05-29 11:32:55 +09:00
syuilo
f557407589 Fix bug 2018-05-29 11:29:02 +09:00
syuilo
a0a4ce4dd9 Fix bug 2018-05-29 11:25:28 +09:00
99 changed files with 2271 additions and 981 deletions

View File

@@ -47,7 +47,14 @@ You need to generate config file via `npm run config` command.
*5.* Build Misskey *5.* Build Misskey
---------------------------------------------------------------- ----------------------------------------------------------------
We need to use `node-gyp` to build the `crypto` module.
Build misskey with the following:
`npm run build`
If you're on Debian, you will need to install the `build-essential` package.
If you're still encountering errors about some modules, use node-gyp:
1. `npm install -g node-gyp` 1. `npm install -g node-gyp`
2. `node-gyp configure` 2. `node-gyp configure`

View File

@@ -36,38 +36,39 @@ common:
confused: "Verwirrt" confused: "Verwirrt"
pudding: "Pudding" pudding: "Pudding"
note-placeholders: note-placeholders:
a: "今どうしてる?" a: "Was machst du gerade?"
b: "何かありましたか?" b: "Was ist so passiert?"
c: "何をお考えですか?" c: "Was geht dir durch den Kopf?"
d: "言いたいことは?" d: "Willst du etwas sagen?"
e: "ここに書いてください" e: "Schreib hier etwas!"
f: "あなたが書くのを待っています..." f: "Warte darauf, das du schreibst."
delete: "Löschen" delete: "Löschen"
loading: "Laden" loading: "Laden"
ok: "OK" ok: "OK"
update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden" update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden"
my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet." my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet."
widgets: widgets:
profile: "プロフィール" analog-clock: "Analoge Uhr"
calendar: "カレンダー" profile: "Profil"
timemachine: "カレンダー(タイムマシン)" calendar: "Kalender"
activity: "アクティビティ" timemachine: "Kalender (Zeitmaschiene)"
rss: "RSSリーダー" activity: "Aktivitäten"
memo: "メモ" rss: "RSS Leser"
trends: "トレンド" memo: "Notizen"
photo-stream: "フォトストリーム" trends: "Trends"
slideshow: "スライドショー" photo-stream: "Bilder"
version: "バージョン" slideshow: "Diashow"
version: "Version"
broadcast: "ブロードキャスト" broadcast: "ブロードキャスト"
notifications: "通知" notifications: "Benachrichtigungen"
users: "おすすめユーザー" users: "Empfohlene Benutzer"
polls: "投票" polls: "Umfragen"
post-form: "投稿フォーム" post-form: "投稿フォーム"
messaging: "メッセージ" messaging: "Nachrichten"
server: "サーバー情報" server: "Server-Info"
donation: "寄付のお願い" donation: "Spenden"
nav: "ナビゲーション" nav: "Navigation"
tips: "ヒント" tips: "Tipps"
common/views/components/connect-failed.vue: common/views/components/connect-failed.vue:
title: "Verbindung zum Server ist fehlgeschlagen" title: "Verbindung zum Server ist fehlgeschlagen"
description: "Es gibt entweder ein Problem mit deiner Internetverbindung, der Server ist nicht erreichbar oder wird gerade gewartet. Bitte versuche es später noch einmal." description: "Es gibt entweder ein Problem mit deiner Internetverbindung, der Server ist nicht erreichbar oder wird gerade gewartet. Bitte versuche es später noch einmal."
@@ -122,8 +123,8 @@ common/views/components/nav.vue:
common/views/components/note-menu.vue: common/views/components/note-menu.vue:
favorite: "Diese Anmerkung favorisieren" favorite: "Diese Anmerkung favorisieren"
pin: "An die Profilseite pinnen" pin: "An die Profilseite pinnen"
delete: "削除" delete: "Löschen"
delete-confirm: "この投稿を削除しますか?" delete-confirm: "Diesen Post löschen?"
remote: "Auf Quelle anzeigen" remote: "Auf Quelle anzeigen"
common/views/components/poll.vue: common/views/components/poll.vue:
vote-to: "Stimme für '{}'" vote-to: "Stimme für '{}'"
@@ -184,14 +185,14 @@ common/views/components/twitter-setting.vue:
common/views/components/uploader.vue: common/views/components/uploader.vue:
waiting: "Warten" waiting: "Warten"
common/views/components/visibility-chooser.vue: common/views/components/visibility-chooser.vue:
public: "公開" public: "Öffentlich"
home: "ホーム" home: "Home"
home-desc: "ホームタイムラインにのみ公開" home-desc: "ホームタイムラインにのみ公開"
followers: "フォロワー" followers: "Folgende"
followers-desc: "自分のフォロワーにのみ公開" followers-desc: "Nur für diejenigen sichtbar, die dir folgen"
specified: "ダイレクト" specified: "Direkt"
specified-desc: "指定したユーザーにのみ公開" specified-desc: "Poste nur für bestimmte Benutzer"
private: "非公開" private: "Privat"
common/views/widgets/broadcast.vue: common/views/widgets/broadcast.vue:
fetching: "Laden" fetching: "Laden"
no-broadcasts: "Keine Broadcasts" no-broadcasts: "Keine Broadcasts"
@@ -207,9 +208,9 @@ common/views/widgets/server.vue:
title: "Serverinformationen" title: "Serverinformationen"
toggle: "Sicht umschalten" toggle: "Sicht umschalten"
common/views/widgets/memo.vue: common/views/widgets/memo.vue:
title: "メモ" title: "Notizen"
memo: "ここに書いて!" memo: "Schreib hier!"
save: "保存" save: "Speichern"
desktop/views/components/activity.chart.vue: desktop/views/components/activity.chart.vue:
total: "Schwarz ... komplett" total: "Schwarz ... komplett"
notes: "Blau ... Hinweise" notes: "Blau ... Hinweise"
@@ -248,29 +249,29 @@ desktop/views/components/drive.file.vue:
copy-url: "URL kopieren" copy-url: "URL kopieren"
download: "Download" download: "Download"
else-files: "その他..." else-files: "その他..."
set-as-avatar: "アイコンに設定" set-as-avatar: "Als Avatar festlegen"
set-as-banner: "バナーに設定" set-as-banner: "Setze als Banner"
open-in-app: "アプリで開く" open-in-app: "In der App öffnen"
add-app: "アプリを追加" add-app: "App hinzufügen"
rename-file: "ファイル名の変更" rename-file: "Datei umbennen"
input-new-file-name: "新しいファイル名を入力してください" input-new-file-name: "Geben Sie den neuen Dateinamen an"
copied: "コピー完了" copied: "Kopieren erfolgreich"
copied-url-to-clipboard: "URLをクリップボードにコピーしました" copied-url-to-clipboard: "URL wurde in die Zwischenablage kopiert"
desktop/views/components/drive.folder.vue: desktop/views/components/drive.folder.vue:
unable-to-process: "操作を完了できません" unable-to-process: "Der Vorgang konnte nicht beendet werden"
circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。" circular-reference-detected: "Das Zielverzeichnis ist ein Unterverzeichnis des Verzeichnisses welches du verschieben möchtest"
unhandled-error: "不明なエラー" unhandled-error: "Unbekannter Fehler"
contextmenu: contextmenu:
move-to-this-folder: "このフォルダへ移動" move-to-this-folder: "Verschiebe in diesen Ordner"
show-in-new-window: "新しいウィンドウで表示" show-in-new-window: "In einem neuen Fenster anzeigen"
rename: "名前を変更" rename: "Umbenennen"
rename-folder: "フォルダ名の変更" rename-folder: "Ordner umbenennen"
input-new-folder-name: "新しいフォルダ名を入力してください" input-new-folder-name: "Namen für neuen Ordner eingeben"
desktop/views/components/drive.nav-folder.vue: desktop/views/components/drive.nav-folder.vue:
drive: "ドライブ" drive: "Laufwerk"
desktop/views/components/drive.vue: desktop/views/components/drive.vue:
search: "検索" search: "Suchen"
load-more: "もっと読み込む" load-more: "Mehr laden"
empty-draghover: "Herzlich Willkommen!" empty-draghover: "Herzlich Willkommen!"
empty-drive: "Dein Speicher ist leer" empty-drive: "Dein Speicher ist leer"
empty-drive-description: "Du kannst rechts klicken und \"Datei hochladen\" auswählen oder eine Datei per Drag and Drop auf das Fenster ziehen." empty-drive-description: "Du kannst rechts klicken und \"Datei hochladen\" auswählen oder eine Datei per Drag and Drop auf das Fenster ziehen."
@@ -289,12 +290,14 @@ desktop/views/components/drive.vue:
upload: "Eine Datei hochladen" upload: "Eine Datei hochladen"
url-upload: "Von einer URL hochladen" url-upload: "Von einer URL hochladen"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
empty: "フォロワーはいないようです。" empty: "Dir scheint niemand zu folgen."
desktop/views/components/following-window.vue: desktop/views/components/following-window.vue:
following: "{} のフォロー" following: "{} のフォロー"
desktop/views/components/following.vue: desktop/views/components/following.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "Ort" location: "Ort"
renote: "Anmerkung" renote: "Anmerkung"
add-reaction: "Reaktion hinzufügen" add-reaction: "Reaktion hinzufügen"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "Auch geteilt von" reposted-by: "Auch geteilt von"
reply: "Antworten" reply: "Antworten"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "Speicher" drive: "Speicher"
favorites: "Favoriten" favorites: "Favoriten"
lists: "Listen" lists: "Listen"
follow-requests: "フォロー申請"
customize: "Anpassen" customize: "Anpassen"
settings: "Einstellungen" settings: "Einstellungen"
signout: "Ausloggen" signout: "Ausloggen"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "Einen neuen Post erstellen" post: "Einen neuen Post erstellen"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "Suchen" placeholder: "Suchen"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -5,7 +5,7 @@ meta:
common: common:
misskey: "A planet of fediverse" misskey: "A planet of fediverse"
about-title: "A ⭐ of fediverse." about-title: "A ⭐ of fediverse."
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。" about: "Thanks for finding Misskey. Misskey is a <b>decentralized microblogging platform</b> born on Earth. Since it exists within 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?"
time: time:
unknown: "unknown" unknown: "unknown"
future: "future" future: "future"
@@ -45,9 +45,10 @@ common:
delete: "Delete" delete: "Delete"
loading: "Loading" loading: "Loading"
ok: "OK" ok: "OK"
update-available: "A new version of Misskey is now available({newer}, current is {current}). Reload the page to apply the update." update-available: "A new version of Misskey is now available({newer}, the current version is {current}). Reload the page to apply updates."
my-token-regenerated: "Your token has been generated. You will now get logged out." my-token-regenerated: "Your token has been renewed so you will be signed out."
widgets: widgets:
analog-clock: "Analog clock"
profile: "Profile" profile: "Profile"
calendar: "Calendar" calendar: "Calendar"
timemachine: "Calendar (Time Machine)" timemachine: "Calendar (Time Machine)"
@@ -81,9 +82,9 @@ common/views/components/connect-failed.troubleshooter.vue:
checking-internet: "Checking internet connection" checking-internet: "Checking internet connection"
server: "Server connection" server: "Server connection"
checking-server: "Checking server connection" checking-server: "Checking server connection"
finding: "Finding a problem" finding: "Searching for issues"
no-network: "There is no Network connection" no-network: "No connection"
no-network-desc: "Please make sure you are connected to the Network." no-network-desc: "Please make sure you are connected to the network."
no-internet: "There is no Internet connection" no-internet: "There is no Internet connection"
no-internet-desc: "Please make sure you are connected to the Internet." no-internet-desc: "Please make sure you are connected to the Internet."
no-server: "Unable to connect to the Misskey server" no-server: "Unable to connect to the Misskey server"
@@ -93,19 +94,19 @@ common/views/components/connect-failed.troubleshooter.vue:
flush: "Clean cache" flush: "Clean cache"
set-version: "Specify version" set-version: "Specify version"
common/views/components/messaging.vue: common/views/components/messaging.vue:
search-user: "Find an user" search-user: "Find a user"
you: "You" you: "You"
no-history: "No history" no-history: "No history"
common/views/components/messaging-room.vue: common/views/components/messaging-room.vue:
empty: "No conversations" empty: "You haven't messaged this user"
more: "More" more: "Read more"
no-history: "There is no more history" no-history: "There is no more history"
resize-form: "Drag to resize" resize-form: "Drag to resize"
new-message: "New message" new-message: "New message"
common/views/components/messaging-room.form.vue: common/views/components/messaging-room.form.vue:
input-message-here: "Enter message here" input-message-here: "Enter message here"
send: "Send" send: "Send"
attach-from-local: "Attach files from your pc" attach-from-local: "Attach files from your PC"
attach-from-drive: "Attach files from your Drive" attach-from-drive: "Attach files from your Drive"
common/views/components/messaging-room.message.vue: common/views/components/messaging-room.message.vue:
is-read: "Read" is-read: "Read"
@@ -137,7 +138,7 @@ common/views/components/poll-editor.vue:
choice-n: "Choice {}" choice-n: "Choice {}"
remove: "Remove this choice" remove: "Remove this choice"
add: "+ Add a choice" add: "+ Add a choice"
destroy: "Destroy this poll" destroy: "Cancel this poll"
common/views/components/reaction-picker.vue: common/views/components/reaction-picker.vue:
choose-reaction: "Choose a reaction" choose-reaction: "Choose a reaction"
common/views/components/signin.vue: common/views/components/signin.vue:
@@ -157,10 +158,10 @@ common/views/components/signup.vue:
too-long: "Please enter up to 20 characters." too-long: "Please enter up to 20 characters."
password: "Password" password: "Password"
password-placeholder: "We recommend more than 8 characters." password-placeholder: "We recommend more than 8 characters."
weak-password: "Weak" weak-password: "Weak password"
normal-password: "So so" normal-password: "Fair password"
strong-password: "Strong" strong-password: "Strong password"
retype: "Type again" retype: "Re-enter"
retype-placeholder: "Confirm your password" retype-placeholder: "Confirm your password"
password-matched: "OK" password-matched: "OK"
password-not-matched: "Doesn't match" password-not-matched: "Doesn't match"
@@ -177,9 +178,9 @@ common/views/components/stream-indicator.vue:
common/views/components/twitter-setting.vue: common/views/components/twitter-setting.vue:
description: "If you connect your Twitter account to your Misskey account, you will be able to see your Twitter account information on your profile and you can sign-in using Twitter." description: "If you connect your Twitter account to your Misskey account, you will be able to see your Twitter account information on your profile and you can sign-in using Twitter."
connected-to: "You are connected to this Twitter account" connected-to: "You are connected to this Twitter account"
detail: "Detail..." detail: "Details..."
reconnect: "Reconnect" reconnect: "Reconnect"
connect: "Link your twitter account" connect: "Link your Twitter account"
disconnect: "Disconnect" disconnect: "Disconnect"
common/views/components/uploader.vue: common/views/components/uploader.vue:
waiting: "Waiting" waiting: "Waiting"
@@ -199,7 +200,7 @@ common/views/widgets/broadcast.vue:
next: "Next" next: "Next"
common/views/widgets/donation.vue: common/views/widgets/donation.vue:
title: "Donation" title: "Donation"
text: "To keep Misskey up and running we spend money for our domain name, servers and so on.. We don't get any money from it, and we would really appreciate it if you could donate. If you're interested contact {}. Thank you for your contribution!" text: "To keep Misskey up and running we spend money for our domain name, servers and so on. Since we don't get money from advertisements, we count on donations from all of you. If you're interested contact {}. Thank you for your contribution!"
common/views/widgets/photo-stream.vue: common/views/widgets/photo-stream.vue:
title: "Photostream" title: "Photostream"
no-photos: "No photos" no-photos: "No photos"
@@ -222,7 +223,7 @@ desktop/views/components/calendar.vue:
title: "{1} / {2}" title: "{1} / {2}"
prev: "Previous month" prev: "Previous month"
next: "Next month" next: "Next month"
go: "Click to naviguate" go: "Click to navigate"
desktop/views/components/choose-file-from-drive-window.vue: desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "Choosing files" choose-file: "Choosing files"
upload: "Upload files from your PC" upload: "Upload files from your PC"
@@ -289,19 +290,21 @@ desktop/views/components/drive.vue:
upload: "Upload a file" upload: "Upload a file"
url-upload: "Upload from a URL" url-upload: "Upload from a URL"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "Unfollow" unfollow: "Following"
follow: "Follow" follow: "Follow"
request-pending: "フォロー許可待ち"
follow-request: "Follow request"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "Followers of {}" followers: "{}'s followers"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
empty: "Seems that you dont have any followers." empty: "Seems like you dont have any followers."
desktop/views/components/following-window.vue: desktop/views/components/following-window.vue:
following: "Following of {}" following: "Following {}"
desktop/views/components/following.vue: desktop/views/components/following.vue:
empty: "You dont follow anyone." empty: "You dont follow anyone."
desktop/views/components/friends-maker.vue: desktop/views/components/friends-maker.vue:
title: "Recommended users:" title: "Recommended users:"
empty: "Similar users werent found." empty: "Couldn't find any recommended users."
fetching: "Loading…" fetching: "Loading…"
refresh: "More" refresh: "More"
close: "Close" close: "Close"
@@ -322,19 +325,16 @@ desktop/views/components/note-detail.vue:
more: "Load more conversations" more: "Load more conversations"
private: "this post is private" private: "this post is private"
deleted: "this post has been deleted" deleted: "this post has been deleted"
reposted-by: "Renoted by {}" reposted-by: "Reposted by {}"
location: "Location" location: "Location"
renote: "Renote" renote: "Repost"
add-reaction: "Add a reaction" add-reaction: "Add a reaction"
desktop/views/components/note-detail.sub.vue:
private: "this post is private"
deleted: "this post has been deleted"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "Reposted by {}" reposted-by: "Reposted by {}"
reply: "Reply" reply: "Reply"
renote: "Renote" renote: "Repost"
add-reaction: "Add a reaction" add-reaction: "Add a reaction"
detail: "Show detail" detail: "Show details"
private: "this post is private" private: "this post is private"
deleted: "this post has been deleted" deleted: "this post has been deleted"
desktop/views/components/notes.vue: desktop/views/components/notes.vue:
@@ -348,20 +348,20 @@ desktop/views/components/post-form.vue:
quote-placeholder: "Quote this note..." quote-placeholder: "Quote this note..."
submit: "Post" submit: "Post"
reply: "Reply" reply: "Reply"
renote: "Renote" renote: "Repost"
posted: "Posted!" posted: "Posted!"
replied: "Replied!" replied: "Replied!"
reposted: "Reposted!" reposted: "Reposted!"
note-failed: "Failed to note" note-failed: "Failed to note"
reply-failed: "Failed to reply" reply-failed: "Failed to reply"
renote-failed: "Failed to renote" renote-failed: "Failed to repost"
posting: "Posting" posting: "Posting"
attach-media-from-local: "Attach media from your pc" attach-media-from-local: "Attach media from your PC"
attach-media-from-drive: "Attach media from your Drive" attach-media-from-drive: "Attach media from your Drive"
attach-cancel: "Cancel attachment" attach-cancel: "Cancel attachment"
insert-a-kao: "v(‘ω’)v" insert-a-kao: "v(‘ω’)v"
create-poll: "Create a poll" create-poll: "Create a poll"
text-remain: "{} chars remaining" text-remain: "{} characters remaining"
desktop/views/components/post-form-window.vue: desktop/views/components/post-form-window.vue:
note: "New note" note: "New note"
reply: "Reply" reply: "Reply"
@@ -372,12 +372,12 @@ desktop/views/components/progress-dialog.vue:
desktop/views/components/renote-form.vue: desktop/views/components/renote-form.vue:
quote: "Quote..." quote: "Quote..."
cancel: "Cancel" cancel: "Cancel"
renote: "Renote" renote: "Repost"
reposting: "Reposting..." reposting: "Reposting..."
success: "Reposted!" success: "Reposted!"
failure: "Failed to Renote" failure: "Repost failed"
desktop/views/components/renote-form-window.vue: desktop/views/components/renote-form-window.vue:
title: "Are you sure you want to renote this note?" title: "Are you sure you want to repost this?"
desktop/views/components/settings-window.vue: desktop/views/components/settings-window.vue:
settings: "Settings" settings: "Settings"
desktop/views/components/settings.vue: desktop/views/components/settings.vue:
@@ -407,22 +407,22 @@ desktop/views/components/settings.vue:
gradient-window-header: "Use gradients on window headers" gradient-window-header: "Use gradients on window headers"
post-form-on-timeline: "Display post form at the top of the timeline" post-form-on-timeline: "Display post form at the top of the timeline"
show-reply-target: "Display reply target" show-reply-target: "Display reply target"
show-my-renotes: "Show my renote in the timeline" show-my-renotes: "Show my reposts in the timeline"
show-renoted-my-notes: "Show renoted my post in the timeline" show-renoted-my-notes: "Show my posts that have been shared in the timeline"
show-maps: "Show the map" show-maps: "Show the map"
show-maps-desc: "Show the map of the location attached to the post." show-maps-desc: "Automatically show the map of the location attached to the post."
sound: "Sound" sound: "Sound"
enable-sounds: "Enable sound" enable-sounds: "Enable sound"
enable-sounds-desc: "Play a sound when you received a post/message. This setting is stored in the browser." enable-sounds-desc: "Play a sound when you receive a post/message. This setting is stored in the browser."
volume: "Volume" volume: "Volume"
test: "Test" test: "Test"
mobile: "Mobile" mobile: "Mobile"
disable-via-mobile: "Not mark the post as 'from mobile'" disable-via-mobile: "Don't mark the post as 'from mobile'"
language: "Language" language: "Language"
pick-language: "Select a language" pick-language: "Select a language"
recommended: "Recommended" recommended: "Recommended"
auto: "Auto" auto: "Auto"
specify-language: "Specify the language" specify-language: "Specify language"
language-desc: "You need to reload the page for the changes to take effect." language-desc: "You need to reload the page for the changes to take effect."
cache: "Cache" cache: "Cache"
clean-cache: "Cleanup" clean-cache: "Cleanup"
@@ -440,11 +440,11 @@ desktop/views/components/settings.vue:
do-update: "Check for update" do-update: "Check for update"
update-settings: "Advanced settings" update-settings: "Advanced settings"
prevent-update: "Postpone updates (not recommended)" prevent-update: "Postpone updates (not recommended)"
prevent-update-desc: "You may reflect updates even if you select this setting. This setting is valid only this device." prevent-update-desc: "Even if you turn this setting on updates may apply. This setting is valid only for this device."
no-updates: "No updates available" no-updates: "No updates available"
no-updates-desc: "Your Misskey is up to date." no-updates-desc: "Your Misskey is up to date."
update-available: "New version is available!" update-available: "New version is available!"
update-available-desc: "To reload the page and updates are applied." update-available-desc: "The updates will apply if you reload the page again."
advanced-settings: "Advanced" advanced-settings: "Advanced"
debug-mode: "Enable the debug mode" debug-mode: "Enable the debug mode"
debug-mode-desc: "This setting is stored in the browser." debug-mode-desc: "This setting is stored in the browser."
@@ -478,8 +478,8 @@ desktop/views/components/settings.api.vue:
regenerate-token: "Regenerate the token" regenerate-token: "Regenerate the token"
token: "Token:" token: "Token:"
enter-password: "Please enter the password" enter-password: "Please enter the password"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "No authorized apps" no-apps: "No linked applications"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "No muted users" no-users: "No muted users"
desktop/views/components/settings.password.vue: desktop/views/components/settings.password.vue:
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "Drive" drive: "Drive"
favorites: "Favorites" favorites: "Favorites"
lists: "Lists" lists: "Lists"
follow-requests: "Follow requests"
customize: "Customize" customize: "Customize"
settings: "Settings" settings: "Settings"
signout: "Sign out" signout: "Sign out"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "Compose new Post" post: "Compose new Post"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "Search" placeholder: "Search"
desktop/views/components/received-follow-requests-window.vue:
title: "Follow requests"
accept: "Accept"
reject: "Reject"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "User lists"
create-list: "Create list" create-list: "Create list"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "Posts" notes: "Posts"
@@ -635,13 +641,13 @@ mobile/views/components/drive.vue:
load-more: "Load more" load-more: "Load more"
nothing-in-drive: "Nothing" nothing-in-drive: "Nothing"
folder-is-empty: "This folder is empty" folder-is-empty: "This folder is empty"
prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>" prompt: "What do you want to do? (Please enter a number): <1 → Upload a file | 2 → Upload a file from a URL | 3 → Create a folder | 4 → Change this folder's name | 5 → Move this folder | 6 → Delete this folder>"
deletion-alert: "Sorry! Deleting a folder is not yet implemented." deletion-alert: "Sorry! Deleting a folder is not yet implemented."
folder-name: "Folder name" folder-name: "Folder name"
root-rename-alert: "現在いる場所はルートで、フォルダではないため名前の変更はできません。名前を変更したいフォルダに移動してからやってください。" root-rename-alert: "You're in the root; it can't be renamed because it's not a folder. Navigate to a folder you want to rename and try again."
root-move-alert: "現在いる場所はルートで、フォルダではないため移動はできません。移動したいフォルダに移動してからやってください。" root-move-alert: "You're in the root; it can't be moved because it's not a folder. Navigate to a folder you want to move and try again."
url-prompt: "URL of file you want to upload" url-prompt: "URL of file you want to upload"
uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。" uploading: "Upload requested. It may take some time for the upload to complete."
mobile/views/components/drive-file-detail.vue: mobile/views/components/drive-file-detail.vue:
rename: "Rename" rename: "Rename"
mobile/views/components/drive-file-chooser.vue: mobile/views/components/drive-file-chooser.vue:
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "Hash (md5)" hash: "Hash (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "Following"
follow: "Follow" follow: "Follow"
unfollow: "Unfollow" request-pending: "フォロー許可待ち"
follow-request: "Follow request"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "Let's follow users" title: "Let's follow users"
empty: "Featured user was not found." empty: "Featured user was not found."
@@ -664,7 +672,7 @@ mobile/views/components/friends-maker.vue:
refresh: "See more" refresh: "See more"
close: "Close" close: "Close"
mobile/views/components/note.vue: mobile/views/components/note.vue:
reposted-by: "Renoted by {}" reposted-by: "Reposted by {}"
more: "See more" more: "See more"
less: "Hide" less: "Hide"
private: "this post is private" private: "this post is private"
@@ -673,7 +681,7 @@ mobile/views/components/note.vue:
mobile/views/components/note-detail.vue: mobile/views/components/note-detail.vue:
reply: "Reply" reply: "Reply"
reaction: "Reaction" reaction: "Reaction"
reposted-by: "Renoted by {}" reposted-by: "Reposted by {}"
private: "this post is private" private: "this post is private"
deleted: "this post has been deleted" deleted: "this post has been deleted"
location: "Location" location: "Location"
@@ -695,11 +703,11 @@ mobile/views/components/post-form.vue:
add-visible-user: "Add a user" add-visible-user: "Add a user"
submit: "Post" submit: "Post"
reply: "Reply" reply: "Reply"
renote: "Renote" renote: "Repost"
renote-placeholder: "Quote this post. (optional)" quote-placeholder: "Quote this post... (optional)"
reply-placeholder: "Reply to this note..." reply-placeholder: "Reply to this note..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "Comments about content (optional)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "Your device does not support location services"
error: "Error" error: "Error"
username-prompt: "Enter user name" username-prompt: "Enter user name"
mobile/views/components/sub-note-content.vue: mobile/views/components/sub-note-content.vue:
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "No notes" empty: "No notes"
load-more: "More" load-more: "More"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "Home" timeline: "Timeline"
notifications: "Notifications" notifications: "Notifications"
messaging: "Messages" messaging: "Messages"
follow-requests: "Follow requests"
search: "Search" search: "Search"
drive: "Drive" drive: "Drive"
favorites: "Favorites"
user-lists: "Lists"
widgets: "Widgets"
game: "Games"
darkmode: "Dark mode"
settings: "Settings" settings: "Settings"
about: "About Misskey" about: "About Misskey"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "All" all: "All"
known: "You know" known: "You know"
load-more: "More" load-more: "More"
mobile/views/pages/favorites.vue:
title: "Favorites"
mobile/views/pages/user-lists.vue:
title: "Lists"
enter-list-name: "Enter list name"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "Drive" drive: "Drive"
more: "Load more"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "Followers of {}" followers-of: "Followers of {}"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "Messaging" messaging: "Messaging"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "Messaging" messaging: "Messaging"
mobile/views/pages/received-follow-requests.vue:
title: "Follow requests"
accept: "Accept"
reject: "Reject"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "Post" title: "Post"
prev: "Previous note" prev: "Previous note"
@@ -779,8 +803,8 @@ mobile/views/pages/settings.vue:
circle-icons: "Use circle icons" circle-icons: "Use circle icons"
timeline: "Timeline" timeline: "Timeline"
show-reply-target: "Show reply target" show-reply-target: "Show reply target"
show-my-renotes: "Show my renotes" show-my-renotes: "Show my reposts"
show-renoted-my-notes: "Show renoted my notes" show-renoted-my-notes: "Show my reposted posts"
post-style: "Post design" post-style: "Post design"
post-style-standard: "Standard" post-style-standard: "Standard"
post-style-smart: "Smart" post-style-smart: "Smart"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Une nouvelle version de Misskey est disponible({newer}, version actuelle: {current}). Recharger la page pour appliquer la mise à jour." update-available: "Une nouvelle version de Misskey est disponible({newer}, version actuelle: {current}). Recharger la page pour appliquer la mise à jour."
my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté." my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté."
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "Uploader un fichier" upload: "Uploader un fichier"
url-upload: "Uploader d'un URL" url-upload: "Uploader d'un URL"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "Reposté par {}" reposted-by: "Reposté par {}"
reply: "Répondre" reply: "Répondre"
@@ -478,8 +478,8 @@ desktop/views/components/settings.api.vue:
regenerate-token: "Regenerer le token" regenerate-token: "Regenerer le token"
token: "Token:" token: "Token:"
enter-password: "Veuillez entrer le mot de passe" enter-password: "Veuillez entrer le mot de passe"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "Aucune application authorisée" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "Aucun utilisateurs mis en sourdine" no-users: "Aucun utilisateurs mis en sourdine"
desktop/views/components/settings.password.vue: desktop/views/components/settings.password.vue:
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "Drive" drive: "Drive"
favorites: "Favorites" favorites: "Favorites"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "Modifications" customize: "Modifications"
settings: "Réglages" settings: "Réglages"
signout: "Déconnexion" signout: "Déconnexion"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "Composer un nouveau post" post: "Composer un nouveau post"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "Chercher" placeholder: "Chercher"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "Hash (md5)" hash: "Hash (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "Suivre" follow: "Suivre"
unfollow: "Ne plus suivre" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "Poster" submit: "Poster"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "Répondre à cette note" reply-placeholder: "Répondre à cette note"
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "Pas de notes" empty: "Pas de notes"
load-more: "Afficher plus" load-more: "Afficher plus"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "Accueil" timeline: "タイムライン"
notifications: "Notifications" notifications: "Notifications"
messaging: "Messages" messaging: "Messages"
follow-requests: "フォロー申請"
search: "Rechercher" search: "Rechercher"
drive: "Drive" drive: "Drive"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "Réglages" settings: "Réglages"
about: "À propose de Misskey" about: "À propose de Misskey"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "Tout" all: "Tout"
known: "Vous connaissez" known: "Vous connaissez"
load-more: "Afficher plus" load-more: "Afficher plus"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "Drive" drive: "Drive"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "Abonnés de {}" followers-of: "Abonnés de {}"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "Messagerie" messaging: "Messagerie"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "Messagerie" messaging: "Messagerie"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "Post" title: "Post"
prev: "Note précedante" prev: "Note précedante"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -54,6 +54,7 @@ common:
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -330,8 +331,10 @@ desktop/views/components/drive.vue:
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" following: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
@@ -379,10 +382,6 @@ desktop/views/components/note-detail.vue:
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -554,7 +553,7 @@ desktop/views/components/settings.api.vue:
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
@@ -599,6 +598,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -618,7 +618,13 @@ desktop/views/components/ui.header.post.vue:
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
@@ -774,8 +780,10 @@ mobile/views/components/drive.file-detail.vue:
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
following: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
@@ -823,7 +831,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -841,11 +849,17 @@ mobile/views/components/timeline.vue:
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
@@ -859,8 +873,16 @@ mobile/views/components/users-list.vue:
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
@@ -879,6 +901,11 @@ mobile/views/pages/messaging.vue:
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -3,8 +3,8 @@ meta:
lang: "język polski" lang: "język polski"
divider: "" divider: ""
common: common:
misskey: "A planet of fediverse" misskey: "Planeta Fediwersum"
about-title: "A ⭐ of fediverse." about-title: "⭐ Fediwersum"
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。" about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
time: time:
unknown: "nieznany" unknown: "nieznany"
@@ -36,18 +36,19 @@ common:
confused: "Zmieszany" confused: "Zmieszany"
pudding: "Pudding" pudding: "Pudding"
note-placeholders: note-placeholders:
a: "今どうしてる?" a: "Co robisz?"
b: "何かありましたか?" b: "Co się wydarzyło?"
c: "何をお考えですか?" c: "Co Ci chodzi po głowie?"
d: "言いたいことは?" d: "Czy masz coś do powiedzenia?"
e: "ここに書いてください" e: "Napisz coś tutaj!"
f: "あなたが書くのを待っています..." f: "Czekamy, aż coś napiszesz."
delete: "Usuń" delete: "Usuń"
loading: "Ładowanie" loading: "Ładowanie"
ok: "OK" ok: "OK"
update-available: "Nowa wersja Misskey jest dostępna ({newer}, obecna to {current}). Odśwież stronę, aby zastosować aktualizację." update-available: "Nowa wersja Misskey jest dostępna ({newer}, obecna to {current}). Odśwież stronę, aby zastosować aktualizację."
my-token-regenerated: "Twój token został wygenerowany. Zostaniesz wylogowany." my-token-regenerated: "Twój token został wygenerowany. Zostaniesz wylogowany."
widgets: widgets:
analog-clock: "Zegar analogowy"
profile: "Profil" profile: "Profil"
calendar: "Kalendarz" calendar: "Kalendarz"
timemachine: "Kalendarz (wehikuł czasu)" timemachine: "Kalendarz (wehikuł czasu)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "Wyślij plik" upload: "Wyślij plik"
url-upload: "Wyślij z adresu URL" url-upload: "Wyślij z adresu URL"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "Przestań śledzić" unfollow: "フォロー中"
follow: "Śledź" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "Śledzący" followers: "Śledzący"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "Informacje o lokalizacji" location: "Informacje o lokalizacji"
renote: "Udostępnienie" renote: "Udostępnienie"
add-reaction: "Dodaj reakcję" add-reaction: "Dodaj reakcję"
desktop/views/components/note-detail.sub.vue:
private: "ten wpis jest prywatny"
deleted: "ten wpis został usunięty"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "Udostępniono przez {}" reposted-by: "Udostępniono przez {}"
reply: "Odpowiedz" reply: "Odpowiedz"
@@ -346,7 +346,7 @@ desktop/views/components/notifications.vue:
desktop/views/components/post-form.vue: desktop/views/components/post-form.vue:
reply-placeholder: "Odpowiedz na ten wpis…" reply-placeholder: "Odpowiedz na ten wpis…"
quote-placeholder: "Zacytuj ten wpis…" quote-placeholder: "Zacytuj ten wpis…"
submit: "投稿" submit: "Wyślij"
reply: "Odpowiedz" reply: "Odpowiedz"
renote: "Udostępnienie" renote: "Udostępnienie"
posted: "Opublikowano!" posted: "Opublikowano!"
@@ -429,7 +429,7 @@ desktop/views/components/settings.vue:
cache-warn: "Pamięć podręczna informacji o koncie/wpisów/odpowiedzi/wiadomości/ustawień przechowywanych w przeglądarce zostanie usunięta. Będziesz musiał odświeżyć stronę po wyczyszczeniu." cache-warn: "Pamięć podręczna informacji o koncie/wpisów/odpowiedzi/wiadomości/ustawień przechowywanych w przeglądarce zostanie usunięta. Będziesz musiał odświeżyć stronę po wyczyszczeniu."
cache-cleared: "Wyczyszczono pamięć podręczną" cache-cleared: "Wyczyszczono pamięć podręczną"
cache-cleared-desc: "Proszę odświeżyć stronę." cache-cleared-desc: "Proszę odświeżyć stronę."
auto-watch: "投稿の自動ウォッチ" auto-watch: "Automatycznie nasłuchuj"
auto-watch-desc: "Otrzymuj natychmiastowo informacje o wpisach/odpowiedziach/reakcjach." auto-watch-desc: "Otrzymuj natychmiastowo informacje o wpisach/odpowiedziach/reakcjach."
about: "O Misskey" about: "O Misskey"
operator: "Administrator instancji" operator: "Administrator instancji"
@@ -472,13 +472,13 @@ desktop/views/components/settings.2fa.vue:
failed: "Nie udało się skonfigurować uwierzytelniania dwuetapowego, upewnij się że wprowadziłeś prawidłowy token." failed: "Nie udało się skonfigurować uwierzytelniania dwuetapowego, upewnij się że wprowadziłeś prawidłowy token."
info: "Od teraz, wprowadzaj token wyświetlany na urządzeniu przy każdym logowaniu do Misskey." info: "Od teraz, wprowadzaj token wyświetlany na urządzeniu przy każdym logowaniu do Misskey."
desktop/views/components/settings.api.vue: desktop/views/components/settings.api.vue:
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" intro: "Aby uzyskać dostęp do API, ustaw ten token jako klucz 'i' parametrów żądań."
caution: "Nie pokazuj tego tokenu osobom trzecim (nie wprowadzaj go nigdzie indziej), aby konto nie trafiło w niepowołane ręce." caution: "Nie pokazuj tego tokenu osobom trzecim (nie wprowadzaj go nigdzie indziej), aby konto nie trafiło w niepowołane ręce."
regeneration-of-token: "W przypadku wycieku tokenu, możesz wygenerować nowy." regeneration-of-token: "W przypadku wycieku tokenu, możesz wygenerować nowy."
regenerate-token: "Wygeneruj nowy token" regenerate-token: "Wygeneruj nowy token"
token: "Token:" token: "Token:"
enter-password: "Wprowadź hasło" enter-password: "Wprowadź hasło"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "Brak zautoryzowanych aplikacji" no-apps: "Brak zautoryzowanych aplikacji"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "Brak wyciszonych użytkowników" no-users: "Brak wyciszonych użytkowników"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "Dysk" drive: "Dysk"
favorites: "Ulubione" favorites: "Ulubione"
lists: "Listy" lists: "Listy"
follow-requests: "フォロー申請"
customize: "Dostosuj" customize: "Dostosuj"
settings: "Ustawienia" settings: "Ustawienia"
signout: "Wyloguj się" signout: "Wyloguj się"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "Utwórz nowy wpis" post: "Utwórz nowy wpis"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "Szukaj" placeholder: "Szukaj"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "Utwórz listę" create-list: "Utwórz listę"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "Wpisy" notes: "Wpisy"
@@ -547,8 +553,8 @@ desktop/views/components/window.vue:
popout: "Pop-out" popout: "Pop-out"
close: "Zamknij" close: "Zamknij"
desktop/views/pages/welcome.vue: desktop/views/pages/welcome.vue:
about: "詳しく..." about: "O Misskey"
gotit: "わかった" gotit: "Rozumiem!"
signin: "Zaloguj się" signin: "Zaloguj się"
signup: "Zarejestruj się" signup: "Zarejestruj się"
signin-button: "Zaloguj się" signin-button: "Zaloguj się"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "Hash (md5)" hash: "Hash (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "Śledź" follow: "Śledź"
unfollow: "Przestań śledzić" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "Zacznij śledzić ludzi takich jak Ty" title: "Zacznij śledzić ludzi takich jak Ty"
empty: "Nie znaleziono podobnych użytkowników." empty: "Nie znaleziono podobnych użytkowników."
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "Wyślij" submit: "Wyślij"
reply: "Odpowiedz" reply: "Odpowiedz"
renote: "Udostępnij" renote: "Udostępnij"
renote-placeholder: "Zacytuj wpis… (nieobowiązkowe)" quote-placeholder: "Zacytuj ten wpis… (nieobowiązkowe)"
reply-placeholder: "Odpowiedź na ten wpis…" reply-placeholder: "Odpowiedź na ten wpis…"
cw-placeholder: "Treść ostrzeżenia (opcjonalnie)" cw-placeholder: "Treść ostrzeżenia (opcjonalnie)"
location-alert: "Twoje urządzenie nie pozwala na przekazywanie informacji o lokalizacji" location-alert: "Twoje urządzenie nie pozwala na przekazywanie informacji o lokalizacji"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "Brak wpisów" empty: "Brak wpisów"
load-more: "Więcej" load-more: "Więcej"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "Strona główna" timeline: "Oś czasu"
notifications: "Powiadomienia" notifications: "Powiadomienia"
messaging: "Wiadomości" messaging: "Wiadomości"
follow-requests: "フォロー申請"
search: "Szukaj" search: "Szukaj"
drive: "Dysk" drive: "Dysk"
favorites: "Ulubione"
user-lists: "Listy"
widgets: "Widżety"
game: "Gry"
darkmode: "Tryb ciemny"
settings: "Ustawienia" settings: "Ustawienia"
about: "O Misskey" about: "O Misskey"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "Wszyscy" all: "Wszyscy"
known: "Znasz" known: "Znasz"
load-more: "Więcej" load-more: "Więcej"
mobile/views/pages/favorites.vue:
title: "Ulubione"
mobile/views/pages/user-lists.vue:
title: "Listy"
enter-list-name: "Wprowadź nazwę listy"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "Dysk" drive: "Dysk"
more: "Załaduj więcej"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "Śledzący {}" followers-of: "Śledzący {}"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "Wiadomości" messaging: "Wiadomości"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "Wiadomości" messaging: "Wiadomości"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "Wpis" title: "Wpis"
prev: "Poprzedni wpis" prev: "Poprzedni wpis"
@@ -783,7 +807,7 @@ mobile/views/pages/settings.vue:
show-renoted-my-notes: "Pokazuj udostępnienia moich wpisów" show-renoted-my-notes: "Pokazuj udostępnienia moich wpisów"
post-style: "Styl wpisów" post-style: "Styl wpisów"
post-style-standard: "Standardowy" post-style-standard: "Standardowy"
post-style-smart: "スマート" post-style-smart: "Inteligentny"
behavior: "Zachowanie" behavior: "Zachowanie"
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół" fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
disable-via-mobile: "Nie oznaczaj wpisów jako „wysłane z telefonu”" disable-via-mobile: "Nie oznaczaj wpisów jako „wysłane z telefonu”"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -48,6 +48,7 @@ common:
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。" update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。" my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
widgets: widgets:
analog-clock: "アナログ時計"
profile: "プロフィール" profile: "プロフィール"
calendar: "カレンダー" calendar: "カレンダー"
timemachine: "カレンダー(タイムマシン)" timemachine: "カレンダー(タイムマシン)"
@@ -289,8 +290,10 @@ desktop/views/components/drive.vue:
upload: "ファイルをアップロード" upload: "ファイルをアップロード"
url-upload: "URLからアップロード" url-upload: "URLからアップロード"
desktop/views/components/follow-button.vue: desktop/views/components/follow-button.vue:
unfollow: "フォロー解除" unfollow: "フォロー"
follow: "フォローする" follow: "フォロー"
request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} のフォロワー" followers: "{} のフォロワー"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
@@ -326,9 +329,6 @@ desktop/views/components/note-detail.vue:
location: "位置情報" location: "位置情報"
renote: "Renote" renote: "Renote"
add-reaction: "リアクション" add-reaction: "リアクション"
desktop/views/components/note-detail.sub.vue:
private: "この投稿は非公開です"
deleted: "この投稿は削除されました"
desktop/views/components/notes.note.vue: desktop/views/components/notes.note.vue:
reposted-by: "{}がRenote" reposted-by: "{}がRenote"
reply: "返信" reply: "返信"
@@ -478,7 +478,7 @@ desktop/views/components/settings.api.vue:
regenerate-token: "トークンを再生成" regenerate-token: "トークンを再生成"
token: "Token:" token: "Token:"
enter-password: "パスワードを入力してください" enter-password: "パスワードを入力してください"
desktop/views/components/settings.app.vue: desktop/views/components/settings.apps.vue:
no-apps: "連携しているアプリケーションはありません" no-apps: "連携しているアプリケーションはありません"
desktop/views/components/settings.mute.vue: desktop/views/components/settings.mute.vue:
no-users: "ミュートしているユーザーはいません" no-users: "ミュートしているユーザーはいません"
@@ -516,6 +516,7 @@ desktop/views/components/ui.header.account.vue:
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り" favorites: "お気に入り"
lists: "リスト" lists: "リスト"
follow-requests: "フォロー申請"
customize: "カスタマイズ" customize: "カスタマイズ"
settings: "設定" settings: "設定"
signout: "サインアウト" signout: "サインアウト"
@@ -530,7 +531,12 @@ desktop/views/components/ui.header.post.vue:
post: "新規投稿" post: "新規投稿"
desktop/views/components/ui.header.search.vue: desktop/views/components/ui.header.search.vue:
placeholder: "検索" placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue: desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成" create-list: "リストを作成"
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "投稿" notes: "投稿"
@@ -655,8 +661,10 @@ mobile/views/components/drive.file-detail.vue:
hash: "ハッシュ (md5)" hash: "ハッシュ (md5)"
exif: "EXIF" exif: "EXIF"
mobile/views/components/follow-button.vue: mobile/views/components/follow-button.vue:
unfollow: "フォロー中"
follow: "フォロー" follow: "フォロー"
unfollow: "フォロー解除" request-pending: "フォロー許可待ち"
follow-request: "フォロー申請"
mobile/views/components/friends-maker.vue: mobile/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー" title: "気になるユーザーをフォロー"
empty: "おすすめのユーザーは見つかりませんでした。" empty: "おすすめのユーザーは見つかりませんでした。"
@@ -696,7 +704,7 @@ mobile/views/components/post-form.vue:
submit: "投稿" submit: "投稿"
reply: "返信" reply: "返信"
renote: "Renote" renote: "Renote"
renote-placeholder: "この投稿を引用... (オプション)" quote-placeholder: "この投稿を引用... (オプション)"
reply-placeholder: "この投稿への返信..." reply-placeholder: "この投稿への返信..."
cw-placeholder: "内容への注釈 (オプション)" cw-placeholder: "内容への注釈 (オプション)"
location-alert: "お使いの端末は位置情報に対応していません" location-alert: "お使いの端末は位置情報に対応していません"
@@ -711,11 +719,17 @@ mobile/views/components/timeline.vue:
empty: "投稿がありません" empty: "投稿がありません"
load-more: "もっと" load-more: "もっと"
mobile/views/components/ui.nav.vue: mobile/views/components/ui.nav.vue:
home: "ホーム" timeline: "タイムライン"
notifications: "通知" notifications: "通知"
messaging: "メッセージ" messaging: "メッセージ"
follow-requests: "フォロー申請"
search: "検索" search: "検索"
drive: "ドライブ" drive: "ドライブ"
favorites: "お気に入り"
user-lists: "リスト"
widgets: "ウィジェット"
game: "ゲーム"
darkmode: "ダークモード"
settings: "設定" settings: "設定"
about: "Misskeyについて" about: "Misskeyについて"
mobile/views/components/user-timeline.vue: mobile/views/components/user-timeline.vue:
@@ -726,8 +740,14 @@ mobile/views/components/users-list.vue:
all: "すべて" all: "すべて"
known: "知り合い" known: "知り合い"
load-more: "もっと" load-more: "もっと"
mobile/views/pages/favorites.vue:
title: "お気に入り"
mobile/views/pages/user-lists.vue:
title: "リスト"
enter-list-name: "リスト名を入力してください"
mobile/views/pages/drive.vue: mobile/views/pages/drive.vue:
drive: "ドライブ" drive: "ドライブ"
more: "もっと見る"
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "{}のフォロワー" followers-of: "{}のフォロワー"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
@@ -740,6 +760,10 @@ mobile/views/pages/messaging.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/messaging-room.vue: mobile/views/pages/messaging-room.vue:
messaging: "メッセージ" messaging: "メッセージ"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue: mobile/views/pages/note.vue:
title: "投稿" title: "投稿"
prev: "前の投稿" prev: "前の投稿"

View File

@@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "2.22.1", "version": "2.25.2",
"clientVersion": "1.0.5942", "clientVersion": "1.0.6116",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!-- Generator: Gravit.io --><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="0 0 512 512" width="512" height="512"><defs><clipPath id="_clipPath_P6eAE2OaBltOJ3gHGVajfqsOnfv4xIns"><rect width="512" height="512"/></clipPath></defs><g clip-path="url(#_clipPath_P6eAE2OaBltOJ3gHGVajfqsOnfv4xIns)"><clipPath id="_clipPath_P6q7MZAUp3XpQhVgs2GuAbegX9v4gkom"><rect x="0" y="0" width="512" height="512" transform="matrix(1,0,0,1,0,0)" fill="rgb(255,255,255)"/></clipPath><g clip-path="url(#_clipPath_P6q7MZAUp3XpQhVgs2GuAbegX9v4gkom)"><g id="Group"><g id="g4502"><g id="g5125"><g id="text4489"><path d=" M 190.093 359.243 C 167.923 359.32 148.881 345.963 139.9 330.409 C 135.104 323.615 125.617 321.198 125.482 330.409 L 125.482 372.939 C 125.482 390.026 119.253 404.799 106.794 417.258 C 94.69 429.362 79.917 435.413 62.474 435.413 C 45.387 435.413 30.614 429.362 18.155 417.258 C 6.052 404.799 0 390.026 0 372.939 L 0 139.061 C 0 125.89 3.738 113.965 11.213 103.285 C 19.045 92.25 29.012 84.596 41.116 80.325 C 47.879 77.833 54.999 76.587 62.474 76.587 C 81.697 76.587 97.716 84.062 110.531 99.013 C 117.295 106.489 121.211 110.405 122.279 110.761 C 122.279 110.761 173.043 172.145 174.467 173.213 C 175.891 174.281 180.073 182.446 190.093 182.446 C 200.112 182.446 204.829 174.281 206.253 173.213 C 207.676 172.145 258.44 110.761 258.44 110.761 C 258.796 111.117 262.534 107.201 269.654 99.013 C 282.825 84.062 299.022 76.587 318.245 76.587 C 325.364 76.587 332.484 77.833 339.603 80.325 C 351.707 84.596 361.496 92.25 368.972 103.285 C 376.803 113.965 380.719 125.89 380.719 139.061 L 380.719 372.939 C 380.719 390.026 374.489 404.799 362.03 417.258 C 349.927 429.362 335.154 435.413 317.711 435.413 C 300.624 435.413 285.851 429.362 273.391 417.258 C 261.288 404.799 255.237 390.026 255.237 372.939 L 255.237 330.409 C 254.184 318.802 243.925 326.116 240.285 330.409 C 230.674 348.208 212.262 359.167 190.093 359.243 Z M 457.535 184.448 Q 435.109 184.448 419.09 168.963 Q 403.605 152.944 403.605 130.518 Q 403.605 108.091 419.09 92.606 Q 435.109 76.587 457.535 76.587 Q 479.962 76.587 495.981 92.606 Q 512 108.091 512 130.518 Q 512 152.944 495.981 168.963 Q 479.962 184.448 457.535 184.448 Z M 458.069 195.128 Q 480.496 195.128 495.981 211.147 Q 512 227.166 512 249.592 L 512 381.482 Q 512 403.909 495.981 419.928 Q 480.496 435.413 458.069 435.413 Q 435.643 435.413 419.624 419.928 Q 403.605 403.909 403.605 381.482 L 403.605 249.592 Q 403.605 227.166 419.624 211.147 Q 435.643 195.128 458.069 195.128 Z " fill-rule="evenodd" fill="rgb(157,157,157)"/></g></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="1024px" height="512px" viewBox="0 256 1024 512" enable-background="new 0 256 1024 512" xml:space="preserve">
<polyline opacity="0.5" fill="none" stroke="#000000" stroke-width="34" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
896.5,608.5 800.5,416.5 704.5,608.5 608.5,416.5 512.5,608.5 416.5,416.5 320.5,608.5 224.5,416.5 128.5,608.5 "/>
</svg>

Before

Width:  |  Height:  |  Size: 646 B

View File

@@ -20,6 +20,7 @@ init(launch => {
// Init router // Init router
const router = new VueRouter({ const router = new VueRouter({
mode: 'history', mode: 'history',
base: '/auth/',
routes: [ routes: [
{ path: '/:token', component: Index }, { path: '/:token', component: Index },
] ]

View File

@@ -3,6 +3,7 @@
<main v-if="$store.getters.isSignedIn"> <main v-if="$store.getters.isSignedIn">
<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p> <p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
<x-form <x-form
class="form"
ref="form" ref="form"
v-if="state == 'waiting'" v-if="state == 'waiting'"
:session="session" :session="session"
@@ -26,7 +27,7 @@
<h1>サインインしてください</h1> <h1>サインインしてください</h1>
<mk-signin/> <mk-signin/>
</main> </main>
<footer><img src="/assets/auth/logo.svg" alt="Misskey"/></footer> <footer><img src="/assets/auth/icon.svg" alt="Misskey"/></footer>
</div> </div>
</template> </template>
@@ -62,7 +63,7 @@ export default Vue.extend({
// 既に連携していた場合 // 既に連携していた場合
if (this.session.app.isAuthorized) { if (this.session.app.isAuthorized) {
this.$root.$data.os.api('auth/accept', { (this as any).api('auth/accept', {
token: this.session.token token: this.session.token
}).then(() => { }).then(() => {
this.accepted(); this.accepted();
@@ -102,7 +103,7 @@ export default Vue.extend({
padding 32px padding 32px
color #555 color #555
> div > div:not(.form)
padding 64px padding 64px
> h1 > h1
@@ -143,8 +144,8 @@ export default Vue.extend({
> footer > footer
> img > img
display block display block
width 64px width 32px
height 64px height 32px
margin 0 auto margin 16px auto
</style> </style>

View File

@@ -32,9 +32,9 @@
//#region Detect app name //#region Detect app name
let app = null; let app = null;
if (url.pathname == '/docs') app = 'docs'; if (url.pathname == '/docs' || url.pathname.startsWith('/docs/')) app = 'docs';
if (url.pathname == '/dev') app = 'dev'; if (url.pathname == '/dev' || url.pathname.startsWith('/dev/')) app = 'dev';
if (url.pathname == '/auth') app = 'auth'; if (url.pathname == '/auth' || url.pathname.startsWith('/auth/')) app = 'auth';
//#endregion //#endregion
//#region Detect the user language //#region Detect the user language

View File

@@ -20,7 +20,7 @@ export class HomeStream extends Stream {
}, 1000 * 60); }, 1000 * 60);
// 自分の情報が更新されたとき // 自分の情報が更新されたとき
this.on('i_updated', i => { this.on('meUpdated', i => {
if (os.debug) { if (os.debug) {
console.log('I updated:', i); console.log('I updated:', i);
} }

View File

@@ -0,0 +1,127 @@
<template>
<svg class="mk-analog-clock" viewBox="0 0 10 10" preserveAspectRatio="none">
<circle v-for="angle, i in graduations"
:cx="5 + (Math.sin(angle) * (5 - graduationsPadding))"
:cy="5 - (Math.cos(angle) * (5 - graduationsPadding))"
:r="i % 5 == 0 ? 0.125 : 0.05"
:fill="i % 5 == 0 ? majorGraduationColor : minorGraduationColor"/>
<line
:x1="5 - (Math.sin(sAngle) * (sHandLengthRatio * handsTailLength))"
:y1="5 + (Math.cos(sAngle) * (sHandLengthRatio * handsTailLength))"
:x2="5 + (Math.sin(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
:y2="5 - (Math.cos(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
:stroke="sHandColor"
stroke-width="0.05"/>
<line
:x1="5 - (Math.sin(mAngle) * (mHandLengthRatio * handsTailLength))"
:y1="5 + (Math.cos(mAngle) * (mHandLengthRatio * handsTailLength))"
:x2="5 + (Math.sin(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
:y2="5 - (Math.cos(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
:stroke="mHandColor"
stroke-width="0.1"/>
<line
:x1="5 - (Math.sin(hAngle) * (hHandLengthRatio * handsTailLength))"
:y1="5 + (Math.cos(hAngle) * (hHandLengthRatio * handsTailLength))"
:x2="5 + (Math.sin(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
:y2="5 - (Math.cos(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
:stroke="hHandColor"
stroke-width="0.1"/>
</svg>
</template>
<script lang="ts">
import Vue from 'vue';
import { themeColor } from '../../../config';
export default Vue.extend({
props: {
dark: {
type: Boolean,
default: false
}
},
data() {
return {
now: new Date(),
clock: null,
graduationsPadding: 0.5,
handsPadding: 1,
handsTailLength: 0.7,
hHandLengthRatio: 0.75,
mHandLengthRatio: 1,
sHandLengthRatio: 1
};
},
computed: {
majorGraduationColor(): string {
return this.dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)';
},
minorGraduationColor(): string {
return this.dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
},
sHandColor(): string {
return this.dark ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.3)';
},
mHandColor(): string {
return this.dark ? '#fff' : '#777';
},
hHandColor(): string {
return themeColor;
},
s(): number {
return this.now.getSeconds();
},
m(): number {
return this.now.getMinutes();
},
h(): number {
return this.now.getHours();
},
hAngle(): number {
return Math.PI * (this.h % 12 + this.m / 60) / 6;
},
mAngle(): number {
return Math.PI * (this.m + this.s / 60) / 30;
},
sAngle(): number {
return Math.PI * this.s / 30;
},
graduations(): any {
const angles = [];
for (let i = 0; i < 60; i++) {
const angle = Math.PI * i / 30;
angles.push(angle);
}
return angles;
}
},
mounted() {
this.clock = setInterval(this.tick, 1000);
},
beforeDestroy() {
clearInterval(this.clock);
},
methods: {
tick() {
this.now = new Date();
}
}
});
</script>
<style lang="stylus" scoped>
.mk-analog-clock
display block
</style>

View File

@@ -1,5 +1,6 @@
import Vue from 'vue'; import Vue from 'vue';
import analogClock from './analog-clock.vue';
import signin from './signin.vue'; import signin from './signin.vue';
import signup from './signup.vue'; import signup from './signup.vue';
import forkit from './forkit.vue'; import forkit from './forkit.vue';
@@ -27,6 +28,7 @@ import Switch from './switch.vue';
import Othello from './othello.vue'; import Othello from './othello.vue';
import welcomeTimeline from './welcome-timeline.vue'; import welcomeTimeline from './welcome-timeline.vue';
Vue.component('mk-analog-clock', analogClock);
Vue.component('mk-signin', signin); Vue.component('mk-signin', signin);
Vue.component('mk-signup', signup); Vue.component('mk-signup', signup);
Vue.component('mk-forkit', forkit); Vue.component('mk-forkit', forkit);

View File

@@ -1,9 +1,11 @@
<template> <template>
<div class="mk-media-list" :data-count="mediaList.length"> <div class="mk-media-list">
<div :data-count="mediaList.length" ref="grid">
<template v-for="media in mediaList"> <template v-for="media in mediaList">
<mk-media-video :video="media" :key="media.id" v-if="media.type.startsWith('video')" :inline-playable="mediaList.length === 1"/> <mk-media-video :video="media" :key="media.id" v-if="media.type.startsWith('video')" :inline-playable="mediaList.length === 1"/>
<mk-media-image :image="media" :key="media.id" v-else :raw="raw"/> <mk-media-image :image="media" :key="media.id" v-else :raw="raw"/>
</template> </template>
</div>
</div> </div>
</template> </template>
@@ -18,18 +20,31 @@ export default Vue.extend({
raw: { raw: {
default: false default: false
} }
},
mounted() {
// for Safari bug
this.$refs.grid.style.height = this.$refs.grid.clientHeight ? `${this.$refs.grid.clientHeight}px` : '128px';
} }
}); });
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
.mk-media-list .mk-media-list
width 100%
&:before
content ''
display block
padding-top 56.25% // 16:9
> div
position absolute
top 0
right 0
bottom 0
left 0
display grid display grid
grid-gap 4px grid-gap 4px
height 256px
@media (max-width 500px)
height 192px
&[data-count="1"] &[data-count="1"]
grid-template-rows 1fr grid-template-rows 1fr
@@ -43,7 +58,7 @@ export default Vue.extend({
grid-row 1 / 3 grid-row 1 / 3
:nth-child(3) :nth-child(3)
grid-column 2 / 3 grid-column 2 / 3
grid-row 2/3 grid-row 2 / 3
&[data-count="4"] &[data-count="4"]
grid-template-columns 1fr 1fr grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr grid-template-rows 1fr 1fr

View File

@@ -0,0 +1,41 @@
<template>
<div class="mkw-analog-clock">
<mk-widget-container :naked="props.naked" :show-header="false">
<div class="mkw-analog-clock--body">
<mk-analog-clock :dark="$store.state.device.darkmode"/>
</div>
</mk-widget-container>
</div>
</template>
<script lang="ts">
import define from '../../../common/define-widget';
export default define({
name: 'analog-clock',
props: () => ({
naked: false
})
}).extend({
methods: {
func() {
this.props.naked = !this.props.naked;
this.save();
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
root(isDark)
.mkw-analog-clock--body
padding 8px
.mkw-analog-clock[data-darkmode]
root(true)
.mkw-analog-clock:not([data-darkmode])
root(false)
</style>

View File

@@ -1,5 +1,6 @@
import Vue from 'vue'; import Vue from 'vue';
import wAnalogClock from './analog-clock.vue';
import wVersion from './version.vue'; import wVersion from './version.vue';
import wRss from './rss.vue'; import wRss from './rss.vue';
import wServer from './server.vue'; import wServer from './server.vue';
@@ -12,6 +13,7 @@ import wTips from './tips.vue';
import wDonation from './donation.vue'; import wDonation from './donation.vue';
import wNav from './nav.vue'; import wNav from './nav.vue';
Vue.component('mkw-analog-clock', wAnalogClock);
Vue.component('mkw-nav', wNav); Vue.component('mkw-nav', wNav);
Vue.component('mkw-calendar', wCalendar); Vue.component('mkw-calendar', wCalendar);
Vue.component('mkw-photo-stream', wPhotoStream); Vue.component('mkw-photo-stream', wPhotoStream);

View File

@@ -73,6 +73,7 @@ root(isDark)
background isDark ? #282c37 : #fff background isDark ? #282c37 : #fff
border none border none
border-bottom solid 1px isDark ? #1c2023 : #eee border-bottom solid 1px isDark ? #1c2023 : #eee
border-radius 0
> button > button
display block display block

View File

@@ -1,108 +0,0 @@
<template>
<canvas class="mk-analog-clock" ref="canvas" width="256" height="256"></canvas>
</template>
<script lang="ts">
import Vue from 'vue';
import { themeColor } from '../../../config';
const Vec2 = function(this: any, x, y) {
this.x = x;
this.y = y;
};
export default Vue.extend({
data() {
return {
clock: null
};
},
mounted() {
this.tick();
this.clock = setInterval(this.tick, 1000);
},
beforeDestroy() {
clearInterval(this.clock);
},
methods: {
tick() {
const canv = this.$refs.canvas as any;
const now = new Date();
const s = now.getSeconds();
const m = now.getMinutes();
const h = now.getHours();
const ctx = canv.getContext('2d');
const canvW = canv.width;
const canvH = canv.height;
ctx.clearRect(0, 0, canvW, canvH);
{ // 背景
const center = Math.min((canvW / 2), (canvH / 2));
const lineStart = center * 0.90;
const shortLineEnd = center * 0.87;
const longLineEnd = center * 0.84;
for (let i = 0; i < 60; i++) {
const angle = Math.PI * i / 30;
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
ctx.beginPath();
ctx.lineWidth = 1;
ctx.moveTo((canvW / 2) + uv.x * lineStart, (canvH / 2) + uv.y * lineStart);
if (i % 5 == 0) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
ctx.lineTo((canvW / 2) + uv.x * longLineEnd, (canvH / 2) + uv.y * longLineEnd);
} else {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineTo((canvW / 2) + uv.x * shortLineEnd, (canvH / 2) + uv.y * shortLineEnd);
}
ctx.stroke();
}
}
{ // 分
const angle = Math.PI * (m + s / 60) / 30;
const length = Math.min(canvW, canvH) / 2.6;
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
ctx.beginPath();
ctx.strokeStyle = '#ffffff';
ctx.lineWidth = 2;
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
ctx.stroke();
}
{ // 時
const angle = Math.PI * (h % 12 + m / 60) / 6;
const length = Math.min(canvW, canvH) / 4;
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
ctx.beginPath();
ctx.strokeStyle = themeColor;
ctx.lineWidth = 2;
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
ctx.stroke();
}
{ // 秒
const angle = Math.PI * s / 30;
const length = Math.min(canvW, canvH) / 2.6;
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
ctx.beginPath();
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 1;
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
ctx.stroke();
}
}
}
});
</script>
<style lang="stylus" scoped>
.mk-analog-clock
display block
width 256px
height 256px
</style>

View File

@@ -62,7 +62,7 @@ export default Vue.extend({
onContextmenu(e) { onContextmenu(e) {
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.rename%', text: '%i18n:@contextmenu.rename%',
icon: '%fa:i-cursor%', icon: '%fa:i-cursor%',

View File

@@ -52,7 +52,7 @@ export default Vue.extend({
onContextmenu(e) { onContextmenu(e) {
this.isContextmenuShowing = true; this.isContextmenuShowing = true;
contextmenu(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.move-to-this-folder%', text: '%i18n:@contextmenu.move-to-this-folder%',
icon: '%fa:arrow-right%', icon: '%fa:arrow-right%',

View File

@@ -136,7 +136,7 @@ export default Vue.extend({
}, },
methods: { methods: {
onContextmenu(e) { onContextmenu(e) {
contextmenu(e, [{ contextmenu((this as any).os)(e, [{
type: 'item', type: 'item',
text: '%i18n:@contextmenu.create-folder%', text: '%i18n:@contextmenu.create-folder%',
icon: '%fa:R folder%', icon: '%fa:R folder%',

View File

@@ -1,19 +1,16 @@
<template> <template>
<button class="mk-follow-button" <button class="mk-follow-button"
:class="{ wait, follow: !user.isFollowing, unfollow: user.isFollowing, big: size == 'big' }" :class="{ wait, active: u.isFollowing || u.hasPendingFollowRequestFromYou, big: size == 'big' }"
@click="onClick" @click="onClick"
:disabled="wait" :disabled="wait"
:title="user.isFollowing ? '%i18n:@unfollow%' : '%i18n:@follow%'"
> >
<template v-if="!wait && user.isFollowing"> <template v-if="!wait">
<template v-if="size == 'compact'">%fa:minus%</template> <template v-if="u.hasPendingFollowRequestFromYou">%fa:hourglass-half%<template v-if="size == 'big'"> %i18n:@request-pending%</template></template>
<template v-if="size == 'big'">%fa:minus%%i18n:@unfollow%</template> <template v-else-if="u.isFollowing">%fa:minus%<template v-if="size == 'big'"> %i18n:@following%</template></template>
<template v-else-if="!u.isFollowing && u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow-request%</template></template>
<template v-else-if="!u.isFollowing && !u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow%</template></template>
</template> </template>
<template v-if="!wait && !user.isFollowing"> <template v-else>%fa:spinner .pulse .fw%</template>
<template v-if="size == 'compact'">%fa:plus%</template>
<template v-if="size == 'big'">%fa:plus%%i18n:@follow%</template>
</template>
<template v-if="wait">%fa:spinner .pulse .fw%</template>
</button> </button>
</template> </template>
@@ -34,6 +31,7 @@ export default Vue.extend({
data() { data() {
return { return {
u: this.user,
wait: false, wait: false,
connection: null, connection: null,
connectionId: null connectionId: null
@@ -56,39 +54,44 @@ export default Vue.extend({
methods: { methods: {
onFollow(user) { onFollow(user) {
if (user.id == this.user.id) { if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing; this.user.isFollowing = user.isFollowing;
} }
}, },
onUnfollow(user) { onUnfollow(user) {
if (user.id == this.user.id) { if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing; this.user.isFollowing = user.isFollowing;
} }
}, },
onClick() { async onClick() {
this.wait = true; this.wait = true;
if (this.user.isFollowing) {
(this as any).api('following/delete', { try {
userId: this.user.id if (this.u.isFollowing) {
}).then(() => { this.u = await (this as any).api('following/delete', {
this.user.isFollowing = false; userId: this.u.id
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false;
}); });
} else { } else {
(this as any).api('following/create', { if (this.u.isLocked && this.u.hasPendingFollowRequestFromYou) {
userId: this.user.id this.u = await (this as any).api('following/requests/cancel', {
}).then(() => { userId: this.u.id
this.user.isFollowing = true;
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false;
}); });
} else if (this.u.isLocked) {
this.u = await (this as any).api('following/create', {
userId: this.u.id
});
} else {
this.u = await (this as any).api('following/create', {
userId: this.user.id
});
}
}
} catch (e) {
console.error(e);
} finally {
this.wait = false;
} }
} }
} }
@@ -124,7 +127,7 @@ root(isDark)
border 2px solid rgba($theme-color, 0.3) border 2px solid rgba($theme-color, 0.3)
border-radius 8px border-radius 8px
&.follow &:not(.active)
color isDark ? #fff : #888 color isDark ? #fff : #888
background isDark ? linear-gradient(to bottom, #313543 0%, #282c37 100%) : linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%) background isDark ? linear-gradient(to bottom, #313543 0%, #282c37 100%) : linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px isDark ? #1c2023 : #e2e2e2 border solid 1px isDark ? #1c2023 : #e2e2e2
@@ -137,7 +140,7 @@ root(isDark)
background isDark ? #22262f : #ececec background isDark ? #22262f : #ececec
border-color isDark ? #151a1d : #dcdcdc border-color isDark ? #151a1d : #dcdcdc
&.unfollow &.active
color $theme-color-foreground color $theme-color-foreground
background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%) background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%)
border solid 1px lighten($theme-color, 15%) border solid 1px lighten($theme-color, 15%)
@@ -162,9 +165,6 @@ root(isDark)
height 38px height 38px
line-height 38px line-height 38px
i
margin-right 8px
.mk-follow-button[data-darkmode] .mk-follow-button[data-darkmode]
root(true) root(true)

View File

@@ -7,6 +7,7 @@
<p>%i18n:@add-widget%</p> <p>%i18n:@add-widget%</p>
<select v-model="widgetAdderSelected"> <select v-model="widgetAdderSelected">
<option value="profile">%i18n:common.widgets.profile%</option> <option value="profile">%i18n:common.widgets.profile%</option>
<option value="analog-clock">%i18n:common.widgets.analog-clock%</option>
<option value="calendar">%i18n:common.widgets.calendar%</option> <option value="calendar">%i18n:common.widgets.calendar%</option>
<option value="timemachine">%i18n:common.widgets.timemachine%</option> <option value="timemachine">%i18n:common.widgets.timemachine%</option>
<option value="activity">%i18n:common.widgets.activity%</option> <option value="activity">%i18n:common.widgets.activity%</option>
@@ -62,9 +63,8 @@
<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/> <component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
</div> </div>
<div class="main"> <div class="main">
<mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/> <mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/> <mk-timeline class="tl" cref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
</div> </div>
</template> </template>
</div> </div>
@@ -298,11 +298,18 @@ root(isDark)
width calc(100% - 275px * 2) width calc(100% - 275px * 2)
order 2 order 2
.mk-post-form > .form
margin-bottom 16px margin-bottom 16px
border solid 1px rgba(#000, 0.075) border solid 1px rgba(#000, 0.075)
border-radius 4px border-radius 4px
@media (max-width 700px)
padding 0
> .tl
border none
border-radius 0
> *:not(.main) > *:not(.main)
width 275px width 275px
padding 16px 0 16px 0 padding 16px 0 16px 0

View File

@@ -9,7 +9,6 @@ import subNoteContent from './sub-note-content.vue';
import window from './window.vue'; import window from './window.vue';
import noteFormWindow from './post-form-window.vue'; import noteFormWindow from './post-form-window.vue';
import renoteFormWindow from './renote-form-window.vue'; import renoteFormWindow from './renote-form-window.vue';
import analogClock from './analog-clock.vue';
import ellipsisIcon from './ellipsis-icon.vue'; import ellipsisIcon from './ellipsis-icon.vue';
import mediaImage from './media-image.vue'; import mediaImage from './media-image.vue';
import mediaImageDialog from './media-image-dialog.vue'; import mediaImageDialog from './media-image-dialog.vue';
@@ -40,7 +39,6 @@ Vue.component('mk-sub-note-content', subNoteContent);
Vue.component('mk-window', window); Vue.component('mk-window', window);
Vue.component('mk-post-form-window', noteFormWindow); Vue.component('mk-post-form-window', noteFormWindow);
Vue.component('mk-renote-form-window', renoteFormWindow); Vue.component('mk-renote-form-window', renoteFormWindow);
Vue.component('mk-analog-clock', analogClock);
Vue.component('mk-ellipsis-icon', ellipsisIcon); Vue.component('mk-ellipsis-icon', ellipsisIcon);
Vue.component('mk-media-image', mediaImage); Vue.component('mk-media-image', mediaImage);
Vue.component('mk-media-image-dialog', mediaImageDialog); Vue.component('mk-media-image-dialog', mediaImageDialog);

View File

@@ -1,124 +0,0 @@
<template>
<div class="sub" :title="title">
<mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<div class="left">
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span class="username"><mk-acct :user="note.user"/></span>
</div>
<div class="right">
<router-link class="time" :to="note | notePage">
<mk-time :time="note.createdAt"/>
</router-link>
</div>
</header>
<div class="body">
<div class="text">
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
<mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
</div>
<div class="media" v-if="note.mediaIds.length > 0">
<mk-media-list :media-list="note.media"/>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import dateStringify from '../../../common/scripts/date-stringify';
export default Vue.extend({
props: ['note'],
computed: {
title(): string {
return dateStringify(this.note.createdAt);
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
margin 0
padding 20px 32px
background isDark ? #21242d : #fdfdfd
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar
display block
float left
margin 0 16px 0 0
width 44px
height 44px
border-radius 4px
> .main
float left
width calc(100% - 60px)
> header
margin-bottom 4px
white-space nowrap
&:after
content ""
display block
clear both
> .left
float left
> .name
display inline
margin 0
padding 0
color isDark ? #fff : #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
text-align left
margin 0 0 0 8px
color isDark ? #606984 : #ccc
> .right
float right
> .time
font-size 0.9em
color isDark ? #606984 : #c0c0c0
> .body
> .text
cursor default
display block
margin 0
padding 0
overflow-wrap break-word
font-size 1em
color isDark ? #959ba7 : #717171
.sub[data-darkmode]
root(true)
.sub:not([data-darkmode])
root(false)
</style>

View File

@@ -89,7 +89,7 @@ import MkPostFormWindow from './post-form-window.vue';
import MkRenoteFormWindow from './renote-form-window.vue'; import MkRenoteFormWindow from './renote-form-window.vue';
import MkNoteMenu from '../../../common/views/components/note-menu.vue'; import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note-detail.sub.vue'; import XSub from './notes.note.sub.vue';
export default Vue.extend({ export default Vue.extend({
components: { components: {
@@ -218,8 +218,6 @@ export default Vue.extend({
@import '~const.styl' @import '~const.styl'
root(isDark) root(isDark)
margin 0 auto
padding 0
overflow hidden overflow hidden
text-align left text-align left
background isDark ? #282C37 : #fff background isDark ? #282C37 : #fff

View File

@@ -5,9 +5,18 @@
<header> <header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> <router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span class="username"><mk-acct :user="note.user"/></span> <span class="username"><mk-acct :user="note.user"/></span>
<router-link class="time" :to="note | notePage"> <div class="info">
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
<router-link class="created-at" :to="note | notePage">
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</router-link> </router-link>
<span class="visibility" v-if="note.visibility != 'public'">
<template v-if="note.visibility == 'home'">%fa:home%</template>
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
<template v-if="note.visibility == 'private'">%fa:lock%</template>
</span>
</div>
</header> </header>
<div class="body"> <div class="body">
<mk-sub-note-content class="text" :note="note"/> <mk-sub-note-content class="text" :note="note"/>
@@ -32,24 +41,20 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
root(isDark) root(isDark)
display flex
font-size 0.9em font-size 0.9em
&:after
content ""
display block
clear both
> .avatar > .avatar
flex-shrink 0
display block display block
float left
margin 0 12px 0 0 margin 0 12px 0 0
width 48px width 48px
height 48px height 48px
border-radius 8px border-radius 8px
> .main > .main
float left flex 1
width calc(100% - 60px) min-width 0
> header > header
display flex display flex
@@ -75,10 +80,19 @@ root(isDark)
text-overflow ellipsis text-overflow ellipsis
color isDark ? #606984 : #d1d8da color isDark ? #606984 : #d1d8da
> .time > .info
margin-left auto margin-left auto
font-size 0.9em
> *
color isDark ? #606984 : #b2b8bb color isDark ? #606984 : #b2b8bb
> .mobile
margin-right 6px
> .visibility
margin-left 6px
> .body > .body
> .text > .text

View File

@@ -44,27 +44,23 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
root(isDark) root(isDark)
display flex
margin 0 margin 0
padding 16px 32px padding 16px 32px
font-size 0.9em font-size 0.9em
background isDark ? #21242d : #fcfcfc background isDark ? #21242d : #fcfcfc
&:after
content ""
display block
clear both
> .avatar > .avatar
flex-shrink 0
display block display block
float left
margin 0 12px 0 0 margin 0 12px 0 0
width 48px width 48px
height 48px height 48px
border-radius 8px border-radius 8px
> .main > .main
float left flex 1
width calc(100% - 60px) min-width 0
> header > header
display flex display flex
@@ -119,8 +115,6 @@ root(isDark)
margin-left 6px margin-left 6px
> .body > .body
max-height 128px
overflow hidden
> .text > .text
cursor default cursor default

View File

@@ -387,20 +387,16 @@ root(isDark)
padding-top 8px padding-top 8px
> article > article
display flex
padding 28px 32px 18px 32px padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover &:hover
> .main > footer > button > .main > footer > button
color isDark ? #707b97 : #888 color isDark ? #707b97 : #888
> .avatar > .avatar
flex-shrink 0
display block display block
float left
margin 0 16px 10px 0 margin 0 16px 10px 0
width 58px width 58px
height 58px height 58px
@@ -410,8 +406,8 @@ root(isDark)
//top 74px //top 74px
> .main > .main
float left flex 1
width calc(100% - 74px) min-width 0
> header > header
display flex display flex
@@ -467,7 +463,7 @@ root(isDark)
> .app > .app
margin-right 8px margin-right 8px
padding-right 8px padding-right 8px
border-right solid 1px #eaeaea border-right solid 1px isDark ? #1c2023 : #eaeaea
> .visibility > .visibility
margin-left 8px margin-left 8px
@@ -556,7 +552,7 @@ root(isDark)
padding 2px 8px 2px 16px padding 2px 8px 2px 16px
font-size 90% font-size 90%
color #8d969e color #8d969e
background #edf0f3 background isDark ? #313543 : #edf0f3
border-radius 4px border-radius 4px
&:before &:before
@@ -569,7 +565,7 @@ root(isDark)
width 8px width 8px
height 8px height 8px
margin auto 0 margin auto 0
background #fff background isDark ? #282c37 : #fff
border-radius 100% border-radius 100%
&:hover &:hover

View File

@@ -5,6 +5,7 @@
<template v-for="(notification, i) in _notifications"> <template v-for="(notification, i) in _notifications">
<div class="notification" :class="notification.type" :key="notification.id"> <div class="notification" :class="notification.type" :key="notification.id">
<mk-time :time="notification.createdAt"/> <mk-time :time="notification.createdAt"/>
<template v-if="notification.type == 'reaction'"> <template v-if="notification.type == 'reaction'">
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
@@ -17,6 +18,7 @@
</router-link> </router-link>
</div> </div>
</template> </template>
<template v-if="notification.type == 'renote'"> <template v-if="notification.type == 'renote'">
<mk-avatar class="avatar" :user="notification.note.user"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
@@ -28,6 +30,7 @@
</router-link> </router-link>
</div> </div>
</template> </template>
<template v-if="notification.type == 'quote'"> <template v-if="notification.type == 'quote'">
<mk-avatar class="avatar" :user="notification.note.user"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
@@ -37,6 +40,7 @@
<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link> <router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
</div> </div>
</template> </template>
<template v-if="notification.type == 'follow'"> <template v-if="notification.type == 'follow'">
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
@@ -45,6 +49,16 @@
</p> </p>
</div> </div>
</template> </template>
<template v-if="notification.type == 'receiveFollowRequest'">
<mk-avatar class="avatar" :user="notification.user"/>
<div class="text">
<p>%fa:user-clock%
<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
</p>
</div>
</template>
<template v-if="notification.type == 'reply'"> <template v-if="notification.type == 'reply'">
<mk-avatar class="avatar" :user="notification.note.user"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
@@ -54,6 +68,7 @@
<router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link> <router-link class="note-preview" :to="notification.note | notePage">{{ getNoteSummary(notification.note) }}</router-link>
</div> </div>
</template> </template>
<template v-if="notification.type == 'mention'"> <template v-if="notification.type == 'mention'">
<mk-avatar class="avatar" :user="notification.note.user"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
@@ -63,6 +78,7 @@
<a class="note-preview" :href="notification.note | notePage">{{ getNoteSummary(notification.note) }}</a> <a class="note-preview" :href="notification.note | notePage">{{ getNoteSummary(notification.note) }}</a>
</div> </div>
</template> </template>
<template v-if="notification.type == 'poll_vote'"> <template v-if="notification.type == 'poll_vote'">
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
@@ -73,6 +89,7 @@
</div> </div>
</template> </template>
</div> </div>
<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'"> <p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
<span>%fa:angle-up%{{ notification._datetext }}</span> <span>%fa:angle-up%{{ notification._datetext }}</span>
<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span> <span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
@@ -251,6 +268,10 @@ root(isDark)
.text p i .text p i
color #53c7ce color #53c7ce
&.receiveFollowRequest
.text p i
color #888
&.reply, &.mention &.reply, &.mention
.text p i .text p i
color #555 color #555

View File

@@ -1,14 +1,15 @@
<template> <template>
<mk-window ref="window" is-modal @closed="$destroy"> <mk-window class="mk-post-form-window" ref="window" is-modal @closed="$destroy">
<span slot="header"> <span slot="header" class="mk-post-form-window--header">
<span :class="$style.icon" v-if="geo">%fa:map-marker-alt%</span> <span class="icon" v-if="geo">%fa:map-marker-alt%</span>
<span v-if="!reply">%i18n:@note%</span> <span v-if="!reply">%i18n:@note%</span>
<span v-if="reply">%i18n:@reply%</span> <span v-if="reply">%i18n:@reply%</span>
<span :class="$style.count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span> <span class="count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span>
<span :class="$style.count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span> <span class="count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
</span> </span>
<mk-note-preview v-if="reply" :class="$style.notePreview" :note="reply"/> <div class="mk-post-form-window--body">
<mk-note-preview v-if="reply" class="notePreview" :note="reply"/>
<mk-post-form ref="form" <mk-post-form ref="form"
:reply="reply" :reply="reply"
@posted="onPosted" @posted="onPosted"
@@ -16,6 +17,7 @@
@change-attached-media="onChangeMedia" @change-attached-media="onChangeMedia"
@geo-attached="onGeoAttached" @geo-attached="onGeoAttached"
@geo-dettached="onGeoDettached"/> @geo-dettached="onGeoDettached"/>
</div>
</mk-window> </mk-window>
</template> </template>
@@ -56,11 +58,13 @@ export default Vue.extend({
}); });
</script> </script>
<style lang="stylus" module> <style lang="stylus" scoped>
.icon root(isDark)
.mk-post-form-window--header
.icon
margin-right 8px margin-right 8px
.count .count
margin-left 8px margin-left 8px
opacity 0.8 opacity 0.8
@@ -70,7 +74,17 @@ export default Vue.extend({
&:after &:after
content ')' content ')'
.notePreview .mk-post-form-window--body
.notePreview
if isDark
margin 16px 22px 0 22px margin 16px 22px 0 22px
else
margin 16px 22px
.mk-post-form-window[data-darkmode]
root(true)
.mk-post-form-window:not([data-darkmode])
root(false)
</style> </style>

View File

@@ -0,0 +1,72 @@
<template>
<mk-window ref="window" is-modal width="450px" height="500px" @closed="$destroy">
<span slot="header">%fa:envelope R% %i18n:@title%</span>
<div data-id="c1136cec-1278-49b1-9ea7-412c1ef794f4" :data-darkmode="$store.state.device.darkmode">
<div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link>
<span>
<a @click="accept(req.follower)">%i18n:@accept%</a>|<a @click="reject(req.follower)">%i18n:@reject%</a>
</span>
</div>
</div>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
data() {
return {
fetching: true,
requests: []
};
},
mounted() {
(this as any).api('following/requests/list').then(requests => {
this.fetching = false;
this.requests = requests;
});
},
methods: {
accept(user) {
(this as any).api('following/requests/accept', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
reject(user) {
(this as any).api('following/requests/reject', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
close() {
(this as any).$refs.window.close();
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
padding 16px
> button
margin-bottom 16px
> div
display flex
padding 16px
border solid 1px isDark ? #1c2023 : #eee
border-radius 4px
> span
margin 0 0 0 auto
[data-id="c1136cec-1278-49b1-9ea7-412c1ef794f4"][data-darkmode]
root(true)
[data-id="c1136cec-1278-49b1-9ea7-412c1ef794f4"]:not([data-darkmode])
root(false)
</style>

View File

@@ -23,7 +23,11 @@
</label> </label>
<button class="ui primary" @click="save">%i18n:@save%</button> <button class="ui primary" @click="save">%i18n:@save%</button>
<section> <section>
<h2>その他</h2> <h2>%i18n:@locked-account%</h2>
<mk-switch v-model="$store.state.i.isLocked" @change="onChangeIsLocked" text="%i18n:@is-locked%"/>
</section>
<section>
<h2>%i18n:@other%</h2>
<mk-switch v-model="$store.state.i.isBot" @change="onChangeIsBot" text="%i18n:@is-bot%"/> <mk-switch v-model="$store.state.i.isBot" @change="onChangeIsBot" text="%i18n:@is-bot%"/>
<mk-switch v-model="$store.state.i.isCat" @change="onChangeIsCat" text="%i18n:@is-cat%"/> <mk-switch v-model="$store.state.i.isCat" @change="onChangeIsCat" text="%i18n:@is-cat%"/>
</section> </section>
@@ -62,6 +66,11 @@ export default Vue.extend({
(this as any).apis.notify('プロフィールを更新しました'); (this as any).apis.notify('プロフィールを更新しました');
}); });
}, },
onChangeIsLocked() {
(this as any).api('i/update', {
isLocked: this.$store.state.i.isLocked
});
},
onChangeIsBot() { onChangeIsBot() {
(this as any).api('i/update', { (this as any).api('i/update', {
isBot: this.$store.state.i.isBot isBot: this.$store.state.i.isBot

View File

@@ -5,7 +5,7 @@
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> <span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a> <a class="reply" v-if="note.replyId">%fa:reply%</a>
<mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/> <mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
<a class="rp" v-if="note.renoteId" :href="`/note:${note.renoteId}`">RP: ...</a> <a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
</div> </div>
<details v-if="note.media.length > 0"> <details v-if="note.media.length > 0">
<summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary> <summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary>

View File

@@ -36,7 +36,7 @@ export default Vue.extend({
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
.mk-ui-notification root(isDark)
display block display block
position fixed position fixed
z-index 10000 z-index 10000
@@ -46,10 +46,10 @@ export default Vue.extend({
margin 0 auto margin 0 auto
padding 128px 0 0 0 padding 128px 0 0 0
width 500px width 500px
color rgba(#000, 0.6) color rgba(isDark ? #fff : #000, 0.6)
background rgba(#fff, 0.9) background rgba(isDark ? #282C37 : #fff, 0.9)
border-radius 0 0 8px 8px border-radius 0 0 8px 8px
box-shadow 0 2px 4px rgba(#000, 0.2) box-shadow 0 2px 4px rgba(#000, isDark ? 0.4 : 0.2)
transform translateY(-64px) transform translateY(-64px)
opacity 0 opacity 0
@@ -58,4 +58,10 @@ export default Vue.extend({
line-height 64px line-height 64px
text-align center text-align center
.mk-ui-notification[data-darkmode]
root(true)
.mk-ui-notification:not([data-darkmode])
root(false)
</style> </style>

View File

@@ -19,6 +19,9 @@
<li @click="list"> <li @click="list">
<p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p> <p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p>
</li> </li>
<li @click="followRequests" v-if="$store.state.i.isLocked">
<p>%fa:envelope R%<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>%fa:angle-right%</p>
</li>
</ul> </ul>
<ul> <ul>
<li> <li>
@@ -46,6 +49,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import MkUserListsWindow from './user-lists-window.vue'; import MkUserListsWindow from './user-lists-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';
import contains from '../../../common/scripts/contains'; import contains from '../../../common/scripts/contains';
@@ -91,6 +95,10 @@ export default Vue.extend({
this.$router.push(`i/lists/${ list.id }`); this.$router.push(`i/lists/${ list.id }`);
}); });
}, },
followRequests() {
this.close();
(this as any).os.new(MkFollowRequestsWindow);
},
settings() { settings() {
this.close(); this.close();
(this as any).os.new(MkSettingsWindow); (this as any).os.new(MkSettingsWindow);
@@ -225,6 +233,16 @@ root(isDark)
> span:first-child > span:first-child
padding-left 22px padding-left 22px
> span:nth-child(2)
> i
margin-left 4px
padding 2px 8px
font-size 90%
font-style normal
background $theme-color
color $theme-color-foreground
border-radius 8px
> [data-fa]:first-child > [data-fa]:first-child
margin-right 6px margin-right 6px
width 16px width 16px

View File

@@ -8,7 +8,7 @@
</time> </time>
</div> </div>
<div class="content"> <div class="content">
<mk-analog-clock/> <mk-analog-clock :dark="true"/>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div> <div class="mk-ui">
<x-header/> <x-header class="header"/>
<div class="content"> <div class="content">
<slot></slot> <slot></slot>
</div> </div>
@@ -35,3 +35,9 @@ export default Vue.extend({
}); });
</script> </script>
<style lang="stylus" scoped>
.mk-ui
> .header
@media (max-width 1000px)
display none
</style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<mk-window ref="window" is-modal width="450px" height="500px" @closed="$destroy"> <mk-window ref="window" is-modal width="450px" height="500px" @closed="$destroy">
<span slot="header">%fa:list% リスト</span> <span slot="header">%fa:list% %i18n:@title%</span>
<div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="$store.state.device.darkmode"> <div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="$store.state.device.darkmode">
<button class="ui" @click="add">%i18n:@create-list%</button> <button class="ui" @click="add">%i18n:@create-list%</button>

View File

@@ -2,7 +2,7 @@
<mk-ui> <mk-ui>
<main v-if="!fetching"> <main v-if="!fetching">
<template v-for="favorite in favorites"> <template v-for="favorite in favorites">
<mk-note-detail :note="favorite.note" :key="favorite.note.id"/> <mk-note-detail class="post" :note="favorite.note" :key="favorite.note.id"/>
</template> </template>
<a v-if="existMore" @click="more">%i18n:@more%</a> <a v-if="existMore" @click="more">%i18n:@more%</a>
</main> </main>
@@ -70,4 +70,7 @@ main
margin 0 auto margin 0 auto
padding 16px padding 16px
max-width 700px max-width 700px
> .post
margin-bottom 16px
</style> </style>

View File

@@ -80,6 +80,8 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
@import '~const.styl' @import '~const.styl'
@import url(https://fonts.googleapis.com/earlyaccess/notosansjp.css);
root(isDark) root(isDark)
display flex display flex
flex-direction column flex-direction column
@@ -103,6 +105,7 @@ root(isDark)
text-align center text-align center
&.about &.about
font-family 'Noto Sans JP'
color isDark ? #fff : #627574 color isDark ? #fff : #627574
> article > article
@@ -114,7 +117,7 @@ root(isDark)
> h1 > h1
margin 0 margin 0
font-variant small-caps font-weight 900
> p > p
margin 20px 0 margin 20px 0

View File

@@ -32,10 +32,14 @@ import MkNotifications from './views/pages/notifications.vue';
import MkWidgets from './views/pages/widgets.vue'; import MkWidgets from './views/pages/widgets.vue';
import MkMessaging from './views/pages/messaging.vue'; import MkMessaging from './views/pages/messaging.vue';
import MkMessagingRoom from './views/pages/messaging-room.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue';
import MkReceivedFollowRequests from './views/pages/received-follow-requests.vue';
import MkNote from './views/pages/note.vue'; import MkNote from './views/pages/note.vue';
import MkSearch from './views/pages/search.vue'; import MkSearch from './views/pages/search.vue';
import MkFollowers from './views/pages/followers.vue'; import MkFollowers from './views/pages/followers.vue';
import MkFollowing from './views/pages/following.vue'; import MkFollowing from './views/pages/following.vue';
import MkFavorites from './views/pages/favorites.vue';
import MkUserLists from './views/pages/user-lists.vue';
import MkUserList from './views/pages/user-list.vue';
import MkSettings from './views/pages/settings.vue'; import MkSettings from './views/pages/settings.vue';
import MkOthello from './views/pages/othello.vue'; import MkOthello from './views/pages/othello.vue';
@@ -72,6 +76,10 @@ init((launch) => {
{ path: '/signup', name: 'signup', component: MkSignup }, { path: '/signup', name: 'signup', component: MkSignup },
{ path: '/i/settings', name: 'settings', component: MkSettings }, { path: '/i/settings', name: 'settings', component: MkSettings },
{ path: '/i/notifications', name: 'notifications', component: MkNotifications }, { path: '/i/notifications', name: 'notifications', component: MkNotifications },
{ path: '/i/favorites', name: 'favorites', component: MkFavorites },
{ path: '/i/lists', name: 'user-lists', component: MkUserLists },
{ path: '/i/lists/:list', name: 'user-list', component: MkUserList },
{ path: '/i/received-follow-requests', name: 'received-follow-requests', component: MkReceivedFollowRequests },
{ path: '/i/widgets', name: 'widgets', component: MkWidgets }, { path: '/i/widgets', name: 'widgets', component: MkWidgets },
{ path: '/i/messaging', name: 'messaging', component: MkMessaging }, { path: '/i/messaging', name: 'messaging', component: MkMessaging },
{ path: '/i/messaging/:user', component: MkMessagingRoom }, { path: '/i/messaging/:user', component: MkMessagingRoom },

View File

@@ -1,13 +1,16 @@
<template> <template>
<button class="mk-follow-button" <button class="mk-follow-button"
:class="{ wait: wait, follow: !user.isFollowing, unfollow: user.isFollowing }" :class="{ wait: wait, active: u.isFollowing || u.hasPendingFollowRequestFromYou }"
@click="onClick" @click="onClick"
:disabled="wait" :disabled="wait"
> >
<template v-if="!wait && user.isFollowing">%fa:minus%</template> <template v-if="!wait">
<template v-if="!wait && !user.isFollowing">%fa:plus%</template> <template v-if="u.hasPendingFollowRequestFromYou">%fa:hourglass-half% %i18n:@request-pending%</template>
<template v-if="wait">%fa:spinner .pulse .fw%</template> <template v-else-if="u.isFollowing">%fa:minus% %i18n:@following%</template>
{{ user.isFollowing ? '%i18n:@unfollow%' : '%i18n:@follow%' }} <template v-else-if="!u.isFollowing && u.isLocked">%fa:plus% %i18n:@follow-request%</template>
<template v-else-if="!u.isFollowing && !u.isLocked">%fa:plus% %i18n:@follow%</template>
</template>
<template v-else>%fa:spinner .pulse .fw%</template>
</button> </button>
</template> </template>
@@ -22,6 +25,7 @@ export default Vue.extend({
}, },
data() { data() {
return { return {
u: this.user,
wait: false, wait: false,
connection: null, connection: null,
connectionId: null connectionId: null
@@ -42,39 +46,44 @@ export default Vue.extend({
methods: { methods: {
onFollow(user) { onFollow(user) {
if (user.id == this.user.id) { if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing; this.u.isFollowing = user.isFollowing;
} }
}, },
onUnfollow(user) { onUnfollow(user) {
if (user.id == this.user.id) { if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing; this.u.isFollowing = user.isFollowing;
} }
}, },
onClick() { async onClick() {
this.wait = true; this.wait = true;
if (this.user.isFollowing) {
(this as any).api('following/delete', { try {
userId: this.user.id if (this.u.isFollowing) {
}).then(() => { this.u = await (this as any).api('following/delete', {
this.user.isFollowing = false; userId: this.u.id
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false;
}); });
} else { } else {
(this as any).api('following/create', { if (this.u.isLocked && this.u.hasPendingFollowRequestFromYou) {
userId: this.user.id this.u = await (this as any).api('following/requests/cancel', {
}).then(() => { userId: this.u.id
this.user.isFollowing = true;
}).catch(err => {
console.error(err);
}).then(() => {
this.wait = false;
}); });
} else if (this.u.isLocked) {
this.u = await (this as any).api('following/create', {
userId: this.u.id
});
} else {
this.u = await (this as any).api('following/create', {
userId: this.user.id
});
}
}
} catch (e) {
console.error(e);
} finally {
this.wait = false;
} }
} }
} }
@@ -90,18 +99,15 @@ export default Vue.extend({
cursor pointer cursor pointer
padding 0 16px padding 0 16px
margin 0 margin 0
height inherit min-width 150px
font-size 16px line-height 36px
outline none font-size 14px
border solid 1px $theme-color font-weight bold
border-radius 4px
*
pointer-events none
&.follow
color $theme-color color $theme-color
background transparent background transparent
outline none
border solid 1px $theme-color
border-radius 36px
&:hover &:hover
background rgba($theme-color, 0.1) background rgba($theme-color, 0.1)
@@ -109,15 +115,23 @@ export default Vue.extend({
&:active &:active
background rgba($theme-color, 0.2) background rgba($theme-color, 0.2)
&.unfollow &.active
color $theme-color-foreground color $theme-color-foreground
background $theme-color background $theme-color
&:hover
background lighten($theme-color, 10%)
border-color lighten($theme-color, 10%)
&:active
background darken($theme-color, 10%)
border-color darken($theme-color, 10%)
&.wait &.wait
cursor wait !important cursor wait !important
opacity 0.7 opacity 0.7
> [data-fa] *
margin-right 4px pointer-events none
</style> </style>

View File

@@ -1,101 +0,0 @@
<template>
<div class="root sub">
<mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
<span class="username"><mk-acct :user="note.user"/></span>
<router-link class="time" :to="note | notePage">
<mk-time :time="note.createdAt"/>
</router-link>
</header>
<div class="body">
<mk-sub-note-content class="text" :note="note"/>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['note']
});
</script>
<style lang="stylus" scoped>
root(isDark)
padding 8px
font-size 0.9em
background isDark ? #21242d : #fdfdfd
@media (min-width 500px)
padding 12px
@media (min-width 600px)
padding 24px 32px
&:after
content ""
display block
clear both
> .avatar
display block
float left
margin 0 12px 0 0
width 48px
height 48px
border-radius 8px
> .main
float left
width calc(100% - 60px)
> header
display flex
align-items baseline
margin-bottom 4px
white-space nowrap
> .name
display block
margin 0 .5em 0 0
padding 0
overflow hidden
color isDark ? #fff : #607073
font-size 1em
font-weight 700
text-align left
text-decoration none
text-overflow ellipsis
&:hover
text-decoration underline
> .username
text-align left
margin 0 .5em 0 0
color isDark ? #606984 : #d1d8da
> .time
margin-left auto
color isDark ? #606984 : #b2b8bb
> .body
> .text
cursor default
margin 0
padding 0
font-size 1.1em
color isDark ? #959ba7 : #717171
.root.sub[data-darkmode]
root(true)
.root.sub:not([data-darkmode])
root(false)
</style>

View File

@@ -87,7 +87,7 @@ import parse from '../../../../../text/parse';
import MkNoteMenu from '../../../common/views/components/note-menu.vue'; import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note-detail.sub.vue'; import XSub from './note.sub.vue';
export default Vue.extend({ export default Vue.extend({
components: { components: {
@@ -172,7 +172,7 @@ export default Vue.extend({
}, },
methods: { methods: {
fetchContext() { fetchConversation() {
this.conversationFetching = true; this.conversationFetching = true;
// Fetch conversation // Fetch conversation
@@ -216,8 +216,6 @@ export default Vue.extend({
root(isDark) root(isDark)
overflow hidden overflow hidden
margin 0 auto
padding 0
width 100% width 100%
text-align left text-align left
background isDark ? #282C37 : #fff background isDark ? #282C37 : #fff

View File

@@ -9,9 +9,18 @@
<span class="is-bot" v-if="note.user.isBot">%i18n:@bot%</span> <span class="is-bot" v-if="note.user.isBot">%i18n:@bot%</span>
<span class="is-cat" v-if="note.user.isCat">%i18n:@cat%</span> <span class="is-cat" v-if="note.user.isCat">%i18n:@cat%</span>
<span class="username"><mk-acct :user="note.user"/></span> <span class="username"><mk-acct :user="note.user"/></span>
<router-link class="time" :to="note | notePage"> <div class="info">
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
<router-link class="created-at" :to="note | notePage">
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</router-link> </router-link>
<span class="visibility" v-if="note.visibility != 'public'">
<template v-if="note.visibility == 'home'">%fa:home%</template>
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
<template v-if="note.visibility == 'private'">%fa:lock%</template>
</span>
</div>
</header> </header>
<div class="body"> <div class="body">
<mk-sub-note-content class="text" :note="note"/> <mk-sub-note-content class="text" :note="note"/>
@@ -30,14 +39,16 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
root(isDark) root(isDark)
display flex
margin 0 margin 0
padding 0 padding 0
font-size 0.9em font-size 10px
&:after @media (min-width 350px)
content "" font-size 12px
display block
clear both @media (min-width 500px)
font-size 14px
&.smart &.smart
> .main > .main
@@ -47,24 +58,26 @@ root(isDark)
align-items center align-items center
> .avatar > .avatar
flex-shrink 0
display block display block
float left margin 0 10px 0 0
margin 0 12px 0 0 width 40px
width 48px height 40px
height 48px
border-radius 8px border-radius 8px
@media (max-width 500px) @media (min-width 350px)
margin 0 10px 0 0 margin 0 10px 0 0
width 44px width 44px
height 44px height 44px
> .main @media (min-width 500px)
float left margin 0 12px 0 0
width calc(100% - 60px) width 48px
height 48px
@media (max-width 500px) > .main
width calc(100% - 54px) flex 1
min-width 0
> header > header
display flex display flex
@@ -97,7 +110,7 @@ root(isDark)
align-self center align-self center
margin 0 0.5em 0 0 margin 0 0.5em 0 0
padding 1px 6px padding 1px 6px
font-size 10px font-size 0.8em
color isDark ? #758188 : #aaa color isDark ? #758188 : #aaa
border solid 1px isDark ? #57616f : #ddd border solid 1px isDark ? #57616f : #ddd
border-radius 3px border-radius 3px
@@ -112,10 +125,19 @@ root(isDark)
text-overflow ellipsis text-overflow ellipsis
color isDark ? #606984 : #d1d8da color isDark ? #606984 : #d1d8da
> .time > .info
margin-left auto margin-left auto
font-size 0.9em
> *
color isDark ? #606984 : #b2b8bb color isDark ? #606984 : #b2b8bb
> .mobile
margin-right 6px
> .visibility
margin-left 6px
> .body > .body
> .text > .text

View File

@@ -33,16 +33,33 @@
import Vue from 'vue'; import Vue from 'vue';
export default Vue.extend({ export default Vue.extend({
props: ['note'] props: {
note: {
type: Object,
required: true
},
// TODO
truncate: {
type: Boolean,
default: true
}
}
}); });
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
root(isDark) root(isDark)
display flex
padding 16px padding 16px
font-size 0.9em font-size 10px
background isDark ? #21242d : #fcfcfc background isDark ? #21242d : #fcfcfc
@media (min-width 350px)
font-size 12px
@media (min-width 500px)
font-size 14px
@media (min-width 600px) @media (min-width 600px)
padding 24px 32px padding 24px 32px
@@ -53,18 +70,18 @@ root(isDark)
> header > header
align-items center align-items center
&:after
content ""
display block
clear both
> .avatar > .avatar
flex-shrink 0
display block display block
float left margin 0 8px 0 0
margin 0 10px 0 0 width 38px
height 38px
border-radius 8px
@media (min-width 350px)
margin-right 10px
width 42px width 42px
height 42px height 42px
border-radius 8px
@media (min-width 500px) @media (min-width 500px)
margin-right 14px margin-right 14px
@@ -72,11 +89,8 @@ root(isDark)
height 50px height 50px
> .main > .main
float left flex 1
width calc(100% - 52px) min-width 0
@media (min-width 500px)
width calc(100% - 64px)
> header > header
display flex display flex
@@ -112,7 +126,7 @@ root(isDark)
align-self center align-self center
margin 0 0.5em 0 0 margin 0 0.5em 0 0
padding 1px 5px padding 1px 5px
font-size 10px font-size 0.8em
color isDark ? #758188 : #aaa color isDark ? #758188 : #aaa
border solid 1px isDark ? #57616f : #ddd border solid 1px isDark ? #57616f : #ddd
border-radius 3px border-radius 3px
@@ -140,11 +154,8 @@ root(isDark)
margin-left 6px margin-left 6px
> .body > .body
max-height 128px
overflow hidden
> .text > .text
cursor default
margin 0 margin 0
padding 0 padding 0
color isDark ? #959ba7 : #717171 color isDark ? #959ba7 : #717171

View File

@@ -269,8 +269,6 @@ root(isDark)
&.smart &.smart
> article > article
> .main > .main
width 100%
> header > header
align-items center align-items center
margin-bottom 4px margin-bottom 4px
@@ -328,27 +326,28 @@ root(isDark)
padding-top 8px padding-top 8px
> article > article
display flex
padding 16px 16px 9px padding 16px 16px 9px
@media (min-width 600px) @media (min-width 600px)
padding 32px 32px 22px padding 32px 32px 22px
&:after
content ""
display block
clear both
> .avatar > .avatar
flex-shrink 0
display block display block
float left
margin 0 10px 8px 0 margin 0 10px 8px 0
width 48px width 42px
height 48px height 42px
border-radius 6px border-radius 6px
//position -webkit-sticky //position -webkit-sticky
//position sticky //position sticky
//top 62px //top 62px
@media (min-width 350px)
width 48px
height 48px
border-radius 6px
@media (min-width 500px) @media (min-width 500px)
margin-right 16px margin-right 16px
width 58px width 58px
@@ -356,11 +355,8 @@ root(isDark)
border-radius 8px border-radius 8px
> .main > .main
float left flex 1
width calc(100% - 58px) min-width 0
@media (min-width 500px)
width calc(100% - 74px)
> header > header
display flex display flex
@@ -393,7 +389,7 @@ root(isDark)
align-self center align-self center
margin 0 0.5em 0 0 margin 0 0.5em 0 0
padding 1px 6px padding 1px 6px
font-size 12px font-size 0.8em
color isDark ? #758188 : #aaa color isDark ? #758188 : #aaa
border solid 1px isDark ? #57616f : #ddd border solid 1px isDark ? #57616f : #ddd
border-radius 3px border-radius 3px
@@ -422,6 +418,8 @@ root(isDark)
margin-left 6px margin-left 6px
> .body > .body
@media (min-width 700px)
font-size 1.1em
> .cw > .cw
cursor default cursor default
@@ -504,7 +502,7 @@ root(isDark)
padding 2px 8px 2px 16px padding 2px 8px 2px 16px
font-size 90% font-size 90%
color #8d969e color #8d969e
background #edf0f3 background isDark ? #313543 : #edf0f3
border-radius 4px border-radius 4px
&:before &:before
@@ -517,7 +515,7 @@ root(isDark)
width 8px width 8px
height 8px height 8px
margin auto 0 margin auto 0
background #fff background isDark ? #282c37 : #fff
border-radius 100% border-radius 100%
> .media > .media

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mk-notification-preview" :class="notification.type"> <div class="mk-notification-preview" :class="notification.type">
<template v-if="notification.type == 'reaction'"> <template v-if="notification.type == 'reaction'">
<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
<p><mk-reaction-icon :reaction="notification.reaction"/>{{ notification.user | userName }}</p> <p><mk-reaction-icon :reaction="notification.reaction"/>{{ notification.user | userName }}</p>
<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p> <p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p>
@@ -9,7 +9,7 @@
</template> </template>
<template v-if="notification.type == 'renote'"> <template v-if="notification.type == 'renote'">
<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
<p>%fa:retweet%{{ notification.note.user | userName }}</p> <p>%fa:retweet%{{ notification.note.user | userName }}</p>
<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%</p> <p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note.renote) }}%fa:quote-right%</p>
@@ -17,7 +17,7 @@
</template> </template>
<template v-if="notification.type == 'quote'"> <template v-if="notification.type == 'quote'">
<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
<p>%fa:quote-left%{{ notification.note.user | userName }}</p> <p>%fa:quote-left%{{ notification.note.user | userName }}</p>
<p class="note-preview">{{ getNoteSummary(notification.note) }}</p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
@@ -25,14 +25,21 @@
</template> </template>
<template v-if="notification.type == 'follow'"> <template v-if="notification.type == 'follow'">
<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
<p>%fa:user-plus%{{ notification.user | userName }}</p> <p>%fa:user-plus%{{ notification.user | userName }}</p>
</div> </div>
</template> </template>
<template v-if="notification.type == 'receiveFollowRequest'">
<mk-avatar class="avatar" :user="notification.user"/>
<div class="text">
<p>%fa:user-clock%{{ notification.user | userName }}</p>
</div>
</template>
<template v-if="notification.type == 'reply'"> <template v-if="notification.type == 'reply'">
<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
<p>%fa:reply%{{ notification.note.user | userName }}</p> <p>%fa:reply%{{ notification.note.user | userName }}</p>
<p class="note-preview">{{ getNoteSummary(notification.note) }}</p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
@@ -40,7 +47,7 @@
</template> </template>
<template v-if="notification.type == 'mention'"> <template v-if="notification.type == 'mention'">
<img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text"> <div class="text">
<p>%fa:at%{{ notification.note.user | userName }}</p> <p>%fa:at%{{ notification.note.user | userName }}</p>
<p class="note-preview">{{ getNoteSummary(notification.note) }}</p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p>
@@ -48,7 +55,7 @@
</template> </template>
<template v-if="notification.type == 'poll_vote'"> <template v-if="notification.type == 'poll_vote'">
<img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <mk-avatar class="avatar" :user="notification.user"/>
<div class="text"> <div class="text">
<p>%fa:chart-pie%{{ notification.user | userName }}</p> <p>%fa:chart-pie%{{ notification.user | userName }}</p>
<p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p> <p class="note-ref">%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%</p>
@@ -83,16 +90,14 @@ export default Vue.extend({
display block display block
clear both clear both
img > .avatar
display block display block
float left float left
min-width 36px width 36px
min-height 36px height 36px
max-width 36px
max-height 36px
border-radius 6px border-radius 6px
.text > .text
float right float right
width calc(100% - 36px) width calc(100% - 36px)
padding-left 8px padding-left 8px
@@ -120,6 +125,10 @@ export default Vue.extend({
.text p i .text p i
color #53c7ce color #53c7ce
&.receiveFollowRequest
.text p i
color #888
&.reply, &.mention &.reply, &.mention
.text p i .text p i
color #fff color #fff

View File

@@ -40,6 +40,17 @@
</div> </div>
</div> </div>
<div class="notification followRequest" v-if="notification.type == 'receiveFollowRequest'">
<mk-avatar class="avatar" :user="notification.user"/>
<div>
<header>
%fa:user-clock%
<router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link>
<mk-time :time="notification.createdAt"/>
</header>
</div>
</div>
<div class="notification poll_vote" v-if="notification.type == 'poll_vote'"> <div class="notification poll_vote" v-if="notification.type == 'poll_vote'">
<mk-avatar class="avatar" :user="notification.user"/> <mk-avatar class="avatar" :user="notification.user"/>
<div> <div>
@@ -55,15 +66,15 @@
</div> </div>
<template v-if="notification.type == 'quote'"> <template v-if="notification.type == 'quote'">
<mk-note :note="notification.note"/> <mk-note :note="notification.note" @update:note="onNoteUpdated"/>
</template> </template>
<template v-if="notification.type == 'reply'"> <template v-if="notification.type == 'reply'">
<mk-note :note="notification.note"/> <mk-note :note="notification.note" @update:note="onNoteUpdated"/>
</template> </template>
<template v-if="notification.type == 'mention'"> <template v-if="notification.type == 'mention'">
<mk-note :note="notification.note"/> <mk-note :note="notification.note" @update:note="onNoteUpdated"/>
</template> </template>
</div> </div>
</template> </template>
@@ -78,6 +89,17 @@ export default Vue.extend({
return { return {
getNoteSummary getNoteSummary
}; };
},
methods: {
onNoteUpdated(note) {
switch (this.notification.type) {
case 'quote':
case 'reply':
case 'mention':
Vue.set(this.notification, 'note', note);
break;
}
}
} }
}); });
</script> </script>
@@ -156,6 +178,10 @@ root(isDark)
> div > header i > div > header i
color #53c7ce color #53c7ce
&.receiveFollowRequest
> div > header i
color #888
.mk-notification[data-darkmode] .mk-notification[data-darkmode]
root(true) root(true)

View File

@@ -15,21 +15,22 @@
</router-link> </router-link>
<div class="links"> <div class="links">
<ul> <ul>
<li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@home%%fa:angle-right%</router-link></li> <li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@timeline%%fa:angle-right%</router-link></li>
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li> <li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li>
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessages">%fa:circle%</template>%fa:angle-right%</router-link></li> <li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>%fa:angle-right%</router-link></li>
<li><router-link to="/othello" :data-active="$route.name == 'othello'">%fa:gamepad%ゲーム<template v-if="hasGameInvitations">%fa:circle%</template>%fa:angle-right%</router-link></li> <li v-if="$store.getters.isSignedIn && $store.state.i.isLocked"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li>
<li><router-link to="/othello" :data-active="$route.name == 'othello'">%fa:gamepad%%i18n:@game%<template v-if="hasGameInvitation">%fa:circle%</template>%fa:angle-right%</router-link></li>
</ul> </ul>
<ul> <ul>
<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:quidditch%%i18n:@widgets%%fa:angle-right%</router-link></li> <li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:R calendar-alt%%i18n:@widgets%%fa:angle-right%</router-link></li>
<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'">%fa:star%%i18n:@favorites%%fa:angle-right%</router-link></li>
<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'">%fa:list%%i18n:@user-lists%%fa:angle-right%</router-link></li>
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li> <li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li>
</ul> </ul>
<ul> <ul>
<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li> <li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
</ul>
<ul>
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li> <li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>ダークモード</span></p></li> <li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
</ul> </ul>
</div> </div>
<a :href="aboutUrl"><p class="about">%i18n:@about%</p></a> <a :href="aboutUrl"><p class="about">%i18n:@about%</p></a>
@@ -158,7 +159,10 @@ root(isDark)
&:first-child &:first-child
margin-top 0 margin-top 0
li &:last-child
margin-bottom 0
> li
display block display block
font-size 1em font-size 1em
line-height 1em line-height 1em
@@ -181,6 +185,8 @@ root(isDark)
> [data-fa]:first-child > [data-fa]:first-child
margin-right 0.5em margin-right 0.5em
width 20px
text-align center
> [data-fa].circle > [data-fa].circle
margin-left 6px margin-left 6px
@@ -198,7 +204,7 @@ root(isDark)
opacity 0.5 opacity 0.5
.about .about
margin 0 margin 0 0 8px 0
padding 1em 0 padding 1em 0
text-align center text-align center
font-size 0.8em font-size 0.8em

View File

@@ -0,0 +1,94 @@
<template>
<mk-ui>
<span slot="header">%fa:star%%i18n:@title%</span>
<main>
<template v-for="favorite in favorites">
<mk-note-detail class="post" :note="favorite.note" :key="favorite.note.id"/>
</template>
<a v-if="existMore" @click="more">%i18n:@more%</a>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
export default Vue.extend({
data() {
return {
fetching: true,
favorites: [],
existMore: false,
moreFetching: false
};
},
created() {
this.fetch();
},
mounted() {
document.title = 'Misskey | %i18n:@notifications%';
},
methods: {
fetch() {
Progress.start();
this.fetching = true;
(this as any).api('i/favorites', {
limit: 11
}).then(favorites => {
if (favorites.length == 11) {
this.existMore = true;
favorites.pop();
}
this.favorites = favorites;
this.fetching = false;
Progress.done();
});
},
more() {
this.moreFetching = true;
(this as any).api('i/favorites', {
limit: 11,
maxId: this.favorites[this.favorites.length - 1].id
}).then(favorites => {
if (favorites.length == 11) {
this.existMore = true;
favorites.pop();
} else {
this.existMore = false;
}
this.favorites = this.favorites.concat(favorites);
this.moreFetching = false;
});
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
main
width 100%
max-width 680px
margin 0 auto
padding 8px
> .post
margin-bottom 8px
@media (min-width 500px)
padding 16px
> .post
margin-bottom 16px
@media (min-width 600px)
padding 32px
</style>

View File

@@ -0,0 +1,78 @@
<template>
<mk-ui>
<span slot="header">%fa:envelope R%%i18n:@title%</span>
<main>
<div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link>
<span>
<a @click="accept(req.follower)">%i18n:@accept%</a>|<a @click="reject(req.follower)">%i18n:@reject%</a>
</span>
</div>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
export default Vue.extend({
data() {
return {
fetching: true,
requests: []
};
},
mounted() {
document.title = 'Misskey | %i18n:@title%';
Progress.start();
(this as any).api('following/requests/list').then(requests => {
this.fetching = false;
this.requests = requests;
Progress.done();
});
},
methods: {
accept(user) {
(this as any).api('following/requests/accept', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
reject(user) {
(this as any).api('following/requests/reject', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
main
width 100%
max-width 680px
margin 0 auto
padding 8px
@media (min-width 500px)
padding 16px
@media (min-width 600px)
padding 32px
> div
display flex
padding 16px
border solid 1px isDark ? #1c2023 : #eee
border-radius 4px
> span
margin 0 0 0 auto
</style>

View File

@@ -0,0 +1,70 @@
<template>
<mk-ui>
<span slot="header" v-if="!fetching">%fa:list%{{ list.title }}</span>
<main v-if="!fetching">
<ul>
<li v-for="user in users" :key="user.id"><router-link :to="user | userPage">{{ user | userName }}</router-link></li>
</ul>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
export default Vue.extend({
data() {
return {
fetching: true,
list: null,
users: null
};
},
watch: {
$route: 'fetch'
},
created() {
this.fetch();
},
methods: {
fetch() {
Progress.start();
this.fetching = true;
(this as any).api('users/lists/show', {
listId: this.$route.params.list
}).then(list => {
this.list = list;
this.fetching = false;
Progress.done();
(this as any).api('users/show', {
userIds: this.list.userIds
}).then(users => {
this.users = users;
});
});
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
main
width 100%
max-width 680px
margin 0 auto
padding 8px
@media (min-width 500px)
padding 16px
@media (min-width 600px)
padding 32px
</style>

View File

@@ -0,0 +1,68 @@
<template>
<mk-ui>
<span slot="header">%fa:list%%i18n:@title%</span>
<template slot="func"><button @click="fn">%fa:plus%</button></template>
<main>
<ul>
<li v-for="list in lists" :key="list.id"><router-link :to="`/i/lists/${list.id}`">{{ list.title }}</router-link></li>
</ul>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
export default Vue.extend({
data() {
return {
fetching: true,
lists: []
};
},
mounted() {
document.title = 'Misskey | %i18n:@title%';
Progress.start();
(this as any).api('users/lists/list').then(lists => {
this.fetching = false;
this.lists = lists;
Progress.done();
});
},
methods: {
fn() {
(this as any).apis.input({
title: '%i18n:@enter-list-name%',
}).then(async title => {
const list = await (this as any).api('users/lists/create', {
title
});
this.$router.push('/i/lists/' + list.id);
});
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
main
width 100%
max-width 680px
margin 0 auto
padding 8px
@media (min-width 500px)
padding 16px
@media (min-width 600px)
padding 32px
</style>

View File

@@ -184,7 +184,6 @@ root(isDark)
> .mk-follow-button > .mk-follow-button
float right float right
height 40px
> .title > .title
margin 8px 0 margin 8px 0

View File

@@ -9,6 +9,7 @@
<header> <header>
<select v-model="widgetAdderSelected"> <select v-model="widgetAdderSelected">
<option value="profile">%i18n:common.widgets.profile%</option> <option value="profile">%i18n:common.widgets.profile%</option>
<option value="analog-clock">%i18n:common.widgets.analog-clock%</option>
<option value="calendar">%i18n:common.widgets.calendar%</option> <option value="calendar">%i18n:common.widgets.calendar%</option>
<option value="activity">%i18n:common.widgets.activity%</option> <option value="activity">%i18n:common.widgets.activity%</option>
<option value="rss">%i18n:common.widgets.rss%</option> <option value="rss">%i18n:common.widgets.rss%</option>

View File

@@ -0,0 +1,87 @@
import * as mongo from 'mongodb';
import * as deepcopy from 'deepcopy';
import db from '../db/mongodb';
import { pack as packUser } from './user';
const FollowRequest = db.get<IFollowRequest>('followRequests');
FollowRequest.createIndex(['followerId', 'followeeId'], { unique: true });
export default FollowRequest;
export type IFollowRequest = {
_id: mongo.ObjectID;
createdAt: Date;
followeeId: mongo.ObjectID;
followerId: mongo.ObjectID;
// 非正規化
_followee: {
host: string;
inbox?: string;
},
_follower: {
host: string;
inbox?: string;
}
};
/**
* FollowRequestを物理削除します
*/
export async function deleteFollowRequest(followRequest: string | mongo.ObjectID | IFollowRequest) {
let f: IFollowRequest;
// Populate
if (mongo.ObjectID.prototype.isPrototypeOf(followRequest)) {
f = await FollowRequest.findOne({
_id: followRequest
});
} else if (typeof followRequest === 'string') {
f = await FollowRequest.findOne({
_id: new mongo.ObjectID(followRequest)
});
} else {
f = followRequest as IFollowRequest;
}
if (f == null) return;
// このFollowingを削除
await FollowRequest.remove({
_id: f._id
});
}
/**
* Pack a request for API response
*/
export const pack = (
request: any,
me?: any
) => new Promise<any>(async (resolve, reject) => {
let _request: any;
// Populate the request if 'request' is ID
if (mongo.ObjectID.prototype.isPrototypeOf(request)) {
_request = await FollowRequest.findOne({
_id: request
});
} else if (typeof request === 'string') {
_request = await FollowRequest.findOne({
_id: new mongo.ObjectID(request)
});
} else {
_request = deepcopy(request);
}
// Rename _id to id
_request.id = _request._id;
delete _request._id;
// Populate follower
_request.follower = await packUser(_request.followerId, me);
// Populate followee
_request.followee = await packUser(_request.followeeId, me);
resolve(_request);
});

View File

@@ -111,6 +111,7 @@ export const pack = (notification: any) => new Promise<any>(async (resolve, reje
switch (_notification.type) { switch (_notification.type) {
case 'follow': case 'follow':
case 'receiveFollowRequest':
// nope // nope
break; break;
case 'mention': case 'mention':

View File

@@ -22,6 +22,7 @@ import FollowedLog, { deleteFollowedLog } from './followed-log';
import SwSubscription, { deleteSwSubscription } from './sw-subscription'; import SwSubscription, { deleteSwSubscription } from './sw-subscription';
import Notification, { deleteNotification } from './notification'; import Notification, { deleteNotification } from './notification';
import UserList, { deleteUserList } from './user-list'; import UserList, { deleteUserList } from './user-list';
import FollowRequest, { deleteFollowRequest } from './follow-request';
const User = db.get<IUser>('users'); const User = db.get<IUser>('users');
@@ -50,7 +51,22 @@ type IUserBase = {
data: any; data: any;
description: string; description: string;
pinnedNoteId: mongo.ObjectID; pinnedNoteId: mongo.ObjectID;
/**
* 凍結されているか否か
*/
isSuspended: boolean; isSuspended: boolean;
/**
* 鍵アカウントか否か
*/
isLocked: boolean;
/**
* このアカウントに届いているフォローリクエストの数
*/
pendingReceivedFollowRequestsCount: number;
host: string; host: string;
}; };
@@ -240,6 +256,16 @@ export async function deleteUser(user: string | mongo.ObjectID | IUser) {
await Following.find({ followeeId: u._id }) await Following.find({ followeeId: u._id })
).map(x => deleteFollowing(x))); ).map(x => deleteFollowing(x)));
// このユーザーのFollowRequestをすべて削除
await Promise.all((
await FollowRequest.find({ followerId: u._id })
).map(x => deleteFollowRequest(x)));
// このユーザーへのFollowRequestをすべて削除
await Promise.all((
await FollowRequest.find({ followeeId: u._id })
).map(x => deleteFollowRequest(x)));
// このユーザーのFollowingLogをすべて削除 // このユーザーのFollowingLogをすべて削除
await Promise.all(( await Promise.all((
await FollowingLog.find({ userId: u._id }) await FollowingLog.find({ userId: u._id })
@@ -395,7 +421,7 @@ export const pack = (
} }
if (meId && !meId.equals(_user.id)) { if (meId && !meId.equals(_user.id)) {
const [following1, following2, mute] = await Promise.all([ const [following1, following2, followReq1, followReq2, mute] = await Promise.all([
Following.findOne({ Following.findOne({
followerId: meId, followerId: meId,
followeeId: _user.id followeeId: _user.id
@@ -404,6 +430,14 @@ export const pack = (
followerId: _user.id, followerId: _user.id,
followeeId: meId followeeId: meId
}), }),
_user.isLocked ? FollowRequest.findOne({
followerId: meId,
followeeId: _user.id
}) : Promise.resolve(null),
FollowRequest.findOne({
followerId: _user.id,
followeeId: meId
}),
Mute.findOne({ Mute.findOne({
muterId: meId, muterId: meId,
muteeId: _user.id muteeId: _user.id
@@ -414,6 +448,9 @@ export const pack = (
_user.isFollowing = following1 !== null; _user.isFollowing = following1 !== null;
_user.isStalking = following1 && following1.stalk; _user.isStalking = following1 && following1.stalk;
_user.hasPendingFollowRequestFromYou = followReq1 !== null;
_user.hasPendingFollowRequestToYou = followReq2 !== null;
// Whether the user is followed // Whether the user is followed
_user.isFollowed = following2 !== null; _user.isFollowed = following2 !== null;

View File

@@ -0,0 +1,27 @@
import * as mongo from 'mongodb';
import User, { IRemoteUser } from '../../../../models/user';
import config from '../../../../config';
import accept from '../../../../services/following/requests/accept';
import { IFollow } from '../../type';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
if (!id.startsWith(config.url + '/')) {
return null;
}
const follower = await User.findOne({
_id: new mongo.ObjectID(id.split('/').pop())
});
if (follower === null) {
throw new Error('follower not found');
}
if (follower.host != null) {
throw new Error('フォローリクエストしたユーザーはローカルユーザーではありません');
}
await accept(actor, follower);
};

View File

@@ -0,0 +1,35 @@
import * as debug from 'debug';
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/user';
import acceptFollow from './follow';
import { IAccept } from '../../type';
const log = debug('misskey:activitypub');
export default async (actor: IRemoteUser, activity: IAccept): Promise<void> => {
const uri = activity.id || activity;
log(`Accept: ${uri}`);
const resolver = new Resolver();
let object;
try {
object = await resolver.resolve(activity.object);
} catch (e) {
log(`Resolution failed: ${e}`);
throw e;
}
switch (object.type) {
case 'Follow':
acceptFollow(actor, object);
break;
default:
console.warn(`Unknown accept type: ${object.type}`);
break;
}
};

View File

@@ -23,5 +23,5 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
throw new Error('フォローしようとしているユーザーはローカルユーザーではありません'); throw new Error('フォローしようとしているユーザーはローカルユーザーではありません');
} }
await follow(actor, followee, activity); await follow(actor, followee);
}; };

View File

@@ -6,6 +6,8 @@ import follow from './follow';
import undo from './undo'; import undo from './undo';
import like from './like'; import like from './like';
import announce from './announce'; import announce from './announce';
import accept from './accept';
import reject from './reject';
const self = async (actor: IRemoteUser, activity: Object): Promise<void> => { const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
switch (activity.type) { switch (activity.type) {
@@ -22,7 +24,11 @@ const self = async (actor: IRemoteUser, activity: Object): Promise<void> => {
break; break;
case 'Accept': case 'Accept':
// noop await accept(actor, activity);
break;
case 'Reject':
await reject(actor, activity);
break; break;
case 'Announce': case 'Announce':

View File

@@ -0,0 +1,27 @@
import * as mongo from 'mongodb';
import User, { IRemoteUser } from '../../../../models/user';
import config from '../../../../config';
import reject from '../../../../services/following/requests/reject';
import { IFollow } from '../../type';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
if (!id.startsWith(config.url + '/')) {
return null;
}
const follower = await User.findOne({
_id: new mongo.ObjectID(id.split('/').pop())
});
if (follower === null) {
throw new Error('follower not found');
}
if (follower.host != null) {
throw new Error('フォローリクエストしたユーザーはローカルユーザーではありません');
}
await reject(actor, follower);
};

View File

@@ -0,0 +1,35 @@
import * as debug from 'debug';
import Resolver from '../../resolver';
import { IRemoteUser } from '../../../../models/user';
import rejectFollow from './follow';
import { IReject } from '../../type';
const log = debug('misskey:activitypub');
export default async (actor: IRemoteUser, activity: IReject): Promise<void> => {
const uri = activity.id || activity;
log(`Reject: ${uri}`);
const resolver = new Resolver();
let object;
try {
object = await resolver.resolve(activity.object);
} catch (e) {
log(`Resolution failed: ${e}`);
throw e;
}
switch (object.type) {
case 'Follow':
rejectFollow(actor, object);
break;
default:
console.warn(`Unknown reject type: ${object.type}`);
break;
}
};

View File

@@ -2,7 +2,9 @@ import * as mongo from 'mongodb';
import User, { IRemoteUser } from '../../../../models/user'; import User, { IRemoteUser } from '../../../../models/user';
import config from '../../../../config'; import config from '../../../../config';
import unfollow from '../../../../services/following/delete'; import unfollow from '../../../../services/following/delete';
import cancelRequest from '../../../../services/following/requests/cancel';
import { IFollow } from '../../type'; import { IFollow } from '../../type';
import FollowRequest from '../../../../models/follow-request';
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => { export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
const id = typeof activity.object == 'string' ? activity.object : activity.object.id; const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
@@ -23,5 +25,14 @@ export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
throw new Error('フォロー解除しようとしているユーザーはローカルユーザーではありません'); throw new Error('フォロー解除しようとしているユーザーはローカルユーザーではありません');
} }
await unfollow(actor, followee, activity); const req = await FollowRequest.findOne({
followerId: actor._id,
followeeId: followee._id
});
if (req) {
await cancelRequest(actor, followee);
} else {
await unfollow(actor, followee);
}
}; };

View File

@@ -93,6 +93,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
notesCount, notesCount,
name: person.name, name: person.name,
driveCapacity: 1024 * 1024 * 8, // 8MiB driveCapacity: 1024 * 1024 * 8, // 8MiB
isLocked: person.manuallyApprovesFollowers,
username: person.preferredUsername, username: person.preferredUsername,
usernameLower: person.preferredUsername.toLowerCase(), usernameLower: person.preferredUsername.toLowerCase(),
host, host,

View File

@@ -1,8 +1,8 @@
import config from '../../../config'; import config from '../../../config';
import { IRemoteUser, ILocalUser } from '../../../models/user'; import { IUser, isLocalUser } from '../../../models/user';
export default (follower: ILocalUser, followee: IRemoteUser) => ({ export default (follower: IUser, followee: IUser) => ({
type: 'Follow', type: 'Follow',
actor: `${config.url}/users/${follower._id}`, actor: isLocalUser(follower) ? `${config.url}/users/${follower._id}` : follower.uri,
object: followee.uri object: isLocalUser(followee) ? `${config.url}/users/${followee._id}` : followee.uri
}); });

View File

@@ -1,8 +1,9 @@
import renderImage from './image'; import renderImage from './image';
import renderKey from './key'; import renderKey from './key';
import config from '../../../config'; import config from '../../../config';
import { ILocalUser } from '../../../models/user';
export default user => { export default (user: ILocalUser) => {
const id = `${config.url}/users/${user._id}`; const id = `${config.url}/users/${user._id}`;
return { return {
@@ -17,6 +18,7 @@ export default user => {
summary: user.description, summary: user.description,
icon: user.avatarId && renderImage({ _id: user.avatarId }), icon: user.avatarId && renderImage({ _id: user.avatarId }),
image: user.bannerId && renderImage({ _id: user.bannerId }), image: user.bannerId && renderImage({ _id: user.bannerId }),
manuallyApprovesFollowers: user.isLocked,
publicKey: renderKey(user) publicKey: renderKey(user)
}; };
}; };

View File

@@ -0,0 +1,4 @@
export default object => ({
type: 'Reject',
object
});

View File

@@ -45,6 +45,7 @@ export interface IPerson extends IObject {
type: 'Person'; type: 'Person';
name: string; name: string;
preferredUsername: string; preferredUsername: string;
manuallyApprovesFollowers: boolean;
inbox: string; inbox: string;
publicKey: any; publicKey: any;
followers: any; followers: any;
@@ -82,6 +83,10 @@ export interface IAccept extends IActivity {
type: 'Accept'; type: 'Accept';
} }
export interface IReject extends IActivity {
type: 'Reject';
}
export interface ILike extends IActivity { export interface ILike extends IActivity {
type: 'Like'; type: 'Like';
_misskey_reaction: string; _misskey_reaction: string;
@@ -99,5 +104,6 @@ export type Object =
IUndo | IUndo |
IFollow | IFollow |
IAccept | IAccept |
IReject |
ILike | ILike |
IAnnounce; IAnnounce;

View File

@@ -7,7 +7,7 @@ const httpSignature = require('http-signature');
import { createHttp } from '../queue'; import { createHttp } from '../queue';
import pack from '../remote/activitypub/renderer'; import pack from '../remote/activitypub/renderer';
import Note from '../models/note'; import Note from '../models/note';
import User, { isLocalUser } from '../models/user'; import User, { isLocalUser, ILocalUser } from '../models/user';
import renderNote from '../remote/activitypub/renderer/note'; import renderNote from '../remote/activitypub/renderer/note';
import renderKey from '../remote/activitypub/renderer/key'; import renderKey from '../remote/activitypub/renderer/key';
import renderPerson from '../remote/activitypub/renderer/person'; import renderPerson from '../remote/activitypub/renderer/person';
@@ -69,7 +69,10 @@ router.get('/notes/:note', async (ctx, next) => {
router.get('/users/:user/outbox', async ctx => { router.get('/users/:user/outbox', async ctx => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId }); const user = await User.findOne({
_id: userId,
host: null
});
if (user === null) { if (user === null) {
ctx.status = 404; ctx.status = 404;
@@ -91,7 +94,10 @@ router.get('/users/:user/outbox', async ctx => {
router.get('/users/:user/publickey', async ctx => { router.get('/users/:user/publickey', async ctx => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId }); const user = await User.findOne({
_id: userId,
host: null
});
if (user === null) { if (user === null) {
ctx.status = 404; ctx.status = 404;
@@ -109,14 +115,17 @@ router.get('/users/:user/publickey', async ctx => {
router.get('/users/:user', async ctx => { router.get('/users/:user', async ctx => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId }); const user = await User.findOne({
_id: userId,
host: null
});
if (user === null) { if (user === null) {
ctx.status = 404; ctx.status = 404;
return; return;
} }
ctx.body = pack(renderPerson(user)); ctx.body = pack(renderPerson(user as ILocalUser));
}); });
// follow form // follow form

View File

@@ -448,6 +448,26 @@ const endpoints: Endpoint[] = [
}, },
kind: 'following-write' kind: 'following-write'
}, },
{
name: 'following/requests/accept',
withCredential: true,
kind: 'following-write'
},
{
name: 'following/requests/reject',
withCredential: true,
kind: 'following-write'
},
{
name: 'following/requests/cancel',
withCredential: true,
kind: 'following-write'
},
{
name: 'following/requests/list',
withCredential: true,
kind: 'following-read'
},
{ {
name: 'following/stalk', name: 'following/stalk',
withCredential: true, withCredential: true,
@@ -555,7 +575,7 @@ const endpoints: Endpoint[] = [
withCredential: true, withCredential: true,
limit: { limit: {
duration: ms('1hour'), duration: ms('1hour'),
max: 100 max: 300
}, },
kind: 'reaction-write' kind: 'reaction-write'
}, },

View File

@@ -2,7 +2,7 @@
* Module dependencies * Module dependencies
*/ */
import $ from 'cafy'; import ID from '../../../../cafy-id'; import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user'; import User, { pack } from '../../../../models/user';
import Following from '../../../../models/following'; import Following from '../../../../models/following';
import create from '../../../../services/following/create'; import create from '../../../../services/following/create';
@@ -49,5 +49,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
create(follower, followee); create(follower, followee);
// Send response // Send response
res(); res(await pack(followee._id, user));
}); });

View File

@@ -2,7 +2,7 @@
* Module dependencies * Module dependencies
*/ */
import $ from 'cafy'; import ID from '../../../../cafy-id'; import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user'; import User, { pack } from '../../../../models/user';
import Following from '../../../../models/following'; import Following from '../../../../models/following';
import deleteFollowing from '../../../../services/following/delete'; import deleteFollowing from '../../../../services/following/delete';
@@ -49,5 +49,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
deleteFollowing(follower, followee); deleteFollowing(follower, followee);
// Send response // Send response
res(); res(await pack(followee._id, user));
}); });

View File

@@ -0,0 +1,26 @@
import $ from 'cafy'; import ID from '../../../../../cafy-id';
import acceptFollowRequest from '../../../../../services/following/requests/accept';
import User from '../../../../../models/user';
/**
* Accept a follow request
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
const [followerId, followerIdErr] = $.type(ID).get(params.userId);
if (followerIdErr) return rej('invalid userId param');
// Fetch follower
const follower = await User.findOne({
_id: followerId
});
if (follower === null) {
return rej('follower not found');
}
await acceptFollowRequest(user, follower);
// Send response
res();
});

View File

@@ -0,0 +1,26 @@
import $ from 'cafy'; import ID from '../../../../../cafy-id';
import cancelFollowRequest from '../../../../../services/following/requests/cancel';
import User, { pack } from '../../../../../models/user';
/**
* Cancel a follow request
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
const [followeeId, followeeIdErr] = $.type(ID).get(params.userId);
if (followeeIdErr) return rej('invalid userId param');
// Fetch followee
const followee = await User.findOne({
_id: followeeId
});
if (followee === null) {
return rej('followee not found');
}
await cancelFollowRequest(followee, user);
// Send response
res(await pack(followee._id, user));
});

View File

@@ -0,0 +1,14 @@
//import $ from 'cafy'; import ID from '../../../../../cafy-id';
import FollowRequest, { pack } from '../../../../../models/follow-request';
/**
* Get all pending received follow requests
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
const reqs = await FollowRequest.find({
followeeId: user._id
});
// Send response
res(await Promise.all(reqs.map(req => pack(req))));
});

View File

@@ -0,0 +1,26 @@
import $ from 'cafy'; import ID from '../../../../../cafy-id';
import rejectFollowRequest from '../../../../../services/following/requests/reject';
import User from '../../../../../models/user';
/**
* Reject a follow request
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
const [followerId, followerIdErr] = $.type(ID).get(params.userId);
if (followerIdErr) return rej('invalid userId param');
// Fetch follower
const follower = await User.findOne({
_id: followerId
});
if (follower === null) {
return rej('follower not found');
}
await rejectFollowRequest(user, follower);
// Send response
res();
});

View File

@@ -5,6 +5,7 @@ import $ from 'cafy'; import ID from '../../../../cafy-id';
import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../../../models/user'; import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../../../models/user';
import event from '../../../../publishers/stream'; import event from '../../../../publishers/stream';
import DriveFile from '../../../../models/drive-file'; import DriveFile from '../../../../models/drive-file';
import acceptAllFollowRequests from '../../../../services/following/requests/accept-all';
/** /**
* Update myself * Update myself
@@ -12,50 +13,57 @@ import DriveFile from '../../../../models/drive-file';
module.exports = async (params, user, app) => new Promise(async (res, rej) => { module.exports = async (params, user, app) => new Promise(async (res, rej) => {
const isSecure = user != null && app == null; const isSecure = user != null && app == null;
const updates = {} as any;
// Get 'name' parameter // Get 'name' parameter
const [name, nameErr] = $.str.optional().nullable().pipe(isValidName).get(params.name); const [name, nameErr] = $.str.optional().nullable().pipe(isValidName).get(params.name);
if (nameErr) return rej('invalid name param'); if (nameErr) return rej('invalid name param');
if (name) user.name = name; if (name) updates.name = name;
// Get 'description' parameter // Get 'description' parameter
const [description, descriptionErr] = $.str.optional().nullable().pipe(isValidDescription).get(params.description); const [description, descriptionErr] = $.str.optional().nullable().pipe(isValidDescription).get(params.description);
if (descriptionErr) return rej('invalid description param'); if (descriptionErr) return rej('invalid description param');
if (description !== undefined) user.description = description; if (description !== undefined) updates.description = description;
// Get 'location' parameter // Get 'location' parameter
const [location, locationErr] = $.str.optional().nullable().pipe(isValidLocation).get(params.location); const [location, locationErr] = $.str.optional().nullable().pipe(isValidLocation).get(params.location);
if (locationErr) return rej('invalid location param'); if (locationErr) return rej('invalid location param');
if (location !== undefined) user.profile.location = location; if (location !== undefined) updates['profile.location'] = location;
// Get 'birthday' parameter // Get 'birthday' parameter
const [birthday, birthdayErr] = $.str.optional().nullable().pipe(isValidBirthday).get(params.birthday); const [birthday, birthdayErr] = $.str.optional().nullable().pipe(isValidBirthday).get(params.birthday);
if (birthdayErr) return rej('invalid birthday param'); if (birthdayErr) return rej('invalid birthday param');
if (birthday !== undefined) user.profile.birthday = birthday; if (birthday !== undefined) updates['profile.birthday'] = birthday;
// Get 'avatarId' parameter // Get 'avatarId' parameter
const [avatarId, avatarIdErr] = $.type(ID).optional().get(params.avatarId); const [avatarId, avatarIdErr] = $.type(ID).optional().nullable().get(params.avatarId);
if (avatarIdErr) return rej('invalid avatarId param'); if (avatarIdErr) return rej('invalid avatarId param');
if (avatarId) user.avatarId = avatarId; if (avatarId !== undefined) updates.avatarId = avatarId;
// Get 'bannerId' parameter // Get 'bannerId' parameter
const [bannerId, bannerIdErr] = $.type(ID).optional().get(params.bannerId); const [bannerId, bannerIdErr] = $.type(ID).optional().nullable().get(params.bannerId);
if (bannerIdErr) return rej('invalid bannerId param'); if (bannerIdErr) return rej('invalid bannerId param');
if (bannerId) user.bannerId = bannerId; if (bannerId !== undefined) updates.bannerId = bannerId;
// Get 'isLocked' parameter
const [isLocked, isLockedErr] = $.bool.optional().get(params.isLocked);
if (isLockedErr) return rej('invalid isLocked param');
if (isLocked != null) updates.isLocked = isLocked;
// Get 'isBot' parameter // Get 'isBot' parameter
const [isBot, isBotErr] = $.bool.optional().get(params.isBot); const [isBot, isBotErr] = $.bool.optional().get(params.isBot);
if (isBotErr) return rej('invalid isBot param'); if (isBotErr) return rej('invalid isBot param');
if (isBot != null) user.isBot = isBot; if (isBot != null) updates.isBot = isBot;
// Get 'isCat' parameter // Get 'isCat' parameter
const [isCat, isCatErr] = $.bool.optional().get(params.isCat); const [isCat, isCatErr] = $.bool.optional().get(params.isCat);
if (isCatErr) return rej('invalid isCat param'); if (isCatErr) return rej('invalid isCat param');
if (isCat != null) user.isCat = isCat; if (isCat != null) updates.isCat = isCat;
// Get 'autoWatch' parameter // Get 'autoWatch' parameter
const [autoWatch, autoWatchErr] = $.bool.optional().get(params.autoWatch); const [autoWatch, autoWatchErr] = $.bool.optional().get(params.autoWatch);
if (autoWatchErr) return rej('invalid autoWatch param'); if (autoWatchErr) return rej('invalid autoWatch param');
if (autoWatch != null) user.settings.autoWatch = autoWatch; if (autoWatch != null) updates['settings.autoWatch'] = autoWatch;
if (avatarId) { if (avatarId) {
const avatar = await DriveFile.findOne({ const avatar = await DriveFile.findOne({
@@ -63,7 +71,7 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
}); });
if (avatar != null && avatar.metadata.properties.avgColor) { if (avatar != null && avatar.metadata.properties.avgColor) {
user.avatarColor = avatar.metadata.properties.avgColor; updates.avatarColor = avatar.metadata.properties.avgColor;
} }
} }
@@ -73,27 +81,16 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
}); });
if (banner != null && banner.metadata.properties.avgColor) { if (banner != null && banner.metadata.properties.avgColor) {
user.bannerColor = banner.metadata.properties.avgColor; updates.bannerColor = banner.metadata.properties.avgColor;
} }
} }
await User.update(user._id, { await User.update(user._id, {
$set: { $set: updates
name: user.name,
description: user.description,
avatarId: user.avatarId,
avatarColor: user.avatarColor,
bannerId: user.bannerId,
bannerColor: user.bannerColor,
profile: user.profile,
isBot: user.isBot,
isCat: user.isCat,
settings: user.settings
}
}); });
// Serialize // Serialize
const iObj = await pack(user, user, { const iObj = await pack(user._id, user, {
detail: true, detail: true,
includeSecrets: isSecure includeSecrets: isSecure
}); });
@@ -101,6 +98,11 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
// Send response // Send response
res(iObj); res(iObj);
// Publish i updated event // Publish meUpdated event
event(user._id, 'i_updated', iObj); event(user._id, 'meUpdated', iObj);
// 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認
if (user.isLocked && isLocked === false) {
acceptAllFollowRequests(user);
}
}); });

View File

@@ -26,7 +26,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
return rej('note not found'); return rej('note not found');
} }
const ids = note._replyIds.slice(offset, offset + limit); const ids = (note._replyIds || []).slice(offset, offset + limit);
// Serialize // Serialize
res(await Promise.all(ids.map(id => pack(id, user)))); res(await Promise.all(ids.map(id => pack(id, user))));

View File

@@ -36,6 +36,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
_id: { _id: {
$nin: followingIds.concat(mutedUserIds) $nin: followingIds.concat(mutedUserIds)
}, },
isLocked: false,
$or: [{ $or: [{
lastUsedAt: { lastUsedAt: {
$gte: new Date(Date.now() - ms('7days')) $gte: new Date(Date.now() - ms('7days'))

View File

@@ -49,7 +49,7 @@ router.get('/disconnect/twitter', async ctx => {
ctx.body = `Twitterの連携を解除しました :v:`; ctx.body = `Twitterの連携を解除しました :v:`;
// Publish i updated event // Publish i updated event
event(user._id, 'i_updated', await pack(user, user, { event(user._id, 'meUpdated', await pack(user, user, {
detail: true, detail: true,
includeSecrets: true includeSecrets: true
})); }));
@@ -174,7 +174,7 @@ if (config.twitter == null) {
ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`; ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`;
// Publish i updated event // Publish i updated event
event(user._id, 'i_updated', await pack(user, user, { event(user._id, 'meUpdated', await pack(user, user, {
detail: true, detail: true,
includeSecrets: true includeSecrets: true
})); }));

View File

@@ -8,13 +8,16 @@ import pack from '../../remote/activitypub/renderer';
import renderFollow from '../../remote/activitypub/renderer/follow'; import renderFollow from '../../remote/activitypub/renderer/follow';
import renderAccept from '../../remote/activitypub/renderer/accept'; import renderAccept from '../../remote/activitypub/renderer/accept';
import { deliver } from '../../queue'; import { deliver } from '../../queue';
import createFollowRequest from './requests/create';
export default async function(follower: IUser, followee: IUser, activity?) { export default async function(follower: IUser, followee: IUser) {
if (followee.isLocked) {
await createFollowRequest(follower, followee);
} else {
const following = await Following.insert({ const following = await Following.insert({
createdAt: new Date(), createdAt: new Date(),
followerId: follower._id, followerId: follower._id,
followeeId: followee._id, followeeId: followee._id,
stalk: true,
// 非正規化 // 非正規化
_follower: { _follower: {
@@ -73,7 +76,8 @@ export default async function(follower: IUser, followee: IUser, activity?) {
} }
if (isRemoteUser(follower) && isLocalUser(followee)) { if (isRemoteUser(follower) && isLocalUser(followee)) {
const content = pack(renderAccept(activity)); const content = pack(renderAccept(renderFollow(follower, followee)));
deliver(followee, content, follower.inbox); deliver(followee, content, follower.inbox);
} }
}
} }

View File

@@ -8,7 +8,7 @@ import renderFollow from '../../remote/activitypub/renderer/follow';
import renderUndo from '../../remote/activitypub/renderer/undo'; import renderUndo from '../../remote/activitypub/renderer/undo';
import { deliver } from '../../queue'; import { deliver } from '../../queue';
export default async function(follower: IUser, followee: IUser, activity?) { export default async function(follower: IUser, followee: IUser) {
const following = await Following.findOne({ const following = await Following.findOne({
followerId: follower._id, followerId: follower._id,
followeeId: followee._id followeeId: followee._id

View File

@@ -0,0 +1,24 @@
import User, { IUser } from "../../../models/user";
import FollowRequest from "../../../models/follow-request";
import accept from './accept';
/**
* 指定したユーザー宛てのフォローリクエストをすべて承認
* @param user ユーザー
*/
export default async function(user: IUser) {
const requests = await FollowRequest.find({
followeeId: user._id
});
requests.forEach(async request => {
const follower = await User.findOne({ _id: request.followerId });
accept(user, follower);
});
User.update({ _id: user._id }, {
$set: {
pendingReceivedFollowRequestsCount: 0
}
});
}

View File

@@ -0,0 +1,70 @@
import User, { IUser, isRemoteUser, ILocalUser, pack as packUser } from "../../../models/user";
import FollowRequest from "../../../models/follow-request";
import pack from '../../../remote/activitypub/renderer';
import renderFollow from '../../../remote/activitypub/renderer/follow';
import renderAccept from '../../../remote/activitypub/renderer/accept';
import { deliver } from '../../../queue';
import Following from "../../../models/following";
import FollowingLog from "../../../models/following-log";
import FollowedLog from "../../../models/followed-log";
import event from '../../../publishers/stream';
export default async function(followee: IUser, follower: IUser) {
const following = await Following.insert({
createdAt: new Date(),
followerId: follower._id,
followeeId: followee._id,
// 非正規化
_follower: {
host: follower.host,
inbox: isRemoteUser(follower) ? follower.inbox : undefined
},
_followee: {
host: followee.host,
inbox: isRemoteUser(followee) ? followee.inbox : undefined
}
});
if (isRemoteUser(follower)) {
const content = pack(renderAccept(renderFollow(follower, followee)));
deliver(followee as ILocalUser, content, follower.inbox);
}
await FollowRequest.remove({
followeeId: followee._id,
followerId: follower._id
});
//#region Increment following count
await User.update({ _id: follower._id }, {
$inc: {
followingCount: 1
}
});
FollowingLog.insert({
createdAt: following.createdAt,
userId: follower._id,
count: follower.followingCount + 1
});
//#endregion
//#region Increment followers count
await User.update({ _id: followee._id }, {
$inc: {
followersCount: 1
}
});
FollowedLog.insert({
createdAt: following.createdAt,
userId: followee._id,
count: followee.followersCount + 1
});
//#endregion
packUser(followee, followee, {
detail: true
}).then(packed => event(followee._id, 'meUpdated', packed));
}

View File

@@ -0,0 +1,29 @@
import User, { IUser, isRemoteUser, ILocalUser, pack as packUser } from "../../../models/user";
import FollowRequest from "../../../models/follow-request";
import pack from '../../../remote/activitypub/renderer';
import renderFollow from '../../../remote/activitypub/renderer/follow';
import renderUndo from '../../../remote/activitypub/renderer/undo';
import { deliver } from '../../../queue';
import event from '../../../publishers/stream';
export default async function(followee: IUser, follower: IUser) {
if (isRemoteUser(followee)) {
const content = pack(renderUndo(renderFollow(follower, followee)));
deliver(follower as ILocalUser, content, followee.inbox);
}
await FollowRequest.remove({
followeeId: followee._id,
followerId: follower._id
});
await User.update({ _id: followee._id }, {
$inc: {
pendingReceivedFollowRequestsCount: -1
}
});
packUser(followee, followee, {
detail: true
}).then(packed => event(followee._id, 'meUpdated', packed));
}

View File

@@ -0,0 +1,50 @@
import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../../models/user';
import event from '../../../publishers/stream';
import notify from '../../../publishers/notify';
import pack from '../../../remote/activitypub/renderer';
import renderFollow from '../../../remote/activitypub/renderer/follow';
import { deliver } from '../../../queue';
import FollowRequest from '../../../models/follow-request';
export default async function(follower: IUser, followee: IUser) {
if (!followee.isLocked) throw '対象のアカウントは鍵アカウントではありません';
await FollowRequest.insert({
createdAt: new Date(),
followerId: follower._id,
followeeId: followee._id,
// 非正規化
_follower: {
host: follower.host,
inbox: isRemoteUser(follower) ? follower.inbox : undefined
},
_followee: {
host: followee.host,
inbox: isRemoteUser(followee) ? followee.inbox : undefined
}
});
await User.update({ _id: followee._id }, {
$inc: {
pendingReceivedFollowRequestsCount: 1
}
});
// Publish receiveRequest event
if (isLocalUser(followee)) {
packUser(follower, followee).then(packed => event(followee._id, 'receiveFollowRequest', packed));
packUser(followee, followee, {
detail: true
}).then(packed => event(followee._id, 'meUpdated', packed));
// 通知を作成
notify(followee._id, follower._id, 'receiveFollowRequest');
}
if (isLocalUser(follower) && isRemoteUser(followee)) {
const content = pack(renderFollow(follower, followee));
deliver(follower, content, followee.inbox);
}
}

View File

@@ -0,0 +1,24 @@
import User, { IUser, isRemoteUser, ILocalUser } from "../../../models/user";
import FollowRequest from "../../../models/follow-request";
import pack from '../../../remote/activitypub/renderer';
import renderFollow from '../../../remote/activitypub/renderer/follow';
import renderReject from '../../../remote/activitypub/renderer/reject';
import { deliver } from '../../../queue';
export default async function(followee: IUser, follower: IUser) {
if (isRemoteUser(follower)) {
const content = pack(renderReject(renderFollow(follower, followee)));
deliver(followee as ILocalUser, content, follower.inbox);
}
await FollowRequest.remove({
followeeId: followee._id,
followerId: follower._id
});
User.update({ _id: followee._id }, {
$inc: {
pendingReceivedFollowRequestsCount: -1
}
});
}