Compare commits
255 Commits
Author | SHA1 | Date | |
---|---|---|---|
047bcc78ad | |||
9df68618f2 | |||
732db087ab | |||
0e95b33b6a | |||
816ae7eb7e | |||
5a5ff194fa | |||
a60edf9cff | |||
1c2dbb914e | |||
9c170c426b | |||
c6239c8ad9 | |||
159b361bac | |||
160f64c18e | |||
e5916b3789 | |||
70982b33c5 | |||
b4d614ad45 | |||
6d2ef41b37 | |||
e102237aab | |||
665af87031 | |||
6f4e439697 | |||
742dcf35c9 | |||
9cd70c568c | |||
facabf274f | |||
e3ab51022f | |||
d278367cf9 | |||
a70ced8e90 | |||
567cedc7cc | |||
9b3af6efcd | |||
d9edc1eb1d | |||
65e46b5cec | |||
e00b5f11cb | |||
6b53d5f269 | |||
59c80ab140 | |||
da323aad36 | |||
7c1611c939 | |||
ab861beabe | |||
d260e93161 | |||
65a1855606 | |||
c0e08e44a4 | |||
5c1cebcef4 | |||
af25d3a85e | |||
8cb7183107 | |||
1bf228d73e | |||
d952b996e6 | |||
1e407c4059 | |||
b56d1fa60e | |||
6340f95bfc | |||
3c08dacf6c | |||
2908124ad8 | |||
3d62faaaf2 | |||
b1efa9700d | |||
1d08af5747 | |||
2f82d0db87 | |||
d88159907d | |||
9ed9fbef65 | |||
86c2e5bb91 | |||
d9b548de1a | |||
2271c6cbd8 | |||
c4d4293c46 | |||
39bdfb6e0d | |||
1003fd393e | |||
2ede3c0864 | |||
674764a035 | |||
a780e7b936 | |||
03d0ce1f89 | |||
4182a0cf4c | |||
305915611e | |||
b0cd59bed9 | |||
599dcbaa48 | |||
2806dc98bd | |||
bdc52dc114 | |||
3f6b9e554c | |||
f47ad7bf31 | |||
f992f72d31 | |||
a26f1db2cb | |||
361ab00c61 | |||
f5cbcf3452 | |||
599386190a | |||
ec541d3cd0 | |||
3199819ded | |||
ccf04d63ec | |||
b9f5fca333 | |||
b6a330928d | |||
1c65cb3e36 | |||
dbb8c99efb | |||
0adcb646fe | |||
a1ef70c0bf | |||
75cd580c3a | |||
e05acb8d18 | |||
10af684804 | |||
3e897727ca | |||
d0570d7fe3 | |||
0b98a2364b | |||
1305006391 | |||
106d990bd2 | |||
b29eb29556 | |||
aeac1854ed | |||
dbc57dd0d3 | |||
328a87609e | |||
5d848f3900 | |||
cf4ed45fe4 | |||
07293094d5 | |||
0917696c86 | |||
030a027366 | |||
372c488585 | |||
738b8ff1ee | |||
1561fc5994 | |||
c84f18545e | |||
48e4dc75f4 | |||
63a8d556e5 | |||
e5591618ee | |||
4794748c73 | |||
02e7e3b971 | |||
d2aca3c28b | |||
11b84a04b3 | |||
f243ce66e7 | |||
baf9b65801 | |||
55419d2524 | |||
401d0b1298 | |||
fce7dc0f4e | |||
35489ef5b7 | |||
546d494587 | |||
e8afa2c940 | |||
c1ef1bf605 | |||
4ab0dbe7e3 | |||
44f86a94f4 | |||
a0278154a3 | |||
8b7e6b200e | |||
d6f6c26725 | |||
cf66343b31 | |||
d53689332f | |||
4105237027 | |||
436962e4b8 | |||
a85efa1392 | |||
f0115a5e21 | |||
03ee5eba3b | |||
295ea79231 | |||
a5486176c1 | |||
de58325fd0 | |||
1e7932d9c7 | |||
8ba76df409 | |||
a8f9d20229 | |||
5e6d1b9ae8 | |||
c5afbaef35 | |||
3b5a36a09f | |||
fcb20d05d7 | |||
9e6990c44b | |||
8f3fd9b0dc | |||
5b1b4a02d8 | |||
dba83aa50d | |||
bade054a6a | |||
34d3485dc9 | |||
a84d066daa | |||
3360cf27cd | |||
c1a13af611 | |||
47274a658b | |||
b194334031 | |||
4136c4a807 | |||
f1c212fe75 | |||
d08cbff4b7 | |||
0b774475fa | |||
c4f6195df3 | |||
192cdbe322 | |||
abef6bafe3 | |||
da237a5e2d | |||
c0ac15cad7 | |||
90ce09be2e | |||
fd39afb374 | |||
80e56fddd9 | |||
4daf9e1180 | |||
f72abc0e47 | |||
9c177f3df2 | |||
a279b32c93 | |||
51465ba026 | |||
6a7bdcc533 | |||
fddb3a5f10 | |||
643c7abc12 | |||
5715afd44c | |||
d65c1c420e | |||
35598c8064 | |||
a5e716eb5d | |||
e8073b7484 | |||
d6a5fc20bb | |||
e763d43085 | |||
a6904d5249 | |||
7bcb91d3ca | |||
fb0c1efa41 | |||
03d243d444 | |||
b91585d1fe | |||
d1fa318cda | |||
42decae424 | |||
78bc7c20ed | |||
e6616bdf57 | |||
cefe1f34be | |||
d469e2152c | |||
35c2d47518 | |||
c00634a2cf | |||
d1835e262d | |||
d0f304f0ce | |||
154abe06a7 | |||
ac41cd378c | |||
d59afda2c9 | |||
4d213833e2 | |||
e9214d4330 | |||
6b41bb95b2 | |||
36de13d543 | |||
3893def9f4 | |||
b91b0d17c3 | |||
ab7d4fa2a2 | |||
f30c8b8a47 | |||
fdaebc6315 | |||
f1a05c214e | |||
9ad32ffee9 | |||
70f83ab019 | |||
07e64631f2 | |||
498416e2e3 | |||
87c4f908fe | |||
27e6eaacde | |||
ada47920ca | |||
f2606d62ff | |||
35032152b3 | |||
90b545fd69 | |||
4f7776d1f9 | |||
03bd0c4c9e | |||
5734221c8f | |||
d17280b341 | |||
f523d3f3bc | |||
d23bc1e02a | |||
86fcd9208e | |||
f2b97a889c | |||
97f91102fe | |||
07b04578c8 | |||
31f3c1996b | |||
f4116e7300 | |||
5e5239c16e | |||
3adfcd1d13 | |||
3eb43a5413 | |||
80f41e2ac1 | |||
9e0b0b4210 | |||
f3380d3184 | |||
54bc91ea2b | |||
7bb25917f8 | |||
c5ff6df7e6 | |||
e2b2982f95 | |||
a6e307010f | |||
c636e35467 | |||
3d26bd0532 | |||
16130e46dd | |||
9f703085ba | |||
0af09f13cf | |||
cd8619113a | |||
4bf6d9f80b | |||
a559b2c20c | |||
72411abfcd | |||
491c3f1dc0 | |||
d2ffc4df6c |
82
CHANGELOG.md
82
CHANGELOG.md
@ -5,6 +5,88 @@ ChangeLog
|
|||||||
|
|
||||||
This document describes breaking changes only.
|
This document describes breaking changes only.
|
||||||
|
|
||||||
|
10.0.0
|
||||||
|
------
|
||||||
|
|
||||||
|
ストリーミングAPIに破壊的変更があります。運営者がすべきことはありません。
|
||||||
|
|
||||||
|
変更は以下の通りです
|
||||||
|
|
||||||
|
* ストリーミングでやり取りする際の snake_case が全て camelCase に
|
||||||
|
* リバーシのストリームエンドポイント名が reversi → gamesReversi、reversiGame → gamesReversiGame に
|
||||||
|
* ストリーミングの個々のエンドポイントが廃止され、一旦元となるストリームに接続してから、個々のチャンネル(今までのエンドポイント)に接続します。詳細は後述します。
|
||||||
|
* ストリームから流れてくる、キャプチャした投稿の更新イベントに投稿自体のデータは含まれず、代わりにアクションが設定されるようになります。詳細は後述します。
|
||||||
|
* ストリームに接続する際に追加で指定していたパラメータ(トークン除く)が、URLにクエリとして含むのではなくチャンネル接続時にパラメータ指定するように
|
||||||
|
|
||||||
|
### 個々のエンドポイントが廃止されることによる新しいストリーミングAPIの利用方法
|
||||||
|
具体的には、まず https://example.misskey/streaming にwebsocket接続します。
|
||||||
|
次に、例えば「messaging」ストリーム(チャンネルと呼びます)に接続したいときは、ストリームに次のようなデータを送信します:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
type: 'connect',
|
||||||
|
body: {
|
||||||
|
channel: 'messaging',
|
||||||
|
id: 'foobar',
|
||||||
|
params: {
|
||||||
|
otherparty: 'xxxxxxxxxxxx'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
ここで、`id`にはそのチャンネルとやり取りするための任意のIDを設定します。
|
||||||
|
IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。
|
||||||
|
`params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
|
||||||
|
|
||||||
|
チャンネルにメッセージを送信するには、次のようなデータを送信します:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
type: 'channel',
|
||||||
|
body: {
|
||||||
|
id: 'foobar',
|
||||||
|
type: 'something',
|
||||||
|
body: {
|
||||||
|
some: 'thing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
ここで、`id`にはチャンネルに接続するときに指定したIDを設定します。
|
||||||
|
|
||||||
|
逆に、チャンネルからメッセージが流れてくると、次のようなデータが受信されます:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
type: 'channel',
|
||||||
|
body: {
|
||||||
|
id: 'foobar',
|
||||||
|
type: 'something',
|
||||||
|
body: {
|
||||||
|
some: 'thing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
ここで、`id`にはチャンネルに接続するときに指定したIDが設定されています。
|
||||||
|
|
||||||
|
### 投稿のキャプチャに関する変更
|
||||||
|
投稿の更新イベントに投稿情報は含まれなくなりました。代わりに、その投稿が「リアクションされた」「アンケートに投票された」「削除された」といったアクション情報が設定されます。
|
||||||
|
|
||||||
|
具体的には次のようなデータが受信されます:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
type: 'noteUpdated',
|
||||||
|
body: {
|
||||||
|
id: 'xxxxxxxxxxx',
|
||||||
|
type: 'reacted',
|
||||||
|
body: {
|
||||||
|
reaction: 'hmm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* reacted ... 投稿にリアクションされた。`reaction`プロパティにリアクションコードが含まれます。
|
||||||
|
* pollVoted ... アンケートに投票された。`choice`プロパティに選択肢ID、`userId`に投票者IDが含まれます。
|
||||||
|
|
||||||
9.0.0
|
9.0.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Diese Anmerkung favorisieren"
|
favorite: "Diese Anmerkung favorisieren"
|
||||||
pin: "An die Profilseite pinnen"
|
pin: "An die Profilseite pinnen"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "Löschen"
|
delete: "Löschen"
|
||||||
delete-confirm: "Diesen Post löschen?"
|
delete-confirm: "Diesen Post löschen?"
|
||||||
remote: "Auf Quelle anzeigen"
|
remote: "Auf Quelle anzeigen"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "Folge ich"
|
following: "Folge ich"
|
||||||
follow: "Folgen"
|
follow: "Folgen"
|
||||||
request-pending: "Ausstehend"
|
request-pending: "Ausstehend"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Follower-Anfragen"
|
follow-request: "Follower-Anfragen"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Zwei-Faktor-Authentifizierung"
|
2fa: "Zwei-Faktor-Authentifizierung"
|
||||||
other: "Anderes"
|
other: "Anderes"
|
||||||
license: "Lizenz"
|
license: "Lizenz"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "Verhalten"
|
behaviour: "Verhalten"
|
||||||
fetch-on-scroll: "Aktualisieren beim scrollen"
|
fetch-on-scroll: "Aktualisieren beim scrollen"
|
||||||
fetch-on-scroll-desc: "Wenn du runterscrollst empfängt die Seite automatisch zusätzliche Inhalte."
|
fetch-on-scroll-desc: "Wenn du runterscrollst empfängt die Seite automatisch zusätzliche Inhalte."
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "Nacht Modus"
|
dark-mode: "Nacht Modus"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "Kreisförmige Icons"
|
circle-icons: "Kreisförmige Icons"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "Übergang in Fensterköpfen"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "Karte anzeigen"
|
show-maps: "Karte anzeigen"
|
||||||
show-maps-desc: "Zeige den Standort zu diesem Beitrag automatisch an."
|
|
||||||
sound: "Ton"
|
sound: "Ton"
|
||||||
enable-sounds: "Ton aktivieren"
|
enable-sounds: "Ton aktivieren"
|
||||||
enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert."
|
enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert."
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -109,7 +109,7 @@ common:
|
|||||||
use-contrast-reversi-stones: "Make the stone color clear in reversi"
|
use-contrast-reversi-stones: "Make the stone color clear in reversi"
|
||||||
verified-user: "Verified account"
|
verified-user: "Verified account"
|
||||||
disable-animated-mfm: "Disable animated texts in a post"
|
disable-animated-mfm: "Disable animated texts in a post"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "Always show NSFW contents"
|
||||||
always-mark-nsfw: "Always post with a warning about media attachment"
|
always-mark-nsfw: "Always post with a warning about media attachment"
|
||||||
show-full-acct: "Do not omit the hostname from the username"
|
show-full-acct: "Do not omit the hostname from the username"
|
||||||
reduce-motion: "Reduce motion in UI"
|
reduce-motion: "Reduce motion in UI"
|
||||||
@ -158,7 +158,7 @@ common:
|
|||||||
hashtag: "Hashtag"
|
hashtag: "Hashtag"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
direct: "ダイレクト投稿"
|
direct: "Direct post"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
list: "Lists"
|
list: "Lists"
|
||||||
swap-left: "Move to the left"
|
swap-left: "Move to the left"
|
||||||
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "NSFW"
|
sensitive: "NSFW"
|
||||||
click-to-show: "Click to show"
|
click-to-show: "Click to show"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "See more"
|
show: "See more"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "Copy link"
|
copy-link: "Copy link"
|
||||||
favorite: "Favorite this note"
|
favorite: "Favorite this note"
|
||||||
pin: "Pin to your profile"
|
pin: "Pin to your profile"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
delete-confirm: "Delete this post?"
|
delete-confirm: "Delete this post?"
|
||||||
remote: "Show original note"
|
remote: "Show original note"
|
||||||
@ -478,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "The number of posts: increase/decrease (Combined)"
|
notes: "The number of posts: increase/decrease (Combined)"
|
||||||
local-notes: "The number of posts: increase/decrease (Local)"
|
local-notes: "The number of posts: increase/decrease (Local)"
|
||||||
remote-notes: "The number of posts: increase/decrease (Remote)"
|
remote-notes: "The number of posts: increase/decrease (Remote)"
|
||||||
notes-total: "The number of posts: cumulative total"
|
notes-total: "投稿の積算"
|
||||||
users: "The number of users: increase/decrease"
|
users: "The number of users: increase/decrease"
|
||||||
users-total: "The number of users: cumulative total"
|
users-total: "ユーザーの積算"
|
||||||
drive: "Capacity used as the storage: increase/decrease"
|
drive: "Capacity used as the storage: increase/decrease"
|
||||||
drive-total: "Capacity used as the storage: cumulative total"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "The number of files on the storage: increase/decrease"
|
drive-files: "The number of files on the storage: increase/decrease"
|
||||||
drive-files-total: "The number of files on the storage: cumulative total"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "Requests"
|
network-requests: "Requests"
|
||||||
network-time: "Response time"
|
network-time: "Response time"
|
||||||
network-usage: "Traffic"
|
network-usage: "Traffic"
|
||||||
@ -677,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Two-factor authentication"
|
2fa: "Two-factor authentication"
|
||||||
other: "Other"
|
other: "Other"
|
||||||
license: "License"
|
license: "License"
|
||||||
|
theme: "Theme"
|
||||||
behaviour: "Behavior"
|
behaviour: "Behavior"
|
||||||
fetch-on-scroll: "Endless loading on scroll"
|
fetch-on-scroll: "Endless loading on scroll"
|
||||||
fetch-on-scroll-desc: "When you scroll down the page, it automatically fetches additional content."
|
fetch-on-scroll-desc: "When you scroll down the page, it automatically fetches additional content."
|
||||||
@ -693,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "Choose a background"
|
choose-wallpaper: "Choose a background"
|
||||||
delete-wallpaper: "Remove background"
|
delete-wallpaper: "Remove background"
|
||||||
dark-mode: "Dark Mode"
|
dark-mode: "Dark Mode"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "Use circle icons"
|
circle-icons: "Use circle icons"
|
||||||
contrasted-acct: "Add contrast to username"
|
contrasted-acct: "Add contrast to username"
|
||||||
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"
|
||||||
suggest-recent-hashtags: "Show recent popular hashtags on the post form"
|
suggest-recent-hashtags: "Show recent popular hashtags on the post form"
|
||||||
show-clock-on-header: "Show clock on upper-right"
|
show-clock-on-header: "Show clock on upper-right"
|
||||||
@ -704,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "Show renoted my posts in timelines"
|
show-renoted-my-notes: "Show renoted my posts in timelines"
|
||||||
show-local-renotes: "Show renoted local posts in timelines"
|
show-local-renotes: "Show renoted local posts in timelines"
|
||||||
show-maps: "Display a map to show the location"
|
show-maps: "Display a map to show the location"
|
||||||
show-maps-desc: "If there comes a post contains location information, show a map to display the location."
|
|
||||||
sound: "Sound"
|
sound: "Sound"
|
||||||
enable-sounds: "Enable sound"
|
enable-sounds: "Enable sound"
|
||||||
enable-sounds-desc: "Play a sound when you receive 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."
|
||||||
@ -1222,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "Notification style"
|
notification-position: "Notification style"
|
||||||
notification-position-bottom: "Bottom"
|
notification-position-bottom: "Bottom"
|
||||||
notification-position-top: "Top"
|
notification-position-top: "Top"
|
||||||
|
theme: "Theme"
|
||||||
behavior: "Behavior"
|
behavior: "Behavior"
|
||||||
fetch-on-scroll: "Endless loading on scroll"
|
fetch-on-scroll: "Endless loading on scroll"
|
||||||
note-visibility: "Post visibility"
|
note-visibility: "Post visibility"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "Copiar enlace"
|
copy-link: "Copiar enlace"
|
||||||
favorite: "Me gusta esta nota"
|
favorite: "Me gusta esta nota"
|
||||||
pin: "Fijar en el perfil"
|
pin: "Fijar en el perfil"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "Borrar"
|
delete: "Borrar"
|
||||||
delete-confirm: "¿Seguro que quieres borrar la publicación?"
|
delete-confirm: "¿Seguro que quieres borrar la publicación?"
|
||||||
remote: "Ver el original"
|
remote: "Ver el original"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "Siguiendo"
|
following: "Siguiendo"
|
||||||
follow: "Seguir"
|
follow: "Seguir"
|
||||||
request-pending: "Solicitud pendiente"
|
request-pending: "Solicitud pendiente"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Solicitar suscripción"
|
follow-request: "Solicitar suscripción"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "Corta la parte que aparece como un banner"
|
banner-crop-title: "Corta la parte que aparece como un banner"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "Número de publicaciones: aumentar/disminuir (Combinado)"
|
notes: "Número de publicaciones: aumentar/disminuir (Combinado)"
|
||||||
local-notes: "Número de publicaciones: aumentar/disminuir (Local)"
|
local-notes: "Número de publicaciones: aumentar/disminuir (Local)"
|
||||||
remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)"
|
remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)"
|
||||||
notes-total: "Número de publicaciones: Acumulativo total"
|
notes-total: "投稿の積算"
|
||||||
users: "Número de usuarios: aumentar/disminuir"
|
users: "Número de usuarios: aumentar/disminuir"
|
||||||
users-total: "Número de usuarios: Acumulativo total"
|
users-total: "ユーザーの積算"
|
||||||
drive: "Capacidad de almacenamiento usada: aumentar/disminuir"
|
drive: "Capacidad de almacenamiento usada: aumentar/disminuir"
|
||||||
drive-total: "Capacidad de almacenamiento usada: Acumulativa total"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "Número de archivos almacenados: aumentar/disminuir"
|
drive-files: "Número de archivos almacenados: aumentar/disminuir"
|
||||||
drive-files-total: "Número de archivos almacenados: Acumulativo total"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "Siguiendo"
|
following: "Siguiendo"
|
||||||
follow: "Sigue"
|
follow: "Sigue"
|
||||||
request-pending: "Pendiente de aprobación"
|
request-pending: "Pendiente de aprobación"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Solicitud de seguir"
|
follow-request: "Solicitud de seguir"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} seguidores"
|
followers: "{} seguidores"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Autenticación de Doble-Factor"
|
2fa: "Autenticación de Doble-Factor"
|
||||||
other: "Otros"
|
other: "Otros"
|
||||||
license: "Licencia"
|
license: "Licencia"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "Acciones"
|
behaviour: "Acciones"
|
||||||
fetch-on-scroll: "Desplazamiento infinito"
|
fetch-on-scroll: "Desplazamiento infinito"
|
||||||
fetch-on-scroll-desc: "Cuando te deslizas al final de la página nuevo contenido se carga automáticamente."
|
fetch-on-scroll-desc: "Cuando te deslizas al final de la página nuevo contenido se carga automáticamente."
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "Elije un fondo"
|
choose-wallpaper: "Elije un fondo"
|
||||||
delete-wallpaper: "Suprimir fondo"
|
delete-wallpaper: "Suprimir fondo"
|
||||||
dark-mode: "Modo Nocturno"
|
dark-mode: "Modo Nocturno"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "Usar iconos circulares"
|
circle-icons: "Usar iconos circulares"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "Usar degradados en las cabeceras de las páginas"
|
|
||||||
post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo"
|
post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -9,7 +9,7 @@ common:
|
|||||||
intro:
|
intro:
|
||||||
title: "C’est quoi Misskey ?"
|
title: "C’est quoi Misskey ?"
|
||||||
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
||||||
features: "Fonctionnalités"
|
features: "Options"
|
||||||
rich-contents: "Notes"
|
rich-contents: "Notes"
|
||||||
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
|
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
|
||||||
reaction: "Réactions"
|
reaction: "Réactions"
|
||||||
@ -52,7 +52,7 @@ common:
|
|||||||
weeks_ago: "Il y a {} semaines·s"
|
weeks_ago: "Il y a {} semaines·s"
|
||||||
months_ago: "Il y a {} mois"
|
months_ago: "Il y a {} mois"
|
||||||
years_ago: "Il y a {} an·s"
|
years_ago: "Il y a {} an·s"
|
||||||
month-and-day: "{month}/{day}"
|
month-and-day: "{month} mois/{day} jour"
|
||||||
trash: "Corbeille"
|
trash: "Corbeille"
|
||||||
weekday-short:
|
weekday-short:
|
||||||
sunday: "D"
|
sunday: "D"
|
||||||
@ -111,7 +111,7 @@ common:
|
|||||||
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
show-full-acct: "ユーザー名のホストを省略しない"
|
show-full-acct: "Afficher l’adresse complète de l’utilisateur"
|
||||||
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
||||||
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
||||||
do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.'
|
do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.'
|
||||||
@ -149,16 +149,16 @@ common:
|
|||||||
donation: "Dons"
|
donation: "Dons"
|
||||||
nav: "Navigation"
|
nav: "Navigation"
|
||||||
tips: "Conseils"
|
tips: "Conseils"
|
||||||
hashtags: "Étiquettes"
|
hashtags: "Hashtags"
|
||||||
deck:
|
deck:
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
home: "Accueil"
|
home: "Accueil"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
hybrid: "Social"
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "Hashtag"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
direct: "ダイレクト投稿"
|
direct: "Messages directs"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
list: "Liste"
|
list: "Liste"
|
||||||
swap-left: "Déplacer à gauche"
|
swap-left: "Déplacer à gauche"
|
||||||
@ -189,7 +189,7 @@ auth/views/index.vue:
|
|||||||
denied: "L'autorisation de l'application a été refusée."
|
denied: "L'autorisation de l'application a été refusée."
|
||||||
denied-paragraph: "Cette application ne va pas accéder à votre compte."
|
denied-paragraph: "Cette application ne va pas accéder à votre compte."
|
||||||
already-authorized: "Cette application est déjà autorisée"
|
already-authorized: "Cette application est déjà autorisée"
|
||||||
allowed: "アプリケーションの連携を許可しました"
|
allowed: "Permissions autorisées de l’application."
|
||||||
callback-url: "Retour vers l'application"
|
callback-url: "Retour vers l'application"
|
||||||
please-go-back: "Veillez retourner à l'application."
|
please-go-back: "Veillez retourner à l'application."
|
||||||
error: "La session n'existe pas."
|
error: "La session n'existe pas."
|
||||||
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "Contenu sensible"
|
sensitive: "Contenu sensible"
|
||||||
click-to-show: "Cliquer pour afficher"
|
click-to-show: "Cliquer pour afficher"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "Installer un thème"
|
||||||
|
theme-code: "Code du thème"
|
||||||
|
install: "Installation"
|
||||||
|
installed: "« {} » a été installé"
|
||||||
|
create-a-theme: "Créer un thème"
|
||||||
|
save-created-theme: "Enregistrer le thème"
|
||||||
|
primary-color: "Couleur primaire"
|
||||||
|
secondary-color: "Couleur secondaire"
|
||||||
|
text-color: "Couleur du texte"
|
||||||
|
base-theme: "Thème de base"
|
||||||
|
base-theme-light: "Clair"
|
||||||
|
base-theme-dark: "Sombre"
|
||||||
|
theme-name: "Nom du Thème"
|
||||||
|
preview-created-theme: "Prévisualisation"
|
||||||
|
invalid-theme: "Thème n’est pas valide."
|
||||||
|
already-installed: "Le thème est déjà installé."
|
||||||
|
saved: "enregistré"
|
||||||
|
installed-themes: "Thèmes installés"
|
||||||
|
select-theme: "Veuillez sélectionner un thème"
|
||||||
|
uninstall: "Désinstaller"
|
||||||
|
uninstalled: "« {} » a été désinstallé"
|
||||||
|
author: "Auteur"
|
||||||
|
desc: "Description"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "Importer"
|
||||||
|
import-by-code: "Ou coller du code"
|
||||||
|
theme-name-required: "Nom du thème est obligatoire."
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "Masquer"
|
hide: "Masquer"
|
||||||
show: "Voir plus"
|
show: "Voir plus"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "Copier le lien"
|
copy-link: "Copier le lien"
|
||||||
favorite: "Mettre cette note en favoris"
|
favorite: "Mettre cette note en favoris"
|
||||||
pin: "Épingler sur votre profil"
|
pin: "Épingler sur votre profil"
|
||||||
|
unpin: "Désépingler"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
delete-confirm: "Supprimer cette publication ?"
|
delete-confirm: "Supprimer cette publication ?"
|
||||||
remote: "Afficher la note originale"
|
remote: "Afficher la note originale"
|
||||||
@ -401,7 +434,7 @@ common/views/widgets/posts-monitor.vue:
|
|||||||
title: "Graphe des publications"
|
title: "Graphe des publications"
|
||||||
toggle: "Basculer entre les vues"
|
toggle: "Basculer entre les vues"
|
||||||
common/views/widgets/hashtags.vue:
|
common/views/widgets/hashtags.vue:
|
||||||
title: "Étiquettes"
|
title: "Hashtags"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "Informations sur le serveur"
|
title: "Informations sur le serveur"
|
||||||
toggle: "Afficher les vues"
|
toggle: "Afficher les vues"
|
||||||
@ -420,7 +453,7 @@ common/views/widgets/tips.vue:
|
|||||||
tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note"
|
tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note"
|
||||||
tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser-déposer"
|
tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser-déposer"
|
||||||
tips-line6: "Vous pouvez déplacer un dossier en le glissant dans le Drive"
|
tips-line6: "Vous pouvez déplacer un dossier en le glissant dans le Drive"
|
||||||
tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます"
|
tips-line7: "Vous pouvez déplacer des dossiers en les glissant dans le Drive"
|
||||||
tips-line8: "Vous pouvez personnaliser l'Accueil via les paramètres"
|
tips-line8: "Vous pouvez personnaliser l'Accueil via les paramètres"
|
||||||
tips-line9: "Misskey est sous licence AGPLv3"
|
tips-line9: "Misskey est sous licence AGPLv3"
|
||||||
tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます"
|
tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます"
|
||||||
@ -428,7 +461,7 @@ common/views/widgets/tips.vue:
|
|||||||
tips-line13: "Tous les fichiers attachés à cette publication sont sauvegardés dans le Drive"
|
tips-line13: "Tous les fichiers attachés à cette publication sont sauvegardés dans le Drive"
|
||||||
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
|
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
|
||||||
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
|
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
|
||||||
tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができます"
|
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
|
||||||
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
|
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
|
||||||
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
|
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
|
||||||
tips-line23: "Mayu est mignone avec ses sourcils."
|
tips-line23: "Mayu est mignone avec ses sourcils."
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "Suit"
|
following: "Suit"
|
||||||
follow: "Suivre"
|
follow: "Suivre"
|
||||||
request-pending: "Demande d'abonnement en attente"
|
request-pending: "Demande d'abonnement en attente"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Demande d'abonnement"
|
follow-request: "Demande d'abonnement"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "Découpez la partie qui apparaitra comme bannière"
|
banner-crop-title: "Découpez la partie qui apparaitra comme bannière"
|
||||||
@ -451,7 +485,7 @@ desktop:
|
|||||||
uploading-avatar: "Téléversement du nouvel avatar"
|
uploading-avatar: "Téléversement du nouvel avatar"
|
||||||
avatar-updated: "L'avatar est mis à jour"
|
avatar-updated: "L'avatar est mis à jour"
|
||||||
choose-avatar: "Choisir un avatar"
|
choose-avatar: "Choisir un avatar"
|
||||||
invalid-filetype: "この形式のファイルはサポートされていません"
|
invalid-filetype: "Ce format de fichier n’est pas pris en charge"
|
||||||
desktop/views/components/activity.chart.vue:
|
desktop/views/components/activity.chart.vue:
|
||||||
total: "Noirs ... Total"
|
total: "Noirs ... Total"
|
||||||
notes: "Bleu ... Notes"
|
notes: "Bleu ... Notes"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "Nombre d’utilisateurs·trices : augmentation/diminution"
|
users: "Nombre d’utilisateurs·trices : augmentation/diminution"
|
||||||
users-total: "Nombre total d’utilisateurs·trices : total cumulé"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "Requêtes"
|
network-requests: "Requêtes"
|
||||||
network-time: "Temps de réponse"
|
network-time: "Temps de réponse"
|
||||||
network-usage: "Traffic"
|
network-usage: "Traffic"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "Abonnements"
|
following: "Abonnements"
|
||||||
follow: "Suivre"
|
follow: "Suivre"
|
||||||
request-pending: "En attente d'approbation"
|
request-pending: "En attente d'approbation"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Demande d'abonnement"
|
follow-request: "Demande d'abonnement"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} abonné·e·s"
|
followers: "{} abonné·e·s"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Vérification en deux étapes"
|
2fa: "Vérification en deux étapes"
|
||||||
other: "Autres"
|
other: "Autres"
|
||||||
license: "License"
|
license: "License"
|
||||||
|
theme: "Thèmes"
|
||||||
behaviour: "Comportement"
|
behaviour: "Comportement"
|
||||||
fetch-on-scroll: "Chargement lors du défilement"
|
fetch-on-scroll: "Chargement lors du défilement"
|
||||||
fetch-on-scroll-desc: "Chargement automatique du contenu lors du défilement de la page."
|
fetch-on-scroll-desc: "Chargement automatique du contenu lors du défilement de la page."
|
||||||
@ -691,18 +727,18 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "Sélectionner un fond d'écran"
|
choose-wallpaper: "Sélectionner un fond d'écran"
|
||||||
delete-wallpaper: "Supprimer le fond d'écran"
|
delete-wallpaper: "Supprimer le fond d'écran"
|
||||||
dark-mode: "Mode nuit"
|
dark-mode: "Mode nuit"
|
||||||
|
use-shadow: "Utiliser les ombres dans l'interface utilisateur"
|
||||||
|
rounded-corners: "Coins arrondis"
|
||||||
circle-icons: "Utiliser des icônes circulaires"
|
circle-icons: "Utiliser des icônes circulaires"
|
||||||
contrasted-acct: "Nom d’utilisateur contrasté"
|
contrasted-acct: "Nom d’utilisateur contrasté"
|
||||||
gradient-window-header: "Utiliser les dégradés sur la barre de titre de la fenêtre"
|
|
||||||
post-form-on-timeline: "Afficher le formulaire en haut du fil"
|
post-form-on-timeline: "Afficher le formulaire en haut du fil"
|
||||||
suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie"
|
suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie"
|
||||||
show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur"
|
show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur"
|
||||||
show-reply-target: "Afficher les réponses"
|
show-reply-target: "Afficher les réponses"
|
||||||
show-my-renotes: "Afficher mes republications dans le fil"
|
show-my-renotes: "Afficher mes republications dans le fil"
|
||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "Afficher mes republications dans les fils"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "Afficher la carte"
|
show-maps: "Afficher la carte"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "Son"
|
sound: "Son"
|
||||||
enable-sounds: "Activer le son"
|
enable-sounds: "Activer le son"
|
||||||
enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur."
|
enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur."
|
||||||
@ -741,7 +777,7 @@ desktop/views/components/settings.vue:
|
|||||||
debug-mode: "Activer le mode debug"
|
debug-mode: "Activer le mode debug"
|
||||||
debug-mode-desc: "Ce paramètre est stocké dans le navigateur."
|
debug-mode-desc: "Ce paramètre est stocké dans le navigateur."
|
||||||
experimental: "Activer les fonctionnalités expérimentales"
|
experimental: "Activer les fonctionnalités expérimentales"
|
||||||
experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。"
|
experimental-desc: "L’activation des fonctionnalités expérimentales peuvent rendre le client Misskey instable. Ce paramètre est stocké dans le navigateur."
|
||||||
tools: "Outils"
|
tools: "Outils"
|
||||||
task-manager: "Gestionnaire de tâches"
|
task-manager: "Gestionnaire de tâches"
|
||||||
third-parties: "Services tiers"
|
third-parties: "Services tiers"
|
||||||
@ -811,12 +847,12 @@ desktop/views/components/timeline.vue:
|
|||||||
hybrid: "Social"
|
hybrid: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
messages: "メッセージ"
|
messages: "Messages"
|
||||||
list: "Listes"
|
list: "Listes"
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "Hashtag"
|
||||||
add-tag-timeline: "ハッシュタグを追加"
|
add-tag-timeline: "Ajouter un fil de hashtags"
|
||||||
add-list: "リストを追加"
|
add-list: "Ajouter une nouvelle liste"
|
||||||
list-name: "リスト名"
|
list-name: "Nom de la liste"
|
||||||
desktop/views/components/ui.header.vue:
|
desktop/views/components/ui.header.vue:
|
||||||
welcome-back: "Content de vous revoir !"
|
welcome-back: "Content de vous revoir !"
|
||||||
adjective: "さん"
|
adjective: "さん"
|
||||||
@ -932,7 +968,7 @@ desktop/views/pages/selectdrive.vue:
|
|||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
upload: "Uploader un ou plusieurs fichier(s) depuis votre PC"
|
upload: "Uploader un ou plusieurs fichier(s) depuis votre PC"
|
||||||
desktop/views/pages/search.vue:
|
desktop/views/pages/search.vue:
|
||||||
not-available: "検索機能はインスタンスの設定で無効になっています。"
|
not-available: "La fonction de recherche est désactivée dans les paramètres de l’instance."
|
||||||
not-found: "Aucun message trouvé pour '{}'"
|
not-found: "Aucun message trouvé pour '{}'"
|
||||||
desktop/views/pages/share.vue:
|
desktop/views/pages/share.vue:
|
||||||
share-with: "Partager avec {}"
|
share-with: "Partager avec {}"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "Abonnements"
|
following: "Abonnements"
|
||||||
follow: "Suivre"
|
follow: "Suivre"
|
||||||
request-pending: "En attente d'approbation"
|
request-pending: "En attente d'approbation"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Demande d'abonnement"
|
follow-request: "Demande d'abonnement"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "Abonnez-vous aux utilisateurs"
|
title: "Abonnez-vous aux utilisateurs"
|
||||||
@ -1142,7 +1179,7 @@ mobile/views/pages/home.vue:
|
|||||||
hybrid: "Social"
|
hybrid: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
messages: "メッセージ"
|
messages: "Messages"
|
||||||
mobile/views/pages/tag.vue:
|
mobile/views/pages/tag.vue:
|
||||||
no-posts-found: "Pas de message avec un hashtag {} trouvé."
|
no-posts-found: "Pas de message avec un hashtag {} trouvé."
|
||||||
mobile/views/pages/welcome.vue:
|
mobile/views/pages/welcome.vue:
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "Style de notification"
|
notification-position: "Style de notification"
|
||||||
notification-position-bottom: "en bas"
|
notification-position-bottom: "en bas"
|
||||||
notification-position-top: "en haut"
|
notification-position-top: "en haut"
|
||||||
|
theme: "Thème"
|
||||||
behavior: "Comportement"
|
behavior: "Comportement"
|
||||||
fetch-on-scroll: "Chargement lors du défilement"
|
fetch-on-scroll: "Chargement lors du défilement"
|
||||||
note-visibility: "Visibilité de la publication"
|
note-visibility: "Visibilité de la publication"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -288,6 +288,8 @@ common/views/components/media-banner.vue:
|
|||||||
common/views/components/theme.vue:
|
common/views/components/theme.vue:
|
||||||
light-theme: "非ダークモード時に使用するテーマ"
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
dark-theme: "ダークモード時に使用するテーマ"
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
install-a-theme: "テーマのインストール"
|
install-a-theme: "テーマのインストール"
|
||||||
theme-code: "テーマコード"
|
theme-code: "テーマコード"
|
||||||
install: "インストール"
|
install: "インストール"
|
||||||
@ -564,13 +566,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
|
@ -264,9 +264,41 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "見せたらあかん"
|
sensitive: "見せたらあかん"
|
||||||
click-to-show: "押してみ、見せたるわ"
|
click-to-show: "押してみ、見せたるわ"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "見せへんわ"
|
hide: "もうええわ"
|
||||||
show: "もっとあるやろ!"
|
show: "見たいやろ?"
|
||||||
common/views/components/messaging.vue:
|
common/views/components/messaging.vue:
|
||||||
search-user: "ユーザーを探す"
|
search-user: "ユーザーを探す"
|
||||||
you: "あんさん"
|
you: "あんさん"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留めやめる"
|
||||||
delete: "ほかす"
|
delete: "ほかす"
|
||||||
delete-confirm: "この投稿を削除してもええか?"
|
delete-confirm: "この投稿を削除してもええか?"
|
||||||
remote: "投稿元に行ってみよか"
|
remote: "投稿元に行ってみよか"
|
||||||
@ -431,7 +464,7 @@ common/views/widgets/tips.vue:
|
|||||||
tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができんで"
|
tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができんで"
|
||||||
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示してんねん"
|
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示してんねん"
|
||||||
tips-line21: "APIをつこてbotの開発なども行えるで"
|
tips-line21: "APIをつこてbotの開発なども行えるで"
|
||||||
tips-line23: "まゆかわいいよまゆ"
|
tips-line23: "ウチのタコちゃんかわええやろ…今の突っ込むところや!"
|
||||||
tips-line24: "Misskeyは2014年にサービスを開始したんよ"
|
tips-line24: "Misskeyは2014年にサービスを開始したんよ"
|
||||||
tips-line25: "対応ブラウザやったらMisskeyを開いとらんでも通知を受け取れんで"
|
tips-line25: "対応ブラウザやったらMisskeyを開いとらんでも通知を受け取れんで"
|
||||||
common/views/pages/follow.vue:
|
common/views/pages/follow.vue:
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "どこバナーとして出す?"
|
banner-crop-title: "どこバナーとして出す?"
|
||||||
@ -453,10 +487,10 @@ desktop:
|
|||||||
choose-avatar: "アバターにする画像選んでや"
|
choose-avatar: "アバターにする画像選んでや"
|
||||||
invalid-filetype: "この形式のファイル無理やねん"
|
invalid-filetype: "この形式のファイル無理やねん"
|
||||||
desktop/views/components/activity.chart.vue:
|
desktop/views/components/activity.chart.vue:
|
||||||
total: "Black ... Total"
|
total: "黒いの… 全部"
|
||||||
notes: "Blue ... Notes"
|
notes: "青いの… 投稿"
|
||||||
replies: "Red ... Replies"
|
replies: "赤いの… 返信"
|
||||||
renotes: "Green ... Renotes"
|
renotes: "みどり… Renotes"
|
||||||
desktop/views/components/activity.vue:
|
desktop/views/components/activity.vue:
|
||||||
title: "アクティビティ"
|
title: "アクティビティ"
|
||||||
toggle: "表示変える"
|
toggle: "表示変える"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減(統合)"
|
notes: "投稿の増減(統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "全部の投稿"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -588,7 +623,7 @@ desktop/views/components/home.vue:
|
|||||||
add: "増やす"
|
add: "増やす"
|
||||||
desktop/views/input-dialog.vue:
|
desktop/views/input-dialog.vue:
|
||||||
cancel: "やめとくわ"
|
cancel: "やめとくわ"
|
||||||
ok: "決定"
|
ok: "これや!"
|
||||||
desktop/views/components/messaging-room-window.vue:
|
desktop/views/components/messaging-room-window.vue:
|
||||||
title: "メッセージ:"
|
title: "メッセージ:"
|
||||||
desktop/views/components/messaging-window.vue:
|
desktop/views/components/messaging-window.vue:
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動き"
|
behaviour: "動き"
|
||||||
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動でもっとコンテンツを読み込むで。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動でもっとコンテンツを読み込むで。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙選ぶ"
|
choose-wallpaper: "壁紙選ぶ"
|
||||||
delete-wallpaper: "壁紙ほかす"
|
delete-wallpaper: "壁紙ほかす"
|
||||||
dark-mode: "夜にすんで"
|
dark-mode: "夜にすんで"
|
||||||
|
use-shadow: "UIに影付けたる"
|
||||||
|
rounded-corners: "みんなまぁるくUI変更"
|
||||||
circle-icons: "アイコンもタコ焼きも丸いやんな?"
|
circle-icons: "アイコンもタコ焼きも丸いやんな?"
|
||||||
contrasted-acct: "ユーザー名ようわからんし見やすしといて"
|
contrasted-acct: "ユーザー名ようわからんし見やすしといて"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーション付ける"
|
|
||||||
post-form-on-timeline: "タイムラインの上の方で投稿できるようにせえへん?"
|
post-form-on-timeline: "タイムラインの上の方で投稿できるようにせえへん?"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示すんで"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示すんで"
|
||||||
show-clock-on-header: "右上をカリヨン広場にする(時計表示)"
|
show-clock-on-header: "右上をカリヨン広場にする(時計表示)"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "わしのRenoteもタイムライン載せてくれや"
|
show-renoted-my-notes: "わしのRenoteもタイムライン載せてくれや"
|
||||||
show-local-renotes: "ローカル投稿のRenoteも見たいんや"
|
show-local-renotes: "ローカル投稿のRenoteも見たいんや"
|
||||||
show-maps: "地図勝手にバァーって開いてくれ"
|
show-maps: "地図勝手にバァーって開いてくれ"
|
||||||
show-maps-desc: "どこにおるんかわかっとる投稿の地図は自動で見せるで"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンド鳴らす"
|
enable-sounds: "サウンド鳴らす"
|
||||||
enable-sounds-desc: "投稿やメッセージもろたとき、音鳴らしたるわ。大丈夫や、この設定はブラウザが覚えてくれとる。"
|
enable-sounds-desc: "投稿やメッセージもろたとき、音鳴らしたるわ。大丈夫や、この設定はブラウザが覚えてくれとる。"
|
||||||
@ -793,7 +829,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
birthday: "誕生日"
|
birthday: "誕生日"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウント守る"
|
locked-account: "アカウント守る"
|
||||||
is-locked: "他人のフォローは許してからや!"
|
is-locked: "他人のフォローは許可してからや!"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotやで"
|
is-bot: "このアカウントはBotやで"
|
||||||
is-cat: "このアカウントはCatやで"
|
is-cat: "このアカウントはCatやで"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "おもろそうやな"
|
title: "おもろそうやな"
|
||||||
@ -1185,97 +1222,98 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
is-cat: "このアカウントはCatや"
|
is-cat: "このアカウントはCatや"
|
||||||
is-locked: "他人のフォローは許してからや!"
|
is-locked: "他人のフォローは許してからや!"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー⇔オカンの年齢"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
saved: "プロフィールを保存しました"
|
saved: "プロフィールを保存したで"
|
||||||
uploading: "アップロード中"
|
uploading: "アップロードしとるで…"
|
||||||
upload-failed: "アップロードに失敗しました"
|
upload-failed: "これアップロードでけへんわ"
|
||||||
mobile/views/pages/search.vue:
|
mobile/views/pages/search.vue:
|
||||||
search: "検索"
|
search: "探す"
|
||||||
empty: "「{}」に関する投稿は見つかりませんでした。"
|
empty: "ワイは「{}」なんて投稿知らんわ、無いんちゃう?知らんけど。"
|
||||||
not-found: "「{}」に関する投稿は見つかりませんでした。"
|
not-found: "ワイは「{}」なんて投稿知らんわ、無いんちゃう?知らんけど。"
|
||||||
mobile/views/pages/selectdrive.vue:
|
mobile/views/pages/selectdrive.vue:
|
||||||
select-file: "ファイルを選択"
|
select-file: "ファイル選んでや"
|
||||||
mobile/views/pages/settings.vue:
|
mobile/views/pages/settings.vue:
|
||||||
signed-in-as: "{}としてサインイン中"
|
signed-in-as: "あんたは橋の下で拾った{}や!"
|
||||||
lang: "言語"
|
lang: "言語"
|
||||||
lang-tip: "変更はページの再読み込み後に反映されます。"
|
lang-tip: "ページもっぺん読み込んだら反映したるで。"
|
||||||
recommended: "推奨"
|
recommended: "これええで"
|
||||||
auto: "自動"
|
auto: "勝手にやる"
|
||||||
specify-language: "言語を指定"
|
specify-language: "言語選びや"
|
||||||
design: "デザインと表示"
|
design: "見た感じ"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ナイトゲームや!"
|
||||||
i-am-under-limited-internet: "私は通信を制限されている"
|
i-am-under-limited-internet: "電波がバァーっといけへんねん"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "アイコンもタコ焼きも丸いやんな?"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名ようわからんし見やすしといて"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
show-reply-target: "リプライ先を表示する"
|
show-reply-target: "どこにリプライするんや見せて"
|
||||||
show-my-renotes: "自分の行ったRenoteを表示する"
|
show-my-renotes: "あんたのしたRenoteも出すで"
|
||||||
show-renoted-my-notes: "自分の投稿のRenoteを表示する"
|
show-renoted-my-notes: "あんたの言うたことのRenoteも出すで"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteを表示する"
|
show-local-renotes: "ローカル投稿のRenoteも出すで"
|
||||||
post-style: "投稿の表示スタイル"
|
post-style: "投稿の表示スタイル"
|
||||||
post-style-standard: "標準"
|
post-style-standard: "標準"
|
||||||
post-style-smart: "べっぴんさん"
|
post-style-smart: "べっぴんさん"
|
||||||
notification-position: "通知の表示"
|
notification-position: "通知どこ見せる?"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "ミナミ"
|
||||||
notification-position-top: "上"
|
notification-position-top: "キタ"
|
||||||
behavior: "動作"
|
theme: "テーマ"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
behavior: "動き"
|
||||||
|
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
default-note-visibility: "デフォルトの公開範囲"
|
default-note-visibility: "もとからの公開範囲"
|
||||||
remember-note-visibility: "投稿の公開範囲を記憶する"
|
remember-note-visibility: "投稿の公開範囲おぼえといて"
|
||||||
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
disable-via-mobile: "「モバイルからの投稿」フラグなんて要らんわ"
|
||||||
load-raw-images: "添付された画像を高画質で表示する"
|
load-raw-images: "添付された画像もべっぴんさんのままにしといてな"
|
||||||
load-remote-media: "リモートサーバーのメディアを表示する"
|
load-remote-media: "東京とか、リモートサーバーのメディアも見せてや"
|
||||||
twitter: "Twitter連携"
|
twitter: "鳥さんとも連携や!"
|
||||||
twitter-connect: "Twitterアカウントに接続する"
|
twitter-connect: "鳥さん邪魔すんで"
|
||||||
twitter-reconnect: "再接続する"
|
twitter-reconnect: "もっぺん繋ぎ直すで"
|
||||||
twitter-disconnect: "切断する"
|
twitter-disconnect: "邪魔するんやったら帰って"
|
||||||
update: "Misskey Update"
|
update: "あんたのMisskeyいつのや?"
|
||||||
version: "バージョン:"
|
version: "バージョン:"
|
||||||
latest-version: "最新のバージョン:"
|
latest-version: "いっちゃん新しいやつ:"
|
||||||
update-checking: "アップデートを確認中"
|
update-checking: "アップデートはあらへんか…"
|
||||||
check-for-updates: "アップデートを確認"
|
check-for-updates: "アップデートあるんかな?"
|
||||||
no-updates: "利用可能な更新はありません"
|
no-updates: "アップデートあらへんわ"
|
||||||
no-updates-desc: "お使いのMisskeyは最新です。"
|
no-updates-desc: "つこてるMisskeyは最新や!"
|
||||||
update-available: "新しいバージョンが利用可能です"
|
update-available: "もっとええバージョンがあるで"
|
||||||
update-available-desc: "ページを再度読み込みすると更新が適用されます。"
|
update-available-desc: "もっぺんページ読み込んだら新しなるで"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
signout: "サインアウト"
|
signout: "さいなら"
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンド鳴らす"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "フォローされています"
|
follows-you: "フォローされとるで"
|
||||||
following: "フォロー"
|
following: "フォロー"
|
||||||
followers: "フォロワー"
|
followers: "フォロワー"
|
||||||
notes: "投稿"
|
notes: "投稿"
|
||||||
overview: "概要"
|
overview: "こんなやつ"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
media: "メディア"
|
media: "メディア"
|
||||||
is-suspended: "このユーザーは凍結されています。"
|
is-suspended: "このユーザーはあかんわ。凍結されとる。"
|
||||||
is-remote: "このユーザーはリモートユーザーです。"
|
is-remote: "このユーザーは東京とかそこらへんのリモートユーザーや。"
|
||||||
view-remote: "正確な情報を見る"
|
view-remote: "ちゃんとした情報を見る"
|
||||||
mobile/views/pages/user/home.vue:
|
mobile/views/pages/user/home.vue:
|
||||||
recent-notes: "最近の投稿"
|
recent-notes: "最近儲かりまっか?"
|
||||||
images: "画像"
|
images: "画像"
|
||||||
activity: "アクティビティ"
|
activity: "やっとること"
|
||||||
keywords: "キーワード"
|
keywords: "キーワード"
|
||||||
domains: "頻出ドメイン"
|
domains: "よく出るドメイン"
|
||||||
frequently-replied-users: "よく会話するユーザー"
|
frequently-replied-users: "よう話しとるユーザー"
|
||||||
followers-you-know: "知り合いのフォロワー"
|
followers-you-know: "知っとるフォロワー"
|
||||||
last-used-at: "最終ログイン"
|
last-used-at: "最後いつ来た?"
|
||||||
mobile/views/pages/user/home.followers-you-know.vue:
|
mobile/views/pages/user/home.followers-you-know.vue:
|
||||||
loading: "読み込み中"
|
loading: "読み込んどる…"
|
||||||
no-users: "知り合いのユーザーはいません"
|
no-users: "知っとるユーザーは居らん"
|
||||||
mobile/views/pages/user/home.friends.vue:
|
mobile/views/pages/user/home.friends.vue:
|
||||||
loading: "読み込み中"
|
loading: "読み込んどる…"
|
||||||
no-users: "よく会話するユーザーはいません"
|
no-users: "よう話すユーザーは居らん"
|
||||||
mobile/views/pages/user/home.notes.vue:
|
mobile/views/pages/user/home.notes.vue:
|
||||||
loading: "読み込み中"
|
loading: "読み込んどる…"
|
||||||
no-notes: "投稿はありません"
|
no-notes: "投稿はあらへん"
|
||||||
mobile/views/pages/user/home.photos.vue:
|
mobile/views/pages/user/home.photos.vue:
|
||||||
loading: "読み込み中"
|
loading: "読み込んどる…"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はあらへんで"
|
||||||
docs:
|
docs:
|
||||||
edit-this-page-on-github: "間違いや改善点を見つけましたか?"
|
edit-this-page-on-github: "間違いや改善点を見つけましたか?"
|
||||||
edit-this-page-on-github-link: "このページをGitHubで編集"
|
edit-this-page-on-github-link: "このページをGitHubで編集"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Deze notitie toevoegen aan favorieten"
|
favorite: "Deze notitie toevoegen aan favorieten"
|
||||||
pin: "Vastmaken aan profielpagina"
|
pin: "Vastmaken aan profielpagina"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "Origineel tonen"
|
remote: "Origineel tonen"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "Volgen"
|
follow: "Volgen"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "Volgers van {}"
|
followers: "Volgers van {}"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Authenticatie in twee stappen"
|
2fa: "Authenticatie in twee stappen"
|
||||||
other: "Overig"
|
other: "Overig"
|
||||||
license: "Licentie"
|
license: "Licentie"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "Gedrag"
|
behaviour: "Gedrag"
|
||||||
fetch-on-scroll: "Ophalen bij scrollen"
|
fetch-on-scroll: "Ophalen bij scrollen"
|
||||||
fetch-on-scroll-desc: "Als je omlaag scrolt, wordt de rest van de inhoud automatisch opgehaald."
|
fetch-on-scroll-desc: "Als je omlaag scrolt, wordt de rest van de inhoud automatisch opgehaald."
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "Donkere modus"
|
dark-mode: "Donkere modus"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "Ronde pictogrammen gebruiken"
|
circle-icons: "Ronde pictogrammen gebruiken"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "Kleurverloop gebruiken op vensterkoppen"
|
|
||||||
post-form-on-timeline: "Berichtformulier boven de tijdlijn tonen"
|
post-form-on-timeline: "Berichtformulier boven de tijdlijn tonen"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "Mijn gerenote bericht tonen op de tijdlijn"
|
show-renoted-my-notes: "Mijn gerenote bericht tonen op de tijdlijn"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "Kaart tonen"
|
show-maps: "Kaart tonen"
|
||||||
show-maps-desc: "Kaart van bijgevoegde locatie tonen."
|
|
||||||
sound: "Geluid"
|
sound: "Geluid"
|
||||||
enable-sounds: "Geluid inschakelen"
|
enable-sounds: "Geluid inschakelen"
|
||||||
enable-sounds-desc: "Een geluid afspelen bij het ontvangen van een bericht. Deze instelling wordt opgeslagen in je browser."
|
enable-sounds-desc: "Een geluid afspelen bij het ontvangen van een bericht. Deze instelling wordt opgeslagen in je browser."
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "Volgen"
|
follow: "Volgen"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "Gedrag"
|
behavior: "Gedrag"
|
||||||
fetch-on-scroll: "Ophalen bij scrollen"
|
fetch-on-scroll: "Ophalen bij scrollen"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Dodaj do ulubionych"
|
favorite: "Dodaj do ulubionych"
|
||||||
pin: "Przypnij do profilu"
|
pin: "Przypnij do profilu"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "Usuń"
|
delete: "Usuń"
|
||||||
delete-confirm: "Czy na pewno chcesz usunąć ten wpis?"
|
delete-confirm: "Czy na pewno chcesz usunąć ten wpis?"
|
||||||
remote: "Pokaż oryginał"
|
remote: "Pokaż oryginał"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "Śledzisz"
|
following: "Śledzisz"
|
||||||
follow: "Śledź"
|
follow: "Śledź"
|
||||||
request-pending: "Oczekiwanie na pozwolenie"
|
request-pending: "Oczekiwanie na pozwolenie"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Poproś o śledzenie"
|
follow-request: "Poproś o śledzenie"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "Śledzisz"
|
following: "Śledzisz"
|
||||||
follow: "Śledź"
|
follow: "Śledź"
|
||||||
request-pending: "Oczekiwanie na pozwolenie"
|
request-pending: "Oczekiwanie na pozwolenie"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Poproś o śledzenie"
|
follow-request: "Poproś o śledzenie"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "Śledzący"
|
followers: "Śledzący"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Uwierzytelnianie dwuetapowe"
|
2fa: "Uwierzytelnianie dwuetapowe"
|
||||||
other: "Inne"
|
other: "Inne"
|
||||||
license: "Licencja"
|
license: "Licencja"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "Zachowanie"
|
behaviour: "Zachowanie"
|
||||||
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
|
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
|
||||||
fetch-on-scroll-desc: "Po przewinięciu na dół strony automatycznie zostaną załadowane nowe treści."
|
fetch-on-scroll-desc: "Po przewinięciu na dół strony automatycznie zostaną załadowane nowe treści."
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "Wybierz tło"
|
choose-wallpaper: "Wybierz tło"
|
||||||
delete-wallpaper: "Usuń tło"
|
delete-wallpaper: "Usuń tło"
|
||||||
dark-mode: "Tryb ciemny"
|
dark-mode: "Tryb ciemny"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "Używaj okrągłych ikon"
|
circle-icons: "Używaj okrągłych ikon"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "Używaj gradientów na pasku tytułu okna"
|
|
||||||
post-form-on-timeline: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
|
post-form-on-timeline: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "Automatycznie pokazuj mapę"
|
show-maps: "Automatycznie pokazuj mapę"
|
||||||
show-maps-desc: "Mapa będzie automatycznie rozwijana dla wpisów zawierających informacje o lokalizacji."
|
|
||||||
sound: "Dźwięk"
|
sound: "Dźwięk"
|
||||||
enable-sounds: "Włącz dźwięk"
|
enable-sounds: "Włącz dźwięk"
|
||||||
enable-sounds-desc: "Odtwarzaj dźwięk przy wstawianiu wpisów, wysyłaniu lub otrzymywaniu wiadomości. Opcja ta jest zapamiętywana przez przeglądarkę."
|
enable-sounds-desc: "Odtwarzaj dźwięk przy wstawianiu wpisów, wysyłaniu lub otrzymywaniu wiadomości. Opcja ta jest zapamiętywana przez przeglądarkę."
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "Śledzisz"
|
following: "Śledzisz"
|
||||||
follow: "Śledź"
|
follow: "Śledź"
|
||||||
request-pending: "Oczekiwanie na pozwolenie"
|
request-pending: "Oczekiwanie na pozwolenie"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "Poproś o śledzenie"
|
follow-request: "Poproś o śledzenie"
|
||||||
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"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
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ół"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
|
common/views/components/theme.vue:
|
||||||
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
|
light-themes: "明るいテーマ"
|
||||||
|
dark-themes: "暗いテーマ"
|
||||||
|
install-a-theme: "テーマのインストール"
|
||||||
|
theme-code: "テーマコード"
|
||||||
|
install: "インストール"
|
||||||
|
installed: "「{}」をインストールしました"
|
||||||
|
create-a-theme: "テーマの作成"
|
||||||
|
save-created-theme: "テーマを保存"
|
||||||
|
primary-color: "プライマリ カラー"
|
||||||
|
secondary-color: "セカンダリ カラー"
|
||||||
|
text-color: "文字色"
|
||||||
|
base-theme: "ベーステーマ"
|
||||||
|
base-theme-light: "Light"
|
||||||
|
base-theme-dark: "Dark"
|
||||||
|
theme-name: "テーマ名"
|
||||||
|
preview-created-theme: "プレビュー"
|
||||||
|
invalid-theme: "テーマが正しくありません。"
|
||||||
|
already-installed: "既にそのテーマはインストールされています。"
|
||||||
|
saved: "保存しました"
|
||||||
|
installed-themes: "インストールされたテーマ"
|
||||||
|
select-theme: "テーマを選択してください"
|
||||||
|
uninstall: "アンインストール"
|
||||||
|
uninstalled: "「{}」をアンインストールしました"
|
||||||
|
author: "作者"
|
||||||
|
desc: "説明"
|
||||||
|
export: "エクスポート"
|
||||||
|
import: "インポート"
|
||||||
|
import-by-code: "またはコードをペースト"
|
||||||
|
theme-name-required: "テーマ名は必須です。"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
show: "もっと見る"
|
show: "もっと見る"
|
||||||
@ -301,6 +333,7 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "この投稿を削除しますか?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
@ -439,6 +472,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "バナーとして表示する部分を選択"
|
banner-crop-title: "バナーとして表示する部分を選択"
|
||||||
@ -477,13 +511,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の累計"
|
notes-total: "投稿の積算"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
users-total: "ユーザーの累計"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
drive-total: "ドライブ使用量の累計"
|
drive-total: "ドライブ使用量の積算"
|
||||||
drive-files: "ドライブのファイル数の増減"
|
drive-files: "ドライブのファイル数の増減"
|
||||||
drive-files-total: "ドライブのファイル数の累計"
|
drive-files-total: "ドライブのファイル数の積算"
|
||||||
network-requests: "リクエスト"
|
network-requests: "リクエスト"
|
||||||
network-time: "応答時間"
|
network-time: "応答時間"
|
||||||
network-usage: "通信量"
|
network-usage: "通信量"
|
||||||
@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -675,6 +710,7 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
|
theme: "テーマ"
|
||||||
behaviour: "動作"
|
behaviour: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
@ -691,9 +727,10 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "壁紙を選択"
|
choose-wallpaper: "壁紙を選択"
|
||||||
delete-wallpaper: "壁紙を削除"
|
delete-wallpaper: "壁紙を削除"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "ダークモード"
|
||||||
|
use-shadow: "UIに影を使用"
|
||||||
|
rounded-corners: "UIの角を丸める"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "円形のアイコンを使用"
|
||||||
contrasted-acct: "ユーザー名にコントラストを付ける"
|
contrasted-acct: "ユーザー名にコントラストを付ける"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
show-clock-on-header: "右上に時計を表示する"
|
show-clock-on-header: "右上に時計を表示する"
|
||||||
@ -702,7 +739,6 @@ desktop/views/components/settings.vue:
|
|||||||
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
|
||||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "マップの自動展開"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
|
||||||
sound: "サウンド"
|
sound: "サウンド"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "サウンドを有効にする"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
|
follow-processing: "フォロー処理中"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "フォロー申請"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue:
|
|||||||
notification-position: "通知の表示"
|
notification-position: "通知の表示"
|
||||||
notification-position-bottom: "下"
|
notification-position-bottom: "下"
|
||||||
notification-position-top: "上"
|
notification-position-top: "上"
|
||||||
|
theme: "テーマ"
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
note-visibility: "投稿の公開範囲"
|
note-visibility: "投稿の公開範囲"
|
||||||
|
47
package.json
47
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "9.4.0",
|
"version": "10.0.0",
|
||||||
"clientVersion": "1.0.10062",
|
"clientVersion": "1.0.10328",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"@prezzemolo/zip": "0.0.3",
|
"@prezzemolo/zip": "0.0.3",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/dateformat": "1.0.1",
|
"@types/dateformat": "1.0.1",
|
||||||
"@types/debug": "0.0.30",
|
"@types/debug": "0.0.31",
|
||||||
"@types/deep-equal": "1.0.1",
|
"@types/deep-equal": "1.0.1",
|
||||||
"@types/double-ended-queue": "2.1.0",
|
"@types/double-ended-queue": "2.1.0",
|
||||||
"@types/elasticsearch": "5.0.26",
|
"@types/elasticsearch": "5.0.26",
|
||||||
@ -58,12 +58,12 @@
|
|||||||
"@types/minio": "7.0.0",
|
"@types/minio": "7.0.0",
|
||||||
"@types/mkdirp": "0.5.2",
|
"@types/mkdirp": "0.5.2",
|
||||||
"@types/mocha": "5.2.3",
|
"@types/mocha": "5.2.3",
|
||||||
"@types/mongodb": "3.1.7",
|
"@types/mongodb": "3.1.10",
|
||||||
"@types/ms": "0.7.30",
|
"@types/ms": "0.7.30",
|
||||||
"@types/node": "10.10.3",
|
"@types/node": "10.11.4",
|
||||||
"@types/portscanner": "2.1.0",
|
"@types/portscanner": "2.1.0",
|
||||||
"@types/pug": "2.0.4",
|
"@types/pug": "2.0.4",
|
||||||
"@types/qrcode": "1.2.0",
|
"@types/qrcode": "1.3.0",
|
||||||
"@types/ratelimiter": "2.1.28",
|
"@types/ratelimiter": "2.1.28",
|
||||||
"@types/redis": "2.8.6",
|
"@types/redis": "2.8.6",
|
||||||
"@types/request": "2.47.1",
|
"@types/request": "2.47.1",
|
||||||
@ -78,11 +78,12 @@
|
|||||||
"@types/tinycolor2": "1.4.1",
|
"@types/tinycolor2": "1.4.1",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"@types/uuid": "3.4.4",
|
"@types/uuid": "3.4.4",
|
||||||
"@types/webpack": "4.4.12",
|
"@types/webpack": "4.4.14",
|
||||||
"@types/webpack-stream": "3.2.10",
|
"@types/webpack-stream": "3.2.10",
|
||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"animejs": "2.2.0",
|
"animejs": "2.2.0",
|
||||||
|
"autobind-decorator": "2.1.0",
|
||||||
"autosize": "4.0.2",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
@ -98,7 +99,7 @@
|
|||||||
"debug": "4.0.1",
|
"debug": "4.0.1",
|
||||||
"deep-equal": "1.0.1",
|
"deep-equal": "1.0.1",
|
||||||
"deepcopy": "0.6.3",
|
"deepcopy": "0.6.3",
|
||||||
"diskusage": "0.2.4",
|
"diskusage": "0.2.5",
|
||||||
"dompurify": "1.0.5",
|
"dompurify": "1.0.5",
|
||||||
"double-ended-queue": "2.1.0-0",
|
"double-ended-queue": "2.1.0-0",
|
||||||
"elasticsearch": "15.1.1",
|
"elasticsearch": "15.1.1",
|
||||||
@ -108,12 +109,12 @@
|
|||||||
"eslint-plugin-vue": "4.7.1",
|
"eslint-plugin-vue": "4.7.1",
|
||||||
"eventemitter3": "3.1.0",
|
"eventemitter3": "3.1.0",
|
||||||
"exif-js": "2.3.0",
|
"exif-js": "2.3.0",
|
||||||
"file-loader": "1.1.11",
|
"file-loader": "2.0.0",
|
||||||
"file-type": "9.0.0",
|
"file-type": "10.0.0",
|
||||||
"fuckadblock": "3.2.1",
|
"fuckadblock": "3.2.1",
|
||||||
"gulp": "3.9.1",
|
"gulp": "3.9.1",
|
||||||
"gulp-cssnano": "2.1.3",
|
"gulp-cssnano": "2.1.3",
|
||||||
"gulp-htmlmin": "4.0.0",
|
"gulp-htmlmin": "5.0.1",
|
||||||
"gulp-imagemin": "4.1.0",
|
"gulp-imagemin": "4.1.0",
|
||||||
"gulp-mocha": "6.0.0",
|
"gulp-mocha": "6.0.0",
|
||||||
"gulp-pug": "4.0.1",
|
"gulp-pug": "4.0.1",
|
||||||
@ -133,7 +134,7 @@
|
|||||||
"is-root": "2.0.0",
|
"is-root": "2.0.0",
|
||||||
"is-url": "1.2.4",
|
"is-url": "1.2.4",
|
||||||
"js-yaml": "3.12.0",
|
"js-yaml": "3.12.0",
|
||||||
"jsdom": "11.12.0",
|
"jsdom": "12.2.0",
|
||||||
"json5": "2.1.0",
|
"json5": "2.1.0",
|
||||||
"json5-loader": "1.0.1",
|
"json5-loader": "1.0.1",
|
||||||
"koa": "2.5.1",
|
"koa": "2.5.1",
|
||||||
@ -142,7 +143,7 @@
|
|||||||
"koa-favicon": "2.0.1",
|
"koa-favicon": "2.0.1",
|
||||||
"koa-json-body": "5.3.0",
|
"koa-json-body": "5.3.0",
|
||||||
"koa-logger": "3.2.0",
|
"koa-logger": "3.2.0",
|
||||||
"koa-mount": "3.0.0",
|
"koa-mount": "4.0.0",
|
||||||
"koa-multer": "1.0.2",
|
"koa-multer": "1.0.2",
|
||||||
"koa-router": "7.4.0",
|
"koa-router": "7.4.0",
|
||||||
"koa-send": "5.0.0",
|
"koa-send": "5.0.0",
|
||||||
@ -159,7 +160,7 @@
|
|||||||
"mongodb": "3.1.1",
|
"mongodb": "3.1.1",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.11.0",
|
"nan": "2.11.1",
|
||||||
"nested-property": "0.0.7",
|
"nested-property": "0.0.7",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"object-assign-deep": "0.4.0",
|
"object-assign-deep": "0.4.0",
|
||||||
@ -171,10 +172,10 @@
|
|||||||
"promise-sequential": "1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
"pug": "2.0.3",
|
"pug": "2.0.3",
|
||||||
"punycode": "2.1.1",
|
"punycode": "2.1.1",
|
||||||
"qrcode": "1.2.2",
|
"qrcode": "1.3.0",
|
||||||
"ratelimiter": "3.2.0",
|
"ratelimiter": "3.2.0",
|
||||||
"recaptcha-promise": "0.1.3",
|
"recaptcha-promise": "0.1.3",
|
||||||
"reconnecting-websocket": "3.2.2",
|
"reconnecting-websocket": "4.1.5",
|
||||||
"redis": "2.8.0",
|
"redis": "2.8.0",
|
||||||
"request": "2.88.0",
|
"request": "2.88.0",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
@ -184,7 +185,7 @@
|
|||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass-loader": "7.1.0",
|
"sass-loader": "7.1.0",
|
||||||
"seedrandom": "2.4.4",
|
"seedrandom": "2.4.4",
|
||||||
"sharp": "0.20.7",
|
"sharp": "0.21.0",
|
||||||
"showdown": "1.8.6",
|
"showdown": "1.8.6",
|
||||||
"showdown-highlightjs-extension": "0.1.2",
|
"showdown-highlightjs-extension": "0.1.2",
|
||||||
"single-line-log": "1.1.2",
|
"single-line-log": "1.1.2",
|
||||||
@ -194,7 +195,7 @@
|
|||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
"stylus-loader": "3.0.2",
|
"stylus-loader": "3.0.2",
|
||||||
"summaly": "2.2.0",
|
"summaly": "2.2.0",
|
||||||
"systeminformation": "3.45.6",
|
"systeminformation": "3.45.7",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"tinycolor2": "1.4.1",
|
"tinycolor2": "1.4.1",
|
||||||
@ -203,7 +204,7 @@
|
|||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.10.0",
|
"tslint": "5.10.0",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"typescript-eslint-parser": "18.0.0",
|
"typescript-eslint-parser": "19.0.2",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
@ -217,7 +218,7 @@
|
|||||||
"vue-loader": "15.4.2",
|
"vue-loader": "15.4.2",
|
||||||
"vue-router": "3.0.1",
|
"vue-router": "3.0.1",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader": "1.1.3",
|
"vue-svg-inline-loader": "1.2.0",
|
||||||
"vue-template-compiler": "2.5.17",
|
"vue-template-compiler": "2.5.17",
|
||||||
"vuedraggable": "2.16.0",
|
"vuedraggable": "2.16.0",
|
||||||
"vuewordcloud": "18.7.11",
|
"vuewordcloud": "18.7.11",
|
||||||
@ -225,10 +226,10 @@
|
|||||||
"vuex-persistedstate": "2.5.4",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"web-push": "3.3.3",
|
"web-push": "3.3.3",
|
||||||
"webfinger.js": "2.6.6",
|
"webfinger.js": "2.6.6",
|
||||||
"webpack": "4.19.1",
|
"webpack": "4.20.2",
|
||||||
"webpack-cli": "3.1.0",
|
"webpack-cli": "3.1.2",
|
||||||
"websocket": "1.0.28",
|
"websocket": "1.0.28",
|
||||||
"ws": "6.0.0",
|
"ws": "6.1.0",
|
||||||
"xev": "2.0.1"
|
"xev": "2.0.1"
|
||||||
},
|
},
|
||||||
"greenkeeper": {
|
"greenkeeper": {
|
||||||
|
@ -13,21 +13,21 @@ type Notification = {
|
|||||||
|
|
||||||
export default function(type, data): Notification {
|
export default function(type, data): Notification {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'drive_file_created':
|
case 'driveFileCreated':
|
||||||
return {
|
return {
|
||||||
title: '%i18n:common.notification.file-uploaded%',
|
title: '%i18n:common.notification.file-uploaded%',
|
||||||
body: data.name,
|
body: data.name,
|
||||||
icon: data.url
|
icon: data.url
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'unread_messaging_message':
|
case 'unreadMessagingMessage':
|
||||||
return {
|
return {
|
||||||
title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] ,
|
title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] ,
|
||||||
body: data.text, // TODO: getMessagingMessageSummary(data),
|
body: data.text, // TODO: getMessagingMessageSummary(data),
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'reversi_invited':
|
case 'reversiInvited':
|
||||||
return {
|
return {
|
||||||
title: '%i18n:common.notification.reversi-invited%',
|
title: '%i18n:common.notification.reversi-invited%',
|
||||||
body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1],
|
body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1],
|
||||||
|
8
src/client/app/common/scripts/get-md5.ts
Normal file
8
src/client/app/common/scripts/get-md5.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
export default (data: ArrayBuffer) => {
|
||||||
|
const buf = new Buffer(data);
|
||||||
|
const hash = crypto.createHash("md5");
|
||||||
|
hash.update(buf);
|
||||||
|
return hash.digest("hex");
|
||||||
|
};
|
116
src/client/app/common/scripts/note-subscriber.ts
Normal file
116
src/client/app/common/scripts/note-subscriber.ts
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default prop => ({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
connection: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
$_ns_note_(): any {
|
||||||
|
return this[prop];
|
||||||
|
},
|
||||||
|
|
||||||
|
$_ns_isRenote(): boolean {
|
||||||
|
return (this.$_ns_note_.renote &&
|
||||||
|
this.$_ns_note_.text == null &&
|
||||||
|
this.$_ns_note_.fileIds.length == 0 &&
|
||||||
|
this.$_ns_note_.poll == null);
|
||||||
|
},
|
||||||
|
|
||||||
|
$_ns_target(): any {
|
||||||
|
return this._ns_isRenote ? this.$_ns_note_.renote : this.$_ns_note_;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection = (this as any).os.stream;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.capture(true);
|
||||||
|
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection.on('_connected_', this.onStreamConnected);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.decapture(true);
|
||||||
|
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection.off('_connected_', this.onStreamConnected);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
capture(withHandler = false) {
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
const data = {
|
||||||
|
id: this.$_ns_target.id
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(this.$_ns_target.visibleUserIds || []).includes(this.$store.state.i.id) ||
|
||||||
|
(this.$_ns_target.mentions || []).includes(this.$store.state.i.id)
|
||||||
|
) {
|
||||||
|
data.read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connection.send('sn', data);
|
||||||
|
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
decapture(withHandler = false) {
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection.send('un', {
|
||||||
|
id: this.$_ns_target.id
|
||||||
|
});
|
||||||
|
if (withHandler) this.connection.off('noteUpdated', this.onStreamNoteUpdated);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onStreamConnected() {
|
||||||
|
this.capture();
|
||||||
|
},
|
||||||
|
|
||||||
|
onStreamNoteUpdated(data) {
|
||||||
|
const { type, id, body } = data;
|
||||||
|
|
||||||
|
if (id !== this.$_ns_target.id) return;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'reacted': {
|
||||||
|
const reaction = body.reaction;
|
||||||
|
if (this.$_ns_target.reactionCounts == null) Vue.set(this.$_ns_target, 'reactionCounts', {});
|
||||||
|
this.$_ns_target.reactionCounts[reaction] = (this.$_ns_target.reactionCounts[reaction] || 0) + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'pollVoted': {
|
||||||
|
if (body.userId == this.$store.state.i.id) return;
|
||||||
|
const choice = body.choice;
|
||||||
|
this.$_ns_target.poll.choices.find(c => c.id === choice).votes++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'deleted': {
|
||||||
|
Vue.set(this.$_ns_target, 'deletedAt', body.deletedAt);
|
||||||
|
this.$_ns_target.text = null;
|
||||||
|
this.$_ns_target.tags = [];
|
||||||
|
this.$_ns_target.fileIds = [];
|
||||||
|
this.$_ns_target.poll = null;
|
||||||
|
this.$_ns_target.geo = null;
|
||||||
|
this.$_ns_target.cw = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit(`update:${prop}`, this.$_ns_note_);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
318
src/client/app/common/scripts/stream.ts
Normal file
318
src/client/app/common/scripts/stream.ts
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
import autobind from 'autobind-decorator';
|
||||||
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import ReconnectingWebsocket from 'reconnecting-websocket';
|
||||||
|
import { wsUrl } from '../../config';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Misskey stream connection
|
||||||
|
*/
|
||||||
|
export default class Stream extends EventEmitter {
|
||||||
|
private stream: ReconnectingWebsocket;
|
||||||
|
private state: string;
|
||||||
|
private buffer: any[];
|
||||||
|
private sharedConnections: SharedConnection[] = [];
|
||||||
|
private nonSharedConnections: NonSharedConnection[] = [];
|
||||||
|
|
||||||
|
constructor(os: MiOS) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = 'initializing';
|
||||||
|
this.buffer = [];
|
||||||
|
|
||||||
|
const user = os.store.state.i;
|
||||||
|
|
||||||
|
this.stream = new ReconnectingWebsocket(wsUrl + (user ? `?i=${user.token}` : ''));
|
||||||
|
this.stream.addEventListener('open', this.onOpen);
|
||||||
|
this.stream.addEventListener('close', this.onClose);
|
||||||
|
this.stream.addEventListener('message', this.onMessage);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
const main = this.useSharedConnection('main');
|
||||||
|
|
||||||
|
// 自分の情報が更新されたとき
|
||||||
|
main.on('meUpdated', i => {
|
||||||
|
os.store.dispatch('mergeMe', i);
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllNotifications', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadNotification: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadNotification', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadNotification: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllMessagingMessages', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMessagingMessage: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadMessagingMessage', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMessagingMessage: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadMention', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMentions: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllUnreadMentions', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMentions: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadSpecifiedNote', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadSpecifiedNotes: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllUnreadSpecifiedNotes', () => {
|
||||||
|
os.store.dispatch('mergeMe', {
|
||||||
|
hasUnreadSpecifiedNotes: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('clientSettingUpdated', x => {
|
||||||
|
os.store.commit('settings/set', {
|
||||||
|
key: x.key,
|
||||||
|
value: x.value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('homeUpdated', x => {
|
||||||
|
os.store.commit('settings/setHome', x);
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('mobileHomeUpdated', x => {
|
||||||
|
os.store.commit('settings/setMobileHome', x);
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('widgetUpdated', x => {
|
||||||
|
os.store.commit('settings/setWidget', {
|
||||||
|
id: x.id,
|
||||||
|
data: x.data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// トークンが再生成されたとき
|
||||||
|
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
||||||
|
main.on('myTokenRegenerated', () => {
|
||||||
|
alert('%i18n:common.my-token-regenerated%');
|
||||||
|
os.signout();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public useSharedConnection = (channel: string): SharedConnection => {
|
||||||
|
const existConnection = this.sharedConnections.find(c => c.channel === channel);
|
||||||
|
|
||||||
|
if (existConnection) {
|
||||||
|
existConnection.use();
|
||||||
|
return existConnection;
|
||||||
|
} else {
|
||||||
|
const connection = new SharedConnection(this, channel);
|
||||||
|
connection.use();
|
||||||
|
this.sharedConnections.push(connection);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public removeSharedConnection(connection: SharedConnection) {
|
||||||
|
this.sharedConnections = this.sharedConnections.filter(c => c.id !== connection.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public connectToChannel = (channel: string, params?: any): NonSharedConnection => {
|
||||||
|
const connection = new NonSharedConnection(this, channel, params);
|
||||||
|
this.nonSharedConnections.push(connection);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public disconnectToChannel(connection: NonSharedConnection) {
|
||||||
|
this.nonSharedConnections = this.nonSharedConnections.filter(c => c.id !== connection.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback of when open connection
|
||||||
|
*/
|
||||||
|
@autobind
|
||||||
|
private onOpen() {
|
||||||
|
const isReconnect = this.state == 'reconnecting';
|
||||||
|
|
||||||
|
this.state = 'connected';
|
||||||
|
this.emit('_connected_');
|
||||||
|
|
||||||
|
// バッファーを処理
|
||||||
|
const _buffer = [].concat(this.buffer); // Shallow copy
|
||||||
|
this.buffer = []; // Clear buffer
|
||||||
|
_buffer.forEach(data => {
|
||||||
|
this.send(data); // Resend each buffered messages
|
||||||
|
});
|
||||||
|
|
||||||
|
// チャンネル再接続
|
||||||
|
if (isReconnect) {
|
||||||
|
this.sharedConnections.forEach(c => {
|
||||||
|
c.connect();
|
||||||
|
});
|
||||||
|
this.nonSharedConnections.forEach(c => {
|
||||||
|
c.connect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback of when close connection
|
||||||
|
*/
|
||||||
|
@autobind
|
||||||
|
private onClose() {
|
||||||
|
this.state = 'reconnecting';
|
||||||
|
this.emit('_disconnected_');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback of when received a message from connection
|
||||||
|
*/
|
||||||
|
@autobind
|
||||||
|
private onMessage(message) {
|
||||||
|
const { type, body } = JSON.parse(message.data);
|
||||||
|
|
||||||
|
if (type == 'channel') {
|
||||||
|
const id = body.id;
|
||||||
|
const connection = this.sharedConnections.find(c => c.id === id) || this.nonSharedConnections.find(c => c.id === id);
|
||||||
|
connection.emit(body.type, body.body);
|
||||||
|
} else {
|
||||||
|
this.emit(type, body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to connection
|
||||||
|
*/
|
||||||
|
@autobind
|
||||||
|
public send(typeOrPayload, payload?) {
|
||||||
|
const data = payload === undefined ? typeOrPayload : {
|
||||||
|
type: typeOrPayload,
|
||||||
|
body: payload
|
||||||
|
};
|
||||||
|
|
||||||
|
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
|
||||||
|
if (this.state != 'connected') {
|
||||||
|
this.buffer.push(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stream.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close this connection
|
||||||
|
*/
|
||||||
|
@autobind
|
||||||
|
public close() {
|
||||||
|
this.stream.removeEventListener('open', this.onOpen);
|
||||||
|
this.stream.removeEventListener('message', this.onMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Connection extends EventEmitter {
|
||||||
|
public channel: string;
|
||||||
|
public id: string;
|
||||||
|
protected params: any;
|
||||||
|
protected stream: Stream;
|
||||||
|
|
||||||
|
constructor(stream: Stream, channel: string, params?: any) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.stream = stream;
|
||||||
|
this.channel = channel;
|
||||||
|
this.params = params;
|
||||||
|
this.id = Math.random().toString();
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public connect() {
|
||||||
|
this.stream.send('connect', {
|
||||||
|
channel: this.channel,
|
||||||
|
id: this.id,
|
||||||
|
params: this.params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public send(typeOrPayload, payload?) {
|
||||||
|
const data = payload === undefined ? typeOrPayload : {
|
||||||
|
type: typeOrPayload,
|
||||||
|
body: payload
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stream.send('channel', {
|
||||||
|
id: this.id,
|
||||||
|
body: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract dispose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SharedConnection extends Connection {
|
||||||
|
private users = 0;
|
||||||
|
private disposeTimerId: any;
|
||||||
|
|
||||||
|
constructor(stream: Stream, channel: string) {
|
||||||
|
super(stream, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public use() {
|
||||||
|
this.users++;
|
||||||
|
|
||||||
|
// タイマー解除
|
||||||
|
if (this.disposeTimerId) {
|
||||||
|
clearTimeout(this.disposeTimerId);
|
||||||
|
this.disposeTimerId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public dispose() {
|
||||||
|
this.users--;
|
||||||
|
|
||||||
|
// そのコネクションの利用者が誰もいなくなったら
|
||||||
|
if (this.users === 0) {
|
||||||
|
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
||||||
|
// 新たな利用者が現れなければコネクションを切断する
|
||||||
|
this.disposeTimerId = setTimeout(() => {
|
||||||
|
this.disposeTimerId = null;
|
||||||
|
this.removeAllListeners();
|
||||||
|
this.stream.send('disconnect', { id: this.id });
|
||||||
|
this.stream.removeSharedConnection(this);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NonSharedConnection extends Connection {
|
||||||
|
constructor(stream: Stream, channel: string, params?: any) {
|
||||||
|
super(stream, channel, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public dispose() {
|
||||||
|
this.removeAllListeners();
|
||||||
|
this.stream.send('disconnect', { id: this.id });
|
||||||
|
this.stream.disconnectToChannel(this);
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drive stream connection
|
|
||||||
*/
|
|
||||||
export class DriveStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'drive', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DriveStreamManager extends StreamManager<DriveStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new DriveStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import Stream from '../../stream';
|
|
||||||
import MiOS from '../../../../../mios';
|
|
||||||
|
|
||||||
export class ReversiGameStream extends Stream {
|
|
||||||
constructor(os: MiOS, me, game) {
|
|
||||||
super(os, 'games/reversi-game', me ? {
|
|
||||||
i: me.token,
|
|
||||||
game: game.id
|
|
||||||
} : {
|
|
||||||
game: game.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
import StreamManager from '../../stream-manager';
|
|
||||||
import Stream from '../../stream';
|
|
||||||
import MiOS from '../../../../../mios';
|
|
||||||
|
|
||||||
export class ReversiStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'games/reversi', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ReversiStreamManager extends StreamManager<ReversiStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new ReversiStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global timeline stream connection
|
|
||||||
*/
|
|
||||||
export class GlobalTimelineStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'global-timeline', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GlobalTimelineStreamManager extends StreamManager<GlobalTimelineStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new GlobalTimelineStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
export class HashtagStream extends Stream {
|
|
||||||
constructor(os: MiOS, me, q) {
|
|
||||||
super(os, 'hashtag', me ? {
|
|
||||||
i: me.token,
|
|
||||||
q: JSON.stringify(q)
|
|
||||||
} : {
|
|
||||||
q: JSON.stringify(q)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Home stream connection
|
|
||||||
*/
|
|
||||||
export class HomeStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, '', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
|
|
||||||
// 最終利用日時を更新するため定期的にaliveメッセージを送信
|
|
||||||
setInterval(() => {
|
|
||||||
this.send({ type: 'alive' });
|
|
||||||
me.lastUsedAt = new Date();
|
|
||||||
}, 1000 * 60);
|
|
||||||
|
|
||||||
// 自分の情報が更新されたとき
|
|
||||||
this.on('meUpdated', i => {
|
|
||||||
if (os.debug) {
|
|
||||||
console.log('I updated:', i);
|
|
||||||
}
|
|
||||||
|
|
||||||
os.store.dispatch('mergeMe', i);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('read_all_notifications', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadNotification: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('unread_notification', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadNotification: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('read_all_messaging_messages', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMessagingMessage: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('unread_messaging_message', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMessagingMessage: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('unreadMention', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMentions: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('readAllUnreadMentions', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMentions: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('unreadSpecifiedNote', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadSpecifiedNotes: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('readAllUnreadSpecifiedNotes', () => {
|
|
||||||
os.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadSpecifiedNotes: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('clientSettingUpdated', x => {
|
|
||||||
os.store.commit('settings/set', {
|
|
||||||
key: x.key,
|
|
||||||
value: x.value
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('home_updated', x => {
|
|
||||||
os.store.commit('settings/setHome', x);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('mobile_home_updated', x => {
|
|
||||||
os.store.commit('settings/setMobileHome', x);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('widgetUpdated', x => {
|
|
||||||
os.store.commit('settings/setWidget', {
|
|
||||||
id: x.id,
|
|
||||||
data: x.data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// トークンが再生成されたとき
|
|
||||||
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
|
||||||
this.on('my_token_regenerated', () => {
|
|
||||||
alert('%i18n:common.my-token-regenerated%');
|
|
||||||
os.signout();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HomeStreamManager extends StreamManager<HomeStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new HomeStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hybrid timeline stream connection
|
|
||||||
*/
|
|
||||||
export class HybridTimelineStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'hybrid-timeline', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HybridTimelineStreamManager extends StreamManager<HybridTimelineStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new HybridTimelineStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local timeline stream connection
|
|
||||||
*/
|
|
||||||
export class LocalTimelineStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'local-timeline', me ? {
|
|
||||||
i: me.token
|
|
||||||
} : {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LocalTimelineStreamManager extends StreamManager<LocalTimelineStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new LocalTimelineStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Messaging index stream connection
|
|
||||||
*/
|
|
||||||
export class MessagingIndexStream extends Stream {
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super(os, 'messaging-index', {
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MessagingIndexStreamManager extends StreamManager<MessagingIndexStream> {
|
|
||||||
private me;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, me) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.me = me;
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new MessagingIndexStream(this.os, this.me);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Messaging stream connection
|
|
||||||
*/
|
|
||||||
export class MessagingStream extends Stream {
|
|
||||||
constructor(os: MiOS, me, otherparty) {
|
|
||||||
super(os, 'messaging', {
|
|
||||||
i: me.token,
|
|
||||||
otherparty
|
|
||||||
});
|
|
||||||
|
|
||||||
(this as any).on('_connected_', () => {
|
|
||||||
this.send({
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notes stats stream connection
|
|
||||||
*/
|
|
||||||
export class NotesStatsStream extends Stream {
|
|
||||||
constructor(os: MiOS) {
|
|
||||||
super(os, 'notes-stats');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotesStatsStreamManager extends StreamManager<NotesStatsStream> {
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new NotesStatsStream(this.os);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import StreamManager from './stream-manager';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server stats stream connection
|
|
||||||
*/
|
|
||||||
export class ServerStatsStream extends Stream {
|
|
||||||
constructor(os: MiOS) {
|
|
||||||
super(os, 'server-stats');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ServerStatsStreamManager extends StreamManager<ServerStatsStream> {
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConnection() {
|
|
||||||
if (this.connection == null) {
|
|
||||||
this.connection = new ServerStatsStream(this.os);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
import * as uuid from 'uuid';
|
|
||||||
import Connection from './stream';
|
|
||||||
import { erase } from '../../../../../prelude/array';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ストリーム接続を管理するクラス
|
|
||||||
* 複数の場所から同じストリームを利用する際、接続をまとめたりする
|
|
||||||
*/
|
|
||||||
export default abstract class StreamManager<T extends Connection> extends EventEmitter {
|
|
||||||
private _connection: T = null;
|
|
||||||
|
|
||||||
private disposeTimerId: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コネクションを必要としているユーザー
|
|
||||||
*/
|
|
||||||
private users = [];
|
|
||||||
|
|
||||||
protected set connection(connection: T) {
|
|
||||||
this._connection = connection;
|
|
||||||
|
|
||||||
if (this._connection == null) {
|
|
||||||
this.emit('disconnected');
|
|
||||||
} else {
|
|
||||||
this.emit('connected', this._connection);
|
|
||||||
|
|
||||||
this._connection.on('_connected_', () => {
|
|
||||||
this.emit('_connected_');
|
|
||||||
});
|
|
||||||
|
|
||||||
this._connection.on('_disconnected_', () => {
|
|
||||||
this.emit('_disconnected_');
|
|
||||||
});
|
|
||||||
|
|
||||||
this._connection.user = 'Managed';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get connection() {
|
|
||||||
return this._connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コネクションを持っているか否か
|
|
||||||
*/
|
|
||||||
public get hasConnection() {
|
|
||||||
return this._connection != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get state(): string {
|
|
||||||
if (!this.hasConnection) return 'no-connection';
|
|
||||||
return this._connection.state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コネクションを要求します
|
|
||||||
*/
|
|
||||||
public abstract getConnection(): T;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 現在接続しているコネクションを取得します
|
|
||||||
*/
|
|
||||||
public borrow() {
|
|
||||||
return this._connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コネクションを要求するためのユーザーIDを発行します
|
|
||||||
*/
|
|
||||||
public use() {
|
|
||||||
// タイマー解除
|
|
||||||
if (this.disposeTimerId) {
|
|
||||||
clearTimeout(this.disposeTimerId);
|
|
||||||
this.disposeTimerId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ユーザーID生成
|
|
||||||
const userId = uuid();
|
|
||||||
|
|
||||||
this.users.push(userId);
|
|
||||||
|
|
||||||
this._connection.user = `Managed (${ this.users.length })`;
|
|
||||||
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* コネクションを利用し終わってもう必要ないことを通知します
|
|
||||||
* @param userId use で発行したユーザーID
|
|
||||||
*/
|
|
||||||
public dispose(userId) {
|
|
||||||
this.users = erase(userId, this.users);
|
|
||||||
|
|
||||||
this._connection.user = `Managed (${ this.users.length })`;
|
|
||||||
|
|
||||||
// 誰もコネクションの利用者がいなくなったら
|
|
||||||
if (this.users.length == 0) {
|
|
||||||
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
|
||||||
// 新たな利用者が現れなければコネクションを切断する
|
|
||||||
this.disposeTimerId = setTimeout(() => {
|
|
||||||
this.disposeTimerId = null;
|
|
||||||
|
|
||||||
this.connection.close();
|
|
||||||
this.connection = null;
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
import * as uuid from 'uuid';
|
|
||||||
import * as ReconnectingWebsocket from 'reconnecting-websocket';
|
|
||||||
import { wsUrl } from '../../../config';
|
|
||||||
import MiOS from '../../../mios';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Misskey stream connection
|
|
||||||
*/
|
|
||||||
export default class Connection extends EventEmitter {
|
|
||||||
public state: string;
|
|
||||||
private buffer: any[];
|
|
||||||
public socket: ReconnectingWebsocket;
|
|
||||||
public name: string;
|
|
||||||
public connectedAt: Date;
|
|
||||||
public user: string = null;
|
|
||||||
public in: number = 0;
|
|
||||||
public out: number = 0;
|
|
||||||
public inout: Array<{
|
|
||||||
type: 'in' | 'out',
|
|
||||||
at: Date,
|
|
||||||
data: string
|
|
||||||
}> = [];
|
|
||||||
public id: string;
|
|
||||||
public isSuspended = false;
|
|
||||||
private os: MiOS;
|
|
||||||
|
|
||||||
constructor(os: MiOS, endpoint, params?) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
//#region BIND
|
|
||||||
this.onOpen = this.onOpen.bind(this);
|
|
||||||
this.onClose = this.onClose.bind(this);
|
|
||||||
this.onMessage = this.onMessage.bind(this);
|
|
||||||
this.send = this.send.bind(this);
|
|
||||||
this.close = this.close.bind(this);
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
this.id = uuid();
|
|
||||||
this.os = os;
|
|
||||||
this.name = endpoint;
|
|
||||||
this.state = 'initializing';
|
|
||||||
this.buffer = [];
|
|
||||||
|
|
||||||
const query = params
|
|
||||||
? Object.keys(params)
|
|
||||||
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
|
|
||||||
.join('&')
|
|
||||||
: null;
|
|
||||||
|
|
||||||
this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? `?${query}` : ''}`);
|
|
||||||
this.socket.addEventListener('open', this.onOpen);
|
|
||||||
this.socket.addEventListener('close', this.onClose);
|
|
||||||
this.socket.addEventListener('message', this.onMessage);
|
|
||||||
|
|
||||||
// Register this connection for debugging
|
|
||||||
this.os.registerStreamConnection(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback of when open connection
|
|
||||||
*/
|
|
||||||
private onOpen() {
|
|
||||||
this.state = 'connected';
|
|
||||||
this.emit('_connected_');
|
|
||||||
|
|
||||||
this.connectedAt = new Date();
|
|
||||||
|
|
||||||
// バッファーを処理
|
|
||||||
const _buffer = [].concat(this.buffer); // Shallow copy
|
|
||||||
this.buffer = []; // Clear buffer
|
|
||||||
_buffer.forEach(data => {
|
|
||||||
this.send(data); // Resend each buffered messages
|
|
||||||
|
|
||||||
if (this.os.debug) {
|
|
||||||
this.out++;
|
|
||||||
this.inout.push({ type: 'out', at: new Date(), data });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback of when close connection
|
|
||||||
*/
|
|
||||||
private onClose() {
|
|
||||||
this.state = 'reconnecting';
|
|
||||||
this.emit('_disconnected_');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback of when received a message from connection
|
|
||||||
*/
|
|
||||||
private onMessage(message) {
|
|
||||||
if (this.isSuspended) return;
|
|
||||||
|
|
||||||
if (this.os.debug) {
|
|
||||||
this.in++;
|
|
||||||
this.inout.push({ type: 'in', at: new Date(), data: message.data });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const msg = JSON.parse(message.data);
|
|
||||||
if (msg.type) this.emit(msg.type, msg.body);
|
|
||||||
} catch (e) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message to connection
|
|
||||||
*/
|
|
||||||
public send(data) {
|
|
||||||
if (this.isSuspended) return;
|
|
||||||
|
|
||||||
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
|
|
||||||
if (this.state != 'connected') {
|
|
||||||
this.buffer.push(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.os.debug) {
|
|
||||||
this.out++;
|
|
||||||
this.inout.push({ type: 'out', at: new Date(), data });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.socket.send(JSON.stringify(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close this connection
|
|
||||||
*/
|
|
||||||
public close() {
|
|
||||||
this.os.unregisterStreamConnection(this);
|
|
||||||
this.socket.removeEventListener('open', this.onOpen);
|
|
||||||
this.socket.removeEventListener('message', this.onMessage);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import Stream from './stream';
|
|
||||||
import MiOS from '../../mios';
|
|
||||||
|
|
||||||
export class UserListStream extends Stream {
|
|
||||||
constructor(os: MiOS, me, listId) {
|
|
||||||
super(os, 'user-list', {
|
|
||||||
i: me.token,
|
|
||||||
listId
|
|
||||||
});
|
|
||||||
|
|
||||||
(this as any).on('_connected_', () => {
|
|
||||||
this.send({
|
|
||||||
i: me.token
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,6 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XGame from './reversi.game.vue';
|
import XGame from './reversi.game.vue';
|
||||||
import XRoom from './reversi.room.vue';
|
import XRoom from './reversi.room.vue';
|
||||||
import { ReversiGameStream } from '../../../../scripts/streaming/games/reversi/reversi-game';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
@ -34,12 +33,13 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.g = this.game;
|
this.g = this.game;
|
||||||
this.connection = new ReversiGameStream((this as any).os, this.$store.state.i, this.game);
|
this.connection = (this as any).os.stream.connectToChannel('gamesReversiGame', {
|
||||||
|
gameId: this.game.id
|
||||||
|
});
|
||||||
this.connection.on('started', this.onStarted);
|
this.connection.on('started', this.onStarted);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('started', this.onStarted);
|
this.connection.dispose();
|
||||||
this.connection.close();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onStarted(game) {
|
onStarted(game) {
|
||||||
|
@ -59,15 +59,13 @@ export default Vue.extend({
|
|||||||
myGames: [],
|
myGames: [],
|
||||||
matching: null,
|
matching: null,
|
||||||
invitations: [],
|
invitations: [],
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.streams.reversiStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('gamesReversi');
|
||||||
this.connectionId = (this as any).os.streams.reversiStream.use();
|
|
||||||
|
|
||||||
this.connection.on('invited', this.onInvited);
|
this.connection.on('invited', this.onInvited);
|
||||||
|
|
||||||
@ -90,8 +88,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
this.connection.off('invited', this.onInvited);
|
this.connection.dispose();
|
||||||
(this as any).os.streams.reversiStream.dispose(this.connectionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ export default Vue.extend({
|
|||||||
game: null,
|
game: null,
|
||||||
matching: null,
|
matching: null,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
pingClock: null
|
pingClock: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -66,8 +65,7 @@ export default Vue.extend({
|
|||||||
this.fetch();
|
this.fetch();
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.streams.reversiStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('gamesReversi');
|
||||||
this.connectionId = (this as any).os.streams.reversiStream.use();
|
|
||||||
|
|
||||||
this.connection.on('matched', this.onMatched);
|
this.connection.on('matched', this.onMatched);
|
||||||
|
|
||||||
@ -84,9 +82,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
this.connection.off('matched', this.onMatched);
|
this.connection.dispose();
|
||||||
(this as any).os.streams.reversiStream.dispose(this.connectionId);
|
|
||||||
|
|
||||||
clearInterval(this.pingClock);
|
clearInterval(this.pingClock);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { MessagingStream } from '../../scripts/streaming/messaging';
|
|
||||||
import XMessage from './messaging-room.message.vue';
|
import XMessage from './messaging-room.message.vue';
|
||||||
import XForm from './messaging-room.form.vue';
|
import XForm from './messaging-room.form.vue';
|
||||||
import { url } from '../../../config';
|
import { url } from '../../../config';
|
||||||
@ -72,7 +71,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = new MessagingStream((this as any).os, this.$store.state.i, this.user.id);
|
this.connection =((this as any).os.stream.connectToChannel('messaging', { otherparty: this.user.id });
|
||||||
|
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
this.connection.on('read', this.onRead);
|
this.connection.on('read', this.onRead);
|
||||||
@ -92,9 +91,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('message', this.onMessage);
|
this.connection.dispose();
|
||||||
this.connection.off('read', this.onRead);
|
|
||||||
this.connection.close();
|
|
||||||
|
|
||||||
if (this.isNaked) {
|
if (this.isNaked) {
|
||||||
window.removeEventListener('scroll', this.onScroll);
|
window.removeEventListener('scroll', this.onScroll);
|
||||||
|
@ -71,13 +71,11 @@ export default Vue.extend({
|
|||||||
messages: [],
|
messages: [],
|
||||||
q: null,
|
q: null,
|
||||||
result: [],
|
result: [],
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.streams.messagingIndexStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('messagingIndex');
|
||||||
this.connectionId = (this as any).os.streams.messagingIndexStream.use();
|
|
||||||
|
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
this.connection.on('read', this.onRead);
|
this.connection.on('read', this.onRead);
|
||||||
@ -88,9 +86,7 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('message', this.onMessage);
|
this.connection.dispose();
|
||||||
this.connection.off('read', this.onRead);
|
|
||||||
(this as any).os.streams.messagingIndexStream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAcct,
|
getAcct,
|
||||||
|
@ -95,7 +95,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement(MkUrl, {
|
return [createElement(MkUrl, {
|
||||||
props: {
|
props: {
|
||||||
url: token.content,
|
url: token.content,
|
||||||
target: '_blank'
|
target: '_blank',
|
||||||
|
style: 'color:var(--mfmLink);'
|
||||||
}
|
}
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
@ -106,7 +107,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
class: 'link',
|
class: 'link',
|
||||||
href: token.url,
|
href: token.url,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
title: token.url
|
title: token.url,
|
||||||
|
style: 'color:var(--mfmLink);'
|
||||||
}
|
}
|
||||||
}, token.title)];
|
}, token.title)];
|
||||||
}
|
}
|
||||||
@ -116,7 +118,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
attrs: {
|
attrs: {
|
||||||
href: `${url}/@${getAcct(token)}`,
|
href: `${url}/@${getAcct(token)}`,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token)
|
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
|
||||||
|
style: 'color:var(--mfmMention);'
|
||||||
},
|
},
|
||||||
directives: [{
|
directives: [{
|
||||||
name: 'user-preview',
|
name: 'user-preview',
|
||||||
@ -129,7 +132,8 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
return [createElement('a', {
|
return [createElement('a', {
|
||||||
attrs: {
|
attrs: {
|
||||||
href: `${url}/tags/${encodeURIComponent(token.hashtag)}`,
|
href: `${url}/tags/${encodeURIComponent(token.hashtag)}`,
|
||||||
target: '_blank'
|
target: '_blank',
|
||||||
|
style: 'color:var(--mfmHashtag);'
|
||||||
}
|
}
|
||||||
}, token.content)];
|
}, token.content)];
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ export default Vue.extend({
|
|||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
||||||
}).then(() => {
|
}, true).then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
alert('%i18n:@login-failed%');
|
alert('%i18n:@login-failed%');
|
||||||
|
@ -131,11 +131,11 @@ export default Vue.extend({
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
invitationCode: this.invitationCode,
|
invitationCode: this.invitationCode,
|
||||||
'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null
|
'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null
|
||||||
}).then(() => {
|
}, true).then(() => {
|
||||||
(this as any).api('signin', {
|
(this as any).api('signin', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password
|
password: this.password
|
||||||
}).then(() => {
|
}, true).then(() => {
|
||||||
location.href = '/';
|
location.href = '/';
|
||||||
});
|
});
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -3,14 +3,24 @@
|
|||||||
<label>
|
<label>
|
||||||
<span>%i18n:@light-theme%</span>
|
<span>%i18n:@light-theme%</span>
|
||||||
<ui-select v-model="light" placeholder="%i18n:@light-theme%">
|
<ui-select v-model="light" placeholder="%i18n:@light-theme%">
|
||||||
<option v-for="x in themes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
<optgroup label="%i18n:@light-themes%">
|
||||||
|
<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="%i18n:@dark-themes%">
|
||||||
|
<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
||||||
|
</optgroup>
|
||||||
</ui-select>
|
</ui-select>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<span>%i18n:@dark-theme%</span>
|
<span>%i18n:@dark-theme%</span>
|
||||||
<ui-select v-model="dark" placeholder="%i18n:@dark-theme%">
|
<ui-select v-model="dark" placeholder="%i18n:@dark-theme%">
|
||||||
<option v-for="x in themes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
<optgroup label="%i18n:@dark-themes%">
|
||||||
|
<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="%i18n:@light-themes%">
|
||||||
|
<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
|
||||||
|
</optgroup>
|
||||||
</ui-select>
|
</ui-select>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@ -120,7 +130,15 @@ export default Vue.extend({
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
themes(): Theme[] {
|
themes(): Theme[] {
|
||||||
return this.$store.state.device.themes.concat(builtinThemes);
|
return builtinThemes.concat(this.$store.state.device.themes);
|
||||||
|
},
|
||||||
|
|
||||||
|
darkThemes(): Theme[] {
|
||||||
|
return this.themes.filter(t => t.base == 'dark' || t.kind == 'dark');
|
||||||
|
},
|
||||||
|
|
||||||
|
lightThemes(): Theme[] {
|
||||||
|
return this.themes.filter(t => t.base == 'light' || t.kind == 'light');
|
||||||
},
|
},
|
||||||
|
|
||||||
installedThemes(): Theme[] {
|
installedThemes(): Theme[] {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { apiUrl } from '../../../config';
|
import { apiUrl } from '../../../config';
|
||||||
|
import getMD5 from '../../scripts/get-md5';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
data() {
|
data() {
|
||||||
@ -28,27 +29,48 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
upload(file, folder) {
|
checkExistence(fileData: ArrayBuffer): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('md5', getMD5(fileData));
|
||||||
|
|
||||||
|
(this as any).api('drive/files/check_existence', {
|
||||||
|
md5: getMD5(fileData)
|
||||||
|
}).then(resp => {
|
||||||
|
resolve(resp.file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
upload(file: File, folder: any) {
|
||||||
if (folder && typeof folder == 'object') folder = folder.id;
|
if (folder && typeof folder == 'object') folder = folder.id;
|
||||||
|
|
||||||
const id = Math.random();
|
const id = Math.random();
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e: any) => {
|
||||||
|
this.checkExistence(e.target.result).then(result => {
|
||||||
|
if (result !== null) {
|
||||||
|
this.$emit('uploaded', result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload if the file didn't exist yet
|
||||||
|
const buf = new Uint8Array(e.target.result);
|
||||||
|
let bin = '';
|
||||||
|
// We use for-of loop instead of apply() to avoid RangeError
|
||||||
|
// SEE: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
|
||||||
|
for (const byte of buf) bin += String.fromCharCode(byte);
|
||||||
const ctx = {
|
const ctx = {
|
||||||
id: id,
|
id: id,
|
||||||
name: file.name || 'untitled',
|
name: file.name || 'untitled',
|
||||||
progress: undefined,
|
progress: undefined,
|
||||||
img: undefined
|
img: 'data:*/*;base64,' + btoa(bin)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.uploads.push(ctx);
|
this.uploads.push(ctx);
|
||||||
this.$emit('change', this.uploads);
|
this.$emit('change', this.uploads);
|
||||||
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (e: any) => {
|
|
||||||
ctx.img = e.target.result;
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
|
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('i', this.$store.state.i.token);
|
data.append('i', this.$store.state.i.token);
|
||||||
data.append('file', file);
|
data.append('file', file);
|
||||||
@ -75,14 +97,15 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(data);
|
xhr.send(data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.mk-uploader
|
.mk-uploader
|
||||||
overflow auto
|
overflow auto
|
||||||
|
|
||||||
|
@ -38,23 +38,20 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
fetching: true,
|
fetching: true,
|
||||||
notes: [],
|
notes: [],
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
|
|
||||||
this.connection = (this as any).os.streams.localTimelineStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
|
||||||
this.connectionId = (this as any).os.streams.localTimelineStream.use();
|
|
||||||
|
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('note', this.onNote);
|
this.connection.dispose();
|
||||||
(this as any).os.streams.localTimelineStream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -24,15 +24,13 @@ export default define({
|
|||||||
return {
|
return {
|
||||||
images: [],
|
images: [],
|
||||||
fetching: true,
|
fetching: true,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('drive_file_created', this.onDriveFileCreated);
|
this.connection.on('driveFileCreated', this.onDriveFileCreated);
|
||||||
|
|
||||||
(this as any).api('drive/stream', {
|
(this as any).api('drive/stream', {
|
||||||
type: 'image/*',
|
type: 'image/*',
|
||||||
@ -43,8 +41,7 @@ export default define({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('drive_file_created', this.onDriveFileCreated);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onDriveFileCreated(file) {
|
onDriveFileCreated(file) {
|
||||||
|
@ -82,7 +82,6 @@ export default define({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
viewBoxY: 30,
|
viewBoxY: 30,
|
||||||
stats: [],
|
stats: [],
|
||||||
fediGradientId: uuid(),
|
fediGradientId: uuid(),
|
||||||
@ -110,8 +109,7 @@ export default define({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.streams.notesStatsStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('notesStats');
|
||||||
this.connectionId = (this as any).os.streams.notesStatsStream.use();
|
|
||||||
|
|
||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
this.connection.on('statsLog', this.onStatsLog);
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
@ -121,9 +119,7 @@ export default define({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('stats', this.onStats);
|
this.connection.dispose();
|
||||||
this.connection.off('statsLog', this.onStatsLog);
|
|
||||||
(this as any).os.streams.notesStatsStream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggle() {
|
toggle() {
|
||||||
|
@ -45,8 +45,7 @@ export default define({
|
|||||||
return {
|
return {
|
||||||
fetching: true,
|
fetching: true,
|
||||||
meta: null,
|
meta: null,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -55,11 +54,10 @@ export default define({
|
|||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection = (this as any).os.streams.serverStatsStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
|
||||||
this.connectionId = (this as any).os.streams.serverStatsStream.use();
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
(this as any).os.streams.serverStatsStream.dispose(this.connectionId);
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggle() {
|
toggle() {
|
||||||
|
@ -12,7 +12,7 @@ export const host = address.host;
|
|||||||
export const hostname = address.hostname;
|
export const hostname = address.hostname;
|
||||||
export const url = address.origin;
|
export const url = address.origin;
|
||||||
export const apiUrl = url + '/api';
|
export const apiUrl = url + '/api';
|
||||||
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://');
|
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
||||||
export const lang = _LANG_;
|
export const lang = _LANG_;
|
||||||
export const langs = _LANGS_;
|
export const langs = _LANGS_;
|
||||||
export const themeColor = _THEME_COLOR_;
|
export const themeColor = _THEME_COLOR_;
|
||||||
|
@ -9,7 +9,6 @@ import './style.styl';
|
|||||||
|
|
||||||
import init from '../init';
|
import init from '../init';
|
||||||
import fuckAdBlock from '../common/scripts/fuck-ad-block';
|
import fuckAdBlock from '../common/scripts/fuck-ad-block';
|
||||||
import { HomeStreamManager } from '../common/scripts/streaming/home';
|
|
||||||
import composeNotification from '../common/scripts/compose-notification';
|
import composeNotification from '../common/scripts/compose-notification';
|
||||||
|
|
||||||
import chooseDriveFolder from './api/choose-drive-folder';
|
import chooseDriveFolder from './api/choose-drive-folder';
|
||||||
@ -37,6 +36,7 @@ import MkTag from './views/pages/tag.vue';
|
|||||||
import MkReversi from './views/pages/games/reversi.vue';
|
import MkReversi from './views/pages/games/reversi.vue';
|
||||||
import MkShare from './views/pages/share.vue';
|
import MkShare from './views/pages/share.vue';
|
||||||
import MkFollow from '../common/views/pages/follow.vue';
|
import MkFollow from '../common/views/pages/follow.vue';
|
||||||
|
import MiOS from '../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init
|
* init
|
||||||
@ -102,23 +102,18 @@ init(async (launch) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((Notification as any).permission == 'granted') {
|
if ((Notification as any).permission == 'granted') {
|
||||||
registerNotifications(os.stream);
|
registerNotifications(os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
function registerNotifications(stream: HomeStreamManager) {
|
function registerNotifications(os: MiOS) {
|
||||||
|
const stream = os.stream;
|
||||||
|
|
||||||
if (stream == null) return;
|
if (stream == null) return;
|
||||||
|
|
||||||
if (stream.hasConnection) {
|
const connection = stream.useSharedConnection('main');
|
||||||
attach(stream.borrow());
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.on('connected', connection => {
|
|
||||||
attach(connection);
|
|
||||||
});
|
|
||||||
|
|
||||||
function attach(connection) {
|
|
||||||
connection.on('notification', notification => {
|
connection.on('notification', notification => {
|
||||||
const _n = composeNotification('notification', notification);
|
const _n = composeNotification('notification', notification);
|
||||||
const n = new Notification(_n.title, {
|
const n = new Notification(_n.title, {
|
||||||
@ -128,8 +123,8 @@ function registerNotifications(stream: HomeStreamManager) {
|
|||||||
setTimeout(n.close.bind(n), 6000);
|
setTimeout(n.close.bind(n), 6000);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.on('drive_file_created', file => {
|
connection.on('driveFileCreated', file => {
|
||||||
const _n = composeNotification('drive_file_created', file);
|
const _n = composeNotification('driveFileCreated', file);
|
||||||
const n = new Notification(_n.title, {
|
const n = new Notification(_n.title, {
|
||||||
body: _n.body,
|
body: _n.body,
|
||||||
icon: _n.icon
|
icon: _n.icon
|
||||||
@ -137,8 +132,8 @@ function registerNotifications(stream: HomeStreamManager) {
|
|||||||
setTimeout(n.close.bind(n), 5000);
|
setTimeout(n.close.bind(n), 5000);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.on('unread_messaging_message', message => {
|
connection.on('unreadMessagingMessage', message => {
|
||||||
const _n = composeNotification('unread_messaging_message', message);
|
const _n = composeNotification('unreadMessagingMessage', message);
|
||||||
const n = new Notification(_n.title, {
|
const n = new Notification(_n.title, {
|
||||||
body: _n.body,
|
body: _n.body,
|
||||||
icon: _n.icon
|
icon: _n.icon
|
||||||
@ -152,12 +147,11 @@ function registerNotifications(stream: HomeStreamManager) {
|
|||||||
setTimeout(n.close.bind(n), 7000);
|
setTimeout(n.close.bind(n), 7000);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.on('reversi_invited', matching => {
|
connection.on('reversiInvited', matching => {
|
||||||
const _n = composeNotification('reversi_invited', matching);
|
const _n = composeNotification('reversiInvited', matching);
|
||||||
const n = new Notification(_n.title, {
|
const n = new Notification(_n.title, {
|
||||||
body: _n.body,
|
body: _n.body,
|
||||||
icon: _n.icon
|
icon: _n.icon
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -98,8 +98,7 @@ export default Vue.extend({
|
|||||||
hierarchyFolders: [],
|
hierarchyFolders: [],
|
||||||
selectedFiles: [],
|
selectedFiles: [],
|
||||||
uploadings: [],
|
uploadings: [],
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ドロップされようとしているか
|
* ドロップされようとしているか
|
||||||
@ -116,8 +115,7 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.streams.driveStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('drive');
|
||||||
this.connectionId = (this as any).os.streams.driveStream.use();
|
|
||||||
|
|
||||||
this.connection.on('file_created', this.onStreamDriveFileCreated);
|
this.connection.on('file_created', this.onStreamDriveFileCreated);
|
||||||
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
|
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
|
||||||
@ -132,12 +130,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('file_created', this.onStreamDriveFileCreated);
|
this.connection.dispose();
|
||||||
this.connection.off('file_updated', this.onStreamDriveFileUpdated);
|
|
||||||
this.connection.off('file_deleted', this.onStreamDriveFileDeleted);
|
|
||||||
this.connection.off('folder_created', this.onStreamDriveFolderCreated);
|
|
||||||
this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
|
|
||||||
(this as any).os.streams.driveStream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onContextmenu(e) {
|
onContextmenu(e) {
|
||||||
|
@ -34,23 +34,18 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
u: this.user,
|
u: this.user,
|
||||||
wait: false,
|
wait: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('follow', this.onFollow);
|
this.connection.on('follow', this.onFollow);
|
||||||
this.connection.on('unfollow', this.onUnfollow);
|
this.connection.on('unfollow', this.onUnfollow);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('follow', this.onFollow);
|
this.connection.dispose();
|
||||||
this.connection.off('unfollow', this.onUnfollow);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -141,7 +141,6 @@ export default Vue.extend({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
widgetAdderSelected: null,
|
widgetAdderSelected: null,
|
||||||
trash: []
|
trash: []
|
||||||
};
|
};
|
||||||
@ -176,12 +175,11 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -6,19 +6,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="vwxdhznewyashiknzolsoihtlpicqepe" v-else>
|
<div class="vwxdhznewyashiknzolsoihtlpicqepe" v-else>
|
||||||
<video class="video"
|
|
||||||
:src="video.url"
|
|
||||||
:title="video.name"
|
|
||||||
controls
|
|
||||||
@dblclick.prevent="onClick"
|
|
||||||
ref="video"
|
|
||||||
v-if="inlinePlayable" />
|
|
||||||
<a class="thumbnail"
|
<a class="thumbnail"
|
||||||
:href="video.url"
|
:href="video.url"
|
||||||
:style="imageStyle"
|
:style="imageStyle"
|
||||||
@click.prevent="onClick"
|
@click.prevent="onClick"
|
||||||
:title="video.name"
|
:title="video.name"
|
||||||
v-else>
|
>
|
||||||
%fa:R play-circle%
|
%fa:R play-circle%
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -46,7 +39,7 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
imageStyle(): any {
|
imageStyle(): any {
|
||||||
return {
|
return {
|
||||||
'background-image': `url(${this.video.url})`
|
'background-image': null // TODO `url(${this.video.thumbnailUrl})`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -93,12 +93,15 @@ 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 './notes.note.sub.vue';
|
import XSub from './notes.note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import { sum } from '../../../../../prelude/array';
|
||||||
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [noteSubscriber('note')],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer v-if="p.deletedAt == null">
|
||||||
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
||||||
<button class="replyButton" @click="reply()" title="%i18n:@reply%">
|
<button class="replyButton" @click="reply()" title="%i18n:@reply%">
|
||||||
<template v-if="p.reply">%fa:reply-all%</template>
|
<template v-if="p.reply">%fa:reply-all%</template>
|
||||||
@ -77,6 +77,7 @@ 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 './notes.note.sub.vue';
|
import XSub from './notes.note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import { sum } from '../../../../../prelude/array';
|
||||||
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
function focus(el, fn) {
|
function focus(el, fn) {
|
||||||
const target = fn(el);
|
const target = fn(el);
|
||||||
@ -94,6 +95,8 @@ export default Vue.extend({
|
|||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [noteSubscriber('note')],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -104,9 +107,7 @@ export default Vue.extend({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showContent: false,
|
showContent: false,
|
||||||
isDetailOpened: false,
|
isDetailOpened: false
|
||||||
connection: null,
|
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -168,86 +169,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.capture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.on('_connected_', this.onStreamConnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw map
|
|
||||||
if (this.p.geo) {
|
|
||||||
const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
|
|
||||||
if (shouldShowMap) {
|
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
|
||||||
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
|
|
||||||
const map = new maps.Map(this.$refs.map, {
|
|
||||||
center: uluru,
|
|
||||||
zoom: 15
|
|
||||||
});
|
|
||||||
new maps.Marker({
|
|
||||||
position: uluru,
|
|
||||||
map: map
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy() {
|
|
||||||
this.decapture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.off('_connected_', this.onStreamConnected);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
capture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
const data = {
|
|
||||||
type: 'capture',
|
|
||||||
id: this.p.id
|
|
||||||
} as any;
|
|
||||||
if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
|
|
||||||
data.read = true;
|
|
||||||
}
|
|
||||||
this.connection.send(data);
|
|
||||||
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
decapture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.send({
|
|
||||||
type: 'decapture',
|
|
||||||
id: this.p.id
|
|
||||||
});
|
|
||||||
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamConnected() {
|
|
||||||
this.capture();
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamNoteUpdated(data) {
|
|
||||||
const note = data.note;
|
|
||||||
if (note.id == this.note.id) {
|
|
||||||
this.$emit('update:note', note);
|
|
||||||
} else if (note.id == this.note.renoteId) {
|
|
||||||
this.note.renote = note;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reply(viaKeyboard = false) {
|
reply(viaKeyboard = false) {
|
||||||
(this as any).os.new(MkPostFormWindow, {
|
(this as any).os.new(MkPostFormWindow, {
|
||||||
reply: this.p,
|
reply: this.p,
|
||||||
|
@ -118,10 +118,10 @@ export default Vue.extend({
|
|||||||
notifications: [],
|
notifications: [],
|
||||||
moreNotifications: false,
|
moreNotifications: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
getNoteSummary
|
getNoteSummary
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
_notifications(): any[] {
|
_notifications(): any[] {
|
||||||
return (this.notifications as any).map(notification => {
|
return (this.notifications as any).map(notification => {
|
||||||
@ -133,9 +133,9 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('notification', this.onNotification);
|
this.connection.on('notification', this.onNotification);
|
||||||
|
|
||||||
@ -153,10 +153,11 @@ export default Vue.extend({
|
|||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('notification', this.onNotification);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchMoreNotifications() {
|
fetchMoreNotifications() {
|
||||||
this.fetchingMoreNotifications = true;
|
this.fetchingMoreNotifications = true;
|
||||||
@ -177,10 +178,11 @@ export default Vue.extend({
|
|||||||
this.fetchingMoreNotifications = false;
|
this.fetchingMoreNotifications = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onNotification(notification) {
|
onNotification(notification) {
|
||||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
type: 'read_notification',
|
type: 'readNotification',
|
||||||
id: notification.id
|
id: notification.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,25 +23,25 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
fetching: true,
|
fetching: true,
|
||||||
signins: [],
|
signins: [],
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
(this as any).api('i/signin_history').then(signins => {
|
(this as any).api('i/signin_history').then(signins => {
|
||||||
this.signins = signins;
|
this.signins = signins;
|
||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('signin', this.onSignin);
|
this.connection.on('signin', this.onSignin);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('signin', this.onSignin);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onSignin(signin) {
|
onSignin(signin) {
|
||||||
this.signins.unshift(signin);
|
this.signins.unshift(signin);
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { HashtagStream } from '../../../common/scripts/streaming/hashtag';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
@ -35,9 +34,7 @@ export default Vue.extend({
|
|||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false,
|
moreFetching: false,
|
||||||
existMore: false,
|
existMore: false,
|
||||||
streamManager: null,
|
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
date: null,
|
date: null,
|
||||||
baseQuery: {
|
baseQuery: {
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
@ -69,69 +66,33 @@ export default Vue.extend({
|
|||||||
this.query = {
|
this.query = {
|
||||||
query: this.tagTl.query
|
query: this.tagTl.query
|
||||||
};
|
};
|
||||||
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
this.connection = (this as any).os.stream.connectToChannel('hashtag', { q: this.tagTl.query });
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.connection.close();
|
|
||||||
});
|
|
||||||
} else if (this.src == 'home') {
|
} else if (this.src == 'home') {
|
||||||
this.endpoint = 'notes/timeline';
|
this.endpoint = 'notes/timeline';
|
||||||
const onChangeFollowing = () => {
|
const onChangeFollowing = () => {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
};
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('homeTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.connection.on('follow', onChangeFollowing);
|
this.connection.on('follow', onChangeFollowing);
|
||||||
this.connection.on('unfollow', onChangeFollowing);
|
this.connection.on('unfollow', onChangeFollowing);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.connection.off('follow', onChangeFollowing);
|
|
||||||
this.connection.off('unfollow', onChangeFollowing);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'local') {
|
} else if (this.src == 'local') {
|
||||||
this.endpoint = 'notes/local-timeline';
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.streamManager = (this as any).os.streams.localTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'hybrid') {
|
} else if (this.src == 'hybrid') {
|
||||||
this.endpoint = 'notes/hybrid-timeline';
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('hybridTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
this.endpoint = 'notes/global-timeline';
|
this.endpoint = 'notes/global-timeline';
|
||||||
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('globalTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'mentions') {
|
} else if (this.src == 'mentions') {
|
||||||
this.endpoint = 'notes/mentions';
|
this.endpoint = 'notes/mentions';
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('mention', prepend);
|
this.connection.on('mention', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('mention', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'messages') {
|
} else if (this.src == 'messages') {
|
||||||
this.endpoint = 'notes/mentions';
|
this.endpoint = 'notes/mentions';
|
||||||
this.query = {
|
this.query = {
|
||||||
@ -142,21 +103,15 @@ export default Vue.extend({
|
|||||||
prepend(note);
|
prepend(note);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('mention', onNote);
|
this.connection.on('mention', onNote);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('mention', onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$emit('beforeDestroy');
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -89,7 +89,7 @@ export default Vue.extend({
|
|||||||
display table-cell
|
display table-cell
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
height 48px
|
height 48px
|
||||||
color #9eaba8
|
color var(--desktopHeaderFg)
|
||||||
|
|
||||||
> .yyyymmdd
|
> .yyyymmdd
|
||||||
opacity 0.7
|
opacity 0.7
|
||||||
|
@ -42,8 +42,7 @@ export default Vue.extend({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasGameInvitations: false,
|
hasGameInvitations: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -53,18 +52,15 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('reversi_invited', this.onReversiInvited);
|
this.connection.on('reversiInvited', this.onReversiInvited);
|
||||||
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection.off('reversi_invited', this.onReversiInvited);
|
this.connection.dispose();
|
||||||
this.connection.off('reversi_no_invites', this.onReversiNoInvites);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { UserListStream } from '../../../common/scripts/streaming/user-list';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
@ -44,8 +44,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.qldxjjsrseehkusjuoooapmsprvfrxyl
|
.qldxjjsrseehkusjuoooapmsprvfrxyl
|
||||||
textarea
|
textarea
|
||||||
width 100%
|
width 100%
|
||||||
|
@ -56,13 +56,11 @@ export default Vue.extend({
|
|||||||
disableLocalTimeline: false,
|
disableLocalTimeline: false,
|
||||||
bannerUrl: null,
|
bannerUrl: null,
|
||||||
inviteCode: null,
|
inviteCode: null,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.connection = (this as any).os.streams.serverStatsStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
|
||||||
this.connectionId = (this as any).os.streams.serverStatsStream.use();
|
|
||||||
|
|
||||||
(this as any).os.getMeta().then(meta => {
|
(this as any).os.getMeta().then(meta => {
|
||||||
this.disableRegistration = meta.disableRegistration;
|
this.disableRegistration = meta.disableRegistration;
|
||||||
@ -75,7 +73,7 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
(this as any).os.streams.serverStatsStream.dispose(this.connectionId);
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
invite() {
|
invite() {
|
||||||
|
@ -21,23 +21,19 @@ export default Vue.extend({
|
|||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false,
|
moreFetching: false,
|
||||||
existMore: false,
|
existMore: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('mention', this.onNote);
|
this.connection.on('mention', this.onNote);
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('mention', this.onNote);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XNotes from './deck.notes.vue';
|
import XNotes from './deck.notes.vue';
|
||||||
import { HashtagStream } from '../../../../common/scripts/streaming/hashtag';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.connection) this.connection.close();
|
if (this.connection) this.connection.close();
|
||||||
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
this.connection = (this as any).os.stream.connectToChannel('hashtag', this.tagTl.query);
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XNotes from './deck.notes.vue';
|
import XNotes from './deck.notes.vue';
|
||||||
import { UserListStream } from '../../../../common/scripts/streaming/user-list';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
@ -21,23 +21,19 @@ export default Vue.extend({
|
|||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false,
|
moreFetching: false,
|
||||||
existMore: false,
|
existMore: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('mention', this.onNote);
|
this.connection.on('mention', this.onNote);
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('mention', this.onNote);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -70,12 +70,15 @@ import parse from '../../../../../../mfm/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 './deck.note.sub.vue';
|
import XSub from './deck.note.sub.vue';
|
||||||
|
import noteSubscriber from '../../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [noteSubscriber('note')],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -90,9 +93,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showContent: false,
|
showContent: false
|
||||||
connection: null,
|
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -120,68 +121,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.capture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.on('_connected_', this.onStreamConnected);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy() {
|
|
||||||
this.decapture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.off('_connected_', this.onStreamConnected);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
capture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
const data = {
|
|
||||||
type: 'capture',
|
|
||||||
id: this.p.id
|
|
||||||
} as any;
|
|
||||||
if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
|
|
||||||
data.read = true;
|
|
||||||
}
|
|
||||||
this.connection.send(data);
|
|
||||||
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
decapture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.send({
|
|
||||||
type: 'decapture',
|
|
||||||
id: this.p.id
|
|
||||||
});
|
|
||||||
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamConnected() {
|
|
||||||
this.capture();
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamNoteUpdated(data) {
|
|
||||||
const note = data.note;
|
|
||||||
if (note.id == this.note.id) {
|
|
||||||
this.$emit('update:note', note);
|
|
||||||
} else if (note.id == this.note.renoteId) {
|
|
||||||
this.note.renote = note;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reply() {
|
reply() {
|
||||||
(this as any).apis.post({
|
(this as any).apis.post({
|
||||||
reply: this.p
|
reply: this.p
|
||||||
|
@ -38,8 +38,7 @@ export default Vue.extend({
|
|||||||
notifications: [],
|
notifications: [],
|
||||||
queue: [],
|
queue: [],
|
||||||
moreNotifications: false,
|
moreNotifications: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -62,8 +61,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('notification', this.onNotification);
|
this.connection.on('notification', this.onNotification);
|
||||||
|
|
||||||
@ -86,8 +84,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('notification', this.onNotification);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
|
|
||||||
this.column.$off('top', this.onTop);
|
this.column.$off('top', this.onTop);
|
||||||
this.column.$off('bottom', this.onBottom);
|
this.column.$off('bottom', this.onBottom);
|
||||||
@ -117,7 +114,7 @@ export default Vue.extend({
|
|||||||
onNotification(notification) {
|
onNotification(notification) {
|
||||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
type: 'read_notification',
|
type: 'readNotification',
|
||||||
id: notification.id
|
id: notification.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,18 +36,17 @@ export default Vue.extend({
|
|||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false,
|
moreFetching: false,
|
||||||
existMore: false,
|
existMore: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
stream(): any {
|
stream(): any {
|
||||||
switch (this.src) {
|
switch (this.src) {
|
||||||
case 'home': return (this as any).os.stream;
|
case 'home': return (this as any).os.stream.useSharedConnection('homeTimeline');
|
||||||
case 'local': return (this as any).os.streams.localTimelineStream;
|
case 'local': return (this as any).os.stream.useSharedConnection('localTimeline');
|
||||||
case 'hybrid': return (this as any).os.streams.hybridTimelineStream;
|
case 'hybrid': return (this as any).os.stream.useSharedConnection('hybridTimeline');
|
||||||
case 'global': return (this as any).os.streams.globalTimelineStream;
|
case 'global': return (this as any).os.stream.useSharedConnection('globalTimeline');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -68,8 +67,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = this.stream.getConnection();
|
this.connection = this.stream;
|
||||||
this.connectionId = this.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
if (this.src == 'home') {
|
if (this.src == 'home') {
|
||||||
@ -81,12 +79,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('note', this.onNote);
|
this.connection.dispose();
|
||||||
if (this.src == 'home') {
|
|
||||||
this.connection.off('follow', this.onChangeFollowing);
|
|
||||||
this.connection.off('unfollow', this.onChangeFollowing);
|
|
||||||
}
|
|
||||||
this.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import autobind from 'autobind-decorator';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
@ -5,19 +6,9 @@ import * as uuid from 'uuid';
|
|||||||
import initStore from './store';
|
import initStore from './store';
|
||||||
import { apiUrl, version, lang } from './config';
|
import { apiUrl, version, lang } from './config';
|
||||||
import Progress from './common/scripts/loading';
|
import Progress from './common/scripts/loading';
|
||||||
import Connection from './common/scripts/streaming/stream';
|
|
||||||
import { HomeStreamManager } from './common/scripts/streaming/home';
|
|
||||||
import { DriveStreamManager } from './common/scripts/streaming/drive';
|
|
||||||
import { ServerStatsStreamManager } from './common/scripts/streaming/server-stats';
|
|
||||||
import { NotesStatsStreamManager } from './common/scripts/streaming/notes-stats';
|
|
||||||
import { MessagingIndexStreamManager } from './common/scripts/streaming/messaging-index';
|
|
||||||
import { ReversiStreamManager } from './common/scripts/streaming/games/reversi/reversi';
|
|
||||||
|
|
||||||
import Err from './common/views/components/connect-failed.vue';
|
import Err from './common/views/components/connect-failed.vue';
|
||||||
import { LocalTimelineStreamManager } from './common/scripts/streaming/local-timeline';
|
import Stream from './common/scripts/stream';
|
||||||
import { HybridTimelineStreamManager } from './common/scripts/streaming/hybrid-timeline';
|
|
||||||
import { GlobalTimelineStreamManager } from './common/scripts/streaming/global-timeline';
|
|
||||||
import { erase } from '../../prelude/array';
|
|
||||||
|
|
||||||
//#region api requests
|
//#region api requests
|
||||||
let spinner = null;
|
let spinner = null;
|
||||||
@ -102,30 +93,7 @@ export default class MiOS extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* A connection manager of home stream
|
* A connection manager of home stream
|
||||||
*/
|
*/
|
||||||
public stream: HomeStreamManager;
|
public stream: Stream;
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection managers
|
|
||||||
*/
|
|
||||||
public streams: {
|
|
||||||
localTimelineStream: LocalTimelineStreamManager;
|
|
||||||
hybridTimelineStream: HybridTimelineStreamManager;
|
|
||||||
globalTimelineStream: GlobalTimelineStreamManager;
|
|
||||||
driveStream: DriveStreamManager;
|
|
||||||
serverStatsStream: ServerStatsStreamManager;
|
|
||||||
notesStatsStream: NotesStatsStreamManager;
|
|
||||||
messagingIndexStream: MessagingIndexStreamManager;
|
|
||||||
reversiStream: ReversiStreamManager;
|
|
||||||
} = {
|
|
||||||
localTimelineStream: null,
|
|
||||||
hybridTimelineStream: null,
|
|
||||||
globalTimelineStream: null,
|
|
||||||
driveStream: null,
|
|
||||||
serverStatsStream: null,
|
|
||||||
notesStatsStream: null,
|
|
||||||
messagingIndexStream: null,
|
|
||||||
reversiStream: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A registration of service worker
|
* A registration of service worker
|
||||||
@ -151,71 +119,36 @@ export default class MiOS extends EventEmitter {
|
|||||||
|
|
||||||
this.shouldRegisterSw = shouldRegisterSw;
|
this.shouldRegisterSw = shouldRegisterSw;
|
||||||
|
|
||||||
//#region BIND
|
|
||||||
this.log = this.log.bind(this);
|
|
||||||
this.logInfo = this.logInfo.bind(this);
|
|
||||||
this.logWarn = this.logWarn.bind(this);
|
|
||||||
this.logError = this.logError.bind(this);
|
|
||||||
this.init = this.init.bind(this);
|
|
||||||
this.api = this.api.bind(this);
|
|
||||||
this.getMeta = this.getMeta.bind(this);
|
|
||||||
this.registerSw = this.registerSw.bind(this);
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
(window as any).os = this;
|
(window as any).os = this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private googleMapsIniting = false;
|
@autobind
|
||||||
|
|
||||||
public getGoogleMaps() {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
if ((window as any).google && (window as any).google.maps) {
|
|
||||||
res((window as any).google.maps);
|
|
||||||
} else {
|
|
||||||
this.once('init-google-maps', () => {
|
|
||||||
res((window as any).google.maps);
|
|
||||||
});
|
|
||||||
|
|
||||||
//#region load google maps api
|
|
||||||
if (!this.googleMapsIniting) {
|
|
||||||
this.googleMapsIniting = true;
|
|
||||||
(window as any).initGoogleMaps = () => {
|
|
||||||
this.emit('init-google-maps');
|
|
||||||
};
|
|
||||||
const head = document.getElementsByTagName('head')[0];
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.setAttribute('src', `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=initGoogleMaps`);
|
|
||||||
script.setAttribute('async', 'true');
|
|
||||||
script.setAttribute('defer', 'true');
|
|
||||||
head.appendChild(script);
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public log(...args) {
|
public log(...args) {
|
||||||
if (!this.debug) return;
|
if (!this.debug) return;
|
||||||
console.log.apply(null, args);
|
console.log.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
public logInfo(...args) {
|
public logInfo(...args) {
|
||||||
if (!this.debug) return;
|
if (!this.debug) return;
|
||||||
console.info.apply(null, args);
|
console.info.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
public logWarn(...args) {
|
public logWarn(...args) {
|
||||||
if (!this.debug) return;
|
if (!this.debug) return;
|
||||||
console.warn.apply(null, args);
|
console.warn.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
public logError(...args) {
|
public logError(...args) {
|
||||||
if (!this.debug) return;
|
if (!this.debug) return;
|
||||||
console.error.apply(null, args);
|
console.error.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
public signout() {
|
public signout() {
|
||||||
this.store.dispatch('logout');
|
this.store.dispatch('logout');
|
||||||
location.href = '/';
|
location.href = '/';
|
||||||
@ -225,27 +158,10 @@ export default class MiOS extends EventEmitter {
|
|||||||
* Initialize MiOS (boot)
|
* Initialize MiOS (boot)
|
||||||
* @param callback A function that call when initialized
|
* @param callback A function that call when initialized
|
||||||
*/
|
*/
|
||||||
|
@autobind
|
||||||
public async init(callback) {
|
public async init(callback) {
|
||||||
this.store = initStore(this);
|
this.store = initStore(this);
|
||||||
|
|
||||||
//#region Init stream managers
|
|
||||||
this.streams.serverStatsStream = new ServerStatsStreamManager(this);
|
|
||||||
this.streams.notesStatsStream = new NotesStatsStreamManager(this);
|
|
||||||
this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.store.state.i);
|
|
||||||
|
|
||||||
this.once('signedin', () => {
|
|
||||||
// Init home stream manager
|
|
||||||
this.stream = new HomeStreamManager(this, this.store.state.i);
|
|
||||||
|
|
||||||
// Init other stream manager
|
|
||||||
this.streams.hybridTimelineStream = new HybridTimelineStreamManager(this, this.store.state.i);
|
|
||||||
this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.store.state.i);
|
|
||||||
this.streams.driveStream = new DriveStreamManager(this, this.store.state.i);
|
|
||||||
this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.store.state.i);
|
|
||||||
this.streams.reversiStream = new ReversiStreamManager(this, this.store.state.i);
|
|
||||||
});
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
// ユーザーをフェッチしてコールバックする
|
// ユーザーをフェッチしてコールバックする
|
||||||
const fetchme = (token, cb) => {
|
const fetchme = (token, cb) => {
|
||||||
let me = null;
|
let me = null;
|
||||||
@ -296,6 +212,8 @@ export default class MiOS extends EventEmitter {
|
|||||||
const fetched = () => {
|
const fetched = () => {
|
||||||
this.emit('signedin');
|
this.emit('signedin');
|
||||||
|
|
||||||
|
this.stream = new Stream(this);
|
||||||
|
|
||||||
// Finish init
|
// Finish init
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
@ -328,6 +246,8 @@ export default class MiOS extends EventEmitter {
|
|||||||
} else {
|
} else {
|
||||||
// Finish init
|
// Finish init
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
|
this.stream = new Stream(this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -336,6 +256,7 @@ export default class MiOS extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Register service worker
|
* Register service worker
|
||||||
*/
|
*/
|
||||||
|
@autobind
|
||||||
private registerSw() {
|
private registerSw() {
|
||||||
// Check whether service worker and push manager supported
|
// Check whether service worker and push manager supported
|
||||||
const isSwSupported =
|
const isSwSupported =
|
||||||
@ -418,7 +339,8 @@ export default class MiOS extends EventEmitter {
|
|||||||
* @param endpoint エンドポイント名
|
* @param endpoint エンドポイント名
|
||||||
* @param data パラメータ
|
* @param data パラメータ
|
||||||
*/
|
*/
|
||||||
public api(endpoint: string, data: { [x: string]: any } = {}): Promise<{ [x: string]: any }> {
|
@autobind
|
||||||
|
public api(endpoint: string, data: { [x: string]: any } = {}, forceFetch = false): Promise<{ [x: string]: any }> {
|
||||||
if (++pending === 1) {
|
if (++pending === 1) {
|
||||||
spinner = document.createElement('div');
|
spinner = document.createElement('div');
|
||||||
spinner.setAttribute('id', 'wait');
|
spinner.setAttribute('id', 'wait');
|
||||||
@ -430,13 +352,12 @@ export default class MiOS extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
const viaStream = this.stream && this.stream.hasConnection && this.store.state.device.apiViaStream;
|
const viaStream = this.stream && this.store.state.device.apiViaStream && !forceFetch;
|
||||||
|
|
||||||
if (viaStream) {
|
if (viaStream) {
|
||||||
const stream = this.stream.borrow();
|
|
||||||
const id = Math.random().toString();
|
const id = Math.random().toString();
|
||||||
|
|
||||||
stream.once(`api-res:${id}`, res => {
|
this.stream.once(`api:${id}`, res => {
|
||||||
if (res == null || Object.keys(res).length == 0) {
|
if (res == null || Object.keys(res).length == 0) {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
} else if (res.res) {
|
} else if (res.res) {
|
||||||
@ -446,11 +367,10 @@ export default class MiOS extends EventEmitter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.send({
|
this.stream.send('api', {
|
||||||
type: 'api',
|
id: id,
|
||||||
id,
|
ep: endpoint,
|
||||||
endpoint,
|
data: data
|
||||||
data
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Append a credential
|
// Append a credential
|
||||||
@ -503,6 +423,7 @@ export default class MiOS extends EventEmitter {
|
|||||||
* Misskeyのメタ情報を取得します
|
* Misskeyのメタ情報を取得します
|
||||||
* @param force キャッシュを無視するか否か
|
* @param force キャッシュを無視するか否か
|
||||||
*/
|
*/
|
||||||
|
@autobind
|
||||||
public getMeta(force = false) {
|
public getMeta(force = false) {
|
||||||
return new Promise<{ [x: string]: any }>(async (res, rej) => {
|
return new Promise<{ [x: string]: any }>(async (res, rej) => {
|
||||||
if (this.isMetaFetching) {
|
if (this.isMetaFetching) {
|
||||||
@ -530,16 +451,6 @@ export default class MiOS extends EventEmitter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public connections: Connection[] = [];
|
|
||||||
|
|
||||||
public registerStreamConnection(connection: Connection) {
|
|
||||||
this.connections.push(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public unregisterStreamConnection(connection: Connection) {
|
|
||||||
this.connections = erase(connection, this.connections);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WindowSystem extends EventEmitter {
|
class WindowSystem extends EventEmitter {
|
||||||
|
@ -38,10 +38,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div>
|
<div>
|
||||||
<a :href="`${file.url}?download`" :download="file.name">%fa:download%%i18n:@download%</a>
|
<ui-button link :href="`${file.url}?download`" :download="file.name">%fa:download% %i18n:@download%</ui-button>
|
||||||
<button @click="rename">%fa:pencil-alt%%i18n:@rename%</button>
|
<ui-button @click="rename">%fa:pencil-alt% %i18n:@rename%</ui-button>
|
||||||
<button @click="move">%fa:R folder-open%%i18n:@move%</button>
|
<ui-button @click="move">%fa:R folder-open% %i18n:@move%</ui-button>
|
||||||
<button @click="del">%fa:trash-alt R%%i18n:@delete%</button>
|
<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="exif" v-show="exif">
|
<div class="exif" v-show="exif">
|
||||||
@ -205,28 +205,6 @@ export default Vue.extend({
|
|||||||
max-width 500px
|
max-width 500px
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
|
||||||
> *
|
|
||||||
display block
|
|
||||||
width 100%
|
|
||||||
padding 10px 16px
|
|
||||||
margin 0 0 12px 0
|
|
||||||
color var(--primaryForeground)
|
|
||||||
font-size 0.9em
|
|
||||||
text-align center
|
|
||||||
text-decoration none
|
|
||||||
background var(--primary)
|
|
||||||
border none
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&:last-child
|
|
||||||
margin-bottom 0
|
|
||||||
|
|
||||||
&:active
|
|
||||||
background var(--primaryDarken10)
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> .hash
|
> .hash
|
||||||
padding 14px
|
padding 14px
|
||||||
border-top solid 1px var(--faceDivider)
|
border-top solid 1px var(--faceDivider)
|
||||||
|
@ -81,8 +81,7 @@ export default Vue.extend({
|
|||||||
hierarchyFolders: [],
|
hierarchyFolders: [],
|
||||||
selectedFiles: [],
|
selectedFiles: [],
|
||||||
info: null,
|
info: null,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null,
|
|
||||||
|
|
||||||
fetching: true,
|
fetching: true,
|
||||||
fetchingMoreFiles: false,
|
fetchingMoreFiles: false,
|
||||||
@ -102,8 +101,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.streams.driveStream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('drive');
|
||||||
this.connectionId = (this as any).os.streams.driveStream.use();
|
|
||||||
|
|
||||||
this.connection.on('file_created', this.onStreamDriveFileCreated);
|
this.connection.on('file_created', this.onStreamDriveFileCreated);
|
||||||
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
|
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
|
||||||
@ -124,12 +122,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('file_created', this.onStreamDriveFileCreated);
|
this.connection.dispose();
|
||||||
this.connection.off('file_updated', this.onStreamDriveFileUpdated);
|
|
||||||
this.connection.off('file_deleted', this.onStreamDriveFileDeleted);
|
|
||||||
this.connection.off('folder_created', this.onStreamDriveFolderCreated);
|
|
||||||
this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
|
|
||||||
(this as any).os.streams.driveStream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onStreamDriveFileCreated(file) {
|
onStreamDriveFileCreated(file) {
|
||||||
|
@ -28,21 +28,17 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
u: this.user,
|
u: this.user,
|
||||||
wait: false,
|
wait: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('follow', this.onFollow);
|
this.connection.on('follow', this.onFollow);
|
||||||
this.connection.on('unfollow', this.onUnfollow);
|
this.connection.on('unfollow', this.onUnfollow);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('follow', this.onFollow);
|
this.connection.dispose();
|
||||||
this.connection.off('unfollow', this.onUnfollow);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
:href="video.url"
|
:href="video.url"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:style="imageStyle"
|
:style="imageStyle"
|
||||||
:title="video.name">
|
:title="video.name"
|
||||||
|
>
|
||||||
%fa:R play-circle%
|
%fa:R play-circle%
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
@ -32,7 +33,7 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
imageStyle(): any {
|
imageStyle(): any {
|
||||||
return {
|
return {
|
||||||
'background-image': `url(${this.video.url})`
|
'background-image': null // TODO `url(${this.video.thumbnailUrl})`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,12 +92,15 @@ 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.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import { sum } from '../../../../../prelude/array';
|
||||||
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [noteSubscriber('note')],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer v-if="p.deletedAt == null">
|
||||||
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
||||||
<button @click="reply">
|
<button @click="reply">
|
||||||
<template v-if="p.reply">%fa:reply-all%</template>
|
<template v-if="p.reply">%fa:reply-all%</template>
|
||||||
@ -69,19 +69,20 @@ 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.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import { sum } from '../../../../../prelude/array';
|
||||||
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [noteSubscriber('note')],
|
||||||
|
|
||||||
props: ['note'],
|
props: ['note'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showContent: false,
|
showContent: false
|
||||||
connection: null,
|
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -115,86 +116,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.capture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.on('_connected_', this.onStreamConnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw map
|
|
||||||
if (this.p.geo) {
|
|
||||||
const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
|
|
||||||
if (shouldShowMap) {
|
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
|
||||||
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
|
|
||||||
const map = new maps.Map(this.$refs.map, {
|
|
||||||
center: uluru,
|
|
||||||
zoom: 15
|
|
||||||
});
|
|
||||||
new maps.Marker({
|
|
||||||
position: uluru,
|
|
||||||
map: map
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy() {
|
|
||||||
this.decapture(true);
|
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.off('_connected_', this.onStreamConnected);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
capture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
const data = {
|
|
||||||
type: 'capture',
|
|
||||||
id: this.p.id
|
|
||||||
} as any;
|
|
||||||
if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
|
|
||||||
data.read = true;
|
|
||||||
}
|
|
||||||
this.connection.send(data);
|
|
||||||
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
decapture(withHandler = false) {
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
|
||||||
this.connection.send({
|
|
||||||
type: 'decapture',
|
|
||||||
id: this.p.id
|
|
||||||
});
|
|
||||||
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamConnected() {
|
|
||||||
this.capture();
|
|
||||||
},
|
|
||||||
|
|
||||||
onStreamNoteUpdated(data) {
|
|
||||||
const note = data.note;
|
|
||||||
if (note.id == this.note.id) {
|
|
||||||
this.$emit('update:note', note);
|
|
||||||
} else if (note.id == this.note.renoteId) {
|
|
||||||
this.note.renote = note;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reply() {
|
reply() {
|
||||||
(this as any).apis.post({
|
(this as any).apis.post({
|
||||||
reply: this.p
|
reply: this.p
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -30,10 +31,10 @@ export default Vue.extend({
|
|||||||
fetchingMoreNotifications: false,
|
fetchingMoreNotifications: false,
|
||||||
notifications: [],
|
notifications: [],
|
||||||
moreNotifications: false,
|
moreNotifications: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
_notifications(): any[] {
|
_notifications(): any[] {
|
||||||
return (this.notifications as any).map(notification => {
|
return (this.notifications as any).map(notification => {
|
||||||
@ -45,9 +46,11 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
window.addEventListener('scroll', this.onScroll, { passive: true });
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
|
|
||||||
this.connection.on('notification', this.onNotification);
|
this.connection.on('notification', this.onNotification);
|
||||||
|
|
||||||
@ -66,10 +69,12 @@ export default Vue.extend({
|
|||||||
this.$emit('fetched');
|
this.$emit('fetched');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('notification', this.onNotification);
|
window.removeEventListener('scroll', this.onScroll);
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchMoreNotifications() {
|
fetchMoreNotifications() {
|
||||||
this.fetchingMoreNotifications = true;
|
this.fetchingMoreNotifications = true;
|
||||||
@ -90,14 +95,27 @@ export default Vue.extend({
|
|||||||
this.fetchingMoreNotifications = false;
|
this.fetchingMoreNotifications = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onNotification(notification) {
|
onNotification(notification) {
|
||||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
type: 'read_notification',
|
type: 'readNotification',
|
||||||
id: notification.id
|
id: notification.id
|
||||||
});
|
});
|
||||||
|
|
||||||
this.notifications.unshift(notification);
|
this.notifications.unshift(notification);
|
||||||
|
},
|
||||||
|
|
||||||
|
onScroll() {
|
||||||
|
if (this.$store.state.settings.fetchOnScroll !== false) {
|
||||||
|
// 親要素が display none だったら弾く
|
||||||
|
// https://github.com/syuilo/misskey/issues/1569
|
||||||
|
// http://d.hatena.ne.jp/favril/20091105/1257403319
|
||||||
|
if (this.$el.offsetHeight == 0) return;
|
||||||
|
|
||||||
|
const current = window.scrollY + window.innerHeight;
|
||||||
|
if (current > document.body.offsetHeight - 8) this.fetchMoreNotifications();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -148,7 +166,7 @@ export default Vue.extend({
|
|||||||
display block
|
display block
|
||||||
width 100%
|
width 100%
|
||||||
padding 16px
|
padding 16px
|
||||||
color #555
|
color var(--text)
|
||||||
border-top solid 1px rgba(#000, 0.05)
|
border-top solid 1px rgba(#000, 0.05)
|
||||||
|
|
||||||
> [data-fa]
|
> [data-fa]
|
||||||
|
@ -478,7 +478,7 @@ export default Vue.extend({
|
|||||||
width 48px
|
width 48px
|
||||||
height 48px
|
height 48px
|
||||||
font-size 20px
|
font-size 20px
|
||||||
color #657786
|
color var(--mobilePostFormButton)
|
||||||
background transparent
|
background transparent
|
||||||
outline none
|
outline none
|
||||||
border none
|
border none
|
||||||
|
@ -24,44 +24,47 @@ import { env } from '../../../config';
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['func'],
|
props: ['func'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasGameInvitation: false,
|
hasGameInvitation: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
env: env
|
env: env
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
hasUnreadNotification(): boolean {
|
hasUnreadNotification(): boolean {
|
||||||
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadNotification;
|
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadNotification;
|
||||||
},
|
},
|
||||||
|
|
||||||
hasUnreadMessagingMessage(): boolean {
|
hasUnreadMessagingMessage(): boolean {
|
||||||
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
|
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.commit('setUiHeaderHeight', this.$refs.root.offsetHeight);
|
this.$store.commit('setUiHeaderHeight', this.$refs.root.offsetHeight);
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('reversi_invited', this.onReversiInvited);
|
this.connection.on('reversiInvited', this.onReversiInvited);
|
||||||
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection.off('reversi_invited', this.onReversiInvited);
|
this.connection.dispose();
|
||||||
this.connection.off('reversi_no_invites', this.onReversiNoInvites);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onReversiInvited() {
|
onReversiInvited() {
|
||||||
this.hasGameInvitation = true;
|
this.hasGameInvitation = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
onReversiNoInvites() {
|
onReversiNoInvites() {
|
||||||
this.hasGameInvitation = false;
|
this.hasGameInvitation = false;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
hasGameInvitation: false,
|
hasGameInvitation: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
aboutUrl: `/docs/${lang}/about`,
|
aboutUrl: `/docs/${lang}/about`,
|
||||||
announcements: []
|
announcements: []
|
||||||
};
|
};
|
||||||
@ -79,19 +78,16 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('reversi_invited', this.onReversiInvited);
|
this.connection.on('reversiInvited', this.onReversiInvited);
|
||||||
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection.off('reversi_invited', this.onReversiInvited);
|
this.connection.dispose();
|
||||||
this.connection.off('reversi_no_invites', this.onReversiNoInvites);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -23,40 +23,43 @@ export default Vue.extend({
|
|||||||
XHeader,
|
XHeader,
|
||||||
XNav
|
XNav
|
||||||
},
|
},
|
||||||
|
|
||||||
props: ['title'],
|
props: ['title'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isDrawerOpening: false,
|
isDrawerOpening: false,
|
||||||
connection: null,
|
connection: null
|
||||||
connectionId: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'$store.state.uiHeaderHeight'() {
|
'$store.state.uiHeaderHeight'() {
|
||||||
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
||||||
|
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('notification', this.onNotification);
|
this.connection.on('notification', this.onNotification);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection.off('notification', this.onNotification);
|
this.connection.dispose();
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onNotification(notification) {
|
onNotification(notification) {
|
||||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
type: 'read_notification',
|
type: 'readNotification',
|
||||||
id: notification.id
|
id: notification.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { UserListStream } from '../../../common/scripts/streaming/user-list';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { HashtagStream } from '../../../common/scripts/streaming/hashtag';
|
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
@ -35,7 +34,6 @@ export default Vue.extend({
|
|||||||
existMore: false,
|
existMore: false,
|
||||||
streamManager: null,
|
streamManager: null,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
|
||||||
unreadCount: 0,
|
unreadCount: 0,
|
||||||
date: null,
|
date: null,
|
||||||
baseQuery: {
|
baseQuery: {
|
||||||
@ -68,69 +66,33 @@ export default Vue.extend({
|
|||||||
this.query = {
|
this.query = {
|
||||||
query: this.tagTl.query
|
query: this.tagTl.query
|
||||||
};
|
};
|
||||||
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
this.connection = (this as any).os.stream.connectToChannel('hashtag', { q: this.tagTl.query });
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.connection.close();
|
|
||||||
});
|
|
||||||
} else if (this.src == 'home') {
|
} else if (this.src == 'home') {
|
||||||
this.endpoint = 'notes/timeline';
|
this.endpoint = 'notes/timeline';
|
||||||
const onChangeFollowing = () => {
|
const onChangeFollowing = () => {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
};
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('homeTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.connection.on('follow', onChangeFollowing);
|
this.connection.on('follow', onChangeFollowing);
|
||||||
this.connection.on('unfollow', onChangeFollowing);
|
this.connection.on('unfollow', onChangeFollowing);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.connection.off('follow', onChangeFollowing);
|
|
||||||
this.connection.off('unfollow', onChangeFollowing);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'local') {
|
} else if (this.src == 'local') {
|
||||||
this.endpoint = 'notes/local-timeline';
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.streamManager = (this as any).os.streams.localTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'hybrid') {
|
} else if (this.src == 'hybrid') {
|
||||||
this.endpoint = 'notes/hybrid-timeline';
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('hybridTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
this.endpoint = 'notes/global-timeline';
|
this.endpoint = 'notes/global-timeline';
|
||||||
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
this.connection = (this as any).os.stream.useSharedConnection('globalTimeline');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('note', prepend);
|
this.connection.on('note', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('note', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'mentions') {
|
} else if (this.src == 'mentions') {
|
||||||
this.endpoint = 'notes/mentions';
|
this.endpoint = 'notes/mentions';
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('mention', prepend);
|
this.connection.on('mention', prepend);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('mention', prepend);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
} else if (this.src == 'messages') {
|
} else if (this.src == 'messages') {
|
||||||
this.endpoint = 'notes/mentions';
|
this.endpoint = 'notes/mentions';
|
||||||
this.query = {
|
this.query = {
|
||||||
@ -141,21 +103,15 @@ export default Vue.extend({
|
|||||||
prepend(note);
|
prepend(note);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
this.connection = this.streamManager.getConnection();
|
|
||||||
this.connectionId = this.streamManager.use();
|
|
||||||
this.connection.on('mention', onNote);
|
this.connection.on('mention', onNote);
|
||||||
this.$once('beforeDestroy', () => {
|
|
||||||
this.connection.off('mention', onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$emit('beforeDestroy');
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -13,12 +13,14 @@ export type Theme = {
|
|||||||
export const lightTheme: Theme = require('../theme/light.json5');
|
export const lightTheme: Theme = require('../theme/light.json5');
|
||||||
export const darkTheme: Theme = require('../theme/dark.json5');
|
export const darkTheme: Theme = require('../theme/dark.json5');
|
||||||
export const pinkTheme: Theme = require('../theme/pink.json5');
|
export const pinkTheme: Theme = require('../theme/pink.json5');
|
||||||
|
export const blackTheme: Theme = require('../theme/black.json5');
|
||||||
export const halloweenTheme: Theme = require('../theme/halloween.json5');
|
export const halloweenTheme: Theme = require('../theme/halloween.json5');
|
||||||
|
|
||||||
export const builtinThemes = [
|
export const builtinThemes = [
|
||||||
lightTheme,
|
lightTheme,
|
||||||
darkTheme,
|
darkTheme,
|
||||||
pinkTheme,
|
pinkTheme,
|
||||||
|
blackTheme,
|
||||||
halloweenTheme
|
halloweenTheme
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noLib": false,
|
"noLib": false,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": false
|
"strictNullChecks": false,
|
||||||
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"include": [
|
"include": [
|
||||||
|
20
src/client/theme/black.json5
Normal file
20
src/client/theme/black.json5
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
id: 'bb5a8287-a072-4b0a-8ae5-ea2a0d33f4f2',
|
||||||
|
|
||||||
|
name: 'Future',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
vars: {
|
||||||
|
primary: 'rgb(94, 158, 185)',
|
||||||
|
secondary: 'rgb(22, 24, 30)',
|
||||||
|
text: 'rgb(214, 218, 224)',
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
renoteGradient: '#0a2d3c',
|
||||||
|
renoteText: '$primary',
|
||||||
|
quoteBorder: '$primary',
|
||||||
|
},
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
name: 'Dark',
|
name: 'Dark',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
desc: 'Default dark theme',
|
desc: 'Default dark theme',
|
||||||
|
kind: 'dark',
|
||||||
|
|
||||||
vars: {
|
vars: {
|
||||||
primary: '#fb4e4e',
|
primary: '#fb4e4e',
|
||||||
@ -46,15 +47,15 @@
|
|||||||
noteHeaderBadgeBg: 'rgba(0, 0, 0, 0.25)',
|
noteHeaderBadgeBg: 'rgba(0, 0, 0, 0.25)',
|
||||||
noteHeaderAdminFg: '#f15f71',
|
noteHeaderAdminFg: '#f15f71',
|
||||||
noteHeaderAdminBg: '#5d282e',
|
noteHeaderAdminBg: '#5d282e',
|
||||||
noteHeaderAcct: '#606984',
|
noteHeaderAcct: ':alpha<0.65<$text',
|
||||||
noteHeaderInfo: '#606984',
|
noteHeaderInfo: ':alpha<0.5<$text',
|
||||||
|
|
||||||
noteActions: '#606984',
|
noteActions: ':alpha<0.45<$text',
|
||||||
noteActionsHover: '#a1a8bf',
|
noteActionsHover: ':alpha<0.6<$text',
|
||||||
noteActionsReplyHover: '#0af',
|
noteActionsReplyHover: '#0af',
|
||||||
noteActionsRenoteHover: '#8d0',
|
noteActionsRenoteHover: '#8d0',
|
||||||
noteActionsReactionHover: '#fa0',
|
noteActionsReactionHover: '#fa0',
|
||||||
noteActionsHighlighted: '#707b97',
|
noteActionsHighlighted: ':alpha<0.7<$text',
|
||||||
|
|
||||||
noteAttachedFile: 'rgba(255, 255, 255, 0.1)',
|
noteAttachedFile: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
|
||||||
@ -98,7 +99,7 @@
|
|||||||
|
|
||||||
calendarWeek: '#43d5dc',
|
calendarWeek: '#43d5dc',
|
||||||
calendarSaturdayOrSunday: '#ff6679',
|
calendarSaturdayOrSunday: '#ff6679',
|
||||||
calendarDay: '#c5ced6',
|
calendarDay: '$text',
|
||||||
|
|
||||||
materBg: 'rgba(0, 0, 0, 0.3)',
|
materBg: 'rgba(0, 0, 0, 0.3)',
|
||||||
|
|
||||||
@ -120,6 +121,9 @@
|
|||||||
mfmTitleBg: 'rgba(0, 0, 0, 0.2)',
|
mfmTitleBg: 'rgba(0, 0, 0, 0.2)',
|
||||||
mfmQuote: ':alpha<0.7<$text',
|
mfmQuote: ':alpha<0.7<$text',
|
||||||
mfmQuoteLine: ':alpha<0.6<$text',
|
mfmQuoteLine: ':alpha<0.6<$text',
|
||||||
|
mfmLink: '$primary',
|
||||||
|
mfmMention: '$primary',
|
||||||
|
mfmHashtag: '$primary',
|
||||||
|
|
||||||
suspendedInfoBg: '#611d1d',
|
suspendedInfoBg: '#611d1d',
|
||||||
suspendedInfoFg: '#ffb4b4',
|
suspendedInfoFg: '#ffb4b4',
|
||||||
@ -175,6 +179,7 @@
|
|||||||
mobileNavBackdrop: 'rgba(0, 0, 0, 0.7)',
|
mobileNavBackdrop: 'rgba(0, 0, 0, 0.7)',
|
||||||
mobilePostFormDivider: 'rgba(0, 0, 0, 0.2)',
|
mobilePostFormDivider: 'rgba(0, 0, 0, 0.2)',
|
||||||
mobilePostFormTextareaBg: 'rgba(0, 0, 0, 0.3)',
|
mobilePostFormTextareaBg: 'rgba(0, 0, 0, 0.3)',
|
||||||
|
mobilePostFormButton: '$text',
|
||||||
mobileDriveNavBg: ':alpha<0.75<$secondary',
|
mobileDriveNavBg: ':alpha<0.75<$secondary',
|
||||||
mobileHomeTlItemHover: 'rgba(255, 255, 255, 0.1)',
|
mobileHomeTlItemHover: 'rgba(255, 255, 255, 0.1)',
|
||||||
mobileUserPageName: '#fff',
|
mobileUserPageName: '#fff',
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
name: 'Light',
|
name: 'Light',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
desc: 'Default light theme',
|
desc: 'Default light theme',
|
||||||
|
kind: 'light',
|
||||||
|
|
||||||
vars: {
|
vars: {
|
||||||
primary: '#fb4e4e',
|
primary: '#fb4e4e',
|
||||||
@ -23,13 +24,13 @@
|
|||||||
scrollbarHandleHover: '#00000066',
|
scrollbarHandleHover: '#00000066',
|
||||||
|
|
||||||
face: '$secondary',
|
face: '$secondary',
|
||||||
faceText: '#444',
|
faceText: '$text',
|
||||||
faceHeader: ':lighten<5<$secondary',
|
faceHeader: ':lighten<5<$secondary',
|
||||||
faceHeaderText: '#888',
|
faceHeaderText: '$text',
|
||||||
faceDivider: 'rgba(0, 0, 0, 0.082)',
|
faceDivider: 'rgba(0, 0, 0, 0.082)',
|
||||||
faceTextButton: '#ccc',
|
faceTextButton: ':alpha<0.7<$text',
|
||||||
faceTextButtonHover: '#aaa',
|
faceTextButtonHover: ':alpha<0.7<:darken<7<$text',
|
||||||
faceTextButtonActive: '#999',
|
faceTextButtonActive: ':alpha<0.7<:darken<10<$text',
|
||||||
faceClearButtonHover: 'rgba(0, 0, 0, 0.025)',
|
faceClearButtonHover: 'rgba(0, 0, 0, 0.025)',
|
||||||
faceClearButtonActive: 'rgba(0, 0, 0, 0.05)',
|
faceClearButtonActive: 'rgba(0, 0, 0, 0.05)',
|
||||||
popupBg: ':lighten<5<$secondary',
|
popupBg: ':lighten<5<$secondary',
|
||||||
@ -40,7 +41,7 @@
|
|||||||
renoteGradient: '#edfde2',
|
renoteGradient: '#edfde2',
|
||||||
renoteText: '#9dbb00',
|
renoteText: '#9dbb00',
|
||||||
quoteBorder: '#c0dac6',
|
quoteBorder: '#c0dac6',
|
||||||
noteText: '#717171',
|
noteText: '$text',
|
||||||
noteHeaderName: ':darken<2<$text',
|
noteHeaderName: ':darken<2<$text',
|
||||||
noteHeaderBadgeFg: '#aaa',
|
noteHeaderBadgeFg: '#aaa',
|
||||||
noteHeaderBadgeBg: 'rgba(0, 0, 0, 0.05)',
|
noteHeaderBadgeBg: 'rgba(0, 0, 0, 0.05)',
|
||||||
@ -98,7 +99,7 @@
|
|||||||
|
|
||||||
calendarWeek: '#19a2a9',
|
calendarWeek: '#19a2a9',
|
||||||
calendarSaturdayOrSunday: '#ef95a0',
|
calendarSaturdayOrSunday: '#ef95a0',
|
||||||
calendarDay: '#777',
|
calendarDay: '$text',
|
||||||
|
|
||||||
materBg: 'rgba(0, 0, 0, 0.1)',
|
materBg: 'rgba(0, 0, 0, 0.1)',
|
||||||
|
|
||||||
@ -120,6 +121,9 @@
|
|||||||
mfmTitleBg: 'rgba(0, 0, 0, 0.07)',
|
mfmTitleBg: 'rgba(0, 0, 0, 0.07)',
|
||||||
mfmQuote: ':alpha<0.6<$text',
|
mfmQuote: ':alpha<0.6<$text',
|
||||||
mfmQuoteLine: ':alpha<0.5<$text',
|
mfmQuoteLine: ':alpha<0.5<$text',
|
||||||
|
mfmLink: '$primary',
|
||||||
|
mfmMention: '$primary',
|
||||||
|
mfmHashtag: '$primary',
|
||||||
|
|
||||||
suspendedInfoBg: '#ffdbdb',
|
suspendedInfoBg: '#ffdbdb',
|
||||||
suspendedInfoFg: '#570808',
|
suspendedInfoFg: '#570808',
|
||||||
@ -141,7 +145,7 @@
|
|||||||
|
|
||||||
desktopHeaderBg: ':lighten<5<$secondary',
|
desktopHeaderBg: ':lighten<5<$secondary',
|
||||||
desktopHeaderFg: '$text',
|
desktopHeaderFg: '$text',
|
||||||
desktopHeaderHoverFg: '#7b8c88',
|
desktopHeaderHoverFg: ':darken<7<$text',
|
||||||
desktopHeaderSearchBg: 'rgba(0, 0, 0, 0.05)',
|
desktopHeaderSearchBg: 'rgba(0, 0, 0, 0.05)',
|
||||||
desktopHeaderSearchHoverBg: 'rgba(0, 0, 0, 0.08)',
|
desktopHeaderSearchHoverBg: 'rgba(0, 0, 0, 0.08)',
|
||||||
desktopHeaderSearchFg: '#000',
|
desktopHeaderSearchFg: '#000',
|
||||||
@ -156,9 +160,9 @@
|
|||||||
desktopPostFormTransparentButtonActiveGradientEnd: ':lighten<33<$primary',
|
desktopPostFormTransparentButtonActiveGradientEnd: ':lighten<33<$primary',
|
||||||
desktopRenoteFormFooter: ':lighten<33<$primary',
|
desktopRenoteFormFooter: ':lighten<33<$primary',
|
||||||
desktopTimelineHeaderShadow: 'rgba(0, 0, 0, 0.08)',
|
desktopTimelineHeaderShadow: 'rgba(0, 0, 0, 0.08)',
|
||||||
desktopTimelineSrc: '#6f7477',
|
desktopTimelineSrc: '$text',
|
||||||
desktopTimelineSrcHover: '#525a5f',
|
desktopTimelineSrcHover: ':darken<7<$text',
|
||||||
desktopWindowTitle: '#666',
|
desktopWindowTitle: '$text',
|
||||||
desktopWindowShadow: 'rgba(0, 0, 0, 0.2)',
|
desktopWindowShadow: 'rgba(0, 0, 0, 0.2)',
|
||||||
desktopDriveBg: '#fff',
|
desktopDriveBg: '#fff',
|
||||||
desktopDriveFolderBg: ':lighten<31<$primary',
|
desktopDriveFolderBg: ':lighten<31<$primary',
|
||||||
@ -175,6 +179,7 @@
|
|||||||
mobileNavBackdrop: 'rgba(0, 0, 0, 0.2)',
|
mobileNavBackdrop: 'rgba(0, 0, 0, 0.2)',
|
||||||
mobilePostFormDivider: 'rgba(0, 0, 0, 0.1)',
|
mobilePostFormDivider: 'rgba(0, 0, 0, 0.1)',
|
||||||
mobilePostFormTextareaBg: '#fff',
|
mobilePostFormTextareaBg: '#fff',
|
||||||
|
mobilePostFormButton: '$text',
|
||||||
mobileDriveNavBg: ':alpha<0.75<$secondary',
|
mobileDriveNavBg: ':alpha<0.75<$secondary',
|
||||||
mobileHomeTlItemHover: 'rgba(0, 0, 0, 0.05)',
|
mobileHomeTlItemHover: 'rgba(0, 0, 0, 0.05)',
|
||||||
mobileUserPageName: '#757c82',
|
mobileUserPageName: '#757c82',
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
id: 'e9c8c01d-9c15-48d0-9b5c-3d00843b5b36',
|
id: 'e9c8c01d-9c15-48d0-9b5c-3d00843b5b36',
|
||||||
|
|
||||||
name: 'Strawberry Milk',
|
name: 'Lavender',
|
||||||
author: 'syuilo',
|
author: 'sokuyuku & syuilo',
|
||||||
|
|
||||||
base: 'light',
|
base: 'light',
|
||||||
|
|
||||||
vars: {
|
vars: {
|
||||||
primary: 'rgb(251, 78, 112)',
|
primary: 'rgb(206, 147, 191)',
|
||||||
secondary: 'rgb(255, 218, 240)',
|
secondary: 'rgb(253, 242, 243)',
|
||||||
text: 'rgb(113, 91, 102)',
|
text: 'rgb(161, 139, 146)',
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
renoteGradient: '#ffb1c9',
|
renoteGradient: '#f7e4ec',
|
||||||
renoteText: '#ff588d',
|
renoteText: '$primary',
|
||||||
quoteBorder: '#ff6c9b',
|
quoteBorder: '$primary',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ APIへリクエストすると、レスポンスがストリームから次の
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
type: 'api-res:xxxxxxxxxxxxxxxx',
|
type: 'api:xxxxxxxxxxxxxxxx',
|
||||||
body: {
|
body: {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
type: 'note-updated',
|
type: 'noteUpdated',
|
||||||
body: {
|
body: {
|
||||||
note: {
|
note: {
|
||||||
...
|
...
|
||||||
@ -108,7 +108,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
このように、投稿の情報が更新されると、`note-updated`イベントが流れてくるようになります。`note-updated`イベントが発生するのは、以下の場合です:
|
このように、投稿の情報が更新されると、`noteUpdated`イベントが流れてくるようになります。`noteUpdated`イベントが発生するのは、以下の場合です:
|
||||||
|
|
||||||
- 投稿にリアクションが付いた
|
- 投稿にリアクションが付いた
|
||||||
- 投稿に添付されたアンケートに投票がされた
|
- 投稿に添付されたアンケートに投票がされた
|
||||||
@ -153,7 +153,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
|
|||||||
|
|
||||||
`body`プロパティの中に、投稿情報が含まれています。
|
`body`プロパティの中に、投稿情報が含まれています。
|
||||||
|
|
||||||
### `read_all_notifications`
|
### `readAllNotifications`
|
||||||
|
|
||||||
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
|
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
|
||||||
|
|
||||||
|
@ -127,6 +127,15 @@ export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriv
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packMany = async (
|
||||||
|
files: any[],
|
||||||
|
options?: {
|
||||||
|
detail: boolean
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
return (await Promise.all(files.map(f => pack(f, options)))).filter(x => x != null);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack a drive file for API response
|
* Pack a drive file for API response
|
||||||
*/
|
*/
|
||||||
@ -155,7 +164,11 @@ export const pack = (
|
|||||||
_file = deepcopy(file);
|
_file = deepcopy(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_file) return reject('invalid file arg.');
|
// (データベースの欠損などで)ファイルがデータベース上に見つからなかったとき
|
||||||
|
if (_file == null) {
|
||||||
|
console.warn(`in packaging driveFile: driveFile not found on database: ${_file}`);
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
// rendered target
|
// rendered target
|
||||||
let _target: any = {};
|
let _target: any = {};
|
||||||
|
@ -41,6 +41,13 @@ export async function deleteFavorite(favorite: string | mongo.ObjectID | IFavori
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packMany = async (
|
||||||
|
favorites: any[],
|
||||||
|
me: any
|
||||||
|
) => {
|
||||||
|
return (await Promise.all(favorites.map(f => pack(f, me)))).filter(x => x != null);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack a favorite for API response
|
* Pack a favorite for API response
|
||||||
*/
|
*/
|
||||||
@ -70,5 +77,11 @@ export const pack = (
|
|||||||
// Populate note
|
// Populate note
|
||||||
_favorite.note = await packNote(_favorite.noteId, me);
|
_favorite.note = await packNote(_favorite.noteId, me);
|
||||||
|
|
||||||
|
// (データベースの不具合などで)投稿が見つからなかったら
|
||||||
|
if (_favorite.note == null) {
|
||||||
|
console.warn(`in packaging favorite: note not found on database: ${_favorite.noteId}`);
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
resolve(_favorite);
|
resolve(_favorite);
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@ import { IUser, pack as packUser } from './user';
|
|||||||
import { pack as packApp } from './app';
|
import { pack as packApp } from './app';
|
||||||
import PollVote, { deletePollVote } from './poll-vote';
|
import PollVote, { deletePollVote } from './poll-vote';
|
||||||
import Reaction, { deleteNoteReaction } from './note-reaction';
|
import Reaction, { deleteNoteReaction } from './note-reaction';
|
||||||
import { pack as packFile, IDriveFile } from './drive-file';
|
import { packMany as packFileMany, IDriveFile } from './drive-file';
|
||||||
import NoteWatching, { deleteNoteWatching } from './note-watching';
|
import NoteWatching, { deleteNoteWatching } from './note-watching';
|
||||||
import NoteReaction from './note-reaction';
|
import NoteReaction from './note-reaction';
|
||||||
import Favorite, { deleteFavorite } from './favorite';
|
import Favorite, { deleteFavorite } from './favorite';
|
||||||
@ -220,7 +220,6 @@ export const hideNote = async (packedNote: any, meId: mongo.ObjectID) => {
|
|||||||
packedNote.poll = null;
|
packedNote.poll = null;
|
||||||
packedNote.cw = null;
|
packedNote.cw = null;
|
||||||
packedNote.tags = [];
|
packedNote.tags = [];
|
||||||
packedNote.tagsLower = [];
|
|
||||||
packedNote.geo = null;
|
packedNote.geo = null;
|
||||||
packedNote.isHidden = true;
|
packedNote.isHidden = true;
|
||||||
}
|
}
|
||||||
@ -294,6 +293,9 @@ export const pack = async (
|
|||||||
_note.id = _note._id;
|
_note.id = _note._id;
|
||||||
delete _note._id;
|
delete _note._id;
|
||||||
|
|
||||||
|
delete _note.prev;
|
||||||
|
delete _note.next;
|
||||||
|
delete _note.tagsLower;
|
||||||
delete _note._user;
|
delete _note._user;
|
||||||
delete _note._reply;
|
delete _note._reply;
|
||||||
delete _note._renote;
|
delete _note._renote;
|
||||||
@ -309,9 +311,7 @@ export const pack = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populate files
|
// Populate files
|
||||||
_note.files = Promise.all((_note.fileIds || []).map((fileId: mongo.ObjectID) =>
|
_note.files = packFileMany(_note.fileIds || []);
|
||||||
packFile(fileId)
|
|
||||||
));
|
|
||||||
|
|
||||||
// 後方互換性のため
|
// 後方互換性のため
|
||||||
_note.mediaIds = _note.fileIds;
|
_note.mediaIds = _note.fileIds;
|
||||||
@ -380,6 +380,12 @@ export const pack = async (
|
|||||||
// resolve promises in _note object
|
// resolve promises in _note object
|
||||||
_note = await rap(_note);
|
_note = await rap(_note);
|
||||||
|
|
||||||
|
// (データベースの欠損などで)ユーザーがデータベース上に見つからなかったとき
|
||||||
|
if (_note.user == null) {
|
||||||
|
console.warn(`in packaging note: note user not found on database: note(${_note.id})`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (_note.user.isCat && _note.text) {
|
if (_note.user.isCat && _note.text) {
|
||||||
_note.text = _note.text.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ');
|
_note.text = _note.text.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ');
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,12 @@ export async function deleteNotification(notification: string | mongo.ObjectID |
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packMany = async (
|
||||||
|
notifications: any[]
|
||||||
|
) => {
|
||||||
|
return (await Promise.all(notifications.map(n => pack(n)))).filter(x => x != null);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack a notification for API response
|
* Pack a notification for API response
|
||||||
*/
|
*/
|
||||||
@ -123,6 +129,12 @@ export const pack = (notification: any) => new Promise<any>(async (resolve, reje
|
|||||||
case 'poll_vote':
|
case 'poll_vote':
|
||||||
// Populate note
|
// Populate note
|
||||||
_notification.note = await packNote(_notification.noteId, me);
|
_notification.note = await packNote(_notification.noteId, me);
|
||||||
|
|
||||||
|
// (データベースの不具合などで)投稿が見つからなかったら
|
||||||
|
if (_notification.note == null) {
|
||||||
|
console.warn(`in packaging notification: note not found on database: ${_notification.noteId}`);
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`Unknown type: ${_notification.type}`);
|
console.error(`Unknown type: ${_notification.type}`);
|
||||||
|
@ -361,10 +361,10 @@ export const pack = (
|
|||||||
_user = deepcopy(user);
|
_user = deepcopy(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ユーザーがデータベース上に見つからなかったとき
|
// (データベースの欠損などで)ユーザーがデータベース上に見つからなかったとき
|
||||||
if (_user == null) {
|
if (_user == null) {
|
||||||
console.warn(`user not found on database: ${user}`);
|
console.warn(`user not found on database: ${user}`);
|
||||||
return null;
|
return resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Me
|
// Me
|
||||||
|
@ -2,7 +2,7 @@ import * as mongo from 'mongodb';
|
|||||||
import Notification from './models/notification';
|
import Notification from './models/notification';
|
||||||
import Mute from './models/mute';
|
import Mute from './models/mute';
|
||||||
import { pack } from './models/notification';
|
import { pack } from './models/notification';
|
||||||
import { publishUserStream } from './stream';
|
import { publishMainStream } from './stream';
|
||||||
import User from './models/user';
|
import User from './models/user';
|
||||||
import pushSw from './push-sw';
|
import pushSw from './push-sw';
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export default (
|
|||||||
const packed = await pack(notification);
|
const packed = await pack(notification);
|
||||||
|
|
||||||
// Publish notification event
|
// Publish notification event
|
||||||
publishUserStream(notifiee, 'notification', packed);
|
publishMainStream(notifiee, 'notification', packed);
|
||||||
|
|
||||||
// Update flag
|
// Update flag
|
||||||
User.update({ _id: notifiee }, {
|
User.update({ _id: notifiee }, {
|
||||||
@ -39,7 +39,7 @@ export default (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const fresh = await Notification.findOne({ _id: notification._id }, { isRead: true });
|
const fresh = await Notification.findOne({ _id: notification._id }, { isRead: true });
|
||||||
if (!fresh.isRead) {
|
if (!fresh.isRead) {
|
||||||
@ -54,9 +54,9 @@ export default (
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
publishUserStream(notifiee, 'unread_notification', packed);
|
publishMainStream(notifiee, 'unreadNotification', packed);
|
||||||
|
|
||||||
pushSw(notifiee, 'notification', packed);
|
pushSw(notifiee, 'notification', packed);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user