Compare commits
210 Commits
Author | SHA1 | Date | |
---|---|---|---|
1bec4e2d12 | |||
03cd1d27bf | |||
9427a756c9 | |||
d32b2a8ce5 | |||
15473b4368 | |||
54de0dc4a7 | |||
0162eaf826 | |||
572cfafbe1 | |||
4d6335ce9a | |||
1c9c4af9f1 | |||
a6844ebc9d | |||
072492c29b | |||
99da4f9839 | |||
88664486af | |||
80daf7c749 | |||
beb2f7e558 | |||
6243184c95 | |||
1b3baef966 | |||
98f38ee29b | |||
09b82bfea4 | |||
937f686264 | |||
9bc9cbac21 | |||
6024550158 | |||
4ae5f82171 | |||
6d2c9dcee9 | |||
0f1b0e1870 | |||
81c682cdc8 | |||
ab9fa67d9f | |||
9537fce335 | |||
9d97e7e348 | |||
ebe7939412 | |||
807e3e8ca7 | |||
a59faf9117 | |||
d786036155 | |||
61d6ed5489 | |||
b38200d48a | |||
a0c396a842 | |||
88fbc53e37 | |||
a2206b2d52 | |||
a95ff447d7 | |||
49dbd7f9d2 | |||
2ad2779096 | |||
23045369aa | |||
116faf26e6 | |||
2582b8d132 | |||
63f7941073 | |||
676f026085 | |||
a13319fd86 | |||
be8765278c | |||
c8bb3dc209 | |||
ea16befb73 | |||
20b1bb7681 | |||
bd10eb50eb | |||
d47c0eb31a | |||
177e8bb19f | |||
d156111637 | |||
8c13d3e50b | |||
6ff01016f0 | |||
5d659da012 | |||
28e7552a1a | |||
53d264814b | |||
2d6b20d34b | |||
99073b56df | |||
5dce81c0db | |||
be82d845a4 | |||
f49ccd0cd3 | |||
69d83f535d | |||
c7988fb6f5 | |||
3961fd08c9 | |||
e3faf64061 | |||
ed83993e15 | |||
0f8847bb74 | |||
a72cfa7535 | |||
514b74a19d | |||
a2c124306f | |||
273f67e268 | |||
2870a7e463 | |||
935b074a7a | |||
9d9c609bfb | |||
f6a664f181 | |||
fce68d1f75 | |||
88739c2444 | |||
7e2f10fce3 | |||
a494c3a5cc | |||
d6bb702883 | |||
d15a972c68 | |||
2ae7d31725 | |||
2e329b1888 | |||
522d40328b | |||
2ecbff45bf | |||
b6f7282c13 | |||
65e5cfa68e | |||
10e59957d1 | |||
4f74373df3 | |||
2d414bbf86 | |||
a199969b81 | |||
3aef5e6748 | |||
2b536a7443 | |||
20fe68de05 | |||
c7684b59de | |||
a7237d157a | |||
35f91fa280 | |||
299ac32225 | |||
a038738d72 | |||
2b0a919fb5 | |||
946c706913 | |||
89b5d976ee | |||
6f679bb6b4 | |||
db4e7b0e16 | |||
9ca942490d | |||
ebcf249c8b | |||
939c487503 | |||
981a8b267e | |||
9531da80a0 | |||
e1109b168c | |||
b7c70039aa | |||
17b6f6cf2a | |||
dd88483ba4 | |||
0ff27f65b3 | |||
b1655740df | |||
6d562aece1 | |||
2182c3372b | |||
d3331bfe82 | |||
cfc4a2e8b4 | |||
36c41c8eb3 | |||
d255157e6e | |||
c12e07277d | |||
06b4fb5095 | |||
8fafdcb428 | |||
537a606bb6 | |||
3dc7a4463c | |||
fd6ff05b60 | |||
1a159e41b8 | |||
23533cdd16 | |||
2f598b8fa1 | |||
bca349fec1 | |||
719fac6480 | |||
1012b2b2c7 | |||
5149be4b1b | |||
d12deeb0d8 | |||
9df81d1939 | |||
3be0079868 | |||
9b253ccb3a | |||
dded76099c | |||
41a7ec7d3d | |||
168c773ba0 | |||
9abed92196 | |||
4a75e3602a | |||
1a689f6641 | |||
08d7ae11d6 | |||
9535759787 | |||
f8fc31f14a | |||
b74bf97761 | |||
a090b908bd | |||
3046821026 | |||
e94c73efe2 | |||
e85f9f4aa5 | |||
ad67886f96 | |||
5df0e102fd | |||
a04f0e3545 | |||
dff9c7ac48 | |||
3a80b59986 | |||
07560a4fdd | |||
7edca21c05 | |||
34105abd9d | |||
1bbca48a0b | |||
21f6a86772 | |||
6559197c55 | |||
05f9ad11bb | |||
f06d586680 | |||
4f45e8125c | |||
cc2843503d | |||
324a974dec | |||
4d4ffd70ac | |||
bf98a11b65 | |||
1117ce4b54 | |||
57e93b9b4e | |||
9e4b061ed0 | |||
1067bef7d6 | |||
8bff529acd | |||
4b08677839 | |||
70997cb551 | |||
bf0ef17e23 | |||
7dae5107f8 | |||
2dea88a147 | |||
f44c2a3e4f | |||
1fad3cbaae | |||
40d2e3e97c | |||
2efabe612e | |||
3107cbd6b9 | |||
3a061ed1c3 | |||
d4f0e6461a | |||
3285687652 | |||
51c53f64d0 | |||
1d582f5ad2 | |||
8a62748e39 | |||
b9290a021b | |||
129ce93868 | |||
5f41e5d6d0 | |||
c706d030ea | |||
34716a34f8 | |||
6db3d6dfb6 | |||
38e2853dcf | |||
ba5a540ca3 | |||
fb1e05c2e9 | |||
aba84612a7 | |||
9bebbf4e03 | |||
e41b3f9c10 | |||
890dc05022 | |||
375f86ec82 |
@ -60,11 +60,6 @@ mongodb:
|
|||||||
user: example-misskey-user
|
user: example-misskey-user
|
||||||
pass: example-misskey-pass
|
pass: example-misskey-pass
|
||||||
|
|
||||||
redis:
|
|
||||||
host: localhost
|
|
||||||
port: 6379
|
|
||||||
pass: example-pass
|
|
||||||
|
|
||||||
# Drive capacity of a local user (MB)
|
# Drive capacity of a local user (MB)
|
||||||
localDriveCapacityMb: 256
|
localDriveCapacityMb: 256
|
||||||
|
|
||||||
@ -122,6 +117,12 @@ drive:
|
|||||||
# Below settings are optional
|
# Below settings are optional
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
#redis:
|
||||||
|
# host: localhost
|
||||||
|
# port: 6379
|
||||||
|
# pass: example-pass
|
||||||
|
|
||||||
# Elasticsearch
|
# Elasticsearch
|
||||||
#elasticsearch:
|
#elasticsearch:
|
||||||
# host: localhost
|
# host: localhost
|
||||||
@ -137,12 +138,10 @@ drive:
|
|||||||
#sw:
|
#sw:
|
||||||
# # Public key of VAPID
|
# # Public key of VAPID
|
||||||
# public_key: example-sw-public-key
|
# public_key: example-sw-public-key
|
||||||
|
#
|
||||||
# # Private key of VAPID
|
# # Private key of VAPID
|
||||||
# private_key: example-sw-private-key
|
# private_key: example-sw-private-key
|
||||||
|
|
||||||
# google_maps_api_key: example-google-maps-api-key
|
|
||||||
|
|
||||||
# Twitter integration
|
# Twitter integration
|
||||||
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/tw/cb
|
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/tw/cb
|
||||||
#twitter:
|
#twitter:
|
||||||
@ -161,8 +160,7 @@ drive:
|
|||||||
#summalyProxy: "http://example.com"
|
#summalyProxy: "http://example.com"
|
||||||
|
|
||||||
# User recommendation
|
# User recommendation
|
||||||
user_recommendation:
|
#user_recommendation:
|
||||||
external: true
|
# external: true
|
||||||
engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
|
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
|
||||||
timeout: 300000
|
# timeout: 300000
|
||||||
|
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
maintainer: '@syuilo'
|
maintainer:
|
||||||
url: 'https://misskey.xyz'
|
name: syuilo
|
||||||
secondary_url: 'https://himasaku.net'
|
url: 'https://syuilo.com'
|
||||||
|
url: 'http://misskey.local'
|
||||||
port: 80
|
port: 80
|
||||||
https:
|
|
||||||
enable: false
|
|
||||||
key: null
|
|
||||||
cert: null
|
|
||||||
ca: null
|
|
||||||
mongodb:
|
mongodb:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 27017
|
port: 27017
|
||||||
@ -21,6 +17,3 @@ elasticsearch:
|
|||||||
host: localhost
|
host: localhost
|
||||||
port: 9200
|
port: 9200
|
||||||
pass: ''
|
pass: ''
|
||||||
recaptcha:
|
|
||||||
site_key: hima
|
|
||||||
secret_key: saku
|
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
maintainer: '@syuilo'
|
maintainer:
|
||||||
url: 'https://misskey.xyz'
|
name: syuilo
|
||||||
secondary_url: 'https://himasaku.net'
|
url: 'https://syuilo.com'
|
||||||
|
url: 'http://misskey.local'
|
||||||
port: 80
|
port: 80
|
||||||
https:
|
|
||||||
enable: false
|
|
||||||
key: null
|
|
||||||
cert: null
|
|
||||||
ca: null
|
|
||||||
mongodb:
|
mongodb:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 27017
|
port: 27017
|
||||||
@ -21,6 +17,3 @@ elasticsearch:
|
|||||||
host: localhost
|
host: localhost
|
||||||
port: 9200
|
port: 9200
|
||||||
pass: ''
|
pass: ''
|
||||||
recaptcha:
|
|
||||||
site_key: hima
|
|
||||||
secret_key: saku
|
|
||||||
|
@ -24,12 +24,12 @@ Please install and setup these softwares:
|
|||||||
#### Dependencies :package:
|
#### Dependencies :package:
|
||||||
* **[Node.js](https://nodejs.org/en/)**
|
* **[Node.js](https://nodejs.org/en/)**
|
||||||
* **[MongoDB](https://www.mongodb.com/)** >= 3.6
|
* **[MongoDB](https://www.mongodb.com/)** >= 3.6
|
||||||
* **[Redis](https://redis.io/)**
|
|
||||||
|
|
||||||
##### Optional
|
##### Optional
|
||||||
|
* [Redis](https://redis.io/)
|
||||||
|
* Redis is optional, but we strongly recommended to install it
|
||||||
* [Elasticsearch](https://www.elastic.co/) - used to provide searching feature instead of MongoDB
|
* [Elasticsearch](https://www.elastic.co/) - used to provide searching feature instead of MongoDB
|
||||||
|
|
||||||
|
|
||||||
*3.* Setup MongoDB
|
*3.* Setup MongoDB
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
In root :
|
In root :
|
||||||
|
@ -24,10 +24,17 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
#### 依存関係 :package:
|
#### 依存関係 :package:
|
||||||
* **[Node.js](https://nodejs.org/en/)**
|
* **[Node.js](https://nodejs.org/en/)**
|
||||||
* **[MongoDB](https://www.mongodb.com/)** (3.6以上)
|
* **[MongoDB](https://www.mongodb.com/)** (3.6以上)
|
||||||
* **[Redis](https://redis.io/)**
|
|
||||||
|
|
||||||
##### オプション
|
##### オプション
|
||||||
* [Elasticsearch](https://www.elastic.co/) - 検索機能を向上させるために用います。
|
* [Redis](https://redis.io/)
|
||||||
|
* Redisはオプションですが、インストールすることを強く推奨します。
|
||||||
|
* インストールしなくていいのは、あなたのインスタンスが自分専用のときだけとお考えください。
|
||||||
|
* 具体的には、Redisをインストールしないと、次の事が出来なくなります:
|
||||||
|
* Misskeyプロセスを複数起動しての負荷分散
|
||||||
|
* レートリミット
|
||||||
|
* Twitter連携
|
||||||
|
* [Elasticsearch](https://www.elastic.co/)
|
||||||
|
* 検索機能を有効にするためにはインストールが必要です。
|
||||||
|
|
||||||
*3.* MongoDBの設定
|
*3.* MongoDBの設定
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -3,16 +3,16 @@ meta:
|
|||||||
lang: "Deutsch"
|
lang: "Deutsch"
|
||||||
divider: ""
|
divider: ""
|
||||||
common:
|
common:
|
||||||
misskey: "A ⭐ of fediverse"
|
misskey: "Ein ⭐ des Fediversums"
|
||||||
about-title: "A ⭐ of fediverse."
|
about-title: "Ein ⭐ des Fediversums."
|
||||||
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
||||||
intro:
|
intro:
|
||||||
title: "Misskeyって?"
|
title: "Was ist Misskey?"
|
||||||
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
||||||
features: "特徴"
|
features: "Funktionen"
|
||||||
rich-contents: "投稿"
|
rich-contents: "Notizen"
|
||||||
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
|
rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
|
||||||
reaction: "リアクション"
|
reaction: "Reaktionen"
|
||||||
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
|
reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
|
||||||
ui: "インターフェース"
|
ui: "インターフェース"
|
||||||
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
|
ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
|
||||||
@ -23,7 +23,7 @@ common:
|
|||||||
detected: "広告ブロッカーを無効にしてください"
|
detected: "広告ブロッカーを無効にしてください"
|
||||||
warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
|
warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
|
||||||
application-authorization: "アプリの連携"
|
application-authorization: "アプリの連携"
|
||||||
close: "閉じる"
|
close: "Schließen"
|
||||||
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
|
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
|
||||||
got-it: "わかった"
|
got-it: "わかった"
|
||||||
customization-tips:
|
customization-tips:
|
||||||
@ -34,13 +34,13 @@ common:
|
|||||||
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
|
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
|
||||||
gotit: "Got it!"
|
gotit: "Got it!"
|
||||||
notification:
|
notification:
|
||||||
file-uploaded: "ファイルがアップロードされました"
|
file-uploaded: "Datei hochgeladen!"
|
||||||
message-from: "{}さんからメッセージ:"
|
message-from: "{}さんからメッセージ:"
|
||||||
reversi-invited: "対局への招待があります"
|
reversi-invited: "対局への招待があります"
|
||||||
reversi-invited-by: "{}さんから"
|
reversi-invited-by: "{}さんから"
|
||||||
notified-by: "{}さんから"
|
notified-by: "Benachrichtigt von {}:"
|
||||||
reply-from: "{}さんから返信:"
|
reply-from: "Antwort von {}:"
|
||||||
quoted-by: "{}さんが引用:"
|
quoted-by: "Zitiert von {}:"
|
||||||
time:
|
time:
|
||||||
unknown: "Unbekannt"
|
unknown: "Unbekannt"
|
||||||
future: "Zukunft"
|
future: "Zukunft"
|
||||||
@ -53,7 +53,7 @@ common:
|
|||||||
months_ago: "vor {0} Monat{0:en}"
|
months_ago: "vor {0} Monat{0:en}"
|
||||||
years_ago: "vor {} Jahr{0:en}"
|
years_ago: "vor {} Jahr{0:en}"
|
||||||
month-and-day: "{month}月 {day}日"
|
month-and-day: "{month}月 {day}日"
|
||||||
trash: "ゴミ箱"
|
trash: "Papierkorb"
|
||||||
weekday-short:
|
weekday-short:
|
||||||
sunday: "So"
|
sunday: "So"
|
||||||
monday: "Mo"
|
monday: "Mo"
|
||||||
@ -63,13 +63,13 @@ common:
|
|||||||
friday: "Fr"
|
friday: "Fr"
|
||||||
saturday: "Sa"
|
saturday: "Sa"
|
||||||
weekday:
|
weekday:
|
||||||
sunday: "日曜日"
|
sunday: "Sonntag"
|
||||||
monday: "月曜日"
|
monday: "Montag"
|
||||||
tuesday: "火曜日"
|
tuesday: "Dienstag"
|
||||||
wednesday: "水曜日"
|
wednesday: "Mittwoch"
|
||||||
thursday: "木曜日"
|
thursday: "Donnerstag"
|
||||||
friday: "金曜日"
|
friday: "Freitag"
|
||||||
saturday: "土曜日"
|
saturday: "Samstag"
|
||||||
reactions:
|
reactions:
|
||||||
like: "いいね"
|
like: "いいね"
|
||||||
love: "Lieben"
|
love: "Lieben"
|
||||||
@ -82,10 +82,10 @@ common:
|
|||||||
rip: "RIP"
|
rip: "RIP"
|
||||||
pudding: "Pudding"
|
pudding: "Pudding"
|
||||||
note-visibility:
|
note-visibility:
|
||||||
public: "公開"
|
public: "Öffentlich"
|
||||||
home: "ホーム"
|
home: "ホーム"
|
||||||
home-desc: "ホームタイムラインにのみ公開"
|
home-desc: "ホームタイムラインにのみ公開"
|
||||||
followers: "フォロワー"
|
followers: "Abonnenten"
|
||||||
followers-desc: "自分のフォロワーにのみ公開"
|
followers-desc: "自分のフォロワーにのみ公開"
|
||||||
specified: "ダイレクト"
|
specified: "ダイレクト"
|
||||||
specified-desc: "指定したユーザーにのみ公開"
|
specified-desc: "指定したユーザーにのみ公開"
|
||||||
@ -122,9 +122,9 @@ common:
|
|||||||
turn-of: "{}のターンです"
|
turn-of: "{}のターンです"
|
||||||
past-turn-of: "{}のターン"
|
past-turn-of: "{}のターン"
|
||||||
won: "{}の勝ち"
|
won: "{}の勝ち"
|
||||||
black: "黒"
|
black: "Schwarz"
|
||||||
white: "白"
|
white: "Weiß"
|
||||||
total: "合計"
|
total: "Gesamt"
|
||||||
this-turn: "{}ターン目"
|
this-turn: "{}ターン目"
|
||||||
widgets:
|
widgets:
|
||||||
analog-clock: "Analoge Uhr"
|
analog-clock: "Analoge Uhr"
|
||||||
@ -142,23 +142,23 @@ common:
|
|||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
notifications: "Benachrichtigungen"
|
notifications: "Benachrichtigungen"
|
||||||
users: "Empfohlene Benutzer"
|
users: "Empfohlene Benutzer"
|
||||||
polls: "アンケート"
|
polls: "Umfrage"
|
||||||
post-form: "Beitragsform"
|
post-form: "Beitragsform"
|
||||||
messaging: "Nachrichten"
|
messaging: "Nachrichten"
|
||||||
server: "Server-Info"
|
server: "Server-Info"
|
||||||
donation: "Spenden"
|
donation: "Spenden"
|
||||||
nav: "Navigation"
|
nav: "Navigation"
|
||||||
tips: "Tipps"
|
tips: "Tipps"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "Hashtags"
|
||||||
deck:
|
deck:
|
||||||
widgets: "Widget hinzufügen:"
|
widgets: "Widget hinzufügen:"
|
||||||
home: "Startseite"
|
home: "Startseite"
|
||||||
local: "Lokal"
|
local: "Lokal"
|
||||||
hybrid: "ソーシャル"
|
hybrid: "ソーシャル"
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "Hashtag"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "あなた宛て"
|
mentions: "Erwähnungen"
|
||||||
direct: "ダイレクト投稿"
|
direct: "Direktnachrichten"
|
||||||
notifications: "Mitteilungen"
|
notifications: "Mitteilungen"
|
||||||
list: "Listen"
|
list: "Listen"
|
||||||
swap-left: "Nach links"
|
swap-left: "Nach links"
|
||||||
@ -182,10 +182,10 @@ auth/views/form.vue:
|
|||||||
drive-write: "ドライブを操作する。"
|
drive-write: "ドライブを操作する。"
|
||||||
notification-read: "通知を見る。"
|
notification-read: "通知を見る。"
|
||||||
notification-write: "通知を操作する。"
|
notification-write: "通知を操作する。"
|
||||||
cancel: "キャンセル"
|
cancel: "Abbrechen"
|
||||||
accept: "アクセスを許可"
|
accept: "Zugriff erlauben."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
loading: "読み込み中"
|
loading: "Lädt"
|
||||||
denied: "アプリケーションの連携をキャンセルしました。"
|
denied: "アプリケーションの連携をキャンセルしました。"
|
||||||
denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
|
denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
|
||||||
already-authorized: "このアプリは既に連携済みです"
|
already-authorized: "このアプリは既に連携済みです"
|
||||||
@ -196,10 +196,10 @@ auth/views/index.vue:
|
|||||||
sign-in: "サインインしてください"
|
sign-in: "サインインしてください"
|
||||||
common/views/components/games/reversi/reversi.vue:
|
common/views/components/games/reversi/reversi.vue:
|
||||||
matching:
|
matching:
|
||||||
waiting-for: "{}を待っています"
|
waiting-for: "Warten auf {}"
|
||||||
cancel: "キャンセル"
|
cancel: "Abbrechen"
|
||||||
common/views/components/games/reversi/reversi.game.vue:
|
common/views/components/games/reversi/reversi.game.vue:
|
||||||
surrender: "投了"
|
surrender: "Aufgeben"
|
||||||
surrendered: "投了により"
|
surrendered: "投了により"
|
||||||
is-llotheo: "石の少ない方が勝ち(ロセオ)"
|
is-llotheo: "石の少ない方が勝ち(ロセオ)"
|
||||||
looped-map: "ループマップ"
|
looped-map: "ループマップ"
|
||||||
@ -208,9 +208,9 @@ common/views/components/games/reversi/reversi.index.vue:
|
|||||||
title: "Misskey Reversi"
|
title: "Misskey Reversi"
|
||||||
sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
|
sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
|
||||||
invite: "招待"
|
invite: "招待"
|
||||||
rule: "遊び方"
|
rule: "Spielanleitung"
|
||||||
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。"
|
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。"
|
||||||
mode-invite: "招待"
|
mode-invite: "Einladen"
|
||||||
mode-invite-desc: "指定したユーザーと対戦するモードです。"
|
mode-invite-desc: "指定したユーザーと対戦するモードです。"
|
||||||
invitations: "対局の招待があります!"
|
invitations: "対局の招待があります!"
|
||||||
my-games: "自分の対局"
|
my-games: "自分の対局"
|
||||||
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Diese Anmerkung favorisieren"
|
favorite: "Diese Anmerkung favorisieren"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "An die Profilseite pinnen"
|
pin: "An die Profilseite pinnen"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Löschen"
|
delete: "Löschen"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Werkzeuge"
|
tools: "Werkzeuge"
|
||||||
task-manager: "Taskmanager"
|
task-manager: "Taskmanager"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Profil aktualisieren"
|
save: "Profil aktualisieren"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -265,40 +265,40 @@ common/views/components/media-banner.vue:
|
|||||||
sensitive: "NSFW"
|
sensitive: "NSFW"
|
||||||
click-to-show: "Click to show"
|
click-to-show: "Click to show"
|
||||||
common/views/components/theme.vue:
|
common/views/components/theme.vue:
|
||||||
light-theme: "非ダークモード時に使用するテーマ"
|
light-theme: "Theme during non-dark mode"
|
||||||
dark-theme: "ダークモード時に使用するテーマ"
|
dark-theme: "Theme during dark mode"
|
||||||
light-themes: "明るいテーマ"
|
light-themes: "Light theme"
|
||||||
dark-themes: "暗いテーマ"
|
dark-themes: "Dark theme"
|
||||||
install-a-theme: "テーマのインストール"
|
install-a-theme: "Install a theme"
|
||||||
theme-code: "テーマコード"
|
theme-code: "Theme code"
|
||||||
install: "インストール"
|
install: "Install"
|
||||||
installed: "「{}」をインストールしました"
|
installed: "\"{}\" has been installed"
|
||||||
create-a-theme: "テーマの作成"
|
create-a-theme: "Create a theme"
|
||||||
save-created-theme: "テーマを保存"
|
save-created-theme: "Save a theme"
|
||||||
primary-color: "プライマリ カラー"
|
primary-color: "Primary color"
|
||||||
secondary-color: "セカンダリ カラー"
|
secondary-color: "Secondary color"
|
||||||
text-color: "文字色"
|
text-color: "Text color"
|
||||||
base-theme: "ベーステーマ"
|
base-theme: "Base theme"
|
||||||
base-theme-light: "Light"
|
base-theme-light: "Light"
|
||||||
base-theme-dark: "Dark"
|
base-theme-dark: "Dark"
|
||||||
theme-name: "テーマ名"
|
theme-name: "Theme name"
|
||||||
preview-created-theme: "プレビュー"
|
preview-created-theme: "Preview"
|
||||||
invalid-theme: "テーマが正しくありません。"
|
invalid-theme: "Not valid theme"
|
||||||
already-installed: "既にそのテーマはインストールされています。"
|
already-installed: "This theme is already installed."
|
||||||
saved: "保存しました"
|
saved: "Saved"
|
||||||
manage-themes: "テーマの管理"
|
manage-themes: "Themes manager"
|
||||||
builtin-themes: "標準テーマ"
|
builtin-themes: "Standard themes"
|
||||||
my-themes: "マイテーマ"
|
my-themes: "My themes"
|
||||||
installed-themes: "インストールされたテーマ"
|
installed-themes: "Installed themes"
|
||||||
select-theme: "テーマを選択してください"
|
select-theme: "Select your theme"
|
||||||
uninstall: "アンインストール"
|
uninstall: "Uninstall"
|
||||||
uninstalled: "「{}」をアンインストールしました"
|
uninstalled: "\"{}\" has been uninstalled"
|
||||||
author: "作者"
|
author: "Author"
|
||||||
desc: "説明"
|
desc: "Description"
|
||||||
export: "エクスポート"
|
export: "Export"
|
||||||
import: "インポート"
|
import: "Import"
|
||||||
import-by-code: "またはコードをペースト"
|
import-by-code: "or paste code"
|
||||||
theme-name-required: "テーマ名は必須です。"
|
theme-name-required: "Theme name is required"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "See more"
|
show: "See more"
|
||||||
@ -335,8 +335,9 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "Details"
|
detail: "Details"
|
||||||
copy-link: "Copy link"
|
copy-link: "Copy link"
|
||||||
favorite: "Favorite this note"
|
favorite: "Favorite this note"
|
||||||
|
unfavorite: "Unfavorite"
|
||||||
pin: "Pin to your profile"
|
pin: "Pin to your profile"
|
||||||
unpin: "ピン留め解除"
|
unpin: "Unpin"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
delete-confirm: "Delete this post?"
|
delete-confirm: "Delete this post?"
|
||||||
remote: "Show original note"
|
remote: "Show original note"
|
||||||
@ -514,13 +515,13 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "The number of posts: increase/decrease (Combined)"
|
notes: "The number of posts: increase/decrease (Combined)"
|
||||||
local-notes: "The number of posts: increase/decrease (Local)"
|
local-notes: "The number of posts: increase/decrease (Local)"
|
||||||
remote-notes: "The number of posts: increase/decrease (Remote)"
|
remote-notes: "The number of posts: increase/decrease (Remote)"
|
||||||
notes-total: "投稿の積算"
|
notes-total: "Total posts"
|
||||||
users: "The number of users: increase/decrease"
|
users: "The number of users: increase/decrease"
|
||||||
users-total: "ユーザーの積算"
|
users-total: "Total users"
|
||||||
drive: "Capacity used as the storage: increase/decrease"
|
drive: "Capacity used as the storage: increase/decrease"
|
||||||
drive-total: "ドライブ使用量の積算"
|
drive-total: "Total usage of Drive"
|
||||||
drive-files: "The number of files on the storage: increase/decrease"
|
drive-files: "The number of files on the storage: increase/decrease"
|
||||||
drive-files-total: "ドライブのファイル数の積算"
|
drive-files-total: "Total number of files on Drive"
|
||||||
network-requests: "Requests"
|
network-requests: "Requests"
|
||||||
network-time: "Response time"
|
network-time: "Response time"
|
||||||
network-usage: "Traffic"
|
network-usage: "Traffic"
|
||||||
@ -730,8 +731,8 @@ desktop/views/components/settings.vue:
|
|||||||
choose-wallpaper: "Choose a background"
|
choose-wallpaper: "Choose a background"
|
||||||
delete-wallpaper: "Remove background"
|
delete-wallpaper: "Remove background"
|
||||||
dark-mode: "Dark Mode"
|
dark-mode: "Dark Mode"
|
||||||
use-shadow: "UIに影を使用"
|
use-shadow: "Use shadows in the UI"
|
||||||
rounded-corners: "UIの角を丸める"
|
rounded-corners: "Round corners of UI"
|
||||||
circle-icons: "Use circle icons"
|
circle-icons: "Use circle icons"
|
||||||
contrasted-acct: "Add contrast to username"
|
contrasted-acct: "Add contrast to username"
|
||||||
post-form-on-timeline: "Display post form at the top of the timeline"
|
post-form-on-timeline: "Display post form at the top of the timeline"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Tools"
|
tools: "Tools"
|
||||||
task-manager: "Task Manager"
|
task-manager: "Task Manager"
|
||||||
third-parties: "Third-parties"
|
third-parties: "Third-parties"
|
||||||
|
navbar-position: "Navigation bar position"
|
||||||
|
navbar-position-top: "Top"
|
||||||
|
navbar-position-left: "Left"
|
||||||
|
navbar-position-right: "Right"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "If you set up 2-step verification, you will not only need a password at sign-in, but also a pre-registered physical device (such as your smartphone), which will improve security."
|
intro: "If you set up 2-step verification, you will not only need a password at sign-in, but also a pre-registered physical device (such as your smartphone), which will improve security."
|
||||||
detail: "Details…"
|
detail: "Details…"
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Update profile"
|
save: "Update profile"
|
||||||
locked-account: "Protect your account"
|
locked-account: "Protect your account"
|
||||||
is-locked: "Follow request needs approval"
|
is-locked: "Follow request needs approval"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "Other"
|
other: "Other"
|
||||||
is-bot: "This account is a Bot"
|
is-bot: "This account is a Bot"
|
||||||
is-cat: "This account is a Cat"
|
is-cat: "This account is a Cat"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "Hash (md5)"
|
hash: "Hash (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "NSFW"
|
nsfw: "NSFW"
|
||||||
|
mark-as-sensitive: "Mark as 'sensitive'"
|
||||||
|
unmark-as-sensitive: "Unmark as 'sensitive'"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "NSFW"
|
sensitive: "NSFW"
|
||||||
click-to-show: "Click to show"
|
click-to-show: "Click to show"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Banner"
|
banner: "Banner"
|
||||||
is-cat: "This account is a Cat"
|
is-cat: "This account is a Cat"
|
||||||
is-locked: "Follow request needs approval"
|
is-locked: "Follow request needs approval"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "Advanced"
|
advanced: "Advanced"
|
||||||
privacy: "Privacy"
|
privacy: "Privacy"
|
||||||
save: "Update profile"
|
save: "Update profile"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "Detalles"
|
detail: "Detalles"
|
||||||
copy-link: "Copiar enlace"
|
copy-link: "Copiar enlace"
|
||||||
favorite: "Me gusta esta nota"
|
favorite: "Me gusta esta nota"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "Fijar en el perfil"
|
pin: "Fijar en el perfil"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Borrar"
|
delete: "Borrar"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Herramientas"
|
tools: "Herramientas"
|
||||||
task-manager: "Navegador de tareas"
|
task-manager: "Navegador de tareas"
|
||||||
third-parties: "Servicios externos"
|
third-parties: "Servicios externos"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "Ver detalles..."
|
detail: "Ver detalles..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Perfil actualizado"
|
save: "Perfil actualizado"
|
||||||
locked-account: "Protege tu cuenta"
|
locked-account: "Protege tu cuenta"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -34,7 +34,7 @@ common:
|
|||||||
paragraph4: "Pour terminer la personnalisation, cliquez sur \"Terminer\" dans le coin supérieur droit."
|
paragraph4: "Pour terminer la personnalisation, cliquez sur \"Terminer\" dans le coin supérieur droit."
|
||||||
gotit: "Compris !"
|
gotit: "Compris !"
|
||||||
notification:
|
notification:
|
||||||
file-uploaded: "Le fichier a été téléversé !"
|
file-uploaded: "Le fichier a été transféré !"
|
||||||
message-from: "Message de {} :"
|
message-from: "Message de {} :"
|
||||||
reversi-invited: "Invité à jouer"
|
reversi-invited: "Invité à jouer"
|
||||||
reversi-invited-by: "Invité par {} :"
|
reversi-invited-by: "Invité par {} :"
|
||||||
@ -83,17 +83,17 @@ common:
|
|||||||
pudding: "Pudding"
|
pudding: "Pudding"
|
||||||
note-visibility:
|
note-visibility:
|
||||||
public: "Public"
|
public: "Public"
|
||||||
home: "Accueil"
|
home: "Principal"
|
||||||
home-desc: "Publier sur le fil local uniquement"
|
home-desc: "Publier sur le fil principal uniquement"
|
||||||
followers: "Abonnés·es"
|
followers: "Abonnés·es"
|
||||||
followers-desc: "Publier à vos abonnés·es uniquement"
|
followers-desc: "Publier à vos abonnés·es uniquement"
|
||||||
specified: "Direct"
|
specified: "Direct"
|
||||||
specified-desc: "Publier aux utilisateurs·trices mentionnés·es"
|
specified-desc: "Publier uniquement aux utilisateurs·rices mentionnés·es"
|
||||||
private: "Privé"
|
private: "Privé"
|
||||||
note-placeholders:
|
note-placeholders:
|
||||||
a: "Que faites-vous maintenant ?"
|
a: "Que faites-vous maintenant ?"
|
||||||
b: "Quoi de neuf ?"
|
b: "Quoi de neuf ?"
|
||||||
c: "Qu'avez-vous en tête ?"
|
c: "Qu’avez-vous en tête ?"
|
||||||
d: "Désirez-vous publier quelques mots ?"
|
d: "Désirez-vous publier quelques mots ?"
|
||||||
e: "Écrivez ici"
|
e: "Écrivez ici"
|
||||||
f: "En attente de vos écrits"
|
f: "En attente de vos écrits"
|
||||||
@ -103,7 +103,7 @@ common:
|
|||||||
ok: "OK"
|
ok: "OK"
|
||||||
update-available-title: "Mise à jour disponible"
|
update-available-title: "Mise à jour disponible"
|
||||||
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
|
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
|
||||||
my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté."
|
my-token-regenerated: "Votre jeton vient d’être généré, vous allez maintenant être déconnecté."
|
||||||
i-like-sushi: "Je préfère les sushis plutôt que le pudding"
|
i-like-sushi: "Je préfère les sushis plutôt que le pudding"
|
||||||
show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi"
|
show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi"
|
||||||
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
|
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
|
||||||
@ -120,7 +120,7 @@ common:
|
|||||||
my-turn: "C’est votre tour"
|
my-turn: "C’est votre tour"
|
||||||
opponent-turn: "Tour de l’adversaire"
|
opponent-turn: "Tour de l’adversaire"
|
||||||
turn-of: "C’est le tour de {}"
|
turn-of: "C’est le tour de {}"
|
||||||
past-turn-of: "C'est au tour de {}"
|
past-turn-of: "C’est au tour de {}"
|
||||||
won: "{} a gagné"
|
won: "{} a gagné"
|
||||||
black: "Noirs"
|
black: "Noirs"
|
||||||
white: "Blancs"
|
white: "Blancs"
|
||||||
@ -136,7 +136,7 @@ common:
|
|||||||
memo: "Pense-bête"
|
memo: "Pense-bête"
|
||||||
trends: "Tendances"
|
trends: "Tendances"
|
||||||
photo-stream: "Flux de photos"
|
photo-stream: "Flux de photos"
|
||||||
posts-monitor: "Graphe des publications"
|
posts-monitor: "Graph des publications"
|
||||||
slideshow: "Diaporama"
|
slideshow: "Diaporama"
|
||||||
version: "Version"
|
version: "Version"
|
||||||
broadcast: "Diffusion"
|
broadcast: "Diffusion"
|
||||||
@ -267,8 +267,8 @@ common/views/components/media-banner.vue:
|
|||||||
common/views/components/theme.vue:
|
common/views/components/theme.vue:
|
||||||
light-theme: "非ダークモード時に使用するテーマ"
|
light-theme: "非ダークモード時に使用するテーマ"
|
||||||
dark-theme: "ダークモード時に使用するテーマ"
|
dark-theme: "ダークモード時に使用するテーマ"
|
||||||
light-themes: "明るいテーマ"
|
light-themes: "Thème clair"
|
||||||
dark-themes: "暗いテーマ"
|
dark-themes: "Thème sombre"
|
||||||
install-a-theme: "Installer un thème"
|
install-a-theme: "Installer un thème"
|
||||||
theme-code: "Code du thème"
|
theme-code: "Code du thème"
|
||||||
install: "Installation"
|
install: "Installation"
|
||||||
@ -286,16 +286,16 @@ common/views/components/theme.vue:
|
|||||||
invalid-theme: "Thème n’est pas valide."
|
invalid-theme: "Thème n’est pas valide."
|
||||||
already-installed: "Le thème est déjà installé."
|
already-installed: "Le thème est déjà installé."
|
||||||
saved: "enregistré"
|
saved: "enregistré"
|
||||||
manage-themes: "テーマの管理"
|
manage-themes: "Gestion des thèmes"
|
||||||
builtin-themes: "標準テーマ"
|
builtin-themes: "Thèmes standards"
|
||||||
my-themes: "マイテーマ"
|
my-themes: "Mes thèmes"
|
||||||
installed-themes: "Thèmes installés"
|
installed-themes: "Thèmes installés"
|
||||||
select-theme: "Veuillez sélectionner un thème"
|
select-theme: "Veuillez sélectionner un thème"
|
||||||
uninstall: "Désinstaller"
|
uninstall: "Désinstaller"
|
||||||
uninstalled: "« {} » a été désinstallé"
|
uninstalled: "« {} » a été désinstallé"
|
||||||
author: "Auteur"
|
author: "Auteur"
|
||||||
desc: "Description"
|
desc: "Description"
|
||||||
export: "エクスポート"
|
export: "Exporter"
|
||||||
import: "Importer"
|
import: "Importer"
|
||||||
import-by-code: "Ou coller du code"
|
import-by-code: "Ou coller du code"
|
||||||
theme-name-required: "Nom du thème est obligatoire."
|
theme-name-required: "Nom du thème est obligatoire."
|
||||||
@ -329,12 +329,13 @@ common/views/components/nav.vue:
|
|||||||
wiki: "Wiki"
|
wiki: "Wiki"
|
||||||
donors: "Donateur·rice·s"
|
donors: "Donateur·rice·s"
|
||||||
repository: "Dépôt"
|
repository: "Dépôt"
|
||||||
develop: "Développeur·se·s"
|
develop: "Développeurs"
|
||||||
feedback: "Remarques"
|
feedback: "Suggestions"
|
||||||
common/views/components/note-menu.vue:
|
common/views/components/note-menu.vue:
|
||||||
detail: "Détails"
|
detail: "Détails"
|
||||||
copy-link: "Copier le lien"
|
copy-link: "Copier le lien"
|
||||||
favorite: "Mettre cette note en favoris"
|
favorite: "Mettre cette note en favoris"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "Épingler sur votre profil"
|
pin: "Épingler sur votre profil"
|
||||||
unpin: "Désépingler"
|
unpin: "Désépingler"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
@ -410,10 +411,10 @@ common/views/components/visibility-chooser.vue:
|
|||||||
followers: "Abonné·e·s"
|
followers: "Abonné·e·s"
|
||||||
followers-desc: "Publier à vos abonné·e·s uniquement"
|
followers-desc: "Publier à vos abonné·e·s uniquement"
|
||||||
specified: "Direct"
|
specified: "Direct"
|
||||||
specified-desc: "Publier aux utilisateur·rice·s mentionné·e·s"
|
specified-desc: "Publier uniquement aux utilisateurs·rices mentionné·e·s"
|
||||||
private: "Privé"
|
private: "Privé"
|
||||||
common/views/components/trends.vue:
|
common/views/components/trends.vue:
|
||||||
count: "{} utilisateurs·trices mentionnés·es"
|
count: "{} utilisateurs·rices mentionnés·es"
|
||||||
empty: "Aucune tendance"
|
empty: "Aucune tendance"
|
||||||
common/views/widgets/broadcast.vue:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Récupération"
|
fetching: "Récupération"
|
||||||
@ -434,7 +435,7 @@ common/views/widgets/photo-stream.vue:
|
|||||||
title: "Flux de photos"
|
title: "Flux de photos"
|
||||||
no-photos: "Pas de photo"
|
no-photos: "Pas de photo"
|
||||||
common/views/widgets/posts-monitor.vue:
|
common/views/widgets/posts-monitor.vue:
|
||||||
title: "Graphe des publications"
|
title: "Graph des publications"
|
||||||
toggle: "Basculer entre les vues"
|
toggle: "Basculer entre les vues"
|
||||||
common/views/widgets/hashtags.vue:
|
common/views/widgets/hashtags.vue:
|
||||||
title: "Hashtags"
|
title: "Hashtags"
|
||||||
@ -514,7 +515,7 @@ desktop/views/components/charts.vue:
|
|||||||
notes: "投稿の増減 (統合)"
|
notes: "投稿の増減 (統合)"
|
||||||
local-notes: "投稿の増減 (ローカル)"
|
local-notes: "投稿の増減 (ローカル)"
|
||||||
remote-notes: "投稿の増減 (リモート)"
|
remote-notes: "投稿の増減 (リモート)"
|
||||||
notes-total: "投稿の積算"
|
notes-total: "Total des notes"
|
||||||
users: "Nombre d’utilisateurs·trices : augmentation/diminution"
|
users: "Nombre d’utilisateurs·trices : augmentation/diminution"
|
||||||
users-total: "ユーザーの積算"
|
users-total: "ユーザーの積算"
|
||||||
drive: "ドライブ使用量の増減"
|
drive: "ドライブ使用量の増減"
|
||||||
@ -582,7 +583,7 @@ desktop/views/components/drive.vue:
|
|||||||
unable-to-process: "L'opération n'a pas pu être complétée"
|
unable-to-process: "L'opération n'a pas pu être complétée"
|
||||||
circular-reference-detected: "Le dossier de destination est un sous-dossier du dossier que vous souhaitez déplacer."
|
circular-reference-detected: "Le dossier de destination est un sous-dossier du dossier que vous souhaitez déplacer."
|
||||||
unhandled-error: "Erreur inconnue"
|
unhandled-error: "Erreur inconnue"
|
||||||
url-upload: "Uploader d'un URL"
|
url-upload: "Téléverser via une URL"
|
||||||
url-of-file: "URL de l'image que vous souhaitez uploader."
|
url-of-file: "URL de l'image que vous souhaitez uploader."
|
||||||
url-upload-requested: "Upload requested"
|
url-upload-requested: "Upload requested"
|
||||||
may-take-time: "L'upload de votre fichier peut prendre un certain temps."
|
may-take-time: "L'upload de votre fichier peut prendre un certain temps."
|
||||||
@ -590,8 +591,8 @@ desktop/views/components/drive.vue:
|
|||||||
folder-name: "Nom du dossier"
|
folder-name: "Nom du dossier"
|
||||||
contextmenu:
|
contextmenu:
|
||||||
create-folder: "Créer un dossier"
|
create-folder: "Créer un dossier"
|
||||||
upload: "Uploader un fichier"
|
upload: "Transférer un fichier"
|
||||||
url-upload: "Uploader d'un URL"
|
url-upload: "Transférer à partir d’une URL"
|
||||||
desktop/views/components/media-image.vue:
|
desktop/views/components/media-image.vue:
|
||||||
sensitive: "Le contenu est NSFW"
|
sensitive: "Le contenu est NSFW"
|
||||||
click-to-show: "Cliquer pour afficher"
|
click-to-show: "Cliquer pour afficher"
|
||||||
@ -658,21 +659,21 @@ desktop/views/components/post-form.vue:
|
|||||||
add-visible-user: "+Ajouter un utilisateur"
|
add-visible-user: "+Ajouter un utilisateur"
|
||||||
attach-location-information: "Attacher des informations de localisation"
|
attach-location-information: "Attacher des informations de localisation"
|
||||||
hide-contents: "Masquer les contenus"
|
hide-contents: "Masquer les contenus"
|
||||||
reply-placeholder: "Répondre à cette note"
|
reply-placeholder: "Répondre à cette note …"
|
||||||
quote-placeholder: "Citer cette note"
|
quote-placeholder: "Citer cette note …"
|
||||||
submit: "Poster"
|
submit: "Publier"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
renote: "Republier"
|
renote: "Republier"
|
||||||
posted: "Posté!"
|
posted: "Publié !"
|
||||||
replied: "Répondu !"
|
replied: "Répondu !"
|
||||||
reposted: "Reposté !"
|
reposted: "Reposté !"
|
||||||
note-failed: "La note à échoué"
|
note-failed: "La note à échoué"
|
||||||
reply-failed: "La réponse à échoué"
|
reply-failed: "La réponse à échoué"
|
||||||
renote-failed: "La renote à échoué"
|
renote-failed: "Échec lors de la republication"
|
||||||
posting: "Publication..."
|
posting: "Publication …"
|
||||||
attach-media-from-local: "Joindre un media depuis votre PC"
|
attach-media-from-local: "Joindre un média depuis votre appareil"
|
||||||
attach-media-from-drive: "Joindre un media depuis votre Drive"
|
attach-media-from-drive: "Joindre un média depuis votre Drive"
|
||||||
attach-cancel: "Annuler la jointure de fichier"
|
attach-cancel: "Annuler le fichier attaché"
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "Créer un sondage"
|
create-poll: "Créer un sondage"
|
||||||
text-remain: "{} charactères restants"
|
text-remain: "{} charactères restants"
|
||||||
@ -687,15 +688,15 @@ desktop/views/components/post-form-window.vue:
|
|||||||
note: "Nouvelle note"
|
note: "Nouvelle note"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
attaches: "{} media joint(s)"
|
attaches: "{} media joint(s)"
|
||||||
uploading-media: "Upload du media {}"
|
uploading-media: "Transfert du média {}"
|
||||||
desktop/views/components/progress-dialog.vue:
|
desktop/views/components/progress-dialog.vue:
|
||||||
waiting: "En attente"
|
waiting: "En attente"
|
||||||
desktop/views/components/renote-form.vue:
|
desktop/views/components/renote-form.vue:
|
||||||
quote: "Citer..."
|
quote: "Citer..."
|
||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
renote: "Republier"
|
renote: "Republier"
|
||||||
reposting: "Repost en cours..."
|
reposting: "Republication en cours …"
|
||||||
success: "Reposté!"
|
success: "Republié !"
|
||||||
failure: "La renote a échoué"
|
failure: "La renote a échoué"
|
||||||
desktop/views/components/renote-form-window.vue:
|
desktop/views/components/renote-form-window.vue:
|
||||||
title: "Êtes vous sûr de vouloir renote cette note?"
|
title: "Êtes vous sûr de vouloir renote cette note?"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Outils"
|
tools: "Outils"
|
||||||
task-manager: "Gestionnaire de tâches"
|
task-manager: "Gestionnaire de tâches"
|
||||||
third-parties: "Services tiers"
|
third-parties: "Services tiers"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "Si vous configurez la vérication en deux étapes vous aurez non seulement besoin de votre mot de passe mais aussi un appareil déjà pré-enregistré(tel que votre smartphone) ce qui ameliora grandement la sécurité de votre compte."
|
intro: "Si vous configurez la vérication en deux étapes vous aurez non seulement besoin de votre mot de passe mais aussi un appareil déjà pré-enregistré(tel que votre smartphone) ce qui ameliora grandement la sécurité de votre compte."
|
||||||
detail: "Voir les détails..."
|
detail: "Voir les détails..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Mettre à jour le profil"
|
save: "Mettre à jour le profil"
|
||||||
locked-account: "Protéger votre compte"
|
locked-account: "Protéger votre compte"
|
||||||
is-locked: "Demande d’abonnement en attente d’approbation"
|
is-locked: "Demande d’abonnement en attente d’approbation"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "Autre"
|
other: "Autre"
|
||||||
is-bot: "Ce compte est un Bot"
|
is-bot: "Ce compte est un Bot"
|
||||||
is-cat: "Ce compte est un Chat"
|
is-cat: "Ce compte est un Chat"
|
||||||
@ -858,7 +864,7 @@ desktop/views/components/timeline.vue:
|
|||||||
list-name: "Nom de la liste"
|
list-name: "Nom de la liste"
|
||||||
desktop/views/components/ui.header.vue:
|
desktop/views/components/ui.header.vue:
|
||||||
welcome-back: "Content de vous revoir !"
|
welcome-back: "Content de vous revoir !"
|
||||||
adjective: "さん"
|
adjective: "M."
|
||||||
desktop/views/components/ui.header.account.vue:
|
desktop/views/components/ui.header.account.vue:
|
||||||
profile: "Votre profil"
|
profile: "Votre profil"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
@ -878,7 +884,7 @@ desktop/views/components/ui.header.nav.vue:
|
|||||||
desktop/views/components/ui.header.notifications.vue:
|
desktop/views/components/ui.header.notifications.vue:
|
||||||
title: "Notifications"
|
title: "Notifications"
|
||||||
desktop/views/components/ui.header.post.vue:
|
desktop/views/components/ui.header.post.vue:
|
||||||
post: "Composer un nouveau post"
|
post: "Rédiger une nouvelle publication"
|
||||||
desktop/views/components/ui.header.search.vue:
|
desktop/views/components/ui.header.search.vue:
|
||||||
placeholder: "Chercher"
|
placeholder: "Chercher"
|
||||||
desktop/views/components/received-follow-requests-window.vue:
|
desktop/views/components/received-follow-requests-window.vue:
|
||||||
@ -911,9 +917,9 @@ desktop/views/pages/admin/admin.vue:
|
|||||||
desktop/views/pages/admin/admin.dashboard.vue:
|
desktop/views/pages/admin/admin.dashboard.vue:
|
||||||
dashboard: "Tableau de bord"
|
dashboard: "Tableau de bord"
|
||||||
all-users: "Toutes les utilisateurrices"
|
all-users: "Toutes les utilisateurrices"
|
||||||
original-users: "Utilisateurrices sur cette instance"
|
original-users: "Utilisateur·rice·s sur cette instance"
|
||||||
all-notes: "Toutes les publications"
|
all-notes: "Toutes les publications"
|
||||||
original-notes: "Publication sur cette instance"
|
original-notes: "Publications sur cette instance"
|
||||||
invite: "Invitation"
|
invite: "Invitation"
|
||||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||||
suspend-user: "Suspendre un·e utilisateur·rice"
|
suspend-user: "Suspendre un·e utilisateur·rice"
|
||||||
@ -941,9 +947,9 @@ desktop/views/pages/deck/deck.note.vue:
|
|||||||
deleted: "cette publication a été supprimée"
|
deleted: "cette publication a été supprimée"
|
||||||
desktop/views/pages/stats/stats.vue:
|
desktop/views/pages/stats/stats.vue:
|
||||||
all-users: "Toutes les utilisateurrices"
|
all-users: "Toutes les utilisateurrices"
|
||||||
original-users: "Utilisateurrices sur cette instance"
|
original-users: "Utilisateur·rice·s sur cette instance"
|
||||||
all-notes: "Toutes les publications"
|
all-notes: "Toutes les publications"
|
||||||
original-notes: "Publication sur cette instance"
|
original-notes: "Publications sur cette instance"
|
||||||
desktop/views/pages/welcome.vue:
|
desktop/views/pages/welcome.vue:
|
||||||
about: "à propos"
|
about: "à propos"
|
||||||
gotit: "J'ai compris !"
|
gotit: "J'ai compris !"
|
||||||
@ -969,7 +975,7 @@ desktop/views/pages/selectdrive.vue:
|
|||||||
title: "Choisir fichier(s)"
|
title: "Choisir fichier(s)"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
upload: "Uploader un ou plusieurs fichier(s) depuis votre PC"
|
upload: "Téléverser des fichiers à partir de votre ordinateur"
|
||||||
desktop/views/pages/search.vue:
|
desktop/views/pages/search.vue:
|
||||||
not-available: "La fonction de recherche est désactivée dans les paramètres de l’instance."
|
not-available: "La fonction de recherche est désactivée dans les paramètres de l’instance."
|
||||||
not-found: "Aucun message trouvé pour '{}'"
|
not-found: "Aucun message trouvé pour '{}'"
|
||||||
@ -986,13 +992,13 @@ desktop/views/pages/user/user.followers-you-know.vue:
|
|||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
no-users: "Pas d'utilisateurs"
|
no-users: "Pas d'utilisateurs"
|
||||||
desktop/views/pages/user/user.friends.vue:
|
desktop/views/pages/user/user.friends.vue:
|
||||||
title: "Personnes qui répondent le plus"
|
title: "Mentions fréquentes"
|
||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
no-users: "Pas d'utilisateurs"
|
no-users: "Pas d'utilisateurs"
|
||||||
desktop/views/pages/user/user.vue:
|
desktop/views/pages/user/user.vue:
|
||||||
is-suspended: "Ce compte a été suspendu."
|
is-suspended: "Ce compte a été suspendu."
|
||||||
is-remote: "Cet utilisateur n'est pas un utilisateur de Misskey. Certaines informations peuvent être erronées"
|
is-remote: "Cet utilisateur n'est pas un utilisateur Misskey. Certaines informations peuvent ne pas refléter ce profil dans sa totalité."
|
||||||
view-remote: "Voir les informations détaillées"
|
view-remote: "Consulter le profil complet"
|
||||||
desktop/views/pages/user/user.home.vue:
|
desktop/views/pages/user/user.home.vue:
|
||||||
last-used-at: "Last used at"
|
last-used-at: "Last used at"
|
||||||
desktop/views/pages/user/user.photos.vue:
|
desktop/views/pages/user/user.photos.vue:
|
||||||
@ -1000,7 +1006,7 @@ desktop/views/pages/user/user.photos.vue:
|
|||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
no-photos: "Pas de photos"
|
no-photos: "Pas de photos"
|
||||||
desktop/views/pages/user/user.profile.vue:
|
desktop/views/pages/user/user.profile.vue:
|
||||||
follows-you: "Vous suis"
|
follows-you: "Vous suit"
|
||||||
stalk: "Traquer"
|
stalk: "Traquer"
|
||||||
stalking: "ストーキングしています"
|
stalking: "ストーキングしています"
|
||||||
unstalk: "ストーク解除"
|
unstalk: "ストーク解除"
|
||||||
@ -1029,8 +1035,8 @@ desktop/views/widgets/polls.vue:
|
|||||||
refresh: "Afficher d'autres"
|
refresh: "Afficher d'autres"
|
||||||
nothing: "Rien"
|
nothing: "Rien"
|
||||||
desktop/views/widgets/post-form.vue:
|
desktop/views/widgets/post-form.vue:
|
||||||
title: "Post"
|
title: "Publication"
|
||||||
note: "Post"
|
note: "Publication"
|
||||||
desktop/views/widgets/profile.vue:
|
desktop/views/widgets/profile.vue:
|
||||||
update-banner: "Cliquer pour éditer votre bannière"
|
update-banner: "Cliquer pour éditer votre bannière"
|
||||||
update-avatar: "Cliquer pour éditer votre avatar"
|
update-avatar: "Cliquer pour éditer votre avatar"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "Hash (md5)"
|
hash: "Hash (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "CW"
|
nsfw: "CW"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "Le contenu est NSFW"
|
sensitive: "Le contenu est NSFW"
|
||||||
click-to-show: "Cliquer pour afficher"
|
click-to-show: "Cliquer pour afficher"
|
||||||
@ -1092,7 +1100,7 @@ mobile/views/components/friends-maker.vue:
|
|||||||
refresh: "Voir plus"
|
refresh: "Voir plus"
|
||||||
close: "Fermer"
|
close: "Fermer"
|
||||||
mobile/views/components/note.vue:
|
mobile/views/components/note.vue:
|
||||||
reposted-by: "Renoté par {}"
|
reposted-by: "Republié par {}"
|
||||||
private: "cette publication est privée"
|
private: "cette publication est privée"
|
||||||
deleted: "cette publication a été supprimée"
|
deleted: "cette publication a été supprimée"
|
||||||
location: "Géolocalisation"
|
location: "Géolocalisation"
|
||||||
@ -1119,7 +1127,7 @@ mobile/views/components/notifications.vue:
|
|||||||
empty: "Pas de notifications"
|
empty: "Pas de notifications"
|
||||||
mobile/views/components/post-form.vue:
|
mobile/views/components/post-form.vue:
|
||||||
add-visible-user: "Ajouter un utilisateur"
|
add-visible-user: "Ajouter un utilisateur"
|
||||||
submit: "Poster"
|
submit: "Publier"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
renote: "Republier"
|
renote: "Republier"
|
||||||
quote-placeholder: "Citer ce billet ... (Facultatif)"
|
quote-placeholder: "Citer ce billet ... (Facultatif)"
|
||||||
@ -1171,7 +1179,7 @@ mobile/views/pages/drive.vue:
|
|||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
more: "Afficher plus ..."
|
more: "Afficher plus ..."
|
||||||
mobile/views/pages/signup.vue:
|
mobile/views/pages/signup.vue:
|
||||||
lets-start: "Commençons ! 📦"
|
lets-start: "Votre compte est prêt ! 📦"
|
||||||
mobile/views/pages/followers.vue:
|
mobile/views/pages/followers.vue:
|
||||||
followers-of: "Abonné·e·s de {}"
|
followers-of: "Abonné·e·s de {}"
|
||||||
mobile/views/pages/following.vue:
|
mobile/views/pages/following.vue:
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Bannière"
|
banner: "Bannière"
|
||||||
is-cat: "Ce compte est un Bot"
|
is-cat: "Ce compte est un Bot"
|
||||||
is-locked: "Demande d’abonnement en attente d’approbation"
|
is-locked: "Demande d’abonnement en attente d’approbation"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "Avancé"
|
advanced: "Avancé"
|
||||||
privacy: "Vie privée"
|
privacy: "Vie privée"
|
||||||
save: "Mettre à jour le profil"
|
save: "Mettre à jour le profil"
|
||||||
@ -1286,7 +1295,7 @@ mobile/views/pages/settings.vue:
|
|||||||
sound: "Sons"
|
sound: "Sons"
|
||||||
enable-sounds: "Activer les sons"
|
enable-sounds: "Activer les sons"
|
||||||
mobile/views/pages/user.vue:
|
mobile/views/pages/user.vue:
|
||||||
follows-you: "vous suit"
|
follows-you: "Vous suit"
|
||||||
following: "Abonnements"
|
following: "Abonnements"
|
||||||
followers: "Abonné·e·s"
|
followers: "Abonné·e·s"
|
||||||
notes: "Notes"
|
notes: "Notes"
|
||||||
@ -1294,8 +1303,8 @@ mobile/views/pages/user.vue:
|
|||||||
timeline: "Fil d'actualité"
|
timeline: "Fil d'actualité"
|
||||||
media: "Media"
|
media: "Media"
|
||||||
is-suspended: "This account has been suspended."
|
is-suspended: "This account has been suspended."
|
||||||
is-remote: "Cet utilisateur n'est pas un utilisateur de Misskey. Certaines informations peuvent être erronées "
|
is-remote: "Ceci est le profil d’un utilisateur·rice distant·e. Certaines informations peuvent ne pas refléter ce profil dans sa totalité."
|
||||||
view-remote: "Voir les informations détaillées"
|
view-remote: "Consulter son profil complet"
|
||||||
mobile/views/pages/user/home.vue:
|
mobile/views/pages/user/home.vue:
|
||||||
recent-notes: "Notes récentes"
|
recent-notes: "Notes récentes"
|
||||||
images: "Images"
|
images: "Images"
|
||||||
@ -1319,7 +1328,7 @@ mobile/views/pages/user/home.photos.vue:
|
|||||||
no-photos: "Pas de photos"
|
no-photos: "Pas de photos"
|
||||||
docs:
|
docs:
|
||||||
edit-this-page-on-github: "Vous avez trouvé une erreur ou vous voulez contribuer à la documentation?"
|
edit-this-page-on-github: "Vous avez trouvé une erreur ou vous voulez contribuer à la documentation?"
|
||||||
edit-this-page-on-github-link: "Modifiez cette page sur github!"
|
edit-this-page-on-github-link: "Éditez cette page sur Github !"
|
||||||
api:
|
api:
|
||||||
entities:
|
entities:
|
||||||
properties: "Propriétés"
|
properties: "Propriétés"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -363,6 +363,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -882,6 +883,11 @@ desktop/views/components/settings.vue:
|
|||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
|
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -937,6 +943,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1232,6 +1239,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
|
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
@ -1419,6 +1428,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -265,40 +265,40 @@ common/views/components/media-banner.vue:
|
|||||||
sensitive: "見せたらあかん"
|
sensitive: "見せたらあかん"
|
||||||
click-to-show: "押してみ、見せたるわ"
|
click-to-show: "押してみ、見せたるわ"
|
||||||
common/views/components/theme.vue:
|
common/views/components/theme.vue:
|
||||||
light-theme: "非ダークモード時に使用するテーマ"
|
light-theme: "ナイトゲームちゃう時のテーマどないする?"
|
||||||
dark-theme: "ダークモード時に使用するテーマ"
|
dark-theme: "ナイトゲームの時のテーマどないする?"
|
||||||
light-themes: "明るいテーマ"
|
light-themes: "デイゲーム"
|
||||||
dark-themes: "暗いテーマ"
|
dark-themes: "ナイトゲーム"
|
||||||
install-a-theme: "テーマのインストール"
|
install-a-theme: "テーマ入れるで"
|
||||||
theme-code: "テーマコード"
|
theme-code: "テーマコード"
|
||||||
install: "インストール"
|
install: "インストール"
|
||||||
installed: "「{}」をインストールしました"
|
installed: "「{}」を入れたで!"
|
||||||
create-a-theme: "テーマの作成"
|
create-a-theme: "テーマ作る"
|
||||||
save-created-theme: "テーマを保存"
|
save-created-theme: "テーマ保存"
|
||||||
primary-color: "プライマリ カラー"
|
primary-color: "この色一番重要や"
|
||||||
secondary-color: "セカンダリ カラー"
|
secondary-color: "次はこの色出したって"
|
||||||
text-color: "文字色"
|
text-color: "文字はこの色や!"
|
||||||
base-theme: "ベーステーマ"
|
base-theme: "この色が背景や!"
|
||||||
base-theme-light: "Light"
|
base-theme-light: "Light"
|
||||||
base-theme-dark: "Dark"
|
base-theme-dark: "Dark"
|
||||||
theme-name: "テーマ名"
|
theme-name: "テーマ名"
|
||||||
preview-created-theme: "プレビュー"
|
preview-created-theme: "試してみる"
|
||||||
invalid-theme: "テーマが正しくありません。"
|
invalid-theme: "このテーマあかんわ、なんか間違うとる"
|
||||||
already-installed: "既にそのテーマはインストールされています。"
|
already-installed: "このテーマもうあるで"
|
||||||
saved: "保存しました"
|
saved: "保存したで!"
|
||||||
manage-themes: "テーマの管理"
|
manage-themes: "テーマの管理"
|
||||||
builtin-themes: "標準テーマ"
|
builtin-themes: "いつものテーマ"
|
||||||
my-themes: "マイテーマ"
|
my-themes: "ワイのテーマ"
|
||||||
installed-themes: "インストールされたテーマ"
|
installed-themes: "入れたテーマ"
|
||||||
select-theme: "テーマを選択してください"
|
select-theme: "テーマ選んでや!"
|
||||||
uninstall: "アンインストール"
|
uninstall: "ほかす"
|
||||||
uninstalled: "「{}」をアンインストールしました"
|
uninstalled: "「{}」をほかしてもうたわ"
|
||||||
author: "作者"
|
author: "作った人"
|
||||||
desc: "説明"
|
desc: "説明"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
import: "インポート"
|
import: "インポート"
|
||||||
import-by-code: "またはコードをペースト"
|
import-by-code: "それかコードを貼っつける"
|
||||||
theme-name-required: "テーマ名は必須です。"
|
theme-name-required: "テーマ名は絶対要るで"
|
||||||
common/views/components/cw-button.vue:
|
common/views/components/cw-button.vue:
|
||||||
hide: "もうええわ"
|
hide: "もうええわ"
|
||||||
show: "見たいやろ?"
|
show: "見たいやろ?"
|
||||||
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "もっと"
|
detail: "もっと"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入りやめる"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留めやめる"
|
unpin: "ピン留めやめる"
|
||||||
delete: "ほかす"
|
delete: "ほかす"
|
||||||
@ -475,7 +476,7 @@ common/views/pages/follow.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
follow-processing: "フォロー処理中"
|
follow-processing: "今フォロー処理やっとる‥"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
desktop:
|
desktop:
|
||||||
banner-crop-title: "どこバナーとして出す?"
|
banner-crop-title: "どこバナーとして出す?"
|
||||||
@ -602,7 +603,7 @@ desktop/views/components/follow-button.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
follow-processing: "フォロー処理中"
|
follow-processing: "今フォロー処理やっとる‥"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけとちゃうくて、予め登録しておいた物理的なデバイス(例えばあんさんのスマートフォンなど)も必要になり、よりセキュリティが向上すんで。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけとちゃうくて、予め登録しておいた物理的なデバイス(例えばあんさんのスマートフォンなど)も必要になり、よりセキュリティが向上すんで。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウント守る"
|
locked-account: "アカウント守る"
|
||||||
is-locked: "他人のフォローは許可してからや!"
|
is-locked: "他人のフォローは許可してからや!"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotやで"
|
is-bot: "このアカウントはBotやで"
|
||||||
is-cat: "このアカウントはCatやで"
|
is-cat: "このアカウントはCatやで"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ(md5)"
|
hash: "ハッシュ(md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "ちょっと見せられへんわ"
|
nsfw: "ちょっと見せられへんわ"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "見たらあかんで"
|
sensitive: "見たらあかんで"
|
||||||
click-to-show: "押してみ、見せたるわ"
|
click-to-show: "押してみ、見せたるわ"
|
||||||
@ -1083,7 +1091,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォローしとる"
|
following: "フォローしとる"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
request-pending: "フォローの許し待っとる"
|
request-pending: "フォローの許し待っとる"
|
||||||
follow-processing: "フォロー処理中"
|
follow-processing: "今フォロー処理やっとる‥"
|
||||||
follow-request: "フォロー許してくれや!言うてみる"
|
follow-request: "フォロー許してくれや!言うてみる"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "おもろそうやな"
|
title: "おもろそうやな"
|
||||||
@ -1223,9 +1231,10 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
avatar: "アイコン"
|
avatar: "アイコン"
|
||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatや"
|
is-cat: "このアカウントはCatや"
|
||||||
is-locked: "他人のフォローは許してからや!"
|
is-locked: "他人のフォローは許可してからや!"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー⇔オカンの年齢"
|
privacy: "プライバシーってなんや?オカンの年齢か?"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
saved: "プロフィールを保存したで"
|
saved: "プロフィールを保存したで"
|
||||||
uploading: "アップロードしとるで…"
|
uploading: "アップロードしとるで…"
|
||||||
@ -1245,7 +1254,7 @@ mobile/views/pages/settings.vue:
|
|||||||
specify-language: "言語選びや"
|
specify-language: "言語選びや"
|
||||||
design: "見た感じ"
|
design: "見た感じ"
|
||||||
dark-mode: "ナイトゲームや!"
|
dark-mode: "ナイトゲームや!"
|
||||||
i-am-under-limited-internet: "電波がバァーっといけへんねん"
|
i-am-under-limited-internet: "電波と阪神がザコいんや"
|
||||||
circle-icons: "アイコンもタコ焼きも丸いやんな?"
|
circle-icons: "アイコンもタコ焼きも丸いやんな?"
|
||||||
contrasted-acct: "ユーザー名ようわからんし見やすしといて"
|
contrasted-acct: "ユーザー名ようわからんし見やすしといて"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
@ -1257,8 +1266,8 @@ mobile/views/pages/settings.vue:
|
|||||||
post-style-standard: "標準"
|
post-style-standard: "標準"
|
||||||
post-style-smart: "べっぴんさん"
|
post-style-smart: "べっぴんさん"
|
||||||
notification-position: "通知どこ見せる?"
|
notification-position: "通知どこ見せる?"
|
||||||
notification-position-bottom: "ミナミ"
|
notification-position-bottom: "ミナミの方"
|
||||||
notification-position-top: "キタ"
|
notification-position-top: "キタの方"
|
||||||
theme: "テーマ"
|
theme: "テーマ"
|
||||||
behavior: "動き"
|
behavior: "動き"
|
||||||
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
fetch-on-scroll: "スクロールしたらもっと見せてや"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "링크 복사"
|
copy-link: "링크 복사"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Deze notitie toevoegen aan favorieten"
|
favorite: "Deze notitie toevoegen aan favorieten"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "Vastmaken aan profielpagina"
|
pin: "Vastmaken aan profielpagina"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Hulpmiddelen"
|
tools: "Hulpmiddelen"
|
||||||
task-manager: "Taakbeheer"
|
task-manager: "Taakbeheer"
|
||||||
third-parties: "Derde partij"
|
third-parties: "Derde partij"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "Als je verificatie in twee stappen instelt, dan heb je niet alleen een wachtwoord nodig bij het inloggen, maar ook een geregistreerd fysiek apparaat (zoals je smartphone). Dit verhoogt de veiligheid. "
|
intro: "Als je verificatie in twee stappen instelt, dan heb je niet alleen een wachtwoord nodig bij het inloggen, maar ook een geregistreerd fysiek apparaat (zoals je smartphone). Dit verhoogt de veiligheid. "
|
||||||
detail: "Details bekijken..."
|
detail: "Details bekijken..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Profiel bijwerken"
|
save: "Profiel bijwerken"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "Dit account is een Bot"
|
is-bot: "Dit account is een Bot"
|
||||||
is-cat: "Dit account is een Kat"
|
is-cat: "Dit account is een Kat"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "Hash (md5)"
|
hash: "Hash (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Omslagfoto"
|
banner: "Omslagfoto"
|
||||||
is-cat: "Dit account is een Kat"
|
is-cat: "Dit account is een Kat"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "Profiel bijwerken"
|
save: "Profiel bijwerken"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "Detaljer"
|
detail: "Detaljer"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Merket som favoritt"
|
favorite: "Merket som favoritt"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "Fest til profilen din"
|
pin: "Fest til profilen din"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Slett"
|
delete: "Slett"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Verktøy"
|
tools: "Verktøy"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "Detaljer..."
|
detail: "Detaljer..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Lagre profilen"
|
save: "Lagre profilen"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "Annet"
|
other: "Annet"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "NSFW"
|
nsfw: "NSFW"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "NSFW"
|
sensitive: "NSFW"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Banner"
|
banner: "Banner"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "Avansert"
|
advanced: "Avansert"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "Lagre profilen"
|
save: "Lagre profilen"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Dodaj do ulubionych"
|
favorite: "Dodaj do ulubionych"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "Przypnij do profilu"
|
pin: "Przypnij do profilu"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Usuń"
|
delete: "Usuń"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "Narzędzia"
|
tools: "Narzędzia"
|
||||||
task-manager: "Menedżer zadań"
|
task-manager: "Menedżer zadań"
|
||||||
third-parties: "Autorzy trzeci"
|
third-parties: "Autorzy trzeci"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "Jeżeli skonfigurujesz uwierzytelnianie dwuetapowe, aby zablokować się będziesz potrzebować (oprócz hasła) kodu ze skonfigurowanego urządzenia (np. smartfonu), co zwiększy bezpieczeństwo."
|
intro: "Jeżeli skonfigurujesz uwierzytelnianie dwuetapowe, aby zablokować się będziesz potrzebować (oprócz hasła) kodu ze skonfigurowanego urządzenia (np. smartfonu), co zwiększy bezpieczeństwo."
|
||||||
detail: "Zobacz szczegóły…"
|
detail: "Zobacz szczegóły…"
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "Aktualizuj profil"
|
save: "Aktualizuj profil"
|
||||||
locked-account: "Zabezpiecz swoje konto"
|
locked-account: "Zabezpiecz swoje konto"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "Inne"
|
other: "Inne"
|
||||||
is-bot: "To konto jest prowadzone przez bota"
|
is-bot: "To konto jest prowadzone przez bota"
|
||||||
is-cat: "To konto jest prowadzone przez kota"
|
is-cat: "To konto jest prowadzone przez kota"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "Hash (md5)"
|
hash: "Hash (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "To jest zawartość NSFW"
|
sensitive: "To jest zawartość NSFW"
|
||||||
click-to-show: "Naciśnij aby wyświetlić"
|
click-to-show: "Naciśnij aby wyświetlić"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Baner"
|
banner: "Baner"
|
||||||
is-cat: "To konto jest prowadzone przez kota"
|
is-cat: "To konto jest prowadzone przez kota"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "Aktualizuj profil"
|
save: "Aktualizuj profil"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "Capa"
|
banner: "Capa"
|
||||||
is-cat: "Esta conta é gato"
|
is-cat: "Esta conta é gato"
|
||||||
is-locked: "Pedido para seguir precisa ser aprovado"
|
is-locked: "Pedido para seguir precisa ser aprovado"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "Avançado"
|
advanced: "Avançado"
|
||||||
privacy: "Provacidade"
|
privacy: "Provacidade"
|
||||||
save: "Atualizar perfil"
|
save: "Atualizar perfil"
|
||||||
|
@ -3,9 +3,9 @@ meta:
|
|||||||
lang: "Русский язык"
|
lang: "Русский язык"
|
||||||
divider: ""
|
divider: ""
|
||||||
common:
|
common:
|
||||||
misskey: "A ⭐ of fediverse"
|
misskey: "Мы — ⭐ fediverse"
|
||||||
about-title: "A ⭐ of fediverse."
|
about-title: "Мы — ⭐ fediverse"
|
||||||
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
about: "Спасибо, что нашли Misskey. Misskey — это <b>децентрализованная платформа для микроблоггинга</b> родом с планеты Земля. Поскольку она существует внутри Fediverse (вселенной различных социальных платформ), она связана с другими платформами. Отдохните от шума большого города — и познакомьтесь с новым интернетом."
|
||||||
intro:
|
intro:
|
||||||
title: "Misskeyって?"
|
title: "Misskeyって?"
|
||||||
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
|
||||||
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
@ -335,6 +335,7 @@ common/views/components/note-menu.vue:
|
|||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
|
unfavorite: "お気に入り解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -784,6 +785,10 @@ desktop/views/components/settings.vue:
|
|||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "タスクマネージャ"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "サードパーティ"
|
||||||
|
navbar-position: "ナビゲーションバーの位置"
|
||||||
|
navbar-position-top: "上"
|
||||||
|
navbar-position-left: "左"
|
||||||
|
navbar-position-right: "右"
|
||||||
desktop/views/components/settings.2fa.vue:
|
desktop/views/components/settings.2fa.vue:
|
||||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||||
detail: "詳細..."
|
detail: "詳細..."
|
||||||
@ -833,6 +838,7 @@ desktop/views/components/settings.profile.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
locked-account: "アカウントの保護"
|
locked-account: "アカウントの保護"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "このアカウントはBotです"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
@ -1073,6 +1079,8 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "ハッシュ (md5)"
|
hash: "ハッシュ (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "閲覧注意"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
mobile/views/components/media-image.vue:
|
mobile/views/components/media-image.vue:
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
click-to-show: "クリックして表示"
|
click-to-show: "クリックして表示"
|
||||||
@ -1224,6 +1232,7 @@ mobile/views/pages/settings/settings.profile.vue:
|
|||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "このアカウントはCatです"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "フォローを承認制にする"
|
||||||
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "その他"
|
||||||
privacy: "プライバシー"
|
privacy: "プライバシー"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
|
35
package.json
35
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.4.0",
|
"version": "10.20.0",
|
||||||
"clientVersion": "1.0.10397",
|
"clientVersion": "1.0.10607",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -28,18 +28,19 @@
|
|||||||
"@prezzemolo/rap": "0.1.2",
|
"@prezzemolo/rap": "0.1.2",
|
||||||
"@prezzemolo/zip": "0.0.3",
|
"@prezzemolo/zip": "0.0.3",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
|
"@types/chai-http": "3.0.5",
|
||||||
"@types/dateformat": "1.0.1",
|
"@types/dateformat": "1.0.1",
|
||||||
"@types/debug": "0.0.31",
|
"@types/debug": "0.0.31",
|
||||||
"@types/deep-equal": "1.0.1",
|
"@types/deep-equal": "1.0.1",
|
||||||
"@types/double-ended-queue": "2.1.0",
|
"@types/double-ended-queue": "2.1.0",
|
||||||
"@types/elasticsearch": "5.0.26",
|
"@types/elasticsearch": "5.0.27",
|
||||||
"@types/file-type": "5.2.1",
|
"@types/file-type": "5.2.1",
|
||||||
"@types/gulp": "3.8.36",
|
"@types/gulp": "3.8.36",
|
||||||
"@types/gulp-htmlmin": "1.3.32",
|
"@types/gulp-htmlmin": "1.3.32",
|
||||||
"@types/gulp-mocha": "0.0.32",
|
"@types/gulp-mocha": "0.0.32",
|
||||||
"@types/gulp-rename": "0.0.33",
|
"@types/gulp-rename": "0.0.33",
|
||||||
"@types/gulp-replace": "0.0.31",
|
"@types/gulp-replace": "0.0.31",
|
||||||
"@types/gulp-uglify": "3.0.5",
|
"@types/gulp-uglify": "3.0.6",
|
||||||
"@types/gulp-util": "3.0.34",
|
"@types/gulp-util": "3.0.34",
|
||||||
"@types/is-root": "1.0.0",
|
"@types/is-root": "1.0.0",
|
||||||
"@types/is-url": "1.2.28",
|
"@types/is-url": "1.2.28",
|
||||||
@ -48,7 +49,7 @@
|
|||||||
"@types/koa-bodyparser": "5.0.1",
|
"@types/koa-bodyparser": "5.0.1",
|
||||||
"@types/koa-compress": "2.0.8",
|
"@types/koa-compress": "2.0.8",
|
||||||
"@types/koa-favicon": "2.0.19",
|
"@types/koa-favicon": "2.0.19",
|
||||||
"@types/koa-logger": "3.1.0",
|
"@types/koa-logger": "3.1.1",
|
||||||
"@types/koa-mount": "3.0.1",
|
"@types/koa-mount": "3.0.1",
|
||||||
"@types/koa-multer": "1.0.0",
|
"@types/koa-multer": "1.0.0",
|
||||||
"@types/koa-router": "7.0.32",
|
"@types/koa-router": "7.0.32",
|
||||||
@ -58,9 +59,9 @@
|
|||||||
"@types/minio": "7.0.0",
|
"@types/minio": "7.0.0",
|
||||||
"@types/mkdirp": "0.5.2",
|
"@types/mkdirp": "0.5.2",
|
||||||
"@types/mocha": "5.2.3",
|
"@types/mocha": "5.2.3",
|
||||||
"@types/mongodb": "3.1.11",
|
"@types/mongodb": "3.1.12",
|
||||||
"@types/ms": "0.7.30",
|
"@types/ms": "0.7.30",
|
||||||
"@types/node": "10.11.5",
|
"@types/node": "10.12.0",
|
||||||
"@types/portscanner": "2.1.0",
|
"@types/portscanner": "2.1.0",
|
||||||
"@types/pug": "2.0.4",
|
"@types/pug": "2.0.4",
|
||||||
"@types/qrcode": "1.3.0",
|
"@types/qrcode": "1.3.0",
|
||||||
@ -70,7 +71,7 @@
|
|||||||
"@types/request-promise-native": "1.0.15",
|
"@types/request-promise-native": "1.0.15",
|
||||||
"@types/rimraf": "2.0.2",
|
"@types/rimraf": "2.0.2",
|
||||||
"@types/seedrandom": "2.4.27",
|
"@types/seedrandom": "2.4.27",
|
||||||
"@types/sharp": "0.17.10",
|
"@types/sharp": "0.21.0",
|
||||||
"@types/showdown": "1.7.5",
|
"@types/showdown": "1.7.5",
|
||||||
"@types/single-line-log": "1.1.0",
|
"@types/single-line-log": "1.1.0",
|
||||||
"@types/speakeasy": "2.0.2",
|
"@types/speakeasy": "2.0.2",
|
||||||
@ -78,7 +79,7 @@
|
|||||||
"@types/tinycolor2": "1.4.1",
|
"@types/tinycolor2": "1.4.1",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"@types/uuid": "3.4.4",
|
"@types/uuid": "3.4.4",
|
||||||
"@types/webpack": "4.4.15",
|
"@types/webpack": "4.4.17",
|
||||||
"@types/webpack-stream": "3.2.10",
|
"@types/webpack-stream": "3.2.10",
|
||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
@ -90,8 +91,10 @@
|
|||||||
"bee-queue": "1.2.2",
|
"bee-queue": "1.2.2",
|
||||||
"bootstrap-vue": "2.0.0-rc.11",
|
"bootstrap-vue": "2.0.0-rc.11",
|
||||||
"cafy": "11.3.0",
|
"cafy": "11.3.0",
|
||||||
|
"chai": "4.2.0",
|
||||||
|
"chai-http": "4.2.0",
|
||||||
"chalk": "2.4.1",
|
"chalk": "2.4.1",
|
||||||
"chart.js": "2.7.2",
|
"chart.js": "2.7.3",
|
||||||
"commander": "2.19.0",
|
"commander": "2.19.0",
|
||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "1.0.0",
|
"css-loader": "1.0.0",
|
||||||
@ -157,7 +160,7 @@
|
|||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "5.2.0",
|
"mocha": "5.2.0",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"mongodb": "3.1.1",
|
"mongodb": "3.1.8",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.11.1",
|
"nan": "2.11.1",
|
||||||
@ -169,13 +172,14 @@
|
|||||||
"parse5": "5.1.0",
|
"parse5": "5.1.0",
|
||||||
"portscanner": "2.2.0",
|
"portscanner": "2.2.0",
|
||||||
"progress-bar-webpack-plugin": "1.11.0",
|
"progress-bar-webpack-plugin": "1.11.0",
|
||||||
|
"promise-limit": "2.7.0",
|
||||||
"promise-sequential": "1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
"pug": "2.0.3",
|
"pug": "2.0.3",
|
||||||
"punycode": "2.1.1",
|
"punycode": "2.1.1",
|
||||||
"qrcode": "1.3.0",
|
"qrcode": "1.3.0",
|
||||||
"ratelimiter": "3.2.0",
|
"ratelimiter": "3.2.0",
|
||||||
"recaptcha-promise": "0.1.3",
|
"recaptcha-promise": "0.1.3",
|
||||||
"reconnecting-websocket": "4.1.5",
|
"reconnecting-websocket": "4.1.8",
|
||||||
"redis": "2.8.0",
|
"redis": "2.8.0",
|
||||||
"request": "2.88.0",
|
"request": "2.88.0",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
@ -206,19 +210,20 @@
|
|||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"typescript-eslint-parser": "20.0.0",
|
"typescript-eslint-parser": "20.0.0",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.2",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"v-animate-css": "0.0.2",
|
"v-animate-css": "0.0.2",
|
||||||
"vue": "2.5.17",
|
"vue": "2.5.17",
|
||||||
"vue-chartjs": "3.4.0",
|
"vue-chartjs": "3.4.0",
|
||||||
"vue-color": "2.6.0",
|
"vue-color": "2.7.0",
|
||||||
|
"vue-content-loading": "1.5.3",
|
||||||
"vue-cropperjs": "2.2.2",
|
"vue-cropperjs": "2.2.2",
|
||||||
"vue-js-modal": "1.3.26",
|
"vue-js-modal": "1.3.26",
|
||||||
"vue-json-tree-view": "2.1.4",
|
"vue-json-tree-view": "2.1.4",
|
||||||
"vue-loader": "15.4.2",
|
"vue-loader": "15.4.2",
|
||||||
"vue-router": "3.0.1",
|
"vue-router": "3.0.1",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader": "1.2.0",
|
"vue-svg-inline-loader": "1.2.1",
|
||||||
"vue-sweetalert2": "1.5.5",
|
"vue-sweetalert2": "1.5.5",
|
||||||
"vue-template-compiler": "2.5.17",
|
"vue-template-compiler": "2.5.17",
|
||||||
"vuedraggable": "2.16.0",
|
"vuedraggable": "2.16.0",
|
||||||
|
@ -131,15 +131,28 @@ pre
|
|||||||
[data-fa]
|
[data-fa]
|
||||||
display inline-block
|
display inline-block
|
||||||
|
|
||||||
|
.swal2-container
|
||||||
|
z-index 10000 !important
|
||||||
|
|
||||||
|
&.swal2-shown
|
||||||
|
background-color rgba(0, 0, 0, 0.5) !important
|
||||||
|
|
||||||
.swal2-popup
|
.swal2-popup
|
||||||
background var(--face) !important
|
background var(--face) !important
|
||||||
|
|
||||||
.swal-icon-only
|
.swal2-content
|
||||||
width 180px !important
|
color var(--text) !important
|
||||||
|
|
||||||
> .swal2-header
|
.swal2-confirm
|
||||||
> .swal2-icon
|
background-color var(--primary) !important
|
||||||
margin 1.25em auto 1.875em
|
border-left-color var(--primary) !important
|
||||||
|
border-right-color var(--primary) !important
|
||||||
|
color var(--primaryForeground) !important
|
||||||
|
|
||||||
> .swal2-title
|
&:hover
|
||||||
display none
|
background-image none !important
|
||||||
|
background-color var(--primaryDarken5) !important
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background-image none !important
|
||||||
|
background-color var(--primaryDarken5) !important
|
||||||
|
@ -142,7 +142,7 @@
|
|||||||
localStorage.setItem('shouldFlush', 'false');
|
localStorage.setItem('shouldFlush', 'false');
|
||||||
|
|
||||||
// Random
|
// Random
|
||||||
localStorage.setItem('salt', Math.random().toString());
|
localStorage.setItem('salt', Math.random().toString().substr(2, 8));
|
||||||
|
|
||||||
// Clear cache (service worker)
|
// Clear cache (service worker)
|
||||||
try {
|
try {
|
||||||
|
178
src/client/app/common/scripts/note-mixin.ts
Normal file
178
src/client/app/common/scripts/note-mixin.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import parse from '../../../../mfm/parse';
|
||||||
|
import { sum } from '../../../../prelude/array';
|
||||||
|
import MkNoteMenu from '../views/components/note-menu.vue';
|
||||||
|
import MkReactionPicker from '../views/components/reaction-picker.vue';
|
||||||
|
import Ok from '../views/components/ok.vue';
|
||||||
|
|
||||||
|
function focus(el, fn) {
|
||||||
|
const target = fn(el);
|
||||||
|
if (target) {
|
||||||
|
if (target.hasAttribute('tabindex')) {
|
||||||
|
target.focus();
|
||||||
|
} else {
|
||||||
|
focus(target, fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Opts = {
|
||||||
|
mobile?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (opts: Opts = {}) => ({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showContent: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
keymap(): any {
|
||||||
|
return {
|
||||||
|
'r|left': () => this.reply(true),
|
||||||
|
'e|a|plus': () => this.react(true),
|
||||||
|
'q|right': () => this.renote(true),
|
||||||
|
'f|b': this.favorite,
|
||||||
|
'delete|ctrl+d': this.del,
|
||||||
|
'ctrl+q|ctrl+right': this.renoteDirectly,
|
||||||
|
'up|k|shift+tab': this.focusBefore,
|
||||||
|
'down|j|tab': this.focusAfter,
|
||||||
|
'esc': this.blur,
|
||||||
|
'm|o': () => this.menu(true),
|
||||||
|
's': this.toggleShowContent,
|
||||||
|
'1': () => this.reactDirectly('like'),
|
||||||
|
'2': () => this.reactDirectly('love'),
|
||||||
|
'3': () => this.reactDirectly('laugh'),
|
||||||
|
'4': () => this.reactDirectly('hmm'),
|
||||||
|
'5': () => this.reactDirectly('surprise'),
|
||||||
|
'6': () => this.reactDirectly('congrats'),
|
||||||
|
'7': () => this.reactDirectly('angry'),
|
||||||
|
'8': () => this.reactDirectly('confused'),
|
||||||
|
'9': () => this.reactDirectly('rip'),
|
||||||
|
'0': () => this.reactDirectly('pudding'),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
isRenote(): boolean {
|
||||||
|
return (this.note.renote &&
|
||||||
|
this.note.text == null &&
|
||||||
|
this.note.fileIds.length == 0 &&
|
||||||
|
this.note.poll == null);
|
||||||
|
},
|
||||||
|
|
||||||
|
appearNote(): any {
|
||||||
|
return this.isRenote ? this.note.renote : this.note;
|
||||||
|
},
|
||||||
|
|
||||||
|
reactionsCount(): number {
|
||||||
|
return this.appearNote.reactionCounts
|
||||||
|
? sum(Object.values(this.appearNote.reactionCounts))
|
||||||
|
: 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
title(): string {
|
||||||
|
return new Date(this.appearNote.createdAt).toLocaleString();
|
||||||
|
},
|
||||||
|
|
||||||
|
urls(): string[] {
|
||||||
|
if (this.appearNote.text) {
|
||||||
|
const ast = parse(this.appearNote.text);
|
||||||
|
return ast
|
||||||
|
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
|
||||||
|
.map(t => t.url);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
reply(viaKeyboard = false) {
|
||||||
|
(this as any).apis.post({
|
||||||
|
reply: this.appearNote,
|
||||||
|
animation: !viaKeyboard,
|
||||||
|
cb: () => {
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renote(viaKeyboard = false) {
|
||||||
|
(this as any).apis.post({
|
||||||
|
renote: this.appearNote,
|
||||||
|
animation: !viaKeyboard,
|
||||||
|
cb: () => {
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renoteDirectly() {
|
||||||
|
(this as any).api('notes/create', {
|
||||||
|
renoteId: this.appearNote.id
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
react(viaKeyboard = false) {
|
||||||
|
this.blur();
|
||||||
|
(this as any).os.new(MkReactionPicker, {
|
||||||
|
source: this.$refs.reactButton,
|
||||||
|
note: this.appearNote,
|
||||||
|
showFocus: viaKeyboard,
|
||||||
|
animation: !viaKeyboard,
|
||||||
|
compact: opts.mobile,
|
||||||
|
big: opts.mobile
|
||||||
|
}).$once('closed', this.focus);
|
||||||
|
},
|
||||||
|
|
||||||
|
reactDirectly(reaction) {
|
||||||
|
(this as any).api('notes/reactions/create', {
|
||||||
|
noteId: this.appearNote.id,
|
||||||
|
reaction: reaction
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
favorite() {
|
||||||
|
(this as any).api('notes/favorites/create', {
|
||||||
|
noteId: this.appearNote.id
|
||||||
|
}).then(() => {
|
||||||
|
(this as any).os.new(Ok);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
del() {
|
||||||
|
(this as any).api('notes/delete', {
|
||||||
|
noteId: this.appearNote.id
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
menu(viaKeyboard = false) {
|
||||||
|
(this as any).os.new(MkNoteMenu, {
|
||||||
|
source: this.$refs.menuButton,
|
||||||
|
note: this.appearNote,
|
||||||
|
animation: !viaKeyboard,
|
||||||
|
compact: opts.mobile,
|
||||||
|
}).$once('closed', this.focus);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleShowContent() {
|
||||||
|
this.showContent = !this.showContent;
|
||||||
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$el.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
blur() {
|
||||||
|
this.$el.blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
focusBefore() {
|
||||||
|
focus(this.$el, e => e.previousElementSibling);
|
||||||
|
},
|
||||||
|
|
||||||
|
focusAfter() {
|
||||||
|
focus(this.$el, e => e.nextElementSibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -9,8 +9,8 @@ import MiOS from '../../mios';
|
|||||||
*/
|
*/
|
||||||
export default class Stream extends EventEmitter {
|
export default class Stream extends EventEmitter {
|
||||||
private stream: ReconnectingWebsocket;
|
private stream: ReconnectingWebsocket;
|
||||||
private state: string;
|
public state: string;
|
||||||
private buffer: any[];
|
private sharedConnectionPools: Pool[] = [];
|
||||||
private sharedConnections: SharedConnection[] = [];
|
private sharedConnections: SharedConnection[] = [];
|
||||||
private nonSharedConnections: NonSharedConnection[] = [];
|
private nonSharedConnections: NonSharedConnection[] = [];
|
||||||
|
|
||||||
@ -18,7 +18,6 @@ export default class Stream extends EventEmitter {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.state = 'initializing';
|
this.state = 'initializing';
|
||||||
this.buffer = [];
|
|
||||||
|
|
||||||
const user = os.store.state.i;
|
const user = os.store.state.i;
|
||||||
|
|
||||||
@ -28,26 +27,32 @@ export default class Stream extends EventEmitter {
|
|||||||
this.stream.addEventListener('message', this.onMessage);
|
this.stream.addEventListener('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public useSharedConnection = (channel: string): SharedConnection => {
|
@autobind
|
||||||
const existConnection = this.sharedConnections.find(c => c.channel === channel);
|
public useSharedConnection(channel: string): SharedConnection {
|
||||||
|
let pool = this.sharedConnectionPools.find(p => p.channel === channel);
|
||||||
|
|
||||||
if (existConnection) {
|
if (pool == null) {
|
||||||
existConnection.use();
|
pool = new Pool(this, channel);
|
||||||
return existConnection;
|
this.sharedConnectionPools.push(pool);
|
||||||
} else {
|
}
|
||||||
const connection = new SharedConnection(this, channel);
|
|
||||||
connection.use();
|
const connection = new SharedConnection(this, channel, pool);
|
||||||
this.sharedConnections.push(connection);
|
this.sharedConnections.push(connection);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public removeSharedConnection(connection: SharedConnection) {
|
public removeSharedConnection(connection: SharedConnection) {
|
||||||
this.sharedConnections = this.sharedConnections.filter(c => c.id !== connection.id);
|
this.sharedConnections = this.sharedConnections.filter(c => c !== connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectToChannel = (channel: string, params?: any): NonSharedConnection => {
|
@autobind
|
||||||
|
public removeSharedConnectionPool(pool: Pool) {
|
||||||
|
this.sharedConnectionPools = this.sharedConnectionPools.filter(p => p !== pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public connectToChannel(channel: string, params?: any): NonSharedConnection {
|
||||||
const connection = new NonSharedConnection(this, channel, params);
|
const connection = new NonSharedConnection(this, channel, params);
|
||||||
this.nonSharedConnections.push(connection);
|
this.nonSharedConnections.push(connection);
|
||||||
return connection;
|
return connection;
|
||||||
@ -55,7 +60,7 @@ export default class Stream extends EventEmitter {
|
|||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public disconnectToChannel(connection: NonSharedConnection) {
|
public disconnectToChannel(connection: NonSharedConnection) {
|
||||||
this.nonSharedConnections = this.nonSharedConnections.filter(c => c.id !== connection.id);
|
this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,17 +73,10 @@ export default class Stream extends EventEmitter {
|
|||||||
this.state = 'connected';
|
this.state = 'connected';
|
||||||
this.emit('_connected_');
|
this.emit('_connected_');
|
||||||
|
|
||||||
// バッファーを処理
|
|
||||||
const _buffer = [].concat(this.buffer); // Shallow copy
|
|
||||||
this.buffer = []; // Clear buffer
|
|
||||||
_buffer.forEach(data => {
|
|
||||||
this.send(data); // Resend each buffered messages
|
|
||||||
});
|
|
||||||
|
|
||||||
// チャンネル再接続
|
// チャンネル再接続
|
||||||
if (isReconnect) {
|
if (isReconnect) {
|
||||||
this.sharedConnections.forEach(c => {
|
this.sharedConnectionPools.forEach(p => {
|
||||||
c.connect();
|
p.connect();
|
||||||
});
|
});
|
||||||
this.nonSharedConnections.forEach(c => {
|
this.nonSharedConnections.forEach(c => {
|
||||||
c.connect();
|
c.connect();
|
||||||
@ -91,9 +89,11 @@ export default class Stream extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
@autobind
|
@autobind
|
||||||
private onClose() {
|
private onClose() {
|
||||||
|
if (this.state == 'connected') {
|
||||||
this.state = 'reconnecting';
|
this.state = 'reconnecting';
|
||||||
this.emit('_disconnected_');
|
this.emit('_disconnected_');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback of when received a message from connection
|
* Callback of when received a message from connection
|
||||||
@ -104,8 +104,18 @@ export default class Stream extends EventEmitter {
|
|||||||
|
|
||||||
if (type == 'channel') {
|
if (type == 'channel') {
|
||||||
const id = body.id;
|
const id = body.id;
|
||||||
const connection = this.sharedConnections.find(c => c.id === id) || this.nonSharedConnections.find(c => c.id === id);
|
|
||||||
connection.emit(body.type, body.body);
|
let connections: Connection[];
|
||||||
|
|
||||||
|
connections = this.sharedConnections.filter(c => c.id === id);
|
||||||
|
|
||||||
|
if (connections.length === 0) {
|
||||||
|
connections = [this.nonSharedConnections.find(c => c.id === id)];
|
||||||
|
}
|
||||||
|
|
||||||
|
connections.filter(c => c != null).forEach(c => {
|
||||||
|
c.emit(body.type, body.body);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.emit(type, body);
|
this.emit(type, body);
|
||||||
}
|
}
|
||||||
@ -121,12 +131,6 @@ export default class Stream extends EventEmitter {
|
|||||||
body: payload
|
body: payload
|
||||||
};
|
};
|
||||||
|
|
||||||
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
|
|
||||||
if (this.state != 'connected') {
|
|
||||||
this.buffer.push(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stream.send(JSON.stringify(data));
|
this.stream.send(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,19 +144,139 @@ export default class Stream extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Connection extends EventEmitter {
|
class Pool {
|
||||||
public channel: string;
|
public channel: string;
|
||||||
public id: string;
|
public id: string;
|
||||||
protected params: any;
|
|
||||||
protected stream: Stream;
|
protected stream: Stream;
|
||||||
|
public users = 0;
|
||||||
|
private disposeTimerId: any;
|
||||||
|
private isConnected = false;
|
||||||
|
|
||||||
constructor(stream: Stream, channel: string, params?: any) {
|
constructor(stream: Stream, channel: string) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.stream = stream;
|
||||||
|
|
||||||
|
this.id = Math.random().toString().substr(2, 8);
|
||||||
|
|
||||||
|
this.stream.on('_disconnected_', this.onStreamDisconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
private onStreamDisconnected() {
|
||||||
|
this.isConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public inc() {
|
||||||
|
if (this.users === 0 && !this.isConnected) {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.users++;
|
||||||
|
|
||||||
|
// タイマー解除
|
||||||
|
if (this.disposeTimerId) {
|
||||||
|
clearTimeout(this.disposeTimerId);
|
||||||
|
this.disposeTimerId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public dec() {
|
||||||
|
this.users--;
|
||||||
|
|
||||||
|
// そのコネクションの利用者が誰もいなくなったら
|
||||||
|
if (this.users === 0) {
|
||||||
|
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
||||||
|
// 新たな利用者が現れなければコネクションを切断する
|
||||||
|
this.disposeTimerId = setTimeout(() => {
|
||||||
|
this.disconnect();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public connect() {
|
||||||
|
if (this.isConnected) return;
|
||||||
|
this.isConnected = true;
|
||||||
|
this.stream.send('connect', {
|
||||||
|
channel: this.channel,
|
||||||
|
id: this.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
private disconnect() {
|
||||||
|
this.stream.off('_disconnected_', this.onStreamDisconnected);
|
||||||
|
this.stream.send('disconnect', { id: this.id });
|
||||||
|
this.stream.removeSharedConnectionPool(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Connection extends EventEmitter {
|
||||||
|
public channel: string;
|
||||||
|
protected stream: Stream;
|
||||||
|
public abstract id: string;
|
||||||
|
|
||||||
|
constructor(stream: Stream, channel: string) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public send(id: string, typeOrPayload, payload?) {
|
||||||
|
const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
|
||||||
|
const body = payload === undefined ? typeOrPayload.body : payload;
|
||||||
|
|
||||||
|
this.stream.send('ch', {
|
||||||
|
id: id,
|
||||||
|
type: type,
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract dispose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SharedConnection extends Connection {
|
||||||
|
private pool: Pool;
|
||||||
|
|
||||||
|
public get id(): string {
|
||||||
|
return this.pool.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(stream: Stream, channel: string, pool: Pool) {
|
||||||
|
super(stream, channel);
|
||||||
|
|
||||||
|
this.pool = pool;
|
||||||
|
this.pool.inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public send(typeOrPayload, payload?) {
|
||||||
|
super.send(this.pool.id, typeOrPayload, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public dispose() {
|
||||||
|
this.pool.dec();
|
||||||
|
this.removeAllListeners();
|
||||||
|
this.stream.removeSharedConnection(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NonSharedConnection extends Connection {
|
||||||
|
public id: string;
|
||||||
|
protected params: any;
|
||||||
|
|
||||||
|
constructor(stream: Stream, channel: string, params?: any) {
|
||||||
|
super(stream, channel);
|
||||||
|
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.id = Math.random().toString();
|
this.id = Math.random().toString().substr(2, 8);
|
||||||
|
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,59 +291,7 @@ abstract class Connection extends EventEmitter {
|
|||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public send(typeOrPayload, payload?) {
|
public send(typeOrPayload, payload?) {
|
||||||
const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
|
super.send(this.id, typeOrPayload, payload);
|
||||||
const body = payload === undefined ? typeOrPayload.body : payload;
|
|
||||||
|
|
||||||
this.stream.send('channel', {
|
|
||||||
id: this.id,
|
|
||||||
type: type,
|
|
||||||
body: body
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract dispose(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SharedConnection extends Connection {
|
|
||||||
private users = 0;
|
|
||||||
private disposeTimerId: any;
|
|
||||||
|
|
||||||
constructor(stream: Stream, channel: string) {
|
|
||||||
super(stream, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
public use() {
|
|
||||||
this.users++;
|
|
||||||
|
|
||||||
// タイマー解除
|
|
||||||
if (this.disposeTimerId) {
|
|
||||||
clearTimeout(this.disposeTimerId);
|
|
||||||
this.disposeTimerId = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
public dispose() {
|
|
||||||
this.users--;
|
|
||||||
|
|
||||||
// そのコネクションの利用者が誰もいなくなったら
|
|
||||||
if (this.users === 0) {
|
|
||||||
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
|
||||||
// 新たな利用者が現れなければコネクションを切断する
|
|
||||||
this.disposeTimerId = setTimeout(() => {
|
|
||||||
this.disposeTimerId = null;
|
|
||||||
this.removeAllListeners();
|
|
||||||
this.stream.send('disconnect', { id: this.id });
|
|
||||||
this.stream.removeSharedConnection(this);
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NonSharedConnection extends Connection {
|
|
||||||
constructor(stream: Stream, channel: string, params?: any) {
|
|
||||||
super(stream, channel, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
import noteSkeleton from './note-skeleton.vue';
|
||||||
import theme from './theme.vue';
|
import theme from './theme.vue';
|
||||||
import instance from './instance.vue';
|
import instance from './instance.vue';
|
||||||
import cwButton from './cw-button.vue';
|
import cwButton from './cw-button.vue';
|
||||||
@ -44,6 +45,7 @@ import uiSelect from './ui/select.vue';
|
|||||||
import formButton from './ui/form/button.vue';
|
import formButton from './ui/form/button.vue';
|
||||||
import formRadio from './ui/form/radio.vue';
|
import formRadio from './ui/form/radio.vue';
|
||||||
|
|
||||||
|
Vue.component('mk-note-skeleton', noteSkeleton);
|
||||||
Vue.component('mk-theme', theme);
|
Vue.component('mk-theme', theme);
|
||||||
Vue.component('mk-instance', instance);
|
Vue.component('mk-instance', instance);
|
||||||
Vue.component('mk-cw-button', cwButton);
|
Vue.component('mk-cw-button', cwButton);
|
||||||
|
@ -71,7 +71,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection =((this as any).os.stream.connectToChannel('messaging', { otherparty: this.user.id });
|
this.connection = (this as any).os.stream.connectToChannel('messaging', { otherparty: this.user.id });
|
||||||
|
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
this.connection.on('read', this.onRead);
|
this.connection.on('read', this.onRead);
|
||||||
@ -354,7 +354,7 @@ export default Vue.extend({
|
|||||||
max-width 600px
|
max-width 600px
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
padding 0
|
padding 0
|
||||||
//background rgba(var(--face), 0.95)
|
background var(--messagingRoomBg)
|
||||||
background-clip content-box
|
background-clip content-box
|
||||||
|
|
||||||
> .new-message
|
> .new-message
|
||||||
|
@ -116,16 +116,16 @@ export default Vue.component('misskey-flavored-markdown', {
|
|||||||
case 'mention': {
|
case 'mention': {
|
||||||
return (createElement as any)('a', {
|
return (createElement as any)('a', {
|
||||||
attrs: {
|
attrs: {
|
||||||
href: `${url}/@${getAcct(token)}`,
|
href: `${url}/${token.canonical}`,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
|
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
|
||||||
style: 'color:var(--mfmMention);'
|
style: 'color:var(--mfmMention);'
|
||||||
},
|
},
|
||||||
directives: [{
|
directives: [{
|
||||||
name: 'user-preview',
|
name: 'user-preview',
|
||||||
value: token.content
|
value: token.canonical
|
||||||
}]
|
}]
|
||||||
}, token.content);
|
}, token.canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'hashtag': {
|
case 'hashtag': {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { url } from '../../../config';
|
import { url } from '../../../config';
|
||||||
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
||||||
|
import Ok from './ok.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['note', 'source', 'compact'],
|
props: ['note', 'source', 'compact'],
|
||||||
@ -21,11 +22,33 @@ export default Vue.extend({
|
|||||||
icon: '%fa:link%',
|
icon: '%fa:link%',
|
||||||
text: '%i18n:@copy-link%',
|
text: '%i18n:@copy-link%',
|
||||||
action: this.copyLink
|
action: this.copyLink
|
||||||
}, null, {
|
}];
|
||||||
|
|
||||||
|
if (this.note.uri) {
|
||||||
|
items.push({
|
||||||
|
icon: '%fa:external-link-square-alt%',
|
||||||
|
text: '%i18n:@remote%',
|
||||||
|
action: () => {
|
||||||
|
window.open(this.note.uri, '_blank');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(null);
|
||||||
|
|
||||||
|
if (this.note.isFavorited) {
|
||||||
|
items.push({
|
||||||
|
icon: '%fa:star%',
|
||||||
|
text: '%i18n:@unfavorite%',
|
||||||
|
action: this.unfavorite
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
items.push({
|
||||||
icon: '%fa:star%',
|
icon: '%fa:star%',
|
||||||
text: '%i18n:@favorite%',
|
text: '%i18n:@favorite%',
|
||||||
action: this.favorite
|
action: this.favorite
|
||||||
}];
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.note.userId == this.$store.state.i.id) {
|
if (this.note.userId == this.$store.state.i.id) {
|
||||||
if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) {
|
if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) {
|
||||||
@ -44,6 +67,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) {
|
if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) {
|
||||||
|
items.push(null);
|
||||||
items.push({
|
items.push({
|
||||||
icon: '%fa:trash-alt R%',
|
icon: '%fa:trash-alt R%',
|
||||||
text: '%i18n:@delete%',
|
text: '%i18n:@delete%',
|
||||||
@ -51,16 +75,6 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.note.uri) {
|
|
||||||
items.push({
|
|
||||||
icon: '%fa:external-link-square-alt%',
|
|
||||||
text: '%i18n:@remote%',
|
|
||||||
action: () => {
|
|
||||||
window.open(this.note.uri, '_blank');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -78,6 +92,7 @@ export default Vue.extend({
|
|||||||
(this as any).api('i/pin', {
|
(this as any).api('i/pin', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
(this as any).os.new(Ok);
|
||||||
this.destroyDom();
|
this.destroyDom();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -103,12 +118,16 @@ export default Vue.extend({
|
|||||||
(this as any).api('notes/favorites/create', {
|
(this as any).api('notes/favorites/create', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$swal({
|
(this as any).os.new(Ok);
|
||||||
type: 'success',
|
this.destroyDom();
|
||||||
showConfirmButton: false,
|
|
||||||
timer: 1250,
|
|
||||||
customClass: 'swal-icon-only'
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
unfavorite() {
|
||||||
|
(this as any).api('notes/favorites/delete', {
|
||||||
|
noteId: this.note.id
|
||||||
|
}).then(() => {
|
||||||
|
(this as any).os.new(Ok);
|
||||||
this.destroyDom();
|
this.destroyDom();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
52
src/client/app/common/views/components/note-skeleton.vue
Normal file
52
src/client/app/common/views/components/note-skeleton.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<vue-content-loading v-if="width" :width="width" :height="100" :primary="primary" :secondary="secondary">
|
||||||
|
<circle cx="30" cy="30" r="30" />
|
||||||
|
<rect x="75" y="13" rx="4" ry="4" :width="150 + r1" height="15" />
|
||||||
|
<rect x="75" y="39" rx="4" ry="4" :width="260 + r2" height="10" />
|
||||||
|
<rect x="75" y="59" rx="4" ry="4" :width="230 + r3" height="10" />
|
||||||
|
</vue-content-loading>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueContentLoading from 'vue-content-loading';
|
||||||
|
import * as tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
VueContentLoading,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
width: 0,
|
||||||
|
r1: (Math.random() * 100) - 50,
|
||||||
|
r2: (Math.random() * 100) - 50,
|
||||||
|
r3: (Math.random() * 100) - 50
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
text(): tinycolor.Instance {
|
||||||
|
const text = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text'));
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
|
||||||
|
primary(): string {
|
||||||
|
return '#' + this.text.clone().toHex();
|
||||||
|
},
|
||||||
|
|
||||||
|
secondary(): string {
|
||||||
|
return '#' + this.text.clone().darken(20).toHex();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
let width = this.$el.clientWidth;
|
||||||
|
if (width < 400) width = 400;
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
175
src/client/app/common/views/components/ok.vue
Normal file
175
src/client/app/common/views/components/ok.vue
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
<template>
|
||||||
|
<div class="yvbkymdqeusiqucuuloahhiqflzinufs">
|
||||||
|
<div class="bg" ref="bg"></div>
|
||||||
|
<div class="body" ref="body">
|
||||||
|
<div class="icon">
|
||||||
|
<div class="circle left"></div>
|
||||||
|
<span class="check tip"></span>
|
||||||
|
<span class="check long"></span>
|
||||||
|
<div class="ring"></div>
|
||||||
|
<div class="fix"></div>
|
||||||
|
<div class="circle right"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import * as anime from 'animejs';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.bg,
|
||||||
|
opacity: 1,
|
||||||
|
duration: 300,
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.body,
|
||||||
|
opacity: 1,
|
||||||
|
scale: [1.2, 1],
|
||||||
|
duration: 300,
|
||||||
|
easing: [0, 0.5, 0.5, 1]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.bg,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 300,
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.body,
|
||||||
|
opacity: 0,
|
||||||
|
scale: 0.8,
|
||||||
|
duration: 300,
|
||||||
|
easing: [0.5, 0, 1, 0.5],
|
||||||
|
complete: () => this.destroyDom()
|
||||||
|
});
|
||||||
|
}, 1250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.yvbkymdqeusiqucuuloahhiqflzinufs
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
> .bg
|
||||||
|
display block
|
||||||
|
position fixed
|
||||||
|
z-index 10000
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background rgba(#000, 0.7)
|
||||||
|
opacity 0
|
||||||
|
|
||||||
|
> .body
|
||||||
|
position fixed
|
||||||
|
z-index 10000
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
left 0
|
||||||
|
bottom 0
|
||||||
|
margin auto
|
||||||
|
width 150px
|
||||||
|
height 150px
|
||||||
|
background var(--face)
|
||||||
|
border-radius 8px
|
||||||
|
opacity 0
|
||||||
|
|
||||||
|
> .icon
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
left 0
|
||||||
|
bottom 0
|
||||||
|
width 5em
|
||||||
|
height 5em
|
||||||
|
margin auto
|
||||||
|
border .25em solid transparent
|
||||||
|
border-radius 50%
|
||||||
|
line-height 5em
|
||||||
|
cursor default
|
||||||
|
box-sizing content-box
|
||||||
|
user-select none
|
||||||
|
zoom normal
|
||||||
|
border-color #a5dc86
|
||||||
|
|
||||||
|
> .circle
|
||||||
|
position absolute
|
||||||
|
width 3.75em
|
||||||
|
height 7.5em
|
||||||
|
transform rotate(45deg)
|
||||||
|
border-radius 50%
|
||||||
|
background var(--face)
|
||||||
|
|
||||||
|
&.left
|
||||||
|
top -.4375em
|
||||||
|
left -2.0635em
|
||||||
|
transform rotate(-45deg)
|
||||||
|
transform-origin 3.75em 3.75em
|
||||||
|
border-radius 7.5em 0 0 7.5em
|
||||||
|
|
||||||
|
&.right
|
||||||
|
top -.6875em
|
||||||
|
left 1.875em
|
||||||
|
transform rotate(-45deg)
|
||||||
|
transform-origin 0 3.75em
|
||||||
|
border-radius 0 7.5em 7.5em 0
|
||||||
|
animation swal2-rotate-success-circular-line 4.25s ease-in
|
||||||
|
|
||||||
|
> .check
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
height .3125em
|
||||||
|
border-radius .125em
|
||||||
|
background-color #a5dc86
|
||||||
|
z-index 2
|
||||||
|
|
||||||
|
&.tip
|
||||||
|
top 2.875em
|
||||||
|
left .875em
|
||||||
|
width 1.5625em
|
||||||
|
transform rotate(45deg)
|
||||||
|
animation swal2-animate-success-line-tip .75s
|
||||||
|
|
||||||
|
&.long
|
||||||
|
top 2.375em
|
||||||
|
right .5em
|
||||||
|
width 2.9375em
|
||||||
|
transform rotate(-45deg)
|
||||||
|
animation swal2-animate-success-line-long .75s
|
||||||
|
|
||||||
|
> .fix
|
||||||
|
position absolute
|
||||||
|
top .5em
|
||||||
|
left 1.625em
|
||||||
|
width .4375em
|
||||||
|
height 5.625em
|
||||||
|
transform rotate(-45deg)
|
||||||
|
z-index 1
|
||||||
|
background var(--face)
|
||||||
|
|
||||||
|
> .ring
|
||||||
|
position absolute
|
||||||
|
top -.25em
|
||||||
|
left -.25em
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
border .25em solid rgba(165,220,134,.3)
|
||||||
|
border-radius 50%
|
||||||
|
z-index 2
|
||||||
|
box-sizing content-box
|
||||||
|
</style>
|
@ -219,7 +219,10 @@ export default Vue.extend({
|
|||||||
try {
|
try {
|
||||||
theme = JSON5.parse(code);
|
theme = JSON5.parse(code);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert('%i18n:@invalid-theme%');
|
this.$swal({
|
||||||
|
type: 'error',
|
||||||
|
text: '%i18n:@invalid-theme%'
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,12 +232,18 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (theme.id == null) {
|
if (theme.id == null) {
|
||||||
alert('%i18n:@invalid-theme%');
|
this.$swal({
|
||||||
|
type: 'error',
|
||||||
|
text: '%i18n:@invalid-theme%'
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.device.themes.some(t => t.id == theme.id)) {
|
if (this.$store.state.device.themes.some(t => t.id == theme.id)) {
|
||||||
alert('%i18n:@already-installed%');
|
this.$swal({
|
||||||
|
type: 'info',
|
||||||
|
text: '%i18n:@already-installed%'
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +252,10 @@ export default Vue.extend({
|
|||||||
key: 'themes', value: themes
|
key: 'themes', value: themes
|
||||||
});
|
});
|
||||||
|
|
||||||
alert('%i18n:@installed%'.replace('{}', theme.name));
|
this.$swal({
|
||||||
|
type: 'success',
|
||||||
|
text: '%i18n:@installed%'.replace('{}', theme.name)
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
uninstall() {
|
uninstall() {
|
||||||
@ -252,7 +264,11 @@ export default Vue.extend({
|
|||||||
this.$store.commit('device/set', {
|
this.$store.commit('device/set', {
|
||||||
key: 'themes', value: themes
|
key: 'themes', value: themes
|
||||||
});
|
});
|
||||||
alert('%i18n:@uninstalled%'.replace('{}', theme.name));
|
|
||||||
|
this.$swal({
|
||||||
|
type: 'info',
|
||||||
|
text: '%i18n:@uninstalled%'.replace('{}', theme.name)
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
import_() {
|
import_() {
|
||||||
@ -284,16 +300,26 @@ export default Vue.extend({
|
|||||||
|
|
||||||
gen() {
|
gen() {
|
||||||
const theme = this.myTheme;
|
const theme = this.myTheme;
|
||||||
|
|
||||||
if (theme.name == null || theme.name.trim() == '') {
|
if (theme.name == null || theme.name.trim() == '') {
|
||||||
alert('%i18n:@theme-name-required%');
|
this.$swal({
|
||||||
|
type: 'warning',
|
||||||
|
text: '%i18n:@theme-name-required%'
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
theme.id = uuid();
|
theme.id = uuid();
|
||||||
|
|
||||||
const themes = this.$store.state.device.themes.concat(theme);
|
const themes = this.$store.state.device.themes.concat(theme);
|
||||||
this.$store.commit('device/set', {
|
this.$store.commit('device/set', {
|
||||||
key: 'themes', value: themes
|
key: 'themes', value: themes
|
||||||
});
|
});
|
||||||
alert('%i18n:@saved%');
|
|
||||||
|
this.$swal({
|
||||||
|
type: 'success',
|
||||||
|
text: '%i18n:@saved%'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as getCaretCoordinates from 'textarea-caret';
|
import * as getCaretCoordinates from 'textarea-caret';
|
||||||
import MkAutocomplete from '../components/autocomplete.vue';
|
import MkAutocomplete from '../components/autocomplete.vue';
|
||||||
import renderAcct from '../../../../../misc/acct/render';
|
import { toASCII } from 'punycode';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
bind(el, binding, vn) {
|
bind(el, binding, vn) {
|
||||||
@ -188,7 +188,7 @@ class Autocomplete {
|
|||||||
const trimmedBefore = before.substring(0, before.lastIndexOf('@'));
|
const trimmedBefore = before.substring(0, before.lastIndexOf('@'));
|
||||||
const after = source.substr(caret);
|
const after = source.substr(caret);
|
||||||
|
|
||||||
const acct = renderAcct(value);
|
const acct = value.host === null ? value.username : `${value.username}@${toASCII(value.host)}`;
|
||||||
|
|
||||||
// 挿入
|
// 挿入
|
||||||
this.text = `${trimmedBefore}@${acct} ${after}`;
|
this.text = `${trimmedBefore}@${acct} ${after}`;
|
||||||
|
@ -114,7 +114,7 @@ export default define({
|
|||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
this.connection.on('statsLog', this.onStatsLog);
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
this.connection.send('requestLog',{
|
this.connection.send('requestLog',{
|
||||||
id: Math.random().toString()
|
id: Math.random().toString().substr(2, 8)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
@ -92,7 +92,7 @@ export default Vue.extend({
|
|||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
this.connection.on('statsLog', this.onStatsLog);
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
this.connection.send('requestLog', {
|
this.connection.send('requestLog', {
|
||||||
id: Math.random().toString()
|
id: Math.random().toString().substr(2, 8)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
@ -6,13 +6,17 @@ export default (os: OS) => opts => {
|
|||||||
const o = opts || {};
|
const o = opts || {};
|
||||||
if (o.renote) {
|
if (o.renote) {
|
||||||
const vm = os.new(RenoteFormWindow, {
|
const vm = os.new(RenoteFormWindow, {
|
||||||
note: o.renote
|
note: o.renote,
|
||||||
|
animation: o.animation == null ? true : o.animation
|
||||||
});
|
});
|
||||||
|
if (o.cb) vm.$once('closed', o.cb);
|
||||||
document.body.appendChild(vm.$el);
|
document.body.appendChild(vm.$el);
|
||||||
} else {
|
} else {
|
||||||
const vm = os.new(PostFormWindow, {
|
const vm = os.new(PostFormWindow, {
|
||||||
reply: o.reply
|
reply: o.reply,
|
||||||
|
animation: o.animation == null ? true : o.animation
|
||||||
});
|
});
|
||||||
|
if (o.cb) vm.$once('closed', o.cb);
|
||||||
document.body.appendChild(vm.$el);
|
document.body.appendChild(vm.$el);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mk-ellipsis-icon">
|
|
||||||
<div></div><div></div><div></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.mk-ellipsis-icon
|
|
||||||
width 70px
|
|
||||||
margin 0 auto
|
|
||||||
text-align center
|
|
||||||
|
|
||||||
> div
|
|
||||||
display inline-block
|
|
||||||
width 18px
|
|
||||||
height 18px
|
|
||||||
background-color rgba(#000, 0.3)
|
|
||||||
border-radius 100%
|
|
||||||
animation bounce 1.4s infinite ease-in-out both
|
|
||||||
|
|
||||||
&:nth-child(1)
|
|
||||||
animation-delay 0s
|
|
||||||
|
|
||||||
&:nth-child(2)
|
|
||||||
margin 0 6px
|
|
||||||
animation-delay 0.16s
|
|
||||||
|
|
||||||
&:nth-child(3)
|
|
||||||
animation-delay 0.32s
|
|
||||||
|
|
||||||
@keyframes bounce
|
|
||||||
0%, 80%, 100%
|
|
||||||
transform scale(0)
|
|
||||||
40%
|
|
||||||
transform scale(1)
|
|
||||||
|
|
||||||
</style>
|
|
@ -38,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main" :class="{ side: widgets.left.length == 0 || widgets.right.length == 0 }">
|
||||||
<template v-if="customize">
|
<template v-if="customize">
|
||||||
<x-draggable v-for="place in ['left', 'right']"
|
<x-draggable v-for="place in ['left', 'right']"
|
||||||
:list="widgets[place]"
|
:list="widgets[place]"
|
||||||
@ -359,12 +359,10 @@ export default Vue.extend({
|
|||||||
box-shadow var(--shadow)
|
box-shadow var(--shadow)
|
||||||
border-radius var(--round)
|
border-radius var(--round)
|
||||||
|
|
||||||
@media (max-width 700px)
|
&.side
|
||||||
padding 0
|
> .main
|
||||||
|
width calc(100% - 280px)
|
||||||
> .tl
|
max-width 680px
|
||||||
border none
|
|
||||||
border-radius 0
|
|
||||||
|
|
||||||
> *:not(.main)
|
> *:not(.main)
|
||||||
width 280px
|
width 280px
|
||||||
@ -381,12 +379,22 @@ export default Vue.extend({
|
|||||||
padding-right 16px
|
padding-right 16px
|
||||||
order 3
|
order 3
|
||||||
|
|
||||||
@media (max-width 1100px)
|
&.side
|
||||||
|
@media (max-width 1000px)
|
||||||
|
> *:not(.main)
|
||||||
|
display none
|
||||||
|
|
||||||
|
> .main
|
||||||
|
width 100%
|
||||||
|
max-width 700px
|
||||||
|
margin 0 auto
|
||||||
|
|
||||||
|
&:not(.side)
|
||||||
|
@media (max-width 1200px)
|
||||||
> *:not(.main)
|
> *:not(.main)
|
||||||
display none
|
display none
|
||||||
|
|
||||||
> .main
|
> .main
|
||||||
float none
|
|
||||||
width 100%
|
width 100%
|
||||||
max-width 700px
|
max-width 700px
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -9,7 +9,6 @@ import subNoteContent from './sub-note-content.vue';
|
|||||||
import window from './window.vue';
|
import window from './window.vue';
|
||||||
import noteFormWindow from './post-form-window.vue';
|
import noteFormWindow from './post-form-window.vue';
|
||||||
import renoteFormWindow from './renote-form-window.vue';
|
import renoteFormWindow from './renote-form-window.vue';
|
||||||
import ellipsisIcon from './ellipsis-icon.vue';
|
|
||||||
import mediaImage from './media-image.vue';
|
import mediaImage from './media-image.vue';
|
||||||
import mediaImageDialog from './media-image-dialog.vue';
|
import mediaImageDialog from './media-image-dialog.vue';
|
||||||
import mediaVideo from './media-video.vue';
|
import mediaVideo from './media-video.vue';
|
||||||
@ -39,7 +38,6 @@ Vue.component('mk-sub-note-content', subNoteContent);
|
|||||||
Vue.component('mk-window', window);
|
Vue.component('mk-window', window);
|
||||||
Vue.component('mk-post-form-window', noteFormWindow);
|
Vue.component('mk-post-form-window', noteFormWindow);
|
||||||
Vue.component('mk-renote-form-window', renoteFormWindow);
|
Vue.component('mk-renote-form-window', renoteFormWindow);
|
||||||
Vue.component('mk-ellipsis-icon', ellipsisIcon);
|
|
||||||
Vue.component('mk-media-image', mediaImage);
|
Vue.component('mk-media-image', mediaImage);
|
||||||
Vue.component('mk-media-image-dialog', mediaImageDialog);
|
Vue.component('mk-media-image-dialog', mediaImageDialog);
|
||||||
Vue.component('mk-media-video', mediaVideo);
|
Vue.component('mk-media-video', mediaVideo);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="note" tabindex="-1" v-hotkey="keymap" :title="title">
|
<div class="note" v-show="appearNote.deletedAt == null" :tabindex="appearNote.deletedAt == null ? '-1' : null" v-hotkey="keymap" :title="title">
|
||||||
<div class="reply-to" v-if="p.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
||||||
<x-sub :note="p.reply"/>
|
<x-sub :note="appearNote.reply"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="renote" v-if="isRenote">
|
<div class="renote" v-if="isRenote">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
@ -12,228 +12,76 @@
|
|||||||
<mk-time :time="note.createdAt"/>
|
<mk-time :time="note.createdAt"/>
|
||||||
</div>
|
</div>
|
||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user"/>
|
<mk-avatar class="avatar" :user="appearNote.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<mk-note-header class="header" :note="p"/>
|
<mk-note-header class="header" :note="appearNote"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
|
||||||
<mk-cw-button v-model="showContent"/>
|
<mk-cw-button v-model="showContent"/>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-show="p.cw == null || showContent">
|
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||||
<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
||||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
<a class="rp" v-if="appearNote.renote">RP:</a>
|
||||||
<a class="rp" v-if="p.renote">RP:</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="p.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<mk-media-list :media-list="p.files"/>
|
<mk-media-list :media-list="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
|
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
|
||||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
|
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
|
||||||
<div class="map" v-if="p.geo" ref="map"></div>
|
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div>
|
||||||
<div class="renote" v-if="p.renote"><mk-note-preview :note="p.renote"/></div>
|
|
||||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer v-if="p.deletedAt == null">
|
<footer>
|
||||||
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
|
||||||
<button class="replyButton" @click="reply()" title="%i18n:@reply%">
|
<button class="replyButton" @click="reply()" title="%i18n:@reply%">
|
||||||
<template v-if="p.reply">%fa:reply-all%</template>
|
<template v-if="appearNote.reply">%fa:reply-all%</template>
|
||||||
<template v-else>%fa:reply%</template>
|
<template v-else>%fa:reply%</template>
|
||||||
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
|
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button class="renoteButton" @click="renote()" title="%i18n:@renote%">
|
<button class="renoteButton" @click="renote()" title="%i18n:@renote%">
|
||||||
%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
|
%fa:retweet%<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
|
<button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
|
||||||
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
|
%fa:plus%<p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button @click="menu()" ref="menuButton">
|
<button @click="menu()" ref="menuButton">
|
||||||
%fa:ellipsis-h%
|
%fa:ellipsis-h%
|
||||||
</button>
|
</button>
|
||||||
<!-- <button title="%i18n:@detail">
|
|
||||||
<template v-if="!isDetailOpened">%fa:caret-down%</template>
|
|
||||||
<template v-if="isDetailOpened">%fa:caret-up%</template>
|
|
||||||
</button> -->
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<div class="detail" v-if="isDetailOpened">
|
|
||||||
<mk-note-status-graph width="462" height="130" :note="p"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import parse from '../../../../../mfm/parse';
|
|
||||||
|
|
||||||
import MkPostFormWindow from './post-form-window.vue';
|
import MkPostFormWindow from './post-form-window.vue';
|
||||||
import MkRenoteFormWindow from './renote-form-window.vue';
|
import MkRenoteFormWindow from './renote-form-window.vue';
|
||||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
|
||||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
|
||||||
import XSub from './notes.note.sub.vue';
|
import XSub from './notes.note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import noteMixin from '../../../common/scripts/note-mixin';
|
||||||
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
function focus(el, fn) {
|
|
||||||
const target = fn(el);
|
|
||||||
if (target) {
|
|
||||||
if (target.hasAttribute('tabindex')) {
|
|
||||||
target.focus();
|
|
||||||
} else {
|
|
||||||
focus(target, fn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [noteSubscriber('note')],
|
mixins: [
|
||||||
|
noteMixin(),
|
||||||
|
noteSubscriber('note')
|
||||||
|
],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
showContent: false,
|
|
||||||
isDetailOpened: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
keymap(): any {
|
|
||||||
return {
|
|
||||||
'r|left': () => this.reply(true),
|
|
||||||
'e|a|plus': () => this.react(true),
|
|
||||||
'q|right': () => this.renote(true),
|
|
||||||
'ctrl+q|ctrl+right': this.renoteDirectly,
|
|
||||||
'up|k|shift+tab': this.focusBefore,
|
|
||||||
'down|j|tab': this.focusAfter,
|
|
||||||
'esc': this.blur,
|
|
||||||
'm|o': () => this.menu(true),
|
|
||||||
's': this.toggleShowContent,
|
|
||||||
'1': () => this.reactDirectly('like'),
|
|
||||||
'2': () => this.reactDirectly('love'),
|
|
||||||
'3': () => this.reactDirectly('laugh'),
|
|
||||||
'4': () => this.reactDirectly('hmm'),
|
|
||||||
'5': () => this.reactDirectly('surprise'),
|
|
||||||
'6': () => this.reactDirectly('congrats'),
|
|
||||||
'7': () => this.reactDirectly('angry'),
|
|
||||||
'8': () => this.reactDirectly('confused'),
|
|
||||||
'9': () => this.reactDirectly('rip'),
|
|
||||||
'0': () => this.reactDirectly('pudding'),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
isRenote(): boolean {
|
|
||||||
return (this.note.renote &&
|
|
||||||
this.note.text == null &&
|
|
||||||
this.note.fileIds.length == 0 &&
|
|
||||||
this.note.poll == null);
|
|
||||||
},
|
|
||||||
|
|
||||||
p(): any {
|
|
||||||
return this.isRenote ? this.note.renote : this.note;
|
|
||||||
},
|
|
||||||
|
|
||||||
reactionsCount(): number {
|
|
||||||
return this.p.reactionCounts
|
|
||||||
? sum(Object.values(this.p.reactionCounts))
|
|
||||||
: 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
title(): string {
|
|
||||||
return new Date(this.p.createdAt).toLocaleString();
|
|
||||||
},
|
|
||||||
|
|
||||||
urls(): string[] {
|
|
||||||
if (this.p.text) {
|
|
||||||
const ast = parse(this.p.text);
|
|
||||||
return ast
|
|
||||||
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
|
|
||||||
.map(t => t.url);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
reply(viaKeyboard = false) {
|
|
||||||
(this as any).os.new(MkPostFormWindow, {
|
|
||||||
reply: this.p,
|
|
||||||
animation: !viaKeyboard
|
|
||||||
}).$once('closed', this.focus);
|
|
||||||
},
|
|
||||||
|
|
||||||
renote(viaKeyboard = false) {
|
|
||||||
(this as any).os.new(MkRenoteFormWindow, {
|
|
||||||
note: this.p,
|
|
||||||
animation: !viaKeyboard
|
|
||||||
}).$once('closed', this.focus);
|
|
||||||
},
|
|
||||||
|
|
||||||
renoteDirectly() {
|
|
||||||
(this as any).api('notes/create', {
|
|
||||||
renoteId: this.p.id
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
react(viaKeyboard = false) {
|
|
||||||
this.blur();
|
|
||||||
(this as any).os.new(MkReactionPicker, {
|
|
||||||
source: this.$refs.reactButton,
|
|
||||||
note: this.p,
|
|
||||||
showFocus: viaKeyboard,
|
|
||||||
animation: !viaKeyboard
|
|
||||||
}).$once('closed', this.focus);
|
|
||||||
},
|
|
||||||
|
|
||||||
reactDirectly(reaction) {
|
|
||||||
(this as any).api('notes/reactions/create', {
|
|
||||||
noteId: this.p.id,
|
|
||||||
reaction: reaction
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
menu(viaKeyboard = false) {
|
|
||||||
(this as any).os.new(MkNoteMenu, {
|
|
||||||
source: this.$refs.menuButton,
|
|
||||||
note: this.p,
|
|
||||||
animation: !viaKeyboard
|
|
||||||
}).$once('closed', this.focus);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleShowContent() {
|
|
||||||
this.showContent = !this.showContent;
|
|
||||||
},
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
this.$el.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
blur() {
|
|
||||||
this.$el.blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
focusBefore() {
|
|
||||||
focus(this.$el, e => e.previousElementSibling);
|
|
||||||
},
|
|
||||||
|
|
||||||
focusAfter() {
|
|
||||||
focus(this.$el, e => e.nextElementSibling);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -445,10 +293,6 @@ export default Vue.extend({
|
|||||||
&.reacted, &.reacted:hover
|
&.reacted, &.reacted:hover
|
||||||
color var(--noteActionsReactionHover)
|
color var(--noteActionsReactionHover)
|
||||||
|
|
||||||
> .detail
|
|
||||||
padding-top 4px
|
|
||||||
background rgba(#000, 0.0125)
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="stylus" module>
|
<style lang="stylus" module>
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
<button @click="resolveInitPromise">%i18n:@retry%</button>
|
<button @click="resolveInitPromise">%i18n:@retry%</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="placeholder" v-if="fetching">
|
||||||
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||||
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notes" class="notes transition" tag="div" ref="notes">
|
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notes" class="notes transition" tag="div" ref="notes">
|
||||||
<template v-for="(note, i) in _notes">
|
<template v-for="(note, i) in _notes">
|
||||||
@ -226,6 +232,10 @@ export default Vue.extend({
|
|||||||
> *
|
> *
|
||||||
transition transform .3s ease, opacity .3s ease
|
transition transform .3s ease, opacity .3s ease
|
||||||
|
|
||||||
|
> .placeholder
|
||||||
|
padding 32px
|
||||||
|
opacity 0.3
|
||||||
|
|
||||||
> .notes
|
> .notes
|
||||||
> .date
|
> .date
|
||||||
display block
|
display block
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-notifications">
|
<div class="mk-notifications">
|
||||||
|
<div class="placeholder" v-if="fetching">
|
||||||
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="notifications" v-if="notifications.length != 0">
|
<div class="notifications" v-if="notifications.length != 0">
|
||||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||||
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition" tag="div">
|
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition" tag="div">
|
||||||
@ -102,7 +108,6 @@
|
|||||||
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
|
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
|
||||||
</button>
|
</button>
|
||||||
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
||||||
<p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -202,6 +207,10 @@ export default Vue.extend({
|
|||||||
> *
|
> *
|
||||||
transition transform .3s ease, opacity .3s ease
|
transition transform .3s ease, opacity .3s ease
|
||||||
|
|
||||||
|
> .placeholder
|
||||||
|
padding 16px
|
||||||
|
opacity 0.3
|
||||||
|
|
||||||
> .notifications
|
> .notifications
|
||||||
> div
|
> div
|
||||||
> .notification
|
> .notification
|
||||||
@ -319,13 +328,4 @@ export default Vue.extend({
|
|||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color #aaa
|
||||||
|
|
||||||
> .loading
|
|
||||||
margin 0
|
|
||||||
padding 16px
|
|
||||||
text-align center
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -65,6 +65,7 @@ import { host } from '../../../config';
|
|||||||
import { erase, unique } from '../../../../../prelude/array';
|
import { erase, unique } from '../../../../../prelude/array';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import parseAcct from '../../../../../misc/acct/parse';
|
import parseAcct from '../../../../../misc/acct/parse';
|
||||||
|
import { toASCII } from 'punycode';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
@ -158,14 +159,14 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.reply && this.reply.user.host != null) {
|
if (this.reply && this.reply.user.host != null) {
|
||||||
this.text = `@${this.reply.user.username}@${this.reply.user.host} `;
|
this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.reply && this.reply.text != null) {
|
if (this.reply && this.reply.text != null) {
|
||||||
const ast = parse(this.reply.text);
|
const ast = parse(this.reply.text);
|
||||||
|
|
||||||
ast.filter(t => t.type == 'mention').forEach(x => {
|
ast.filter(t => t.type == 'mention').forEach(x => {
|
||||||
const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`;
|
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
||||||
|
|
||||||
// 自分は除外
|
// 自分は除外
|
||||||
if (this.$store.state.i.username == x.username && x.host == null) return;
|
if (this.$store.state.i.username == x.username && x.host == null) return;
|
||||||
|
@ -21,12 +21,13 @@
|
|||||||
<ui-button primary @click="save">%i18n:@save%</ui-button>
|
<ui-button primary @click="save">%i18n:@save%</ui-button>
|
||||||
<section>
|
<section>
|
||||||
<h2>%i18n:@locked-account%</h2>
|
<h2>%i18n:@locked-account%</h2>
|
||||||
<ui-switch v-model="$store.state.i.isLocked" @change="onChangeIsLocked">%i18n:@is-locked%</ui-switch>
|
<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch>
|
||||||
|
<ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>%i18n:@other%</h2>
|
<h2>%i18n:@other%</h2>
|
||||||
<ui-switch v-model="$store.state.i.isBot" @change="onChangeIsBot">%i18n:@is-bot%</ui-switch>
|
<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch>
|
||||||
<ui-switch v-model="$store.state.i.isCat" @change="onChangeIsCat">%i18n:@is-cat%</ui-switch>
|
<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch>
|
||||||
<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch>
|
<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -42,6 +43,10 @@ export default Vue.extend({
|
|||||||
location: null,
|
location: null,
|
||||||
description: null,
|
description: null,
|
||||||
birthday: null,
|
birthday: null,
|
||||||
|
isBot: false,
|
||||||
|
isCat: false,
|
||||||
|
isLocked: false,
|
||||||
|
carefulBot: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -55,34 +60,29 @@ export default Vue.extend({
|
|||||||
this.location = this.$store.state.i.profile.location;
|
this.location = this.$store.state.i.profile.location;
|
||||||
this.description = this.$store.state.i.description;
|
this.description = this.$store.state.i.description;
|
||||||
this.birthday = this.$store.state.i.profile.birthday;
|
this.birthday = this.$store.state.i.profile.birthday;
|
||||||
|
this.isCat = this.$store.state.i.isCat;
|
||||||
|
this.isBot = this.$store.state.i.isBot;
|
||||||
|
this.isLocked = this.$store.state.i.isLocked;
|
||||||
|
this.carefulBot = this.$store.state.i.carefulBot;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateAvatar() {
|
updateAvatar() {
|
||||||
(this as any).apis.updateAvatar();
|
(this as any).apis.updateAvatar();
|
||||||
},
|
},
|
||||||
save() {
|
save(notify) {
|
||||||
(this as any).api('i/update', {
|
(this as any).api('i/update', {
|
||||||
name: this.name || null,
|
name: this.name || null,
|
||||||
location: this.location || null,
|
location: this.location || null,
|
||||||
description: this.description || null,
|
description: this.description || null,
|
||||||
birthday: this.birthday || null
|
birthday: this.birthday || null,
|
||||||
|
isCat: this.isCat,
|
||||||
|
isBot: this.isBot,
|
||||||
|
isLocked: this.isLocked,
|
||||||
|
carefulBot: this.carefulBot
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
if (notify) {
|
||||||
(this as any).apis.notify('%i18n:@profile-updated%');
|
(this as any).apis.notify('%i18n:@profile-updated%');
|
||||||
});
|
}
|
||||||
},
|
|
||||||
onChangeIsLocked() {
|
|
||||||
(this as any).api('i/update', {
|
|
||||||
isLocked: this.$store.state.i.isLocked
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onChangeIsBot() {
|
|
||||||
(this as any).api('i/update', {
|
|
||||||
isBot: this.$store.state.i.isBot
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onChangeIsCat() {
|
|
||||||
(this as any).api('i/update', {
|
|
||||||
isCat: this.$store.state.i.isCat
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,13 @@
|
|||||||
<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
||||||
<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||||
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>%i18n:@navbar-position%</header>
|
||||||
|
<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio>
|
||||||
|
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
||||||
|
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
@ -293,6 +300,11 @@ export default Vue.extend({
|
|||||||
set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navbar: {
|
||||||
|
get() { return this.$store.state.device.navbar; },
|
||||||
|
set(value) { this.$store.commit('device/set', { key: 'navbar', value }); }
|
||||||
|
},
|
||||||
|
|
||||||
enableSounds: {
|
enableSounds: {
|
||||||
get() { return this.$store.state.device.enableSounds; },
|
get() { return this.$store.state.device.enableSounds; },
|
||||||
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-timeline-core">
|
<div class="mk-timeline-core">
|
||||||
<mk-friends-maker v-if="src == 'home' && alone"/>
|
<mk-friends-maker v-if="src == 'home' && alone"/>
|
||||||
<div class="fetching" v-if="fetching">
|
|
||||||
<mk-ellipsis-icon/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mk-notes ref="timeline" :more="existMore ? more : null">
|
<mk-notes ref="timeline" :more="existMore ? more : null">
|
||||||
<p :class="$style.empty" slot="empty">
|
<p :class="$style.empty" slot="empty">
|
||||||
@ -170,15 +167,10 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.mk-timeline-core
|
.mk-timeline-core
|
||||||
> .mk-friends-maker
|
> .mk-friends-maker
|
||||||
border-bottom solid 1px #eee
|
border-bottom solid 1px #eee
|
||||||
|
|
||||||
> .fetching
|
|
||||||
padding 64px 0
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="stylus" module>
|
<style lang="stylus" module>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<li @click="list">
|
<li @click="list">
|
||||||
<p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p>
|
<p>%fa:list%<span>%i18n:@lists%</span>%fa:angle-right%</p>
|
||||||
</li>
|
</li>
|
||||||
<li @click="followRequests" v-if="$store.state.i.isLocked">
|
<li @click="followRequests" v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
|
||||||
<p>%fa:envelope R%<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>%fa:angle-right%</p>
|
<p>%fa:envelope R%<span>%i18n:@follow-requests%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>%fa:angle-right%</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -157,6 +157,9 @@ export default Vue.extend({
|
|||||||
font-family Meiryo, sans-serif
|
font-family Meiryo, sans-serif
|
||||||
text-decoration none
|
text-decoration none
|
||||||
|
|
||||||
|
@media (max-width 1100px)
|
||||||
|
display none
|
||||||
|
|
||||||
[data-fa]
|
[data-fa]
|
||||||
margin-left 8px
|
margin-left 8px
|
||||||
|
|
||||||
@ -171,6 +174,9 @@ export default Vue.extend({
|
|||||||
border-radius 4px
|
border-radius 4px
|
||||||
transition filter 100ms ease
|
transition filter 100ms ease
|
||||||
|
|
||||||
|
@media (max-width 1100px)
|
||||||
|
margin-left 8px
|
||||||
|
|
||||||
> .menu
|
> .menu
|
||||||
$bgcolor = var(--face)
|
$bgcolor = var(--face)
|
||||||
display block
|
display block
|
||||||
|
@ -17,8 +17,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.note
|
.note
|
||||||
display inline-block
|
display inline-block
|
||||||
padding 8px
|
padding 8px
|
||||||
|
@ -29,6 +29,9 @@ export default Vue.extend({
|
|||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.search
|
.search
|
||||||
|
@media (max-width 800px)
|
||||||
|
display none !important
|
||||||
|
|
||||||
> [data-fa]
|
> [data-fa]
|
||||||
display block
|
display block
|
||||||
position absolute
|
position absolute
|
||||||
@ -58,6 +61,9 @@ export default Vue.extend({
|
|||||||
transition color 0.5s ease, border 0.5s ease
|
transition color 0.5s ease, border 0.5s ease
|
||||||
color var(--desktopHeaderSearchFg)
|
color var(--desktopHeaderSearchFg)
|
||||||
|
|
||||||
|
@media (max-width 1000px)
|
||||||
|
width 10em
|
||||||
|
|
||||||
&::placeholder
|
&::placeholder
|
||||||
color var(--desktopHeaderFg)
|
color var(--desktopHeaderFg)
|
||||||
|
|
||||||
|
368
src/client/app/desktop/views/components/ui.sidebar.vue
Normal file
368
src/client/app/desktop/views/components/ui.sidebar.vue
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
<template>
|
||||||
|
<div class="header" :class="navbar">
|
||||||
|
<div class="body">
|
||||||
|
<div class="post">
|
||||||
|
<button @click="post" title="%i18n:@post%">%fa:pencil-alt%</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav" v-if="$store.getters.isSignedIn">
|
||||||
|
<div class="home" :class="{ active: $route.name == 'index' }" @click="goToTop">
|
||||||
|
<router-link to="/">%fa:home%</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
||||||
|
<router-link to="/deck">%fa:columns%</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="messaging">
|
||||||
|
<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a>
|
||||||
|
</div>
|
||||||
|
<div class="game">
|
||||||
|
<a @click="game">%fa:gamepad%<template v-if="hasGameInvitations">%fa:circle%</template></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav bottom" v-if="$store.getters.isSignedIn">
|
||||||
|
<div>
|
||||||
|
<a @click="drive">%fa:cloud%</a>
|
||||||
|
</div>
|
||||||
|
<div ref="notificationsButton" :class="{ active: showNotifications }">
|
||||||
|
<a @click="notifications">%fa:R bell%</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a @click="settings">%fa:cog%</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="account">
|
||||||
|
<router-link :to="`/@${ $store.state.i.username }`">
|
||||||
|
<mk-avatar class="avatar" :user="$store.state.i"/>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<div class="nav menu">
|
||||||
|
<div class="signout">
|
||||||
|
<a @click="signout">%fa:power-off%</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<router-link to="/i/favorites">%fa:star%</router-link>
|
||||||
|
</div>
|
||||||
|
<div v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
|
||||||
|
<a @click="followRequests">%fa:envelope R%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav dark">
|
||||||
|
<div>
|
||||||
|
<a @click="dark"><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition :name="`slide-${navbar}`">
|
||||||
|
<div class="notifications" v-if="showNotifications" ref="notifications" :class="navbar">
|
||||||
|
<mk-notifications/>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import MkUserListsWindow from './user-lists-window.vue';
|
||||||
|
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
||||||
|
import MkSettingsWindow from './settings-window.vue';
|
||||||
|
import MkDriveWindow from './drive-window.vue';
|
||||||
|
import MkMessagingWindow from './messaging-window.vue';
|
||||||
|
import MkGameWindow from './game-window.vue';
|
||||||
|
import contains from '../../../common/scripts/contains';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hasGameInvitations: false,
|
||||||
|
connection: null,
|
||||||
|
showNotifications: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
hasUnreadMessagingMessage(): boolean {
|
||||||
|
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
|
||||||
|
},
|
||||||
|
|
||||||
|
navbar(): string {
|
||||||
|
return this.$store.state.device.navbar;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||||
|
|
||||||
|
this.connection.on('reversiInvited', this.onReversiInvited);
|
||||||
|
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.$store.getters.isSignedIn) {
|
||||||
|
this.connection.dispose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onReversiInvited() {
|
||||||
|
this.hasGameInvitations = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
onReversiNoInvites() {
|
||||||
|
this.hasGameInvitations = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
messaging() {
|
||||||
|
(this as any).os.new(MkMessagingWindow);
|
||||||
|
},
|
||||||
|
|
||||||
|
game() {
|
||||||
|
(this as any).os.new(MkGameWindow);
|
||||||
|
},
|
||||||
|
|
||||||
|
post() {
|
||||||
|
(this as any).apis.post();
|
||||||
|
},
|
||||||
|
|
||||||
|
drive() {
|
||||||
|
(this as any).os.new(MkDriveWindow);
|
||||||
|
},
|
||||||
|
|
||||||
|
list() {
|
||||||
|
const w = (this as any).os.new(MkUserListsWindow);
|
||||||
|
w.$once('choosen', list => {
|
||||||
|
this.$router.push(`i/lists/${ list.id }`);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
followRequests() {
|
||||||
|
(this as any).os.new(MkFollowRequestsWindow);
|
||||||
|
},
|
||||||
|
|
||||||
|
settings() {
|
||||||
|
(this as any).os.new(MkSettingsWindow);
|
||||||
|
},
|
||||||
|
|
||||||
|
signout() {
|
||||||
|
(this as any).os.signout();
|
||||||
|
},
|
||||||
|
|
||||||
|
notifications() {
|
||||||
|
this.showNotifications ? this.closeNotifications() : this.openNotifications();
|
||||||
|
},
|
||||||
|
|
||||||
|
openNotifications() {
|
||||||
|
this.showNotifications = true;
|
||||||
|
Array.from(document.querySelectorAll('body *')).forEach(el => {
|
||||||
|
el.addEventListener('mousedown', this.onMousedown);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeNotifications() {
|
||||||
|
this.showNotifications = false;
|
||||||
|
Array.from(document.querySelectorAll('body *')).forEach(el => {
|
||||||
|
el.removeEventListener('mousedown', this.onMousedown);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onMousedown(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (
|
||||||
|
!contains(this.$refs.notifications, e.target) &&
|
||||||
|
this.$refs.notifications != e.target &&
|
||||||
|
!contains(this.$refs.notificationsButton, e.target) &&
|
||||||
|
this.$refs.notificationsButton != e.target
|
||||||
|
) {
|
||||||
|
this.closeNotifications();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
dark() {
|
||||||
|
this.$store.commit('device/set', {
|
||||||
|
key: 'darkmode',
|
||||||
|
value: !this.$store.state.device.darkmode
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
goToTop() {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.header
|
||||||
|
$width = 68px
|
||||||
|
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
z-index 1000
|
||||||
|
width $width
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
&.left
|
||||||
|
left 0
|
||||||
|
box-shadow var(--shadowRight)
|
||||||
|
|
||||||
|
&.right
|
||||||
|
right 0
|
||||||
|
box-shadow var(--shadowLeft)
|
||||||
|
|
||||||
|
> .body
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
z-index 1
|
||||||
|
width $width
|
||||||
|
height 100%
|
||||||
|
background var(--desktopHeaderBg)
|
||||||
|
|
||||||
|
> .post
|
||||||
|
width $width
|
||||||
|
height $width
|
||||||
|
padding 12px
|
||||||
|
|
||||||
|
> button
|
||||||
|
display inline-block
|
||||||
|
margin 0
|
||||||
|
padding 0
|
||||||
|
height 100%
|
||||||
|
width 100%
|
||||||
|
font-size 1.2em
|
||||||
|
font-weight normal
|
||||||
|
text-decoration none
|
||||||
|
color var(--primaryForeground)
|
||||||
|
background var(--primary) !important
|
||||||
|
outline none
|
||||||
|
border none
|
||||||
|
border-radius 100%
|
||||||
|
transition background 0.1s ease
|
||||||
|
cursor pointer
|
||||||
|
|
||||||
|
*
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background var(--primaryLighten10) !important
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background var(--primaryDarken10) !important
|
||||||
|
transition background 0s ease
|
||||||
|
|
||||||
|
> .nav.bottom
|
||||||
|
position absolute
|
||||||
|
bottom 128px
|
||||||
|
left 0
|
||||||
|
|
||||||
|
> .account
|
||||||
|
position absolute
|
||||||
|
bottom 64px
|
||||||
|
left 0
|
||||||
|
width $width
|
||||||
|
height $width
|
||||||
|
padding 14px
|
||||||
|
|
||||||
|
> .menu
|
||||||
|
display none
|
||||||
|
position absolute
|
||||||
|
bottom 64px
|
||||||
|
left 0
|
||||||
|
background var(--desktopHeaderBg)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
> .menu
|
||||||
|
display block
|
||||||
|
|
||||||
|
> *:not(.menu)
|
||||||
|
display block
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
> .avatar
|
||||||
|
pointer-events none
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
> .dark
|
||||||
|
position absolute
|
||||||
|
bottom 0
|
||||||
|
left 0
|
||||||
|
width $width
|
||||||
|
height $width
|
||||||
|
|
||||||
|
> .notifications
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
width 350px
|
||||||
|
height 100%
|
||||||
|
overflow auto
|
||||||
|
background var(--face)
|
||||||
|
|
||||||
|
&.left
|
||||||
|
left $width
|
||||||
|
box-shadow var(--shadowRight)
|
||||||
|
|
||||||
|
&.right
|
||||||
|
right $width
|
||||||
|
box-shadow var(--shadowLeft)
|
||||||
|
|
||||||
|
.nav
|
||||||
|
> *
|
||||||
|
> *
|
||||||
|
display block
|
||||||
|
width $width
|
||||||
|
line-height 52px
|
||||||
|
text-align center
|
||||||
|
font-size 18px
|
||||||
|
color var(--desktopHeaderFg)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background rgba(0, 0, 0, 0.05)
|
||||||
|
color var(--desktopHeaderHoverFg)
|
||||||
|
text-decoration none
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background rgba(0, 0, 0, 0.1)
|
||||||
|
|
||||||
|
&.left
|
||||||
|
.nav
|
||||||
|
> *
|
||||||
|
&.active
|
||||||
|
box-shadow -4px 0 var(--primary) inset
|
||||||
|
|
||||||
|
&.right
|
||||||
|
.nav
|
||||||
|
> *
|
||||||
|
&.active
|
||||||
|
box-shadow 4px 0 var(--primary) inset
|
||||||
|
|
||||||
|
.slide-left-enter-active,
|
||||||
|
.slide-left-leave-active {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-enter, .slide-left-leave-to {
|
||||||
|
transform: translateX(-16px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-enter-active,
|
||||||
|
.slide-right-leave-active {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-enter, .slide-right-leave-to {
|
||||||
|
transform: translateX(16px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-ui" v-hotkey.global="keymap">
|
<div class="mk-ui" v-hotkey.global="keymap">
|
||||||
<div class="bg" v-if="$store.getters.isSignedIn && $store.state.i.wallpaperUrl" :style="style"></div>
|
<div class="bg" v-if="$store.getters.isSignedIn && $store.state.i.wallpaperUrl" :style="style"></div>
|
||||||
<x-header class="header" v-show="!zenMode" ref="header"/>
|
<x-header class="header" v-if="navbar == 'top'" v-show="!zenMode" ref="header"/>
|
||||||
<div class="content">
|
<x-sidebar class="sidebar" v-if="navbar != 'top'" ref="sidebar"/>
|
||||||
|
<div class="content" :class="[{ sidebar: navbar != 'top' }, navbar]">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<mk-stream-indicator v-if="$store.getters.isSignedIn"/>
|
<mk-stream-indicator v-if="$store.getters.isSignedIn"/>
|
||||||
@ -12,10 +13,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XHeader from './ui.header.vue';
|
import XHeader from './ui.header.vue';
|
||||||
|
import XSidebar from './ui.sidebar.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XHeader
|
XHeader,
|
||||||
|
XSidebar
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@ -25,6 +28,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
navbar(): string {
|
||||||
|
return this.$store.state.device.navbar;
|
||||||
|
},
|
||||||
|
|
||||||
style(): any {
|
style(): any {
|
||||||
if (!this.$store.getters.isSignedIn || this.$store.state.i.wallpaperUrl == null) return {};
|
if (!this.$store.getters.isSignedIn || this.$store.state.i.wallpaperUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
@ -45,6 +52,12 @@ export default Vue.extend({
|
|||||||
watch: {
|
watch: {
|
||||||
'$store.state.uiHeaderHeight'() {
|
'$store.state.uiHeaderHeight'() {
|
||||||
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
||||||
|
},
|
||||||
|
|
||||||
|
navbar() {
|
||||||
|
if (this.navbar != 'top') {
|
||||||
|
this.$store.commit('setUiHeaderHeight', 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -83,8 +96,10 @@ export default Vue.extend({
|
|||||||
background-attachment fixed
|
background-attachment fixed
|
||||||
opacity 0.3
|
opacity 0.3
|
||||||
|
|
||||||
> .header
|
> .content.sidebar.left
|
||||||
@media (max-width 1000px)
|
padding-left 68px
|
||||||
display none
|
|
||||||
|
> .content.sidebar.right
|
||||||
|
padding-right 68px
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -78,7 +78,7 @@ export default Vue.extend({
|
|||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
this.connection.on('statsLog', this.onStatsLog);
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
this.connection.send('requestLog', {
|
this.connection.send('requestLog', {
|
||||||
id: Math.random().toString(),
|
id: Math.random().toString().substr(2, 8),
|
||||||
length: 200
|
length: 200
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -276,13 +276,24 @@ export default Vue.extend({
|
|||||||
min-width 330px
|
min-width 330px
|
||||||
height 100%
|
height 100%
|
||||||
background var(--face)
|
background var(--face)
|
||||||
border-radius 6px
|
border-radius var(--round)
|
||||||
//box-shadow 0 2px 16px rgba(#000, 0.1)
|
box-shadow var(--shadow)
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
&.draghover
|
&.draghover
|
||||||
box-shadow 0 0 0 2px var(--primaryAlpha08)
|
box-shadow 0 0 0 2px var(--primaryAlpha08)
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
z-index 1000
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background var(--primaryAlpha02)
|
||||||
|
|
||||||
&.dragging
|
&.dragging
|
||||||
box-shadow 0 0 0 2px var(--primaryAlpha04)
|
box-shadow 0 0 0 2px var(--primaryAlpha04)
|
||||||
|
|
||||||
@ -310,7 +321,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
> header
|
> header
|
||||||
display flex
|
display flex
|
||||||
z-index 1
|
z-index 2
|
||||||
line-height $header-height
|
line-height $header-height
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
font-size 14px
|
font-size 14px
|
||||||
@ -338,6 +349,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
> .toggleActive
|
> .toggleActive
|
||||||
> .menu
|
> .menu
|
||||||
|
padding 0
|
||||||
width $header-height
|
width $header-height
|
||||||
line-height $header-height
|
line-height $header-height
|
||||||
font-size 16px
|
font-size 16px
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!mediaView" class="zyjjkidcqjnlegkqebitfviomuqmseqk" :class="{ renote: isRenote }">
|
<div
|
||||||
<div class="reply-to" v-if="p.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
v-if="!mediaView"
|
||||||
<x-sub :note="p.reply"/>
|
v-show="appearNote.deletedAt == null"
|
||||||
|
:tabindex="appearNote.deletedAt == null ? '-1' : null"
|
||||||
|
class="zyjjkidcqjnlegkqebitfviomuqmseqk"
|
||||||
|
:class="{ renote: isRenote }"
|
||||||
|
v-hotkey="keymap"
|
||||||
|
:title="title"
|
||||||
|
>
|
||||||
|
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
||||||
|
<x-sub :note="appearNote.reply"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="renote" v-if="isRenote">
|
<div class="renote" v-if="isRenote">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
@ -12,43 +20,42 @@
|
|||||||
<mk-time :time="note.createdAt"/>
|
<mk-time :time="note.createdAt"/>
|
||||||
</div>
|
</div>
|
||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user"/>
|
<mk-avatar class="avatar" :user="appearNote.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<mk-note-header class="header" :note="p" :mini="true"/>
|
<mk-note-header class="header" :note="appearNote" :mini="true"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
|
||||||
<mk-cw-button v-model="showContent"/>
|
<mk-cw-button v-model="showContent"/>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-show="p.cw == null || showContent">
|
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i"/>
|
||||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
|
<a class="rp" v-if="appearNote.renote != null">RP:</a>
|
||||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="p.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<mk-media-list :media-list="p.files"/>
|
<mk-media-list :media-list="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
|
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
|
||||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||||
<div class="renote" v-if="p.renote">
|
<div class="renote" v-if="appearNote.renote">
|
||||||
<mk-note-preview :note="p.renote" :mini="true"/>
|
<mk-note-preview :note="appearNote.renote" :mini="true"/>
|
||||||
</div>
|
</div>
|
||||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="false" :mini="true"/>
|
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="false" :mini="true"/>
|
||||||
</div>
|
</div>
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
<span class="app" v-if="appearNote.app">via <b>{{ appearNote.app.name }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
|
||||||
<button @click="reply">
|
<button @click="reply()">
|
||||||
<template v-if="p.reply">%fa:reply-all%</template>
|
<template v-if="appearNote.reply">%fa:reply-all%</template>
|
||||||
<template v-else>%fa:reply%</template>
|
<template v-else>%fa:reply%</template>
|
||||||
</button>
|
</button>
|
||||||
<button @click="renote" title="Renote">%fa:retweet%</button>
|
<button @click="renote()" title="Renote">%fa:retweet%</button>
|
||||||
<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton">%fa:plus%</button>
|
<button :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton">%fa:plus%</button>
|
||||||
<button class="menu" @click="menu" ref="menuButton">%fa:ellipsis-h%</button>
|
<button class="menu" @click="menu()" ref="menuButton">%fa:ellipsis-h%</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@ -65,11 +72,10 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import parse from '../../../../../../mfm/parse';
|
import MkPostFormWindow from '../../components/post-form-window.vue';
|
||||||
|
import MkRenoteFormWindow from '../../components/renote-form-window.vue';
|
||||||
import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
|
|
||||||
import MkReactionPicker from '../../../../common/views/components/reaction-picker.vue';
|
|
||||||
import XSub from './deck.note.sub.vue';
|
import XSub from './deck.note.sub.vue';
|
||||||
|
import noteMixin from '../../../../common/scripts/note-mixin';
|
||||||
import noteSubscriber from '../../../../common/scripts/note-subscriber';
|
import noteSubscriber from '../../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
@ -77,7 +83,10 @@ export default Vue.extend({
|
|||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [noteSubscriber('note')],
|
mixins: [
|
||||||
|
noteMixin(),
|
||||||
|
noteSubscriber('note')
|
||||||
|
],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
@ -89,66 +98,6 @@ export default Vue.extend({
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
showContent: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
isRenote(): boolean {
|
|
||||||
return (this.note.renote &&
|
|
||||||
this.note.text == null &&
|
|
||||||
this.note.fileIds.length == 0 &&
|
|
||||||
this.note.poll == null);
|
|
||||||
},
|
|
||||||
|
|
||||||
p(): any {
|
|
||||||
return this.isRenote ? this.note.renote : this.note;
|
|
||||||
},
|
|
||||||
|
|
||||||
urls(): string[] {
|
|
||||||
if (this.p.text) {
|
|
||||||
const ast = parse(this.p.text);
|
|
||||||
return ast
|
|
||||||
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
|
|
||||||
.map(t => t.url);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
reply() {
|
|
||||||
(this as any).apis.post({
|
|
||||||
reply: this.p
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
renote() {
|
|
||||||
(this as any).apis.post({
|
|
||||||
renote: this.p
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
react() {
|
|
||||||
(this as any).os.new(MkReactionPicker, {
|
|
||||||
source: this.$refs.reactButton,
|
|
||||||
note: this.p,
|
|
||||||
compact: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
menu() {
|
|
||||||
(this as any).os.new(MkNoteMenu, {
|
|
||||||
source: this.$refs.menuButton,
|
|
||||||
note: this.p,
|
|
||||||
compact: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -168,6 +117,20 @@ export default Vue.extend({
|
|||||||
font-size 13px
|
font-size 13px
|
||||||
border-bottom solid 1px var(--faceDivider)
|
border-bottom solid 1px var(--faceDivider)
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
z-index 1
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
pointer-events none
|
||||||
|
position absolute
|
||||||
|
top 2px
|
||||||
|
right 2px
|
||||||
|
bottom 2px
|
||||||
|
left 2px
|
||||||
|
border 2px solid var(--primaryAlpha03)
|
||||||
|
border-radius 4px
|
||||||
|
|
||||||
&:last-of-type
|
&:last-of-type
|
||||||
border-bottom none
|
border-bottom none
|
||||||
|
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
<div class="eamppglmnmimdhrlzhplwpvyeaqmmhxu">
|
<div class="eamppglmnmimdhrlzhplwpvyeaqmmhxu">
|
||||||
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
||||||
|
|
||||||
|
<div class="placeholder" v-if="fetching">
|
||||||
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="!fetching && requestInitPromise != null">
|
<div v-if="!fetching && requestInitPromise != null">
|
||||||
<p>%i18n:@error%</p>
|
<p>%i18n:@error%</p>
|
||||||
<button @click="resolveInitPromise">%i18n:@retry%</button>
|
<button @click="resolveInitPromise">%i18n:@retry%</button>
|
||||||
@ -205,6 +211,10 @@ export default Vue.extend({
|
|||||||
> *
|
> *
|
||||||
transition transform .3s ease, opacity .3s ease
|
transition transform .3s ease, opacity .3s ease
|
||||||
|
|
||||||
|
> .placeholder
|
||||||
|
padding 16px
|
||||||
|
opacity 0.3
|
||||||
|
|
||||||
> .notes
|
> .notes
|
||||||
> .date
|
> .date
|
||||||
display block
|
display block
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="oxynyeqmfvracxnglgulyqfgqxnxmehl">
|
<div class="oxynyeqmfvracxnglgulyqfgqxnxmehl">
|
||||||
|
<div class="placeholder" v-if="fetching">
|
||||||
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||||
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition notifications">
|
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition notifications">
|
||||||
<template v-for="(notification, i) in _notifications">
|
<template v-for="(notification, i) in _notifications">
|
||||||
@ -14,7 +20,6 @@
|
|||||||
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
|
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
|
||||||
</button>
|
</button>
|
||||||
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
||||||
<p class="loading" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -161,6 +166,10 @@ export default Vue.extend({
|
|||||||
> *
|
> *
|
||||||
transition transform .3s ease, opacity .3s ease
|
transition transform .3s ease, opacity .3s ease
|
||||||
|
|
||||||
|
> .placeholder
|
||||||
|
padding 16px
|
||||||
|
opacity 0.3
|
||||||
|
|
||||||
> .notifications
|
> .notifications
|
||||||
|
|
||||||
> .notification:not(:last-child)
|
> .notification:not(:last-child)
|
||||||
@ -207,13 +216,4 @@ export default Vue.extend({
|
|||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color #aaa
|
||||||
|
|
||||||
> .loading
|
|
||||||
margin 0
|
|
||||||
padding 16px
|
|
||||||
text-align center
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,9 +3,6 @@
|
|||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
<h1>{{ q }}</h1>
|
<h1>{{ q }}</h1>
|
||||||
</header>
|
</header>
|
||||||
<div :class="$style.loading" v-if="fetching">
|
|
||||||
<mk-ellipsis-icon/>
|
|
||||||
</div>
|
|
||||||
<p :class="$style.notAvailable" v-if="!fetching && notAvailable">%i18n:@not-available%</p>
|
<p :class="$style.notAvailable" v-if="!fetching && notAvailable">%i18n:@not-available%</p>
|
||||||
<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
|
<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
|
||||||
<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
|
<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
|
||||||
@ -119,9 +116,6 @@ export default Vue.extend({
|
|||||||
border-radius 6px
|
border-radius 6px
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
.loading
|
|
||||||
padding 64px 0
|
|
||||||
|
|
||||||
.empty
|
.empty
|
||||||
display block
|
display block
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -3,9 +3,6 @@
|
|||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
<h1>#{{ $route.params.tag }}</h1>
|
<h1>#{{ $route.params.tag }}</h1>
|
||||||
</header>
|
</header>
|
||||||
<div :class="$style.loading" v-if="fetching">
|
|
||||||
<mk-ellipsis-icon/>
|
|
||||||
</div>
|
|
||||||
<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
|
<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:no-posts-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:no-posts-found%'.split('{}')[1] }}</p>
|
||||||
<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
|
<mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
@ -108,9 +105,6 @@ export default Vue.extend({
|
|||||||
border-radius 6px
|
border-radius 6px
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
.loading
|
|
||||||
padding 64px 0
|
|
||||||
|
|
||||||
.empty
|
.empty
|
||||||
display block
|
display block
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<span class="username"><mk-acct :user="user" :detail="true" /></span>
|
<span class="username"><mk-acct :user="user" :detail="true" /></span>
|
||||||
<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
|
<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
|
||||||
<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
|
|
||||||
<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -18,6 +16,10 @@
|
|||||||
<div class="description">
|
<div class="description">
|
||||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
|
||||||
|
<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span>
|
||||||
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span>
|
<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span>
|
||||||
<span class="following clickable" @click="showFollowing"><b>{{ user.followingCount | number }}</b>%i18n:@following%</span>
|
<span class="following clickable" @click="showFollowing"><b>{{ user.followingCount | number }}</b>%i18n:@following%</span>
|
||||||
@ -182,6 +184,14 @@ export default Vue.extend({
|
|||||||
padding 16px 16px 16px 154px
|
padding 16px 16px 16px 154px
|
||||||
color var(--text)
|
color var(--text)
|
||||||
|
|
||||||
|
> .info
|
||||||
|
margin-top 16px
|
||||||
|
padding-top 16px
|
||||||
|
border-top solid 1px var(--faceDivider)
|
||||||
|
|
||||||
|
> *
|
||||||
|
margin-right 16px
|
||||||
|
|
||||||
> .status
|
> .status
|
||||||
margin-top 16px
|
margin-top 16px
|
||||||
padding-top 16px
|
padding-top 16px
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%fa:comments% %i18n:@with-replies%</span>
|
<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%fa:comments% %i18n:@with-replies%</span>
|
||||||
<span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%fa:images% %i18n:@with-media%</span>
|
<span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%fa:images% %i18n:@with-media%</span>
|
||||||
</header>
|
</header>
|
||||||
<div class="loading" v-if="fetching">
|
|
||||||
<mk-ellipsis-icon/>
|
|
||||||
</div>
|
|
||||||
<mk-notes ref="timeline" :more="existMore ? more : null">
|
<mk-notes ref="timeline" :more="existMore ? more : null">
|
||||||
<p class="empty" slot="empty">%fa:R comments%%i18n:@empty%</p>
|
<p class="empty" slot="empty">%fa:R comments%%i18n:@empty%</p>
|
||||||
</mk-notes>
|
</mk-notes>
|
||||||
@ -152,9 +149,6 @@ export default Vue.extend({
|
|||||||
&:hover
|
&:hover
|
||||||
color var(--desktopTimelineSrcHover)
|
color var(--desktopTimelineSrcHover)
|
||||||
|
|
||||||
> .loading
|
|
||||||
padding 64px 0
|
|
||||||
|
|
||||||
> .empty
|
> .empty
|
||||||
display block
|
display block
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -124,11 +124,17 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
|
|||||||
|
|
||||||
//#region shadow
|
//#region shadow
|
||||||
const shadow = '0 3px 8px rgba(0, 0, 0, 0.2)';
|
const shadow = '0 3px 8px rgba(0, 0, 0, 0.2)';
|
||||||
|
const shadowRight = '4px 0 4px rgba(0, 0, 0, 0.1)';
|
||||||
|
const shadowLeft = '-4px 0 4px rgba(0, 0, 0, 0.1)';
|
||||||
if (os.store.state.settings.useShadow) document.documentElement.style.setProperty('--shadow', shadow);
|
if (os.store.state.settings.useShadow) document.documentElement.style.setProperty('--shadow', shadow);
|
||||||
|
if (os.store.state.settings.useShadow) document.documentElement.style.setProperty('--shadowRight', shadowRight);
|
||||||
|
if (os.store.state.settings.useShadow) document.documentElement.style.setProperty('--shadowLeft', shadowLeft);
|
||||||
os.store.watch(s => {
|
os.store.watch(s => {
|
||||||
return s.settings.useShadow;
|
return s.settings.useShadow;
|
||||||
}, v => {
|
}, v => {
|
||||||
document.documentElement.style.setProperty('--shadow', v ? shadow : 'none');
|
document.documentElement.style.setProperty('--shadow', v ? shadow : 'none');
|
||||||
|
document.documentElement.style.setProperty('--shadowRight', v ? shadowRight : 'none');
|
||||||
|
document.documentElement.style.setProperty('--shadowLeft', v ? shadowLeft : 'none');
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
@ -443,10 +443,10 @@ export default class MiOS extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
const viaStream = this.stream && this.store.state.device.apiViaStream && !forceFetch;
|
const viaStream = this.stream && this.stream.state == 'connected' && this.store.state.device.apiViaStream && !forceFetch;
|
||||||
|
|
||||||
if (viaStream) {
|
if (viaStream) {
|
||||||
const id = Math.random().toString();
|
const id = Math.random().toString().substr(2, 8);
|
||||||
|
|
||||||
this.stream.once(`api:${id}`, res => {
|
this.stream.once(`api:${id}`, res => {
|
||||||
if (res == null || Object.keys(res).length == 0) {
|
if (res == null || Object.keys(res).length == 0) {
|
||||||
|
@ -18,6 +18,7 @@ export default (os) => (opts) => {
|
|||||||
}).$mount();
|
}).$mount();
|
||||||
vm.$once('cancel', recover);
|
vm.$once('cancel', recover);
|
||||||
vm.$once('posted', recover);
|
vm.$once('posted', recover);
|
||||||
|
if (o.cb) vm.$once('closed', o.cb);
|
||||||
document.body.appendChild(vm.$el);
|
document.body.appendChild(vm.$el);
|
||||||
(vm as any).focus();
|
(vm as any).focus();
|
||||||
};
|
};
|
||||||
|
@ -91,8 +91,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
|
|
||||||
|
|
||||||
.mk-dialog
|
.mk-dialog
|
||||||
> .bg
|
> .bg
|
||||||
display block
|
display block
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
<ui-button link :href="`${file.url}?download`" :download="file.name">%fa:download% %i18n:@download%</ui-button>
|
<ui-button link :href="`${file.url}?download`" :download="file.name">%fa:download% %i18n:@download%</ui-button>
|
||||||
<ui-button @click="rename">%fa:pencil-alt% %i18n:@rename%</ui-button>
|
<ui-button @click="rename">%fa:pencil-alt% %i18n:@rename%</ui-button>
|
||||||
<ui-button @click="move">%fa:R folder-open% %i18n:@move%</ui-button>
|
<ui-button @click="move">%fa:R folder-open% %i18n:@move%</ui-button>
|
||||||
|
<ui-button @click="toggleSensitive" v-if="file.isSensitive">%fa:R eye% %i18n:@unmark-as-sensitive%</ui-button>
|
||||||
|
<ui-button @click="toggleSensitive" v-else>%fa:R eye-slash% %i18n:@mark-as-sensitive%</ui-button>
|
||||||
<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button>
|
<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -71,25 +73,30 @@ import { gcd } from '../../../../../prelude/math';
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['file'],
|
props: ['file'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
gcd,
|
gcd,
|
||||||
exif: null
|
exif: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
browser(): any {
|
browser(): any {
|
||||||
return this.$parent;
|
return this.$parent;
|
||||||
},
|
},
|
||||||
|
|
||||||
kind(): string {
|
kind(): string {
|
||||||
return this.file.type.split('/')[0];
|
return this.file.type.split('/')[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
style(): any {
|
style(): any {
|
||||||
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? {
|
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? {
|
||||||
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
|
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
|
||||||
} : {};
|
} : {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
rename() {
|
rename() {
|
||||||
const name = window.prompt('%i18n:@rename%', this.file.name);
|
const name = window.prompt('%i18n:@rename%', this.file.name);
|
||||||
@ -101,6 +108,7 @@ export default Vue.extend({
|
|||||||
this.browser.cf(this.file, true);
|
this.browser.cf(this.file, true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
move() {
|
move() {
|
||||||
(this as any).apis.chooseDriveFolder().then(folder => {
|
(this as any).apis.chooseDriveFolder().then(folder => {
|
||||||
(this as any).api('drive/files/update', {
|
(this as any).api('drive/files/update', {
|
||||||
@ -111,6 +119,7 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
del() {
|
del() {
|
||||||
(this as any).api('drive/files/delete', {
|
(this as any).api('drive/files/delete', {
|
||||||
fileId: this.file.id
|
fileId: this.file.id
|
||||||
@ -118,9 +127,20 @@ export default Vue.extend({
|
|||||||
this.browser.cd(this.file.folderId, true);
|
this.browser.cd(this.file.folderId, true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleSensitive() {
|
||||||
|
(this as any).api('drive/files/update', {
|
||||||
|
fileId: this.file.id,
|
||||||
|
isSensitive: !this.file.isSensitive
|
||||||
|
});
|
||||||
|
|
||||||
|
this.file.isSensitive = !this.file.isSensitive;
|
||||||
|
},
|
||||||
|
|
||||||
showCreatedAt() {
|
showCreatedAt() {
|
||||||
alert(new Date(this.file.createdAt).toLocaleString());
|
alert(new Date(this.file.createdAt).toLocaleString());
|
||||||
},
|
},
|
||||||
|
|
||||||
onImageLoaded() {
|
onImageLoaded() {
|
||||||
const self = this;
|
const self = this;
|
||||||
EXIF.getData(this.$refs.img, function(this: any) {
|
EXIF.getData(this.$refs.img, function(this: any) {
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="note" :class="{ renote: isRenote, smart: $store.state.device.postStyle == 'smart' }">
|
<div
|
||||||
<div class="reply-to" v-if="p.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
class="note"
|
||||||
<x-sub :note="p.reply"/>
|
v-show="appearNote.deletedAt == null"
|
||||||
|
:tabindex="appearNote.deletedAt == null ? '-1' : null"
|
||||||
|
:class="{ renote: isRenote, smart: $store.state.device.postStyle == 'smart' }"
|
||||||
|
v-hotkey="keymap"
|
||||||
|
>
|
||||||
|
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
||||||
|
<x-sub :note="appearNote.reply"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="renote" v-if="isRenote">
|
<div class="renote" v-if="isRenote">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
@ -12,47 +18,45 @@
|
|||||||
<mk-time :time="note.createdAt"/>
|
<mk-time :time="note.createdAt"/>
|
||||||
</div>
|
</div>
|
||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
<mk-avatar class="avatar" :user="appearNote.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<mk-note-header class="header" :note="p" :mini="true"/>
|
<mk-note-header class="header" :note="appearNote" :mini="true"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
|
||||||
<mk-cw-button v-model="showContent"/>
|
<mk-cw-button v-model="showContent"/>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-show="p.cw == null || showContent">
|
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
||||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
<a class="rp" v-if="appearNote.renote != null">RP:</a>
|
||||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="p.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<mk-media-list :media-list="p.files"/>
|
<mk-media-list :media-list="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
|
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
|
||||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||||
<div class="map" v-if="p.geo" ref="map"></div>
|
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div>
|
||||||
<div class="renote" v-if="p.renote"><mk-note-preview :note="p.renote"/></div>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
<span class="app" v-if="appearNote.app">via <b>{{ appearNote.app.name }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
<footer v-if="p.deletedAt == null">
|
<footer>
|
||||||
<mk-reactions-viewer :note="p" ref="reactionsViewer"/>
|
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
|
||||||
<button @click="reply">
|
<button @click="reply()">
|
||||||
<template v-if="p.reply">%fa:reply-all%</template>
|
<template v-if="appearNote.reply">%fa:reply-all%</template>
|
||||||
<template v-else>%fa:reply%</template>
|
<template v-else>%fa:reply%</template>
|
||||||
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
|
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button @click="renote" title="Renote">
|
<button @click="renote()" title="Renote">
|
||||||
%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
|
%fa:retweet%<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton">
|
<button :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton">
|
||||||
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
|
%fa:plus%<p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button class="menu" @click="menu" ref="menuButton">
|
<button class="menu" @click="menu()" ref="menuButton">
|
||||||
%fa:ellipsis-h%
|
%fa:ellipsis-h%
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
@ -63,12 +67,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import parse from '../../../../../mfm/parse';
|
|
||||||
|
|
||||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
|
||||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
|
||||||
import XSub from './note.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import { sum } from '../../../../../prelude/array';
|
import noteMixin from '../../../common/scripts/note-mixin';
|
||||||
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
@ -76,74 +77,17 @@ export default Vue.extend({
|
|||||||
XSub
|
XSub
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [noteSubscriber('note')],
|
mixins: [
|
||||||
|
noteMixin({
|
||||||
|
mobile: true
|
||||||
|
}),
|
||||||
|
noteSubscriber('note')
|
||||||
|
],
|
||||||
|
|
||||||
props: ['note'],
|
props: {
|
||||||
|
note: {
|
||||||
data() {
|
type: Object,
|
||||||
return {
|
required: true
|
||||||
showContent: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
isRenote(): boolean {
|
|
||||||
return (this.note.renote &&
|
|
||||||
this.note.text == null &&
|
|
||||||
this.note.fileIds.length == 0 &&
|
|
||||||
this.note.poll == null);
|
|
||||||
},
|
|
||||||
|
|
||||||
p(): any {
|
|
||||||
return this.isRenote ? this.note.renote : this.note;
|
|
||||||
},
|
|
||||||
|
|
||||||
reactionsCount(): number {
|
|
||||||
return this.p.reactionCounts
|
|
||||||
? sum(Object.values(this.p.reactionCounts))
|
|
||||||
: 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
urls(): string[] {
|
|
||||||
if (this.p.text) {
|
|
||||||
const ast = parse(this.p.text);
|
|
||||||
return ast
|
|
||||||
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
|
|
||||||
.map(t => t.url);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
reply() {
|
|
||||||
(this as any).apis.post({
|
|
||||||
reply: this.p
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
renote() {
|
|
||||||
(this as any).apis.post({
|
|
||||||
renote: this.p
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
react() {
|
|
||||||
(this as any).os.new(MkReactionPicker, {
|
|
||||||
source: this.$refs.reactButton,
|
|
||||||
note: this.p,
|
|
||||||
compact: true,
|
|
||||||
big: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
menu() {
|
|
||||||
(this as any).os.new(MkNoteMenu, {
|
|
||||||
source: this.$refs.menuButton,
|
|
||||||
note: this.p,
|
|
||||||
compact: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -154,6 +98,20 @@ export default Vue.extend({
|
|||||||
font-size 12px
|
font-size 12px
|
||||||
border-bottom solid 1px var(--faceDivider)
|
border-bottom solid 1px var(--faceDivider)
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
z-index 1
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
pointer-events none
|
||||||
|
position absolute
|
||||||
|
top 2px
|
||||||
|
right 2px
|
||||||
|
bottom 2px
|
||||||
|
left 2px
|
||||||
|
border 2px solid var(--primaryAlpha03)
|
||||||
|
border-radius 4px
|
||||||
|
|
||||||
&:last-of-type
|
&:last-of-type
|
||||||
border-bottom none
|
border-bottom none
|
||||||
|
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
||||||
|
|
||||||
<div class="init" v-if="fetching">
|
<div class="placeholder" v-if="fetching">
|
||||||
%fa:spinner .pulse%%i18n:common.loading%
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!fetching && requestInitPromise != null">
|
<div v-if="!fetching && requestInitPromise != null">
|
||||||
@ -251,13 +253,12 @@ export default Vue.extend({
|
|||||||
[data-fa]
|
[data-fa]
|
||||||
margin-right 8px
|
margin-right 8px
|
||||||
|
|
||||||
> .init
|
> .placeholder
|
||||||
padding 64px 0
|
padding 16px
|
||||||
text-align center
|
opacity 0.3
|
||||||
color #999
|
|
||||||
|
|
||||||
> [data-fa]
|
@media (min-width 500px)
|
||||||
margin-right 4px
|
padding 32px
|
||||||
|
|
||||||
> .empty
|
> .empty
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-notifications">
|
<div class="mk-notifications">
|
||||||
|
<div class="placeholder" v-if="fetching">
|
||||||
|
<template v-for="i in 10">
|
||||||
|
<mk-note-skeleton :key="i"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||||
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition notifications">
|
<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition notifications">
|
||||||
<template v-for="(notification, i) in _notifications">
|
<template v-for="(notification, i) in _notifications">
|
||||||
@ -17,7 +23,6 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
<p class="empty" v-if="notifications.length == 0 && !fetching">%i18n:@empty%</p>
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -179,13 +184,11 @@ export default Vue.extend({
|
|||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color #aaa
|
||||||
|
|
||||||
> .fetching
|
> .placeholder
|
||||||
margin 0
|
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
opacity 0.3
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
@media (min-width 500px)
|
||||||
margin-right 4px
|
padding 32px
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -62,6 +62,7 @@ import { host } from '../../../config';
|
|||||||
import { erase, unique } from '../../../../../prelude/array';
|
import { erase, unique } from '../../../../../prelude/array';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import parseAcct from '../../../../../misc/acct/parse';
|
import parseAcct from '../../../../../misc/acct/parse';
|
||||||
|
import { toASCII } from 'punycode';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
@ -153,14 +154,14 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.reply && this.reply.user.host != null) {
|
if (this.reply && this.reply.user.host != null) {
|
||||||
this.text = `@${this.reply.user.username}@${this.reply.user.host} `;
|
this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.reply && this.reply.text != null) {
|
if (this.reply && this.reply.text != null) {
|
||||||
const ast = parse(this.reply.text);
|
const ast = parse(this.reply.text);
|
||||||
|
|
||||||
ast.filter(t => t.type == 'mention').forEach(x => {
|
ast.filter(t => t.type == 'mention').forEach(x => {
|
||||||
const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`;
|
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
|
||||||
|
|
||||||
// 自分は除外
|
// 自分は除外
|
||||||
if (this.$store.state.i.username == x.username && x.host == null) return;
|
if (this.$store.state.i.username == x.username && x.host == null) return;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@timeline%%fa:angle-right%</router-link></li>
|
<li><router-link to="/" :data-active="$route.name == 'index'">%fa:home%%i18n:@timeline%%fa:angle-right%</router-link></li>
|
||||||
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'">%fa:R bell%%i18n:@notifications%<template v-if="hasUnreadNotification">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
||||||
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'">%fa:R comments%%i18n:@messaging%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
||||||
<li v-if="$store.getters.isSignedIn && $store.state.i.isLocked"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'">%fa:R envelope%%i18n:@follow-requests%<template v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
||||||
<li><router-link to="/reversi" :data-active="$route.name == 'reversi'">%fa:gamepad%%i18n:@game%<template v-if="hasGameInvitation">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
<li><router-link to="/reversi" :data-active="$route.name == 'reversi'">%fa:gamepad%%i18n:@game%<template v-if="hasGameInvitation">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -8,7 +8,14 @@
|
|||||||
<x-profile/>
|
<x-profile/>
|
||||||
|
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%fa:palette% %i18n:@design%</div>
|
<div slot="title">%fa:palette% %i18n:@theme%</div>
|
||||||
|
<section>
|
||||||
|
<mk-theme/>
|
||||||
|
</section>
|
||||||
|
</ui-card>
|
||||||
|
|
||||||
|
<ui-card>
|
||||||
|
<div slot="title">%fa:poll-h% %i18n:@design%</div>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
||||||
@ -23,13 +30,6 @@
|
|||||||
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
|
||||||
<header>%i18n:@theme%</header>
|
|
||||||
<div>
|
|
||||||
<mk-theme/>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<header>%i18n:@timeline%</header>
|
<header>%i18n:@timeline%</header>
|
||||||
<div>
|
<div>
|
||||||
@ -54,7 +54,7 @@
|
|||||||
</ui-card>
|
</ui-card>
|
||||||
|
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<div slot="title">%fa:cog% %i18n:@behavior%</div>
|
<div slot="title">%fa:sliders-h% %i18n:@behavior%</div>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<ui-switch v-model="fetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
|
<ui-switch v-model="fetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch>
|
<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch>
|
||||||
|
<ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</ui-card>
|
</ui-card>
|
||||||
@ -80,6 +81,7 @@ export default Vue.extend({
|
|||||||
bannerId: null,
|
bannerId: null,
|
||||||
isCat: false,
|
isCat: false,
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
|
carefulBot: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
avatarUploading: false,
|
avatarUploading: false,
|
||||||
bannerUploading: false
|
bannerUploading: false
|
||||||
@ -103,6 +105,7 @@ export default Vue.extend({
|
|||||||
this.bannerId = this.$store.state.i.bannerId;
|
this.bannerId = this.$store.state.i.bannerId;
|
||||||
this.isCat = this.$store.state.i.isCat;
|
this.isCat = this.$store.state.i.isCat;
|
||||||
this.isLocked = this.$store.state.i.isLocked;
|
this.isLocked = this.$store.state.i.isLocked;
|
||||||
|
this.carefulBot = this.$store.state.i.carefulBot;
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@ -161,7 +164,8 @@ export default Vue.extend({
|
|||||||
avatarId: this.avatarId,
|
avatarId: this.avatarId,
|
||||||
bannerId: this.bannerId,
|
bannerId: this.bannerId,
|
||||||
isCat: this.isCat,
|
isCat: this.isCat,
|
||||||
isLocked: this.isLocked
|
isLocked: this.isLocked,
|
||||||
|
carefulBot: this.carefulBot
|
||||||
}).then(i => {
|
}).then(i => {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
this.$store.state.i.avatarId = i.avatarId;
|
this.$store.state.i.avatarId = i.avatarId;
|
||||||
@ -170,7 +174,10 @@ export default Vue.extend({
|
|||||||
this.$store.state.i.bannerUrl = i.bannerUrl;
|
this.$store.state.i.bannerUrl = i.bannerUrl;
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
alert('%i18n:@saved%');
|
this.$swal({
|
||||||
|
type: 'success',
|
||||||
|
text: '%i18n:@saved%'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ const defaultDeviceSettings = {
|
|||||||
loadRawImages: false,
|
loadRawImages: false,
|
||||||
alwaysShowNsfw: false,
|
alwaysShowNsfw: false,
|
||||||
postStyle: 'standard',
|
postStyle: 'standard',
|
||||||
|
navbar: 'top',
|
||||||
mobileNotificationPosition: 'bottom'
|
mobileNotificationPosition: 'bottom'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,6 +62,8 @@ export type Source = {
|
|||||||
*/
|
*/
|
||||||
ghost?: string;
|
ghost?: string;
|
||||||
|
|
||||||
|
proxy?: string;
|
||||||
|
|
||||||
summalyProxy?: string;
|
summalyProxy?: string;
|
||||||
|
|
||||||
accesslog?: string;
|
accesslog?: string;
|
||||||
@ -93,11 +95,9 @@ export type Source = {
|
|||||||
private_key: string;
|
private_key: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
google_maps_api_key: string;
|
|
||||||
|
|
||||||
clusterLimit?: number;
|
clusterLimit?: number;
|
||||||
|
|
||||||
user_recommendation: {
|
user_recommendation?: {
|
||||||
external: boolean;
|
external: boolean;
|
||||||
engine: string;
|
engine: string;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as redis from 'redis';
|
import * as redis from 'redis';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
export default redis.createClient(
|
export default config.redis ? redis.createClient(
|
||||||
config.redis.port,
|
config.redis.port,
|
||||||
config.redis.host,
|
config.redis.host,
|
||||||
{
|
{
|
||||||
auth_pass: config.redis.pass
|
auth_pass: config.redis.pass
|
||||||
}
|
}
|
||||||
);
|
) : null;
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">→</kbd></kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
|
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">→</kbd></kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
|
||||||
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
|
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
|
||||||
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
|
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
|
||||||
|
<tr><td><kbd class="key">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
|
||||||
|
<tr><td><kbd class="key">Del</kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">D</kbd></kbd></td><td>投稿を削除</td><td><b>D</b>elete</tr>
|
||||||
<tr><td><kbd class="key">M</kbd>, <kbd class="key">O</kbd></td><td>投稿に対するメニューを開く</td><td><b>M</b>ore, <b>O</b>ther</td></tr>
|
<tr><td><kbd class="key">M</kbd>, <kbd class="key">O</kbd></td><td>投稿に対するメニューを開く</td><td><b>M</b>ore, <b>O</b>ther</td></tr>
|
||||||
<tr><td><kbd class="key">S</kbd></td><td>CWで隠された部分を表示 or 隠す</td><td><b>S</b>how, <b>S</b>ee</td></tr>
|
<tr><td><kbd class="key">S</kbd></td><td>CWで隠された部分を表示 or 隠す</td><td><b>S</b>how, <b>S</b>ee</td></tr>
|
||||||
<tr><td><kbd class="key">Esc</kbd></td><td>フォーカスを外す</td><td>-</td></tr>
|
<tr><td><kbd class="key">Esc</kbd></td><td>フォーカスを外す</td><td>-</td></tr>
|
||||||
|
@ -111,6 +111,7 @@ async function workerMain() {
|
|||||||
*/
|
*/
|
||||||
async function init(): Promise<Config> {
|
async function init(): Promise<Config> {
|
||||||
Logger.info('Welcome to Misskey!');
|
Logger.info('Welcome to Misskey!');
|
||||||
|
Logger.info(`<<< Misskey v${pkg.version} >>>`);
|
||||||
|
|
||||||
new Logger('Deps').info(`Node.js ${process.version}`);
|
new Logger('Deps').info(`Node.js ${process.version}`);
|
||||||
MachineInfo.show();
|
MachineInfo.show();
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
* Mention
|
* Mention
|
||||||
*/
|
*/
|
||||||
import parseAcct from '../../../misc/acct/parse';
|
import parseAcct from '../../../misc/acct/parse';
|
||||||
|
import { toUnicode } from 'punycode';
|
||||||
|
|
||||||
export type TextElementMention = {
|
export type TextElementMention = {
|
||||||
type: 'mention'
|
type: 'mention'
|
||||||
content: string
|
content: string
|
||||||
|
canonical: string
|
||||||
username: string
|
username: string
|
||||||
host: string
|
host: string
|
||||||
};
|
};
|
||||||
@ -15,9 +17,11 @@ export default function(text: string) {
|
|||||||
if (!match) return null;
|
if (!match) return null;
|
||||||
const mention = match[0];
|
const mention = match[0];
|
||||||
const { username, host } = parseAcct(mention.substr(1));
|
const { username, host } = parseAcct(mention.substr(1));
|
||||||
|
const canonical = host != null ? `@${username}@${toUnicode(host)}` : mention;
|
||||||
return {
|
return {
|
||||||
type: 'mention',
|
type: 'mention',
|
||||||
content: mention,
|
content: mention,
|
||||||
|
canonical,
|
||||||
username,
|
username,
|
||||||
host
|
host
|
||||||
} as TextElementMention;
|
} as TextElementMention;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import { Context } from 'cafy';
|
import { Context } from 'cafy';
|
||||||
|
import isObjectId from './is-objectid';
|
||||||
|
|
||||||
export const isAnId = (x: any) => mongo.ObjectID.isValid(x);
|
export const isAnId = (x: any) => mongo.ObjectID.isValid(x);
|
||||||
export const isNotAnId = (x: any) => !isAnId(x);
|
export const isNotAnId = (x: any) => !isAnId(x);
|
||||||
@ -12,7 +13,7 @@ export default class ID extends Context<mongo.ObjectID> {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.transform = v => {
|
this.transform = v => {
|
||||||
if (isAnId(v) && !mongo.ObjectID.prototype.isPrototypeOf(v)) {
|
if (isAnId(v) && !isObjectId(v)) {
|
||||||
return new mongo.ObjectID(v);
|
return new mongo.ObjectID(v);
|
||||||
} else {
|
} else {
|
||||||
return v;
|
return v;
|
||||||
@ -20,7 +21,7 @@ export default class ID extends Context<mongo.ObjectID> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.push(v => {
|
this.push(v => {
|
||||||
if (!mongo.ObjectID.prototype.isPrototypeOf(v) && isNotAnId(v)) {
|
if (!isObjectId(v) && isNotAnId(v)) {
|
||||||
return new Error('must-be-an-id');
|
return new Error('must-be-an-id');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
3
src/misc/is-objectid.ts
Normal file
3
src/misc/is-objectid.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function(x: any): boolean {
|
||||||
|
return x.hasOwnProperty('toHexString') || x.hasOwnProperty('_bsontype');
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
|
import isObjectId from './is-objectid';
|
||||||
|
|
||||||
function toString(id: any) {
|
function toString(id: any) {
|
||||||
return mongo.ObjectID.prototype.isPrototypeOf(id) ? (id as mongo.ObjectID).toHexString() : id;
|
return isObjectId(id) ? (id as mongo.ObjectID).toHexString() : id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(note: any, mutedUserIds: string[]): boolean {
|
export default function(note: any, mutedUserIds: string[]): boolean {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const AccessToken = db.get<IAccessToken>('accessTokens');
|
const AccessToken = db.get<IAccessToken>('accessTokens');
|
||||||
AccessToken.createIndex('token');
|
AccessToken.createIndex('token');
|
||||||
@ -22,7 +23,7 @@ export async function deleteAccessToken(accessToken: string | mongo.ObjectID | I
|
|||||||
let a: IAccessToken;
|
let a: IAccessToken;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(accessToken)) {
|
if (isObjectId(accessToken)) {
|
||||||
a = await AccessToken.findOne({
|
a = await AccessToken.findOne({
|
||||||
_id: accessToken
|
_id: accessToken
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import * as mongo from 'mongodb';
|
|||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import AccessToken from './access-token';
|
import AccessToken from './access-token';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
const App = db.get<IApp>('apps');
|
const App = db.get<IApp>('apps');
|
||||||
@ -43,7 +44,7 @@ export const pack = (
|
|||||||
let _app: any;
|
let _app: any;
|
||||||
|
|
||||||
// Populate the app if 'app' is ID
|
// Populate the app if 'app' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(app)) {
|
if (isObjectId(app)) {
|
||||||
_app = await App.findOne({
|
_app = await App.findOne({
|
||||||
_id: app
|
_id: app
|
||||||
});
|
});
|
||||||
@ -56,7 +57,7 @@ export const pack = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Me
|
// Me
|
||||||
if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) {
|
if (me && !isObjectId(me)) {
|
||||||
if (typeof me === 'string') {
|
if (typeof me === 'string') {
|
||||||
me = new mongo.ObjectID(me);
|
me = new mongo.ObjectID(me);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import { pack as packApp } from './app';
|
import { pack as packApp } from './app';
|
||||||
|
|
||||||
const AuthSession = db.get<IAuthSession>('authSessions');
|
const AuthSession = db.get<IAuthSession>('authSessions');
|
||||||
@ -31,7 +32,7 @@ export const pack = (
|
|||||||
_session = deepcopy(session);
|
_session = deepcopy(session);
|
||||||
|
|
||||||
// Me
|
// Me
|
||||||
if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) {
|
if (me && !isObjectId(me)) {
|
||||||
if (typeof me === 'string') {
|
if (typeof me === 'string') {
|
||||||
me = new mongo.ObjectID(me);
|
me = new mongo.ObjectID(me);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import monkDb, { nativeDbConn } from '../db/mongodb';
|
import monkDb, { nativeDbConn } from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const DriveFileThumbnail = monkDb.get<IDriveFileThumbnail>('driveFileThumbnails.files');
|
const DriveFileThumbnail = monkDb.get<IDriveFileThumbnail>('driveFileThumbnails.files');
|
||||||
DriveFileThumbnail.createIndex('metadata.originalId', { sparse: true, unique: true });
|
DriveFileThumbnail.createIndex('metadata.originalId', { sparse: true, unique: true });
|
||||||
@ -35,7 +36,7 @@ export async function deleteDriveFileThumbnail(driveFile: string | mongo.ObjectI
|
|||||||
let d: IDriveFileThumbnail;
|
let d: IDriveFileThumbnail;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(driveFile)) {
|
if (isObjectId(driveFile)) {
|
||||||
d = await DriveFileThumbnail.findOne({
|
d = await DriveFileThumbnail.findOne({
|
||||||
_id: driveFile
|
_id: driveFile
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ const deepcopy = require('deepcopy');
|
|||||||
import { pack as packFolder } from './drive-folder';
|
import { pack as packFolder } from './drive-folder';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import monkDb, { nativeDbConn } from '../db/mongodb';
|
import monkDb, { nativeDbConn } from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import Note, { deleteNote } from './note';
|
import Note, { deleteNote } from './note';
|
||||||
import MessagingMessage, { deleteMessagingMessage } from './messaging-message';
|
import MessagingMessage, { deleteMessagingMessage } from './messaging-message';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
@ -11,6 +12,8 @@ import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumb
|
|||||||
const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');
|
const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');
|
||||||
DriveFile.createIndex('md5');
|
DriveFile.createIndex('md5');
|
||||||
DriveFile.createIndex('metadata.uri');
|
DriveFile.createIndex('metadata.uri');
|
||||||
|
DriveFile.createIndex('metadata.userId');
|
||||||
|
DriveFile.createIndex('metadata.folderId');
|
||||||
export default DriveFile;
|
export default DriveFile;
|
||||||
|
|
||||||
export const DriveFileChunk = monkDb.get('driveFiles.chunks');
|
export const DriveFileChunk = monkDb.get('driveFiles.chunks');
|
||||||
@ -76,7 +79,7 @@ export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriv
|
|||||||
let d: IDriveFile;
|
let d: IDriveFile;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(driveFile)) {
|
if (isObjectId(driveFile)) {
|
||||||
d = await DriveFile.findOne({
|
d = await DriveFile.findOne({
|
||||||
_id: driveFile
|
_id: driveFile
|
||||||
});
|
});
|
||||||
@ -152,7 +155,7 @@ export const pack = (
|
|||||||
let _file: any;
|
let _file: any;
|
||||||
|
|
||||||
// Populate the file if 'file' is ID
|
// Populate the file if 'file' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(file)) {
|
if (isObjectId(file)) {
|
||||||
_file = await DriveFile.findOne({
|
_file = await DriveFile.findOne({
|
||||||
_id: file
|
_id: file
|
||||||
});
|
});
|
||||||
@ -166,7 +169,7 @@ export const pack = (
|
|||||||
|
|
||||||
// (データベースの欠損などで)ファイルがデータベース上に見つからなかったとき
|
// (データベースの欠損などで)ファイルがデータベース上に見つからなかったとき
|
||||||
if (_file == null) {
|
if (_file == null) {
|
||||||
console.warn(`in packaging driveFile: driveFile not found on database: ${_file}`);
|
console.warn(`[DAMAGED DB] (missing) pkg: driveFile :: ${file}`);
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import DriveFile from './drive-file';
|
import DriveFile from './drive-file';
|
||||||
|
|
||||||
const DriveFolder = db.get<IDriveFolder>('driveFolders');
|
const DriveFolder = db.get<IDriveFolder>('driveFolders');
|
||||||
|
DriveFolder.createIndex('userId');
|
||||||
export default DriveFolder;
|
export default DriveFolder;
|
||||||
|
|
||||||
export type IDriveFolder = {
|
export type IDriveFolder = {
|
||||||
@ -28,7 +30,7 @@ export async function deleteDriveFolder(driveFolder: string | mongo.ObjectID | I
|
|||||||
let d: IDriveFolder;
|
let d: IDriveFolder;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(driveFolder)) {
|
if (isObjectId(driveFolder)) {
|
||||||
d = await DriveFolder.findOne({
|
d = await DriveFolder.findOne({
|
||||||
_id: driveFolder
|
_id: driveFolder
|
||||||
});
|
});
|
||||||
@ -82,7 +84,7 @@ export const pack = (
|
|||||||
let _folder: any;
|
let _folder: any;
|
||||||
|
|
||||||
// Populate the folder if 'folder' is ID
|
// Populate the folder if 'folder' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(folder)) {
|
if (isObjectId(folder)) {
|
||||||
_folder = await DriveFolder.findOne({ _id: folder });
|
_folder = await DriveFolder.findOne({ _id: folder });
|
||||||
} else if (typeof folder === 'string') {
|
} else if (typeof folder === 'string') {
|
||||||
_folder = await DriveFolder.findOne({ _id: new mongo.ObjectID(folder) });
|
_folder = await DriveFolder.findOne({ _id: new mongo.ObjectID(folder) });
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import { pack as packNote } from './note';
|
import { pack as packNote } from './note';
|
||||||
|
|
||||||
const Favorite = db.get<IFavorite>('favorites');
|
const Favorite = db.get<IFavorite>('favorites');
|
||||||
@ -21,7 +22,7 @@ export async function deleteFavorite(favorite: string | mongo.ObjectID | IFavori
|
|||||||
let f: IFavorite;
|
let f: IFavorite;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(favorite)) {
|
if (isObjectId(favorite)) {
|
||||||
f = await Favorite.findOne({
|
f = await Favorite.findOne({
|
||||||
_id: favorite
|
_id: favorite
|
||||||
});
|
});
|
||||||
@ -58,7 +59,7 @@ export const pack = (
|
|||||||
let _favorite: any;
|
let _favorite: any;
|
||||||
|
|
||||||
// Populate the favorite if 'favorite' is ID
|
// Populate the favorite if 'favorite' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(favorite)) {
|
if (isObjectId(favorite)) {
|
||||||
_favorite = await Favorite.findOne({
|
_favorite = await Favorite.findOne({
|
||||||
_id: favorite
|
_id: favorite
|
||||||
});
|
});
|
||||||
@ -75,11 +76,13 @@ export const pack = (
|
|||||||
delete _favorite._id;
|
delete _favorite._id;
|
||||||
|
|
||||||
// Populate note
|
// Populate note
|
||||||
_favorite.note = await packNote(_favorite.noteId, me);
|
_favorite.note = await packNote(_favorite.noteId, me, {
|
||||||
|
detail: true
|
||||||
|
});
|
||||||
|
|
||||||
// (データベースの不具合などで)投稿が見つからなかったら
|
// (データベースの不具合などで)投稿が見つからなかったら
|
||||||
if (_favorite.note == null) {
|
if (_favorite.note == null) {
|
||||||
console.warn(`in packaging favorite: note not found on database: ${_favorite.noteId}`);
|
console.warn(`[DAMAGED DB] (missing) pkg: favorite -> note :: ${_favorite.id} (note ${_favorite.noteId})`);
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import { pack as packUser } from './user';
|
import { pack as packUser } from './user';
|
||||||
|
|
||||||
const FollowRequest = db.get<IFollowRequest>('followRequests');
|
const FollowRequest = db.get<IFollowRequest>('followRequests');
|
||||||
@ -12,6 +13,7 @@ export type IFollowRequest = {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
followeeId: mongo.ObjectID;
|
followeeId: mongo.ObjectID;
|
||||||
followerId: mongo.ObjectID;
|
followerId: mongo.ObjectID;
|
||||||
|
requestId?: string; // id of Follow Activity
|
||||||
|
|
||||||
// 非正規化
|
// 非正規化
|
||||||
_followee: {
|
_followee: {
|
||||||
@ -33,7 +35,7 @@ export async function deleteFollowRequest(followRequest: string | mongo.ObjectID
|
|||||||
let f: IFollowRequest;
|
let f: IFollowRequest;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(followRequest)) {
|
if (isObjectId(followRequest)) {
|
||||||
f = await FollowRequest.findOne({
|
f = await FollowRequest.findOne({
|
||||||
_id: followRequest
|
_id: followRequest
|
||||||
});
|
});
|
||||||
@ -63,7 +65,7 @@ export const pack = (
|
|||||||
let _request: any;
|
let _request: any;
|
||||||
|
|
||||||
// Populate the request if 'request' is ID
|
// Populate the request if 'request' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(request)) {
|
if (isObjectId(request)) {
|
||||||
_request = await FollowRequest.findOne({
|
_request = await FollowRequest.findOne({
|
||||||
_id: request
|
_id: request
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const FollowedLog = db.get<IFollowedLog>('followedLogs');
|
const FollowedLog = db.get<IFollowedLog>('followedLogs');
|
||||||
export default FollowedLog;
|
export default FollowedLog;
|
||||||
@ -18,7 +19,7 @@ export async function deleteFollowedLog(followedLog: string | mongo.ObjectID | I
|
|||||||
let f: IFollowedLog;
|
let f: IFollowedLog;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(followedLog)) {
|
if (isObjectId(followedLog)) {
|
||||||
f = await FollowedLog.findOne({
|
f = await FollowedLog.findOne({
|
||||||
_id: followedLog
|
_id: followedLog
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const FollowingLog = db.get<IFollowingLog>('followingLogs');
|
const FollowingLog = db.get<IFollowingLog>('followingLogs');
|
||||||
export default FollowingLog;
|
export default FollowingLog;
|
||||||
@ -18,7 +19,7 @@ export async function deleteFollowingLog(followingLog: string | mongo.ObjectID |
|
|||||||
let f: IFollowingLog;
|
let f: IFollowingLog;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(followingLog)) {
|
if (isObjectId(followingLog)) {
|
||||||
f = await FollowingLog.findOne({
|
f = await FollowingLog.findOne({
|
||||||
_id: followingLog
|
_id: followingLog
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const Following = db.get<IFollowing>('following');
|
const Following = db.get<IFollowing>('following');
|
||||||
Following.createIndex(['followerId', 'followeeId'], { unique: true });
|
Following.createIndex(['followerId', 'followeeId'], { unique: true });
|
||||||
@ -32,7 +33,7 @@ export async function deleteFollowing(following: string | mongo.ObjectID | IFoll
|
|||||||
let f: IFollowing;
|
let f: IFollowing;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(following)) {
|
if (isObjectId(following)) {
|
||||||
f = await Following.findOne({
|
f = await Following.findOne({
|
||||||
_id: following
|
_id: following
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../../../db/mongodb';
|
import db from '../../../db/mongodb';
|
||||||
|
import isObjectId from '../../../misc/is-objectid';
|
||||||
import { IUser, pack as packUser } from '../../user';
|
import { IUser, pack as packUser } from '../../user';
|
||||||
|
|
||||||
const ReversiGame = db.get<IReversiGame>('reversiGames');
|
const ReversiGame = db.get<IReversiGame>('reversiGames');
|
||||||
@ -62,7 +63,7 @@ export const pack = (
|
|||||||
let _game: any;
|
let _game: any;
|
||||||
|
|
||||||
// Populate the game if 'game' is ID
|
// Populate the game if 'game' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(game)) {
|
if (isObjectId(game)) {
|
||||||
_game = await ReversiGame.findOne({
|
_game = await ReversiGame.findOne({
|
||||||
_id: game
|
_id: game
|
||||||
});
|
});
|
||||||
@ -76,7 +77,7 @@ export const pack = (
|
|||||||
|
|
||||||
// Me
|
// Me
|
||||||
const meId: mongo.ObjectID = me
|
const meId: mongo.ObjectID = me
|
||||||
? mongo.ObjectID.prototype.isPrototypeOf(me)
|
? isObjectId(me)
|
||||||
? me as mongo.ObjectID
|
? me as mongo.ObjectID
|
||||||
: typeof me === 'string'
|
: typeof me === 'string'
|
||||||
? new mongo.ObjectID(me)
|
? new mongo.ObjectID(me)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../../../db/mongodb';
|
import db from '../../../db/mongodb';
|
||||||
|
import isObjectId from '../../../misc/is-objectid';
|
||||||
import { IUser, pack as packUser } from '../../user';
|
import { IUser, pack as packUser } from '../../user';
|
||||||
|
|
||||||
const Matching = db.get<IMatching>('reversiMatchings');
|
const Matching = db.get<IMatching>('reversiMatchings');
|
||||||
@ -23,7 +24,7 @@ export const pack = (
|
|||||||
|
|
||||||
// Me
|
// Me
|
||||||
const meId: mongo.ObjectID = me
|
const meId: mongo.ObjectID = me
|
||||||
? mongo.ObjectID.prototype.isPrototypeOf(me)
|
? isObjectId(me)
|
||||||
? me as mongo.ObjectID
|
? me as mongo.ObjectID
|
||||||
: typeof me === 'string'
|
: typeof me === 'string'
|
||||||
? new mongo.ObjectID(me)
|
? new mongo.ObjectID(me)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const MessagingHistory = db.get<IMessagingHistory>('messagingHistories');
|
const MessagingHistory = db.get<IMessagingHistory>('messagingHistories');
|
||||||
export default MessagingHistory;
|
export default MessagingHistory;
|
||||||
@ -19,7 +20,7 @@ export async function deleteMessagingHistory(messagingHistory: string | mongo.Ob
|
|||||||
let m: IMessagingHistory;
|
let m: IMessagingHistory;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(messagingHistory)) {
|
if (isObjectId(messagingHistory)) {
|
||||||
m = await MessagingHistory.findOne({
|
m = await MessagingHistory.findOne({
|
||||||
_id: messagingHistory
|
_id: messagingHistory
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ const deepcopy = require('deepcopy');
|
|||||||
import { pack as packUser } from './user';
|
import { pack as packUser } from './user';
|
||||||
import { pack as packFile } from './drive-file';
|
import { pack as packFile } from './drive-file';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import MessagingHistory, { deleteMessagingHistory } from './messaging-history';
|
import MessagingHistory, { deleteMessagingHistory } from './messaging-history';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ export async function deleteMessagingMessage(messagingMessage: string | mongo.Ob
|
|||||||
let m: IMessagingMessage;
|
let m: IMessagingMessage;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(messagingMessage)) {
|
if (isObjectId(messagingMessage)) {
|
||||||
m = await MessagingMessage.findOne({
|
m = await MessagingMessage.findOne({
|
||||||
_id: messagingMessage
|
_id: messagingMessage
|
||||||
});
|
});
|
||||||
@ -72,7 +73,7 @@ export const pack = (
|
|||||||
let _message: any;
|
let _message: any;
|
||||||
|
|
||||||
// Populate the message if 'message' is ID
|
// Populate the message if 'message' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(message)) {
|
if (isObjectId(message)) {
|
||||||
_message = await MessagingMessage.findOne({
|
_message = await MessagingMessage.findOne({
|
||||||
_id: message
|
_id: message
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const Mute = db.get<IMute>('mute');
|
const Mute = db.get<IMute>('mute');
|
||||||
Mute.createIndex(['muterId', 'muteeId'], { unique: true });
|
Mute.createIndex(['muterId', 'muteeId'], { unique: true });
|
||||||
@ -19,7 +20,7 @@ export async function deleteMute(mute: string | mongo.ObjectID | IMute) {
|
|||||||
let m: IMute;
|
let m: IMute;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(mute)) {
|
if (isObjectId(mute)) {
|
||||||
m = await Mute.findOne({
|
m = await Mute.findOne({
|
||||||
_id: mute
|
_id: mute
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import * as mongo from 'mongodb';
|
|||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import Reaction from './note-reaction';
|
import Reaction from './note-reaction';
|
||||||
import { pack as packUser } from './user';
|
import { pack as packUser } from './user';
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ export async function deleteNoteReaction(noteReaction: string | mongo.ObjectID |
|
|||||||
let n: INoteReaction;
|
let n: INoteReaction;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(noteReaction)) {
|
if (isObjectId(noteReaction)) {
|
||||||
n = await NoteReaction.findOne({
|
n = await NoteReaction.findOne({
|
||||||
_id: noteReaction
|
_id: noteReaction
|
||||||
});
|
});
|
||||||
@ -67,7 +68,7 @@ export const pack = (
|
|||||||
let _reaction: any;
|
let _reaction: any;
|
||||||
|
|
||||||
// Populate the reaction if 'reaction' is ID
|
// Populate the reaction if 'reaction' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(reaction)) {
|
if (isObjectId(reaction)) {
|
||||||
_reaction = await Reaction.findOne({
|
_reaction = await Reaction.findOne({
|
||||||
_id: reaction
|
_id: reaction
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
|
|
||||||
const NoteWatching = db.get<INoteWatching>('noteWatching');
|
const NoteWatching = db.get<INoteWatching>('noteWatching');
|
||||||
NoteWatching.createIndex(['userId', 'noteId'], { unique: true });
|
NoteWatching.createIndex(['userId', 'noteId'], { unique: true });
|
||||||
@ -19,7 +20,7 @@ export async function deleteNoteWatching(noteWatching: string | mongo.ObjectID |
|
|||||||
let n: INoteWatching;
|
let n: INoteWatching;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(noteWatching)) {
|
if (isObjectId(noteWatching)) {
|
||||||
n = await NoteWatching.findOne({
|
n = await NoteWatching.findOne({
|
||||||
_id: noteWatching
|
_id: noteWatching
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import * as mongo from 'mongodb';
|
|||||||
const deepcopy = require('deepcopy');
|
const deepcopy = require('deepcopy');
|
||||||
import rap from '@prezzemolo/rap';
|
import rap from '@prezzemolo/rap';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
|
import isObjectId from '../misc/is-objectid';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { IUser, pack as packUser } from './user';
|
import { IUser, pack as packUser } from './user';
|
||||||
import { pack as packApp } from './app';
|
import { pack as packApp } from './app';
|
||||||
@ -107,7 +108,7 @@ export async function deleteNote(note: string | mongo.ObjectID | INote) {
|
|||||||
let n: INote;
|
let n: INote;
|
||||||
|
|
||||||
// Populate
|
// Populate
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(note)) {
|
if (isObjectId(note)) {
|
||||||
n = await Note.findOne({
|
n = await Note.findOne({
|
||||||
_id: note
|
_id: note
|
||||||
});
|
});
|
||||||
@ -259,7 +260,7 @@ export const pack = async (
|
|||||||
|
|
||||||
// Me
|
// Me
|
||||||
const meId: mongo.ObjectID = me
|
const meId: mongo.ObjectID = me
|
||||||
? mongo.ObjectID.prototype.isPrototypeOf(me)
|
? isObjectId(me)
|
||||||
? me as mongo.ObjectID
|
? me as mongo.ObjectID
|
||||||
: typeof me === 'string'
|
: typeof me === 'string'
|
||||||
? new mongo.ObjectID(me)
|
? new mongo.ObjectID(me)
|
||||||
@ -269,7 +270,7 @@ export const pack = async (
|
|||||||
let _note: any;
|
let _note: any;
|
||||||
|
|
||||||
// Populate the note if 'note' is ID
|
// Populate the note if 'note' is ID
|
||||||
if (mongo.ObjectID.prototype.isPrototypeOf(note)) {
|
if (isObjectId(note)) {
|
||||||
_note = await Note.findOne({
|
_note = await Note.findOne({
|
||||||
_id: note
|
_id: note
|
||||||
});
|
});
|
||||||
@ -281,9 +282,9 @@ export const pack = async (
|
|||||||
_note = deepcopy(note);
|
_note = deepcopy(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 投稿がデータベース上に見つからなかったとき
|
// (データベースの欠損などで)投稿がデータベース上に見つからなかったとき
|
||||||
if (_note == null) {
|
if (_note == null) {
|
||||||
console.warn(`note not found on database: ${note}`);
|
console.warn(`[DAMAGED DB] (missing) pkg: note :: ${note}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,8 +359,8 @@ export const pack = async (
|
|||||||
})(_note.poll);
|
})(_note.poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch my reaction
|
|
||||||
if (meId) {
|
if (meId) {
|
||||||
|
// Fetch my reaction
|
||||||
_note.myReaction = (async () => {
|
_note.myReaction = (async () => {
|
||||||
const reaction = await Reaction
|
const reaction = await Reaction
|
||||||
.findOne({
|
.findOne({
|
||||||
@ -374,18 +375,44 @@ export const pack = async (
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// isFavorited
|
||||||
|
_note.isFavorited = (async () => {
|
||||||
|
const favorite = await Favorite
|
||||||
|
.count({
|
||||||
|
userId: meId,
|
||||||
|
noteId: id
|
||||||
|
}, {
|
||||||
|
limit: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
return favorite === 1;
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve promises in _note object
|
// resolve promises in _note object
|
||||||
_note = await rap(_note);
|
_note = await rap(_note);
|
||||||
|
|
||||||
// (データベースの欠損などで)ユーザーがデータベース上に見つからなかったとき
|
//#region (データベースの欠損などで)参照しているデータがデータベース上に見つからなかったとき
|
||||||
if (_note.user == null) {
|
if (_note.user == null) {
|
||||||
console.warn(`in packaging note: note user not found on database: note(${_note.id})`);
|
console.warn(`[DAMAGED DB] (missing) pkg: note -> user :: ${_note.id} (user ${_note.userId})`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.detail) {
|
||||||
|
if (_note.replyId != null && _note.reply == null) {
|
||||||
|
console.warn(`[DAMAGED DB] (missing) pkg: note -> reply :: ${_note.id} (reply ${_note.replyId})`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_note.renoteId != null && _note.renote == null) {
|
||||||
|
console.warn(`[DAMAGED DB] (missing) pkg: note -> renote :: ${_note.id} (renote ${_note.renoteId})`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
if (_note.user.isCat && _note.text) {
|
if (_note.user.isCat && _note.text) {
|
||||||
_note.text = _note.text.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ');
|
_note.text = _note.text.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ');
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user