Compare commits
263 Commits
Author | SHA1 | Date | |
---|---|---|---|
8e9717a5fc | |||
3e28b296e3 | |||
056fef70da | |||
55be9cc9d1 | |||
3f2ffcea97 | |||
b07d037cb5 | |||
4feccdfd92 | |||
f1ef85b636 | |||
cf9266eab9 | |||
4a1552fb3c | |||
e5863c2867 | |||
58211fc6a7 | |||
bd54e44b35 | |||
e1f2e364a4 | |||
186b26e103 | |||
74706a8d2c | |||
7e2b6b6369 | |||
1a2de1a051 | |||
83900cbca6 | |||
166bc19131 | |||
da874f3383 | |||
9c30b23358 | |||
b8350d5093 | |||
58f7af8927 | |||
c3b9c7b74b | |||
9415618992 | |||
1c200c9b94 | |||
ce8fa8e423 | |||
a4b7a9db03 | |||
280eeb9d75 | |||
3f71b14637 | |||
705d40ab37 | |||
b39850de01 | |||
b9c5e95b85 | |||
0c1de7b1b6 | |||
0a4499fd03 | |||
b663a47331 | |||
eb275a62a6 | |||
e18caa3396 | |||
eb15d31ebf | |||
e7f1ab2d01 | |||
9d3beb3174 | |||
b6c3399abe | |||
0a28573845 | |||
937df577f1 | |||
e54fd6c2cb | |||
3caea9d33e | |||
b9e9631195 | |||
76bded455a | |||
c94d9210ed | |||
0f5db9558c | |||
35a8c37922 | |||
6ff84a1061 | |||
aae9bc4cf4 | |||
426c2fa5d1 | |||
dab728278c | |||
7555ab097a | |||
5b5b64d251 | |||
eb84445796 | |||
364bd9ae74 | |||
d4b0761549 | |||
f8e06f12fd | |||
320352bf4b | |||
3c66990263 | |||
7cbe95a1cf | |||
c89abda3fb | |||
90348f4ac7 | |||
08293f368f | |||
d5378dab27 | |||
91648d1bd4 | |||
66d6e71f06 | |||
a0ea5776ab | |||
9b73e897df | |||
debc0086fa | |||
065ec8e170 | |||
11f8d742eb | |||
adf4f5410a | |||
8ff2694cad | |||
191c064611 | |||
d327bb8ff1 | |||
80bebea9e6 | |||
cf3fc97202 | |||
5b28d7bf90 | |||
5f8fb43cc9 | |||
6eff6ee451 | |||
c2ab3a15f4 | |||
a100e13a18 | |||
a591a334ed | |||
ca2e53bd6e | |||
d4b4b61535 | |||
440deb4624 | |||
bbb0130522 | |||
b6a4061097 | |||
48c94907c2 | |||
4fd06369d3 | |||
27a17b467d | |||
c25cf7f89a | |||
ade11aa447 | |||
3799708daf | |||
462204e204 | |||
752669bf5e | |||
b08e3f59d3 | |||
443b45e509 | |||
b2bed61088 | |||
be516d3c1e | |||
f5b41e1fbf | |||
e9afc1d867 | |||
a891f7e862 | |||
b715ea4621 | |||
ea13efe495 | |||
37f862947b | |||
ecb0861be4 | |||
624c9f3418 | |||
1b75984046 | |||
157f1c66dc | |||
cb41391bae | |||
acc88825fc | |||
233a837e35 | |||
9e4456ac1b | |||
83e1068da3 | |||
1fd345f563 | |||
37c16e5b45 | |||
ca25b9acc1 | |||
c3022d38f7 | |||
3599f16d22 | |||
3f78f6f6bb | |||
41f66e4299 | |||
0d36b144cf | |||
aa652aac8a | |||
8dbdab4a47 | |||
90c07a220f | |||
23e2a870cc | |||
dc8eb7d4fe | |||
fd363f5617 | |||
1726ff3977 | |||
93aba74463 | |||
99955f0af9 | |||
30cf154542 | |||
f2c33b06cf | |||
f12473e677 | |||
e845db01bf | |||
7f76a73eee | |||
3c2d94ace3 | |||
1e2239f527 | |||
1851daf9fd | |||
f378f26e5e | |||
cda6bc3404 | |||
071c7e6a58 | |||
010e1b3ba4 | |||
66de51c1ca | |||
265d6bda15 | |||
fecb12bae1 | |||
83ec906ee7 | |||
d44fbf58c9 | |||
9c4a789a4e | |||
bfa1705bad | |||
2876f2188c | |||
579c0043c3 | |||
0fa57957a4 | |||
05cb0b0ec5 | |||
4b24e96dfb | |||
c7eab37177 | |||
c7d0b6cb29 | |||
22ee087bb9 | |||
2480fcdc53 | |||
7e093aee5e | |||
dd8413a485 | |||
925f2912a9 | |||
ed00ea0865 | |||
3f19d221b7 | |||
808271838b | |||
ac0950fdef | |||
38f306ba73 | |||
5c1748d63d | |||
c00cddf5b0 | |||
baf3274748 | |||
9e0515e563 | |||
9c0404c407 | |||
0b85177690 | |||
7ec28ced40 | |||
19ae3b66ec | |||
0118dee3e5 | |||
9201714313 | |||
8b9c1efd7e | |||
111eb43fd9 | |||
f2964101d1 | |||
6b2c289029 | |||
fd2573c068 | |||
df0e9d75fe | |||
2bc86756c8 | |||
fb91ab4080 | |||
0b4d29ed1e | |||
2a8c65e2c3 | |||
ffc7f42efc | |||
7c38cda8ee | |||
d3f5001679 | |||
83d9a4b6d9 | |||
9760e08af4 | |||
8d48e4c76e | |||
a1e0c866aa | |||
8380222baf | |||
eda7d60c26 | |||
ddf92c3e2c | |||
9bb528eb6e | |||
9756957ac1 | |||
af0205b77d | |||
3f0da5453d | |||
923c3071f0 | |||
a8584973e2 | |||
886766cca5 | |||
974abbe826 | |||
61bdf51e90 | |||
9bee9d20f7 | |||
7aee3b88eb | |||
d08184f5fe | |||
ae08232bfb | |||
2b5e4b57bd | |||
35ae13a490 | |||
74f55b4d3f | |||
abe9440021 | |||
6a95b94aaa | |||
21ee38d813 | |||
9681a906d5 | |||
2ca760bee6 | |||
da9f916daa | |||
bc05b83a24 | |||
620e0a9df6 | |||
38ad4f7098 | |||
05c7cacdd1 | |||
baa49271df | |||
e2cbe70966 | |||
6a98301cc9 | |||
81f1df7472 | |||
abc296cdcc | |||
4df5ec82ce | |||
3963ed8ff7 | |||
11141c878c | |||
b1a2046a7f | |||
e44322c9bf | |||
2e6462bf1b | |||
667d9c2be3 | |||
34a86229db | |||
7dd8dbeb5b | |||
b5fb98f01a | |||
f6cfa5cbb4 | |||
c1b95838f6 | |||
6cee608c91 | |||
d979fb6dc0 | |||
ca2a33edc9 | |||
ea80d5eac2 | |||
51cf0970b3 | |||
9c8eb93446 | |||
3ac3a45aa5 | |||
36fcc0d5f6 | |||
6667b86650 | |||
9244efe351 | |||
538ca2a7c7 | |||
c5dd9439d5 | |||
2170c27b62 | |||
61582a0a33 | |||
65efe1f42c | |||
b2d3d43c97 | |||
4ce330c59e |
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [11.10.x, 12.x, 13.x, 14.x]
|
||||
node-version: [12.x, 14.x]
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,7 +12,7 @@ report.*.json
|
||||
# config
|
||||
/.config/*
|
||||
!/.config/example.yml
|
||||
!/.config/mongo_initdb_example.js
|
||||
!/.config/docker_example.env
|
||||
|
||||
# misskey
|
||||
/build
|
||||
|
@ -1 +1 @@
|
||||
v12.11.1
|
||||
v14.4.0
|
||||
|
151
CHANGELOG.md
151
CHANGELOG.md
@ -1,5 +1,156 @@
|
||||
ChangeLog
|
||||
=========
|
||||
12.42.0 (2020/7/19)
|
||||
-------------------
|
||||
*このアップデートでは、データベースのマイグレーション(`npm run migrate`/`yarn migrate`)が必要です。*
|
||||
|
||||
### ✨Improvements
|
||||
- Deckでマウスホイールを使って横スクロールできるように [e18caa3](https://github.com/syuilo/misskey/commit/e18caa339624b566e76d19d0e132028b6377f7f8), [eb275a6](https://github.com/syuilo/misskey/commit/eb275a62a6ae5699b38cf3bca516d34b44e9d944)
|
||||
- 設定画面を整理 [b663a47](https://github.com/syuilo/misskey/commit/b663a47331000b61010ad91fdc422b60b2eeb660)
|
||||
* アクセシビリティ → アピアランス
|
||||
- リモートで削除されており、ローカルで削除されている若しくは未認知のActorからActivityを受信した場合に、エラーでリトライしないように [#6554](https://github.com/syuilo/misskey/pull/6554)
|
||||
- トークン手動発行機能を実装 [0c1de7b](https://github.com/syuilo/misskey/commit/0c1de7b1b6e9ac10b62d8b3157cb064c79aa21d1), [b9c5e95](https://github.com/syuilo/misskey/commit/b9c5e95b855fcf599b339037d4753252a1f786d4)
|
||||
- AiScriptからAPIにアクセスできるように [b39850d](https://github.com/syuilo/misskey/commit/b39850de012fa7b05959c7f4bbbbade841d186ff)
|
||||
- Blurhashを実装 [3f71b14](https://github.com/syuilo/misskey/commit/3f71b1463719bee476d39b7ceca5a2eea4b5cb67)
|
||||
* avgColor, avatarColor, bannerColor は使われなくなります。
|
||||
- デザイン・挙動の調整 [280eeb9](https://github.com/syuilo/misskey/commit/280eeb9d7539e5b7c8d09dfa21a7679eebb09407)
|
||||
|
||||
### 🐛Fixes
|
||||
- AiScriptのアップデートとプラグインの動作の修正 [705d40a](https://github.com/syuilo/misskey/commit/705d40ab37bedb1e43e4677457497c342517a23d)
|
||||
|
||||
12.41.3 (2020/7/15)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- サウンドを追加 [b9e9631](https://github.com/syuilo/misskey/commit/b9e9631195a8ca5ed1386daeacdc835456d52975)
|
||||
|
||||
### 🐛Fixes
|
||||
- サイドバーのsticky動作の修正 [937df57](https://github.com/syuilo/misskey/commit/937df577f1b005ff4da2122e642c5c9f687d0069)
|
||||
- iOS/macOS Safariで投稿フォームやノートメニューをたまに表示できない問題を修正 [9d3beb3](https://github.com/syuilo/misskey/commit/9d3beb3174f87f05c50e2e7304a03d2c55a3f7ec)
|
||||
* windowのstorageイベントが発火すると永続化されたstateのみが残る問題を修正
|
||||
- iOS Safariで設定を選べなくなってしまうことがある問題を修正 [e7f1ab2](https://github.com/syuilo/misskey/commit/e7f1ab2d01f92558ff5e230663d951686390d35a)
|
||||
* Safariのvh計算のバグに対処
|
||||
|
||||
12.41.2 (2020/7/12)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- モーダルにぼかし効果を使用するオプション [aae9bc4c](https://github.com/syuilo/misskey/commit/aae9bc4cf4c583b4d675391fe3da2fa53b7f18e0)
|
||||
- スタイルの調整 [eb84445](https://github.com/syuilo/misskey/commit/eb84445796039b93d124fa615e96c08fedcd9bf9), [dab7282](https://github.com/syuilo/misskey/commit/dab728278ca577622c575d1968eb6a22c7b444b9), [35a8c379](https://github.com/syuilo/misskey/commit/35a8c37922193317b3f6397562c762f9a9169b91)
|
||||
|
||||
### 🐛Fixes
|
||||
- Deckのタイムラインを追加した直後のタイムライン種別の選択がキャンセルできない問題を修正 [#6535](https://github.com/syuilo/misskey/pull/6535)
|
||||
- ノート詳細 /notes/:id ページの直リンを踏むと Not Found になる問題を修正 [364bd9a](https://github.com/syuilo/misskey/commit/364bd9ae74226c46ccdad810884bce11b2bef156)
|
||||
- Deckでメインカラムの「投稿があります」をクリックしても上に行かない問題を修正 [5b5b64d](https://github.com/syuilo/misskey/commit/5b5b64d2514cf445aa81a6750ac4185f4e7dd8cd)
|
||||
- 翻訳の修正 [7555ab0](https://github.com/syuilo/misskey/commit/7555ab097a6aab68851782b641a33fb3fdf2f101), [426c2fa](https://github.com/syuilo/misskey/commit/426c2fa5d152610516337cc5a53810e136d573db)
|
||||
|
||||
12.41.1 (2020/7/12)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- ResizeObserver Polyfillを削除 [c89abda](https://github.com/syuilo/misskey/commit/c89abda3fb55857bb81c4f2163a4a0396a04fc27)
|
||||
* Misskey Webのパフォーマンスが劇的に改善されました
|
||||
- スタイルの調整 [7cbe95a](https://github.com/syuilo/misskey/commit/7cbe95a1cf67f2536a6332bbccc7129afcd92f73), [320352b](https://github.com/syuilo/misskey/commit/320352bf4ba56ddd67c9c6bc0816dab94c53191b)
|
||||
|
||||
### 🐛Fixes
|
||||
- サイドバーのホームを押すことでのトップへのスクロールが動作しなくなっている問題を修正 [3c66990](https://github.com/syuilo/misskey/commit/3c669902632570bb1354f6b53253037f183718b5)
|
||||
|
||||
12.41.0 (2020/7/12)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- デッキの実装 [#6504](https://github.com/syuilo/misskey/pull/6504), [065ec8e](https://github.com/syuilo/misskey/commit/065ec8e17080887814b1912233d38e412b2811d2), [debc008](https://github.com/syuilo/misskey/commit/debc0086fab6c131cf37f00e8b03fbe5d6f09c64)
|
||||
- テーマエディターの実装 [#6482](https://github.com/syuilo/misskey/pull/6482)
|
||||
- プラグインシステムの実装 [#6479](https://github.com/syuilo/misskey/pull/6479)
|
||||
- ウィジェットの位置を固定するオプションを追加 [3799708](https://github.com/syuilo/misskey/commit/3799708daf52c221c03ff0b1c11d8b888b22d32f)
|
||||
- ウィジェットの位置を固定しない場合、Twitterのようにstickyに画面追従するように [c25cf7f](https://github.com/syuilo/misskey/commit/c25cf7f89a1d3d7e55331396bbc3f44920a38de5)
|
||||
- サウンドを追加 (syuilo/pirori) [d4b4b61](https://github.com/syuilo/misskey/commit/d4b4b61535ee4f5f759ba3342b55e978e43f1c7b)
|
||||
- タイムライン上でTwitterの埋め込みプレビューを表示できるように [#6496](https://github.com/syuilo/misskey/pull/6496)
|
||||
- デザインや挙動の調整 [#6495](https://github.com/syuilo/misskey/pull/6495), [752669b](https://github.com/syuilo/misskey/commit/752669bf5ea83b81ddcabb804e795a24debe6dc0), [#6497](https://github.com/syuilo/misskey/pull/6497), [ade11aa](https://github.com/syuilo/misskey/commit/ade11aa447f0102c9202955e01c59fcb501f794e), [27a17b4](https://github.com/syuilo/misskey/commit/27a17b467d72aea81774c04b8ca3e01ed6874b24), [4fd0636](https://github.com/syuilo/misskey/commit/4fd06369d355f032b5eb245dfd98faadee2289f9), [ca2e53b](https://github.com/syuilo/misskey/commit/ca2e53bd6e3de50f2fdf62da16734873be37fcc4), [8ff2694](https://github.com/syuilo/misskey/commit/8ff2694cadd3ab3d51f96fc2ea3bbfde29475660), [11f8d74](https://github.com/syuilo/misskey/commit/11f8d742eb53e8b815abc8ed1c34627dcbaa9e2f)
|
||||
- ソースコードのリファクタ [a591a33](https://github.com/syuilo/misskey/commit/a591a334ed6fd7f8ed936bf7e7edfcce08de035a)
|
||||
|
||||
### 🐛Fixes
|
||||
- 依存パッケージの更新 [#6491](https://github.com/syuilo/misskey/pull/6491), [#6516](https://github.com/syuilo/misskey/pull/6516), [d327bb8](https://github.com/syuilo/misskey/commit/d327bb8ff1b8765e92d6815d244e74f0793f6157)
|
||||
- サーバーへのファイルダウンロードのタイムアウトを11秒から60秒に緩和 [#6503](https://github.com/syuilo/misskey/pull/6503)
|
||||
- 非ログイン時にキーボードショートカットで投稿フォームが開けてしまう問題を修正 [#6508](https://github.com/syuilo/misskey/pull/6508)
|
||||
- キャッシュされてないリモートファイルのURLが相対URLで返ってくる問題を修正 [#6514](https://github.com/syuilo/misskey/pull/6514)
|
||||
* リモートファイルをキャッシュしない設定のインスタンスにおいてサードパーティークライアントでリモートの画像が表示できない問題が修正されます
|
||||
- Mastodon v2.5.0未満からのActivityが受け取れない問題の修正 [#6518](https://github.com/syuilo/misskey/pull/6518)
|
||||
- music.youtube.comのURLプレビューの修正 [#6496](https://github.com/syuilo/misskey/pull/6496)
|
||||
- URLプレビューの翻訳を修正 [#6496](https://github.com/syuilo/misskey/pull/6496)
|
||||
- ノートの表示幅が狭いとTwitterウィジェットがはみ出すのをなんとか修正 [#6496](https://github.com/syuilo/misskey/pull/6496)
|
||||
- HiDPi環境でMisskey v12 Roomの家具を選択できない問題を修正 [#6507](https://github.com/syuilo/misskey/pull/6507)
|
||||
- Safariでの検索インプット・検索ボタンのデザインが適用されないのを修正 [#6484](https://github.com/syuilo/misskey/pull/6484)
|
||||
- フォロワーではないリモートユーザーに削除通知が配信されない問題を修正 [#6475](https://github.com/syuilo/misskey/pull/6475)
|
||||
|
||||
12.40.0 (2020/7/5)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- AP向けのアンケートのfallbackリンク(`リモートで結果を表示`)、`番号を返信して投票`、`_misskey_fallback_content`を削除 [#6466](https://github.com/syuilo/misskey/pull/6466)
|
||||
- 英語のNyaizeを改良 [#6456](https://github.com/syuilo/misskey/pull/6456)
|
||||
- プロフィールの「場所」「誕生日」を連合するように [#6463](https://github.com/syuilo/misskey/pull/6463)
|
||||
- リアクションピッカーの入力で空白を無視するように [90c07a2](https://github.com/syuilo/misskey/commit/90c07a220f1787cd25a17feefe2df667db5b630d)
|
||||
- ウィジェットを左に置けるように [624c9f3](https://github.com/syuilo/misskey/commit/624c9f3418ce1c2597fbe2cb75caf01939e4d845)
|
||||
- ウェルカムウィジェットの追加 [ea13efe](https://github.com/syuilo/misskey/commit/ea13efe495272fcfc9fb29c4f2127e4f908f9802)
|
||||
- 全体的なデザインの変更
|
||||
|
||||
### 🐛Fixes
|
||||
- アカウント切り替え後にインスタンス設定の表示値が変わらないのを修正 [#6454](https://github.com/syuilo/misskey/pull/6454)
|
||||
- isCatがLD-Signatureの対象になってないのを修正 [#6463](https://github.com/syuilo/misskey/pull/6463)
|
||||
- タップ不可能なリアクションを押してもパーティクルが出るのを修正 [#6472](https://github.com/syuilo/misskey/pull/6472)
|
||||
- サイドバーの設定に不具合があるとページが表示できなくなる問題を修正 [#6473](https://github.com/syuilo/misskey/pull/6473)
|
||||
- 投稿詳細でTwitterウィジェットが表示されなくなっているのを修正 [#6488](https://github.com/syuilo/misskey/pull/6488)
|
||||
- 「すべて既読にする」でグループメッセージが既読にならない問題を修正 [#6476](https://github.com/syuilo/misskey/pull/6476)
|
||||
|
||||
12.39.1 (2020/6/5)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
- メンションの色をテーマで指定できるように [071c7e6](https://github.com/syuilo/misskey/commit/071c7e6a581ca5d025d414869e03536011219370)
|
||||
|
||||
### 🐛Fixes
|
||||
- リモートからのノートが受信できない問題を修正 [3c2d94ac](https://github.com/syuilo/misskey/commit/3c2d94ace31c0dbbbd18606d16828df60d0392eb), [7f76a73e](https://github.com/syuilo/misskey/commit/7f76a73eeef5df3b1fc02a00a0ca5710383a2429)
|
||||
* MiAuthのレスポンスが返ってこない問題を修正を差し戻し
|
||||
- ドキュメントのMiAuthのURLを現状利用できるものに修正 [ddf92c3e](https://github.com/syuilo/misskey/commit/ddf92c3e2c5bdfc89e5c223a3cc2794f6a023400), [7f76a73e](https://github.com/syuilo/misskey/commit/7f76a73eeef5df3b1fc02a00a0ca5710383a2429)
|
||||
|
||||
12.39.0 (2020/6/4)
|
||||
-------------------
|
||||
**12.39.0にはリモートからのノートが受信できないという重大なバグがありますので、使わないでください。**
|
||||
**NEVER USE 12.39.0 because it has a serious bug that Misskey cannot recieve notes from remotes.**
|
||||
|
||||
### ✨Improvements
|
||||
- アラビア語を追加 [#6416](https://github.com/syuilo/misskey/pull/6416)
|
||||
- 自動でもっと見る [#6403](https://github.com/syuilo/misskey/pull/6403)
|
||||
- MFMのテキストノードは、HTMLではspanタグではなくテキストノードに変換するように [#6399](https://github.com/syuilo/misskey/pull/6399)
|
||||
- ローカルのみボタンを公開範囲ピッカーに統合 [#6428](https://github.com/syuilo/misskey/pull/6428)
|
||||
- ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブではない時)は通知を既読にしないように [#6407](https://github.com/syuilo/misskey/pull/6407)
|
||||
- 通知一覧で、通知が画面に表示されると既読にするように [#6407](https://github.com/syuilo/misskey/pull/6407)
|
||||
- APIのNotificationでisRead(既読かどうか)を含めるように [#6407](https://github.com/syuilo/misskey/pull/6407)
|
||||
|
||||
### 🐛Fixes
|
||||
- 引用ノートのフォントサイズがおかしいときがあるのを修正 [#6414](https://github.com/syuilo/misskey/pull/6414)
|
||||
- iOS Safari 上で アイコンおよびバナーのアップロードができない不具合を修正 [#6427](https://github.com/syuilo/misskey/pull/6427)
|
||||
- APで `HTTP-Signature検証失敗 かつ LD-Signatureなし` がキューに溜まってリトライし続けるのを修正 [#6437](https://github.com/syuilo/misskey/pull/6437)
|
||||
- MiAuthでトークンが利用できない問題を修正 [6b2c2890](https://github.com/syuilo/misskey/commit/6b2c289029cbf01537c2a67a3e61d615aad30c34)
|
||||
- Twitterのプレビューが利用できなくなっている問題を修正 [f296410](https://github.com/syuilo/misskey/commit/f2964101d162fb64ac9e7ad99123c5bb568ac52b)
|
||||
- IDの重複が起きてしまう問題を修正 [#6440](https://github.com/syuilo/misskey/pull/6440)
|
||||
- ※MiAuthのレスポンスが返ってこない問題を修正 [#6418](https://github.com/syuilo/misskey/issues/6418)
|
||||
|
||||
12.38.0 (2020/5/17)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
* Renoteの削除をわかりやすく [#6366](https://github.com/syuilo/misskey/pull/6366), [#6373](https://github.com/syuilo/misskey/pull/6373)
|
||||
* Unicode 13.0の絵文字に対応 [#6365](https://github.com/syuilo/misskey/pull/6365)
|
||||
* リレーのHTTP-Signatureは投稿者の鍵でするように [#6357](https://github.com/syuilo/misskey/pull/6357)
|
||||
* 追加のAPオブジェクトをキャッシュ出来るように [#6349](https://github.com/syuilo/misskey/pull/6349)
|
||||
* ローカルのみボタンを公開範囲ボタンの横に移動 [51cf097](https://github.com/syuilo/misskey/commit/51cf0970b3b990cd67c94c5fcc5d7c1c3f7f13df)
|
||||
* 公開範囲がローカルのみであることを表示するように [#6291](https://github.com/syuilo/misskey/pull/6291)
|
||||
* Roomに藍ちゃん人形と札束を追加 [#6350](https://github.com/syuilo/misskey/pull/6350), [6cee608](https://github.com/syuilo/misskey/commit/6cee608c91850c035c35f605296410e72d1ef793), [7dd8dbe](https://github.com/syuilo/misskey/commit/7dd8dbeb5b2f33b679248ecc2138f556b72d9a06)
|
||||
* ユーザーページの画像欄の画像をクリックしたとき、UIが再読み込みされないように [ca2a33e](https://github.com/syuilo/misskey/commit/ca2a33edc928c0dfe59f50502d3eedb9e97e88db)
|
||||
|
||||
### 🐛Fixes
|
||||
* reCAPTCHAが動かなくなっているのを修正 [#6367](https://github.com/syuilo/misskey/pull/6367)
|
||||
* インスタンスブロックがリレーに適用されない問題を修正 [#6355](https://github.com/syuilo/misskey/pull/6355)
|
||||
* リレーに不正なURLを追加できてしまう問題を修正 [#6351](https://github.com/syuilo/misskey/pull/6351)
|
||||
* Pages: Mk:api関数にトークンを渡せない問題を修正 [9244efe](https://github.com/syuilo/misskey/commit/9244efe3513dd72be04d7588dea8ec27509e96d1)
|
||||
* nyaizeが適用されるとMFMのオプションが失われるのを修正 [#6371](https://github.com/syuilo/misskey/pull/6371)
|
||||
* 上流ノートの削除に伴うノートの削除が連合リレーに伝達されない問題を修正 [#6374](https://github.com/syuilo/misskey/pull/6374)
|
||||
* 引用元の削除に伴う引用RNの削除がリモートに伝達されない問題を修正 [#6374](https://github.com/syuilo/misskey/pull/6374)
|
||||
|
||||
12.37.0 (2020/5/10)
|
||||
-------------------
|
||||
|
@ -1,6 +1,12 @@
|
||||
# Contribution guide
|
||||
:v: Thanks for your contributions :v:
|
||||
|
||||
## When you contribute...
|
||||
- 任意のIssueについて、せっかく実装してくださっても、実装方法や設計の認識が揃ってないとマージできない/しないことになりかねないので、初めにそのIssue上で着手することを宣言し、必要に応じて他メンバーと実装方法や設計のすり合わせを行ってください。宣言することは作業が他の人と被るのを防止する効果もあります。
|
||||
- 設計に迷った時はプロジェクトリーダーの判断を仰いでください。
|
||||
- 時間や優先度の都合上、提出してくださったPRが長期間放置されることもありますがご理解ください。
|
||||
- 温度感高めで見てほしいものは責付いてください。
|
||||
|
||||
## Issues
|
||||
Feature suggestions and bug reports are filed in https://github.com/syuilo/misskey/issues .
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM node:14.2.0-alpine AS base
|
||||
FROM node:14.4.0-alpine AS base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
|
26
README.md
26
README.md
@ -114,6 +114,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weepjp " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/605366/c9dc408fdcbf412fb183ca5b06235f8d/1.jpeg?token-time=2145916800&token-hash=oaqsjLqOFjWN5I9hm2epOaTXaEtKwQUy5OW-EpAz6-g%3D" alt="Jon Leibowitz" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19045173/cb91c0f345c24d4ebfd05f19906d5e26/1.png?token-time=2145916800&token-hash=o_zKBytJs_AxHwSYw_5R8eD0eSJe3RoTR3kR3Q0syN0%3D" alt="kiritan " width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/27648259" alt="みなしま " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/24430516/b1964ac5b9f746d2a12ff53dbc9aa40a/1.jpg?token-time=2145916800&token-hash=bmEiMGYpp3bS7hCCbymjGGsHBZM3AXuBOFO3Kro37PU%3D" alt="Eduardo Quiros" width="100"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=20832595">Roujo </a></td>
|
||||
@ -121,10 +122,12 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/weepjp">weepjp </a></td>
|
||||
<td><a href="https://www.patreon.com/jonleibowitz">Jon Leibowitz</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=19045173">kiritan </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=27648259">みなしま </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=24430516">Eduardo Quiros</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<td><img src="https://c8.patreon.com/2/200/776209" alt="Denshi " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/14215107/1cbe1912c26143919fa0faca16f12ce1/4.jpg?token-time=2145916800&token-hash=BslMqDjTjz8KYANLvxL87agHTugHa0dMPUzT-hwR6Vk%3D" alt="Nesakko" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/776209" alt="Demogrognard" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/3075183/c2ae575c604e420297f000ccc396e395/1.jpeg?token-time=2145916800&token-hash=O9qmPtpo6wWb0OuvnkEekhk_1WO2MTdytLr7ZgsAr80%3D" alt="Liaizon Wakest" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/557245" alt="mkatze " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/23915207/25428766ecd745478e600b3d7f871eb2/1.png?token-time=2145916800&token-hash=urCLLA4KjJZX92Y1CxcBP4d8bVTHGkiaPnQZp-Tqz68%3D" alt="kabo2468y " width="100"></td>
|
||||
@ -133,9 +136,9 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1.jpg?token-time=2145916800&token-hash=mPLM9CA-riFHx-myr3bLZJuH2xBRHA9se5VbHhLIOuA%3D" alt="osapon " width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18899730/6a22797f68254034a854d69ea2445fc8/1.png?token-time=2145916800&token-hash=b_uj57yxo5VzkSOUS7oXE_762dyOTB_oxzbO6lFNG3k%3D" alt="YuzuRyo61 " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5788159/af42076ab3354bb49803cfba65f94bee/1.jpg?token-time=2145916800&token-hash=iSaxp_Yr2-ZiU2YVi9rcpZZj9mj3UvNSMrZr4CU4qtA%3D" alt="mewl hayabusa" width="100"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=776209">Denshi </a></td>
|
||||
<td><a href="https://www.patreon.com/Nesakko">Nesakko</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=776209">Demogrognard</a></td>
|
||||
<td><a href="https://www.patreon.com/wakest">Liaizon Wakest</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=557245">mkatze </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=23915207">kabo2468y </a></td>
|
||||
@ -144,9 +147,9 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/osapon">osapon </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ </a></td>
|
||||
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61 </a></td>
|
||||
<td><a href="https://www.patreon.com/hs_sh_net">mewl hayabusa</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5788159/af42076ab3354bb49803cfba65f94bee/1.jpg?token-time=2145916800&token-hash=iSaxp_Yr2-ZiU2YVi9rcpZZj9mj3UvNSMrZr4CU4qtA%3D" alt="mewl hayabusa" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/28779508/3cd4cb7f017f4ee0864341e3464d42f9/1.png?token-time=2145916800&token-hash=eGQtR15be44kgvh8fw2Jx8Db4Bv15YBp2ldxh0EKRxA%3D" alt="S Y" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin " width="100"></td>
|
||||
@ -154,9 +157,8 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/26340354/08834cf767b3449e93098ef73a434e2f/2.png?token-time=2145916800&token-hash=nyM8DnKRL8hR47HQ619mUzsqVRpkWZjgtgBU9RY15Uc%3D" alt="totokoro " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5827393/59893c191dda408f9cabd0f20a3a5627/1.jpeg?token-time=2145916800&token-hash=i9N05vOph-eP1LTLb9_npATjYOpntL0ZsHNaZFSsPmE%3D" alt="motcha " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/20494440/540beaf2445f408ea6597bc61e077bb3/1.png?token-time=2145916800&token-hash=UJ0JQge64Bx9XmN_qYA1inMQhrWf4U91fqz7VAKJeSg%3D" alt="axtuki1 " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/hs_sh_net">mewl hayabusa</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=28779508">S Y</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin </a></td>
|
||||
@ -164,10 +166,10 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/user?u=26340354">totokoro </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=5827393">motcha </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=20494440">axtuki1 </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/20494440/540beaf2445f408ea6597bc61e077bb3/1.png?token-time=2145916800&token-hash=UJ0JQge64Bx9XmN_qYA1inMQhrWf4U91fqz7VAKJeSg%3D" alt="axtuki1 " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpg?token-time=2145916800&token-hash=nVAntpybQrznE0rg05keLrSE6ogPKJXB13rmrJng42c%3D" alt="takimura " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13100201/fc5be4fa90444f09a9c8a06f72385272/1.png?token-time=2145916800&token-hash=i8PjlgfOB2LPEdbtWyx8ZPsBKhGcNZqcw_FQmH71UGU%3D" alt="aqz tamaina" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/28295158/cd2451bfb94a449dbf705ef4718cd355/2.jpeg?token-time=2145916800&token-hash=MRv3BxufHPuCyiBSxU5UYmLGvD6YZlhtSFRfMWg2k4U%3D" alt="012 " width="100"></td>
|
||||
@ -178,8 +180,9 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5923936/2a743cbfbff946c2af3f09026047c0da/2.png?token-time=2145916800&token-hash=h6yphW1qnM0n_NOWaf8qtszMRLXEwIxfk5beu4RxdT0%3D" alt="noellabo " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpg?token-time=2145916800&token-hash=7bkMqTwHPRsJPGAq42PYdDXDZBVGLqdgr1ZmBxX8GFQ%3D" alt="Hekovic " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/24641572/b4fd175424814f15b0ca9178d2d2d2e4/1.png?token-time=2145916800&token-hash=e2fyqdbuJbpCckHcwux7rbuW6OPkKdERcus0u2wIEWU%3D" alt="uroco @99" width="100"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=20494440">axtuki1 </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
|
||||
<td><a href="https://www.patreon.com/takimura">takimura </a></td>
|
||||
<td><a href="https://www.patreon.com/aqz">aqz tamaina</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=28295158">012 </a></td>
|
||||
@ -190,21 +193,22 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
<td><a href="https://www.patreon.com/noellabo">noellabo </a></td>
|
||||
<td><a href="https://www.patreon.com/Corset">CG </a></td>
|
||||
<td><a href="https://www.patreon.com/hekovic">Hekovic </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=24641572">uroco @99</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/24641572/b4fd175424814f15b0ca9178d2d2d2e4/1.png?token-time=2145916800&token-hash=e2fyqdbuJbpCckHcwux7rbuW6OPkKdERcus0u2wIEWU%3D" alt="uroco @99" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
|
||||
<td><img src="https://c8.patreon.com/2/200/23932002" alt="nenohi " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/9481273/7fa89168e72943859c3d3c96e424ed31/4.jpeg?token-time=2145916800&token-hash=5w1QV1qXe-NdWbdFmp1H7O_-QBsSiV0haumk3XTHIEg%3D" alt="Efertone " width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%3D" alt="Takashi Shibuya" width="100"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=24641572">uroco @99</a></td>
|
||||
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=23932002">nenohi </a></td>
|
||||
<td><a href="https://www.patreon.com/efertone">Efertone </a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Thu, 07 May 2020 18:00:08 UTC
|
||||
**Last updated:** Tue, 02 Jun 2020 00:00:08 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
[backer-url]: #backers
|
||||
|
@ -53,7 +53,6 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Accept-Encoding "";
|
||||
proxy_http_version 1.1;
|
||||
proxy_redirect off;
|
||||
|
||||
|
@ -22,8 +22,8 @@ adduser --disabled-password --disabled-login misskey
|
||||
Please install and setup these softwares:
|
||||
|
||||
#### Dependencies :package:
|
||||
* **[Node.js](https://nodejs.org/en/)** >= 11.10.1
|
||||
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
||||
* **[Node.js](https://nodejs.org/en/)** (12.x, 14.x)
|
||||
* **[PostgreSQL](https://www.postgresql.org/)** (>= 10)
|
||||
* **[Redis](https://redis.io/)**
|
||||
|
||||
##### Optional
|
||||
|
@ -22,8 +22,8 @@ adduser --disabled-password --disabled-login misskey
|
||||
Installez les paquets suivants :
|
||||
|
||||
#### Dépendences :package:
|
||||
* **[Node.js](https://nodejs.org/en/)** >= 11.10.1
|
||||
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
||||
* **[Node.js](https://nodejs.org/en/)** (12.x, 14.x)
|
||||
* **[PostgreSQL](https://www.postgresql.org/)** (>= 10)
|
||||
* **[Redis](https://redis.io/)**
|
||||
|
||||
##### Optionnels
|
||||
|
@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
|
||||
これらのソフトウェアをインストール・設定してください:
|
||||
|
||||
#### 依存関係 :package:
|
||||
* **[Node.js](https://nodejs.org/en/)** (11.10.1以上)
|
||||
* **[Node.js](https://nodejs.org/en/)** (12.x, 14.x)
|
||||
* **[PostgreSQL](https://www.postgresql.org/)** (10以上)
|
||||
* **[Redis](https://redis.io/)**
|
||||
|
||||
|
@ -11,7 +11,7 @@ const cleanCSS = require('gulp-clean-css');
|
||||
const sass = require('gulp-dart-sass');
|
||||
const fiber = require('fibers');
|
||||
|
||||
const locales = require('./locales');
|
||||
const locales: { [x: string]: any } = require('./locales');
|
||||
const meta = require('./package.json');
|
||||
|
||||
gulp.task('build:ts', () => {
|
||||
@ -31,8 +31,10 @@ gulp.task('build:copy:views', () =>
|
||||
gulp.task('build:copy:locales', cb => {
|
||||
fs.mkdirSync('./built/client/assets/locales', { recursive: true });
|
||||
|
||||
const v = { '_version_': meta.version };
|
||||
|
||||
for (const [lang, locale] of Object.entries(locales)) {
|
||||
fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify(locale), 'utf-8');
|
||||
fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify({ ...locale, ...v }), 'utf-8');
|
||||
}
|
||||
|
||||
cb();
|
||||
|
510
locales/ar-SA.yml
Normal file
510
locales/ar-SA.yml
Normal file
@ -0,0 +1,510 @@
|
||||
---
|
||||
_lang_: "العربية"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "البحث"
|
||||
notifications: "الإشعارات"
|
||||
username: "اسم المستخدم"
|
||||
password: "الكلمة السرية"
|
||||
fetchingAsApObject: "جارٍ جلبه مِن الفديفرس…"
|
||||
ok: " حسناً"
|
||||
gotIt: "فهِمت"
|
||||
cancel: " إلغاء"
|
||||
enterUsername: "أدخِل إسم مسخدم"
|
||||
noNotes: "لم يتم العثور على أية ملاحظات"
|
||||
noNotifications: "ليس هناك أية اشعارات"
|
||||
instance: "مثيل الخادم"
|
||||
settings: "الاعدادات"
|
||||
profile: "الملف التعريفي"
|
||||
timeline: "الخيط الزمني"
|
||||
login: "لِج"
|
||||
loggingIn: "جارٍ تسجيل الدخول"
|
||||
logout: "الخروج"
|
||||
signup: "أنشئ حسابًا"
|
||||
uploading: "عملية الإرسال جارية"
|
||||
save: "حفظ"
|
||||
users: "المستخدمون"
|
||||
addUser: "اضافة مستخدم"
|
||||
favorite: "إضافة إلى المفضلة"
|
||||
favorites: "المفضلات"
|
||||
unfavorite: "إزالة من المفضلة"
|
||||
pin: "دبّسها على الصفحة الشخصية"
|
||||
copyContent: "انسخ المحتوى"
|
||||
copyLink: "انسخ الرابط"
|
||||
delete: "حذف"
|
||||
deleteAndEdit: "إزالة وإعادة الصياغة"
|
||||
addToList: "أضفه إلى قائمة"
|
||||
sendMessage: "أرسل رسالة"
|
||||
copyUsername: "انسخ اسم المستخدم"
|
||||
reply: "رد"
|
||||
loadMore: "عرض المزيد"
|
||||
youGotNewFollower: "يتابعك"
|
||||
mentions: "الإشارات"
|
||||
directNotes: "الملاحظات المباشرة"
|
||||
import: "استيراد"
|
||||
export: "تصدير"
|
||||
files: "الملفات"
|
||||
download: "تنزيل"
|
||||
lists: "القوائم"
|
||||
noLists: "ليس لديك أية قائمة"
|
||||
note: "ملاحظة"
|
||||
notes: "الملاحظات"
|
||||
following: "المتابَعون"
|
||||
followers: "المتابِعين"
|
||||
followsYou: "يتابعك"
|
||||
createList: "إنشاء قائمة"
|
||||
manageLists: "إدارة القوائم"
|
||||
error: "حدث خطأ ما"
|
||||
retry: "حاول مجددًا"
|
||||
enterListName: "اسم القائمة"
|
||||
privacy: "الخصوصية"
|
||||
makeFollowManuallyApprove: "القبول يدويا طلبات الإشتراك"
|
||||
defaultNoteVisibility: "مدى الرؤية الافتراضي"
|
||||
follow: "تابِع"
|
||||
followRequest: "طلب اشتراك"
|
||||
followRequests: "طلبات الإشتراك"
|
||||
unfollow: "إلغاء الاشتراك"
|
||||
followRequestPending: "طلبات الإشتراك المعلّقة"
|
||||
unrenote: "إلغاء مشاركة الملاحظة"
|
||||
quote: "اقتبس"
|
||||
pinnedNote: "ملاحظة مدبسة"
|
||||
you: "أنت"
|
||||
clickToShow: "اضغط للعرض"
|
||||
sensitive: "محتوى حساس"
|
||||
add: "إضافة"
|
||||
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
|
||||
enterFileName: "ادخل اسم الملف"
|
||||
mute: "اكتم"
|
||||
unmute: "إلغاء الكتم"
|
||||
block: "احجب"
|
||||
unblock: "إلغاء الحجب"
|
||||
selectList: "اختر قائمة"
|
||||
customEmojis: "إيموجي مخصص"
|
||||
addEmoji: "إضافة إيموجي"
|
||||
addAcount: "إضافة حساب"
|
||||
showOnRemote: "رؤيته على مثيل الخادم البُعدي"
|
||||
general: "الرئيسية"
|
||||
wallpaper: "خلفية الشاشة"
|
||||
setWallpaper: "استخدم خلفية الشاشة"
|
||||
removeWallpaper: "إزالة خلفية الشاشة"
|
||||
searchWith: "البحث: {q}"
|
||||
youHaveNoLists: "لا تمتلك أية قائمة"
|
||||
proxyAccount: "حساب وكيل البروكسي"
|
||||
host: "المضيف"
|
||||
selectUser: "حدّد مستخدمًا"
|
||||
recipient: "المرسَل إليه·ها"
|
||||
annotation: "التعليقات"
|
||||
federation: "الفديرالية"
|
||||
instances: "مثيل الخادم"
|
||||
latestRequestSentAt: "آخر طلب أرسِل في"
|
||||
charts: "المنحنيات البيانية"
|
||||
perHour: "في الساعة"
|
||||
perDay: "في اليوم"
|
||||
stopActivityDelivery: "وقف إرسال النشاط"
|
||||
blockThisInstance: "احجب مثيل الخادم هذا"
|
||||
operations: "الإجراءات"
|
||||
software: "البرنامج"
|
||||
version: "الإصدار"
|
||||
metadata: "البيانات الوصفية"
|
||||
withNFiles: "{n} ملف (ملفات)"
|
||||
monitor: "شاشة التحكم"
|
||||
jobQueue: "قائمة الانتظار"
|
||||
cpuAndMemory: "وحدة المعالجة المركزية والذاكرة"
|
||||
network: "الشبكة"
|
||||
disk: "قرص التخزين"
|
||||
instanceInfo: "معلومات مثيل الخادم"
|
||||
statistics: "الإحصائيات"
|
||||
clearQueue: "تفريغ قائمة الإنتظار"
|
||||
muteAndBlock: "تم كتمها / تم حجبها"
|
||||
mutedUsers: "الحسابات التي تم كتمها"
|
||||
blockedUsers: "الحسابات التي تم حظرها"
|
||||
noUsers: "ليس هناك مستخدمون"
|
||||
editProfile: "تعديل الملف التعريفي"
|
||||
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
|
||||
pinLimitExceeded: "لا يمكنك تدبيس الملاحظات بعد الآن."
|
||||
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
|
||||
done: "تمّ"
|
||||
processing: "المعالجة جارية"
|
||||
preview: "معاينة"
|
||||
default: "افتراضي"
|
||||
noCustomEmojis: "ليس هناك إيموجيات"
|
||||
customEmojisOfRemote: "الإيموجيات القادمة مِن مثيلات الخوادم الأخرى"
|
||||
federating: "الفديرالية جارية"
|
||||
blocked: "محجوب"
|
||||
suspended: "مُعلّق"
|
||||
all: "الكل"
|
||||
notResponding: "لا يستجيب"
|
||||
changePassword: "تغيير الكلمة السرية"
|
||||
security: "الأمان"
|
||||
more: "المزيد!"
|
||||
featured: "المتداولة"
|
||||
usernameOrUserId: "اسم المستخدم أو معرّفه"
|
||||
noSuchUser: "لم يُعثَر على المستخدم"
|
||||
lookup: "البحث"
|
||||
announcements: "الإعلانات"
|
||||
imageUrl: "عنوان URL للصورة"
|
||||
remove: "حذف"
|
||||
removed: "تم حذفه بنجاح"
|
||||
removeAreYouSure: "متأكد من أنك تريد حذف {x}؟"
|
||||
saved: "تم حفظه"
|
||||
messaging: "الدردشة"
|
||||
upload: "تحميل"
|
||||
fromDrive: "من المخزن"
|
||||
fromUrl: "من عنوان URL"
|
||||
uploadFromUrl: "التحميل عبر URL"
|
||||
explore: "استكشاف"
|
||||
games: "ألعاب Misskey"
|
||||
messageRead: "مقروءة"
|
||||
startMessaging: "ابدأ الدردشة"
|
||||
tos: "شروط الخدمة"
|
||||
start: "البداية"
|
||||
home: "الرئيسي"
|
||||
activity: "النشاط"
|
||||
images: "الصور"
|
||||
birthday: "تاريخ الميلاد"
|
||||
yearsOld: "{age} سنة"
|
||||
registeredDate: "انظم في"
|
||||
location: "المكان"
|
||||
theme: "المظهر"
|
||||
themeForLightMode: "الحلة في الوضع الفاتح"
|
||||
themeForDarkMode: "الحلة في الوضع الداكن"
|
||||
light: "فاتح"
|
||||
dark: "داكن"
|
||||
lightThemes: "الحلة الفاتحة"
|
||||
darkThemes: "الحلة الداكنة"
|
||||
drive: "قرص التخرين"
|
||||
fileName: "اسم الملف"
|
||||
selectFile: "اختر ملفًا"
|
||||
selectFiles: "اختر ملفات"
|
||||
selectFolder: "اختر مجلدًا"
|
||||
selectFolders: "اختر مجلدات"
|
||||
renameFile: "إعادة تسمية الملف"
|
||||
folderName: "اسم المجلد"
|
||||
createFolder: "أنشئ مجلدًا"
|
||||
renameFolder: "إعادة تسمية المجلد"
|
||||
deleteFolder: "احذف هذا المجلد"
|
||||
addFile: "إضافة ملف"
|
||||
emptyDrive: "قرص التخزين فارغ"
|
||||
emptyFolder: "هذا المجلد فارغ"
|
||||
unableToDelete: "لا يمكن حذفه"
|
||||
inputNewFileName: "ادخل الإسم الجديد للملف"
|
||||
inputNewFolderName: "ادخل الإسم الجديد للمجلد"
|
||||
copyUrl: "انسخ عنوان URL"
|
||||
rename: "إعادة التسمية"
|
||||
avatar: "الصورة الرمزية"
|
||||
banner: "الصورة الرأسية"
|
||||
nsfw: "محتوى حساس"
|
||||
disconnectedFromServer: "قُطِع الإتصال بالخادم"
|
||||
reload: "انعش"
|
||||
doNothing: "تجاهل"
|
||||
watch: "راقب"
|
||||
unwatch: "إلغاء المراقبة"
|
||||
accept: "السماح"
|
||||
reject: "رفض"
|
||||
normal: "عادي"
|
||||
instanceName: "اسم مثيل الخادم"
|
||||
instanceDescription: "وصف مثيل الخادم"
|
||||
maintainerName: "المدير"
|
||||
maintainerEmail: "عنوان بريد المدير الإلكتروني"
|
||||
tosUrl: "عنوان URL لشروط الخدمة"
|
||||
thisYear: "هذا العام"
|
||||
thisMonth: "هذا الشهر"
|
||||
today: "اليوم"
|
||||
dayX: "{day}"
|
||||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "الصفحات"
|
||||
connectSerice: "أوصل"
|
||||
disconnectSerice: "قطع الاتصال"
|
||||
enableLocalTimeline: "تفعيل الخيط المحلي"
|
||||
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
|
||||
registration: "إنشاء حساب"
|
||||
enableRegistration: "تفعيل إنشاء الحسابات الجديدة"
|
||||
invite: "دعوة"
|
||||
basicInfo: "المعلومات الأساسية "
|
||||
hcaptchaSiteKey: "مفتاح الموقع"
|
||||
hcaptchaSecretKey: "المفتاح السري"
|
||||
recaptcha: "reCAPTCHA"
|
||||
enableRecaptcha: "تمكين reCAPTCHA"
|
||||
recaptchaSiteKey: "مفتاح الموقع"
|
||||
recaptchaSecretKey: "المفتاح السري"
|
||||
antennas: "الهوائيات"
|
||||
manageAntennas: "إدارة الهوائيات"
|
||||
name: "الإسم"
|
||||
antennaSource: "مصدر الهوائي"
|
||||
antennaKeywords: "الكلمات المفتاحية للإستقبال"
|
||||
withReplies: "بالردود"
|
||||
notesAndReplies: "الملاحظات والردود"
|
||||
withFiles: "بالمرفقات"
|
||||
silence: "اكتم"
|
||||
unsilence: "إلغاء الكتم"
|
||||
popularUsers: "المستخدمون الشائعون"
|
||||
exploreFediverse: "استكشف الفديفرس"
|
||||
popularTags: "الوسوم الرائجة"
|
||||
userList: "القوائم"
|
||||
about: "عن"
|
||||
aboutMisskey: "عن Misskey"
|
||||
patrons: "الداعمون"
|
||||
administrator: "المدير"
|
||||
token: "الرمز المميز"
|
||||
twoStepAuthentication: "الإستيثاق بعاملَيْن"
|
||||
moderator: "مشرِف"
|
||||
nUsersMentioned: "{n} مستخدمين تمت الإشارة إليهم"
|
||||
securityKey: "مفتاح الأمان"
|
||||
securityKeyName: "اسم المفتاح"
|
||||
lastUsed: "آخر استخدام"
|
||||
unregister: "إلغاء التسجيل"
|
||||
passwordLessLogin: "لِج مِن دون كلمة سرية"
|
||||
resetPassword: "أعد تعيين كلمتك السرية"
|
||||
newPasswordIs: "كلمتك السرية الجديدة هي {password}"
|
||||
autoReloadWhenDisconnected: "إنعاش تلقائي عندما يُقطَع الإتصال بالخادم"
|
||||
autoNoteWatch: "راقب الملاحظات تلقائيا"
|
||||
share: "شارِك"
|
||||
notFound: "غير موجود"
|
||||
help: "المساعدة"
|
||||
inputMessageHere: "اكتب رسالتك هنا"
|
||||
close: "اغلق"
|
||||
group: "الفريق"
|
||||
groups: "الفِرَق"
|
||||
createGroup: "انشئ فريقًا"
|
||||
invites: "دعوة"
|
||||
groupName: "اسم الفريق"
|
||||
members: "الأعضاء"
|
||||
transfer: "نقل"
|
||||
messagingWithUser: "الدردشة مع مستخدم آخر"
|
||||
messagingWithGroup: "دردشة جماعية"
|
||||
title: "العنوان"
|
||||
text: "النص"
|
||||
enable: "تشغيل"
|
||||
next: "التالية"
|
||||
retype: "أعد الكتابة"
|
||||
noteOf: "ملاحظات {user}"
|
||||
inviteToGroup: "دعوة إلى فريق"
|
||||
noMessagesYet: "ليس هناك رسائل بعد"
|
||||
newMessageExists: "لقد تلقيت رسالة جديدة"
|
||||
invitationCode: "رمز الدعوة"
|
||||
checking: "التحقق جارٍ"
|
||||
available: "متوفر"
|
||||
unavailable: "غير متوفر"
|
||||
tooShort: "قصير جدًا"
|
||||
tooLong: "طويل جدًا"
|
||||
weakPassword: "الكلمة السرية ضعيفة"
|
||||
normalPassword: "الكلمة السرية جيدة"
|
||||
strongPassword: "الكلمة السرية قوية"
|
||||
passwordMatched: "التطابق صحيح!"
|
||||
passwordNotMatched: "غير متطابقتان"
|
||||
signinWith: "الولوج عبر {x}"
|
||||
or: "أو"
|
||||
uiLanguage: "لغة واجهة المستخدم"
|
||||
aboutX: "عن {x}"
|
||||
useOsNativeEmojis: "استخدم الإيموجيات الخاصة بنظام التشغيل"
|
||||
youHaveNoGroups: "لا تمتلك أية فِرَق"
|
||||
noHistory: "السجل فارغ"
|
||||
doing: "انتظر لحظة"
|
||||
category: "الفئات"
|
||||
tags: "الوسوم"
|
||||
docSource: "مصدر هذا المستند"
|
||||
createAccount: "أنشئ حسابًا"
|
||||
existingAcount: "الحسابات الموجودة"
|
||||
regenerate: "أعِد التوليد"
|
||||
fontSize: "حجم الخط"
|
||||
dashboard: "لوحة التحكم"
|
||||
local: "المحلي"
|
||||
remote: "بُعدي"
|
||||
total: "المجموع"
|
||||
weekOverWeekChanges: "أسبوعيا"
|
||||
dayOverDayChanges: "يوميا"
|
||||
appearance: "المظهر"
|
||||
clinetSettings: "إعدادات التطبيق"
|
||||
accountSettings: "إعدادات الحساب"
|
||||
promotion: "ترقية"
|
||||
promote: "روِّج"
|
||||
numberOfDays: "عدد الأيام"
|
||||
hideThisNote: "إخفاء هذه الملاحظة"
|
||||
deleteAll: "حذف الكل"
|
||||
sounds: "الرنات"
|
||||
listen: "استمع"
|
||||
none: "لا شيء"
|
||||
volume: "مستوى الصوت"
|
||||
details: "التفاصيل"
|
||||
chooseEmoji: "اختر إيموجي"
|
||||
recentUsed: "المستخدمة مؤخرا"
|
||||
install: "التثبيت"
|
||||
uninstall: "إلغاء التثبيت"
|
||||
installedApps: "التطبيقات المُخوّلة"
|
||||
lastUsedDate: "آخر استخدام"
|
||||
state: "الحالة"
|
||||
sort: "ترتيب حسب"
|
||||
output: "الخارجة"
|
||||
updateRemoteUser: "تحديث المعلومات عن المستخدم البعيد"
|
||||
sidebar: "الشريط الجانبي"
|
||||
addItem: "إضافة عنصر"
|
||||
rooms: "الغرفة"
|
||||
relays: "المُرَحلات"
|
||||
addRelay: "إضافة مُرحّل"
|
||||
addedRelays: "المرحلات التي تم إضافتها"
|
||||
deletedNote: "ملاحظة محذوفة"
|
||||
invisibleNote: "ملاحظة مخفية"
|
||||
poll: "استطلاع رأي"
|
||||
themeEditor: "مصمم القوالب"
|
||||
plugins: "الإضافات"
|
||||
pluginInstallWarn: "يرجى تنصيب إضافات ذات مصدر موثوق منه فقط."
|
||||
smtpHost: "المضيف"
|
||||
smtpUser: "اسم المستخدم"
|
||||
smtpPass: "الكلمة السرية"
|
||||
_theme:
|
||||
explore: "استكشف قوالب المظهر"
|
||||
install: "تنصيب قالب"
|
||||
manage: "إدارة القوالب"
|
||||
code: "شيفرة القالب"
|
||||
installed: "تم تنصيب {name}"
|
||||
make: "إنشاء قالب"
|
||||
alpha: "الشفافية"
|
||||
keys:
|
||||
messageBg: "خلفية الدردشة"
|
||||
_sfx:
|
||||
note: "الملاحظات"
|
||||
noteMy: "ملاحظتي"
|
||||
notification: "الإشعارات"
|
||||
chat: "الدردشة"
|
||||
_ago:
|
||||
unknown: "مجهول"
|
||||
future: "المستقبَل"
|
||||
justNow: "اللحظة"
|
||||
secondsAgo: "منذ {n} ثوانٍ"
|
||||
minutesAgo: "منذ {n} دقائق"
|
||||
hoursAgo: "منذ {n} ساعة"
|
||||
daysAgo: "منذ {n} أيام"
|
||||
weeksAgo: "منذ {n} أسابيع"
|
||||
monthsAgo: "منذ {n} أشهر"
|
||||
yearsAgo: "منذ {n} سنوات"
|
||||
_time:
|
||||
second: "ثا"
|
||||
minute: "د"
|
||||
hour: "سا"
|
||||
day: "ي"
|
||||
_tutorial:
|
||||
title: "كيف تستخدم Misskey"
|
||||
step1_1: "مرحبًا!"
|
||||
_2fa:
|
||||
registerKey: "تسجيل مفتاح أمان جديد"
|
||||
_permissions:
|
||||
"write:account": "تعديل معلومات حسابك"
|
||||
"read:notifications": "اظهر الإشعارات"
|
||||
_weekday:
|
||||
sunday: "الأحد"
|
||||
monday: "الإثنين"
|
||||
tuesday: "الثلاثاء"
|
||||
wednesday: "الأربعاء"
|
||||
thursday: "الخميس"
|
||||
friday: "الجمعة"
|
||||
saturday: "السبت"
|
||||
_widgets:
|
||||
memo: "ملاحظة لاصقة"
|
||||
notifications: "الإشعارات"
|
||||
timeline: "الخيط الزمني"
|
||||
calendar: "التقويم"
|
||||
trends: "المتداوَلة"
|
||||
clock: "الساعة"
|
||||
rss: "تدفق RSS"
|
||||
activity: "النشاط"
|
||||
photos: "الصور"
|
||||
federation: "الفديرالية"
|
||||
_cw:
|
||||
hide: "إخفاء"
|
||||
show: "عرض المزيد"
|
||||
chars: "{count} أحرف"
|
||||
files: "{count} ملفات"
|
||||
_poll:
|
||||
noOnlyOneChoice: "تحتاج إلى خيارَين على الأقل"
|
||||
choiceN: "الخيار {n}"
|
||||
noMore: "لا يمكنك إضافة خيارات أخرى"
|
||||
canMultipleVote: "السماح بالإجابات المتعددة"
|
||||
expiration: "ينتهي استطلاع الرأي في"
|
||||
infinite: "أبدًا"
|
||||
at: "تاريخ الإنتهاء"
|
||||
after: "ينتهي بعد…"
|
||||
deadlineDate: "تاريخ الانتهاء"
|
||||
deadlineTime: "سا"
|
||||
duration: "المدة"
|
||||
votesCount: "{n} أصوات"
|
||||
totalVotes: "المجموع {n} أصوات"
|
||||
vote: "قم بالتصويت"
|
||||
showResult: "اعرض النتائج"
|
||||
voted: "تم التصويت"
|
||||
closed: "انتهى"
|
||||
remainingDays: "{d} أيام و {h} ساعات متبقية"
|
||||
remainingHours: "{h} ساعات و {m} دقائق متبقية"
|
||||
remainingMinutes: "{m} دقائق و {s} ثوانٍ متبقية"
|
||||
remainingSeconds: "{s} ثوانٍ متبقية"
|
||||
_visibility:
|
||||
public: "للعامة"
|
||||
home: "الرئيسي"
|
||||
followers: "المتابِعين"
|
||||
specified: "مباشرة"
|
||||
localOnly: "المحلي فقط"
|
||||
_postForm:
|
||||
replyPlaceholder: "رد على هذه الملاحظة…"
|
||||
quotePlaceholder: "اقتبس هذه الملاحظة…"
|
||||
_profile:
|
||||
name: "الإسم"
|
||||
username: "اسم المستخدم"
|
||||
youCanIncludeHashtags: "يمكنك أيضًا إضافة وسوم إلى نبذتك التعريفية."
|
||||
_exportOrImport:
|
||||
allNotes: "كل الملاحظات"
|
||||
followingList: "المتابَعون"
|
||||
muteList: "اكتم"
|
||||
blockingList: "احجب"
|
||||
userLists: "القوائم"
|
||||
_charts:
|
||||
usersTotal: "مجموع عدد المستخدمين والمستخدمات"
|
||||
activeUsers: "المستخدمون النشطون"
|
||||
_timelines:
|
||||
home: "الرئيسي"
|
||||
local: "المحلي"
|
||||
social: "الاجتماعي"
|
||||
global: "الشامل"
|
||||
_rooms:
|
||||
_roomType:
|
||||
default: "افتراضي"
|
||||
_furnitures:
|
||||
monitor: "شاشة التحكم"
|
||||
banknote: "أوراق نقدية"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "الصور"
|
||||
script:
|
||||
categories:
|
||||
list: "القوائم"
|
||||
blocks:
|
||||
_strReplace:
|
||||
arg1: "نص"
|
||||
arg3: "استُبدِل بـ"
|
||||
_join:
|
||||
arg1: "القوائم"
|
||||
arg2: "فاصل"
|
||||
add: "إضافة"
|
||||
_randomPick:
|
||||
arg1: "القوائم"
|
||||
_dailyRandomPick:
|
||||
arg1: "القوائم"
|
||||
_seedRandomPick:
|
||||
arg2: "القوائم"
|
||||
_pick:
|
||||
arg1: "القوائم"
|
||||
_listLen:
|
||||
arg1: "القوائم"
|
||||
types:
|
||||
array: "القوائم"
|
||||
_notification:
|
||||
youGotPoll: "شارك {name} في استطلاع الرأي"
|
||||
youGotMessagingMessageFromUser: "لقد تلقيت رسالة مِن {name}"
|
||||
youGotMessagingMessageFromGroup: "لقد أرسِلَت رسالة إلى الفريق {name}"
|
||||
youWereFollowed: "يتابعك"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "الإشعارات"
|
||||
tl: "الخيط الزمني"
|
||||
antenna: "الهوائيات"
|
||||
list: "القوائم"
|
||||
mentions: "الإشارات"
|
||||
direct: "مباشرة"
|
@ -43,8 +43,9 @@ copyUsername: "Benutzernamen kopieren"
|
||||
reply: "Antworten"
|
||||
loadMore: "Mehr anzeigen"
|
||||
youGotNewFollower: "Du hast einen neuen Follower"
|
||||
receiveFollowRequest: "Follow-Anfrage erhalten."
|
||||
receiveFollowRequest: "Follow-Anfrage erhalten"
|
||||
followRequestAccepted: "Follow-Anfrage akzeptiert"
|
||||
mention: "Erwähnung"
|
||||
mentions: "Erwähnungen"
|
||||
directNotes: "Direktnachrichten"
|
||||
importAndExport: "Importieren und Exportieren"
|
||||
@ -104,6 +105,7 @@ suspendConfirm: "Möchtest du diesen Benutzer wirklich sperren?"
|
||||
unsuspendConfirm: "Möchtest du die Sperrung dieses Benutzers wirklich aufheben?"
|
||||
selectList: "Wähle eine Liste aus"
|
||||
customEmojis: "Benutzerdefinierte Emojis"
|
||||
emoji: "Emoji"
|
||||
emojiName: "Emojiname"
|
||||
emojiUrl: "Emoji-URL"
|
||||
addEmoji: "Emoji hinzufügen"
|
||||
@ -203,7 +205,7 @@ remove: "Löschen"
|
||||
removed: "Erfolgreich gelöscht"
|
||||
removeAreYouSure: "Möchtest du \"{x}\" wirklich löschen?"
|
||||
saved: "Gespeichert"
|
||||
messaging: "Privatnachrichten"
|
||||
messaging: "Chat"
|
||||
upload: "Hochladen"
|
||||
fromDrive: "Aus Drive"
|
||||
fromUrl: "Von einer URL"
|
||||
@ -215,7 +217,7 @@ explore: "Erkunden"
|
||||
games: "Misskey Spiele"
|
||||
messageRead: "Gelesen"
|
||||
noMoreHistory: "Kein weiterer Verlauf vorhanden"
|
||||
startMessaging: "Neue Privatnachricht erstellen"
|
||||
startMessaging: "Neuen Chat erstellen"
|
||||
nUsersRead: "Von {n} gelesen"
|
||||
agreeTo: "Ich stimme {0} zu"
|
||||
tos: "Nutzungsbedingungen"
|
||||
@ -384,8 +386,8 @@ invites: "Einladungen"
|
||||
groupName: "Gruppenname"
|
||||
members: "Mitglieder"
|
||||
transfer: "Übertragen"
|
||||
messagingWithUser: "Privatnachrichten mit einem Benutzer"
|
||||
messagingWithGroup: "Privatnachrichten mit einer Gruppe"
|
||||
messagingWithUser: "Privatchat"
|
||||
messagingWithGroup: "Gruppenchat"
|
||||
title: "Betreff"
|
||||
text: "Text"
|
||||
enable: "Aktivieren"
|
||||
@ -440,7 +442,7 @@ remote: "Fremd"
|
||||
total: "Gesamt"
|
||||
weekOverWeekChanges: "Wöchentlich"
|
||||
dayOverDayChanges: "Täglich"
|
||||
accessibility: "Barrierefreiheit"
|
||||
appearance: "Aussehen"
|
||||
clinetSettings: "Client-Einstellungen"
|
||||
accountSettings: "Benutzerkonto-Einstellungen"
|
||||
promotion: "Hervorgehoben"
|
||||
@ -506,19 +508,112 @@ relays: "Relays"
|
||||
addRelay: "Relay hinzufügen"
|
||||
inboxUrl: "inbox-URL"
|
||||
addedRelays: "Hinzugefügte Relays"
|
||||
serviceworkerInfo: "Muss für Push-Benachrichtigungen aktiviert sein."
|
||||
deletedNote: "Gelöschte Notiz"
|
||||
invisibleNote: "Private Notiz"
|
||||
enableInfiniteScroll: "Automatisch mehr Notizen laden"
|
||||
visibility: "Sichtbarkeit"
|
||||
poll: "Umfrage"
|
||||
useCw: "Inhalt verstecken"
|
||||
fixedWidgetsPosition: "Widgetposition fixieren"
|
||||
enablePlayer: "Video-Player öffnen"
|
||||
disablePlayer: "Video-Player schließen"
|
||||
expandTweet: "Tweet ausklappen"
|
||||
themeEditor: "Farbthemen-Editor"
|
||||
description: "Beschreibung"
|
||||
author: "Autor"
|
||||
leaveConfirm: "Es gibt unspeicherte Änderungen. Möchtest du diese verwerfen?"
|
||||
manage: "Verwaltung"
|
||||
plugins: "Plugins"
|
||||
pluginInstallWarn: "Installiere nur vertrauenswürdige Plugins."
|
||||
deck: "Deck"
|
||||
undeck: "Deck verlassen"
|
||||
useBlurEffectForModal: "Weichzeichnungseffekt für Modals verwenden"
|
||||
generateAccessToken: "Zugriffstoken generieren"
|
||||
permission: "Berechtigungen"
|
||||
enableAll: "Alle aktivieren"
|
||||
disableAll: "Alle deaktivieren"
|
||||
tokenRequested: "Benutzerkontozugriff gewähren"
|
||||
pluginTokenRequestedDescription: "Dieses Plugin wird die hier konfigurierten Berechtigungen verwenden können."
|
||||
smtpHost: "Host"
|
||||
smtpUser: "Benutzername"
|
||||
smtpPass: "Passwort"
|
||||
_theme:
|
||||
explore: "Themen erforschen"
|
||||
install: "Thema installieren"
|
||||
manage: "Themaverwaltung"
|
||||
code: "Themencode"
|
||||
code: "Themen-Code"
|
||||
installed: "{name} wurde installiert"
|
||||
alreadyInstalled: "Dieses Thema ist bereits installiert"
|
||||
invalid: "Themenformat ist ungültig"
|
||||
make: "Farbthema erstellen"
|
||||
base: "Basis"
|
||||
addConstant: "Konstante hinzufügen"
|
||||
constant: "Konstante"
|
||||
defaultValue: "Standardwert"
|
||||
color: "Farbe"
|
||||
refProp: "Eigenschaft referenzieren"
|
||||
refConst: "Konstante referenzieren"
|
||||
key: "Schlüssel"
|
||||
func: "Funktionen"
|
||||
funcKind: "Funktionstyp"
|
||||
argument: "Parameter"
|
||||
basedProp: "Referenzierte Eigenschaft"
|
||||
alpha: "Transparenz"
|
||||
darken: "Verdunkeln"
|
||||
lighten: "Erhellen"
|
||||
inputConstantName: "Name der Konstanten eingeben"
|
||||
importInfo: "Du kannst hier Themen-Code einfügen, um ihn in den Editor zu importieren"
|
||||
deleteConstantConfirm: "Die Konstante {const} wirklich löschen?"
|
||||
keys:
|
||||
accent: "Akzentfarbe"
|
||||
bg: "Hintergrund"
|
||||
fg: "Text"
|
||||
focus: "Fokus"
|
||||
indicator: "Indikator"
|
||||
panel: "Panel"
|
||||
shadow: "Schatten"
|
||||
header: "Kopfzeile"
|
||||
navBg: "Hintergrund der Seitenleiste"
|
||||
navFg: "Text der Seitenleiste"
|
||||
navHoverFg: "Text der Seitenleiste (Mouseover)"
|
||||
navActive: "Text der Seitenleiste (Aktiv)"
|
||||
navIndicator: "Indikator der Seitenleiste"
|
||||
link: "Link"
|
||||
hashtag: "Hashtag"
|
||||
mention: "Erwähnungen"
|
||||
mentionMe: "Erwähnungen (Ich)"
|
||||
renote: "Renote"
|
||||
modalBg: "Hintergrund des Modals"
|
||||
divider: "Trenner"
|
||||
scrollbarHandle: "Griff des Scrollbalkens"
|
||||
scrollbarHandleHover: "Griff des Scrollbalkens (Mouseover)"
|
||||
dateLabelFg: "Text von Datumsbeschriftungen"
|
||||
infoBg: "Hintergrund von Informationen"
|
||||
infoFg: "Text von Informationen"
|
||||
infoWarnBg: "Hintergrund von Warnungen"
|
||||
infoWarnFg: "Text von Informationen"
|
||||
cwBg: "Hintergrund von versteckten Inhalten"
|
||||
cwFg: "Text von versteckten Inhalten"
|
||||
cwHoverBg: "Hintergrund von versteckten Inhalten (Mouseover)"
|
||||
toastBg: "Hintergrund von Benachrichtigungen"
|
||||
toastFg: "Text von Benachrichtigungen"
|
||||
buttonBg: "Hintergrund von Schaltflächen"
|
||||
buttonHoverBg: "Hintergrund von Schaltflächen (Mouseover)"
|
||||
inputBorder: "Rahmen des Eingabefelds"
|
||||
listItemHoverBg: "Hintergrund von Listeneinträgen (Mouseover)"
|
||||
driveFolderBg: "Hintergrund von Drive-Ordnern"
|
||||
wallpaperOverlay: "Hintergrundbild-Overlay"
|
||||
badge: "Wappen"
|
||||
messageBg: "Hintergrund von Chats"
|
||||
accentDarken: "Akzent (Verdunkelt)"
|
||||
accentLighten: "Akzent (Erhellt)"
|
||||
fgHighlighted: "Hervorgehobener Text"
|
||||
_sfx:
|
||||
note: "Notizen"
|
||||
noteMy: "Meine Notizen"
|
||||
notification: "Benachrichtigungen"
|
||||
chat: "Privatnachrichten"
|
||||
chat: "Chat"
|
||||
chatBg: "Nachrichten (Hintergrund)"
|
||||
antenna: "Antennen"
|
||||
_ago:
|
||||
@ -580,8 +675,8 @@ _permissions:
|
||||
"write:favorites": "Deine Favoriten-Liste bearbeiten"
|
||||
"read:following": "Deine Follower-Liste lesen"
|
||||
"write:following": "Anderen Benutzern folgen oder entfolgen"
|
||||
"read:messaging": "Privatnachrichten lesen"
|
||||
"write:messaging": "Privatnachrichten schicken oder löschen"
|
||||
"read:messaging": "Chats lesen"
|
||||
"write:messaging": "Chatnachrichten schicken oder löschen"
|
||||
"read:mutes": "Stummschaltungen lesen"
|
||||
"write:mutes": "Stummschaltungen bearbeiten"
|
||||
"write:notes": "Notizen schreiben oder löschen"
|
||||
@ -627,12 +722,13 @@ _widgets:
|
||||
rss: "RSS-Reader"
|
||||
activity: "Aktivität"
|
||||
photos: "Fotos"
|
||||
digitalClock: "Digitaluhr"
|
||||
federation: "Föderation"
|
||||
_cw:
|
||||
hide: "Ausblenden"
|
||||
show: "Mehr anzeigen"
|
||||
chars: "{count} Zeichen"
|
||||
files: "{count} Dateien"
|
||||
poll: "Umfrage"
|
||||
_poll:
|
||||
noOnlyOneChoice: "Mindestens zwei Antwortmöglichkeiten werden benötigt."
|
||||
choiceN: "Auswahl {n}"
|
||||
@ -665,6 +761,7 @@ _visibility:
|
||||
specified: "Direkt"
|
||||
specifiedDescription: "Nur für bestimmte Benutzer sichtbar"
|
||||
localOnly: "Nur Lokal"
|
||||
localOnlyDescription: "Unsichtbar für Benutzer anderer Instanzen"
|
||||
_postForm:
|
||||
replyPlaceholder: "Dieser Notiz antworten..."
|
||||
quotePlaceholder: "Diese Notiz zitieren..."
|
||||
@ -761,11 +858,11 @@ _rooms:
|
||||
moon: "Mond"
|
||||
corkboard: "Pinnwand"
|
||||
mousepad: "Mauspad"
|
||||
monitor: "Beobachten"
|
||||
monitor: "Monitor"
|
||||
keyboard: "Tastatur"
|
||||
carpet-stripe: "Gestreifter Teppich"
|
||||
mat: "Matte"
|
||||
color-box: "Farbige Box"
|
||||
color-box: "Regal"
|
||||
wall-clock: "Wanduhr"
|
||||
photoframe: "Bilderrahmen"
|
||||
cube: "Würfel"
|
||||
@ -780,6 +877,8 @@ _rooms:
|
||||
cup-noodle: "Instantnudeln"
|
||||
holo-display: "Holographischer Bildschirm"
|
||||
energy-drink: "Energy Drink"
|
||||
doll-ai: "Ai-Puppe"
|
||||
banknote: "Geldscheine"
|
||||
_pages:
|
||||
newPage: "Seite erstellen"
|
||||
editPage: "Diese Seite bearbeiten"
|
||||
@ -1065,3 +1164,28 @@ _relayStatus:
|
||||
requesting: "Ausstehend"
|
||||
accepted: "Akzeptiert"
|
||||
rejected: "Abgelehnt"
|
||||
_notification:
|
||||
fileUploaded: "Datei erfolgreich hochgeladen"
|
||||
youGotMention: "{name} hat dich erwähnt"
|
||||
youGotReply: "{name} hat dir geantwortet"
|
||||
youGotQuote: "{name} hat dich zitiert"
|
||||
youRenoted: "Renote deiner Notiz von {name}"
|
||||
youGotPoll: "{name} hat auf deiner Umfrage abgestimmt"
|
||||
youGotMessagingMessageFromUser: "{name} hat dir eine Chatnachricht gesendet"
|
||||
youGotMessagingMessageFromGroup: "In die Gruppe {name} wurde eine Chatnachricht gesendet"
|
||||
youWereFollowed: "Du hast einen neuen Follower"
|
||||
youReceivedFollowRequest: "Du hast eine Follow-Anfrage erhalten"
|
||||
yourFollowRequestAccepted: "Deine Follow-Anfrage wurde akzeptiert"
|
||||
youWereInvitedToGroup: "Du wurdest in eine Gruppe eingeladen"
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
||||
columnAlign: "Spalten ausrichten"
|
||||
addColumn: "Spalte hinzufügen"
|
||||
_columns:
|
||||
widgets: "Widgets"
|
||||
notifications: "Benachrichtigungen"
|
||||
tl: "Chronik"
|
||||
antenna: "Antennen"
|
||||
list: "Listen"
|
||||
mentions: "Erwähnungen"
|
||||
direct: "Direkt"
|
||||
|
@ -45,6 +45,7 @@ loadMore: "Load more"
|
||||
youGotNewFollower: "Followed you"
|
||||
receiveFollowRequest: "Follow request received"
|
||||
followRequestAccepted: "Follow request accepted"
|
||||
mention: "Mention"
|
||||
mentions: "Mentions"
|
||||
directNotes: "Direct notes"
|
||||
importAndExport: "Import / Export"
|
||||
@ -104,6 +105,7 @@ suspendConfirm: "Are you sure that you want to suspend this account?"
|
||||
unsuspendConfirm: "Are you sure you that want to unsuspend this account?"
|
||||
selectList: "Select a list"
|
||||
customEmojis: "Custom Emoji"
|
||||
emoji: "Emoji"
|
||||
emojiName: "Emoji name"
|
||||
emojiUrl: "Emoji URL"
|
||||
addEmoji: "Add an emoji"
|
||||
@ -440,7 +442,7 @@ remote: "Remote"
|
||||
total: "Total"
|
||||
weekOverWeekChanges: "Weekly"
|
||||
dayOverDayChanges: "Daily"
|
||||
accessibility: "Accessibility"
|
||||
appearance: "Appearance"
|
||||
clinetSettings: "Client Settings"
|
||||
accountSettings: "Account Settings"
|
||||
promotion: "Promoted"
|
||||
@ -502,6 +504,40 @@ sidebar: "Sidebar"
|
||||
divider: "Divider"
|
||||
addItem: "Add Item"
|
||||
rooms: "Room"
|
||||
relays: "Relays"
|
||||
addRelay: "Add Relay"
|
||||
inboxUrl: "Inbox URL"
|
||||
addedRelays: "Added Relays"
|
||||
serviceworkerInfo: "Must be enabled for push notifications."
|
||||
deletedNote: "Deleted note"
|
||||
invisibleNote: "Invisible note"
|
||||
enableInfiniteScroll: "Enable infinite scrolling"
|
||||
visibility: "Visiblility"
|
||||
poll: "Poll"
|
||||
useCw: "Hide content"
|
||||
fixedWidgetsPosition: "Make widget position fixed"
|
||||
enablePlayer: "Open video player"
|
||||
disablePlayer: "Close video player"
|
||||
expandTweet: "Expand tweet"
|
||||
themeEditor: "Theme editor"
|
||||
description: "Description"
|
||||
author: "Author"
|
||||
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
|
||||
manage: "Management"
|
||||
plugins: "Plugins"
|
||||
pluginInstallWarn: "Please do not install untrustworthy plugins."
|
||||
deck: "Deck"
|
||||
undeck: "Leave Deck"
|
||||
useBlurEffectForModal: "Use blur effect for modals"
|
||||
generateAccessToken: "Generate access token"
|
||||
permission: "Permissions"
|
||||
enableAll: "Enable all"
|
||||
disableAll: "Disable all"
|
||||
tokenRequested: "Grant access to account"
|
||||
pluginTokenRequestedDescription: "This plugin will be able to use the permissions set here."
|
||||
smtpHost: "Host"
|
||||
smtpUser: "Username"
|
||||
smtpPass: "Password"
|
||||
_theme:
|
||||
explore: "Explore Themes"
|
||||
install: "Install theme"
|
||||
@ -510,6 +546,69 @@ _theme:
|
||||
installed: "{name} has been installed"
|
||||
alreadyInstalled: "The theme is already installed"
|
||||
invalid: "Theme format is invalid"
|
||||
make: "Make a theme"
|
||||
base: "Base"
|
||||
addConstant: "Add constant"
|
||||
constant: "Constant"
|
||||
defaultValue: "Default value"
|
||||
color: "Color"
|
||||
refProp: "Reference a property"
|
||||
refConst: "Reference a constant"
|
||||
key: "Key"
|
||||
func: "Functions"
|
||||
funcKind: "Function type"
|
||||
argument: "Argument"
|
||||
basedProp: "Referenced property"
|
||||
alpha: "Opacity"
|
||||
darken: "Darken"
|
||||
lighten: "Lighten"
|
||||
inputConstantName: "Enter a name for the constant"
|
||||
importInfo: "If you enter theme code here, you can import it to the theme editor"
|
||||
deleteConstantConfirm: "Do you really want to delete the constant {const}?"
|
||||
keys:
|
||||
accent: "Accent"
|
||||
bg: "Background"
|
||||
fg: "Text"
|
||||
focus: "Focus"
|
||||
indicator: "Indicator"
|
||||
panel: "Panel"
|
||||
shadow: "Shadow"
|
||||
header: "Header"
|
||||
navBg: "Sidebar background"
|
||||
navFg: "Sidebar text"
|
||||
navHoverFg: "Sidebar text (Hover)"
|
||||
navActive: "Sidebar text (Active)"
|
||||
navIndicator: "Sidebar indicator"
|
||||
link: "Link"
|
||||
hashtag: "Hashtag"
|
||||
mention: "Mention"
|
||||
mentionMe: "Mentions (Me)"
|
||||
renote: "Renote"
|
||||
modalBg: "Modal background"
|
||||
divider: "Divider"
|
||||
scrollbarHandle: "Scrollbar handle"
|
||||
scrollbarHandleHover: "Scrollbar handle (Hover)"
|
||||
dateLabelFg: "Text of date labels"
|
||||
infoBg: "Information background"
|
||||
infoFg: "Information text"
|
||||
infoWarnBg: "Warning background"
|
||||
infoWarnFg: "Warning text"
|
||||
cwBg: "CW background"
|
||||
cwFg: "CW text"
|
||||
cwHoverBg: "CW background (Hover)"
|
||||
toastBg: "Notification background"
|
||||
toastFg: "Notification text"
|
||||
buttonBg: "Button background"
|
||||
buttonHoverBg: "Button background (Hover)"
|
||||
inputBorder: "Input field border"
|
||||
listItemHoverBg: "List item background (Hover)"
|
||||
driveFolderBg: "Drive folder background"
|
||||
wallpaperOverlay: "Wallpaper overlay"
|
||||
badge: "Badge"
|
||||
messageBg: "Chat background"
|
||||
accentDarken: "Accent (Darkened)"
|
||||
accentLighten: "Accent (Lightened)"
|
||||
fgHighlighted: "Highlighted Text"
|
||||
_sfx:
|
||||
note: "New note"
|
||||
noteMy: "My note"
|
||||
@ -623,12 +722,13 @@ _widgets:
|
||||
rss: "RSS reader"
|
||||
activity: "Activity"
|
||||
photos: "Photos"
|
||||
digitalClock: "Digital clock"
|
||||
federation: "Federation"
|
||||
_cw:
|
||||
hide: "Hide"
|
||||
show: "Load more"
|
||||
chars: "{count} characters"
|
||||
files: "{count} file(s)"
|
||||
poll: "Poll"
|
||||
_poll:
|
||||
noOnlyOneChoice: "At least two choices are needed"
|
||||
choiceN: "Choice {n}"
|
||||
@ -661,6 +761,7 @@ _visibility:
|
||||
specified: "Direct"
|
||||
specifiedDescription: "Post to specified users only"
|
||||
localOnly: "Local only"
|
||||
localOnlyDescription: "Not visible to remote users"
|
||||
_postForm:
|
||||
replyPlaceholder: "Reply to this note..."
|
||||
quotePlaceholder: "Quote this note..."
|
||||
@ -776,6 +877,8 @@ _rooms:
|
||||
cup-noodle: "Cup noodle"
|
||||
holo-display: "Holographic display"
|
||||
energy-drink: "Energy drink"
|
||||
doll-ai: "Ai doll"
|
||||
banknote: "Pile of money"
|
||||
_pages:
|
||||
newPage: "Create a page"
|
||||
editPage: "Edit this page"
|
||||
@ -1057,3 +1160,32 @@ _pages:
|
||||
enviromentVariables: "Environment variable"
|
||||
pageVariables: "Page element"
|
||||
argVariables: "Input slot"
|
||||
_relayStatus:
|
||||
requesting: "Pending"
|
||||
accepted: "Accepted"
|
||||
rejected: "Rejected"
|
||||
_notification:
|
||||
fileUploaded: "File successfully uploaded"
|
||||
youGotMention: "{name} mentioned you"
|
||||
youGotReply: "{name} replied to you"
|
||||
youGotQuote: "{name} quoted you"
|
||||
youRenoted: "{name} renoted you"
|
||||
youGotPoll: "{name} voted on your poll"
|
||||
youGotMessagingMessageFromUser: "{name} sent you a message"
|
||||
youGotMessagingMessageFromGroup: "A message was sent to the {name} group"
|
||||
youWereFollowed: "Followed you"
|
||||
youReceivedFollowRequest: "You've received a follow request"
|
||||
yourFollowRequestAccepted: "Your follow request was accepted"
|
||||
youWereInvitedToGroup: "Invited to group"
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Always show main column"
|
||||
columnAlign: "Align columns"
|
||||
addColumn: "Add column"
|
||||
_columns:
|
||||
widgets: "Widgets"
|
||||
notifications: "Notifications"
|
||||
tl: "Timeline"
|
||||
antenna: "Antennas"
|
||||
list: "Lists"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct"
|
||||
|
@ -26,7 +26,7 @@ signup: "Registrarse"
|
||||
uploading: "Cargando"
|
||||
save: "Guardar"
|
||||
users: "Usuarios"
|
||||
addUser: "Añadir usuario"
|
||||
addUser: "Agregar usuario"
|
||||
favorite: "Favorito"
|
||||
favorites: "Favoritos"
|
||||
unfavorite: "Quitar de favoritos"
|
||||
@ -45,6 +45,7 @@ loadMore: "Ver más"
|
||||
youGotNewFollower: "te ha seguido"
|
||||
receiveFollowRequest: "Recibiste una solicitud de seguimiento"
|
||||
followRequestAccepted: "La solicitud de seguimiento fue aceptada"
|
||||
mention: "Menciones"
|
||||
mentions: "Menciones"
|
||||
directNotes: "Notas directas"
|
||||
importAndExport: "Importar y Exportar"
|
||||
@ -84,7 +85,7 @@ pinnedNote: "Nota fijada"
|
||||
you: "Tú"
|
||||
clickToShow: "Click para ver"
|
||||
sensitive: "Marcado como sensible"
|
||||
add: "Añadir"
|
||||
add: "Agregar"
|
||||
reaction: "Reacción"
|
||||
reactionSettingDescription: "Asigne sus reacción favoritas que desean anclar en el selector de reacciones."
|
||||
rememberNoteVisibility: "Recordar visibilidad"
|
||||
@ -104,16 +105,17 @@ suspendConfirm: "¿Quiere suspender esta cuenta?"
|
||||
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
|
||||
selectList: "Seleccione una lista"
|
||||
customEmojis: "Emojis personalizados"
|
||||
emoji: "Emoji"
|
||||
emojiName: "Nombre del emoji"
|
||||
emojiUrl: "URL de la imágen del emoji"
|
||||
addEmoji: "Añadir emoji"
|
||||
addEmoji: "Agregar emoji"
|
||||
settingGuide: "Configuración sugerida"
|
||||
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
||||
cacheRemoteFilesDescription: "Si desactiva esta configuración, Los archivos remotos se cargarán desde el link directo sin usar la caché. Con eso se puede ahorrar almacenamiento del servidor, pero eso aumentará el tráfico al no crear miniaturas."
|
||||
flagAsBot: "Esta cuenta es un bot"
|
||||
flagAsCat: "Esta cuenta es un gato"
|
||||
autoAcceptFollowed: "Aceptar automáticamente las solicitudes de seguimiento de los usuarios que sigues"
|
||||
addAcount: "Añadir cuenta"
|
||||
addAcount: "Agregar cuenta"
|
||||
loginFailed: "Error al iniciar sesión."
|
||||
showOnRemote: "Ver en una instancia remota"
|
||||
general: "General"
|
||||
@ -247,7 +249,7 @@ folderName: "Nombre de la carpeta"
|
||||
createFolder: "Crear carpeta"
|
||||
renameFolder: "Renombrar carpeta"
|
||||
deleteFolder: "Borrar carpeta"
|
||||
addFile: "Añadir archivo"
|
||||
addFile: "Agregar archivo"
|
||||
emptyDrive: "El drive está vacío"
|
||||
emptyFolder: "La carpeta está vacía"
|
||||
unableToDelete: "No se puede borrar"
|
||||
@ -440,7 +442,7 @@ remote: "Remoto"
|
||||
total: "Total"
|
||||
weekOverWeekChanges: "Dif semanal"
|
||||
dayOverDayChanges: "Dif diaria"
|
||||
accessibility: "Accesibilidad"
|
||||
appearance: "Apariencia"
|
||||
clinetSettings: "Ajustes del cliente"
|
||||
accountSettings: "Ajustes de cuenta"
|
||||
promotion: "Promovido"
|
||||
@ -502,6 +504,51 @@ sidebar: "Barra lateral"
|
||||
divider: "Divisor"
|
||||
addItem: "Agregar elemento"
|
||||
rooms: "Cuartos"
|
||||
relays: "Relés"
|
||||
addRelay: "Agregar relé"
|
||||
inboxUrl: "Inbox URL"
|
||||
addedRelays: "Relés añadidos"
|
||||
serviceworkerInfo: "Se necesita activar para usar las notificaciones push"
|
||||
deletedNote: "Nota eliminada"
|
||||
invisibleNote: "Nota oculta"
|
||||
enableInfiniteScroll: "Activar scroll infinito"
|
||||
visibility: "Visibilidad"
|
||||
poll: "Encuesta"
|
||||
useCw: "Esconder contenidos"
|
||||
fixedWidgetsPosition: "Fijar la posición de los widgets"
|
||||
enablePlayer: "Abrir reproductor"
|
||||
disablePlayer: "Cerrar reproductor"
|
||||
expandTweet: "Expandir tweet"
|
||||
themeEditor: "Editor de temas"
|
||||
description: "Descripción"
|
||||
author: "Autor"
|
||||
leaveConfirm: "Hay modificaciones sin guardar. ¿Desea descartarlas?"
|
||||
manage: "Administrar"
|
||||
plugins: "Plugins"
|
||||
pluginInstallWarn: "Por favor no instale plugins que no son de confianza"
|
||||
deck: "Deck"
|
||||
undeck: "Quitar deck"
|
||||
useBlurEffectForModal: "Usar efecto borroso en modales"
|
||||
generateAccessToken: "Generar token de acceso"
|
||||
permission: "Permisos"
|
||||
enableAll: "Activar todo"
|
||||
disableAll: "Desactivar todo"
|
||||
tokenRequested: "Permiso de acceso a la cuenta"
|
||||
pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí"
|
||||
useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella"
|
||||
emailConfig: "Configuración del servidor de correos"
|
||||
enableEmail: "Activar el envío de correos electrónicos"
|
||||
emailConfigInfo: "Usar en caso de validación de correo electrónico y pedido de contraseña"
|
||||
email: "Correo electrónico"
|
||||
smtpConfig: "Configuración del servidor SMTP"
|
||||
smtpHost: "Host"
|
||||
smtpPort: "Puerto"
|
||||
smtpUser: "Nombre de usuario"
|
||||
smtpPass: "Contraseña"
|
||||
emptyToDisableSmtpAuth: "Deje el nombre del usuario y la contraseña en blanco para deshabilitar la autenticación SMTP"
|
||||
smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP"
|
||||
smtpSecureInfo: "Apagar cuando se use STARTTLS"
|
||||
testEmail: "Prueba de envío"
|
||||
_theme:
|
||||
explore: "Explorar temas"
|
||||
install: "Instalar tema"
|
||||
@ -510,6 +557,69 @@ _theme:
|
||||
installed: "{name} ha sido instalado"
|
||||
alreadyInstalled: "Este tema ya está instalado"
|
||||
invalid: "El formato del tema no es válido"
|
||||
make: "Crear tema"
|
||||
base: "Base"
|
||||
addConstant: "Agregar constante"
|
||||
constant: "Constante"
|
||||
defaultValue: "Valor predeterminado"
|
||||
color: "Color"
|
||||
refProp: "Hacer referencia a propiedad"
|
||||
refConst: "Hacer referencia a constante"
|
||||
key: "Clave"
|
||||
func: "funciones"
|
||||
funcKind: "Tipo de función"
|
||||
argument: "Argumento"
|
||||
basedProp: "Nombre de la propiedad referenciada"
|
||||
alpha: "Opacidad"
|
||||
darken: "Oscuridad"
|
||||
lighten: "Brillo"
|
||||
inputConstantName: "Por favor ingrese el nombre de la constante"
|
||||
importInfo: "Pegando el código del tema aquí, puede importarlo al editor"
|
||||
deleteConstantConfirm: "¿Desea borrar la constante {const}?"
|
||||
keys:
|
||||
accent: "Acento"
|
||||
bg: "Fondo"
|
||||
fg: "Texto"
|
||||
focus: "Enfoque"
|
||||
indicator: "Indicador"
|
||||
panel: "Panel"
|
||||
shadow: "Sombra"
|
||||
header: "Cabezal"
|
||||
navBg: "Fondo de la barra lateral"
|
||||
navFg: "Texto de la barra lateral"
|
||||
navHoverFg: "Texto de la barra lateral (hover)"
|
||||
navActive: "Texto de la barra lateral (activo)"
|
||||
navIndicator: "Indicador de la barra lateral"
|
||||
link: "Vínculo"
|
||||
hashtag: "Hashtag"
|
||||
mention: "Menciones"
|
||||
mentionMe: "Menciones (yo)"
|
||||
renote: "Renotar"
|
||||
modalBg: "Fondo modal"
|
||||
divider: "Divisor"
|
||||
scrollbarHandle: "Cuadro de la barra de desplazamiento"
|
||||
scrollbarHandleHover: "Cuadro de la barra de desplazamiento (hover)"
|
||||
dateLabelFg: "Texto de la etiqueta de fecha"
|
||||
infoBg: "Fondo de información"
|
||||
infoFg: "Texto de información"
|
||||
infoWarnBg: "Fondo de advertencias"
|
||||
infoWarnFg: "Texto de advertencias"
|
||||
cwBg: "Fondo del botón CW"
|
||||
cwFg: "Texto del botón CW"
|
||||
cwHoverBg: "Fondo del botón CW (hover)"
|
||||
toastBg: "Fondo de notificaciones"
|
||||
toastFg: "Texto de notificaciones"
|
||||
buttonBg: "Fondo de botón"
|
||||
buttonHoverBg: "Fondo de botón (hover)"
|
||||
inputBorder: "Borde de los campos de entrada"
|
||||
listItemHoverBg: "Fondo de elemento de listas (hover)"
|
||||
driveFolderBg: "Fondo de capeta del drive"
|
||||
wallpaperOverlay: "Transparencia del fondo de pantalla"
|
||||
badge: "Medalla"
|
||||
messageBg: "Fondo de chat"
|
||||
accentDarken: "Acento (oscuro)"
|
||||
accentLighten: "Acento (claro)"
|
||||
fgHighlighted: "Texto resaltado"
|
||||
_sfx:
|
||||
note: "Notas"
|
||||
noteMy: "Nota (a mí mismo)"
|
||||
@ -623,12 +733,13 @@ _widgets:
|
||||
rss: "Lector RSS"
|
||||
activity: "Actividad"
|
||||
photos: "Fotos"
|
||||
digitalClock: "Reloj digital"
|
||||
federation: "Federación"
|
||||
_cw:
|
||||
hide: "Ocultar"
|
||||
show: "Ver más"
|
||||
chars: "{count} caracteres"
|
||||
files: "{count} archivos"
|
||||
poll: "Encuesta"
|
||||
_poll:
|
||||
noOnlyOneChoice: "Se necesitan al menos 2 opciones"
|
||||
choiceN: "Opción {n}"
|
||||
@ -661,6 +772,7 @@ _visibility:
|
||||
specified: "Mensaje directo"
|
||||
specifiedDescription: "Visible sólo para los usuarios elegidos"
|
||||
localOnly: "Solo local"
|
||||
localOnlyDescription: "Oculto para usuarios remotos"
|
||||
_postForm:
|
||||
replyPlaceholder: "Responder a esta nota"
|
||||
quotePlaceholder: "Citar esta nota"
|
||||
@ -776,6 +888,8 @@ _rooms:
|
||||
cup-noodle: "Taza de sopa de fideos"
|
||||
holo-display: "Poster holográfico"
|
||||
energy-drink: "Bebida energética"
|
||||
doll-ai: "Muñeca"
|
||||
banknote: "Billetes"
|
||||
_pages:
|
||||
newPage: "Crear página"
|
||||
editPage: "Editar página"
|
||||
@ -1057,3 +1171,32 @@ _pages:
|
||||
enviromentVariables: "Variables de entorno"
|
||||
pageVariables: "Items de la página"
|
||||
argVariables: "Slot de entrada"
|
||||
_relayStatus:
|
||||
requesting: "Pendiente"
|
||||
accepted: "Aceptar"
|
||||
rejected: "Rechazada"
|
||||
_notification:
|
||||
fileUploaded: "Archivo subido"
|
||||
youGotMention: "Mención de {name}"
|
||||
youGotReply: "Respuesta de {name}"
|
||||
youGotQuote: "Citado por {name}"
|
||||
youRenoted: "Renotado por {name}"
|
||||
youGotPoll: "Encuestado por {name}"
|
||||
youGotMessagingMessageFromUser: "{name} comenzó un chat contigo"
|
||||
youGotMessagingMessageFromGroup: "Tienes un chat de {name}"
|
||||
youWereFollowed: "te ha seguido"
|
||||
youReceivedFollowRequest: "Has mandado una solicitud de seguimiento"
|
||||
yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada"
|
||||
youWereInvitedToGroup: "Invitado al grupo"
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Siempre mostrar la columna principal"
|
||||
columnAlign: "Alinear columnas"
|
||||
addColumn: "Agregar columna"
|
||||
_columns:
|
||||
widgets: "Widgets"
|
||||
notifications: "Notificaciones"
|
||||
tl: "Linea de tiempo"
|
||||
antenna: "Antenas"
|
||||
list: "Listas"
|
||||
mentions: "Menciones"
|
||||
direct: "Mensaje directo"
|
||||
|
@ -1,28 +1,28 @@
|
||||
---
|
||||
_lang_: "Français"
|
||||
introMisskey: "Bienvenue ! Misskey est un service de microblogage décentralisé et open-source.\nÉcrivez des « notes » pour partager ce qui se passe, ou pour parler de vous à tout le monde 📡\nAvec la fonction « réactions », vous pouvez également ajouter une réaction rapide aux notes de chacun 👍\nExplorez un nouveau monde 🚀"
|
||||
introMisskey: "Bienvenue ! Misskey est un service de microblogage décentralisé, libre et ouvert.\nÉcrivez des « notes » et partagez ce qui se passe à l’instant présent, autour de vous avec les autres 📡\nLa fonction « réactions », vous permet également d’ajouter une réaction rapide aux notes des autres utilisateur·rice·s 👍\nExplorons un nouveau monde 🚀"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Rechercher"
|
||||
notifications: "Notifications"
|
||||
username: "Nom d'utilisateur·rice"
|
||||
username: "Nom d’utilisateur·rice"
|
||||
password: "Mot de passe"
|
||||
fetchingAsApObject: "Récupération depuis le Fediverse"
|
||||
ok: "Soumettre"
|
||||
gotIt: "J'ai compris !"
|
||||
fetchingAsApObject: "Récupération depuis le fédiverse …"
|
||||
ok: "OK"
|
||||
gotIt: "J’ai compris !"
|
||||
cancel: "Annuler"
|
||||
enterUsername: "Entrer un nom d'utilisateur·rice"
|
||||
enterUsername: "Entrer un nom d’utilisateur·rice"
|
||||
renotedBy: "Renoté par {user}"
|
||||
noNotes: "Pas de notes"
|
||||
noNotifications: "Pas de notifications"
|
||||
noNotes: "Aucune note"
|
||||
noNotifications: "Aucune notification"
|
||||
instance: "Instance"
|
||||
settings: "Paramètres"
|
||||
profile: "Profil"
|
||||
timeline: "Fil d'actualité"
|
||||
noAccountDescription: "L'utilisateur·rice n'a pas encore renseigné de présentation sur son profil"
|
||||
timeline: "Fil"
|
||||
noAccountDescription: "L’utilisateur·rice n’a pas encore renseigné de biographie de présentation sur son profil."
|
||||
login: "Se connecter"
|
||||
loggingIn: "Connexion en cours"
|
||||
logout: "Se déconnecter"
|
||||
signup: "S'inscrire"
|
||||
signup: "S’inscrire"
|
||||
uploading: "Envoi en cours"
|
||||
save: "Enregistrer"
|
||||
users: "Utilisateur·rice·s"
|
||||
@ -36,29 +36,30 @@ copyContent: "Copier le contenu"
|
||||
copyLink: "Copier le lien"
|
||||
delete: "Supprimer"
|
||||
deleteAndEdit: "Supprimer et réécrire"
|
||||
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir effacer cette note et la modifier ? Vous perdrez toutes les réactions, renotes et réponses."
|
||||
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler ? Vous perdrez toutes les réactions, renotes et réponses y afférentes."
|
||||
addToList: "Ajouter à une liste"
|
||||
sendMessage: "Envoyer un message"
|
||||
copyUsername: "Copier le nom d'utilisateur"
|
||||
copyUsername: "Copier le nom d’utilisateur·rice"
|
||||
reply: "Répondre"
|
||||
loadMore: "Voir plus"
|
||||
loadMore: "Afficher plus …"
|
||||
youGotNewFollower: "Vous suit"
|
||||
receiveFollowRequest: "Demande de suivi reçue"
|
||||
followRequestAccepted: "La demande d'abonnement a été acceptée"
|
||||
receiveFollowRequest: "Demande d’abonnement reçue"
|
||||
followRequestAccepted: "La demande d’abonnement a été acceptée"
|
||||
mention: "Mentionner"
|
||||
mentions: "Mentions"
|
||||
directNotes: "Messages directs"
|
||||
directNotes: "Notes directes"
|
||||
importAndExport: "Import et export"
|
||||
import: "Importer"
|
||||
export: "Exporter"
|
||||
files: "Fichiers"
|
||||
download: "Télécharger"
|
||||
driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\" ? Les notes avec ce fichier joint seront aussi supprimées."
|
||||
unfollowConfirm: "Se désabonner de {name} ?"
|
||||
exportRequested: "Vous avez demandé une exportation. Cela pourrait prendre un peu de temps. Une fois l'exportation terminée, le fichier résultant sera ajouté dans le Drive."
|
||||
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
|
||||
exportRequested: "Vous avez demandé une exportation. L’opération pourrait prendre un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive."
|
||||
importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps."
|
||||
lists: "Listes"
|
||||
noLists: "Aucune liste"
|
||||
note: "Note"
|
||||
noLists: "Vous n’avez aucune liste"
|
||||
note: "Notes"
|
||||
notes: "Notes"
|
||||
following: "Abonnements"
|
||||
followers: "Abonné·e·s"
|
||||
@ -69,10 +70,10 @@ error: "Une erreur est survenue"
|
||||
retry: "Réessayer"
|
||||
enterListName: "Nom de la liste"
|
||||
privacy: "Confidentialité"
|
||||
makeFollowManuallyApprove: "Approuver manuellement les demandes de suivi"
|
||||
makeFollowManuallyApprove: "Accepter manuellement les demandes d’abonnement"
|
||||
defaultNoteVisibility: "Visibilité par défaut"
|
||||
follow: "S'abonner"
|
||||
followRequest: "Demande de suivi"
|
||||
follow: "S’abonner"
|
||||
followRequest: "Demande d’abonnement"
|
||||
followRequests: "Demandes d’abonnement"
|
||||
unfollow: "Se désabonner"
|
||||
followRequestPending: "En attente d’approbation"
|
||||
@ -86,7 +87,7 @@ clickToShow: "Cliquer pour afficher"
|
||||
sensitive: "Contenu sensible"
|
||||
add: "Ajouter"
|
||||
reaction: "Réactions"
|
||||
reactionSettingDescription: "Choisissez vos réactions préférées que vous souhaitez épingler dans le sélecteur de réaction."
|
||||
reactionSettingDescription: "Choisissez vos réactions préférées que vous souhaitez épingler dans le sélecteur de réactions."
|
||||
rememberNoteVisibility: "Se souvenir de la visibilité des notes"
|
||||
attachCancel: "Supprimer le fichier attaché"
|
||||
markAsSensitive: "Marquer comme sensible"
|
||||
@ -104,24 +105,25 @@ suspendConfirm: "Êtes-vous sûr·e de vouloir suspendre ce compte ?"
|
||||
unsuspendConfirm: "Êtes-vous sûr·e de vouloir annuler la suspension de ce compte ?"
|
||||
selectList: "Sélectionner une liste"
|
||||
customEmojis: "Émojis personnalisés"
|
||||
emoji: "Émoji"
|
||||
emojiName: "Nom de l’émoji"
|
||||
emojiUrl: "URL de l’émoji"
|
||||
addEmoji: "Ajouter un émoji"
|
||||
settingGuide: "Configuration suggérée"
|
||||
settingGuide: "Configuration proposée"
|
||||
cacheRemoteFiles: "Mise en cache des fichiers distants"
|
||||
cacheRemoteFilesDescription: "Quand ce paramètre est désactivé, les fichiers distants sont chargés directement depuis l'instance distante. Désactiver cela diminuera l'utilisation du stockage, mais augmentera le trafic réseau, puisque les miniatures ne seront pas générées."
|
||||
cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants sont chargés directement depuis l’instance distante. La désactiver diminuera certes l’utilisation de l’espace de stockage local mais augmentera le trafic réseau puisque les miniatures ne seront plus générées."
|
||||
flagAsBot: "Ce compte est un robot"
|
||||
flagAsCat: "Ce compte est un chat"
|
||||
autoAcceptFollowed: "Approuver automatiquement les demandes de suivi venant d'utilisateur·rice·s que vous suivez"
|
||||
autoAcceptFollowed: "Accepter automatiquement les demandes d’abonnement venant d’utilisateur·rice·s que vous suivez"
|
||||
addAcount: "Ajouter un compte"
|
||||
loginFailed: "Échec de la connexion"
|
||||
showOnRemote: "Voir sur l'instance distante"
|
||||
showOnRemote: "Voir sur l’instance distante"
|
||||
general: "Général"
|
||||
wallpaper: "Fond d'écran"
|
||||
setWallpaper: "Définir le fond d'écran"
|
||||
removeWallpaper: "Supprimer le fond d'écran"
|
||||
wallpaper: "Fond d’écran"
|
||||
setWallpaper: "Définir le fond d’écran"
|
||||
removeWallpaper: "Supprimer le fond d’écran"
|
||||
searchWith: "Recherche : {q}"
|
||||
youHaveNoLists: "Vous n'avez aucune liste"
|
||||
youHaveNoLists: "Vous n’avez aucune liste"
|
||||
followConfirm: "Êtes-vous sûr·e de vouloir suivre {name} ?"
|
||||
proxyAccount: "Compte proxy"
|
||||
proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions, comme un·e abonné·e distant·e pour les utilisateurs d'autres instances. Par exemple, quand un·e utilisateur·rice ajoute un·e utilisateur·rice distant·e à une liste, ses notes ne seront pas visibles sur l'instance si personne ne suit cet·te utilisateur·rice. Le compte proxy va donc suivre cet·te utilisateur·rice pour que ses notes soient acheminées."
|
||||
@ -139,7 +141,7 @@ storageUsage: "Stockage utilisé"
|
||||
charts: "Graphiques"
|
||||
perHour: "par heure"
|
||||
perDay: "par jour"
|
||||
stopActivityDelivery: "Arrêter l'envoi d'activités"
|
||||
stopActivityDelivery: "Arrêter l’envoi de l’activité"
|
||||
blockThisInstance: "Bloquer cette instance"
|
||||
operations: "Opérations"
|
||||
software: "Logiciel"
|
||||
@ -151,10 +153,10 @@ jobQueue: "File d’attente"
|
||||
cpuAndMemory: "Processeur et mémoire"
|
||||
network: "Réseau"
|
||||
disk: "Disque"
|
||||
instanceInfo: "Informations sur l'instance"
|
||||
instanceInfo: "Informations sur l’instance"
|
||||
statistics: "Statistiques"
|
||||
clearQueue: "Vider la file d'attente"
|
||||
clearQueueConfirmTitle: "Êtes-vous sûr·e de vouloir vider la file d'attente ?"
|
||||
clearQueue: "Vider la file d’attente"
|
||||
clearQueueConfirmTitle: "Êtes-vous sûr·e de vouloir vider la file d’attente ?"
|
||||
clearQueueConfirmText: "Les notes non distribuées ne seront pas livrées. Normalement, vous n'avez PAS besoin d'effectuer cette opération."
|
||||
clearCachedFiles: "Vider le cache"
|
||||
clearCachedFilesConfirm: "Êtes-vous sûr·e de vouloir vider le cache de fichiers distants ?"
|
||||
@ -163,18 +165,18 @@ blockedInstancesDescription: "Listez les instances que vous désirez bloquer, un
|
||||
muteAndBlock: "Masqué·e·s / Bloqué·e·s"
|
||||
mutedUsers: "Utilisateur·rice·s en sourdine"
|
||||
blockedUsers: "Utilisateur·rice·s bloqué·e·s"
|
||||
noUsers: "Il n'y a aucun utilisateur·rice"
|
||||
noUsers: "Il n’y a pas d’utilisateur·rice·s"
|
||||
editProfile: "Modifier votre profil"
|
||||
noteDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note ?"
|
||||
pinLimitExceeded: "Vous ne pouvez plus épingler d'autres notes."
|
||||
intro: "L'installation de Misskey est terminée ! Créons le compte administrateur."
|
||||
pinLimitExceeded: "Vous ne pouvez plus épingler d’autres notes."
|
||||
intro: "L’installation de Misskey est terminée ! Veuillez créer un compte administrateur."
|
||||
done: "Terminé"
|
||||
processing: "Traitement en cours"
|
||||
preview: "Prévisualisation"
|
||||
default: "Par défaut"
|
||||
noCustomEmojis: "Il n'y a pas d’émoji"
|
||||
customEmojisOfRemote: "Émojis d'autres instances"
|
||||
noJobs: "Il n'y a aucune tâche planifiée"
|
||||
customEmojisOfRemote: "Émojis provenant des autres instances"
|
||||
noJobs: "Il n’y a aucune tâche planifiée"
|
||||
federating: "En cours de fédération"
|
||||
blocked: "Bloqué·e"
|
||||
suspended: "Suspendu·e"
|
||||
@ -183,8 +185,8 @@ subscribing: "Abonné"
|
||||
publishing: "Publié"
|
||||
notResponding: "Ne répond pas"
|
||||
instanceFollowing: "Abonnements une instance"
|
||||
instanceFollowers: "Abonné·e·s de l'instance"
|
||||
instanceUsers: "Utilisateur·rice·s de l'instance"
|
||||
instanceFollowers: "Abonné·e·s de l’instance"
|
||||
instanceUsers: "Utilisateur·rice·s de cette l’instance"
|
||||
changePassword: "Modifier votre mot de passe"
|
||||
security: "Sécurité"
|
||||
retypedNotMatch: "Les saisies ne correspondent pas."
|
||||
@ -194,7 +196,7 @@ newPasswordRetype: "Répéter le nouveau mot de passe"
|
||||
attachFile: "Joindre un fichier"
|
||||
more: "Plus !"
|
||||
featured: "Tendances"
|
||||
usernameOrUserId: "Nom d'utilisateur ou ID utilisateur"
|
||||
usernameOrUserId: "Nom d’utilisateur·rice ou ID utilisateur"
|
||||
noSuchUser: "Utilisateur·rice non trouvé"
|
||||
lookup: "Recherche"
|
||||
announcements: "Annonces"
|
||||
@ -214,15 +216,15 @@ uploadFromUrlMayTakeTime: "Le téléversement de votre fichier peut prendre un c
|
||||
explore: "Découvrir"
|
||||
games: "Jeux de Misskey"
|
||||
messageRead: "Lus"
|
||||
noMoreHistory: "Il n'y a plus d'historique"
|
||||
noMoreHistory: "Il n’y a plus d’historique"
|
||||
startMessaging: "Commencer à discuter"
|
||||
nUsersRead: "Lu par {n} personnes"
|
||||
agreeTo: "J'accepte {0}"
|
||||
tos: "Conditions d'utilisation"
|
||||
agreeTo: "J’accepte {0}"
|
||||
tos: "les conditions d’utilisation"
|
||||
start: "Commencer"
|
||||
home: "Principal"
|
||||
remoteUserCaution: "Les informations peuvent être incomplètes, parce que l'utilisateur·rice est d'une instance distante."
|
||||
activity: "Activités"
|
||||
remoteUserCaution: "Les informations de ce compte risqueraient d’être incomplètes du fait que l’utilisateur·rice provient d’une instance distante."
|
||||
activity: "Activité"
|
||||
images: "Images"
|
||||
birthday: "Date de naissance"
|
||||
yearsOld: "{age} ans"
|
||||
@ -271,12 +273,12 @@ reject: "Refuser"
|
||||
normal: "Normal"
|
||||
instanceName: "Nom de l’instance"
|
||||
instanceDescription: "Description de l’instance"
|
||||
maintainerName: "Nom de l'administrateur·rice"
|
||||
maintainerEmail: "Email de l'administrateur·rice"
|
||||
tosUrl: "URL des conditions d'utilisation"
|
||||
maintainerName: "L’administrateur·rice"
|
||||
maintainerEmail: "Email de l’administrateur·rice"
|
||||
tosUrl: "URL des conditions d’utilisation"
|
||||
thisYear: "Cette année"
|
||||
thisMonth: "Ce mois-ci"
|
||||
today: "Aujourd'hui"
|
||||
today: "Aujourd’hui"
|
||||
dayX: "{day}"
|
||||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
@ -287,16 +289,16 @@ disconnectSerice: "Déconnecter"
|
||||
enableLocalTimeline: "Activer le fil local"
|
||||
enableGlobalTimeline: "Activer le fil global"
|
||||
disablingTimelinesInfo: "Si vous désactivez ces fils, les administrateurs et les modérateurs pourront toujours y accéder."
|
||||
registration: "S'inscrire"
|
||||
enableRegistration: "Autoriser n’importe qui à s’inscrire"
|
||||
registration: "S’inscrire"
|
||||
enableRegistration: "Autoriser les nouvelles inscriptions"
|
||||
invite: "Inviter"
|
||||
proxyRemoteFiles: "Proxy fichiers distants"
|
||||
proxyRemoteFilesDescription: "Si vous activez ce paramètre, les fichiers distants non stockés ou supprimés en raison d'une capacité excédentaire seront affichés via un proxy local et généreront une miniature. Cela n'affectera pas le stockage du serveur."
|
||||
driveCapacityPerLocalAccount: "Volume du Drive par utilisateur local"
|
||||
driveCapacityPerRemoteAccount: "Volume du Drive par utilisateur distant"
|
||||
inMb: "en mégaoctets"
|
||||
iconUrl: "URL de l'image de l'icône"
|
||||
bannerUrl: "URL de l'image de la bannière"
|
||||
iconUrl: "URL de l’image de l’avatar"
|
||||
bannerUrl: "URL de l’image de la bannière"
|
||||
basicInfo: "Informations basiques"
|
||||
pinnedUsers: "Utilisateur·rice épinglé·e"
|
||||
pinnedUsersDescription: "Listez les utilisateur·rice·s que vous souhaitez voir épinglé·e·s sur la page \"Découvrir\", un·e par ligne."
|
||||
@ -308,26 +310,26 @@ recaptcha: "reCAPTCHA"
|
||||
enableRecaptcha: "Activer reCAPTCHA"
|
||||
recaptchaSiteKey: "Clé du site"
|
||||
recaptchaSecretKey: "Clé secrète"
|
||||
avoidMultiCaptchaConfirm: "L'utilisation de plusieurs Captchas peut provoquer des interférences. Souhaitez-vous désactiver l'autre Captcha? Vous pouvez laisser plusieurs Captcha activés en appuyant sur Annuler."
|
||||
antennas: "Antenne"
|
||||
manageAntennas: "Gestion d'antenne"
|
||||
avoidMultiCaptchaConfirm: "L’utilisation de plusieurs Captchas peut provoquer des interférences. Souhaitez-vous désactiver l’autre Captcha ? Vous pouvez laisser plusieurs Captcha activés en appuyant sur Annuler."
|
||||
antennas: "Antennes"
|
||||
manageAntennas: "Gestion des antennes"
|
||||
name: "Nom"
|
||||
antennaSource: "Recevoir la source"
|
||||
antennaSource: "Source de l’antenne"
|
||||
antennaKeywords: "Mots clés à recevoir"
|
||||
antennaExcludeKeywords: "Mots clés à exclure"
|
||||
antennaKeywordsDescription: "Séparez avec des espaces pour une condition ET. Séparez avec un saut de ligne pour une condition OU."
|
||||
notifyAntenna: "Notifier les nouvelles notes"
|
||||
withFileAntenna: "Notes uniquement avec fichiers joints"
|
||||
antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
|
||||
notifyAntenna: "Me notifier pour les nouvelles notes"
|
||||
withFileAntenna: "Notes ayant des attachements uniquement"
|
||||
serviceworker: "ServiceWorker"
|
||||
enableServiceworker: "Activer ServiceWorker"
|
||||
antennaUsersDescription: "Spécifiez les noms d'utilisateurs séparés par des sauts de ligne"
|
||||
antennaUsersDescription: "Saisissez un seul nom d’utilisateur·rice par ligne"
|
||||
caseSensitive: "Sensible à la casse"
|
||||
withReplies: "Inclure les réponses"
|
||||
connectedTo: "Vous êtes connectés aux services suivants"
|
||||
notesAndReplies: "Notes et Réponses"
|
||||
withFiles: "Avec fichiers joints"
|
||||
silence: "Mettre en sourdine"
|
||||
silenceConfirm: "Êtes-vous sûr·e de vouloir mettre l'utilisateur·rice en sourdine ?"
|
||||
silenceConfirm: "Êtes-vous sûr·e de vouloir mettre l’utilisateur·rice en sourdine ?"
|
||||
unsilence: "Annuler la mise en sourdine"
|
||||
unsilenceConfirm: "Êtes-vous sûr·e de vouloir annuler la mise en sourdine de cette utilisateur·rice ?"
|
||||
popularUsers: "Utilisateur·rice·s populaires"
|
||||
@ -340,10 +342,10 @@ popularTags: "Mots-clés populaires"
|
||||
userList: "Listes"
|
||||
about: "Informations"
|
||||
aboutMisskey: "À propos de Misskey"
|
||||
aboutMisskeyText: "Misskey est un logiciel open source, développé par syuilo depuis 2014."
|
||||
aboutMisskeyText: "Misskey est un logiciel libre et ouvert, développé par syuilo depuis 2014."
|
||||
misskeyMembers: "Il est développé et maintenu par les membres listés ci-dessous :"
|
||||
misskeySource: "Le code source est disponible ici:"
|
||||
misskeyTranslation: "Aidez-nous avec votre contribution à traduire Misskey:"
|
||||
misskeyTranslation: "Aidez-nous en contribuant à traduire Misskey :"
|
||||
misskeyDonate: "Vous pouvez contribuer au développement de Misskey en faisant un don ici:"
|
||||
morePatrons: "Nous apprécions vraiment le soutien de nombreuses autres personnes non mentionnées ici. Merci à toutes et à tous ! 🥰"
|
||||
patrons: "Supporteurs"
|
||||
@ -361,12 +363,12 @@ passwordLessLogin: "Connectez-vous sans mot de passe"
|
||||
resetPassword: "Réinitialiser mot de passe"
|
||||
newPasswordIs: "Votre nouveau mot de passe est \"{password}\""
|
||||
autoReloadWhenDisconnected: "Rechargement automatique lorsque le serveur se déconnecte"
|
||||
autoNoteWatch: "Surveiller automatique pour les notes"
|
||||
autoNoteWatch: "Surveiller les notes automatiquement"
|
||||
autoNoteWatchDescription: "Soyez informé des notes auxquelles vous avez réagi ou répondu."
|
||||
reduceUiAnimation: "Réduire l'animation de l'interface"
|
||||
reduceUiAnimation: "Réduire les animations dans l’interface"
|
||||
share: "Partager"
|
||||
notFound: "Non trouvé"
|
||||
notFoundDescription: "Aucune page ne correspond à l'URL spécifiée."
|
||||
notFoundDescription: "Aucune page ne correspond à l’URL spécifiée."
|
||||
uploadFolder: "Emplacement de téléversement par défaut"
|
||||
cacheClear: "Vider le cache"
|
||||
markAsReadAllNotifications: "Marquer toutes les notifications comme lues"
|
||||
@ -398,7 +400,7 @@ quoteAttached: "Avec citation"
|
||||
quoteQuestion: "Souhaitez-vous ajoutez une citation ?"
|
||||
noMessagesYet: "Pas encore discuté"
|
||||
newMessageExists: "Vous avez un nouveau message"
|
||||
onlyOneFileCanBeAttached: "Vous ne pouvez joindre qu'un seul fichier au message"
|
||||
onlyOneFileCanBeAttached: "Vous ne pouvez joindre qu’un seul fichier au message"
|
||||
signinRequired: "Veuillez vous connecter"
|
||||
invitationCode: "Code d’invitation"
|
||||
checking: "Vérification"
|
||||
@ -410,20 +412,20 @@ tooLong: "Est trop long"
|
||||
weakPassword: "Faible mot de passe"
|
||||
normalPassword: "Bon mot de passe"
|
||||
strongPassword: "Fort mot de passe"
|
||||
passwordMatched: "Correcte"
|
||||
passwordMatched: "Combinaison correcte !"
|
||||
passwordNotMatched: "Ne correspond pas"
|
||||
signinWith: "Connectez-vous avec {x}"
|
||||
signinFailed: "Échec d’authentification. Veuillez vérifier que votre nom d’utilisateur et mot de passe sont corrects."
|
||||
tapSecurityKey: "Touchez la clé de sécurité"
|
||||
tapSecurityKey: "Appuyez sur votre clé de sécurité"
|
||||
or: "OU"
|
||||
uiLanguage: "Langue d'affichage de l'interface"
|
||||
uiLanguage: "Langue d’affichage de l’interface"
|
||||
groupInvited: "Invité au groupe"
|
||||
aboutX: "À propos de {x}"
|
||||
useOsNativeEmojis: "Utiliser les émojis natifs du système"
|
||||
youHaveNoGroups: "Vous n'avez aucune groupe"
|
||||
youHaveNoGroups: "Vous n’avez aucun groupe"
|
||||
joinOrCreateGroup: "Soyez invité à rejoindre les groupes ou vous pouvez créer votre propre groupe."
|
||||
noHistory: "Pas d'historique"
|
||||
disableAnimatedMfm: "Désactiver MFM qui a des animations"
|
||||
disableAnimatedMfm: "Désactiver MFM ayant des animations"
|
||||
doing: "Attends une seconde"
|
||||
category: "Catégories"
|
||||
tags: "Étiquettes"
|
||||
@ -433,14 +435,14 @@ existingAcount: "Comptes existants"
|
||||
regenerate: "Régénérer"
|
||||
fontSize: "Taille de la police"
|
||||
noFollowRequests: "Vous n’avez aucune demande d’abonnement en attente"
|
||||
openImageInNewTab: "Ouvrir l'image dans un nouvel onglet"
|
||||
openImageInNewTab: "Ouvrir les images dans un nouvel onglet"
|
||||
dashboard: "Tableau de bord"
|
||||
local: "Local"
|
||||
remote: "Distant"
|
||||
total: "Total"
|
||||
weekOverWeekChanges: "Diff hebdo"
|
||||
dayOverDayChanges: "Diff quotidien"
|
||||
accessibility: "Accessibilité"
|
||||
appearance: "Aspect"
|
||||
clinetSettings: "Paramètres du client"
|
||||
accountSettings: "Paramètres du compte"
|
||||
promotion: "Promu"
|
||||
@ -451,7 +453,7 @@ showFeaturedNotesInTimeline: "Afficher les notes en vedette dans fil d'actualit
|
||||
objectStorage: "Stockage d'objets"
|
||||
useObjectStorage: "Utiliser le stockage d'objets"
|
||||
objectStorageBaseUrl: "Base URL"
|
||||
objectStorageBaseUrlDesc: "Préfixe d'URL utilisé pour construire l'URL vers le référencement d'objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez l'adresse accessible au public selon le guide de service que vous allez utiliser. i.g 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>' pour GCS."
|
||||
objectStorageBaseUrlDesc: "Préfixe d’URL utilisé pour construire l’URL vers le référencement d’objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez l’adresse accessible au public selon le guide de service que vous allez utiliser. P.ex. 'https://<bucket>.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/<bucket>' pour GCS."
|
||||
objectStorageBucket: "Bucket"
|
||||
objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le service configuré."
|
||||
objectStoragePrefix: "Prefix"
|
||||
@ -474,7 +476,7 @@ none: "Rien"
|
||||
volume: "Volume"
|
||||
details: "Détails"
|
||||
chooseEmoji: "Choisissez un émoji"
|
||||
unableToProcess: "L'opération n'a pas pu être complétée"
|
||||
unableToProcess: "L’opération n’a pas pu être complétée."
|
||||
recentUsed: "Récemment utilisé"
|
||||
install: "Installation"
|
||||
uninstall: "Désinstaller"
|
||||
@ -495,13 +497,38 @@ updateRemoteUser: "Mettre à jour les informations de l’utilisateur·rice dist
|
||||
deleteAllFiles: "Supprimer tous les fichiers"
|
||||
deleteAllFilesConfirm: "Êtes vous surs de vouloir supprimer tous les fichiers ?"
|
||||
removeAllFollowing: "Retenir tous les abonnements"
|
||||
removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Exécutez cette commande si l'instance n'existe plus."
|
||||
removeAllFollowingDescription: "Se désabonner de tous les comptes de {host}. Veuillez lancer cette action uniquement si l’instance n’existe plus."
|
||||
userSuspended: "Cette utilisateur·trice a été suspendue."
|
||||
userSilenced: "Cette utilisateur·trice a été masquer."
|
||||
sidebar: "Barre latérale"
|
||||
divider: "Séparateur"
|
||||
addItem: "Ajouter élément"
|
||||
rooms: "Pièce"
|
||||
rooms: "Chambre"
|
||||
relays: "Relais"
|
||||
addRelay: "Ajouter un relais"
|
||||
inboxUrl: "Inbox URL"
|
||||
addedRelays: "Relais ajoutés"
|
||||
serviceworkerInfo: "Devrait être activé pour les notifications push."
|
||||
deletedNote: "Note supprimée"
|
||||
invisibleNote: "Note invisible"
|
||||
enableInfiniteScroll: "Activer le défilement infini"
|
||||
visibility: "Visibilité"
|
||||
poll: "Sondage"
|
||||
useCw: "Masquer le contenu"
|
||||
fixedWidgetsPosition: "Rendre la position du widget fixe"
|
||||
enablePlayer: "Activer le lecteur vidéo"
|
||||
disablePlayer: "Désactiver le lecteur vidéo"
|
||||
expandTweet: "Étendre le tweet"
|
||||
themeEditor: "Éditeur de thèmes"
|
||||
description: "Description"
|
||||
author: "Auteur·rice"
|
||||
leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ignorer ?"
|
||||
manage: "Gestion"
|
||||
plugins: "Extensions"
|
||||
pluginInstallWarn: "N’installez que des extensions provenant de sources de confiance."
|
||||
smtpHost: "Hôte"
|
||||
smtpUser: "Nom d’utilisateur·rice"
|
||||
smtpPass: "Mot de passe"
|
||||
_theme:
|
||||
explore: "Explorer les thèmes"
|
||||
install: "Installer un thème"
|
||||
@ -510,13 +537,42 @@ _theme:
|
||||
installed: "{name} a été installé"
|
||||
alreadyInstalled: "Ce thème est déjà installé"
|
||||
invalid: "Le format du thème n'est pas valide"
|
||||
make: "Créer un thème"
|
||||
base: "Base"
|
||||
defaultValue: "Valeur par défaut"
|
||||
color: "Couleur"
|
||||
key: "Clé "
|
||||
func: "Fonction"
|
||||
argument: "Argument"
|
||||
alpha: "Transparence"
|
||||
darken: "Assombrir"
|
||||
importInfo: "Vous pouvez importer un thème vers l’éditeur de thèmes en saisissant son code ici."
|
||||
keys:
|
||||
bg: "Arrière-plan"
|
||||
fg: "Texte"
|
||||
focus: "Mise au point"
|
||||
indicator: "Indicateur"
|
||||
panel: "Panneau"
|
||||
shadow: "Ombre"
|
||||
header: "Entête"
|
||||
navBg: "Fond de la barre latérale"
|
||||
navFg: "Texte de la barre latérale"
|
||||
link: "Lien"
|
||||
hashtag: "Hashtags"
|
||||
mention: "Mentionner"
|
||||
mentionMe: "Mentions (Moi)"
|
||||
renote: "Renote"
|
||||
divider: "Séparateur"
|
||||
infoWarnFg: "Texte d’avertissement"
|
||||
badge: "Badge"
|
||||
messageBg: "Arrière plan de la discussion"
|
||||
_sfx:
|
||||
note: "Nouvelle note"
|
||||
noteMy: "Ma note"
|
||||
notification: "Notifications"
|
||||
chat: "Discuter"
|
||||
chatBg: "Discuter (De fond)"
|
||||
antenna: "Réception d'antenne"
|
||||
antenna: "Réception de l’antenne"
|
||||
_ago:
|
||||
unknown: "Inconnu"
|
||||
future: "Futur"
|
||||
@ -536,33 +592,33 @@ _time:
|
||||
_tutorial:
|
||||
title: "Comment utiliser Misskey"
|
||||
step1_1: "Bienvenue,"
|
||||
step1_2: "Cette page est appelée \"fil d'actualité\". Elle montre les \"notes\" des personnes que vous \"abonne\" dans l'ordre chronologique."
|
||||
step1_3: "Vous n'avez pas encore publier de notes et personne n'est encore abonnements, vous ne devriez donc rien voir dans fil d'actualité."
|
||||
step2_1: "Finissons de créer votre profil avant d'écrire une note ou de abonne quelqu'un."
|
||||
step2_2: "En fournissant quelques informations sur vous, il sera plus facile pour les autres de vous abonne."
|
||||
step1_2: "Cette page est appelée « un fil ». Elle affiche les « notes » des personnes auxquelles vous êtes abonné dans un ordre chronologique."
|
||||
step1_3: "Votre fil est actuellement vide vu que vous ne suivez aucun compte et que vous n’avez publié aucune note, pour l’instant."
|
||||
step2_1: "Procédons d’abord à la préparation de votre profil avant d’écrire une note et/ou de vous abonner à un compte."
|
||||
step2_2: "En fournissant quelques informations sur vous, il sera plus facile pour les autres de s’abonner à votre compte."
|
||||
step3_1: "Vous avez fini de créer votre profil ?"
|
||||
step3_2: "L’étape suivante consiste à créer une note. Vous pouvez commencer en cliquant sur l’icône crayon sur l’écran."
|
||||
step3_3: "Remplissez le cadran et cliquez sur le bouton en haut à droite pour envoyer."
|
||||
step3_4: "Vous n'avez rien à dire ? Essayez de dire \"J'ai commencé à utiliser Misskey\"."
|
||||
step4_1: "Avez-vous posté votre première notes ?"
|
||||
step4_2: "Votre première note est maintenant affiché sur votre fil d'actualité."
|
||||
step5_1: "Ensuite, abonnons-nous d'autres personnes et rendre la fil d'actualité en savoir plus vivante."
|
||||
step5_2: "{featured} affiche les notes en tendance sur cette instance. {explore} vous permet de trouver les utilisateur·rice·s en tendance. Essayez de vous abonner aux gens que vous aimez !"
|
||||
step5_3: "Pour abonne un utilisateur, cliquez sur l'icône de l'utilisateur pour afficher la page de l'utilisateur et appuyez sur le bouton \"Abonnement\"."
|
||||
step5_4: "Selon l'utilisateur, il peut s'écouler un certain temps avant que la abonner ne soit approuvé."
|
||||
step6_1: "Si vous voyez la notes d'un autre utilisateur sur fil d'actualité, c'était réussi."
|
||||
step6_2: "Vous pouvez ajouter des \"réactions\" aux notes des autres afin de pouvoir facilement dire votre émotion."
|
||||
step6_3: "Pour ajouter une réaction, cliquez sur la marque \"+\" sur la note et sélectionnez la réaction souhaitée."
|
||||
step7_1: "Tu as bien travaillé ! Ceci conclut l'explication de l'utilisation de base de Misskey."
|
||||
step7_2: "Pour plus d'informations sur Misskey, voir {help}."
|
||||
step7_3: "Alors, profitez de Misskey 🚀"
|
||||
step3_4: "Vous n’avez rien à dire ? Essayez d’écrire « J’ai commencé à utiliser Misskey »."
|
||||
step4_1: "Avez-vous publié votre première note ?"
|
||||
step4_2: "Youpi ! Celle-ci est maintenant affiché sur votre fil d’actualité."
|
||||
step5_1: "Maintenant, essayons de nous abonner à d’autres personnes afin de rendre votre fil plus vivant."
|
||||
step5_2: "La page {featured} affiche les notes en tendance sur la présente instance et {explore} vous permet de trouver des utilisateur·rice·s en tendance. Essayez de vous abonner aux gens que vous aimez !"
|
||||
step5_3: "Pour pouvoir suivre d’autres utilisateur·rice, cliquez sur leur avatar afin d’afficher la page du profil utilisateur ensuite appuyez sur le bouton « S’abonner »."
|
||||
step5_4: "Si l’autre utilisateur possède une icône sous forme d’un cadenas à côté de son nom, il devra accepter votre demande d’abonnement manuellement."
|
||||
step6_1: "Maintenant, vous êtes en mesure de voir s’afficher les notes des autres utilisateur·rice·s sur votre propre fil."
|
||||
step6_2: "Vous avez également la possibilité d’intéragir rapidement avec les notes des autres utilisateur·rice·s en ajoutant des « réactions »."
|
||||
step6_3: "Pour ajouter une réaction à une note, cliquez sur le signe « + » de celle-ci et sélectionnez l’émoji souhaité."
|
||||
step7_1: "Félicitations ! Vous avez atteint la fin du tutoriel de base pour l’utilisation de Misskey."
|
||||
step7_2: "Si vous désirez en savoir plus sur Misskey, jetez un œil sur la section {help}."
|
||||
step7_3: "Bon courage et amusez-vous bien sur Misskey 🚀"
|
||||
_2fa:
|
||||
alreadyRegistered: "Cette étape à déjà été complétée"
|
||||
registerDevice: "Ajouter un appareil"
|
||||
registerDevice: "Ajouter un nouvel appareil"
|
||||
registerKey: "S’inscrire la clé"
|
||||
step1: "Tout d'abord, installez une application d'authentification, telle que {a} ou {b}, sur votre appareil."
|
||||
step2: "Ensuite, scannez le code QR affiché avec l'application."
|
||||
step3: "Entrez le jeton affiché sur l'application et vous avez terminé."
|
||||
step2: "Ensuite, scannez le code QR affiché sur l’écran."
|
||||
step3: "Entrez le jeton affiché sur votre application pour compléter la configuration."
|
||||
step4: "Lorsque vous vous connectez, entrez le jeton de la même manière."
|
||||
securityKeyInfo: "Vous pouvez configurer l'authentification WebAuthN pour sécuriser davantage le processus de connexion avec non seulement la clé de sécurité matérielle qui prend en charge FIDO2, mais également l'authentification par empreinte digitale ou PIN sur votre appareil."
|
||||
_permissions:
|
||||
@ -574,7 +630,7 @@ _permissions:
|
||||
"write:drive": "Écrire sur le Drive"
|
||||
"read:favorites": "Afficher les favoris"
|
||||
"write:favorites": "Écrire des favoris"
|
||||
"read:following": "Voir les informations de l'abonné"
|
||||
"read:following": "Voir les informations de vos abonnements"
|
||||
"write:following": "Abonnements/Se désabonner"
|
||||
"read:messaging": "Cherche à discuter"
|
||||
"write:messaging": "Contrôler le discuter"
|
||||
@ -588,23 +644,23 @@ _permissions:
|
||||
"write:votes": "Voter"
|
||||
"read:pages": "Afficher la page"
|
||||
"write:pages": "Mettre à jour les Pages"
|
||||
"read:page-likes": "Lire les favoris sur les Pages"
|
||||
"read:page-likes": "Voir les favoris sur les Pages"
|
||||
"write:page-likes": "Mettre à jour les favoris sur les Pages"
|
||||
"read:user-groups": "Voir les groupes d'utilisateur·rice·s"
|
||||
"write:user-groups": "Éditer les groupes des utilisateur·rice·s"
|
||||
_auth:
|
||||
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
||||
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
|
||||
permissionAsk: "Cette application nécessite les autorisations suivantes "
|
||||
pleaseGoBack: "Veillez retourner à l'application"
|
||||
permissionAsk: "Cette application nécessite les autorisations suivantes :"
|
||||
pleaseGoBack: "Veuillez retourner à l’application"
|
||||
callback: "Retour vers l’application"
|
||||
denied: "Accès refusé"
|
||||
_antennaSources:
|
||||
all: "Toutes les notes"
|
||||
homeTimeline: "Notes de l'utilisateur auquel je m'abonne"
|
||||
users: "Notes des un ou plusieurs utilisateurs spécifiés"
|
||||
userList: "Notes pour les utilisateurs de la liste spécifiée"
|
||||
userGroup: "Notes pour les utilisateurs de la groupe spécifiée"
|
||||
homeTimeline: "Notes venant des utilisateur·rice·s auxquel·les je suis abonné"
|
||||
users: "Notes venant de la part d’utilisateur·rice·s précis"
|
||||
userList: "Notes venant d’une liste spécifique"
|
||||
userGroup: "Notes venant d’utilisateur·rice·s du groupe spécifié"
|
||||
_weekday:
|
||||
sunday: "Dimanche"
|
||||
monday: "Lundi"
|
||||
@ -616,19 +672,20 @@ _weekday:
|
||||
_widgets:
|
||||
memo: "Note collante"
|
||||
notifications: "Notifications"
|
||||
timeline: "Fil d'actualité"
|
||||
timeline: "Fil"
|
||||
calendar: "Calendrier"
|
||||
trends: "Tendances"
|
||||
clock: "Horloge"
|
||||
rss: "Lecteur de flux RSS"
|
||||
activity: "Activités"
|
||||
activity: "Activité"
|
||||
photos: "Photos"
|
||||
digitalClock: "Horloge numérique"
|
||||
federation: "Fédération"
|
||||
_cw:
|
||||
hide: "Masquer"
|
||||
show: "Voir plus"
|
||||
show: "Afficher plus …"
|
||||
chars: "{count} caractères"
|
||||
files: "{count} fichiers"
|
||||
poll: "Sondage"
|
||||
_poll:
|
||||
noOnlyOneChoice: "Au moins 2 réponses nécéssaires"
|
||||
choiceN: "Choix {n}"
|
||||
@ -637,7 +694,7 @@ _poll:
|
||||
expiration: "Fin du sondage"
|
||||
infinite: "Illimité"
|
||||
at: "Choisir une date"
|
||||
after: "Chosir une durée"
|
||||
after: "Choisir la durée"
|
||||
deadlineDate: "Date de fin"
|
||||
deadlineTime: "Heure de fin"
|
||||
duration: "Durée"
|
||||
@ -661,11 +718,12 @@ _visibility:
|
||||
specified: "Direct"
|
||||
specifiedDescription: "Publier uniquement aux utilisateur·rice·s mentionné·e·s"
|
||||
localOnly: "Local seulement"
|
||||
localOnlyDescription: "Caché pour les utilisateurs distant"
|
||||
_postForm:
|
||||
replyPlaceholder: "Répondre à cette note ..."
|
||||
quotePlaceholder: "Citez cette note ..."
|
||||
_placeholders:
|
||||
a: "Qu'est-ce qu'il se passe ?"
|
||||
a: "Quoi de neuf ?"
|
||||
b: "Quoi de neuf ?"
|
||||
c: "Qu’avez-vous en tête ?"
|
||||
d: "Désirez-vous publier quelques mots ?"
|
||||
@ -673,7 +731,7 @@ _postForm:
|
||||
f: "En attente de vos écrits ..."
|
||||
_profile:
|
||||
name: "Nom"
|
||||
username: "Nom d'utilisateur·rice"
|
||||
username: "Nom d’utilisateur·rice"
|
||||
description: "À propos de moi"
|
||||
youCanIncludeHashtags: "Vous pouvez également inclure des hashtags."
|
||||
metadata: "Informations complémentaires"
|
||||
@ -686,15 +744,15 @@ _exportOrImport:
|
||||
blockingList: "Bloquer"
|
||||
userLists: "Listes"
|
||||
_charts:
|
||||
federationInstancesIncDec: "Variation du nombre d'instances"
|
||||
federationInstancesTotal: "Nombre d'instances au total"
|
||||
federationInstancesIncDec: "Variation du nombre des instances fédérées"
|
||||
federationInstancesTotal: "Nombre total des instances fédérées"
|
||||
usersIncDec: "Variation du nombre d'utilisateur·rice·s"
|
||||
usersTotal: "Nombre d'utilisateur·rice·s au total"
|
||||
usersTotal: "Nombre des utilisateur·rice·s au total"
|
||||
activeUsers: "Utilisateur·rice·s actif·ve·s"
|
||||
notesIncDec: "Variation du nombre d'notes"
|
||||
notesIncDec: "Variation du nombre des notes"
|
||||
localNotesIncDec: "Variation du nombre de notes local"
|
||||
remoteNotesIncDec: "Variation du nombre d’notes distant"
|
||||
notesTotal: "Nombre d'notes au total"
|
||||
notesTotal: "Nombre total des notes"
|
||||
filesIncDec: "Variation du nombre de fichiers"
|
||||
filesTotal: "Nombre de fichiers au total"
|
||||
storageUsageIncDec: "Variation de l'utilisation du stockage"
|
||||
@ -703,8 +761,8 @@ _instanceCharts:
|
||||
requests: "Requêtes"
|
||||
users: "Variation du nombre d'utilisateur·rice·s"
|
||||
usersTotal: "Nombre d'utilisateur·rice·s au total cumulé"
|
||||
notes: "Variation du nombre d'notes"
|
||||
notesTotal: "Nombre d'notes au total cumulé"
|
||||
notes: "Variation du nombre des notes"
|
||||
notesTotal: "Nombre total cumulé des notes"
|
||||
ff: "Variation des abonné·e·s"
|
||||
ffTotal: "Nombre d'abonné·e·s au total cumulé"
|
||||
cacheSize: "Variation de la taille du cache"
|
||||
@ -717,7 +775,7 @@ _timelines:
|
||||
social: "Social"
|
||||
global: "Global"
|
||||
_rooms:
|
||||
roomOf: "Pièce de {user}"
|
||||
roomOf: "Chambre de {user}"
|
||||
addFurniture: "Placer des meubles"
|
||||
translate: "Déplacer"
|
||||
rotate: "Pivoter"
|
||||
@ -727,7 +785,7 @@ _rooms:
|
||||
clearConfirm: "Désirez-vous enlever tout les meubles de votre chambre ?"
|
||||
leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous vraiment quitter ?"
|
||||
chooseImage: "Sélectionnez une image"
|
||||
roomType: "Style de pièce"
|
||||
roomType: "Type de chambre"
|
||||
carpetColor: "Couleur du tapis"
|
||||
_roomType:
|
||||
default: "Par défaut"
|
||||
@ -776,6 +834,8 @@ _rooms:
|
||||
cup-noodle: "Bol de nouilles"
|
||||
holo-display: "Affichage holographique"
|
||||
energy-drink: "Boisson énergétique"
|
||||
doll-ai: "Poupée Ai"
|
||||
banknote: "Billets de banque"
|
||||
_pages:
|
||||
newPage: "Créer une page"
|
||||
editPage: "Modifier une page"
|
||||
@ -785,14 +845,14 @@ _pages:
|
||||
deleted: "La page a bien été supprimée"
|
||||
nameAlreadyExists: "La URL de page spécifiée existe déjà"
|
||||
invalidNameTitle: "La URL de la page spécifiée n’est pas valide"
|
||||
invalidNameText: "Assurez-vous qu'il n'est pas vide"
|
||||
invalidNameText: "Assurez-vous qu’il n’est pas vide"
|
||||
editThisPage: "Éditer cette page"
|
||||
viewSource: "Afficher la source"
|
||||
viewPage: "Afficher la page"
|
||||
like: "Favori"
|
||||
unlike: "Je n’favoris pas"
|
||||
unlike: "Je n’aime pas"
|
||||
my: "Mes pages"
|
||||
liked: "Pages favoris"
|
||||
liked: "Pages favorites"
|
||||
inspector: "Inspecteur"
|
||||
content: "Bloc de page"
|
||||
variables: "Variables"
|
||||
@ -808,7 +868,7 @@ _pages:
|
||||
eyeCatchingImageRemove: "Supprimer une image attirante"
|
||||
chooseBlock: "Ajouter un bloc"
|
||||
selectType: "Choisir un type"
|
||||
enterVariableName: "Veuillez entrer un nom de variable"
|
||||
enterVariableName: "Veuillez entrer un nom pour votre variable"
|
||||
variableNameIsAlreadyUsed: "Cette variable est déjà utilisée"
|
||||
contentBlocks: "Contenu"
|
||||
inputBlocks: "Entrée"
|
||||
@ -868,8 +928,8 @@ _pages:
|
||||
resetRandom: "Réinitialiser le nombre aléatoire"
|
||||
pushEvent: "Envoyer un évènement"
|
||||
_pushEvent:
|
||||
event: "Nom de l'évènement"
|
||||
message: "Message à afficher lorsque appuyé"
|
||||
event: "Nom de l’évènement"
|
||||
message: "Message à afficher lorsqu’il est activé"
|
||||
variable: "Variable à envoyer"
|
||||
no-variable: "Rien"
|
||||
callAiScript: "Appeler AiScript"
|
||||
@ -898,8 +958,8 @@ _pages:
|
||||
multiLineText: "Texte (Multi-lignes)"
|
||||
textList: "Liste de texte"
|
||||
_textList:
|
||||
info: "Veuillez séparer chacun avec une nouvelle ligne"
|
||||
strLen: "Longueur d'un texte"
|
||||
info: "Veuillez séparer chaque entrée avec un saut de ligne"
|
||||
strLen: "Longueur du texte"
|
||||
_strLen:
|
||||
arg1: "Texte"
|
||||
strPick: "Extraire un caractère"
|
||||
@ -1057,3 +1117,32 @@ _pages:
|
||||
enviromentVariables: "Variables d'environnement"
|
||||
pageVariables: "Élément de page"
|
||||
argVariables: "Entrée slot"
|
||||
_relayStatus:
|
||||
requesting: "En attente"
|
||||
accepted: "Accepté"
|
||||
rejected: "Refusée"
|
||||
_notification:
|
||||
fileUploaded: "Le fichier a été téléversé !"
|
||||
youGotMention: "{name} vous a mentionné"
|
||||
youGotReply: "Réponse de {name}"
|
||||
youGotQuote: "Cité·e par {name}"
|
||||
youRenoted: "{name} vous a Renoté"
|
||||
youGotPoll: "{name} a participé à votre sondage"
|
||||
youGotMessagingMessageFromUser: "{name} vous envoyé un message"
|
||||
youGotMessagingMessageFromGroup: "Un message a été envoyé au groupe {name}"
|
||||
youWereFollowed: "Vous suit"
|
||||
youReceivedFollowRequest: "Vous avez reçu une demande d’abonnement"
|
||||
yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté"
|
||||
youWereInvitedToGroup: "Invité au groupe"
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Toujours afficher la colonne principale"
|
||||
columnAlign: "Aligner les colonnes"
|
||||
addColumn: "Ajouter une colonne"
|
||||
_columns:
|
||||
widgets: "Widgets"
|
||||
notifications: "Notifications"
|
||||
tl: "Fil"
|
||||
antenna: "Antennes"
|
||||
list: "Listes"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct"
|
||||
|
@ -14,6 +14,7 @@ const merge = (...args) => args.reduce((a, c) => ({
|
||||
}), {});
|
||||
|
||||
const languages = [
|
||||
'ar-SA',
|
||||
//'cs-CZ',
|
||||
//'da-DK',
|
||||
'de-DE',
|
||||
|
@ -45,6 +45,7 @@ loadMore: "もっと見る"
|
||||
youGotNewFollower: "フォローされました"
|
||||
receiveFollowRequest: "フォローリクエストされました"
|
||||
followRequestAccepted: "フォローが承認されました"
|
||||
mention: "メンション"
|
||||
mentions: "あなた宛て"
|
||||
directNotes: "ダイレクト投稿"
|
||||
importAndExport: "インポートとエクスポート"
|
||||
@ -103,7 +104,10 @@ unblockConfirm: "ブロック解除しますか?"
|
||||
suspendConfirm: "凍結しますか?"
|
||||
unsuspendConfirm: "解凍しますか?"
|
||||
selectList: "リストを選択"
|
||||
selectAntenna: "アンテナを選択"
|
||||
selectWidget: "ウィジェットを選択"
|
||||
customEmojis: "カスタム絵文字"
|
||||
emoji: "絵文字"
|
||||
emojiName: "絵文字名"
|
||||
emojiUrl: "絵文字画像URL"
|
||||
addEmoji: "絵文字を追加"
|
||||
@ -440,7 +444,7 @@ remote: "リモート"
|
||||
total: "合計"
|
||||
weekOverWeekChanges: "前週比"
|
||||
dayOverDayChanges: "前日比"
|
||||
accessibility: "アクセシビリティ"
|
||||
appearance: "アピアランス"
|
||||
clinetSettings: "クライアント設定"
|
||||
accountSettings: "アカウント設定"
|
||||
promotion: "プロモーション"
|
||||
@ -506,6 +510,49 @@ relays: "リレー"
|
||||
addRelay: "リレーの追加"
|
||||
inboxUrl: "inboxのURL"
|
||||
addedRelays: "追加済みのリレー"
|
||||
serviceworkerInfo: "プッシュ通知を行うには有効する必要があります。"
|
||||
deletedNote: "削除された投稿"
|
||||
invisibleNote: "非公開の投稿"
|
||||
enableInfiniteScroll: "自動でもっと見る"
|
||||
visibility: "公開範囲"
|
||||
poll: "アンケート"
|
||||
useCw: "内容を隠す"
|
||||
fixedWidgetsPosition: "ウィジェットの位置を固定する"
|
||||
enablePlayer: "プレイヤーを開く"
|
||||
disablePlayer: "プレイヤーを閉じる"
|
||||
expandTweet: "ツイートを展開する"
|
||||
themeEditor: "テーマエディター"
|
||||
description: "説明"
|
||||
author: "作者"
|
||||
leaveConfirm: "未保存の変更があります。破棄しますか?"
|
||||
manage: "管理"
|
||||
plugins: "プラグイン"
|
||||
pluginInstallWarn: "信頼できないプラグインはインストールしないでください。"
|
||||
deck: "デッキ"
|
||||
undeck: "デッキ解除"
|
||||
useBlurEffectForModal: "モーダルにぼかし効果を使用"
|
||||
generateAccessToken: "アクセストークンの発行"
|
||||
permission: "権限"
|
||||
enableAll: "全て有効にする"
|
||||
disableAll: "全て無効にする"
|
||||
tokenRequested: "アカウントへのアクセス許可"
|
||||
pluginTokenRequestedDescription: "このプラグインはここで設定した権限を行使できるようになります。"
|
||||
notificationType: "通知の種類"
|
||||
edit: "編集"
|
||||
useStarForReactionFallback: "リアクション絵文字が不明な場合、代わりに★を使う"
|
||||
emailConfig: "メールサーバー設定"
|
||||
enableEmail: "メール配信機能を有効化する"
|
||||
emailConfigInfo: "メールアドレスの確認やパスワードリセットの際に使います"
|
||||
email: "メールアドレス"
|
||||
smtpConfig: "SMTP サーバーの設定"
|
||||
smtpHost: "ホスト"
|
||||
smtpPort: "ポート"
|
||||
smtpUser: "ユーザー名"
|
||||
smtpPass: "パスワード"
|
||||
emptyToDisableSmtpAuth: "ユーザー名とパスワードを空欄にすることで、SMTP認証を無効化出来ます"
|
||||
smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
|
||||
smtpSecureInfo: "STARTTLS使用時はオフにします。"
|
||||
testEmail: "配信テスト"
|
||||
|
||||
_theme:
|
||||
explore: "テーマを探す"
|
||||
@ -515,6 +562,70 @@ _theme:
|
||||
installed: "{name}をインストールしました"
|
||||
alreadyInstalled: "そのテーマは既にインストールされています"
|
||||
invalid: "テーマの形式が間違っています"
|
||||
make: "テーマを作る"
|
||||
base: "ベース"
|
||||
addConstant: "定数を追加"
|
||||
constant: "定数"
|
||||
defaultValue: "デフォルト値"
|
||||
color: "色"
|
||||
refProp: "プロパティを参照"
|
||||
refConst: "定数を参照"
|
||||
key: "キー"
|
||||
func: "関数"
|
||||
funcKind: "関数の種類"
|
||||
argument: "引数"
|
||||
basedProp: "元にするプロパティの名前"
|
||||
alpha: "不透明度"
|
||||
darken: "暗さ"
|
||||
lighten: "明るさ"
|
||||
inputConstantName: "定数名を入力してください"
|
||||
importInfo: "ここにテーマコードを貼り付けて、エディターにインポートできます"
|
||||
deleteConstantConfirm: "定数 {const} を削除しても良いですか?"
|
||||
|
||||
keys:
|
||||
accent: "アクセント"
|
||||
bg: "背景"
|
||||
fg: "文字"
|
||||
focus: "フォーカス"
|
||||
indicator: "インジケーター"
|
||||
panel: "パネル"
|
||||
shadow: "影"
|
||||
header: "ヘッダー"
|
||||
navBg: "サイドバーの背景"
|
||||
navFg: "サイドバーの文字"
|
||||
navHoverFg: "サイドバー文字(ホバー)"
|
||||
navActive: "サイドバー文字(アクティブ)"
|
||||
navIndicator: "サイドバーのインジケーター"
|
||||
link: "リンク"
|
||||
hashtag: "ハッシュタグ"
|
||||
mention: "メンション"
|
||||
mentionMe: "あなた宛てメンション"
|
||||
renote: "Renote"
|
||||
modalBg: "モーダルの背景"
|
||||
divider: "分割線"
|
||||
scrollbarHandle: "スクロールバーの取っ手"
|
||||
scrollbarHandleHover: "スクロールバーの取っ手(ホバー)"
|
||||
dateLabelFg: "日付ラベルの文字"
|
||||
infoBg: "情報の背景"
|
||||
infoFg: "情報の文字"
|
||||
infoWarnBg: "警告の背景"
|
||||
infoWarnFg: "警告の文字"
|
||||
cwBg: "CW ボタンの背景"
|
||||
cwFg: "CW ボタンの文字"
|
||||
cwHoverBg: "CW ボタンの背景 (ホバー)"
|
||||
toastBg: "通知トーストの背景"
|
||||
toastFg: "通知トーストの文字"
|
||||
buttonBg: "ボタンの背景"
|
||||
buttonHoverBg: "ボタンの背景 (ホバー)"
|
||||
inputBorder: "入力ボックスの縁取り"
|
||||
listItemHoverBg: "リスト項目の背景 (ホバー)"
|
||||
driveFolderBg: "ドライブフォルダーの背景"
|
||||
wallpaperOverlay: "壁紙のオーバーレイ"
|
||||
badge: "バッジ"
|
||||
messageBg: "チャットの背景"
|
||||
accentDarken: "アクセント (暗め)"
|
||||
accentLighten: "アクセント (明るめ)"
|
||||
fgHighlighted: "強調された文字"
|
||||
|
||||
_sfx:
|
||||
note: "ノート"
|
||||
@ -638,13 +749,14 @@ _widgets:
|
||||
rss: "RSSリーダー"
|
||||
activity: "アクティビティ"
|
||||
photos: "フォト"
|
||||
digitalClock: "デジタル時計"
|
||||
federation: "連合"
|
||||
|
||||
_cw:
|
||||
hide: "隠す"
|
||||
show: "もっと見る"
|
||||
chars: "{count}文字"
|
||||
files: "{count}ファイル"
|
||||
poll: "アンケート"
|
||||
|
||||
_poll:
|
||||
noOnlyOneChoice: "選択肢は最低2つ必要です"
|
||||
@ -679,6 +791,7 @@ _visibility:
|
||||
specified: "ダイレクト"
|
||||
specifiedDescription: "指定したユーザーのみに公開"
|
||||
localOnly: "ローカルのみ"
|
||||
localOnlyDescription: "リモートユーザーには非公開"
|
||||
|
||||
_postForm:
|
||||
replyPlaceholder: "このノートに返信..."
|
||||
@ -801,6 +914,8 @@ _rooms:
|
||||
cup-noodle: "カップ麺"
|
||||
holo-display: "ホログラフィックディスプレイ"
|
||||
energy-drink: "エナジードリンク"
|
||||
doll-ai: "藍ちゃん人形"
|
||||
banknote: "札束"
|
||||
|
||||
_pages:
|
||||
newPage: "ページの作成"
|
||||
@ -1099,3 +1214,48 @@ _relayStatus:
|
||||
requesting: "承認待ち"
|
||||
accepted: "承認済み"
|
||||
rejected: "拒否済み"
|
||||
|
||||
_notification:
|
||||
fileUploaded: "ファイルがアップロードされました"
|
||||
youGotMention: "{name}からのメンション"
|
||||
youGotReply: "{name}からのリプライ"
|
||||
youGotQuote: "{name}による引用"
|
||||
youRenoted: "{name}がRenoteしました"
|
||||
youGotPoll: "{name}が投票しました"
|
||||
youGotMessagingMessageFromUser: "{name}からのチャットがあります"
|
||||
youGotMessagingMessageFromGroup: "{name}のチャットがあります"
|
||||
youWereFollowed: "フォローされました"
|
||||
youReceivedFollowRequest: "フォローリクエストが来ました"
|
||||
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
||||
youWereInvitedToGroup: "グループに招待されました"
|
||||
|
||||
_types:
|
||||
all: "すべて"
|
||||
follow: "フォロー"
|
||||
mention: "メンション"
|
||||
reply: "リプライ"
|
||||
renote: "Renote"
|
||||
quote: "引用"
|
||||
reaction: "リアクション"
|
||||
pollVote: "投票"
|
||||
receiveFollowRequest: "フォローリクエスト"
|
||||
|
||||
_deck:
|
||||
alwaysShowMainColumn: "常にメインカラムを表示"
|
||||
columnAlign: "カラムの寄せ"
|
||||
addColumn: "カラムを追加"
|
||||
swapLeft: "左に移動"
|
||||
swapRight: "右に移動"
|
||||
swapUp: "上に移動"
|
||||
swapDown: "下に移動"
|
||||
stackLeft: "左に重ねる"
|
||||
popRight: "右に出す"
|
||||
|
||||
_columns:
|
||||
widgets: "ウィジェット"
|
||||
notifications: "通知"
|
||||
tl: "タイムライン"
|
||||
antenna: "アンテナ"
|
||||
list: "リスト"
|
||||
mentions: "あなた宛て"
|
||||
direct: "ダイレクト"
|
||||
|
@ -38,6 +38,8 @@ delete: "ほかす"
|
||||
deleteAndEdit: "ほかして直す"
|
||||
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Remote、返信も全部消えんで"
|
||||
addToList: "リストに入れたる"
|
||||
sendMessage: "メッセージを送る"
|
||||
copyUsername: "ユーザー名をコピー"
|
||||
reply: "返す"
|
||||
loadMore: "もっとあるやろ!"
|
||||
youGotNewFollower: "フォローされたで"
|
||||
@ -45,14 +47,26 @@ receiveFollowRequest: "フォローリクエストされたで"
|
||||
followRequestAccepted: "フォローが承認されたで"
|
||||
mentions: "あんた宛て"
|
||||
directNotes: "ダイレクト投稿"
|
||||
importAndExport: "インポートとエクスポート"
|
||||
import: "インポート"
|
||||
export: "エクスポート"
|
||||
files: "ファイル"
|
||||
download: "ダウンロード"
|
||||
driveFileDeleteConfirm: "ファイル「{name}」を消してしもうてええか?このファイルを添付したノートも消えてまうで。"
|
||||
unfollowConfirm: "{name}のフォローを解除してもええんか?"
|
||||
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
|
||||
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
|
||||
lists: "リスト"
|
||||
noLists: "リストはあらへん"
|
||||
note: "ノート"
|
||||
notes: "ノート"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
followsYou: "フォローされとるで"
|
||||
createList: "リスト作る"
|
||||
manageLists: "リストの管理"
|
||||
error: "問題が発生してん"
|
||||
retry: "もっぺんやってみる"
|
||||
enterListName: "リスト名を入れてや"
|
||||
privacy: "プライバシーってなんや?オカンの年齢か?"
|
||||
makeFollowManuallyApprove: "他人のフォローは許可してからや!"
|
||||
@ -60,13 +74,20 @@ defaultNoteVisibility: "もとからの公開範囲"
|
||||
follow: "フォロー"
|
||||
followRequest: "フォロー許してくれや!言うてみる"
|
||||
followRequests: "フォロー許してくれや!"
|
||||
unfollow: "フォローやめる"
|
||||
followRequestPending: "フォロー許してくれるん待っとる"
|
||||
enterEmoji: "絵文字を入れてや"
|
||||
renote: "Renote"
|
||||
unrenote: "Renoteやめる"
|
||||
quote: "引用"
|
||||
pinnedNote: "ピン留めされたノート"
|
||||
you: "あんた"
|
||||
clickToShow: "押してみ、見せたるわ"
|
||||
sensitive: "見たらあかんで"
|
||||
add: "増やす"
|
||||
reaction: "リアクション"
|
||||
reactionSettingDescription: "リアクションピッカーに出しとくリアクションを選んでや。"
|
||||
rememberNoteVisibility: "公開範囲覚えといて"
|
||||
attachCancel: "くっつけるのやめよか"
|
||||
markAsSensitive: "ちょっと見せられへんわ"
|
||||
unmarkAsSensitive: "別にええんじゃね?"
|
||||
@ -77,45 +98,271 @@ block: "ブロック"
|
||||
unblock: "ブロックやめたる"
|
||||
suspend: "凍結"
|
||||
unsuspend: "溶かす"
|
||||
blockConfirm: "ブロックしてしもうてええか?"
|
||||
unblockConfirm: "ブロックすんのやめるけどええか?"
|
||||
suspendConfirm: "凍結してしもうてええか?"
|
||||
unsuspendConfirm: "解凍するけどええか?"
|
||||
selectList: "リストを選ぶ"
|
||||
customEmojis: "カスタム絵文字"
|
||||
emojiName: "絵文字名"
|
||||
emojiUrl: "絵文字画像URL"
|
||||
addEmoji: "絵文字を追加"
|
||||
settingGuide: "ええ感じの設定"
|
||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||
cacheRemoteFilesDescription: "この設定をチャラにすると、リモートファイルをキャッシュせず直リンクするようになります。サーバーのストレージを節約できますが、サムネイルが生成されへんので通信量が増加します。"
|
||||
flagAsBot: "Botやでと言っとく"
|
||||
flagAsCat: "Catやでと言っとく"
|
||||
autoAcceptFollowed: "フォローしとるユーザーからのフォロリクは全部勝手にええでって言うで"
|
||||
addAcount: "アカウント追加"
|
||||
loginFailed: "ログインに失敗してん"
|
||||
showOnRemote: "リモートで見る"
|
||||
general: "全般"
|
||||
wallpaper: "壁紙"
|
||||
setWallpaper: "壁紙を設定"
|
||||
removeWallpaper: "壁紙ほかす"
|
||||
searchWith: "検索: {q}"
|
||||
youHaveNoLists: "リストはあらへん"
|
||||
followConfirm: "{name}をフォローしてええか?"
|
||||
proxyAccount: "プロキシアカウント"
|
||||
proxyAccountDescription: "プロキシアカウントは、代わりにフォローしてくれるアカウントや。例えば、551に豚まんが無いときやったり、ユーザーがリモートユーザーをアカウントに入れたとき、リストに入れられたユーザーが誰からもフォローされてないと寂しいやん。寂しいし、アクティビティも配達されへんから、プロキシアカウントがフォローしてくれるで。ええやつやん…"
|
||||
host: "ホスト"
|
||||
selectUser: "ユーザーを選ぶ"
|
||||
recipient: "宛先"
|
||||
annotation: "注釈"
|
||||
federation: "連合"
|
||||
instances: "インスタンス"
|
||||
registeredAt: "一見さんになった日"
|
||||
latestRequestSentAt: "ちょっと前のリクエスト送信"
|
||||
latestRequestReceivedAt: "ちょっと前のリクエスト受信"
|
||||
latestStatus: "ちょっと前のステータス"
|
||||
storageUsage: "ストレージ使うた量"
|
||||
charts: "チャート"
|
||||
perHour: "1時間ごと"
|
||||
perDay: "1日ごと"
|
||||
stopActivityDelivery: "アクティビティの配送をやめる"
|
||||
blockThisInstance: "このインスタンスをブロック"
|
||||
operations: "操作"
|
||||
software: "ソフトウェア"
|
||||
version: "バージョン"
|
||||
metadata: "メタデータ"
|
||||
withNFiles: "{n}個のファイル"
|
||||
monitor: "モニター"
|
||||
jobQueue: "ジョブキュー"
|
||||
cpuAndMemory: "CPUとメモリ"
|
||||
network: "ネットワーク"
|
||||
disk: "ディスク"
|
||||
instanceInfo: "インスタンス情報"
|
||||
statistics: "統計"
|
||||
clearQueue: "キューにさいなら"
|
||||
clearQueueConfirmTitle: "キューをクリアしまっか?"
|
||||
clearQueueConfirmText: "未配達の投稿は配送されなくなるで。通常この操作を行う必要はあらへんや。"
|
||||
clearCachedFiles: "キャッシュにさいなら"
|
||||
clearCachedFilesConfirm: "キャッシュされとるリモートファイルを全部削除しまっか?"
|
||||
blockedInstances: "インスタンスブロック"
|
||||
blockedInstancesDescription: "ブロックしたいインスタンスのホストを改行で区切って設定してな。ブロックされてもうたインスタンスとはもう金輪際やり取りできひんくなるで。"
|
||||
muteAndBlock: "ミュートとブロック"
|
||||
mutedUsers: "ミュートしたユーザー"
|
||||
blockedUsers: "ブロックしたユーザー"
|
||||
noUsers: "ユーザーはおらへん"
|
||||
editProfile: "プロフィールをいじる"
|
||||
noteDeleteConfirm: "このノートを削除しまっか?"
|
||||
pinLimitExceeded: "これ以上ピン留めできひん"
|
||||
intro: "Misskeyのインストールが完了してん!管理者アカウントを作ってや。"
|
||||
done: "でけた"
|
||||
processing: "処理しとる"
|
||||
preview: "プレビュー"
|
||||
default: "デフォルト"
|
||||
noCustomEmojis: "絵文字はあらへん"
|
||||
customEmojisOfRemote: "リモートの絵文字"
|
||||
noJobs: "ジョブはあらへん"
|
||||
federating: "連合しとる"
|
||||
blocked: "ブロックしとる"
|
||||
suspended: "配信せぇへん"
|
||||
all: "みな"
|
||||
subscribing: "購読しとる"
|
||||
publishing: "配信しとる"
|
||||
notResponding: "応答してへんで"
|
||||
instanceFollowing: "インスタンスのフォロー"
|
||||
instanceFollowers: "インスタンスのフォロワー\n"
|
||||
instanceUsers: "インスタンスのユーザー"
|
||||
changePassword: "パスワード変える"
|
||||
security: "セキュリティ"
|
||||
retypedNotMatch: "そやないねん。"
|
||||
currentPassword: "今のパスワード"
|
||||
newPassword: "今度のパスワード"
|
||||
newPasswordRetype: "今度のパスワード(もっぺん入れて)"
|
||||
attachFile: "ファイルくっつけて"
|
||||
more: "他ないんか!"
|
||||
featured: "ハイライト"
|
||||
usernameOrUserId: "ユーザー名かユーザーID"
|
||||
noSuchUser: "ユーザーが見つからへんで"
|
||||
lookup: "見てきて"
|
||||
announcements: "これ知っといてな"
|
||||
imageUrl: "画像URL"
|
||||
remove: "ほかす"
|
||||
removed: "削除したで!"
|
||||
removeAreYouSure: "「{x}」はなおしてしもてええか?"
|
||||
saved: "保存したで!"
|
||||
messaging: "チャット"
|
||||
upload: "アップロード"
|
||||
fromDrive: "ドライブから"
|
||||
fromUrl: "URLから"
|
||||
uploadFromUrl: "URLアップロード"
|
||||
uploadFromUrlDescription: "このURLのファイルをアップロードしたいねん"
|
||||
uploadFromUrlRequested: "アップロードしたい言うといたで"
|
||||
uploadFromUrlMayTakeTime: "アップロード終わるんにちょい時間かかるかもしれへんわ。"
|
||||
explore: "みつける"
|
||||
games: "Misskey Games"
|
||||
messageRead: "もう読んだ"
|
||||
noMoreHistory: "これより過去の履歴はあらへんで"
|
||||
startMessaging: "チャットやるで"
|
||||
nUsersRead: "{n}人が読んでもうた"
|
||||
agreeTo: "{0}はええで"
|
||||
tos: "利用規約"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
remoteUserCaution: "リモートユーザーやから、ちゃんとした情報とちゃうで。"
|
||||
activity: "アクティビティ"
|
||||
images: "画像"
|
||||
birthday: "生まれた日"
|
||||
yearsOld: "{age}歳"
|
||||
registeredDate: "始めた日"
|
||||
location: "場所"
|
||||
theme: "テーマ"
|
||||
themeForLightMode: "ライトモードではこのテーマつこて"
|
||||
themeForDarkMode: "ダークモードではこのテーマつこて"
|
||||
light: "ライト"
|
||||
dark: "ダーク"
|
||||
lightThemes: "デイゲーム"
|
||||
darkThemes: "ナイトゲーム"
|
||||
syncDeviceDarkMode: "試合開始時間はデバイスのダークモードと一緒や"
|
||||
drive: "ドライブ"
|
||||
fileName: "ファイル名"
|
||||
selectFile: "ファイル選んでや"
|
||||
selectFiles: "ファイル選んでや"
|
||||
selectFolder: "フォルダ選んでや"
|
||||
selectFolders: "フォルダ選んでや"
|
||||
renameFile: "ファイル名をいらう"
|
||||
folderName: "フォルダー名"
|
||||
createFolder: "フォルダー作る"
|
||||
renameFolder: "フォルダー名を変える"
|
||||
deleteFolder: "フォルダーを消してまう"
|
||||
addFile: "ファイルを追加"
|
||||
emptyDrive: "ドライブにはなんも残っとらん"
|
||||
emptyFolder: "ふぉろだーにはなんも残っとらん"
|
||||
unableToDelete: "消そうおもってんけどな、あかんかったわ"
|
||||
inputNewFileName: "今度のファイル名は何にするん?"
|
||||
inputNewFolderName: "今度のフォルダ名は何にするん?"
|
||||
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。"
|
||||
hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん"
|
||||
copyUrl: "URLをコピー"
|
||||
rename: "名前を変えるで"
|
||||
avatar: "アイコン"
|
||||
banner: "バナー"
|
||||
nsfw: "見たらあかんで"
|
||||
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
||||
reload: "リロード"
|
||||
doNothing: "何もせんとく"
|
||||
reloadConfirm: "リロードしてええか?"
|
||||
watch: "ウォッチ"
|
||||
unwatch: "ウォッチやめる"
|
||||
accept: "ええで"
|
||||
reject: "あかん"
|
||||
normal: "ええ感じ"
|
||||
instanceName: "インスタンス名"
|
||||
instanceDescription: "インスタンスの紹介"
|
||||
maintainerName: "管理者の名前"
|
||||
maintainerEmail: "管理者のメールアドレス"
|
||||
tosUrl: "利用規約のURL"
|
||||
thisYear: "今年"
|
||||
thisMonth: "今月"
|
||||
today: "今日"
|
||||
dayX: "{day}日"
|
||||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "ページ"
|
||||
integration: "つないで"
|
||||
connectSerice: "つなげる"
|
||||
disconnectSerice: "切ってまう"
|
||||
enableLocalTimeline: "ローカルタイムラインを使えるようにする"
|
||||
enableGlobalTimeline: "グローバルタイムラインを使えるようにする"
|
||||
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
|
||||
registration: "登録"
|
||||
enableRegistration: "一見さんでも誰でもいらっしゃ~い"
|
||||
invite: "来てや"
|
||||
proxyRemoteFiles: "リモートのファイルをプロキシする"
|
||||
proxyRemoteFilesDescription: "この設定を入れると、保存しとらんかったり、お腹いっぱいになってしもたせいで保存できんかったリモートファイルをローカルでプロキシして、サムネイル作ってもらうことができるで。サーバーの腹具合には影響せんけどな。"
|
||||
driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量"
|
||||
driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量"
|
||||
inMb: "メガバイト単位"
|
||||
recaptcha: "reCAPTCHA"
|
||||
avoidMultiCaptchaConfirm: "ぎょうさんのCaptchaをつこてしまうと、仲良うせんことがあるんや。他のCaptchaをなおしとこか?別にキャンセルしてもろうたらCaptchaは消されへんで済むけど知らんで。"
|
||||
antennas: "アンテナ"
|
||||
manageAntennas: "アンテナいじる"
|
||||
name: "名前"
|
||||
antennaSource: "受信ソース(このソースは食われへん)"
|
||||
antennaKeywords: "受信キーワード"
|
||||
antennaExcludeKeywords: "除外キーワード"
|
||||
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
|
||||
notifyAntenna: "新しいノートを追加すんで"
|
||||
withFileAntenna: "なんか添付されたノートだけ"
|
||||
serviceworker: "ServiceWorker"
|
||||
enableServiceworker: "ServiceWorkerをつこて"
|
||||
antennaUsersDescription: "ユーザー名を改行で区切ったってな"
|
||||
caseSensitive: "大文字と小文字は別もんや"
|
||||
withReplies: "返信も入れたって"
|
||||
connectedTo: "次のアカウントに繋がっとるで"
|
||||
notesAndReplies: "投稿と返信"
|
||||
withFiles: "ファイル付いとる"
|
||||
silence: "サイレンス"
|
||||
silenceConfirm: "サイレンスしよか?"
|
||||
unsilence: "サイレンスやめるで"
|
||||
unsilenceConfirm: "サイレンスやめよか?"
|
||||
popularUsers: "人気のユーザー"
|
||||
recentlyUpdatedUsers: "ちょっと前に投稿したばっかりのユーザー"
|
||||
recentlyRegisteredUsers: "ちょっと前に始めたばっかりのユーザー"
|
||||
recentlyDiscoveredUsers: "最近見っけたユーザー"
|
||||
exploreUsersCount: "{count}もユーザーおるで"
|
||||
exploreFediverse: "Fediverseを探ってみる"
|
||||
popularTags: "人気のタグ"
|
||||
userList: "リスト"
|
||||
about: "情報"
|
||||
aboutMisskey: "Misskeyってなんや?"
|
||||
aboutMisskeyText: "Misskeyはsyuiloいう人が2014年からずっと作ってはる、オープンソースなソフトウェアや。"
|
||||
misskeyMembers: "今んとここんだけのメンバーが作って、メンテナンスしてはる:"
|
||||
misskeySource: "ソースコードはこっから見てな:"
|
||||
misskeyTranslation: "Misskeyの翻訳手伝うてくれへん?:"
|
||||
misskeyDonate: "Misskeyにお金あげたら開発のサポートになるで:"
|
||||
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
|
||||
patrons: "支援者"
|
||||
administrator: "管理者"
|
||||
token: "トークン"
|
||||
twoStepAuthentication: "二段階認証"
|
||||
moderator: "モデレーター"
|
||||
nUsersMentioned: "{n}人が投稿"
|
||||
securityKey: "セキュリティキー"
|
||||
securityKeyName: "キーの名前"
|
||||
registerSecurityKey: "セキュリティキーを登録するで"
|
||||
lastUsed: "最後につこうた日"
|
||||
unregister: "登録やめる"
|
||||
passwordLessLogin: "パスワード無くてもログインできるようにする"
|
||||
resetPassword: "パスワードをリセット"
|
||||
newPasswordIs: "今度のパスワードは「{password}」や"
|
||||
autoReloadWhenDisconnected: "サーバーが調子悪いときには自動でリロードしたる"
|
||||
notFoundDescription: "指定されたURLに該当するページはあらへんやった。"
|
||||
close: "さいなら"
|
||||
joinedGroups: "参加しとるグループ"
|
||||
invites: "来てや"
|
||||
smtpHost: "ホスト"
|
||||
smtpUser: "ユーザー名"
|
||||
smtpPass: "パスワード"
|
||||
_theme:
|
||||
keys:
|
||||
renote: "Renote"
|
||||
_sfx:
|
||||
note: "ノート"
|
||||
notification: "通知"
|
||||
chat: "チャット"
|
||||
_ago:
|
||||
unknown: "謎"
|
||||
future: "未来"
|
||||
@ -142,6 +389,8 @@ _antennaSources:
|
||||
_widgets:
|
||||
notifications: "通知"
|
||||
timeline: "タイムライン"
|
||||
activity: "アクティビティ"
|
||||
federation: "連合"
|
||||
_cw:
|
||||
show: "もっとあるやろ!"
|
||||
_poll:
|
||||
@ -149,14 +398,27 @@ _poll:
|
||||
deadlineTime: "時間"
|
||||
_visibility:
|
||||
publicDescription: "みなのユーザーに公開"
|
||||
home: "ホーム"
|
||||
followers: "フォロワー"
|
||||
_profile:
|
||||
name: "名前"
|
||||
username: "ユーザー名"
|
||||
_exportOrImport:
|
||||
allNotes: "全てのノート"
|
||||
followingList: "フォロー"
|
||||
muteList: "ミュート"
|
||||
blockingList: "ブロック"
|
||||
userLists: "リスト"
|
||||
_timelines:
|
||||
home: "ホーム"
|
||||
_rooms:
|
||||
_roomType:
|
||||
default: "デフォルト"
|
||||
_furnitures:
|
||||
monitor: "モニター"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "画像"
|
||||
script:
|
||||
categories:
|
||||
list: "リスト"
|
||||
@ -175,3 +437,12 @@ _pages:
|
||||
arg1: "リスト"
|
||||
types:
|
||||
array: "リスト"
|
||||
_notification:
|
||||
youWereFollowed: "フォローされたで"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "通知"
|
||||
tl: "タイムライン"
|
||||
antenna: "アンテナ"
|
||||
list: "リスト"
|
||||
mentions: "あんた宛て"
|
||||
|
88
locales/kab-KAB.yml
Normal file
88
locales/kab-KAB.yml
Normal file
@ -0,0 +1,88 @@
|
||||
---
|
||||
_lang_: "Taqbaylit"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Nadi"
|
||||
notifications: "Ilɣuyen"
|
||||
username: "Isem n umseqdac"
|
||||
password: "Awal uffir"
|
||||
ok: "IH"
|
||||
settings: "Iɣewwaṛen"
|
||||
profile: "Amaɣnu"
|
||||
save: "Sekles"
|
||||
delete: "Kkes"
|
||||
addToList: "Rnu ɣer tebdart"
|
||||
reply: "Err"
|
||||
loadMore: "Wali ugar"
|
||||
youGotNewFollower: "Yeṭṭafaṛ-ik·em-id"
|
||||
mention: "Bder"
|
||||
import: "Kter"
|
||||
export: "Sifeḍ"
|
||||
files: "Ifuyla"
|
||||
download: "Sider"
|
||||
lists: "Tibdarin"
|
||||
noLists: "Ulac ɣur-k·m ula d yiwet n tabdart"
|
||||
following: "Ig ṭṭafaṛ"
|
||||
followers: "Imeḍfaṛen"
|
||||
followsYou: "Yeṭṭafaṛ-ik·em-id"
|
||||
createList: "Snulfu-d tabdart"
|
||||
enterListName: "Isem n tebdart"
|
||||
follow: "Ḍfeṛ"
|
||||
you: "Kečči·mmi"
|
||||
selectList: "Fren tabdart"
|
||||
youHaveNoLists: "Ulac ɣur-k·m ula d yiwet n tabdart"
|
||||
remove: "Kkes"
|
||||
userList: "Tibdarin"
|
||||
uiLanguage: "Tutlayt n wegrudem"
|
||||
smtpUser: "Isem n umseqdac"
|
||||
smtpPass: "Awal uffir"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Bder"
|
||||
_sfx:
|
||||
notification: "Ilɣuyen"
|
||||
_widgets:
|
||||
notifications: "Ilɣuyen"
|
||||
_cw:
|
||||
show: "Wali ugar"
|
||||
_visibility:
|
||||
followers: "Imeḍfaṛen"
|
||||
_profile:
|
||||
username: "Isem n umseqdac"
|
||||
_exportOrImport:
|
||||
followingList: "Ig ṭṭafaṛ"
|
||||
muteList: "Sgugem"
|
||||
blockingList: "Seḥbes"
|
||||
userLists: "Tibdarin"
|
||||
_pages:
|
||||
font: "Tasefsit"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageRemove: "Kkes tugna i d-ijebden"
|
||||
selectType: "Fren anaw"
|
||||
contentBlocks: "Agbur"
|
||||
inputBlocks: "Anekcum"
|
||||
specialBlocks: "Uzzig"
|
||||
script:
|
||||
categories:
|
||||
list: "Tibdarin"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Tibdarin"
|
||||
_randomPick:
|
||||
arg1: "Tibdarin"
|
||||
_dailyRandomPick:
|
||||
arg1: "Tibdarin"
|
||||
_seedRandomPick:
|
||||
arg2: "Tibdarin"
|
||||
_pick:
|
||||
arg1: "Tibdarin"
|
||||
_listLen:
|
||||
arg1: "Tibdarin"
|
||||
types:
|
||||
array: "Tibdarin"
|
||||
_notification:
|
||||
youWereFollowed: "Yeṭṭafaṛ-ik·em-id"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "Ilɣuyen"
|
||||
list: "Tibdarin"
|
@ -54,6 +54,8 @@ driveFileDeleteConfirm: "\"{name}\" ಕಡತವನ್ನು ಅಳಿಸಲು
|
||||
unfollowConfirm: "{name}ಅನ್ನು ಹಿಂಬಾಲಿಸದಿರುವುದೇ?"
|
||||
instances: "ನಿದರ್ಶನ"
|
||||
remove: "ಅಳಿಸು"
|
||||
smtpUser: "ಬಳಕೆಹೆಸರು"
|
||||
smtpPass: "ಗುಪ್ತಪದ"
|
||||
_sfx:
|
||||
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
||||
_widgets:
|
||||
@ -63,3 +65,10 @@ _cw:
|
||||
show: "ಇನ್ನಷ್ಟು ನೋಡು"
|
||||
_profile:
|
||||
username: "ಬಳಕೆಹೆಸರು"
|
||||
_notification:
|
||||
youWereFollowed: "ಹಿಂಬಾಲಿಸಿದರು"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "ಅಧಿಸೂಚನೆಗಳು"
|
||||
tl: "ಸಮಯಸಾಲು"
|
||||
mentions: "ಹೆಸರಿಸಿದ"
|
||||
|
@ -45,6 +45,7 @@ loadMore: "더 보기"
|
||||
youGotNewFollower: "새로운 팔로워가 있습니다"
|
||||
receiveFollowRequest: "새로운 팔로우 요청이 있습니다"
|
||||
followRequestAccepted: "팔로우가 수락되었습니다"
|
||||
mention: "멘션"
|
||||
mentions: "받은 멘션"
|
||||
directNotes: "다이렉트 노트"
|
||||
importAndExport: "가져오기와 내보내기"
|
||||
@ -104,6 +105,7 @@ suspendConfirm: "이 계정을 정지하시겠습니까?"
|
||||
unsuspendConfirm: "이 계정의 정지를 해제하시겠습니까?"
|
||||
selectList: "리스트 선택"
|
||||
customEmojis: "커스텀 이모지"
|
||||
emoji: "이모지"
|
||||
emojiName: "이모지 이름"
|
||||
emojiUrl: "이모지 URL"
|
||||
addEmoji: "이모지 추가"
|
||||
@ -440,7 +442,6 @@ remote: "리모트"
|
||||
total: "합계"
|
||||
weekOverWeekChanges: "지난주보다"
|
||||
dayOverDayChanges: "어제보다"
|
||||
accessibility: "접근성"
|
||||
clinetSettings: "클라이언트 설정"
|
||||
accountSettings: "계정 설정"
|
||||
promotion: "프로모션"
|
||||
@ -499,9 +500,36 @@ removeAllFollowingDescription: "{host}(으)로부터 모든 팔로잉을 해제
|
||||
userSuspended: "이 계정은 정지된 상태입니다."
|
||||
userSilenced: "이 계정은 사일런스된 상태입니다."
|
||||
sidebar: "사이드바"
|
||||
divider: "분할선"
|
||||
divider: "구분선"
|
||||
addItem: "항목 추가"
|
||||
rooms: "방"
|
||||
relays: "릴레이"
|
||||
addRelay: "릴레이 추가"
|
||||
inboxUrl: "Inbox 주소"
|
||||
addedRelays: "추가된 릴레이"
|
||||
serviceworkerInfo: "푸시 알림을 수행하려면 활성화해야 합니다."
|
||||
deletedNote: "삭제된 노트"
|
||||
invisibleNote: "비공개 노트"
|
||||
enableInfiniteScroll: "자동으로 좀 더 보기"
|
||||
visibility: "공개 범위"
|
||||
poll: "투표"
|
||||
useCw: "내용 숨기기"
|
||||
fixedWidgetsPosition: "위젯의 위치 고정"
|
||||
enablePlayer: "플레이어 열기"
|
||||
disablePlayer: "플레이어 닫기"
|
||||
expandTweet: "트윗 확장하기"
|
||||
themeEditor: "테마 에디터"
|
||||
description: "설명"
|
||||
author: "작성자"
|
||||
leaveConfirm: "저장하지 않은 변경사항이 있습니다. 취소하시겠습니까?"
|
||||
manage: "관리"
|
||||
plugins: "플러그인"
|
||||
pluginInstallWarn: "신뢰할 수 없는 플러그인은 설치하지 마십시오."
|
||||
deck: "덱"
|
||||
undeck: "덱 해제"
|
||||
smtpHost: "호스트"
|
||||
smtpUser: "유저명"
|
||||
smtpPass: "비밀번호"
|
||||
_theme:
|
||||
explore: "테마 찾아보기"
|
||||
install: "테마 설치"
|
||||
@ -510,6 +538,22 @@ _theme:
|
||||
installed: "{name} 테마가 설치되었습니다"
|
||||
alreadyInstalled: "이미 설치된 테마입니다"
|
||||
invalid: "테마 형식이 올바르지 않습니다"
|
||||
make: "테마 만들기"
|
||||
base: "베이스"
|
||||
addConstant: "상수 추가"
|
||||
constant: "상수"
|
||||
defaultValue: "기본값"
|
||||
color: "색"
|
||||
refProp: "프로퍼티를 참조"
|
||||
refConst: "상수를 참조"
|
||||
key: "키"
|
||||
func: "함수"
|
||||
funcKind: "함수 종류"
|
||||
argument: "매개변수"
|
||||
keys:
|
||||
mention: "멘션"
|
||||
renote: "Renote"
|
||||
divider: "구분선"
|
||||
_sfx:
|
||||
note: "새 노트"
|
||||
noteMy: "내 노트"
|
||||
@ -623,12 +667,13 @@ _widgets:
|
||||
rss: "RSS 리더"
|
||||
activity: "활동"
|
||||
photos: "사진"
|
||||
digitalClock: "디지털 시계"
|
||||
federation: "연합"
|
||||
_cw:
|
||||
hide: "숨기기"
|
||||
show: "더 보기"
|
||||
chars: "{count} 문자"
|
||||
files: "{count} 파일"
|
||||
poll: "투표"
|
||||
_poll:
|
||||
noOnlyOneChoice: "투표 항목이 최소 2개 필요합니다"
|
||||
choiceN: "선택지 {n}"
|
||||
@ -661,6 +706,7 @@ _visibility:
|
||||
specified: "다이렉트"
|
||||
specifiedDescription: "지정한 유저에게만 공개"
|
||||
localOnly: "로컬에만"
|
||||
localOnlyDescription: "리모트 유저에게 보이지 않기"
|
||||
_postForm:
|
||||
replyPlaceholder: "이 노트에 답글..."
|
||||
quotePlaceholder: "이 노트를 인용..."
|
||||
@ -776,6 +822,8 @@ _rooms:
|
||||
cup-noodle: "컵라면"
|
||||
holo-display: "홀로그램"
|
||||
energy-drink: "에너지 드링크"
|
||||
doll-ai: "아이쨩 인형"
|
||||
banknote: "지폐뭉치"
|
||||
_pages:
|
||||
newPage: "페이지 만들기"
|
||||
editPage: "페이지 수정"
|
||||
@ -1057,3 +1105,27 @@ _pages:
|
||||
enviromentVariables: "환경 변수"
|
||||
pageVariables: "페이지 요소"
|
||||
argVariables: "입력 슬롯"
|
||||
_relayStatus:
|
||||
requesting: "대기 중"
|
||||
accepted: "승인됨"
|
||||
rejected: "거절됨"
|
||||
_notification:
|
||||
fileUploaded: "파일이 업로드되었습니다"
|
||||
youGotMention: "{name}님이 멘션함"
|
||||
youGotReply: "{name}님이 답글함"
|
||||
youGotQuote: "{name}님이 인용함"
|
||||
youRenoted: "{name}님이 Renote"
|
||||
youGotPoll: "{name}님이 투표함"
|
||||
youWereFollowed: "새로운 팔로워가 있습니다"
|
||||
youReceivedFollowRequest: "새로운 팔로우 요청이 있습니다"
|
||||
yourFollowRequestAccepted: "팔로우 요청이 수락되었습니다"
|
||||
youWereInvitedToGroup: "그룹에 초대되었습니다"
|
||||
_deck:
|
||||
_columns:
|
||||
widgets: "위젯"
|
||||
notifications: "알림"
|
||||
tl: "타임라인"
|
||||
antenna: "안테나"
|
||||
list: "리스트"
|
||||
mentions: "받은 멘션"
|
||||
direct: "다이렉트"
|
||||
|
@ -1,9 +1,13 @@
|
||||
---
|
||||
_lang_: "Русский язык"
|
||||
introMisskey: "Добро пожаловать! Misskey - это децентрализованный сервис микроблогов с открытым исходным кодом.\nСоздавайте «записи», чтобы поделиться происходящим или рассказать всем о себе 📡\nТакже Вы можете добавить быструю реакцию на все записи с помощью функции «реакция» 👍\nОткройте для себя новый мир 🚀"
|
||||
monthAndDay: "{day}.{month}"
|
||||
search: "Поиск"
|
||||
notifications: "Уведомления"
|
||||
password: "Пароль"
|
||||
fetchingAsApObject: "Запрос на федерацию"
|
||||
ok: "Окей"
|
||||
gotIt: "Отлично"
|
||||
cancel: "Отмена"
|
||||
instance: "Экземпляр"
|
||||
settings: "Настройки"
|
||||
@ -27,6 +31,7 @@ importAndExport: "Импорт / Экспорт"
|
||||
files: "Файл"
|
||||
instances: "Экземпляр"
|
||||
remove: "Удалить"
|
||||
smtpPass: "Пароль"
|
||||
_sfx:
|
||||
notification: "Уведомления"
|
||||
_widgets:
|
||||
@ -34,3 +39,7 @@ _widgets:
|
||||
timeline: "Лента"
|
||||
_cw:
|
||||
show: "Показать еще"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "Уведомления"
|
||||
tl: "Лента"
|
||||
|
3
locales/ug-CN.yml
Normal file
3
locales/ug-CN.yml
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
_lang_: "ياپونچە"
|
||||
search: "ئىزدەش"
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
_lang_: "中文(简体)"
|
||||
introMisskey: "欢迎!Misskey是一个开源的分散型SNS服务。\n通过「帖子」来分享现在发生的事情吧!📡\n「反应」功能,可以让你快速的对大家的「帖子」来表达感情👍\n一起来探索新的世界吧!🚀"
|
||||
introMisskey: "欢迎!Misskey是一个开源的、去中心化的“微博客”服务。\n通过编写「帖文」来和大家分享你的以及你周围的事情吧!📡\n通过「回应」功能,可以让你快速地对大家的帖文表达反馈👍\n来探索新的世界吧!🚀"
|
||||
monthAndDay: "{month}月 {day}日"
|
||||
search: "搜索"
|
||||
notifications: "通知"
|
||||
@ -11,8 +11,8 @@ ok: "OK"
|
||||
gotIt: "我明白了"
|
||||
cancel: "取消"
|
||||
enterUsername: "输入用户名"
|
||||
renotedBy: "由 {user} 转贴"
|
||||
noNotes: "没有投稿"
|
||||
renotedBy: "{user} 转贴了"
|
||||
noNotes: "没有帖文"
|
||||
noNotifications: "无通知"
|
||||
instance: "实例"
|
||||
settings: "设置"
|
||||
@ -35,18 +35,19 @@ unpin: "取消置顶"
|
||||
copyContent: "复制内容"
|
||||
copyLink: "复制链接"
|
||||
delete: "删除"
|
||||
deleteAndEdit: "删除和编辑"
|
||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应,转推和回复也将被删除。"
|
||||
deleteAndEdit: "删除并编辑"
|
||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
||||
addToList: "添加至列表"
|
||||
sendMessage: "发送"
|
||||
copyUsername: "复制用户名"
|
||||
reply: "回复"
|
||||
loadMore: "查看更多"
|
||||
youGotNewFollower: "你有新的关注者"
|
||||
receiveFollowRequest: "收到关注请求"
|
||||
followRequestAccepted: "同意关注请求"
|
||||
receiveFollowRequest: "您收到了关注请求"
|
||||
followRequestAccepted: "您的关注请求被通过了"
|
||||
mention: "提及"
|
||||
mentions: "提及"
|
||||
directNotes: "指定用户可见"
|
||||
directNotes: "私信"
|
||||
importAndExport: "导入和导出"
|
||||
import: "导入"
|
||||
export: "导出"
|
||||
@ -104,6 +105,7 @@ suspendConfirm: "要冻结吗?"
|
||||
unsuspendConfirm: "要解除冻结吗?"
|
||||
selectList: "选择列表"
|
||||
customEmojis: "自定义Emoji"
|
||||
emoji: "表情符号"
|
||||
emojiName: "Emoji 名称"
|
||||
emojiUrl: "emoji 地址"
|
||||
addEmoji: "添加Emoji"
|
||||
@ -235,7 +237,7 @@ light: "浅色"
|
||||
dark: "深色"
|
||||
lightThemes: "亮色主题"
|
||||
darkThemes: "暗色主题"
|
||||
syncDeviceDarkMode: "将深色模式与系统设置同步"
|
||||
syncDeviceDarkMode: "将深色模式与设备设置同步"
|
||||
drive: "网盘"
|
||||
fileName: "文件名称"
|
||||
selectFile: "选择文件"
|
||||
@ -440,7 +442,7 @@ remote: "远程"
|
||||
total: "总计"
|
||||
weekOverWeekChanges: "与前一周相比"
|
||||
dayOverDayChanges: "与前一日相比"
|
||||
accessibility: "辅助功能"
|
||||
appearance: "外观"
|
||||
clinetSettings: "客户端设置"
|
||||
accountSettings: "账户设置"
|
||||
promotion: "推广"
|
||||
@ -502,6 +504,41 @@ sidebar: "侧边栏"
|
||||
divider: "分割线"
|
||||
addItem: "添加项"
|
||||
rooms: "房间"
|
||||
relays: "中继"
|
||||
addRelay: "添加中继"
|
||||
inboxUrl: "Inbox URL"
|
||||
addedRelays: "已添加的中继"
|
||||
serviceworkerInfo: "您需要启用推送通知"
|
||||
deletedNote: "已删除的帖子"
|
||||
invisibleNote: "隐藏的帖子"
|
||||
enableInfiniteScroll: "启用自动滚动页面模式"
|
||||
visibility: "可见性"
|
||||
poll: "调查问卷"
|
||||
useCw: "隐藏内容"
|
||||
fixedWidgetsPosition: "固定小工具的位置"
|
||||
enablePlayer: "打开播放器"
|
||||
disablePlayer: "关闭播放器"
|
||||
expandTweet: "展开推文"
|
||||
themeEditor: "主题编辑器"
|
||||
description: "描述"
|
||||
author: "作者"
|
||||
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
|
||||
manage: "管理"
|
||||
plugins: "插件"
|
||||
pluginInstallWarn: "请不要安装不明来源的插件"
|
||||
deck: "Deck"
|
||||
undeck: "取消Deck"
|
||||
useBlurEffectForModal: "模态框使用模糊效果"
|
||||
generateAccessToken: "生成访问令牌"
|
||||
permission: "权限"
|
||||
enableAll: "启用全部"
|
||||
disableAll: "禁用全部"
|
||||
tokenRequested: "允许访问账户"
|
||||
pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限"
|
||||
smtpHost: "主机名"
|
||||
smtpPort: "端口"
|
||||
smtpUser: "用户名"
|
||||
smtpPass: "密码"
|
||||
_theme:
|
||||
explore: "寻找主题"
|
||||
install: "安装主题"
|
||||
@ -510,6 +547,69 @@ _theme:
|
||||
installed: "{name} 已安装"
|
||||
alreadyInstalled: "此主题已经安装"
|
||||
invalid: "主题格式错误"
|
||||
make: "制作主题"
|
||||
base: "基于"
|
||||
addConstant: "添加常量"
|
||||
constant: "常量"
|
||||
defaultValue: "默认值"
|
||||
color: "颜色"
|
||||
refProp: "查看属性"
|
||||
refConst: "查看常量"
|
||||
key: "主要"
|
||||
func: "函数"
|
||||
funcKind: "功能类型"
|
||||
argument: "参数"
|
||||
basedProp: "基于的属性名称"
|
||||
alpha: "不透明度"
|
||||
darken: "暗色"
|
||||
lighten: "亮色"
|
||||
inputConstantName: "请输入常量名称"
|
||||
importInfo: "您可以在此处粘贴主题代码,将其导入到编辑器中"
|
||||
deleteConstantConfirm: "确定要删除常量{const}吗?"
|
||||
keys:
|
||||
accent: "强调色"
|
||||
bg: "背景"
|
||||
fg: "文本"
|
||||
focus: "聚焦"
|
||||
indicator: "标记"
|
||||
panel: "面板"
|
||||
shadow: "阴影"
|
||||
header: "顶栏"
|
||||
navBg: "侧边栏背景"
|
||||
navFg: "侧栏文本"
|
||||
navHoverFg: "侧栏文本(悬停)"
|
||||
navActive: "侧栏文本(活动)"
|
||||
navIndicator: "侧栏标记"
|
||||
link: "链接"
|
||||
hashtag: "话题标签"
|
||||
mention: "提及"
|
||||
mentionMe: "提及"
|
||||
renote: "转发"
|
||||
modalBg: "模态框背景"
|
||||
divider: "分割线"
|
||||
scrollbarHandle: "滚动条"
|
||||
scrollbarHandleHover: "滚动条(悬停)"
|
||||
dateLabelFg: "日期标签文字"
|
||||
infoBg: "信息背景"
|
||||
infoFg: "信息文本"
|
||||
infoWarnBg: "警告背景"
|
||||
infoWarnFg: "警告文本"
|
||||
cwBg: "CW 按钮背景"
|
||||
cwFg: "CW 按钮文本"
|
||||
cwHoverBg: "CW 按钮背景(悬停)"
|
||||
toastBg: "吐司提示背景"
|
||||
toastFg: "土司提示文本"
|
||||
buttonBg: "按钮背景"
|
||||
buttonHoverBg: "按钮背景(悬停)"
|
||||
inputBorder: "输入框边框"
|
||||
listItemHoverBg: "下拉列表项目背景(悬停)"
|
||||
driveFolderBg: "驱动器文件夹背景"
|
||||
wallpaperOverlay: "壁纸叠加层"
|
||||
badge: "徽章"
|
||||
messageBg: "聊天背景"
|
||||
accentDarken: "强调色(暗)"
|
||||
accentLighten: "强调色(亮)"
|
||||
fgHighlighted: "高亮显示文本"
|
||||
_sfx:
|
||||
note: "帖子"
|
||||
noteMy: "我的帖子"
|
||||
@ -538,7 +638,7 @@ _tutorial:
|
||||
step1_1: "欢迎!"
|
||||
step1_2: "这个页面叫做「时间线」,它会按照时间顺序显示所有你「关注」的人所发的「帖子」。"
|
||||
step1_3: "如果你并没有发布任何帖子,也没有关注其他的人,你的时间线页面应当什么都没有显示。"
|
||||
step2_1: "在你想发布一些帖子之前,让我们先进行一下个人资料设置。"
|
||||
step2_1: "在您想要发帖或关注其他人之前,请先设置一下个人资料吧。"
|
||||
step2_2: "如果别人能够更加的了解你,关注你的概率也会得到提升。"
|
||||
step3_1: "已经设置完个人资料了吗?"
|
||||
step3_2: "那么接下来,试着写一些什么东西来发布吧。你可以通过点击屏幕上的铅笔图标来打开投稿页面。"
|
||||
@ -623,12 +723,13 @@ _widgets:
|
||||
rss: "RSS阅读器"
|
||||
activity: "活动"
|
||||
photos: "照片"
|
||||
digitalClock: "数字时钟"
|
||||
federation: "联邦宇宙"
|
||||
_cw:
|
||||
hide: "隐藏"
|
||||
show: "查看更多"
|
||||
chars: "{count}个字符"
|
||||
files: "{count} 个文件"
|
||||
poll: "投票"
|
||||
_poll:
|
||||
noOnlyOneChoice: "需要至少两个选项"
|
||||
choiceN: "选择{n}"
|
||||
@ -661,6 +762,7 @@ _visibility:
|
||||
specified: "指定用户"
|
||||
specifiedDescription: "仅发送至指定用户"
|
||||
localOnly: "仅限本地"
|
||||
localOnlyDescription: "对远程用户不可见"
|
||||
_postForm:
|
||||
replyPlaceholder: "回复这个帖子..."
|
||||
quotePlaceholder: "引用这个帖子..."
|
||||
@ -776,6 +878,8 @@ _rooms:
|
||||
cup-noodle: "杯面"
|
||||
holo-display: "全息显示器"
|
||||
energy-drink: "能量饮料"
|
||||
doll-ai: "小蓝的玩偶"
|
||||
banknote: "钞票"
|
||||
_pages:
|
||||
newPage: "创建页面"
|
||||
editPage: "编辑页面"
|
||||
@ -1057,3 +1161,32 @@ _pages:
|
||||
enviromentVariables: "环境变量"
|
||||
pageVariables: "页面元素"
|
||||
argVariables: "输入变量"
|
||||
_relayStatus:
|
||||
requesting: "待批准"
|
||||
accepted: "已批准"
|
||||
rejected: "已拒绝"
|
||||
_notification:
|
||||
fileUploaded: "文件已上传"
|
||||
youGotMention: "来自{name}的提及"
|
||||
youGotReply: "来自{name}的回复"
|
||||
youGotQuote: "来自{name}的引用"
|
||||
youRenoted: "来自{name}的转发"
|
||||
youGotPoll: "来自{name}的投票"
|
||||
youGotMessagingMessageFromUser: "来自{name}的聊天"
|
||||
youGotMessagingMessageFromGroup: "来自{name}的群聊"
|
||||
youWereFollowed: "关注了你。"
|
||||
youReceivedFollowRequest: "您有新的关注请求"
|
||||
yourFollowRequestAccepted: "您的关注请求已通过"
|
||||
youWereInvitedToGroup: "您有新的群组邀请"
|
||||
_deck:
|
||||
alwaysShowMainColumn: "总是显示主列"
|
||||
columnAlign: "列对齐"
|
||||
addColumn: "添加列"
|
||||
_columns:
|
||||
widgets: "小部件"
|
||||
notifications: "通知"
|
||||
tl: "时间线"
|
||||
antenna: "天线"
|
||||
list: "列表"
|
||||
mentions: "提及"
|
||||
direct: "指定用户"
|
||||
|
@ -1,18 +1,20 @@
|
||||
---
|
||||
_lang_: "中文(繁体)"
|
||||
_lang_: "中文(繁體)"
|
||||
introMisskey: "歡迎! Misskey是一個開源的去中心化的社群網站。\n通過「貼文」來分享現在發生的事情吧! 📡\n「反應」功能,可以讓你快速的對大家的「帖子」來表達感情👍\n一起來探索新的世界吧! 🚀"
|
||||
monthAndDay: "{month}月 {day}日"
|
||||
search: "搜尋"
|
||||
notifications: "通知"
|
||||
username: "用戶名"
|
||||
username: "使用名稱"
|
||||
password: "密碼"
|
||||
fetchingAsApObject: "從Fediverse尋找中..."
|
||||
ok: "OK"
|
||||
fetchingAsApObject: "從 Fediverse 查詢中..."
|
||||
ok: "確定"
|
||||
gotIt: "知道了"
|
||||
cancel: "取消"
|
||||
enterUsername: "輸入用戶名"
|
||||
enterUsername: "輸入使用者名稱"
|
||||
renotedBy: "由{user}轉發"
|
||||
noNotes: "沒有筆記"
|
||||
noNotes: "貼文不可用。"
|
||||
noNotifications: "沒有通知"
|
||||
instance: "實例"
|
||||
settings: "設定"
|
||||
profile: "個人檔案"
|
||||
timeline: "時間軸"
|
||||
@ -22,40 +24,43 @@ loggingIn: "登入中"
|
||||
logout: "登出"
|
||||
signup: "註冊"
|
||||
uploading: "上傳中"
|
||||
save: "保存"
|
||||
users: "用戶"
|
||||
addUser: "新增用戶"
|
||||
save: "儲存"
|
||||
users: "使用者"
|
||||
addUser: "新增使用者"
|
||||
favorite: "收藏"
|
||||
favorites: "收藏"
|
||||
favorites: "已加星號"
|
||||
unfavorite: "取消收藏"
|
||||
pin: "置頂"
|
||||
unpin: "取消置頂"
|
||||
copyContent: "複製內容"
|
||||
copyLink: "複製連結"
|
||||
delete: "刪除"
|
||||
deleteAndEdit: "刪除並編輯"
|
||||
deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應,轉發和回覆也將會消失。"
|
||||
addToList: "添加至清單"
|
||||
sendMessage: "發送訊息"
|
||||
copyUsername: "複製用戶名"
|
||||
reply: "回覆"
|
||||
loadMore: "載入更多"
|
||||
loadMore: "瀏覽更多"
|
||||
youGotNewFollower: "您有新的追隨者"
|
||||
receiveFollowRequest: "收到追隨請求"
|
||||
followRequestAccepted: "追隨請求已接受"
|
||||
mention: "提及"
|
||||
mentions: "提及"
|
||||
importAndExport: "匯入 / 匯出"
|
||||
import: "匯入"
|
||||
export: "匯出"
|
||||
files: "檔案"
|
||||
download: "下載"
|
||||
driveFileDeleteConfirm: "確定要刪除檔案「{name}」嗎?附加此檔案的筆記也會跟著不見。"
|
||||
driveFileDeleteConfirm: "確定要刪除檔案「{name}」嗎?使用此附件的貼文也會跟著消失。"
|
||||
unfollowConfirm: "確定要取消對{name}的追隨嗎?"
|
||||
exportRequested: "已請求匯出。這可能會花一點時間。結束後檔案將會被放到雲端裡。"
|
||||
importRequested: "已請求匯入。這可能會花一點時間"
|
||||
lists: "清單"
|
||||
noLists: "沒有清單"
|
||||
note: "筆記"
|
||||
note: "貼文"
|
||||
notes: "筆記"
|
||||
following: "關注中"
|
||||
following: "追隨中"
|
||||
followers: "追隨者"
|
||||
followsYou: "追隨你的人"
|
||||
createList: "建立清單"
|
||||
@ -72,22 +77,23 @@ followRequests: "追隨請求"
|
||||
unfollow: "取消追隨"
|
||||
followRequestPending: "追隨許可批准中"
|
||||
enterEmoji: "輸入表情符號"
|
||||
renote: "轉發筆記"
|
||||
unrenote: "取消轉發筆記"
|
||||
renote: "轉發貼文"
|
||||
unrenote: "取消轉發貼文"
|
||||
quote: "引用"
|
||||
pinnedNote: "已置頂筆記"
|
||||
pinnedNote: "已置頂的貼文"
|
||||
you: "您"
|
||||
clickToShow: "點擊查看"
|
||||
clickToShow: "按一下以顯示"
|
||||
sensitive: "敏感內容"
|
||||
add: "新增"
|
||||
reaction: "反應"
|
||||
reactionSettingDescription: "置頂「反應」表情符號\n"
|
||||
rememberNoteVisibility: "記住筆記隱私設定"
|
||||
attachCancel: "移除附件"
|
||||
markAsSensitive: "標記為敏感內容"
|
||||
unmarkAsSensitive: "取消標記為敏感內容"
|
||||
enterFileName: "請輸入檔案名稱"
|
||||
mute: "禁言"
|
||||
unmute: "解除禁言"
|
||||
mute: "消音"
|
||||
unmute: "解除消音"
|
||||
block: "封鎖"
|
||||
unblock: "解除封鎖"
|
||||
suspend: "凍結"
|
||||
@ -98,69 +104,91 @@ suspendConfirm: "確定凍結此帳號?"
|
||||
unsuspendConfirm: "確定解凍此帳號?"
|
||||
selectList: "選擇清單"
|
||||
customEmojis: "自訂表情符號"
|
||||
emoji: "表情符號"
|
||||
emojiName: "表情符號名稱"
|
||||
emojiUrl: "表情符號URL"
|
||||
addEmoji: "新增表情符號"
|
||||
settingGuide: "推薦設定"
|
||||
flagAsBot: "此帳戶是Bot"
|
||||
flagAsCat: "此帳戶是Cat"
|
||||
autoAcceptFollowed: "自動許可關注"
|
||||
addAcount: "新增帳戶"
|
||||
autoAcceptFollowed: "自動許可追隨"
|
||||
addAcount: "新增帳號"
|
||||
loginFailed: "登入失敗"
|
||||
general: "一般"
|
||||
wallpaper: "壁紙"
|
||||
removeWallpaper: "移除壁紙"
|
||||
wallpaper: "桌布"
|
||||
setWallpaper: "設定桌布"
|
||||
removeWallpaper: "移除桌布"
|
||||
searchWith: "搜尋: {q}"
|
||||
youHaveNoLists: "你沒有任何清單"
|
||||
youHaveNoLists: "沒有任何清單"
|
||||
followConfirm: "你真的要關注{name}嗎?"
|
||||
proxyAccount: "代理帳號"
|
||||
host: "主機"
|
||||
selectUser: "選擇用戶"
|
||||
recipient: "收件人"
|
||||
selectUser: "選取使用者"
|
||||
recipient: "發送至"
|
||||
annotation: "註解"
|
||||
federation: "整合"
|
||||
federation: "聯邦宇宙"
|
||||
instances: "實例"
|
||||
latestStatus: "最後狀態"
|
||||
storageUsage: "已使用容量"
|
||||
charts: "圖表"
|
||||
perHour: "每小時"
|
||||
perDay: "每日"
|
||||
blockThisInstance: "封鎖此實例"
|
||||
operations: "操作"
|
||||
software: "軟體"
|
||||
version: "版本"
|
||||
metadata: "元資料(Metadata)"
|
||||
withNFiles: "{n}個檔案"
|
||||
monitor: "監視器"
|
||||
jobQueue: "佇列"
|
||||
cpuAndMemory: "CPU及記憶體用量"
|
||||
network: "網路"
|
||||
disk: "硬碟"
|
||||
instanceInfo: "實例資訊"
|
||||
statistics: "統計"
|
||||
clearQueue: "清除佇列"
|
||||
clearQueueConfirmTitle: "確定要清除佇列嗎?"
|
||||
clearCachedFiles: "清除快取資料"
|
||||
clearCachedFilesConfirm: "確定要清除緩存資料嗎?"
|
||||
blockedInstances: "已封鎖的實例"
|
||||
blockedInstancesDescription: "請逐行輸入需要封鎖的實例。已封鎖的實例將無法與本實例進行通訊。"
|
||||
muteAndBlock: "禁言 / 封鎖"
|
||||
mutedUsers: "已禁言用戶"
|
||||
blockedUsers: "已封鎖用戶"
|
||||
noUsers: "無用戶"
|
||||
editProfile: "編輯個人檔案"
|
||||
noteDeleteConfirm: "確定刪除此筆記嗎?"
|
||||
pinLimitExceeded: "不能再置頂更多筆記了"
|
||||
intro: "Misskey安裝作業完成!請創立管理員用戶"
|
||||
noteDeleteConfirm: "確定刪除此貼文嗎?"
|
||||
pinLimitExceeded: "不能再置頂更多的貼文了"
|
||||
intro: "Misskey 部署完成!請開設管理員帳號!"
|
||||
done: "完成"
|
||||
processing: "處理中"
|
||||
preview: "預覽"
|
||||
default: "預設"
|
||||
noCustomEmojis: "沒有表情符號"
|
||||
federating: "整合檢索中"
|
||||
customEmojisOfRemote: "來自其他實例的表情符號"
|
||||
noJobs: "沒有任務"
|
||||
federating: "整合搜索中"
|
||||
blocked: "已封鎖"
|
||||
suspended: "已凍結"
|
||||
all: "全部"
|
||||
subscribing: "訂閱中"
|
||||
publishing: "現正直播"
|
||||
notResponding: "沒有回應"
|
||||
instanceFollowing: "追蹤實例"
|
||||
instanceFollowers: "追蹤實例"
|
||||
instanceUsers: "用戶"
|
||||
changePassword: "修改密碼"
|
||||
security: "安全性"
|
||||
retypedNotMatch: "不相符的輸入內容"
|
||||
currentPassword: "現在的密碼"
|
||||
newPassword: "新的密碼"
|
||||
newPasswordRetype: "新的密碼(再輸入一次)"
|
||||
newPasswordRetype: "新的密碼(再輸入一次)"
|
||||
attachFile: "添加附件"
|
||||
more: "更多!"
|
||||
featured: "精選"
|
||||
usernameOrUserId: "用戶名或用戶ID"
|
||||
noSuchUser: "用戶不存在"
|
||||
usernameOrUserId: "使用者名稱或使用者 ID"
|
||||
noSuchUser: "使用者不存在"
|
||||
lookup: "查詢"
|
||||
announcements: "公告"
|
||||
imageUrl: "圖片URL"
|
||||
remove: "刪除"
|
||||
@ -171,6 +199,8 @@ messaging: "傳送訊息"
|
||||
upload: "上傳"
|
||||
fromDrive: "從雲端"
|
||||
fromUrl: "從URL"
|
||||
uploadFromUrl: "從網址上傳"
|
||||
uploadFromUrlMayTakeTime: "還需要一些時間才能完成上傳。"
|
||||
explore: "探索"
|
||||
games: "Misskey 遊戲"
|
||||
messageRead: "已讀"
|
||||
@ -181,23 +211,33 @@ tos: "使用條款"
|
||||
start: "開始"
|
||||
home: "首頁"
|
||||
activity: "動態"
|
||||
images: "圖片"
|
||||
birthday: "生日"
|
||||
yearsOld: "{age}歲"
|
||||
registeredDate: "註冊日期"
|
||||
location: "位置"
|
||||
theme: "外觀主題"
|
||||
light: "淺色"
|
||||
dark: "灰暗"
|
||||
lightThemes: "明亮主題"
|
||||
darkThemes: "灰暗主題"
|
||||
drive: "雲端硬碟"
|
||||
fileName: "檔案名稱"
|
||||
selectFile: "選擇檔案"
|
||||
selectFiles: "選擇檔案"
|
||||
selectFolder: "選擇資料夾"
|
||||
selectFolders: "選擇資料夾"
|
||||
renameFile: "重新命名檔案"
|
||||
folderName: "資料夾名稱"
|
||||
createFolder: "新增資料夾"
|
||||
renameFolder: "重新命名資料夾"
|
||||
deleteFolder: "刪除資料夾"
|
||||
addFile: "添加檔案"
|
||||
emptyDrive: "雲端硬碟為空"
|
||||
emptyFolder: "空的資料夾"
|
||||
unableToDelete: "無法刪除"
|
||||
inputNewFileName: "輸入檔案名稱"
|
||||
inputNewFolderName: "輸入新資料夾的名稱"
|
||||
copyUrl: "複製URL"
|
||||
rename: "重新命名"
|
||||
avatar: "頭像"
|
||||
@ -208,9 +248,12 @@ reload: "重新載入"
|
||||
doNothing: "無視"
|
||||
reloadConfirm: "確定要重新嘗試嗎?"
|
||||
watch: "關注"
|
||||
unwatch: "取消關注"
|
||||
unwatch: "取消追隨"
|
||||
accept: "接受"
|
||||
reject: "拒絕"
|
||||
normal: "正常"
|
||||
instanceName: "實例名稱"
|
||||
instanceDescription: "實例描述"
|
||||
maintainerName: "管理員名稱"
|
||||
maintainerEmail: "管理員信箱"
|
||||
tosUrl: "服務條款URL"
|
||||
@ -221,6 +264,7 @@ dayX: "{day}天"
|
||||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "頁面"
|
||||
integration: "整合"
|
||||
connectSerice: "連線"
|
||||
disconnectSerice: "中斷連線"
|
||||
enableLocalTimeline: "開啟本地時間軸"
|
||||
@ -230,11 +274,14 @@ enableRegistration: "開啟新用戶註冊"
|
||||
invite: "邀請"
|
||||
proxyRemoteFiles: "代理遠程檔案"
|
||||
driveCapacityPerLocalAccount: "每個本地用戶的雲端容量"
|
||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
|
||||
inMb: "以Mbps為單位"
|
||||
iconUrl: "圖像URL"
|
||||
bannerUrl: "橫幅圖片URL"
|
||||
basicInfo: "基本資訊"
|
||||
pinnedUsers: "置頂用戶"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "啟用 hCaptcha"
|
||||
hcaptchaSiteKey: "網站金鑰"
|
||||
hcaptchaSecretKey: "金鑰"
|
||||
recaptcha: "reCAPTCHA"
|
||||
@ -242,6 +289,9 @@ enableRecaptcha: "啟用 reCAPTCHA"
|
||||
recaptchaSiteKey: "網站金鑰"
|
||||
recaptchaSecretKey: "金鑰"
|
||||
name: "名稱"
|
||||
antennaKeywords: "包含的關鍵字"
|
||||
antennaExcludeKeywords: "排除關鍵字"
|
||||
notifyAntenna: "通知我有新的貼文"
|
||||
serviceworker: "ServiceWorker"
|
||||
enableServiceworker: "開啟 ServiceWorker"
|
||||
caseSensitive: "區分大小寫"
|
||||
@ -249,26 +299,46 @@ notesAndReplies: "貼文與回覆"
|
||||
withFiles: "附件"
|
||||
silence: "禁言"
|
||||
silenceConfirm: "確定要禁言此用戶嗎?"
|
||||
unsilence: "解除禁言"
|
||||
unsilenceConfirm: "確定要解除禁言嗎?"
|
||||
popularUsers: "熱門用戶"
|
||||
recentlyUpdatedUsers: "最近發文的用戶"
|
||||
recentlyRegisteredUsers: "新加入用戶"
|
||||
recentlyDiscoveredUsers: "最近發現的用戶"
|
||||
exploreUsersCount: "有{count}個用戶"
|
||||
exploreFediverse: "探索聯邦世界"
|
||||
popularTags: "熱門標籤"
|
||||
userList: "清單"
|
||||
about: "資訊"
|
||||
aboutMisskey: "關於 Misskey"
|
||||
misskeyTranslation: "幫助我們為Misskey的翻譯工作出一分力:"
|
||||
misskeyDonate: "向Misskey捐款以支援我們開發工作:"
|
||||
morePatrons: "感激你們的支持、 幫助。 🥰"
|
||||
patrons: "贊助者"
|
||||
administrator: "管理員"
|
||||
token: "令牌"
|
||||
twoStepAuthentication: "雙重身份驗證"
|
||||
moderator: "板主"
|
||||
nUsersMentioned: "提到了{n}"
|
||||
securityKey: "安全金鑰"
|
||||
securityKeyName: "金鑰名稱"
|
||||
registerSecurityKey: "註冊安全金鑰"
|
||||
lastUsed: "最後活躍時間"
|
||||
unregister: "刪除賬戶"
|
||||
passwordLessLogin: "設置無密碼登入"
|
||||
resetPassword: "重置密碼"
|
||||
newPasswordIs: "新密碼為「{password}」"
|
||||
autoReloadWhenDisconnected: "和伺服器斷線時自動重新載入"
|
||||
autoNoteWatch: "自動關注筆記"
|
||||
autoNoteWatchDescription: "收到反應或回覆過的筆記的通知"
|
||||
autoNoteWatch: "自動追隨貼文"
|
||||
autoNoteWatchDescription: "收到反應或回覆過的貼文的通知"
|
||||
reduceUiAnimation: "減少介面的動態視覺"
|
||||
share: "分享"
|
||||
notFound: "找不到"
|
||||
notFoundDescription: "找不到與指定URL回應的頁面"
|
||||
uploadFolder: "預設上傳資料夾"
|
||||
cacheClear: "清除暫存"
|
||||
cacheClear: "清除快取"
|
||||
markAsReadAllNotifications: "標記所有通知為已讀"
|
||||
markAsReadAllUnreadNotes: "標記所有筆記為已讀"
|
||||
markAsReadAllUnreadNotes: "標記所有貼文為已讀"
|
||||
markAsReadAllTalkMessages: "標記所有訊息為已讀"
|
||||
help: "幫助"
|
||||
inputMessageHere: "在此輸入訊息"
|
||||
@ -288,9 +358,9 @@ text: "文字"
|
||||
enable: "啟用"
|
||||
next: "下一步"
|
||||
retype: "重新輸入"
|
||||
noteOf: "{user}的筆記"
|
||||
noteOf: "{user}的貼文"
|
||||
inviteToGroup: "邀請至群組"
|
||||
maxNoteTextLength: "筆記的字數限制"
|
||||
maxNoteTextLength: "貼文的字數限制"
|
||||
quoteAttached: "引用"
|
||||
quoteQuestion: "是否要引用?"
|
||||
noMessagesYet: "沒有訊息"
|
||||
@ -303,12 +373,50 @@ available: "可用的"
|
||||
unavailable: "不可用的"
|
||||
usernameInvalidFormat: "可使用大小寫英文字母、數字和底線"
|
||||
tooShort: "過短"
|
||||
tooLong: "過長"
|
||||
weakPassword: "密碼強度過弱"
|
||||
normalPassword: "密碼強度普通"
|
||||
strongPassword: "密碼強度堅強"
|
||||
passwordMatched: "密碼一致"
|
||||
passwordNotMatched: "密碼不一致"
|
||||
signinFailed: "登入失敗。 請檢查用戶名和密碼。"
|
||||
uiLanguage: "介面語言"
|
||||
youHaveNoGroups: "找不到群組"
|
||||
tags: "標籤"
|
||||
fontSize: "字體大小"
|
||||
total: "合計"
|
||||
clinetSettings: "用戶端設定"
|
||||
serverLogs: "伺服器日誌"
|
||||
deleteAll: "刪除所有記錄"
|
||||
none: "無"
|
||||
volume: "音量"
|
||||
details: "詳細資訊"
|
||||
chooseEmoji: "選擇您的表情符號\n"
|
||||
unableToProcess: "操作無法完成"
|
||||
recentUsed: "最近使用"
|
||||
install: "安裝"
|
||||
uninstall: "解除安裝"
|
||||
lastUsedDate: "最後上線日期"
|
||||
state: "狀態"
|
||||
ascendingOrder: "昇冪"
|
||||
descendingOrder: "降冪"
|
||||
scratchpad: "暫存記憶體"
|
||||
output: "輸出"
|
||||
deleteAllFiles: "刪除所有檔案"
|
||||
deleteAllFilesConfirm: "要删除所有檔案吗?"
|
||||
userSilenced: "該用戶已被禁言。"
|
||||
deletedNote: "已删除的貼文"
|
||||
smtpHost: "主機"
|
||||
smtpUser: "使用名稱"
|
||||
smtpPass: "密碼"
|
||||
_theme:
|
||||
func: "函数"
|
||||
keys:
|
||||
mention: "提及"
|
||||
renote: "轉發貼文"
|
||||
_sfx:
|
||||
note: "筆記"
|
||||
noteMy: "我的筆記"
|
||||
note: "貼文"
|
||||
noteMy: "我的貼文"
|
||||
notification: "通知"
|
||||
chat: "傳送訊息"
|
||||
_ago:
|
||||
@ -330,7 +438,7 @@ _time:
|
||||
_tutorial:
|
||||
title: "Misskey使用方法"
|
||||
step1_1: "歡迎!"
|
||||
step1_2: "此為「時間軸」頁面,它會按照時間順序顯示你「追隨」的人的「筆記」"
|
||||
step1_2: "此為「時間軸」頁面,它會按照時間順序顯示你「追隨」的人的「貼文」"
|
||||
step1_3: "由於你沒有發布任何筆記,也沒有追隨任何人,所以你的時間軸目前是空的。"
|
||||
step2_1: "在發文或追隨其他人之前先讓我們設定一下個人資料吧。"
|
||||
step2_2: "提供一些關於自己的資訊來讓其他人更有追隨你的意願。"
|
||||
@ -339,7 +447,7 @@ _tutorial:
|
||||
step3_3: "輸入完內容後,按視窗右上角的按鈕來發文"
|
||||
step3_4: "不知道該寫什麼內容嗎?試試看「開始使用Misskey了」如何。"
|
||||
step4_1: "筆記發出去了嗎?"
|
||||
step4_2: "如果你的筆記有顯示在時間軸上,就代表已經發文成功。"
|
||||
step4_2: "如果你的貼文有顯示在時間軸上,就代表已經發文成功。"
|
||||
step5_1: "現在試試看追隨其他人來讓你的時間軸變得更生動吧。"
|
||||
step5_3: "想要追隨其他人,只要點擊他們的頭像並按「追隨」即可。"
|
||||
step5_4: "如果使用者的名字旁有鎖頭的圖示,代表他們需要手動核准你的追隨請求。"
|
||||
@ -348,46 +456,226 @@ _tutorial:
|
||||
step6_3: "在他人的貼文按下「+」的圖示即可選擇想要的表情符號來進行「反應」。"
|
||||
step7_1: "以上為Misskey的基本操作說明,教學在此告一段落。辛苦了。"
|
||||
step7_2: "歡迎到{help}來瞭解更多Misskey相關介紹。"
|
||||
_permissions:
|
||||
"read:blocks": "已封鎖用戶名單"
|
||||
"write:blocks": "編輯已封鎖用戶名單"
|
||||
"read:drive": "存取雲端硬碟\n"
|
||||
"write:drive": "編輯雲端硬碟的檔案"
|
||||
"read:favorites": "瀏覽已收藏"
|
||||
"write:favorites": "編輯收藏清單"
|
||||
"write:following": "追隨/解除追隨"
|
||||
"write:notes": "撰寫或刪除貼文"
|
||||
"read:notifications": "查看通知"
|
||||
"read:reactions": "查看反應"
|
||||
"write:reactions": "編輯反應"
|
||||
"write:votes": "投票"
|
||||
_weekday:
|
||||
sunday: "週日"
|
||||
monday: "週一"
|
||||
tuesday: "週二"
|
||||
wednesday: "週三"
|
||||
thursday: "週四"
|
||||
friday: "週五"
|
||||
saturday: "週六"
|
||||
_widgets:
|
||||
notifications: "通知"
|
||||
timeline: "時間軸"
|
||||
clock: "時鐘"
|
||||
rss: "RSS閱讀器"
|
||||
activity: "動態"
|
||||
photos: "照片"
|
||||
federation: "聯邦宇宙"
|
||||
_cw:
|
||||
show: "載入更多"
|
||||
show: "瀏覽更多"
|
||||
files: "{count} 個檔案"
|
||||
_poll:
|
||||
deadlineTime: "小時"
|
||||
vote: "投票"
|
||||
voted: "已投票"
|
||||
_visibility:
|
||||
home: "首頁"
|
||||
followers: "追隨者"
|
||||
_profile:
|
||||
name: "名稱"
|
||||
username: "用戶名"
|
||||
username: "使用名稱"
|
||||
_exportOrImport:
|
||||
followingList: "關注中"
|
||||
muteList: "禁言"
|
||||
followingList: "追隨中"
|
||||
muteList: "消音"
|
||||
blockingList: "封鎖"
|
||||
userLists: "清單"
|
||||
_instanceCharts:
|
||||
cacheSize: "增加或減少快取用量"
|
||||
cacheSizeTotal: "快取大小總計"
|
||||
_timelines:
|
||||
home: "首頁"
|
||||
_rooms:
|
||||
_roomType:
|
||||
default: "預設"
|
||||
_furnitures:
|
||||
monitor: "監視器"
|
||||
keyboard: "鍵盤"
|
||||
_pages:
|
||||
deleted: "頁面已被刪除"
|
||||
like: "喜歡"
|
||||
unlike: "收回喜歡"
|
||||
blocks:
|
||||
image: "圖片"
|
||||
_textareaInput:
|
||||
name: "變數名稱"
|
||||
numberInput: "輸入數值"
|
||||
_numberInput:
|
||||
name: "變數名稱"
|
||||
_canvas:
|
||||
width: "寬度"
|
||||
_counter:
|
||||
text: "標題"
|
||||
_button:
|
||||
text: "標題"
|
||||
script:
|
||||
categories:
|
||||
value: "數值 "
|
||||
fn: "函数"
|
||||
text: "文本操作"
|
||||
convert: "轉換"
|
||||
list: "清單"
|
||||
blocks:
|
||||
text: "文本"
|
||||
multiLineText: "文本 (多行)"
|
||||
textList: "文本列表"
|
||||
_strPick:
|
||||
arg1: "文本"
|
||||
arg2: "字元位置"
|
||||
_strReplace:
|
||||
arg1: "文本"
|
||||
_strReverse:
|
||||
arg1: "本文"
|
||||
_join:
|
||||
arg1: "清單"
|
||||
add: "加"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_round:
|
||||
arg1: "數值"
|
||||
eq: "A和B相等"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A和B不等"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A和B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A或B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A小於B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A大於B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A小於或等於B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A大於或等於B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "分支"
|
||||
_if:
|
||||
arg1: "如果"
|
||||
arg2: "如果"
|
||||
not: "否"
|
||||
_not:
|
||||
arg1: "否"
|
||||
_random:
|
||||
arg1: "機率"
|
||||
rannum: "亂數"
|
||||
_rannum:
|
||||
arg1: "下限"
|
||||
arg2: "上限"
|
||||
_randomPick:
|
||||
arg1: "清單"
|
||||
_dailyRandom:
|
||||
arg1: "機率"
|
||||
_dailyRannum:
|
||||
arg1: "下限"
|
||||
arg2: "上限"
|
||||
_dailyRandomPick:
|
||||
arg1: "清單"
|
||||
seedRandom: "隨機抽選種子碼"
|
||||
_seedRandom:
|
||||
arg1: "種子"
|
||||
arg2: "機率"
|
||||
seedRannum: "亂數 (種子)"
|
||||
_seedRannum:
|
||||
arg1: "種子"
|
||||
arg2: "最小值"
|
||||
arg3: "最大值"
|
||||
seedRandomPick: "從列表中隨機選擇 (種子)"
|
||||
_seedRandomPick:
|
||||
arg1: "種子"
|
||||
arg2: "清單"
|
||||
_DRPWPM:
|
||||
arg1: "文本列表"
|
||||
pick: "從清單中選取"
|
||||
_pick:
|
||||
arg1: "清單"
|
||||
arg2: "位置"
|
||||
listLen: "取得清單長度"
|
||||
_listLen:
|
||||
arg1: "清單"
|
||||
number: "數值"
|
||||
_stringToNumber:
|
||||
arg1: "文字"
|
||||
_numberToString:
|
||||
arg1: "數值"
|
||||
ref: "變數"
|
||||
aiScriptVar: "AiScript的變數"
|
||||
fn: "函数"
|
||||
_fn:
|
||||
slots: "欄位"
|
||||
arg1: "輸出"
|
||||
_for:
|
||||
arg1: "重複次數"
|
||||
arg2: "處理"
|
||||
types:
|
||||
string: "文字"
|
||||
number: "数值"
|
||||
array: "清單"
|
||||
stringArray: "文本列表"
|
||||
enviromentVariables: "環境變數"
|
||||
_relayStatus:
|
||||
requesting: "等待核准"
|
||||
accepted: "已通過核准"
|
||||
rejected: "已拒絕"
|
||||
_notification:
|
||||
youGotPoll: "{name}已投票"
|
||||
youWereFollowed: "您有新的追隨者"
|
||||
yourFollowRequestAccepted: "您的追隨請求已通過"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "通知"
|
||||
tl: "時間軸"
|
||||
list: "清單"
|
||||
mentions: "提及"
|
||||
|
14
migration/1595075960584-blurhash.ts
Normal file
14
migration/1595075960584-blurhash.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class blurhash1595075960584 implements MigrationInterface {
|
||||
name = 'blurhash1595075960584'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" ADD "blurhash" character varying(128)`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "blurhash"`);
|
||||
}
|
||||
|
||||
}
|
20
migration/1595077605646-blurhash-for-avatar-banner.ts
Normal file
20
migration/1595077605646-blurhash-for-avatar-banner.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class blurhashForAvatarBanner1595077605646 implements MigrationInterface {
|
||||
name = 'blurhashForAvatarBanner1595077605646'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarColor"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerColor"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "avatarBlurhash" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "bannerBlurhash" character varying(128)`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerBlurhash"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarBlurhash"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "bannerColor" character varying(32)`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "avatarColor" character varying(32)`);
|
||||
}
|
||||
|
||||
}
|
14
migration/1595676934834-instance-icon-url.ts
Normal file
14
migration/1595676934834-instance-icon-url.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class instanceIconUrl1595676934834 implements MigrationInterface {
|
||||
name = 'instanceIconUrl1595676934834'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "iconUrl" character varying(256) DEFAULT null`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "iconUrl"`);
|
||||
}
|
||||
|
||||
}
|
153
package.json
153
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.37.0",
|
||||
"version": "12.43.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -31,36 +31,36 @@
|
||||
"chokidar": "^3.3.1",
|
||||
"constantinople": "^4.0.1",
|
||||
"core-js": "^3.6.5",
|
||||
"lodash": "^4.17.15",
|
||||
"mocha": "^7.1.1"
|
||||
"gulp/gulp-cli/yargs/yargs-parser": "5.0.0-security.0",
|
||||
"lodash": "^4.17.19",
|
||||
"mocha/serialize-javascript": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-transform-runtime": "7.9.6",
|
||||
"@elastic/elasticsearch": "7.6.1",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.28",
|
||||
"@fortawesome/free-brands-svg-icons": "5.13.0",
|
||||
"@fortawesome/free-regular-svg-icons": "5.13.0",
|
||||
"@fortawesome/free-solid-svg-icons": "5.13.0",
|
||||
"@fortawesome/vue-fontawesome": "0.1.9",
|
||||
"@juggle/resize-observer": "3.1.3",
|
||||
"@koa/cors": "3.0.0",
|
||||
"@koa/multer": "2.0.2",
|
||||
"@koa/router": "8.0.8",
|
||||
"@babel/plugin-transform-runtime": "7.10.3",
|
||||
"@elastic/elasticsearch": "7.8.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.29",
|
||||
"@fortawesome/free-brands-svg-icons": "5.13.1",
|
||||
"@fortawesome/free-regular-svg-icons": "5.13.1",
|
||||
"@fortawesome/free-solid-svg-icons": "5.13.1",
|
||||
"@fortawesome/vue-fontawesome": "0.1.10",
|
||||
"@koa/cors": "3.1.0",
|
||||
"@koa/multer": "3.0.0",
|
||||
"@koa/router": "9.0.1",
|
||||
"@sinonjs/fake-timers": "6.0.1",
|
||||
"@syuilo/aiscript": "0.6.1",
|
||||
"@syuilo/aiscript": "0.8.0",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.12.2",
|
||||
"@types/bull": "3.14.0",
|
||||
"@types/cbor": "5.0.0",
|
||||
"@types/dateformat": "3.0.1",
|
||||
"@types/double-ended-queue": "2.1.1",
|
||||
"@types/escape-regexp": "0.0.0",
|
||||
"@types/glob": "7.1.1",
|
||||
"@types/glob": "7.1.3",
|
||||
"@types/gulp": "4.0.6",
|
||||
"@types/gulp-rename": "0.0.33",
|
||||
"@types/gulp-replace": "0.0.31",
|
||||
"@types/is-url": "1.2.28",
|
||||
"@types/js-yaml": "3.12.3",
|
||||
"@types/jsdom": "16.2.1",
|
||||
"@types/js-yaml": "3.12.5",
|
||||
"@types/jsdom": "16.2.3",
|
||||
"@types/jsonld": "1.5.1",
|
||||
"@types/katex": "0.11.0",
|
||||
"@types/koa": "2.11.3",
|
||||
@ -76,19 +76,19 @@
|
||||
"@types/koa__router": "8.0.2",
|
||||
"@types/markdown-it": "10.0.1",
|
||||
"@types/mocha": "7.0.2",
|
||||
"@types/node": "13.13.5",
|
||||
"@types/node": "14.0.22",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@types/nodemailer": "6.4.0",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/parse5": "5.0.2",
|
||||
"@types/parsimmon": "1.10.1",
|
||||
"@types/parse5": "5.0.3",
|
||||
"@types/parsimmon": "1.10.2",
|
||||
"@types/portscanner": "2.1.0",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/qrcode": "1.3.4",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "2.1.28",
|
||||
"@types/redis": "2.8.20",
|
||||
"@types/redis": "2.8.25",
|
||||
"@types/rename": "1.0.1",
|
||||
"@types/request-stats": "3.0.0",
|
||||
"@types/rimraf": "3.0.0",
|
||||
@ -98,42 +98,44 @@
|
||||
"@types/speakeasy": "2.0.5",
|
||||
"@types/tinycolor2": "1.4.2",
|
||||
"@types/tmp": "0.2.0",
|
||||
"@types/uuid": "7.0.3",
|
||||
"@types/uuid": "8.0.0",
|
||||
"@types/web-push": "3.3.0",
|
||||
"@types/webpack": "4.41.12",
|
||||
"@types/webpack-stream": "3.2.10",
|
||||
"@types/websocket": "1.0.0",
|
||||
"@types/ws": "7.2.4",
|
||||
"@typescript-eslint/parser": "2.31.0",
|
||||
"@types/webpack": "4.41.18",
|
||||
"@types/webpack-stream": "3.2.11",
|
||||
"@types/websocket": "1.0.1",
|
||||
"@types/ws": "7.2.6",
|
||||
"@typescript-eslint/parser": "3.6.0",
|
||||
"abort-controller": "3.0.0",
|
||||
"apexcharts": "3.19.0",
|
||||
"apexcharts": "3.19.3",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.673.0",
|
||||
"aws-sdk": "2.713.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bull": "3.14.0",
|
||||
"blurhash": "1.1.3",
|
||||
"bull": "3.15.0",
|
||||
"cafy": "15.2.1",
|
||||
"cbor": "5.0.2",
|
||||
"chalk": "4.0.0",
|
||||
"chalk": "4.1.0",
|
||||
"chart.js": "2.9.3",
|
||||
"cli-highlight": "2.1.4",
|
||||
"commander": "4.1.1",
|
||||
"content-disposition": "0.5.3",
|
||||
"core-js": "3.6.5",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "3.5.3",
|
||||
"css-loader": "3.6.0",
|
||||
"cssnano": "4.1.10",
|
||||
"dateformat": "3.0.3",
|
||||
"deep-entries": "3.1.0",
|
||||
"diskusage": "1.1.3",
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eslint": "6.8.0",
|
||||
"eslint": "7.4.0",
|
||||
"eslint-plugin-vue": "6.2.2",
|
||||
"eventemitter3": "4.0.0",
|
||||
"feed": "4.1.0",
|
||||
"eventemitter3": "4.0.4",
|
||||
"feed": "4.2.1",
|
||||
"fibers": "5.0.0",
|
||||
"file-type": "14.3.0",
|
||||
"file-type": "14.6.2",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"glob": "7.1.6",
|
||||
"gulp": "4.0.2",
|
||||
@ -146,47 +148,48 @@
|
||||
"gulp-tslint": "8.1.4",
|
||||
"gulp-typescript": "6.0.0-alpha.1",
|
||||
"hard-source-webpack-plugin": "0.13.1",
|
||||
"hcaptcha": "0.0.1",
|
||||
"hcaptcha": "0.0.2",
|
||||
"html-minifier": "4.0.0",
|
||||
"http-proxy-agent": "4.0.1",
|
||||
"http-signature": "1.3.4",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"idb-keyval": "3.2.0",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"is-root": "2.1.0",
|
||||
"is-svg": "4.2.1",
|
||||
"js-yaml": "3.13.1",
|
||||
"jsdom": "16.2.2",
|
||||
"js-yaml": "3.14.0",
|
||||
"jsdom": "16.3.0",
|
||||
"json5": "2.1.3",
|
||||
"json5-loader": "4.0.0",
|
||||
"jsonld": "3.1.0",
|
||||
"jsrsasign": "8.0.15",
|
||||
"jsonld": "3.1.1",
|
||||
"jsrsasign": "8.0.20",
|
||||
"katex": "0.11.1",
|
||||
"koa": "2.11.0",
|
||||
"koa": "2.13.0",
|
||||
"koa-bodyparser": "4.3.0",
|
||||
"koa-favicon": "2.1.0",
|
||||
"koa-json-body": "5.3.0",
|
||||
"koa-logger": "3.2.1",
|
||||
"koa-mount": "4.0.0",
|
||||
"koa-send": "5.0.0",
|
||||
"koa-send": "5.0.1",
|
||||
"koa-slow": "2.1.0",
|
||||
"koa-views": "6.2.1",
|
||||
"koa-views": "6.3.0",
|
||||
"langmap": "0.0.16",
|
||||
"lookup-dns-cache": "2.1.0",
|
||||
"markdown-it": "10.0.0",
|
||||
"markdown-it-anchor": "5.2.7",
|
||||
"mocha": "7.1.2",
|
||||
"markdown-it": "11.0.0",
|
||||
"markdown-it-anchor": "5.3.0",
|
||||
"mocha": "8.0.1",
|
||||
"moji": "0.5.1",
|
||||
"ms": "2.1.2",
|
||||
"multer": "1.4.2",
|
||||
"nested-property": "2.0.0",
|
||||
"nested-property": "2.0.1",
|
||||
"node-fetch": "2.6.0",
|
||||
"nodemailer": "6.4.6",
|
||||
"nodemailer": "6.4.10",
|
||||
"nprogress": "0.2.0",
|
||||
"object-assign-deep": "0.4.0",
|
||||
"os-utils": "0.0.14",
|
||||
"parse5": "6.0.0",
|
||||
"parsimmon": "1.13.0",
|
||||
"pg": "8.1.0",
|
||||
"parsimmon": "1.14.0",
|
||||
"pg": "8.3.0",
|
||||
"portal-vue": "2.1.7",
|
||||
"portscanner": "2.2.0",
|
||||
"postcss-loader": "3.0.0",
|
||||
@ -213,55 +216,55 @@
|
||||
"rimraf": "3.0.2",
|
||||
"rndstr": "1.0.0",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.26.5",
|
||||
"sass-loader": "8.0.2",
|
||||
"sass": "1.26.10",
|
||||
"sass-loader": "9.0.2",
|
||||
"seedrandom": "3.0.5",
|
||||
"sharp": "0.25.2",
|
||||
"sharp": "0.25.4",
|
||||
"speakeasy": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"style-loader": "1.2.1",
|
||||
"summaly": "2.3.1",
|
||||
"summaly": "2.4.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "4.25.1",
|
||||
"systeminformation": "4.26.9",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.116.1",
|
||||
"three": "0.117.1",
|
||||
"tinycolor2": "1.4.1",
|
||||
"tmp": "0.2.1",
|
||||
"ts-loader": "7.0.3",
|
||||
"ts-node": "8.10.1",
|
||||
"ts-loader": "8.0.0",
|
||||
"ts-node": "8.10.2",
|
||||
"tslint": "6.1.2",
|
||||
"tslint-sonarts": "1.9.0",
|
||||
"typeorm": "0.2.24",
|
||||
"typescript": "3.9.1-rc",
|
||||
"typeorm": "0.2.25",
|
||||
"typescript": "3.9.6",
|
||||
"ulid": "2.3.0",
|
||||
"url-loader": "4.1.0",
|
||||
"uuid": "8.0.0",
|
||||
"uuid": "8.2.0",
|
||||
"v-animate-css": "0.0.3",
|
||||
"v-debounce": "0.1.2",
|
||||
"vue": "2.6.11",
|
||||
"vue-color": "2.7.1",
|
||||
"vue-content-loading": "1.6.0",
|
||||
"vue-cropperjs": "4.1.0",
|
||||
"vue-i18n": "8.17.4",
|
||||
"vue-json-pretty": "1.6.3",
|
||||
"vue-loader": "15.9.2",
|
||||
"vue-i18n": "8.18.2",
|
||||
"vue-json-pretty": "1.6.5",
|
||||
"vue-loader": "15.9.3",
|
||||
"vue-marquee-text-component": "1.1.1",
|
||||
"vue-meta": "2.3.3",
|
||||
"vue-meta": "2.4.0",
|
||||
"vue-prism-component": "1.2.0",
|
||||
"vue-prism-editor": "0.6.1",
|
||||
"vue-router": "3.1.6",
|
||||
"vue-router": "3.3.4",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vue-svg-inline-loader-corejs3": "1.5.0",
|
||||
"vue-template-compiler": "2.6.11",
|
||||
"vuedraggable": "2.23.2",
|
||||
"vuex": "3.3.0",
|
||||
"vuedraggable": "2.24.0",
|
||||
"vuex": "3.5.1",
|
||||
"vuex-persistedstate": "3.0.1",
|
||||
"web-push": "3.4.3",
|
||||
"webpack": "5.0.0-beta.16",
|
||||
"webpack-cli": "3.3.11",
|
||||
"web-push": "3.4.4",
|
||||
"webpack": "5.0.0-beta.22",
|
||||
"webpack-cli": "3.3.12",
|
||||
"websocket": "1.0.31",
|
||||
"ws": "7.2.5",
|
||||
"ws": "7.3.1",
|
||||
"xev": "2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -29,47 +29,7 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<transition name="nav-back">
|
||||
<div class="nav-back"
|
||||
v-if="showNav"
|
||||
@click="showNav = false"
|
||||
@touchstart="showNav = false"
|
||||
></div>
|
||||
</transition>
|
||||
|
||||
<transition name="nav">
|
||||
<nav class="nav" ref="nav" v-show="showNav">
|
||||
<div>
|
||||
<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
|
||||
<mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/>
|
||||
</button>
|
||||
<button class="item _button index active" @click="top()" v-if="$route.name === 'index'">
|
||||
<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
||||
</button>
|
||||
<router-link class="item index" active-class="active" to="/" exact v-else>
|
||||
<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
||||
</router-link>
|
||||
<template v-for="item in menu">
|
||||
<div v-if="item === '-'" class="divider"></div>
|
||||
<component v-else-if="menuDef[item].show !== false" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to">
|
||||
<fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
|
||||
<i v-if="menuDef[item].indicated"><fa :icon="faCircle"/></i>
|
||||
</component>
|
||||
</template>
|
||||
<div class="divider"></div>
|
||||
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu">
|
||||
<fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
|
||||
</button>
|
||||
<button class="item _button" @click="more">
|
||||
<fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
|
||||
<i v-if="otherNavItemIndicated"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
<router-link class="item" active-class="active" to="/preferences">
|
||||
<fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</nav>
|
||||
</transition>
|
||||
<x-sidebar ref="nav"/>
|
||||
|
||||
<div class="contents" ref="contents" :class="{ wallpaper }">
|
||||
<main ref="main">
|
||||
@ -86,38 +46,37 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="widgets">
|
||||
<div ref="widgets" :class="{ edit: widgetsEditMode }">
|
||||
<template v-if="isDesktop && $store.getters.isSignedIn">
|
||||
<template v-if="widgetsEditMode">
|
||||
<mk-button primary @click="addWidget" class="add"><fa :icon="faPlus"/></mk-button>
|
||||
<x-draggable
|
||||
:list="widgets"
|
||||
handle=".handle"
|
||||
animation="150"
|
||||
class="sortable"
|
||||
@sort="onWidgetSort"
|
||||
>
|
||||
<div v-for="widget in widgets" class="customize-container _panel" :key="widget.id">
|
||||
<header>
|
||||
<span class="handle"><fa :icon="faBars"/></span>{{ $t('_widgets.' + widget.name) }}<button class="remove _button" @click="removeWidget(widget)"><fa :icon="faTimes"/></button>
|
||||
</header>
|
||||
<div @click="widgetFunc(widget.id)">
|
||||
<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true"/>
|
||||
</div>
|
||||
<template v-if="isDesktop">
|
||||
<div v-for="place in ['left', 'right']" ref="widgets" class="widgets" :class="{ edit: widgetsEditMode, fixed: $store.state.device.fixedWidgetsPosition, empty: widgets[place].length === 0 && !widgetsEditMode }" :key="place">
|
||||
<div class="spacer"></div>
|
||||
<div class="container" v-if="widgetsEditMode">
|
||||
<mk-button primary @click="addWidget(place)" class="add"><fa :icon="faPlus"/></mk-button>
|
||||
<x-draggable
|
||||
:list="widgets[place]"
|
||||
handle=".handle"
|
||||
animation="150"
|
||||
class="sortable"
|
||||
@sort="onWidgetSort"
|
||||
>
|
||||
<div v-for="widget in widgets[place]" class="customize-container _panel" :key="widget.id">
|
||||
<header>
|
||||
<span class="handle"><fa :icon="faBars"/></span>{{ $t('_widgets.' + widget.name) }}<button class="remove _button" @click="removeWidget(widget)"><fa :icon="faTimes"/></button>
|
||||
</header>
|
||||
<div @click="widgetFunc(widget.id)">
|
||||
<component class="_close_ _forceContainerFull_" :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true"/>
|
||||
</div>
|
||||
</x-draggable>
|
||||
</template>
|
||||
<template v-else>
|
||||
<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</x-draggable>
|
||||
</div>
|
||||
<div class="container" v-else>
|
||||
<component v-for="widget in widgets[place]" class="_close_ _forceContainerFull_" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<button class="button nav _button" @click="showNav = true" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button>
|
||||
<button class="button nav _button" @click="showNav" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button>
|
||||
<button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button>
|
||||
<button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button>
|
||||
<button v-if="$store.getters.isSignedIn" class="button notifications _button" @click="$router.push('/my/notifications')"><fa :icon="faBell"/><i v-if="$store.state.i.hasUnreadNotification"><fa :icon="faCircle"/></i></button>
|
||||
@ -134,18 +93,18 @@
|
||||
import Vue from 'vue';
|
||||
import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
|
||||
import { ResizeObserver } from '@juggle/resize-observer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import i18n from './i18n';
|
||||
import { host, instanceName } from './config';
|
||||
import { host } from './config';
|
||||
import { search } from './scripts/search';
|
||||
import { StickySidebar } from './scripts/sticky-sidebar';
|
||||
import { widgets } from './widgets';
|
||||
import XSidebar from './components/sidebar.vue';
|
||||
|
||||
const DESKTOP_THRESHOLD = 1100;
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XSidebar,
|
||||
XClock: () => import('./components/header-clock.vue').then(m => m.default),
|
||||
MkButton: () => import('./components/ui/button.vue').then(m => m.default),
|
||||
XDraggable: () => import('vuedraggable'),
|
||||
@ -155,19 +114,14 @@ export default Vue.extend({
|
||||
return {
|
||||
host: host,
|
||||
pageKey: 0,
|
||||
showNav: false,
|
||||
searching: false,
|
||||
accounts: [],
|
||||
lists: [],
|
||||
connection: null,
|
||||
searchQuery: '',
|
||||
searchWait: false,
|
||||
widgetsEditMode: false,
|
||||
menuDef: this.$store.getters.nav({
|
||||
search: this.search
|
||||
}),
|
||||
isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
|
||||
canBack: false,
|
||||
menuDef: this.$store.getters.nav({}),
|
||||
wallpaper: localStorage.getItem('wallpaper') != null,
|
||||
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
|
||||
};
|
||||
@ -176,6 +130,10 @@ export default Vue.extend({
|
||||
computed: {
|
||||
keymap(): any {
|
||||
return {
|
||||
'd': () => {
|
||||
if (this.$store.state.device.syncDeviceDarkMode) return;
|
||||
this.$store.commit('device/set', { key: 'darkMode', value: !this.$store.state.device.darkMode });
|
||||
},
|
||||
'p': this.post,
|
||||
'n': this.post,
|
||||
's': this.search,
|
||||
@ -184,70 +142,83 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
widgets(): any[] {
|
||||
return this.$store.state.deviceUser.widgets;
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
const widgets = this.$store.state.deviceUser.widgets;
|
||||
return {
|
||||
left: widgets.filter(x => x.place === 'left'),
|
||||
right: widgets.filter(x => x.place == null || x.place === 'right'),
|
||||
mobile: widgets.filter(x => x.place === 'mobile'),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
left: [],
|
||||
right: [{
|
||||
name: 'welcome',
|
||||
id: 'a', place: 'right', data: {}
|
||||
}, {
|
||||
name: 'calendar',
|
||||
id: 'b', place: 'right', data: {}
|
||||
}, {
|
||||
name: 'trends',
|
||||
id: 'c', place: 'right', data: {}
|
||||
}],
|
||||
mobile: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
menu(): string[] {
|
||||
return this.$store.state.deviceUser.menu;
|
||||
},
|
||||
|
||||
otherNavItemIndicated(): boolean {
|
||||
if (!this.$store.getters.isSignedIn) return false;
|
||||
for (const def in this.menuDef) {
|
||||
if (this.menu.includes(def)) continue;
|
||||
if (this.menuDef[def].indicated) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
navIndicated(): boolean {
|
||||
if (!this.$store.getters.isSignedIn) return false;
|
||||
for (const def in this.menuDef) {
|
||||
if (def === 'timeline') continue;
|
||||
if (def === 'notifications') continue;
|
||||
if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから
|
||||
if (this.menuDef[def].indicated) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
watch:{
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.pageKey++;
|
||||
this.showNav = false;
|
||||
this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
|
||||
},
|
||||
|
||||
isDesktop() {
|
||||
if (this.isDesktop) this.adjustWidgetsWidth();
|
||||
this.$nextTick(() => {
|
||||
this.attachSticky();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
document.documentElement.style.overflowY = 'scroll';
|
||||
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection = this.$root.stream.useSharedConnection('main');
|
||||
this.connection.on('notification', this.onNotification);
|
||||
|
||||
if (this.widgets.length === 0) {
|
||||
if (this.$store.state.deviceUser.widgets.length === 0) {
|
||||
this.$store.commit('deviceUser/setWidgets', [{
|
||||
name: 'calendar',
|
||||
id: 'a', data: {}
|
||||
id: 'a', place: 'right', data: {}
|
||||
}, {
|
||||
name: 'notifications',
|
||||
id: 'b', data: {}
|
||||
id: 'b', place: 'right', data: {}
|
||||
}, {
|
||||
name: 'trends',
|
||||
id: 'c', data: {}
|
||||
id: 'c', place: 'right', data: {}
|
||||
}]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.isDesktop) this.adjustWidgetsWidth();
|
||||
|
||||
const adjustTitlePosition = () => {
|
||||
const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.offsetWidth;
|
||||
const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.$el.offsetWidth;
|
||||
if (left >= 0) {
|
||||
this.$refs.title.style.left = left + 'px';
|
||||
}
|
||||
@ -268,20 +239,26 @@ export default Vue.extend({
|
||||
if (window.innerWidth >= DESKTOP_THRESHOLD) this.isDesktop = true;
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
// widget follow
|
||||
this.attachSticky();
|
||||
},
|
||||
|
||||
methods: {
|
||||
adjustWidgetsWidth() {
|
||||
// https://stackoverflow.com/questions/33891709/when-flexbox-items-wrap-in-column-mode-container-does-not-grow-its-width
|
||||
const adjust = () => {
|
||||
const lastChild = this.$refs.widgets.children[this.$refs.widgets.children.length - 1];
|
||||
if (lastChild == null) return;
|
||||
showNav() {
|
||||
this.$refs.nav.show();
|
||||
},
|
||||
|
||||
const width = lastChild.offsetLeft + 300 + 16;
|
||||
this.$refs.widgets.style.width = width + 'px';
|
||||
};
|
||||
setInterval(adjust, 1000);
|
||||
setTimeout(adjust, 100);
|
||||
attachSticky() {
|
||||
if (!this.isDesktop) return;
|
||||
if (this.$store.state.device.fixedWidgetsPosition) return;
|
||||
|
||||
const stickyWidgetColumns = this.$refs.widgets.map(w => new StickySidebar(w.children[1], w.children[0], w.offsetTop));
|
||||
window.addEventListener('scroll', () => {
|
||||
for (const stickyWidgetColumn of stickyWidgetColumns) {
|
||||
stickyWidgetColumn.calc(window.scrollY);
|
||||
}
|
||||
}, { passive: true });
|
||||
},
|
||||
|
||||
top() {
|
||||
@ -330,181 +307,8 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
async openAccountMenu(ev) {
|
||||
const accounts = (await this.$root.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id);
|
||||
|
||||
const accountItems = accounts.map(account => ({
|
||||
type: 'user',
|
||||
user: account,
|
||||
action: () => { this.switchAccount(account); }
|
||||
}));
|
||||
|
||||
this.$root.menu({
|
||||
items: [...[{
|
||||
type: 'link',
|
||||
text: this.$t('profile'),
|
||||
to: `/@${ this.$store.state.i.username }`,
|
||||
avatar: this.$store.state.i,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('accountSettings'),
|
||||
to: '/my/settings',
|
||||
icon: faCog,
|
||||
}, null, ...accountItems, {
|
||||
icon: faPlus,
|
||||
text: this.$t('addAcount'),
|
||||
action: () => {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
text: this.$t('existingAcount'),
|
||||
action: () => { this.addAcount(); },
|
||||
}, {
|
||||
text: this.$t('createAccount'),
|
||||
action: () => { this.createAccount(); },
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
}]],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
oepnInstanceMenu(ev) {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
type: 'link',
|
||||
text: this.$t('dashboard'),
|
||||
to: '/instance',
|
||||
icon: faTachometerAlt,
|
||||
}, null, {
|
||||
type: 'link',
|
||||
text: this.$t('settings'),
|
||||
to: '/instance/settings',
|
||||
icon: faCog,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('customEmojis'),
|
||||
to: '/instance/emojis',
|
||||
icon: faLaugh,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('users'),
|
||||
to: '/instance/users',
|
||||
icon: faUsers,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('files'),
|
||||
to: '/instance/files',
|
||||
icon: faCloud,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('jobQueue'),
|
||||
to: '/instance/queue',
|
||||
icon: faExchangeAlt,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('federation'),
|
||||
to: '/instance/federation',
|
||||
icon: faGlobe,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('relays'),
|
||||
to: '/instance/relays',
|
||||
icon: faProjectDiagram,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('announcements'),
|
||||
to: '/instance/announcements',
|
||||
icon: faBroadcastTower,
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 200,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
more(ev) {
|
||||
const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
|
||||
type: def.to ? 'link' : 'button',
|
||||
text: this.$t(def.title),
|
||||
icon: def.icon,
|
||||
to: def.to,
|
||||
action: def.action,
|
||||
indicate: def.indicated,
|
||||
}));
|
||||
this.$root.menu({
|
||||
items: [...items, null, {
|
||||
type: 'link',
|
||||
text: this.$t('help'),
|
||||
to: '/docs',
|
||||
icon: faQuestionCircle,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('aboutX', { x: instanceName || host }),
|
||||
to: '/about',
|
||||
icon: faInfoCircle,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('aboutMisskey'),
|
||||
to: '/about-misskey',
|
||||
icon: faInfoCircle,
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 200,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
async addAcount() {
|
||||
this.$root.new(await import('./components/signin-dialog.vue').then(m => m.default)).$once('login', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
iconOnly: true, autoClose: true
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async createAccount() {
|
||||
this.$root.new(await import('./components/signup-dialog.vue').then(m => m.default)).$once('signup', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.switchAccountWithToken(res.i);
|
||||
});
|
||||
},
|
||||
|
||||
async switchAccount(account: any) {
|
||||
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
||||
this.switchAccountWithToken(token);
|
||||
},
|
||||
|
||||
switchAccountWithToken(token: string) {
|
||||
this.$root.dialog({
|
||||
type: 'waiting',
|
||||
iconOnly: true
|
||||
});
|
||||
|
||||
this.$root.api('i', {}, token).then((i: any) => {
|
||||
this.$store.dispatch('switchAccount', {
|
||||
...i,
|
||||
token: token
|
||||
}).then(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async onNotification(notification) {
|
||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||
if (true) {
|
||||
if (document.visibilityState === 'visible') {
|
||||
this.$root.stream.send('readNotification', {
|
||||
id: notification.id
|
||||
});
|
||||
@ -518,39 +322,32 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
widgetFunc(id) {
|
||||
const w = this.$refs[id][0];
|
||||
if (w.func) w.func();
|
||||
this.$refs[id][0].setting();
|
||||
},
|
||||
|
||||
onWidgetSort() {
|
||||
this.saveHome();
|
||||
},
|
||||
|
||||
addWidget(ev) {
|
||||
const widgets = [
|
||||
'memo',
|
||||
'notifications',
|
||||
'timeline',
|
||||
'calendar',
|
||||
'rss',
|
||||
'trends',
|
||||
'clock',
|
||||
'activity',
|
||||
'photos',
|
||||
];
|
||||
async addWidget(place) {
|
||||
const { canceled, result: widget } = await this.$root.dialog({
|
||||
type: null,
|
||||
title: this.$t('chooseWidget'),
|
||||
select: {
|
||||
items: widgets.map(widget => ({
|
||||
value: widget,
|
||||
text: this.$t('_widgets.' + widget),
|
||||
}))
|
||||
},
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
this.$root.menu({
|
||||
items: widgets.map(widget => ({
|
||||
text: this.$t('_widgets.' + widget),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/addWidget', {
|
||||
name: widget,
|
||||
id: uuid(),
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
})),
|
||||
source: ev.currentTarget || ev.target,
|
||||
this.$store.commit('deviceUser/addWidget', {
|
||||
name: widget,
|
||||
id: uuid(),
|
||||
place: place,
|
||||
data: {}
|
||||
});
|
||||
},
|
||||
|
||||
@ -559,46 +356,27 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
saveHome() {
|
||||
this.$store.commit('deviceUser/setWidgets', this.widgets);
|
||||
this.$store.commit('deviceUser/setWidgets', [...this.widgets.left, ...this.widgets.right, ...this.widgets.mobile]);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nav-enter-active,
|
||||
.nav-leave-active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.nav-enter,
|
||||
.nav-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateX(-240px);
|
||||
}
|
||||
|
||||
.nav-back-enter-active,
|
||||
.nav-back-leave-active {
|
||||
opacity: 1;
|
||||
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.nav-back-enter,
|
||||
.nav-back-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mk-app {
|
||||
$header-height: 60px;
|
||||
$nav-width: 250px;
|
||||
$nav-icon-only-width: 80px;
|
||||
$main-width: 650px;
|
||||
$ui-font-size: 1em;
|
||||
$nav-icon-only-threshold: 1300px;
|
||||
$nav-hide-threshold: 650px;
|
||||
$side-hide-threshold: 1070px;
|
||||
$nav-width: 250px; // TODO: どこかに集約したい
|
||||
$nav-icon-only-width: 80px; // TODO: どこかに集約したい
|
||||
$main-width: 670px;
|
||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||
$nav-icon-only-threshold: 1279px; // TODO: どこかに集約したい
|
||||
$nav-hide-threshold: 650px; // TODO: どこかに集約したい
|
||||
$header-sub-hide-threshold: 1090px;
|
||||
$left-widgets-hide-threshold: 1600px;
|
||||
$right-widgets-hide-threshold: 1090px;
|
||||
|
||||
min-height: 100vh;
|
||||
// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||
min-height: calc(var(--vh, 1vh) * 100);
|
||||
box-sizing: border-box;
|
||||
padding-top: $header-height;
|
||||
|
||||
@ -694,7 +472,7 @@ export default Vue.extend({
|
||||
right: 16px;
|
||||
height: $header-height;
|
||||
|
||||
@media (max-width: $side-hide-threshold) {
|
||||
@media (max-width: $header-sub-hide-threshold) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -720,6 +498,7 @@ export default Vue.extend({
|
||||
border-radius: 38px;
|
||||
color: var(--fg);
|
||||
background: var(--bg);
|
||||
-webkit-appearance: textfield;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
@ -750,176 +529,6 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
|
||||
> .nav-back {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--modalBg);
|
||||
}
|
||||
|
||||
> .nav {
|
||||
$avatar-size: 32px;
|
||||
$avatar-margin: ($header-height - $avatar-size) / 2;
|
||||
|
||||
flex: 0 0 $nav-width;
|
||||
width: $nav-width;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) {
|
||||
flex: 0 0 $nav-icon-only-width;
|
||||
width: $nav-icon-only-width;
|
||||
}
|
||||
|
||||
@media (max-width: $nav-hide-threshold) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
@media (min-width: $nav-hide-threshold + 1px) {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
> div {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: $nav-width;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
background: var(--navBg);
|
||||
border-right: solid 1px var(--divider);
|
||||
|
||||
> .divider {
|
||||
margin: 16px 0;
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
|
||||
width: $nav-icon-only-width;
|
||||
|
||||
> .divider {
|
||||
margin: 8px auto;
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
> .item {
|
||||
&:first-child {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-left: 32px;
|
||||
font-size: $ui-font-size;
|
||||
line-height: 3.2rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
color: var(--navFg);
|
||||
|
||||
> [data-icon] {
|
||||
width: ($header-height - ($avatar-margin * 2));
|
||||
}
|
||||
|
||||
> [data-icon],
|
||||
> .avatar {
|
||||
margin-right: $avatar-margin;
|
||||
}
|
||||
|
||||
> .avatar {
|
||||
width: $avatar-size;
|
||||
height: $avatar-size;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
> i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: var(--navHoverFg);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--navActive);
|
||||
}
|
||||
|
||||
&:first-child, &:last-child {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
background: var(--wboyroyc);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
top: 0;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
bottom: 0;
|
||||
margin-top: 16px;
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
|
||||
padding-left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: $ui-font-size * 1.2;
|
||||
line-height: 3.7rem;
|
||||
|
||||
> [data-icon],
|
||||
> .avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
> i {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
> .text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $nav-hide-threshold) {
|
||||
> .index,
|
||||
> .notifications {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .contents {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
@ -927,29 +536,22 @@ export default Vue.extend({
|
||||
|
||||
&.wallpaper {
|
||||
background: var(--wallpaperOverlay);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
> main {
|
||||
width: $main-width;
|
||||
min-width: $main-width;
|
||||
box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
|
||||
|
||||
@media (max-width: $side-hide-threshold) {
|
||||
min-width: 0;
|
||||
}
|
||||
min-width: 0;
|
||||
|
||||
> .content {
|
||||
> * {
|
||||
&:not(.full) {
|
||||
padding: var(--margin) 0;
|
||||
}
|
||||
// ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||
min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
|
||||
box-sizing: border-box;
|
||||
padding: var(--margin);
|
||||
|
||||
&:not(.naked) {
|
||||
background: var(--pageBg);
|
||||
}
|
||||
|
||||
&.naked {
|
||||
background: var(--bg);
|
||||
&.full {
|
||||
padding: 0 var(--margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -987,67 +589,85 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
> .widgets {
|
||||
box-sizing: border-box;
|
||||
margin-left: var(--margin);
|
||||
padding: 0 var(--margin);
|
||||
box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
|
||||
|
||||
@media (max-width: $side-hide-threshold) {
|
||||
&.fixed {
|
||||
position: sticky;
|
||||
overflow: auto;
|
||||
// ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||
height: calc((var(--vh, 1vh) * 100) - #{$header-height});
|
||||
top: $header-height;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
order: -1;
|
||||
|
||||
@media (max-width: $left-widgets-hide-threshold) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> div {
|
||||
@media (max-width: $right-widgets-hide-threshold) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .container {
|
||||
position: sticky;
|
||||
top: calc(#{$header-height} + var(--margin));
|
||||
height: calc(100vh - #{$header-height} - var(--margin));
|
||||
|
||||
&.edit {
|
||||
overflow: auto;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
&:not(.edit) {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
place-content: flex-start;
|
||||
}
|
||||
height: min-content;
|
||||
// ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||
min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
|
||||
padding: var(--margin) 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
> * {
|
||||
margin: 0 var(--margin) var(--margin) 0;
|
||||
margin: var(--margin) 0;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
> .add {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.customize-container {
|
||||
margin: 8px 0;
|
||||
background: #fff;
|
||||
|
||||
> header {
|
||||
position: relative;
|
||||
line-height: 32px;
|
||||
|
||||
> .handle {
|
||||
padding: 0 8px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
> .remove {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0 8px;
|
||||
line-height: 32px;
|
||||
}
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> div {
|
||||
padding: 8px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> * {
|
||||
pointer-events: none;
|
||||
}
|
||||
> .add {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.customize-container {
|
||||
margin: 8px 0;
|
||||
|
||||
> header {
|
||||
position: relative;
|
||||
line-height: 32px;
|
||||
|
||||
> .handle {
|
||||
padding: 0 8px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
> .remove {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0 8px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
padding: 8px;
|
||||
|
||||
> * {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1070,7 +690,7 @@ export default Vue.extend({
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: ($side-hide-threshold + 1px)) {
|
||||
@media (min-width: ($header-sub-hide-threshold + 1px)) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@ -1083,7 +703,7 @@ export default Vue.extend({
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(0deg, var(--bg), var(--bonzsgfz));
|
||||
background: linear-gradient(0deg, var(--bg), var(--X1));
|
||||
|
||||
@media (max-width: 500px) {
|
||||
padding: 0 16px 16px 16px;
|
||||
@ -1127,7 +747,7 @@ export default Vue.extend({
|
||||
color: var(--fg);
|
||||
|
||||
&:hover {
|
||||
background: var(--pcncwizz);
|
||||
background: var(--X2);
|
||||
}
|
||||
|
||||
> i {
|
||||
|
BIN
src/client/assets/room/furnitures/banknote/banknote.blend
Normal file
BIN
src/client/assets/room/furnitures/banknote/banknote.blend
Normal file
Binary file not shown.
BIN
src/client/assets/room/furnitures/banknote/banknote.glb
Normal file
BIN
src/client/assets/room/furnitures/banknote/banknote.glb
Normal file
Binary file not shown.
BIN
src/client/assets/room/furnitures/banknote/tex.png
Normal file
BIN
src/client/assets/room/furnitures/banknote/tex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
src/client/assets/room/furnitures/doll-ai/doll-ai.blend
Normal file
BIN
src/client/assets/room/furnitures/doll-ai/doll-ai.blend
Normal file
Binary file not shown.
BIN
src/client/assets/room/furnitures/doll-ai/doll-ai.glb
Normal file
BIN
src/client/assets/room/furnitures/doll-ai/doll-ai.glb
Normal file
Binary file not shown.
BIN
src/client/assets/room/furnitures/doll-ai/doll_ai_tex.png
Normal file
BIN
src/client/assets/room/furnitures/doll-ai/doll_ai_tex.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
src/client/assets/sounds/syuilo/pirori-square-wet.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/pirori-square-wet.mp3
Normal file
Binary file not shown.
BIN
src/client/assets/sounds/syuilo/pirori-wet.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/pirori-wet.mp3
Normal file
Binary file not shown.
BIN
src/client/assets/sounds/syuilo/pirori.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/pirori.mp3
Normal file
Binary file not shown.
@ -426,7 +426,7 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--yrnqrguo);
|
||||
background: var(--X3);
|
||||
}
|
||||
|
||||
&[data-selected='true'] {
|
||||
|
@ -1,15 +1,9 @@
|
||||
<template>
|
||||
<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-if="disableLink && !disablePreview" v-user-preview="user.id" @click="onClick">
|
||||
<span class="inner" :style="icon"></span>
|
||||
<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
|
||||
<img class="inner" :src="url"/>
|
||||
</span>
|
||||
<span class="eiwwqkts" :class="{ cat }" :title="user | acct" v-else-if="disableLink && disablePreview" @click="onClick">
|
||||
<span class="inner" :style="icon"></span>
|
||||
</span>
|
||||
<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id">
|
||||
<span class="inner" :style="icon"></span>
|
||||
</router-link>
|
||||
<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && disablePreview">
|
||||
<span class="inner" :style="icon"></span>
|
||||
<router-link class="eiwwqkts" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
|
||||
<img class="inner" :src="url"/>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
@ -45,24 +39,25 @@ export default Vue.extend({
|
||||
? getStaticImageUrl(this.user.avatarUrl)
|
||||
: this.user.avatarUrl;
|
||||
},
|
||||
icon(): any {
|
||||
return {
|
||||
backgroundColor: this.user.avatarColor,
|
||||
backgroundImage: `url(${this.url})`,
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'user.avatarColor'() {
|
||||
this.$el.style.color = this.user.avatarColor;
|
||||
'user.avatarBlurhash'() {
|
||||
this.$el.style.color = this.getBlurhashAvgColor(this.user.avatarBlurhash);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.user.avatarColor) {
|
||||
this.$el.style.color = this.user.avatarColor;
|
||||
}
|
||||
this.$el.style.color = this.getBlurhashAvgColor(this.user.avatarBlurhash);
|
||||
},
|
||||
methods: {
|
||||
getBlurhashAvgColor(s) {
|
||||
return typeof s == 'string'
|
||||
? '#' + [...s.slice(2, 6)]
|
||||
.map(x => '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~'.indexOf(x))
|
||||
.reduce((a, c) => a * 83 + c, 0)
|
||||
.toString(16)
|
||||
.padStart(6, '0')
|
||||
: undefined;
|
||||
},
|
||||
onClick(e) {
|
||||
this.$emit('click', e);
|
||||
}
|
||||
@ -102,15 +97,17 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
.inner {
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-radius: 100%;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
|
||||
type Captcha = {
|
||||
render(container: string | Node, options: {
|
||||
@ -31,7 +30,6 @@ declare global {
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
provider: {
|
||||
type: String,
|
||||
|
@ -7,13 +7,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import { length } from 'stringz';
|
||||
import { concat } from '../../prelude/array';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
@ -30,7 +27,7 @@ export default Vue.extend({
|
||||
return concat([
|
||||
this.note.text ? [this.$t('_cw.chars', { count: length(this.note.text) })] : [],
|
||||
this.note.files && this.note.files.length !== 0 ? [this.$t('_cw.files', { count: this.note.files.length }) ] : [],
|
||||
this.note.poll != null ? [this.$t('_cw.poll')] : []
|
||||
this.note.poll != null ? [this.$t('poll')] : []
|
||||
] as string[][]).join(' / ');
|
||||
}
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<component :is="$store.state.device.animation ? 'transition-group' : 'div'" class="sqadhkmv" name="list" tag="div" :data-direction="direction" :data-reversed="reversed ? 'true' : 'false'">
|
||||
<component :is="$store.state.device.animation ? 'transition-group' : 'div'" class="sqadhkmv _list_" name="list" tag="div" :data-direction="direction" :data-reversed="reversed ? 'true' : 'false'">
|
||||
<template v-for="(item, i) in items">
|
||||
<slot :item="item"></slot>
|
||||
<div class="separator" v-if="showDate(i, item)" :key="item.id + '_date'">
|
||||
@ -15,11 +15,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
@ -72,6 +69,10 @@ export default Vue.extend({
|
||||
|
||||
<style lang="scss">
|
||||
.sqadhkmv {
|
||||
> *:not(:last-child) {
|
||||
margin-bottom: var(--margin);
|
||||
}
|
||||
|
||||
> .list-move {
|
||||
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
|
87
src/client/components/deck/antenna-column.vue
Normal file
87
src/client/components/deck/antenna-column.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<x-column :menu="menu" :column="column" :is-stacked="isStacked">
|
||||
<template #header>
|
||||
<fa :icon="faSatellite"/><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||
</template>
|
||||
|
||||
<x-timeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @after="() => $emit('loaded')"/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faSatellite, faCog } from '@fortawesome/free-solid-svg-icons';
|
||||
import XColumn from './column.vue';
|
||||
import XTimeline from '../timeline.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XTimeline,
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
faSatellite
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
mediaOnly() {
|
||||
(this.$refs.timeline as any).reload();
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.menu = [{
|
||||
icon: faCog,
|
||||
text: this.$t('selectAntenna'),
|
||||
action: this.setAntenna
|
||||
}];
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.column.antennaId == null) {
|
||||
this.setAntenna();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async setAntenna() {
|
||||
const antennas = await this.$root.api('antennas/list');
|
||||
const { canceled, result: antenna } = await this.$root.dialog({
|
||||
title: this.$t('selectAntenna'),
|
||||
type: null,
|
||||
select: {
|
||||
items: antennas.map(x => ({
|
||||
value: x, text: x.name
|
||||
})),
|
||||
default: this.column.antennaId
|
||||
},
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
Vue.set(this.column, 'antennaId', antenna.id);
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
},
|
||||
|
||||
focus() {
|
||||
(this.$refs.timeline as any).focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
50
src/client/components/deck/column-core.vue
Normal file
50
src/client/components/deck/column-core.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<!-- TODO: リファクタの余地がありそう -->
|
||||
<x-widgets-column v-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<x-notifications-column v-else-if="column.type === 'notifications'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<x-tl-column v-else-if="column.type === 'tl'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<x-list-column v-else-if="column.type === 'list'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<x-antenna-column v-else-if="column.type === 'antenna'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<!-- TODO: <x-tl-column v-else-if="column.type === 'hashtag'" :column="column" :is-stacked="isStacked" v-on="$listeners"/> -->
|
||||
<x-mentions-column v-else-if="column.type === 'mentions'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
<x-direct-column v-else-if="column.type === 'direct'" :column="column" :is-stacked="isStacked" v-on="$listeners"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XTlColumn from './tl-column.vue';
|
||||
import XAntennaColumn from './antenna-column.vue';
|
||||
import XListColumn from './list-column.vue';
|
||||
import XNotificationsColumn from './notifications-column.vue';
|
||||
import XWidgetsColumn from './widgets-column.vue';
|
||||
import XMentionsColumn from './mentions-column.vue';
|
||||
import XDirectColumn from './direct-column.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XTlColumn,
|
||||
XAntennaColumn,
|
||||
XListColumn,
|
||||
XNotificationsColumn,
|
||||
XWidgetsColumn,
|
||||
XMentionsColumn,
|
||||
XDirectColumn
|
||||
},
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
this.$children[0].focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
426
src/client/components/deck/column.vue
Normal file
426
src/client/components/deck/column.vue
Normal file
@ -0,0 +1,426 @@
|
||||
<template>
|
||||
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
|
||||
<section class="dnpfarvg _panel _narrow_" :class="{ naked, paged: isMainColumn, _close_: !isMainColumn, active, isStacked, draghover, dragging, dropready }"
|
||||
@dragover.prevent.stop="onDragover"
|
||||
@dragleave="onDragleave"
|
||||
@drop.prevent.stop="onDrop"
|
||||
v-hotkey="keymap"
|
||||
:style="{ width: `${width}px` }"
|
||||
>
|
||||
<header :class="{ indicated }"
|
||||
draggable="true"
|
||||
@click="goTop"
|
||||
@dragstart="onDragstart"
|
||||
@dragend="onDragend"
|
||||
@contextmenu.prevent.stop="onContextmenu"
|
||||
>
|
||||
<button class="toggleActive _button" @click="toggleActive" v-if="isStacked">
|
||||
<template v-if="active"><fa :icon="faAngleUp"/></template>
|
||||
<template v-else><fa :icon="faAngleDown"/></template>
|
||||
</button>
|
||||
<div class="action">
|
||||
<slot name="action"></slot>
|
||||
</div>
|
||||
<span class="header"><slot name="header"></slot></span>
|
||||
<button v-if="!isMainColumn" class="menu _button" ref="menu" @click.stop="showMenu"><fa :icon="faCaretDown"/></button>
|
||||
<button v-else-if="$route.name !== 'index'" class="close _button" @click.stop="close"><fa :icon="faTimes"/></button>
|
||||
</header>
|
||||
<div ref="body" v-show="active">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faArrowUp, faArrowDown, faAngleUp, faAngleDown, faCaretDown, faTimes, faArrowRight, faArrowLeft, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faWindowMaximize, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
menu: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
naked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
indicated: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
active: true,
|
||||
dragging: false,
|
||||
draghover: false,
|
||||
dropready: false,
|
||||
faArrowUp, faArrowDown, faAngleUp, faAngleDown, faCaretDown, faTimes,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isMainColumn(): boolean {
|
||||
return this.column == null;
|
||||
},
|
||||
|
||||
width(): number {
|
||||
return this.isMainColumn ? 350 : this.column.width;
|
||||
},
|
||||
|
||||
keymap(): any {
|
||||
return {
|
||||
'shift+up': () => this.$parent.$emit('parentFocus', 'up'),
|
||||
'shift+down': () => this.$parent.$emit('parentFocus', 'down'),
|
||||
'shift+left': () => this.$parent.$emit('parentFocus', 'left'),
|
||||
'shift+right': () => this.$parent.$emit('parentFocus', 'right'),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
active(v) {
|
||||
this.$emit('change-active-state', v);
|
||||
},
|
||||
|
||||
dragging(v) {
|
||||
this.$root.$emit(v ? 'deck.column.dragStart' : 'deck.column.dragEnd');
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.isMainColumn) {
|
||||
this.$root.$on('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (!this.isMainColumn) {
|
||||
this.$root.$off('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onOtherDragStart() {
|
||||
this.dropready = true;
|
||||
},
|
||||
|
||||
onOtherDragEnd() {
|
||||
this.dropready = false;
|
||||
},
|
||||
|
||||
toggleActive() {
|
||||
if (!this.isStacked) return;
|
||||
this.active = !this.active;
|
||||
},
|
||||
|
||||
getMenu() {
|
||||
const items = [{
|
||||
icon: faPencilAlt,
|
||||
text: this.$t('rename'),
|
||||
action: () => {
|
||||
this.$root.dialog({
|
||||
title: this.$t('rename'),
|
||||
input: {
|
||||
default: this.column.name,
|
||||
allowEmpty: false
|
||||
}
|
||||
}).then(({ canceled, result: name }) => {
|
||||
if (canceled) return;
|
||||
this.$store.commit('deviceUser/renameDeckColumn', { id: this.column.id, name });
|
||||
});
|
||||
}
|
||||
}, null, {
|
||||
icon: faArrowLeft,
|
||||
text: this.$t('_deck.swapLeft'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/swapLeftDeckColumn', this.column.id);
|
||||
}
|
||||
}, {
|
||||
icon: faArrowRight,
|
||||
text: this.$t('_deck.swapRight'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/swapRightDeckColumn', this.column.id);
|
||||
}
|
||||
}, this.isStacked ? {
|
||||
icon: faArrowUp,
|
||||
text: this.$t('_deck.swapUp'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/swapUpDeckColumn', this.column.id);
|
||||
}
|
||||
} : undefined, this.isStacked ? {
|
||||
icon: faArrowDown,
|
||||
text: this.$t('_deck.swapDown'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/swapDownDeckColumn', this.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: faWindowRestore,
|
||||
text: this.$t('_deck.stackLeft'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/stackLeftDeckColumn', this.column.id);
|
||||
}
|
||||
}, this.isStacked ? {
|
||||
icon: faWindowMaximize,
|
||||
text: this.$t('_deck.popRight'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/popRightDeckColumn', this.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: faTrashAlt,
|
||||
text: this.$t('remove'),
|
||||
action: () => {
|
||||
this.$store.commit('deviceUser/removeDeckColumn', this.column.id);
|
||||
}
|
||||
}];
|
||||
|
||||
if (this.menu) {
|
||||
for (const i of this.menu.reverse()) {
|
||||
items.unshift(i);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
onContextmenu(e) {
|
||||
if (this.isMainColumn) return;
|
||||
this.showMenu();
|
||||
},
|
||||
|
||||
showMenu() {
|
||||
this.$root.menu({
|
||||
items: this.getMenu(),
|
||||
source: this.$refs.menu,
|
||||
});
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$router.push('/');
|
||||
},
|
||||
|
||||
goTop() {
|
||||
this.$refs.body.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
},
|
||||
|
||||
onDragstart(e) {
|
||||
// メインカラムはドラッグさせない
|
||||
if (this.isMainColumn) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('mk-deck-column', this.column.id);
|
||||
this.dragging = true;
|
||||
},
|
||||
|
||||
onDragend(e) {
|
||||
this.dragging = false;
|
||||
},
|
||||
|
||||
onDragover(e) {
|
||||
// メインカラムにはドロップさせない
|
||||
if (this.isMainColumn) {
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// 自分自身がドラッグされている場合
|
||||
if (this.dragging) {
|
||||
// 自分自身にはドロップさせない
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const isDeckColumn = e.dataTransfer.types[0] == 'mk-deck-column';
|
||||
|
||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||
|
||||
if (!this.dragging && isDeckColumn) this.draghover = true;
|
||||
},
|
||||
|
||||
onDragleave() {
|
||||
this.draghover = false;
|
||||
},
|
||||
|
||||
onDrop(e) {
|
||||
this.draghover = false;
|
||||
this.$root.$emit('deck.column.dragEnd');
|
||||
|
||||
const id = e.dataTransfer.getData('mk-deck-column');
|
||||
if (id != null && id != '') {
|
||||
this.$store.commit('deviceUser/swapDeckColumn', {
|
||||
a: this.column.id,
|
||||
b: id
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dnpfarvg {
|
||||
$header-height: 42px;
|
||||
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 0 1px var(--deckColumnBorder);
|
||||
|
||||
&.draghover {
|
||||
box-shadow: 0 0 0 2px var(--focus);
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--focus);
|
||||
}
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
box-shadow: 0 0 0 2px var(--focus);
|
||||
}
|
||||
|
||||
&.dropready {
|
||||
* {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
flex-basis: $header-height;
|
||||
min-height: $header-height;
|
||||
|
||||
> header.indicated {
|
||||
box-shadow: 4px 0px var(--accent) inset;
|
||||
}
|
||||
}
|
||||
|
||||
&.naked {
|
||||
//background: var(--deckAcrylicColumnBg);
|
||||
background: transparent !important;
|
||||
|
||||
> header {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
|
||||
> button {
|
||||
color: var(--fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.paged {
|
||||
> div {
|
||||
background: var(--bg);
|
||||
padding: var(--margin);
|
||||
}
|
||||
}
|
||||
|
||||
> header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
line-height: $header-height;
|
||||
padding: 0 16px;
|
||||
font-size: 0.9em;
|
||||
color: var(--panelHeaderFg);
|
||||
background: var(--panelHeaderBg);
|
||||
box-shadow: 0 1px 0 0 var(--panelHeaderDivider);
|
||||
cursor: pointer;
|
||||
|
||||
&, * {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&.indicated {
|
||||
box-shadow: 0 3px 0 0 var(--accent);
|
||||
}
|
||||
|
||||
> .header {
|
||||
display: inline-block;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
> span:only-of-type {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .toggleActive,
|
||||
> .action > *,
|
||||
> .menu,
|
||||
> .close {
|
||||
z-index: 1;
|
||||
width: $header-height;
|
||||
line-height: $header-height;
|
||||
font-size: 16px;
|
||||
color: var(--faceTextButton);
|
||||
|
||||
&:hover {
|
||||
color: var(--faceTextButtonHover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--faceTextButtonActive);
|
||||
}
|
||||
}
|
||||
|
||||
> .toggleActive, > .action {
|
||||
margin-left: -16px;
|
||||
}
|
||||
|
||||
> .action {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
> .action:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .menu,
|
||||
> .close {
|
||||
margin-left: auto;
|
||||
margin-right: -16px;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
height: calc(100% - #{$header-height});
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
57
src/client/components/deck/direct-column.vue
Normal file
57
src/client/components/deck/direct-column.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<x-column :name="name" :column="column" :is-stacked="isStacked" :menu="menu">
|
||||
<template #header><fa :icon="faEnvelope" style="margin-right: 8px;"/>{{ column.name }}</template>
|
||||
|
||||
<x-notes :pagination="pagination" @before="before()" @after="after()"/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faEnvelope } from '@fortawesome/free-solid-svg-icons';
|
||||
import Progress from '../../scripts/loading';
|
||||
import XColumn from './column.vue';
|
||||
import XNotes from '../notes.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XNotes
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
menu: null,
|
||||
pagination: {
|
||||
endpoint: 'notes/mentions',
|
||||
limit: 10,
|
||||
params: () => ({
|
||||
visibility: 'specified'
|
||||
})
|
||||
},
|
||||
faEnvelope
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
before() {
|
||||
Progress.start();
|
||||
},
|
||||
|
||||
after() {
|
||||
Progress.done();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
87
src/client/components/deck/list-column.vue
Normal file
87
src/client/components/deck/list-column.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<x-column :menu="menu" :column="column" :is-stacked="isStacked">
|
||||
<template #header>
|
||||
<fa :icon="faListUl"/><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||
</template>
|
||||
|
||||
<x-timeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" @after="() => $emit('loaded')"/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faListUl, faCog } from '@fortawesome/free-solid-svg-icons';
|
||||
import XColumn from './column.vue';
|
||||
import XTimeline from '../timeline.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XTimeline,
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
faListUl
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
mediaOnly() {
|
||||
(this.$refs.timeline as any).reload();
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.menu = [{
|
||||
icon: faCog,
|
||||
text: this.$t('selectList'),
|
||||
action: this.setList
|
||||
}];
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.column.listId == null) {
|
||||
this.setList();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async setList() {
|
||||
const lists = await this.$root.api('users/lists/list');
|
||||
const { canceled, result: list } = await this.$root.dialog({
|
||||
title: this.$t('selectList'),
|
||||
type: null,
|
||||
select: {
|
||||
items: lists.map(x => ({
|
||||
value: x, text: x.name
|
||||
})),
|
||||
default: this.column.listId
|
||||
},
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
Vue.set(this.column, 'listId', list.id);
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
},
|
||||
|
||||
focus() {
|
||||
(this.$refs.timeline as any).focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
54
src/client/components/deck/mentions-column.vue
Normal file
54
src/client/components/deck/mentions-column.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<x-column :column="column" :is-stacked="isStacked" :menu="menu">
|
||||
<template #header><fa :icon="faAt" style="margin-right: 8px;"/>{{ column.name }}</template>
|
||||
|
||||
<x-notes :pagination="pagination" @before="before()" @after="after()"/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faAt } from '@fortawesome/free-solid-svg-icons';
|
||||
import Progress from '../../scripts/loading';
|
||||
import XColumn from './column.vue';
|
||||
import XNotes from '../notes.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XNotes
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
menu: null,
|
||||
pagination: {
|
||||
endpoint: 'notes/mentions',
|
||||
limit: 10,
|
||||
},
|
||||
faAt
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
before() {
|
||||
Progress.start();
|
||||
},
|
||||
|
||||
after() {
|
||||
Progress.done();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
69
src/client/components/deck/notifications-column.vue
Normal file
69
src/client/components/deck/notifications-column.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<x-column :column="column" :is-stacked="isStacked" :menu="menu">
|
||||
<template #header><fa :icon="faBell" style="margin-right: 8px;"/>{{ column.name }}</template>
|
||||
|
||||
<x-notifications/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCog } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBell } from '@fortawesome/free-regular-svg-icons';
|
||||
import XColumn from './column.vue';
|
||||
import XNotifications from '../notifications.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XNotifications
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
menu: null,
|
||||
faBell
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.column.notificationType == null) {
|
||||
this.column.notificationType = 'all';
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
}
|
||||
|
||||
this.menu = [{
|
||||
icon: faCog,
|
||||
text: this.$t('notificationType'),
|
||||
action: () => {
|
||||
this.$root.dialog({
|
||||
title: this.$t('notificationType'),
|
||||
type: null,
|
||||
select: {
|
||||
items: ['all', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest'].map(x => ({
|
||||
value: x, text: this.$t(`_notification._types.${x}`)
|
||||
}))
|
||||
default: this.column.notificationType,
|
||||
},
|
||||
showCancelButton: true
|
||||
}).then(({ canceled, result: type }) => {
|
||||
if (canceled) return;
|
||||
this.column.notificationType = type;
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
});
|
||||
}
|
||||
}];
|
||||
},
|
||||
});
|
||||
</script>
|
145
src/client/components/deck/tl-column.vue
Normal file
145
src/client/components/deck/tl-column.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<x-column :menu="menu" :column="column" :is-stacked="isStacked" :indicated="indicated" @change-active-state="onChangeActiveState">
|
||||
<template #header>
|
||||
<fa v-if="column.tl === 'home'" :icon="faHome"/>
|
||||
<fa v-else-if="column.tl === 'local'" :icon="faComments"/>
|
||||
<fa v-else-if="column.tl === 'social'" :icon="faShareAlt"/>
|
||||
<fa v-else-if="column.tl === 'global'" :icon="faGlobe"/>
|
||||
<span style="margin-left: 8px;">{{ column.name }}</span>
|
||||
</template>
|
||||
|
||||
<div class="iwaalbte" v-if="disabled">
|
||||
<p>
|
||||
<fa :icon="faMinusCircle"/>
|
||||
{{ $t('disabled-timeline.title') }}
|
||||
</p>
|
||||
<p class="desc">{{ $t('disabled-timeline.description') }}</p>
|
||||
</div>
|
||||
<x-timeline v-else-if="column.tl" ref="timeline" :src="column.tl" @after="() => $emit('loaded')" @queue="queueUpdated" @note="onNote" :key="column.tl"/>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faMinusCircle, faHome, faComments, faShareAlt, faGlobe, faCog } from '@fortawesome/free-solid-svg-icons';
|
||||
import XColumn from './column.vue';
|
||||
import XTimeline from '../timeline.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XTimeline,
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
menu: null,
|
||||
disabled: false,
|
||||
indicated: false,
|
||||
columnActive: true,
|
||||
faMinusCircle, faHome, faComments, faShareAlt, faGlobe,
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
mediaOnly() {
|
||||
(this.$refs.timeline as any).reload();
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.menu = [{
|
||||
icon: faCog,
|
||||
text: this.$t('timeline'),
|
||||
action: this.setType
|
||||
}];
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.column.tl == null) {
|
||||
this.setType();
|
||||
} else {
|
||||
this.disabled = !this.$store.state.i.isModerator && !this.$store.state.i.isAdmin && (
|
||||
this.$store.state.instance.meta.disableLocalTimeline && ['local', 'social'].includes(this.column.tl) ||
|
||||
this.$store.state.instance.meta.disableGlobalTimeline && ['global'].includes(this.column.tl));
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async setType() {
|
||||
const { canceled, result: src } = await this.$root.dialog({
|
||||
title: this.$t('timeline'),
|
||||
type: null,
|
||||
select: {
|
||||
items: [{
|
||||
value: 'home', text: this.$t('_timelines.home')
|
||||
}, {
|
||||
value: 'local', text: this.$t('_timelines.local')
|
||||
}, {
|
||||
value: 'social', text: this.$t('_timelines.social')
|
||||
}, {
|
||||
value: 'global', text: this.$t('_timelines.global')
|
||||
}]
|
||||
},
|
||||
});
|
||||
if (canceled) {
|
||||
if (this.column.tl == null) {
|
||||
this.$store.commit('deviceUser/removeDeckColumn', this.column.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Vue.set(this.column, 'tl', src);
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
},
|
||||
|
||||
queueUpdated(q) {
|
||||
if (this.columnActive) {
|
||||
this.indicated = q !== 0;
|
||||
}
|
||||
},
|
||||
|
||||
onNote() {
|
||||
if (!this.columnActive) {
|
||||
this.indicated = true;
|
||||
}
|
||||
},
|
||||
|
||||
onChangeActiveState(state) {
|
||||
this.columnActive = state;
|
||||
|
||||
if (this.columnActive) {
|
||||
this.indicated = false;
|
||||
}
|
||||
},
|
||||
|
||||
focus() {
|
||||
(this.$refs.timeline as any).focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iwaalbte {
|
||||
text-align: center;
|
||||
|
||||
> p {
|
||||
margin: 16px;
|
||||
|
||||
&.desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
160
src/client/components/deck/widgets-column.vue
Normal file
160
src/client/components/deck/widgets-column.vue
Normal file
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<x-column :menu="menu" :naked="true" :column="column" :is-stacked="isStacked">
|
||||
<template #header><fa :icon="faWindowMaximize" style="margin-right: 8px;"/>{{ column.name }}</template>
|
||||
|
||||
<div class="wtdtxvec">
|
||||
<template v-if="edit">
|
||||
<header>
|
||||
<mk-select v-model="widgetAdderSelected" style="margin-bottom: var(--margin)">
|
||||
<template #label>{{ $t('selectWidget') }}</template>
|
||||
<option v-for="widget in widgets" :value="widget" :key="widget">{{ $t(`_widgets.${widget}`) }}</option>
|
||||
</mk-select>
|
||||
<mk-button inline @click="addWidget" primary><fa :icon="faPlus"/> {{ $t('add') }}</mk-button>
|
||||
<mk-button inline @click="edit = false">{{ $t('close') }}</mk-button>
|
||||
</header>
|
||||
<x-draggable
|
||||
:list="column.widgets"
|
||||
animation="150"
|
||||
@sort="onWidgetSort"
|
||||
>
|
||||
<div v-for="widget in column.widgets" class="customize-container" :key="widget.id" @click="widgetFunc(widget.id)">
|
||||
<button class="remove _button" @click.prevent.stop="removeWidget(widget)"><fa :icon="faTimes"/></button>
|
||||
<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" :column="column"/>
|
||||
</div>
|
||||
</x-draggable>
|
||||
</template>
|
||||
<component v-else class="widget" v-for="widget in column.widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :column="column"/>
|
||||
</div>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as XDraggable from 'vuedraggable';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { faWindowMaximize, faTimes, faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import MkSelect from '../../components/ui/select.vue';
|
||||
import MkButton from '../../components/ui/button.vue';
|
||||
import XColumn from './column.vue';
|
||||
import { widgets } from '../../widgets';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XDraggable,
|
||||
MkSelect,
|
||||
MkButton,
|
||||
},
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
edit: false,
|
||||
menu: null,
|
||||
widgetAdderSelected: null,
|
||||
widgets,
|
||||
faWindowMaximize, faTimes, faPlus
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.menu = [{
|
||||
icon: faCog,
|
||||
text: this.$t('edit'),
|
||||
action: () => {
|
||||
this.edit = !this.edit;
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
methods: {
|
||||
widgetFunc(id) {
|
||||
this.$refs[id][0].setting();
|
||||
},
|
||||
|
||||
onWidgetSort() {
|
||||
this.saveWidgets();
|
||||
},
|
||||
|
||||
addWidget() {
|
||||
if (this.widgetAdderSelected == null) return;
|
||||
|
||||
this.$store.commit('deviceUser/addDeckWidget', {
|
||||
id: this.column.id,
|
||||
widget: {
|
||||
name: this.widgetAdderSelected,
|
||||
id: uuid(),
|
||||
data: {}
|
||||
}
|
||||
});
|
||||
|
||||
this.widgetAdderSelected = null;
|
||||
},
|
||||
|
||||
removeWidget(widget) {
|
||||
this.$store.commit('deviceUser/removeDeckWidget', {
|
||||
id: this.column.id,
|
||||
widget
|
||||
});
|
||||
},
|
||||
|
||||
saveWidgets() {
|
||||
this.$store.commit('deviceUser/updateDeckColumn', this.column);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wtdtxvec {
|
||||
padding-top: 1px; // ウィジェットのbox-shadowを利用した1px borderを隠さないようにするため
|
||||
|
||||
> header {
|
||||
padding: 16px;
|
||||
|
||||
> * {
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
> .widget, .customize-container {
|
||||
margin: 8px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.customize-container {
|
||||
position: relative;
|
||||
cursor: move;
|
||||
|
||||
> *:not(.remove) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
> .remove {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: #fff;
|
||||
background: rgba(#000, 0.7);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mk-dialog" :class="{ iconOnly }">
|
||||
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
|
||||
<div class="bg" ref="bg" @click="onBgClick" v-if="show"></div>
|
||||
<div class="bg _modalBg" ref="bg" @click="onBgClick" v-if="show"></div>
|
||||
</transition>
|
||||
<transition :name="$store.state.device.animation ? 'dialog' : ''" appear @after-leave="() => { destroyDom(); }">
|
||||
<div class="main" ref="main" v-if="show">
|
||||
@ -57,11 +57,8 @@ import MkInput from './ui/input.vue';
|
||||
import MkSelect from './ui/select.vue';
|
||||
import MkSignin from './signin.vue';
|
||||
import parseAcct from '../../misc/acct/parse';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
MkButton,
|
||||
MkInput,
|
||||
@ -248,16 +245,6 @@ export default Vue.extend({
|
||||
width: initial;
|
||||
}
|
||||
|
||||
> .bg {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
> .main {
|
||||
display: block;
|
||||
position: fixed;
|
||||
|
@ -1,36 +1,15 @@
|
||||
<template>
|
||||
<div class="zdjebgpv" :class="{ detail }" ref="thumbnail" :style="`background-color: ${ background }`">
|
||||
<img
|
||||
:src="file.url"
|
||||
:alt="file.name"
|
||||
:title="file.name"
|
||||
@load="onThumbnailLoaded"
|
||||
v-if="detail && is === 'image'"/>
|
||||
<video
|
||||
:src="file.url"
|
||||
ref="volumectrl"
|
||||
preload="metadata"
|
||||
controls
|
||||
v-else-if="detail && is === 'video'"/>
|
||||
<img :src="file.thumbnailUrl" @load="onThumbnailLoaded" :style="`object-fit: ${ fit }`" v-else-if="isThumbnailAvailable"/>
|
||||
<div class="zdjebgpv" ref="thumbnail">
|
||||
<img-with-blurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :style="`object-fit: ${ fit }`"/>
|
||||
<fa :icon="faFileImage" class="icon" v-else-if="is === 'image'"/>
|
||||
<fa :icon="faFileVideo" class="icon" v-else-if="is === 'video'"/>
|
||||
|
||||
<audio
|
||||
:src="file.url"
|
||||
ref="volumectrl"
|
||||
preload="metadata"
|
||||
controls
|
||||
v-else-if="detail && is === 'audio'"/>
|
||||
<fa :icon="faMusic" class="icon" v-else-if="is === 'audio' || is === 'midi'"/>
|
||||
|
||||
<fa :icon="faFileCsv" class="icon" v-else-if="is === 'csv'"/>
|
||||
<fa :icon="faFilePdf" class="icon" v-else-if="is === 'pdf'"/>
|
||||
<fa :icon="faFileAlt" class="icon" v-else-if="is === 'textfile'"/>
|
||||
<fa :icon="faFileArchive" class="icon" v-else-if="is === 'archive'"/>
|
||||
<fa :icon="faFile" class="icon" v-else/>
|
||||
|
||||
<fa :icon="faFilm" class="icon-sub" v-if="!detail && isThumbnailAvailable && is === 'video'"/>
|
||||
<fa :icon="faFilm" class="icon-sub" v-if="isThumbnailAvailable && is === 'video'"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -47,8 +26,12 @@ import {
|
||||
faFileArchive,
|
||||
faFilm
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import ImgWithBlurhash from './img-with-blurhash.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
ImgWithBlurhash
|
||||
},
|
||||
props: {
|
||||
file: {
|
||||
type: Object,
|
||||
@ -59,11 +42,6 @@ export default Vue.extend({
|
||||
required: false,
|
||||
default: 'cover'
|
||||
},
|
||||
detail: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -108,20 +86,12 @@ export default Vue.extend({
|
||||
? (this.is === 'image' || this.is === 'video')
|
||||
: false;
|
||||
},
|
||||
background(): string {
|
||||
return this.file.properties.avgColor || 'transparent';
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
|
||||
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
|
||||
},
|
||||
methods: {
|
||||
onThumbnailLoaded() {
|
||||
if (this.file.properties.avgColor) {
|
||||
this.$refs.thumbnail.style.backgroundColor = 'transparent';
|
||||
}
|
||||
},
|
||||
volumechange() {
|
||||
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
|
||||
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
|
||||
@ -132,14 +102,8 @@ export default Vue.extend({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zdjebgpv {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
> img,
|
||||
> .icon {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
> .icon-sub {
|
||||
position: absolute;
|
||||
width: 30%;
|
||||
@ -153,37 +117,10 @@ export default Vue.extend({
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&:not(.detail) {
|
||||
> img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
height: 65%;
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
> video,
|
||||
> audio {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.detail {
|
||||
> .icon {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
> *:not(.icon) {
|
||||
max-height: 300px;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
> .icon {
|
||||
pointer-events: none;
|
||||
height: 65%;
|
||||
width: 65%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -12,13 +12,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import XDrive from './drive.vue';
|
||||
import XWindow from './window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XDrive,
|
||||
XWindow,
|
||||
|
@ -32,7 +32,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import copyToClipboard from '../scripts/copy-to-clipboard';
|
||||
//import updateAvatar from '../api/update-avatar';
|
||||
//import updateBanner from '../api/update-banner';
|
||||
@ -40,8 +39,6 @@ import XFileThumbnail from './drive-file-thumbnail.vue';
|
||||
import { faDownload, faLink, faICursor, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
@ -129,17 +126,6 @@ export default Vue.extend({
|
||||
this.browser.isDragSource = false;
|
||||
},
|
||||
|
||||
onThumbnailLoaded() {
|
||||
if (this.file.properties.avgColor) {
|
||||
anime({
|
||||
targets: this.$refs.thumbnail,
|
||||
backgroundColor: 'transparent', // TODO fade
|
||||
duration: 100,
|
||||
easing: 'linear'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
rename() {
|
||||
this.$root.dialog({
|
||||
title: this.$t('renameFile'),
|
||||
@ -335,7 +321,6 @@ export default Vue.extend({
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin: auto;
|
||||
color: var(--driveFileIcon);
|
||||
}
|
||||
|
||||
> .name {
|
||||
|
@ -28,11 +28,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faFolder, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
props: {
|
||||
folder: {
|
||||
type: Object,
|
||||
|
@ -15,11 +15,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCloud } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
props: {
|
||||
folder: {
|
||||
type: Object,
|
||||
|
@ -19,17 +19,17 @@
|
||||
@drop.prevent.stop="onDrop"
|
||||
>
|
||||
<div class="contents" ref="contents">
|
||||
<div class="folders" ref="foldersContainer" v-if="folders.length > 0">
|
||||
<div class="folders" ref="foldersContainer" v-show="folders.length > 0">
|
||||
<x-folder v-for="f in folders" :key="f.id" class="folder" :folder="f" :select-mode="select === 'folder'" :is-selected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<mk-button v-if="moreFolders">{{ $t('loadMore') }}</mk-button>
|
||||
<mk-button ref="moreFolders" v-if="moreFolders">{{ $t('loadMore') }}</mk-button>
|
||||
</div>
|
||||
<div class="files" ref="filesContainer" v-if="files.length > 0">
|
||||
<div class="files" ref="filesContainer" v-show="files.length > 0">
|
||||
<x-file v-for="file in files" :key="file.id" class="file" :file="file" :select-mode="select === 'file'" :is-selected="selectedFiles.some(x => x.id === file.id)" @chosen="chooseFile"/>
|
||||
<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
|
||||
<div class="padding" v-for="(n, i) in 16" :key="i"></div>
|
||||
<mk-button v-if="moreFiles" @click="fetchMoreFiles">{{ $t('loadMore') }}</mk-button>
|
||||
<mk-button ref="loadMoreFiles" @click="fetchMoreFiles" v-show="moreFiles">{{ $t('loadMore') }}</mk-button>
|
||||
</div>
|
||||
<div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching">
|
||||
<p v-if="draghover">{{ $t('empty-draghover') }}</p>
|
||||
@ -48,7 +48,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import XNavFolder from './drive.nav-folder.vue';
|
||||
import XFolder from './drive.folder.vue';
|
||||
import XFile from './drive.file.vue';
|
||||
@ -56,8 +55,6 @@ import XUploader from './uploader.vue';
|
||||
import MkButton from './ui/button.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XNavFolder,
|
||||
XFolder,
|
||||
@ -119,6 +116,13 @@ export default Vue.extend({
|
||||
|
||||
fetching: true,
|
||||
|
||||
ilFilesObserver: new IntersectionObserver(
|
||||
(entries) => entries.some((entry) => entry.isIntersecting)
|
||||
&& !this.fetching && this.moreFiles &&
|
||||
this.fetchMoreFiles()
|
||||
),
|
||||
moreFilesElement: null as Element,
|
||||
|
||||
faAngleRight
|
||||
};
|
||||
},
|
||||
@ -130,6 +134,12 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.$store.state.device.enableInfiniteScroll && this.$refs.loadMoreFiles) {
|
||||
this.$nextTick(() => {
|
||||
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
|
||||
});
|
||||
}
|
||||
|
||||
this.connection = this.$root.stream.useSharedConnection('drive');
|
||||
|
||||
this.connection.on('fileCreated', this.onStreamDriveFileCreated);
|
||||
@ -146,8 +156,17 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
activated() {
|
||||
if (this.$store.state.device.enableInfiniteScroll) {
|
||||
this.$nextTick(() => {
|
||||
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
this.ilFilesObserver.disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -64,17 +64,14 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import { emojilist } from '../../misc/emojilist';
|
||||
import { getStaticImageUrl } from '../scripts/get-static-image-url';
|
||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
||||
import { groupByX } from '../../prelude/array';
|
||||
import XPopup from './popup.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XPopup,
|
||||
},
|
||||
@ -95,9 +92,13 @@ export default Vue.extend({
|
||||
icon: faAsterisk,
|
||||
isActive: true
|
||||
}, {
|
||||
name: 'people',
|
||||
name: 'face',
|
||||
icon: faLaugh,
|
||||
isActive: false
|
||||
}, {
|
||||
name: 'people',
|
||||
icon: faUser,
|
||||
isActive: false
|
||||
}, {
|
||||
name: 'animals_and_nature',
|
||||
icon: faLeaf,
|
||||
|
@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<div class="mjndxjcg _panel">
|
||||
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
||||
<p><fa :icon="faExclamationTriangle"/> {{ $t('error') }}</p>
|
||||
<mk-button @click="() => $emit('retry')" class="button">{{ $t('retry') }}</mk-button>
|
||||
</div>
|
||||
<transition :name="$store.state.device.animation ? 'zoom' : ''" appear>
|
||||
<div class="mjndxjcg _panel">
|
||||
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
||||
<p><fa :icon="faExclamationTriangle"/> {{ $t('error') }}</p>
|
||||
<mk-button @click="() => $emit('retry')" class="button">{{ $t('retry') }}</mk-button>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import MkButton from './ui/button.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
MkButton,
|
||||
},
|
||||
@ -40,7 +40,7 @@ export default Vue.extend({
|
||||
|
||||
> img {
|
||||
vertical-align: bottom;
|
||||
height: 150px;
|
||||
height: 128px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
@ -30,12 +30,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import { faSpinner, faPlus, faMinus, faHourglassHalf } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
|
71
src/client/components/form-window.vue
Normal file
71
src/client/components/form-window.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<x-window ref="window" :width="400" :height="450" :no-padding="true" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="false" @ok="ok()" :can-close="false">
|
||||
<template #header>
|
||||
{{ title }}
|
||||
</template>
|
||||
<div class="xkpnjxcv">
|
||||
<label v-for="item in Object.keys(form).filter(item => !form[item].hidden)" :key="item">
|
||||
<mk-input v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1"><span v-text="form[item].label || item"></span></mk-input>
|
||||
<mk-input v-else-if="form[item].type === 'string' && !item.multiline" v-model="values[item]" type="text"><span v-text="form[item].label || item"></span></mk-input>
|
||||
<mk-textarea v-else-if="form[item].type === 'string' && item.multiline" v-model="values[item]"><span v-text="form[item].label || item"></span></mk-textarea>
|
||||
<mk-switch v-else-if="form[item].type === 'boolean'" v-model="values[item]"><span v-text="form[item].label || item"></span></mk-switch>
|
||||
</label>
|
||||
</div>
|
||||
</x-window>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XWindow from './window.vue';
|
||||
import MkInput from './ui/input.vue';
|
||||
import MkTextarea from './ui/textarea.vue';
|
||||
import MkSwitch from './ui/switch.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XWindow,
|
||||
MkInput,
|
||||
MkTextarea,
|
||||
MkSwitch,
|
||||
},
|
||||
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
values: {}
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
for (const item in this.form) {
|
||||
Vue.set(this.values, item, this.form[item].default || null);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
ok() {
|
||||
this.$emit('ok', this.values);
|
||||
this.$refs.window.close();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.xkpnjxcv {
|
||||
> label {
|
||||
display: block;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -8,10 +8,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faSearch } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: ['q'],
|
||||
data() {
|
||||
return {
|
||||
@ -46,10 +44,12 @@ export default Vue.extend({
|
||||
font-size: 16px;
|
||||
border: solid 1px var(--divider);
|
||||
border-radius: 4px 0 0 4px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
> button {
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
border: solid 1px var(--divider);
|
||||
border-left: none;
|
||||
|
@ -6,12 +6,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import XModal from './modal.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XModal,
|
||||
},
|
||||
|
78
src/client/components/img-with-blurhash.vue
Normal file
78
src/client/components/img-with-blurhash.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="xubzgfgb" :title="title">
|
||||
<canvas ref="canvas" :width="size" :height="size" :title="title" v-if="!loaded"/>
|
||||
<img v-if="src" :src="src" :title="title" :alt="alt" @load="onLoad"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { decode } from 'blurhash';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
hash: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
alt: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 64
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.draw();
|
||||
},
|
||||
|
||||
methods: {
|
||||
draw() {
|
||||
const pixels = decode(this.hash, this.size, this.size);
|
||||
const ctx = (this.$refs.canvas as HTMLCanvasElement).getContext('2d');
|
||||
const imageData = ctx!.createImageData(this.size, this.size);
|
||||
imageData.data.set(pixels);
|
||||
ctx!.putImageData(imageData, 0, 0);
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.xubzgfgb {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
> canvas,
|
||||
> img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -125,7 +125,6 @@
|
||||
import Vue from 'vue';
|
||||
import { faChartBar, faUser, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import Chart from 'chart.js';
|
||||
import i18n from '../i18n';
|
||||
import MkSelect from './ui/select.vue';
|
||||
|
||||
const chartLimit = 90;
|
||||
@ -140,8 +139,6 @@ const alpha = (hex, a) => {
|
||||
};
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
MkSelect
|
||||
},
|
||||
|
@ -62,13 +62,13 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
onMouseover() {
|
||||
if (isDeviceTouch()) return;
|
||||
if (isDeviceTouch) return;
|
||||
clearTimeout(this.showTimer);
|
||||
clearTimeout(this.hideTimer);
|
||||
this.showTimer = setTimeout(this.showPreview, 500);
|
||||
},
|
||||
onMouseleave() {
|
||||
if (isDeviceTouch()) return;
|
||||
if (isDeviceTouch) return;
|
||||
clearTimeout(this.showTimer);
|
||||
clearTimeout(this.hideTimer);
|
||||
this.hideTimer = setTimeout(this.closePreview, 500);
|
||||
|
@ -28,10 +28,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
media: {
|
||||
type: Object,
|
||||
|
@ -1,19 +1,22 @@
|
||||
<template>
|
||||
<div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="hide" @click="hide = false">
|
||||
<div>
|
||||
<b><fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('clickToShow') }}</span>
|
||||
<div class="qjewsnkg" v-if="hide" @click="hide = false">
|
||||
<img-with-blurhash class="bg" :hash="image.blurhash" :title="image.name"/>
|
||||
<div class="text">
|
||||
<div>
|
||||
<b><fa :icon="faExclamationTriangle"/> {{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('clickToShow') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gqnyydlzavusgskkfvwvjiattxdzsqlf" v-else>
|
||||
<div class="gqnyydlz" v-else>
|
||||
<i><fa :icon="faEyeSlash" @click="hide = true"/></i>
|
||||
<a
|
||||
:href="image.url"
|
||||
:style="style"
|
||||
:title="image.name"
|
||||
@click.prevent="onClick"
|
||||
>
|
||||
<div v-if="image.type === 'image/gif'">GIF</div>
|
||||
<img-with-blurhash :hash="image.blurhash" :src="url" :alt="image.name" :title="image.name"/>
|
||||
<div class="gif" v-if="image.type === 'image/gif'">GIF</div>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
@ -21,12 +24,14 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import { getStaticImageUrl } from '../scripts/get-static-image-url';
|
||||
import ImageViewer from './image-viewer.vue';
|
||||
import ImgWithBlurhash from './img-with-blurhash.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
ImgWithBlurhash
|
||||
},
|
||||
props: {
|
||||
image: {
|
||||
type: Object,
|
||||
@ -44,23 +49,18 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
style(): any {
|
||||
let url = `url(${
|
||||
this.$store.state.device.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(this.image.thumbnailUrl)
|
||||
: this.image.thumbnailUrl
|
||||
})`;
|
||||
url(): any {
|
||||
let url = this.$store.state.device.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(this.image.thumbnailUrl)
|
||||
: this.image.thumbnailUrl;
|
||||
|
||||
if (this.$store.state.device.loadRemoteMedia) {
|
||||
url = null;
|
||||
} else if (this.raw || this.$store.state.device.loadRawImages) {
|
||||
url = `url(${this.image.url})`;
|
||||
url = this.image.url;
|
||||
}
|
||||
|
||||
return {
|
||||
'background-color': this.image.properties.avgColor || 'transparent',
|
||||
'background-image': url
|
||||
};
|
||||
return url;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -84,7 +84,38 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gqnyydlzavusgskkfvwvjiattxdzsqlf {
|
||||
.qjewsnkg {
|
||||
position: relative;
|
||||
|
||||
> .bg {
|
||||
filter: brightness(0.5);
|
||||
}
|
||||
|
||||
> .text {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
color: #fff;
|
||||
|
||||
> * {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gqnyydlz {
|
||||
position: relative;
|
||||
|
||||
> i {
|
||||
@ -112,7 +143,7 @@ export default Vue.extend({
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
> div {
|
||||
> .gif {
|
||||
background-color: var(--fg);
|
||||
border-radius: 6px;
|
||||
color: var(--accentLighten);
|
||||
@ -128,22 +159,4 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qjewsnkgzzxlxtzncydssfbgjibiehcy {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
|
||||
> div {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
|
||||
> * {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -114,7 +114,7 @@ export default Vue.extend({
|
||||
|
||||
> * {
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&[data-count="1"] {
|
||||
|
@ -23,10 +23,8 @@
|
||||
import Vue from 'vue';
|
||||
import { faPlayCircle } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
video: {
|
||||
type: Object,
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<router-link class="ldlomzub" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
|
||||
<router-link class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
|
||||
<span class="me" v-if="isMe">{{ $t('you') }}</span>
|
||||
<span class="main">
|
||||
<span class="username">@{{ username }}</span>
|
||||
@ -16,12 +16,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import { toUnicode } from 'punycode';
|
||||
import { host as localHost } from '../config';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
username: {
|
||||
type: String,
|
||||
@ -65,6 +63,10 @@ export default Vue.extend({
|
||||
<style lang="scss" scoped>
|
||||
.ldlomzub {
|
||||
color: var(--mention);
|
||||
|
||||
&.isMe {
|
||||
color: var(--mentionMe);
|
||||
}
|
||||
|
||||
> .me {
|
||||
pointer-events: none;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Vue, { VNode } from 'vue';
|
||||
import { MfmForest } from '../../mfm/types';
|
||||
import { MfmForest } from '../../mfm/prelude';
|
||||
import { parse, parsePlain } from '../../mfm/parse';
|
||||
import MkUrl from './url.vue';
|
||||
import MkLink from './link.vue';
|
||||
@ -53,11 +53,11 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
|
||||
if (!this.plain) {
|
||||
const x = text.split('\n')
|
||||
.map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]);
|
||||
.map(t => t == '' ? [createElement('br')] : [this._v(t), createElement('br')]); // NOTE: this._vはHACK SEE: https://github.com/syuilo/misskey/pull/6399#issuecomment-632820283
|
||||
x[x.length - 1].pop();
|
||||
return x;
|
||||
} else {
|
||||
return [createElement('span', text.replace(/\n/g, ' '))];
|
||||
return [this._v(text.replace(/\n/g, ' '))];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="mk-modal" v-hotkey.global="keymap">
|
||||
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
|
||||
<div class="bg" ref="bg" v-if="show" @click="close()"></div>
|
||||
<div class="bg _modalBg" ref="bg" v-if="show" @click="canClose ? close() : () => {}"></div>
|
||||
</transition>
|
||||
<transition :name="$store.state.device.animation ? 'modal' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }">
|
||||
<div class="content" ref="content" v-if="show" @click.self="close()"><slot></slot></div>
|
||||
<div class="content" ref="content" v-if="show" @click.self="canClose ? close() : () => {}"><slot></slot></div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
@ -14,6 +14,11 @@ import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
canClose: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -55,13 +60,7 @@ export default Vue.extend({
|
||||
|
||||
.mk-modal {
|
||||
> .bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--modalBg)
|
||||
}
|
||||
|
||||
> .content {
|
||||
|
@ -12,18 +12,19 @@
|
||||
<router-link class="created-at" :to="note | notePage">
|
||||
<mk-time :time="note.createdAt"/>
|
||||
</router-link>
|
||||
<span class="visibility" v-if="note.visibility != 'public'">
|
||||
<fa v-if="note.visibility == 'home'" :icon="faHome"/>
|
||||
<fa v-if="note.visibility == 'followers'" :icon="faUnlock"/>
|
||||
<fa v-if="note.visibility == 'specified'" :icon="faEnvelope"/>
|
||||
<span class="visibility" v-if="note.visibility !== 'public'">
|
||||
<fa v-if="note.visibility === 'home'" :icon="faHome"/>
|
||||
<fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
|
||||
<fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
|
||||
</span>
|
||||
<span class="localOnly" v-if="note.localOnly"><fa :icon="faBiohazard"/></span>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, faBiohazard } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
@ -36,7 +37,7 @@ export default Vue.extend({
|
||||
|
||||
data() {
|
||||
return {
|
||||
faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, farBookmark
|
||||
faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, farBookmark, faBiohazard
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -53,7 +54,6 @@ export default Vue.extend({
|
||||
margin: 0 .5em 0 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
color: var(--noteHeaderName);
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
@ -97,6 +97,10 @@ export default Vue.extend({
|
||||
> .visibility {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
> .localOnly {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -50,15 +50,7 @@ export default Vue.extend({
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
font-size: 10px;
|
||||
|
||||
@media (min-width: 350px) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
font-size: 0.95em;
|
||||
|
||||
> .avatar {
|
||||
|
||||
|
@ -21,35 +21,39 @@
|
||||
</router-link>
|
||||
</i18n>
|
||||
<div class="info">
|
||||
<button class="_button time" @click="showRenoteMenu()" ref="renoteTime"><mk-time :time="note.createdAt"/></button>
|
||||
<button class="_button time" @click="showRenoteMenu()" ref="renoteTime">
|
||||
<fa class="dropdownIcon" v-if="isMyRenote" :icon="faEllipsisH"/>
|
||||
<mk-time :time="note.createdAt"/>
|
||||
</button>
|
||||
<span class="visibility" v-if="note.visibility !== 'public'">
|
||||
<fa v-if="note.visibility === 'home'" :icon="faHome"/>
|
||||
<fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
|
||||
<fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
|
||||
</span>
|
||||
<span class="localOnly" v-if="note.localOnly"><fa :icon="faBiohazard"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<article class="article">
|
||||
<mk-avatar class="avatar" :user="appearNote.user"/>
|
||||
<mk-avatar class="avatar" :user="appearNote.user" v-once/>
|
||||
<div class="main">
|
||||
<x-note-header class="header" :note="appearNote" :mini="true"/>
|
||||
<div class="body" v-if="appearNote.deletedAt == null" ref="noteBody">
|
||||
<p v-if="appearNote.cw != null" class="cw">
|
||||
<mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" />
|
||||
<mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" v-once/>
|
||||
<x-cw-button v-model="showContent" :note="appearNote"/>
|
||||
</p>
|
||||
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||
<div class="text">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
||||
<router-link class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><fa :icon="faReply"/></router-link>
|
||||
<mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
||||
<mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis" v-once/>
|
||||
<a class="rp" v-if="appearNote.renote != null">RN:</a>
|
||||
</div>
|
||||
<div class="files" v-if="appearNote.files.length > 0">
|
||||
<x-media-list :media-list="appearNote.files" :parent-element="noteBody"/>
|
||||
</div>
|
||||
<x-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="true" class="url-preview"/>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="detail" class="url-preview"/>
|
||||
<div class="renote" v-if="appearNote.renote"><x-note-preview :note="appearNote.renote"/></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,11 +89,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
import { parse } from '../../mfm/parse';
|
||||
import { sum, unique } from '../../prelude/array';
|
||||
import i18n from '../i18n';
|
||||
import XSub from './note.sub.vue';
|
||||
import XNoteHeader from './note-header.vue';
|
||||
import XNotePreview from './note-preview.vue';
|
||||
@ -105,8 +108,6 @@ import { url } from '../config';
|
||||
import copyToClipboard from '../scripts/copy-to-clipboard';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XSub,
|
||||
XNoteHeader,
|
||||
@ -143,7 +144,7 @@ export default Vue.extend({
|
||||
showContent: false,
|
||||
hideThisNote: false,
|
||||
noteBody: this.$refs.noteBody,
|
||||
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan
|
||||
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug
|
||||
};
|
||||
},
|
||||
|
||||
@ -193,6 +194,10 @@ export default Vue.extend({
|
||||
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.appearNote.userId);
|
||||
},
|
||||
|
||||
isMyRenote(): boolean {
|
||||
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.note.userId);
|
||||
},
|
||||
|
||||
canRenote(): boolean {
|
||||
return ['public', 'home'].includes(this.appearNote.visibility) || this.isMyNote;
|
||||
},
|
||||
@ -606,6 +611,16 @@ export default Vue.extend({
|
||||
.filter(x => x !== undefined);
|
||||
}
|
||||
|
||||
if (this.$store.state.noteActions.length > 0) {
|
||||
menu = menu.concat([null, ...this.$store.state.noteActions.map(action => ({
|
||||
icon: faPlug,
|
||||
text: action.title,
|
||||
action: () => {
|
||||
action.handler(this.appearNote);
|
||||
}
|
||||
}))]);
|
||||
}
|
||||
|
||||
this.$root.menu({
|
||||
items: menu,
|
||||
source: this.$refs.menuButton,
|
||||
@ -614,7 +629,7 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
showRenoteMenu(viaKeyboard = false) {
|
||||
if (!this.$store.getters.isSignedIn || (this.$store.state.i.id !== this.note.userId)) return;
|
||||
if (!this.isMyRenote) return;
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
text: this.$t('unrenote'),
|
||||
@ -718,61 +733,6 @@ export default Vue.extend({
|
||||
transition: box-shadow 0.1s ease;
|
||||
overflow: hidden;
|
||||
|
||||
&.max-width_500px {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&.max-width_450px {
|
||||
> .renote {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
||||
> .article {
|
||||
padding: 14px 16px 9px;
|
||||
|
||||
> .avatar {
|
||||
margin: 0 10px 8px 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_350px {
|
||||
> .article {
|
||||
> .main {
|
||||
> .footer {
|
||||
> .button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_300px {
|
||||
font-size: 0.825em;
|
||||
|
||||
> .article {
|
||||
> .avatar {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
> .main {
|
||||
> .footer {
|
||||
> .button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px var(--focus);
|
||||
@ -791,10 +751,6 @@ export default Vue.extend({
|
||||
white-space: pre;
|
||||
color: #d28a3f;
|
||||
|
||||
@media (max-width: 450px) {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
||||
> [data-icon] {
|
||||
margin-right: 4px;
|
||||
}
|
||||
@ -857,14 +813,18 @@ export default Vue.extend({
|
||||
> .time {
|
||||
flex-shrink: 0;
|
||||
color: inherit;
|
||||
|
||||
> .dropdownIcon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
> .visibility {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
[data-icon] {
|
||||
margin-right: 0;
|
||||
}
|
||||
> .localOnly {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -975,5 +935,64 @@ export default Vue.extend({
|
||||
> .reply {
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
&.max-width_500px {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&.max-width_450px {
|
||||
> .renote {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
||||
> .info {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
||||
> .article {
|
||||
padding: 14px 16px 9px;
|
||||
|
||||
> .avatar {
|
||||
margin: 0 10px 8px 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_350px {
|
||||
> .article {
|
||||
> .main {
|
||||
> .footer {
|
||||
> .button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_300px {
|
||||
font-size: 0.825em;
|
||||
|
||||
> .article {
|
||||
> .avatar {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
> .main {
|
||||
> .footer {
|
||||
> .button {
|
||||
&:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="mk-notes" v-size="[{ max: 500 }]">
|
||||
<div class="mk-notes">
|
||||
<div class="_fullinfo" v-if="empty">
|
||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
||||
<div>{{ $t('noNotes') }}</div>
|
||||
@ -7,19 +7,19 @@
|
||||
|
||||
<mk-error v-if="error" @retry="init()"/>
|
||||
|
||||
<div v-if="more && reversed" style="margin-bottom: var(--margin);">
|
||||
<button class="_panel _button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" @click="fetchMore()">
|
||||
<div v-show="more && reversed" style="margin-bottom: var(--margin);">
|
||||
<button class="_panel _button" ref="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<template v-if="moreFetching"><mk-loading inline/></template>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
|
||||
<x-list ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
|
||||
<x-note :note="note" :detail="detail" :key="note._featuredId_ || note._prId_ || note.id"/>
|
||||
</x-list>
|
||||
|
||||
<div v-if="more && !reversed" style="margin-top: var(--margin);">
|
||||
<button class="_panel _button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" @click="fetchMore()">
|
||||
<div v-show="more && !reversed" style="margin-top: var(--margin);">
|
||||
<button class="_panel _button" ref="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<template v-if="moreFetching"><mk-loading inline/></template>
|
||||
</button>
|
||||
@ -29,15 +29,12 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import paging from '../scripts/paging';
|
||||
import XNote from './note.vue';
|
||||
import XList from './date-separated-list.vue';
|
||||
import MkButton from './ui/button.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XNote, XList, MkButton
|
||||
},
|
||||
@ -88,21 +85,3 @@ export default Vue.extend({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mk-notes {
|
||||
> .notes {
|
||||
> ::v-deep *:not(:last-child) {
|
||||
margin-bottom: var(--marginFull);
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_500px {
|
||||
> .notes {
|
||||
> ::v-deep *:not(:last-child) {
|
||||
//margin-bottom: var(--marginHalf);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -61,13 +61,11 @@
|
||||
import Vue from 'vue';
|
||||
import { faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faCheck, faPollH } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faClock } from '@fortawesome/free-regular-svg-icons';
|
||||
import getNoteSummary from '../../misc/get-note-summary';
|
||||
import noteSummary from '../../misc/get-note-summary';
|
||||
import XReactionIcon from './reaction-icon.vue';
|
||||
import MkFollowButton from './follow-button.vue';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
XReactionIcon, MkFollowButton
|
||||
},
|
||||
@ -89,12 +87,39 @@ export default Vue.extend({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
getNoteSummary,
|
||||
getNoteSummary: (text: string) => noteSummary(text, this.$root.i18n.messages[this.$root.i18n.locale]),
|
||||
followRequestDone: false,
|
||||
groupInviteDone: false,
|
||||
connection: null,
|
||||
readObserver: null,
|
||||
faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faClock, faCheck, faPollH
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.notification.isRead) {
|
||||
this.readObserver = new IntersectionObserver((entries, observer) => {
|
||||
if (!entries.some(entry => entry.isIntersecting)) return;
|
||||
this.$root.stream.send('readNotification', {
|
||||
id: this.notification.id
|
||||
});
|
||||
entries.map(({ target }) => observer.unobserve(target));
|
||||
});
|
||||
|
||||
this.readObserver.observe(this.$el);
|
||||
|
||||
this.connection = this.$root.stream.useSharedConnection('main');
|
||||
this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el));
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (!this.notification.isRead) {
|
||||
this.readObserver.unobserve(this.$el);
|
||||
this.connection.dispose();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
acceptFollowRequest() {
|
||||
this.followRequestDone = true;
|
||||
|
@ -5,7 +5,7 @@
|
||||
<x-notification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
|
||||
</x-list>
|
||||
|
||||
<button class="_panel _button" v-if="more" @click="fetchMore" :disabled="moreFetching">
|
||||
<button class="_panel _button" ref="loadMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||
<template v-if="moreFetching"><mk-loading inline/></template>
|
||||
</button>
|
||||
@ -18,15 +18,12 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import paging from '../scripts/paging';
|
||||
import XNotification from './notification.vue';
|
||||
import XList from './date-separated-list.vue';
|
||||
import XNote from './note.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XNotification,
|
||||
XList,
|
||||
@ -74,10 +71,13 @@ export default Vue.extend({
|
||||
|
||||
methods: {
|
||||
onNotification(notification) {
|
||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||
this.$root.stream.send('readNotification', {
|
||||
id: notification.id
|
||||
});
|
||||
if (document.visibilityState === 'visible') {
|
||||
this.$root.stream.send('readNotification', {
|
||||
id: notification.id
|
||||
});
|
||||
|
||||
notification.isRead = true;
|
||||
}
|
||||
|
||||
this.prepend(notification);
|
||||
},
|
||||
@ -87,13 +87,6 @@ export default Vue.extend({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mfcuwfyp {
|
||||
> .notifications {
|
||||
> ::v-deep * {
|
||||
//margin-bottom: var(--margin);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .empty {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
|
@ -8,13 +8,11 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../../i18n';
|
||||
import MkTextarea from '../ui/textarea.vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import { apiUrl } from '../../config';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
MkTextarea,
|
||||
MkButton,
|
||||
|
@ -9,14 +9,11 @@ import Vue from 'vue';
|
||||
import { parse } from '@syuilo/aiscript';
|
||||
import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHeart } from '@fortawesome/free-regular-svg-icons';
|
||||
import i18n from '../../i18n';
|
||||
import XBlock from './page.block.vue';
|
||||
import { Hpml } from '../../scripts/hpml/evaluator';
|
||||
import { url } from '../../config';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XBlock
|
||||
},
|
||||
|
@ -51,7 +51,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faExclamationTriangle, faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import { erase } from '../../prelude/array';
|
||||
import { addTime } from '../../prelude/time';
|
||||
import { formatDateTimeString } from '../../misc/format-time-string';
|
||||
@ -61,7 +60,6 @@ import MkSwitch from './ui/switch.vue';
|
||||
import MkButton from './ui/button.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
MkInput,
|
||||
MkSelect,
|
||||
|
@ -24,11 +24,9 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
import { sum } from '../../prelude/array';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
@ -54,9 +52,9 @@ export default Vue.extend({
|
||||
},
|
||||
timer(): string {
|
||||
return this.$t(
|
||||
this.remaining > 86400 ? '_poll.remainingDays' :
|
||||
this.remaining > 3600 ? '_poll.remainingHours' :
|
||||
this.remaining > 60 ? '_poll.remainingMinutes' : '_poll.remainingSeconds', {
|
||||
this.remaining >= 86400 ? '_poll.remainingDays' :
|
||||
this.remaining >= 3600 ? '_poll.remainingHours' :
|
||||
this.remaining >= 60 ? '_poll.remainingMinutes' : '_poll.remainingSeconds', {
|
||||
s: Math.floor(this.remaining % 60),
|
||||
m: Math.floor(this.remaining / 60) % 60,
|
||||
h: Math.floor(this.remaining / 3600) % 24,
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mk-popup" v-hotkey.global="keymap">
|
||||
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
|
||||
<div class="bg" ref="bg" @click="close()" v-if="show"></div>
|
||||
<div class="bg _modalBg" ref="bg" @click="close()" v-if="show"></div>
|
||||
</transition>
|
||||
<transition :name="$store.state.device.animation ? 'popup' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }">
|
||||
<div class="content" :class="{ fixed }" ref="content" v-if="show" :style="{ width: width ? width + 'px' : 'auto' }"><slot></slot></div>
|
||||
@ -128,13 +128,7 @@ export default Vue.extend({
|
||||
|
||||
.mk-popup {
|
||||
> .bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--modalBg)
|
||||
}
|
||||
|
||||
> .content {
|
||||
|
@ -14,15 +14,12 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import * as XDraggable from 'vuedraggable';
|
||||
import { faTimesCircle, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faExclamationTriangle, faICursor } from '@fortawesome/free-solid-svg-icons';
|
||||
import XFileThumbnail from './drive-file-thumbnail.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XDraggable,
|
||||
XFileThumbnail
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl">
|
||||
<div class="ulveipgl">
|
||||
<transition :name="$store.state.device.animation ? 'form-fade' : ''" appear @after-leave="$emit('closed');">
|
||||
<div class="bg" ref="bg" v-if="show" @click="close()"></div>
|
||||
<div class="bg _modalBg" ref="bg" v-if="show" @click="close()"></div>
|
||||
</transition>
|
||||
<div class="main" ref="main" @click.self="close()" @keydown="onKeydown">
|
||||
<transition :name="$store.state.device.animation ? 'form' : ''" appear
|
||||
@ -119,16 +119,9 @@ export default Vue.extend({
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ulveipglmagnxfgvitaxyszerjwiqmwl {
|
||||
.ulveipgl {
|
||||
> .bg {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(#000, 0.7);
|
||||
}
|
||||
|
||||
> .main {
|
||||
|
@ -8,8 +8,9 @@
|
||||
<header>
|
||||
<button v-if="!fixed" class="cancel _button" @click="cancel"><fa :icon="faTimes"/></button>
|
||||
<div>
|
||||
<span class="local-only" v-if="localOnly" v-text="$t('_visibility.localOnly')" />
|
||||
<span class="text-count" :class="{ over: trimmedLength(text) > max }">{{ max - trimmedLength(text) }}</span>
|
||||
<button class="_button visibility" @click="setVisibility" ref="visibilityButton">
|
||||
<button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$t('visibility')">
|
||||
<span v-if="visibility === 'public'"><fa :icon="faGlobe"/></span>
|
||||
<span v-if="visibility === 'home'"><fa :icon="faHome"/></span>
|
||||
<span v-if="visibility === 'followers'"><fa :icon="faUnlock"/></span>
|
||||
@ -25,7 +26,7 @@
|
||||
<div v-if="visibility === 'specified'" class="to-specified">
|
||||
<span style="margin-right: 8px;">{{ $t('recipient') }}</span>
|
||||
<div class="visibleUsers">
|
||||
<span v-for="u in visibleUsers">
|
||||
<span v-for="u in visibleUsers" :key="u.id">
|
||||
<mk-acct :user="u"/>
|
||||
<button class="_button" @click="removeVisibleUser(u)"><fa :icon="faTimes"/></button>
|
||||
</span>
|
||||
@ -38,12 +39,12 @@
|
||||
<x-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/>
|
||||
<x-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
|
||||
<footer>
|
||||
<button class="_button" @click="chooseFileFrom"><fa :icon="faPhotoVideo"/></button>
|
||||
<button class="_button" @click="poll = !poll" :class="{ active: poll }"><fa :icon="faPollH"/></button>
|
||||
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }"><fa :icon="faEyeSlash"/></button>
|
||||
<button class="_button" @click="insertMention"><fa :icon="faAt"/></button>
|
||||
<button class="_button" @click="insertEmoji"><fa :icon="faLaughSquint"/></button>
|
||||
<button class="_button" v-if="visibility !== 'specified'" @click="localOnly = !localOnly" :class="{ active: localOnly }"><fa :icon="faBiohazard"/></button>
|
||||
<button class="_button" @click="chooseFileFrom" v-tooltip="$t('attachFile')"><fa :icon="faPhotoVideo"/></button>
|
||||
<button class="_button" @click="poll = !poll" :class="{ active: poll }" v-tooltip="$t('poll')"><fa :icon="faPollH"/></button>
|
||||
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><fa :icon="faEyeSlash"/></button>
|
||||
<button class="_button" @click="insertMention" v-tooltip="$t('mention')"><fa :icon="faAt"/></button>
|
||||
<button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><fa :icon="faLaughSquint"/></button>
|
||||
<button class="_button" @click="showActions" v-tooltip="$t('plugin')" v-if="$store.state.postFormActions.length > 0"><fa :icon="faPlug"/></button>
|
||||
</footer>
|
||||
<input ref="file" class="file _button" type="file" multiple="multiple" @change="onChangeFile"/>
|
||||
</div>
|
||||
@ -52,12 +53,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons';
|
||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||
import { length } from 'stringz';
|
||||
import { toASCII } from 'punycode';
|
||||
import i18n from '../i18n';
|
||||
import MkVisibilityChooser from './visibility-chooser.vue';
|
||||
import MkUserSelect from './user-select.vue';
|
||||
import XNotePreview from './note-preview.vue';
|
||||
@ -68,10 +68,9 @@ import extractMentions from '../../misc/extract-mentions';
|
||||
import getAcct from '../../misc/acct/render';
|
||||
import { formatTimeString } from '../../misc/format-time-string';
|
||||
import { selectDriveFile } from '../scripts/select-drive-file';
|
||||
import { noteVisibilities } from '../../types';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XNotePreview,
|
||||
XUploader: () => import('./uploader.vue').then(m => m.default),
|
||||
@ -135,7 +134,7 @@ export default Vue.extend({
|
||||
draghover: false,
|
||||
quoteId: null,
|
||||
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'),
|
||||
faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard
|
||||
faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug
|
||||
};
|
||||
},
|
||||
|
||||
@ -400,15 +399,17 @@ export default Vue.extend({
|
||||
setVisibility() {
|
||||
const w = this.$root.new(MkVisibilityChooser, {
|
||||
source: this.$refs.visibilityButton,
|
||||
currentVisibility: this.visibility
|
||||
currentVisibility: this.visibility,
|
||||
currentLocalOnly: this.localOnly
|
||||
});
|
||||
w.$once('chosen', v => {
|
||||
this.applyVisibility(v);
|
||||
w.$once('chosen', ({ visibility, localOnly }) => {
|
||||
this.applyVisibility(visibility);
|
||||
this.localOnly = localOnly;
|
||||
});
|
||||
},
|
||||
|
||||
applyVisibility(v: string) {
|
||||
this.visibility = ['public', 'home', 'followers', 'specified'].includes(v) ? v : 'public'; // v11互換性のため
|
||||
this.visibility = (noteVisibilities as unknown as string[]).includes(v) ? v : 'public'; // v11互換性のため
|
||||
},
|
||||
|
||||
addVisibleUser() {
|
||||
@ -579,6 +580,22 @@ export default Vue.extend({
|
||||
insertTextAtCursor(this.$refs.text, emoji);
|
||||
vm.close();
|
||||
});
|
||||
},
|
||||
|
||||
showActions(ev) {
|
||||
this.$root.menu({
|
||||
items: this.$store.state.postFormActions.map(action => ({
|
||||
text: action.title,
|
||||
action: () => {
|
||||
action.handler({
|
||||
text: this.text
|
||||
}, (key, value) => {
|
||||
if (key === 'text') { this.text = value; }
|
||||
});
|
||||
}
|
||||
})),
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -626,6 +643,14 @@ export default Vue.extend({
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
margin: 0 8px;
|
||||
|
||||
& + .localOnly {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.local-only {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
> .submit {
|
||||
@ -705,7 +730,7 @@ export default Vue.extend({
|
||||
margin-right: 14px;
|
||||
padding: 8px 0 8px 8px;
|
||||
border-radius: 8px;
|
||||
background: var(--nwjktjjq);
|
||||
background: var(--X4);
|
||||
|
||||
> button {
|
||||
padding: 4px 8px;
|
||||
@ -787,7 +812,7 @@ export default Vue.extend({
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background: var(--geavgsxy);
|
||||
background: var(--X5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
@ -4,9 +4,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
reaction: {
|
||||
type: String,
|
||||
|
@ -4,21 +4,18 @@
|
||||
<div class="buttons" ref="buttons" :class="{ showFocus }">
|
||||
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="reaction" v-particle><x-reaction-icon :reaction="reaction"/></button>
|
||||
</div>
|
||||
<input class="text" v-model="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||
<input class="text" v-model.trim="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||
</div>
|
||||
</x-popup>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import { emojiRegex } from '../../misc/emoji-regex';
|
||||
import XReactionIcon from './reaction-icon.vue';
|
||||
import XPopup from './popup.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
XPopup,
|
||||
XReactionIcon,
|
||||
|
@ -1,29 +1,29 @@
|
||||
<template>
|
||||
<transition name="zoom-in-top">
|
||||
<div class="buebdbiu" ref="popover" v-if="show">
|
||||
<template v-if="users.length <= 10">
|
||||
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
||||
<mk-avatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/>
|
||||
<mk-user-name :user="u" :nowrap="false" style="line-height: 24px;"/>
|
||||
</b>
|
||||
</template>
|
||||
<template v-if="10 < users.length">
|
||||
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
||||
<mk-avatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/>
|
||||
<mk-user-name :user="u" :nowrap="false" style="line-height: 24px;"/>
|
||||
</b>
|
||||
<span slot="omitted">+{{ count - 10 }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</transition>
|
||||
<mk-tooltip :source="source" ref="tooltip">
|
||||
<template v-if="users.length <= 10">
|
||||
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
||||
<mk-avatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/>
|
||||
<mk-user-name :user="u" :nowrap="false" style="line-height: 24px;"/>
|
||||
</b>
|
||||
</template>
|
||||
<template v-if="10 < users.length">
|
||||
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
||||
<mk-avatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/>
|
||||
<mk-user-name :user="u" :nowrap="false" style="line-height: 24px;"/>
|
||||
</b>
|
||||
<span slot="omitted">+{{ count - 10 }}</span>
|
||||
</template>
|
||||
</mk-tooltip>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import MkTooltip from './ui/tooltip.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
components: {
|
||||
MkTooltip
|
||||
},
|
||||
props: {
|
||||
reaction: {
|
||||
type: String,
|
||||
@ -41,77 +41,11 @@ export default Vue.extend({
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.show = true;
|
||||
|
||||
this.$nextTick(() => {
|
||||
const popover = this.$refs.popover as any;
|
||||
|
||||
if (this.source == null) {
|
||||
this.destroyDom();
|
||||
return;
|
||||
}
|
||||
const rect = this.source.getBoundingClientRect();
|
||||
|
||||
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
||||
const y = rect.top + window.pageYOffset + this.source.offsetHeight;
|
||||
popover.style.left = (x - 28) + 'px';
|
||||
popover.style.top = (y + 16) + 'px';
|
||||
});
|
||||
}
|
||||
methods: {
|
||||
close() {
|
||||
this.show = false;
|
||||
setTimeout(this.destroyDom, 300);
|
||||
this.$refs.tooltip.close();
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.buebdbiu {
|
||||
z-index: 10000;
|
||||
display: block;
|
||||
position: absolute;
|
||||
max-width: 240px;
|
||||
font-size: 0.8em;
|
||||
padding: 6px 8px;
|
||||
background: var(--panel);
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
||||
pointer-events: none;
|
||||
transform-origin: center -16px;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -28px;
|
||||
left: 12px;
|
||||
border-top: solid 14px transparent;
|
||||
border-right: solid 14px transparent;
|
||||
border-bottom: solid 14px rgba(0,0,0,0.1);
|
||||
border-left: solid 14px transparent;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -27px;
|
||||
left: 12px;
|
||||
border-top: solid 14px transparent;
|
||||
border-right: solid 14px transparent;
|
||||
border-bottom: solid 14px var(--panel);
|
||||
border-left: solid 14px transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -4,12 +4,14 @@
|
||||
:class="{ reacted: note.myReaction == reaction, canToggle }"
|
||||
@click="toggleReaction(reaction)"
|
||||
v-if="count > 0"
|
||||
@touchstart="onMouseover"
|
||||
@mouseover="onMouseover"
|
||||
@mouseleave="onMouseleave"
|
||||
@touchend="onMouseleave"
|
||||
ref="reaction"
|
||||
v-particle
|
||||
v-particle="canToggle"
|
||||
>
|
||||
<x-reaction-icon :reaction="reaction" :customEmojis="note.emojis" ref="icon"/>
|
||||
<x-reaction-icon :reaction="reaction" :custom-emojis="note.emojis" ref="icon"/>
|
||||
<span>{{ count }}</span>
|
||||
</button>
|
||||
</template>
|
||||
@ -53,21 +55,20 @@ export default Vue.extend({
|
||||
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId;
|
||||
},
|
||||
canToggle(): boolean {
|
||||
return !this.reaction.match(/@\w/);
|
||||
return !this.reaction.match(/@\w/) && !this.isMe && this.$store.getters.isSignedIn;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (!this.isInitial) this.anime();
|
||||
},
|
||||
watch: {
|
||||
count(newCount, oldCount) {
|
||||
if (oldCount < newCount) this.anime();
|
||||
if (this.details != null) this.openDetails();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (!this.isInitial) this.anime();
|
||||
},
|
||||
methods: {
|
||||
toggleReaction() {
|
||||
if (this.isMe) return;
|
||||
if (!this.canToggle) return;
|
||||
|
||||
const oldReaction = this.note.myReaction;
|
||||
@ -90,16 +91,17 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
onMouseover() {
|
||||
if (this.isHovering) return;
|
||||
this.isHovering = true;
|
||||
this.detailsTimeoutId = setTimeout(this.openDetails, 300);
|
||||
},
|
||||
onMouseleave() {
|
||||
if (!this.isHovering) return;
|
||||
this.isHovering = false;
|
||||
clearTimeout(this.detailsTimeoutId);
|
||||
this.closeDetails();
|
||||
},
|
||||
openDetails() {
|
||||
if (this.$root.isMobile) return;
|
||||
this.$root.api('notes/reactions', {
|
||||
noteId: this.note.id,
|
||||
type: this.reaction,
|
||||
|
@ -5,10 +5,8 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
props: {
|
||||
href: {
|
||||
type: String,
|
||||
|
487
src/client/components/sidebar.vue
Normal file
487
src/client/components/sidebar.vue
Normal file
@ -0,0 +1,487 @@
|
||||
<template>
|
||||
<div class="mvcprjjd">
|
||||
<transition name="nav-back">
|
||||
<div class="nav-back _modalBg"
|
||||
v-if="showing"
|
||||
@click="showing = false"
|
||||
@touchstart="showing = false"
|
||||
></div>
|
||||
</transition>
|
||||
|
||||
<transition name="nav">
|
||||
<nav class="nav" v-show="showing">
|
||||
<div>
|
||||
<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
|
||||
<mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/>
|
||||
</button>
|
||||
<button class="item _button index active" @click="top()" v-if="$route.name === 'index'">
|
||||
<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
||||
</button>
|
||||
<router-link class="item index" active-class="active" to="/" exact v-else>
|
||||
<fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
||||
</router-link>
|
||||
<template v-for="item in menu">
|
||||
<div v-if="item === '-'" class="divider"></div>
|
||||
<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to">
|
||||
<fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
|
||||
<i v-if="menuDef[item].indicated"><fa :icon="faCircle"/></i>
|
||||
</component>
|
||||
</template>
|
||||
<div class="divider"></div>
|
||||
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu">
|
||||
<fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
|
||||
</button>
|
||||
<button class="item _button" @click="more">
|
||||
<fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
|
||||
<i v-if="otherNavItemIndicated"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
<router-link class="item" active-class="active" to="/preferences">
|
||||
<fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</nav>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
|
||||
import { host, instanceName } from '../config';
|
||||
import { search } from '../scripts/search';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
host: host,
|
||||
showing: false,
|
||||
searching: false,
|
||||
accounts: [],
|
||||
connection: null,
|
||||
menuDef: this.$store.getters.nav({
|
||||
search: this.search
|
||||
}),
|
||||
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
menu(): string[] {
|
||||
return this.$store.state.deviceUser.menu;
|
||||
},
|
||||
|
||||
otherNavItemIndicated(): boolean {
|
||||
if (!this.$store.getters.isSignedIn) return false;
|
||||
for (const def in this.menuDef) {
|
||||
if (this.menu.includes(def)) continue;
|
||||
if (this.menuDef[def].indicated) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.showing = false;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
show() {
|
||||
this.showing = true;
|
||||
},
|
||||
|
||||
top() {
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
||||
},
|
||||
|
||||
search() {
|
||||
if (this.searching) return;
|
||||
|
||||
this.$root.dialog({
|
||||
title: this.$t('search'),
|
||||
input: true
|
||||
}).then(async ({ canceled, result: query }) => {
|
||||
if (canceled || query == null || query === '') return;
|
||||
|
||||
this.searching = true;
|
||||
search(this, query).finally(() => {
|
||||
this.searching = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async openAccountMenu(ev) {
|
||||
const accounts = (await this.$root.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id);
|
||||
|
||||
const accountItems = accounts.map(account => ({
|
||||
type: 'user',
|
||||
user: account,
|
||||
action: () => { this.switchAccount(account); }
|
||||
}));
|
||||
|
||||
this.$root.menu({
|
||||
items: [...[{
|
||||
type: 'link',
|
||||
text: this.$t('profile'),
|
||||
to: `/@${ this.$store.state.i.username }`,
|
||||
avatar: this.$store.state.i,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('accountSettings'),
|
||||
to: '/my/settings',
|
||||
icon: faCog,
|
||||
}, null, ...accountItems, {
|
||||
icon: faPlus,
|
||||
text: this.$t('addAcount'),
|
||||
action: () => {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
text: this.$t('existingAcount'),
|
||||
action: () => { this.addAcount(); },
|
||||
}, {
|
||||
text: this.$t('createAccount'),
|
||||
action: () => { this.createAccount(); },
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
}]],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 240,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
oepnInstanceMenu(ev) {
|
||||
this.$root.menu({
|
||||
items: [{
|
||||
type: 'link',
|
||||
text: this.$t('dashboard'),
|
||||
to: '/instance',
|
||||
icon: faTachometerAlt,
|
||||
}, null, {
|
||||
type: 'link',
|
||||
text: this.$t('settings'),
|
||||
to: '/instance/settings',
|
||||
icon: faCog,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('customEmojis'),
|
||||
to: '/instance/emojis',
|
||||
icon: faLaugh,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('users'),
|
||||
to: '/instance/users',
|
||||
icon: faUsers,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('files'),
|
||||
to: '/instance/files',
|
||||
icon: faCloud,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('jobQueue'),
|
||||
to: '/instance/queue',
|
||||
icon: faExchangeAlt,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('federation'),
|
||||
to: '/instance/federation',
|
||||
icon: faGlobe,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('relays'),
|
||||
to: '/instance/relays',
|
||||
icon: faProjectDiagram,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('announcements'),
|
||||
to: '/instance/announcements',
|
||||
icon: faBroadcastTower,
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 200,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
more(ev) {
|
||||
const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
|
||||
type: def.to ? 'link' : 'button',
|
||||
text: this.$t(def.title),
|
||||
icon: def.icon,
|
||||
to: def.to,
|
||||
action: def.action,
|
||||
indicate: def.indicated,
|
||||
}));
|
||||
this.$root.menu({
|
||||
items: [...items, null, {
|
||||
type: 'link',
|
||||
text: this.$t('help'),
|
||||
to: '/docs',
|
||||
icon: faQuestionCircle,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('aboutX', { x: instanceName || host }),
|
||||
to: '/about',
|
||||
icon: faInfoCircle,
|
||||
}, {
|
||||
type: 'link',
|
||||
text: this.$t('aboutMisskey'),
|
||||
to: '/about-misskey',
|
||||
icon: faInfoCircle,
|
||||
}],
|
||||
align: 'left',
|
||||
fixed: true,
|
||||
width: 200,
|
||||
source: ev.currentTarget || ev.target,
|
||||
});
|
||||
},
|
||||
|
||||
async addAcount() {
|
||||
this.$root.new(await import('./signin-dialog.vue').then(m => m.default)).$once('login', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
iconOnly: true, autoClose: true
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async createAccount() {
|
||||
this.$root.new(await import('./signup-dialog.vue').then(m => m.default)).$once('signup', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.switchAccountWithToken(res.i);
|
||||
});
|
||||
},
|
||||
|
||||
async switchAccount(account: any) {
|
||||
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
||||
this.switchAccountWithToken(token);
|
||||
},
|
||||
|
||||
switchAccountWithToken(token: string) {
|
||||
this.$root.dialog({
|
||||
type: 'waiting',
|
||||
iconOnly: true
|
||||
});
|
||||
|
||||
this.$root.api('i', {}, token).then((i: any) => {
|
||||
this.$store.dispatch('switchAccount', {
|
||||
...i,
|
||||
token: token
|
||||
}).then(() => {
|
||||
this.$nextTick(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nav-enter-active,
|
||||
.nav-leave-active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.nav-enter,
|
||||
.nav-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateX(-240px);
|
||||
}
|
||||
|
||||
.nav-back-enter-active,
|
||||
.nav-back-leave-active {
|
||||
opacity: 1;
|
||||
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.nav-back-enter,
|
||||
.nav-back-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.mvcprjjd {
|
||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||
$nav-width: 250px; // TODO: どこかに集約したい
|
||||
$nav-icon-only-width: 80px; // TODO: どこかに集約したい
|
||||
$nav-icon-only-threshold: 1279px; // TODO: どこかに集約したい
|
||||
$nav-hide-threshold: 650px; // TODO: どこかに集約したい
|
||||
|
||||
> .nav-back {
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
> .nav {
|
||||
$avatar-size: 32px;
|
||||
$avatar-margin: 8px;
|
||||
|
||||
flex: 0 0 $nav-width;
|
||||
width: $nav-width;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) {
|
||||
flex: 0 0 $nav-icon-only-width;
|
||||
width: $nav-icon-only-width;
|
||||
}
|
||||
|
||||
@media (max-width: $nav-hide-threshold) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
@media (min-width: $nav-hide-threshold + 1px) {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
> div {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
width: $nav-width;
|
||||
// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||
height: calc(var(--vh, 1vh) * 100);
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
background: var(--navBg);
|
||||
border-right: solid 1px var(--divider);
|
||||
|
||||
> .divider {
|
||||
margin: 16px 0;
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
|
||||
width: $nav-icon-only-width;
|
||||
|
||||
> .divider {
|
||||
margin: 8px auto;
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
> .item {
|
||||
&:first-child {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-left: 32px;
|
||||
font-size: $ui-font-size;
|
||||
line-height: 3.2rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
color: var(--navFg);
|
||||
|
||||
> [data-icon] {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
> [data-icon],
|
||||
> .avatar {
|
||||
margin-right: $avatar-margin;
|
||||
}
|
||||
|
||||
> .avatar {
|
||||
width: $avatar-size;
|
||||
height: $avatar-size;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
> i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: var(--navHoverFg);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--navActive);
|
||||
}
|
||||
|
||||
&:first-child, &:last-child {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
background: var(--X14);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
top: 0;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
bottom: 0;
|
||||
margin-top: 16px;
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
|
||||
padding-left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: $ui-font-size * 1.2;
|
||||
line-height: 3.7rem;
|
||||
|
||||
> [data-icon],
|
||||
> .avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
> i {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
> .text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $nav-hide-threshold) {
|
||||
> .index,
|
||||
> .notifications {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -7,13 +7,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../i18n';
|
||||
import XWindow from './window.vue';
|
||||
import MkSignin from './signin.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n,
|
||||
|
||||
components: {
|
||||
MkSignin,
|
||||
XWindow,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user