Compare commits
140 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af2d36a3c9 | ||
|
|
42a4f92cfa | ||
|
|
ccb9ed3489 | ||
|
|
773b2aa3d1 | ||
|
|
30d5b8d65b | ||
|
|
763676a18c | ||
|
|
e166ad6780 | ||
|
|
034c96d070 | ||
|
|
f34f8d304c | ||
|
|
944000c05c | ||
|
|
52db63bca2 | ||
|
|
55dfd9e2a1 | ||
|
|
d193cbf2b7 | ||
|
|
bdec56a543 | ||
|
|
e0a6d9740c | ||
|
|
0ce9c057e1 | ||
|
|
12a2fdbc20 | ||
|
|
57c294bc89 | ||
|
|
9758757805 | ||
|
|
f9350fa35f | ||
|
|
e120da4ecd | ||
|
|
328a10b70c | ||
|
|
1ed97c8deb | ||
|
|
91b970e2aa | ||
|
|
99af1bb479 | ||
|
|
11ddcbdee3 | ||
|
|
6e8a1086d8 | ||
|
|
c78945436e | ||
|
|
6eff8fde74 | ||
|
|
726d5a177e | ||
|
|
33495b5cb3 | ||
|
|
fe159a13a9 | ||
|
|
22a1dc0566 | ||
|
|
02e6b732e9 | ||
|
|
cc6fa135ac | ||
|
|
5747732156 | ||
|
|
581d1617d8 | ||
|
|
6152fd20bf | ||
|
|
19300ca65c | ||
|
|
2f3d744e19 | ||
|
|
724e812972 | ||
|
|
9a6246fd4e | ||
|
|
34f44de59c | ||
|
|
16e446c121 | ||
|
|
8f232a9da9 | ||
|
|
ebeb7f8578 | ||
|
|
f790673068 | ||
|
|
335ab5ab54 | ||
|
|
00e0d6ce2c | ||
|
|
414fb6d303 | ||
|
|
9c35a12211 | ||
|
|
bb4fe5174f | ||
|
|
3ffd6ff5a2 | ||
|
|
b05feb5bf7 | ||
|
|
fa171f237d | ||
|
|
f2ccb684eb | ||
|
|
ffea6522ac | ||
|
|
3d40a7df00 | ||
|
|
638c41476b | ||
|
|
c6d3088374 | ||
|
|
0f93be9dd4 | ||
|
|
f59982c9c5 | ||
|
|
dff67a5e54 | ||
|
|
6adcc3b2ed | ||
|
|
877ed3663c | ||
|
|
6000a82917 | ||
|
|
6805f9b3e0 | ||
|
|
1366c785f9 | ||
|
|
70540b4500 | ||
|
|
0967f23b6e | ||
|
|
1f7d66169c | ||
|
|
af501f5eeb | ||
|
|
60be60c923 | ||
|
|
48746101e0 | ||
|
|
af9c5c6ab7 | ||
|
|
602284d38c | ||
|
|
26898142c2 | ||
|
|
b0a8d7abe9 | ||
|
|
dc2b266b75 | ||
|
|
07bbd9506a | ||
|
|
14bb218287 | ||
|
|
29f238c929 | ||
|
|
a39a1d4fa5 | ||
|
|
15117c63f5 | ||
|
|
507ffb6fc6 | ||
|
|
6b2e0164cf | ||
|
|
02e06eb1de | ||
|
|
1b50f78733 | ||
|
|
ead629407c | ||
|
|
0abbc9e7dd | ||
|
|
37681e859e | ||
|
|
caabdc68f3 | ||
|
|
9e97eaf24d | ||
|
|
4cd06a789b | ||
|
|
a3ffd968de | ||
|
|
0cf40563aa | ||
|
|
3e7e7f864b | ||
|
|
6ae415e36a | ||
|
|
6cefa3ae26 | ||
|
|
70de3af3ea | ||
|
|
66ed814527 | ||
|
|
e12cc3b7a8 | ||
|
|
93ea19d7ad | ||
|
|
79d592b431 | ||
|
|
c9c3a0be82 | ||
|
|
f04be199dd | ||
|
|
f36cb1cc66 | ||
|
|
a5597e3df9 | ||
|
|
7f4c28053e | ||
|
|
ea24043b22 | ||
|
|
44ef60c8a2 | ||
|
|
bd68ff2cf3 | ||
|
|
0e8a592b26 | ||
|
|
d3b51bf94a | ||
|
|
cc137ee1cc | ||
|
|
c088482cef | ||
|
|
70e3febe0a | ||
|
|
f500cce293 | ||
|
|
c6b836b7be | ||
|
|
15485da1bb | ||
|
|
7195f55a44 | ||
|
|
176f8803eb | ||
|
|
5a3a925a3c | ||
|
|
29bfb9d19b | ||
|
|
86b0dfdd33 | ||
|
|
ab04f2fce0 | ||
|
|
be9f836b21 | ||
|
|
818bc96aab | ||
|
|
14d12c21f2 | ||
|
|
aa5250a37c | ||
|
|
2053a041e5 | ||
|
|
0534a0a41e | ||
|
|
d2f9a99beb | ||
|
|
9625047dc3 | ||
|
|
d6b18ce536 | ||
|
|
df00af1dfa | ||
|
|
3570ec0430 | ||
|
|
a111b014f8 | ||
|
|
50eebe834a | ||
|
|
f965e9f218 |
41
README.md
41
README.md
@@ -12,15 +12,18 @@
|
|||||||
> Lead Maintainer: [syuilo][syuilo-link]
|
> Lead Maintainer: [syuilo][syuilo-link]
|
||||||
|
|
||||||
**[Misskey](https://misskey.xyz)** is a completely open source,
|
**[Misskey](https://misskey.xyz)** is a completely open source,
|
||||||
ultimately sophisticated new type of mini-blog based SNS.
|
ultimately sophisticated professional microblogging software.
|
||||||
|
|
||||||
<a href="https://www.patreon.com/syuilo"><img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="Become a Patron!" width="160" /></a>
|
<a href="https://www.patreon.com/syuilo"><img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="Become a Patron!" width="160" /></a>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
:sparkles: Features
|
:sparkles: Features
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
* Reactions
|
* Reactions
|
||||||
* User lists
|
* User lists
|
||||||
* Cusromizable column view (known as MisskeyDeck)
|
* Customizable column view (known as MisskeyDeck)
|
||||||
|
* and widgets!
|
||||||
* Private messages
|
* Private messages
|
||||||
* Mute
|
* Mute
|
||||||
* Streaming
|
* Streaming
|
||||||
@@ -46,18 +49,9 @@ If you want to...
|
|||||||
[![Backers][backers-image]][support-url]
|
[![Backers][backers-image]][support-url]
|
||||||
[![Sponsors][sponsors-image]][support-url]
|
[![Sponsors][sponsors-image]][support-url]
|
||||||
|
|
||||||
:mortar_board: Notable contributors
|
| ![][ooo-icon] |
|
||||||
----------------------------------------------------------------
|
|:-:|
|
||||||
| ![syuilo][syuilo-icon] | ![Morisawa Aya][ayamorisawa-icon] | ![otofune][otofune-icon] | ![akihikodaki][akihikodaki-icon] | ![tamaina][tamaina-icon] | ![rinsuki][rinsuki-icon] |
|
| [ooo][ooo-link] |
|
||||||
|:-:|:-:|:-:|:-:|:-:|:-:|
|
|
||||||
| [syuilo][syuilo-link]<br>Owner | [Aya Morisawa][ayamorisawa-link]<br>Collaborator | [otofune][otofune-link]<br>Collaborator | [akihikodaki][akihikodaki-link] | [tamaina][tamaina-link] | [rinsuki][rinsuki-link] |
|
|
||||||
|
|
||||||
[List of all contributors](https://github.com/syuilo/misskey/graphs/contributors)
|
|
||||||
|
|
||||||
### :earth_americas: Translators
|
|
||||||
| ![][mirro-san-icon] | ![][Conan-kun-icon] | ![][m4sk1n-icon] |
|
|
||||||
|:-:|:-:|:-:|
|
|
||||||
| [Mirro][mirro-san-link]<br>English, French | [Asriel][Conan-kun-link]<br>English, French | [Marcin Mikołajczak][m4sk1n-link]<br>Polish |
|
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@@ -85,23 +79,8 @@ Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
|
|||||||
[sponsors-image]: https://opencollective.com/misskey/sponsors.svg
|
[sponsors-image]: https://opencollective.com/misskey/sponsors.svg
|
||||||
[support-url]: https://opencollective.com/misskey#support
|
[support-url]: https://opencollective.com/misskey#support
|
||||||
|
|
||||||
<!-- Contributors Info -->
|
|
||||||
[syuilo-link]: https://syuilo.com
|
[syuilo-link]: https://syuilo.com
|
||||||
[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
|
[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
|
||||||
[ayamorisawa-link]: https://github.com/ayamorisawa
|
|
||||||
[ayamorisawa-icon]: https://avatars0.githubusercontent.com/u/10798641?v=3&s=70
|
|
||||||
[otofune-link]: https://github.com/otofune
|
|
||||||
[otofune-icon]: https://avatars0.githubusercontent.com/u/15062473?v=3&s=70
|
|
||||||
[akihikodaki-link]: https://github.com/akihikodaki
|
|
||||||
[akihikodaki-icon]: https://avatars2.githubusercontent.com/u/17036990?s=70&v=4
|
|
||||||
[rinsuki-link]: https://github.com/rinsuki
|
|
||||||
[rinsuki-icon]: https://avatars0.githubusercontent.com/u/6533808?s=70&v=4
|
|
||||||
[tamaina-link]: https://github.com/tamaina
|
|
||||||
[tamaina-icon]: https://avatars1.githubusercontent.com/u/7973572?s=70&v=4
|
|
||||||
|
|
||||||
[mirro-san-link]: https://github.com/mirro-san
|
[ooo-link]: https://www.patreon.com/user/creators?u=11601413
|
||||||
[mirro-san-icon]: https://avatars1.githubusercontent.com/u/17948612?s=70&v=4
|
[ooo-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/11601413/20cb15f209924302b399b99d3c98b850?token-time=2145916800&token-hash=IO31nK6VZCMWBWU2VAk2c824BX2QZ4DNPKyHHZXS0iw%3D
|
||||||
[Conan-kun-link]: https://github.com/Conan-kun
|
|
||||||
[Conan-kun-icon]: https://avatars3.githubusercontent.com/u/30003708?s=70&v=4
|
|
||||||
[m4sk1n-link]: https://github.com/m4sk1n
|
|
||||||
[m4sk1n-icon]: https://avatars3.githubusercontent.com/u/21127288?s=70&v=4
|
|
||||||
|
|||||||
@@ -3,16 +3,21 @@ const User = require('../built/models/user').default;
|
|||||||
|
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
const userId = new mongo.ObjectID(args[0]);
|
const user = args[0];
|
||||||
|
|
||||||
console.log(`Suspending ${userId}...`);
|
const q = user.startsWith('@') ? {
|
||||||
|
username: user.split('@')[1],
|
||||||
|
host: user.split('@')[2] || null
|
||||||
|
} : { _id: new mongo.ObjectID(user) };
|
||||||
|
|
||||||
User.update({ _id: userId }, {
|
console.log(`Suspending ${user}...`);
|
||||||
|
|
||||||
|
User.update(q, {
|
||||||
$set: {
|
$set: {
|
||||||
isSuspended: true
|
isSuspended: true
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
console.log(`Suspended ${userId}`);
|
console.log(`Suspended ${user}`);
|
||||||
}, e => {
|
}, e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
|
|||||||
12
cli/update-remote-user.js
Normal file
12
cli/update-remote-user.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
const updatePerson = require('../built/remote/activitypub/models/person').updatePerson;
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const user = args[0];
|
||||||
|
|
||||||
|
console.log(`Updating ${user}...`);
|
||||||
|
|
||||||
|
updatePerson(user).then(() => {
|
||||||
|
console.log(`Updated ${user}`);
|
||||||
|
}, e => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
111
locales/de.yml
111
locales/de.yml
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "Notizen"
|
memo: "Notizen"
|
||||||
trends: "Trends"
|
trends: "Trends"
|
||||||
photo-stream: "Bilder"
|
photo-stream: "Bilder"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "Diashow"
|
slideshow: "Diashow"
|
||||||
version: "Version"
|
version: "Version"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -70,16 +71,21 @@ common:
|
|||||||
nav: "Navigation"
|
nav: "Navigation"
|
||||||
tips: "Tipps"
|
tips: "Tipps"
|
||||||
deck:
|
deck:
|
||||||
widgets: "ウィジェット"
|
widgets: "Widget hinzufügen:"
|
||||||
home: "ホーム"
|
home: "Startseite"
|
||||||
local: "ローカル"
|
local: "Lokal"
|
||||||
global: "グローバル"
|
global: "Global"
|
||||||
notifications: "通知"
|
notifications: "Mitteilungen"
|
||||||
list: "リスト"
|
list: "Listen"
|
||||||
swap-left: "左に移動"
|
swap-left: "Nach links"
|
||||||
swap-right: "右に移動"
|
swap-right: "Nach rechts"
|
||||||
remove: "カラムを削除"
|
swap-up: "Nach oben"
|
||||||
add-column: "カラムを追加"
|
swap-down: "Nach unten"
|
||||||
|
remove: "Spalte löschen"
|
||||||
|
add-column: "Eine Spalte hinzufügen"
|
||||||
|
rename: "Umbenennen"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "Verbindung zum Server ist fehlgeschlagen"
|
title: "Verbindung zum Server ist fehlgeschlagen"
|
||||||
description: "Es gibt entweder ein Problem mit deiner Internetverbindung, der Server ist nicht erreichbar oder wird gerade gewartet. Bitte versuche es später noch einmal."
|
description: "Es gibt entweder ein Problem mit deiner Internetverbindung, der Server ist nicht erreichbar oder wird gerade gewartet. Bitte versuche es später noch einmal."
|
||||||
@@ -198,7 +204,7 @@ common/views/components/uploader.vue:
|
|||||||
common/views/components/visibility-chooser.vue:
|
common/views/components/visibility-chooser.vue:
|
||||||
public: "Öffentlich"
|
public: "Öffentlich"
|
||||||
home: "Home"
|
home: "Home"
|
||||||
home-desc: "ホームタイムラインにのみ公開"
|
home-desc: "Nur auf die Startseite posten"
|
||||||
followers: "Folgende"
|
followers: "Folgende"
|
||||||
followers-desc: "Nur für diejenigen sichtbar, die dir folgen"
|
followers-desc: "Nur für diejenigen sichtbar, die dir folgen"
|
||||||
specified: "Direkt"
|
specified: "Direkt"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "Fotostream"
|
title: "Fotostream"
|
||||||
no-photos: "Keine Fotos"
|
no-photos: "Keine Fotos"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "Serverinformationen"
|
title: "Serverinformationen"
|
||||||
toggle: "Sicht umschalten"
|
toggle: "Sicht umschalten"
|
||||||
@@ -259,7 +268,7 @@ desktop/views/components/drive.file.vue:
|
|||||||
rename: "Umbenennen"
|
rename: "Umbenennen"
|
||||||
copy-url: "URL kopieren"
|
copy-url: "URL kopieren"
|
||||||
download: "Download"
|
download: "Download"
|
||||||
else-files: "その他..."
|
else-files: "Anderes…"
|
||||||
set-as-avatar: "Als Avatar festlegen"
|
set-as-avatar: "Als Avatar festlegen"
|
||||||
set-as-banner: "Setze als Banner"
|
set-as-banner: "Setze als Banner"
|
||||||
open-in-app: "In der App öffnen"
|
open-in-app: "In der App öffnen"
|
||||||
@@ -301,10 +310,10 @@ desktop/views/components/drive.vue:
|
|||||||
upload: "Eine Datei hochladen"
|
upload: "Eine Datei hochladen"
|
||||||
url-upload: "Von einer URL hochladen"
|
url-upload: "Von einer URL hochladen"
|
||||||
desktop/views/components/follow-button.vue:
|
desktop/views/components/follow-button.vue:
|
||||||
following: "フォロー中"
|
following: "Folge ich"
|
||||||
follow: "フォロー"
|
follow: "Folgen"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "Ausstehend"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "Follower-Anfragen"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} のフォロワー"
|
||||||
desktop/views/components/followers.vue:
|
desktop/views/components/followers.vue:
|
||||||
@@ -312,18 +321,18 @@ desktop/views/components/followers.vue:
|
|||||||
desktop/views/components/following-window.vue:
|
desktop/views/components/following-window.vue:
|
||||||
following: "{} のフォロー"
|
following: "{} のフォロー"
|
||||||
desktop/views/components/following.vue:
|
desktop/views/components/following.vue:
|
||||||
empty: "フォロー中のユーザーはいないようです。"
|
empty: "Du folgst niemanden"
|
||||||
desktop/views/components/friends-maker.vue:
|
desktop/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー:"
|
title: "Wem folgen?"
|
||||||
empty: "おすすめのユーザーは見つかりませんでした。"
|
empty: "Der ausgewählte Benutzer konnte nicht gefunden werden."
|
||||||
fetching: "読み込んでいます"
|
fetching: "Lade…"
|
||||||
refresh: "もっと見る"
|
refresh: "Mehr"
|
||||||
close: "閉じる"
|
close: "Schließen"
|
||||||
desktop/views/components/game-window.vue:
|
desktop/views/components/game-window.vue:
|
||||||
game: "オセロ"
|
game: "オセロ"
|
||||||
desktop/views/components/home.vue:
|
desktop/views/components/home.vue:
|
||||||
done: "完了"
|
done: "Verbunden"
|
||||||
add-widget: "ウィジェットを追加:"
|
add-widget: "Widget hinzufügen:"
|
||||||
add: "Hinzufügen"
|
add: "Hinzufügen"
|
||||||
desktop/views/input-dialog.vue:
|
desktop/views/input-dialog.vue:
|
||||||
cancel: "Abbrechen"
|
cancel: "Abbrechen"
|
||||||
@@ -334,9 +343,9 @@ desktop/views/components/messaging-window.vue:
|
|||||||
title: "Nachrichten"
|
title: "Nachrichten"
|
||||||
desktop/views/components/note-detail.vue:
|
desktop/views/components/note-detail.vue:
|
||||||
more: "Lade weitere Konversationen"
|
more: "Lade weitere Konversationen"
|
||||||
private: "この投稿は非公開です"
|
private: "Dieser Post ist privat"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "Dieser Beitrag wurde entfernt"
|
||||||
reposted-by: "{}がRenote"
|
reposted-by: "Repostet von {}"
|
||||||
location: "Ort"
|
location: "Ort"
|
||||||
renote: "Anmerkung"
|
renote: "Anmerkung"
|
||||||
add-reaction: "Reaktion hinzufügen"
|
add-reaction: "Reaktion hinzufügen"
|
||||||
@@ -346,8 +355,8 @@ desktop/views/components/notes.note.vue:
|
|||||||
renote: "Anmerken"
|
renote: "Anmerken"
|
||||||
add-reaction: "Eine Reaktion hinzufügen"
|
add-reaction: "Eine Reaktion hinzufügen"
|
||||||
detail: "Zeige Details"
|
detail: "Zeige Details"
|
||||||
private: "この投稿は非公開です"
|
private: "Dieser Beitrag ist eine privat"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "Dieser Beitrag wurde entfernt"
|
||||||
desktop/views/components/notes.vue:
|
desktop/views/components/notes.vue:
|
||||||
error: "Laden fehlgeschlagen."
|
error: "Laden fehlgeschlagen."
|
||||||
retry: "Erneut versuchen"
|
retry: "Erneut versuchen"
|
||||||
@@ -388,34 +397,34 @@ desktop/views/components/renote-form.vue:
|
|||||||
success: "Weitergesagt!"
|
success: "Weitergesagt!"
|
||||||
failure: "Weitersagen fehlgeschlagen"
|
failure: "Weitersagen fehlgeschlagen"
|
||||||
desktop/views/components/renote-form-window.vue:
|
desktop/views/components/renote-form-window.vue:
|
||||||
title: "この投稿をRenoteしますか?"
|
title: "Bist du dir sicher, dass du das reposten willst?"
|
||||||
desktop/views/components/settings-window.vue:
|
desktop/views/components/settings-window.vue:
|
||||||
settings: "設定"
|
settings: "Experimentelles"
|
||||||
desktop/views/components/settings.vue:
|
desktop/views/components/settings.vue:
|
||||||
profile: "プロフィール"
|
profile: "プロフィール"
|
||||||
notification: "通知"
|
notification: "Mitteilungen"
|
||||||
apps: "アプリ"
|
apps: "In App öffnen"
|
||||||
mute: "ミュート"
|
mute: "Stummschalten"
|
||||||
drive: "ドライブ"
|
drive: "Dateien vom Drive anfügen"
|
||||||
security: "セキュリティ"
|
security: "セキュリティ"
|
||||||
signin: "サインイン履歴"
|
signin: "サインイン履歴"
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
behaviour: "動作"
|
behaviour: "Verhalten"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "スクロールで自動読み込み"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
auto-popout: "ウィンドウの自動ポップアウト"
|
auto-popout: "ウィンドウの自動ポップアウト"
|
||||||
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
|
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
|
||||||
advanced: "詳細設定"
|
advanced: "Erweiterte Einstellungen"
|
||||||
api-via-stream: "ストリームを経由したAPIリクエスト"
|
api-via-stream: "API-Anfrage via stream"
|
||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
display: "デザインと表示"
|
display: "Erscheinungsbild und Anzeige"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "Startseite anpassen"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "Nacht Modus"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "Kreisförmige Icons"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
gradient-window-header: "Übergang in Fensterköpfen"
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
show-reply-target: "リプライ先を表示する"
|
show-reply-target: "リプライ先を表示する"
|
||||||
show-my-renotes: "自分の行ったRenoteをタイムラインに表示する"
|
show-my-renotes: "自分の行ったRenoteをタイムラインに表示する"
|
||||||
@@ -427,12 +436,12 @@ desktop/views/components/settings.vue:
|
|||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
volume: "ボリューム"
|
volume: "ボリューム"
|
||||||
test: "テスト"
|
test: "テスト"
|
||||||
mobile: "モバイル"
|
mobile: "Mobil"
|
||||||
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
disable-via-mobile: "Diesen Beitrag nicht mit 'vom Handy' absenden"
|
||||||
language: "言語"
|
language: "Sprache"
|
||||||
pick-language: "言語を選択"
|
pick-language: "Sprache auswählen"
|
||||||
recommended: "推奨"
|
recommended: "Empfohlen"
|
||||||
auto: "自動"
|
auto: "Automatisch"
|
||||||
specify-language: "言語を指定"
|
specify-language: "言語を指定"
|
||||||
language-desc: "変更はページの再度読み込み後に反映されます。"
|
language-desc: "変更はページの再度読み込み後に反映されます。"
|
||||||
cache: "キャッシュ"
|
cache: "キャッシュ"
|
||||||
@@ -558,7 +567,7 @@ desktop/views/components/users-list.vue:
|
|||||||
all: "すべて"
|
all: "すべて"
|
||||||
iknow: "知り合い"
|
iknow: "知り合い"
|
||||||
load-more: "もっと"
|
load-more: "もっと"
|
||||||
fetching: "読み込んでいます"
|
fetching: "Lade…"
|
||||||
desktop/views/components/users-list-item.vue:
|
desktop/views/components/users-list-item.vue:
|
||||||
followed: "フォローされています"
|
followed: "フォローされています"
|
||||||
desktop/views/components/window.vue:
|
desktop/views/components/window.vue:
|
||||||
@@ -680,7 +689,7 @@ mobile/views/components/follow-button.vue:
|
|||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "気になるユーザーをフォロー"
|
||||||
empty: "おすすめのユーザーは見つかりませんでした。"
|
empty: "おすすめのユーザーは見つかりませんでした。"
|
||||||
fetching: "読み込んでいます"
|
fetching: "Lade…"
|
||||||
refresh: "もっと見る"
|
refresh: "もっと見る"
|
||||||
close: "閉じる"
|
close: "閉じる"
|
||||||
mobile/views/components/note.vue:
|
mobile/views/components/note.vue:
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "Memo"
|
memo: "Memo"
|
||||||
trends: "Trends"
|
trends: "Trends"
|
||||||
photo-stream: "Photo stream"
|
photo-stream: "Photo stream"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "Slideshow"
|
slideshow: "Slideshow"
|
||||||
version: "Version"
|
version: "Version"
|
||||||
broadcast: "Broadcast"
|
broadcast: "Broadcast"
|
||||||
@@ -76,10 +77,15 @@ common:
|
|||||||
global: "Global"
|
global: "Global"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
list: "List"
|
list: "List"
|
||||||
swap-left: "Move Left"
|
swap-left: "Move left"
|
||||||
swap-right: "Move Right"
|
swap-right: "Move right"
|
||||||
|
swap-up: "Move upward"
|
||||||
|
swap-down: "Move downward"
|
||||||
remove: "Remove"
|
remove: "Remove"
|
||||||
add-column: "Add a column"
|
add-column: "Add a column"
|
||||||
|
rename: "Rename"
|
||||||
|
stack-left: "Stack to left"
|
||||||
|
pop-right: "Pop to right"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "Unable to connect to the server"
|
title: "Unable to connect to the server"
|
||||||
description: "There is a problem either with your Internet connection, or the server may be down or under maintenance. Please {try again} later."
|
description: "There is a problem either with your Internet connection, or the server may be down or under maintenance. Please {try again} later."
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "Photostream"
|
title: "Photostream"
|
||||||
no-photos: "No photos"
|
no-photos: "No photos"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "Server info"
|
title: "Server info"
|
||||||
toggle: "Toggle views"
|
toggle: "Toggle views"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
583
locales/fr.yml
583
locales/fr.yml
@@ -3,9 +3,9 @@ meta:
|
|||||||
lang: "Français"
|
lang: "Français"
|
||||||
divider: ""
|
divider: ""
|
||||||
common:
|
common:
|
||||||
misskey: "A planet of fediverse"
|
misskey: "Une planète du fédiverse"
|
||||||
about-title: "A ⭐ of fediverse."
|
about-title: "Une ⭐ du fédiverse."
|
||||||
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
about: "Merci d'avoir découvert Misskey. Misskey est une <b>plateforme de micro-blogging distribuée</b> née sur Terre. Parce qu'il fait partie du Fédiverse (un univers composé de diverses plateformes de réseaux sociaux organisées), il est mutuellement connecté avec d'autres plateformes de réseaux sociaux. Désirez-vous prendre une pause, pendant un instant, loin de l'agitation de la ville et plonger dans un nouvel Internet ?"
|
||||||
time:
|
time:
|
||||||
unknown: "inconnu"
|
unknown: "inconnu"
|
||||||
future: "future"
|
future: "future"
|
||||||
@@ -24,7 +24,7 @@ common:
|
|||||||
wednesday: "M"
|
wednesday: "M"
|
||||||
thursday: "J"
|
thursday: "J"
|
||||||
friday: "V"
|
friday: "V"
|
||||||
saturday: "土"
|
saturday: "S"
|
||||||
reactions:
|
reactions:
|
||||||
like: "Aime"
|
like: "Aime"
|
||||||
love: "Adore"
|
love: "Adore"
|
||||||
@@ -36,50 +36,56 @@ common:
|
|||||||
confused: "Confus"
|
confused: "Confus"
|
||||||
pudding: "Pudding"
|
pudding: "Pudding"
|
||||||
note-placeholders:
|
note-placeholders:
|
||||||
a: "今どうしてる?"
|
a: "Que faîtes vous à cet instant ?"
|
||||||
b: "何かありましたか?"
|
b: "Quoi de neuf ?"
|
||||||
c: "何をお考えですか?"
|
c: "Qu'avez-vous en tête ?"
|
||||||
d: "言いたいことは?"
|
d: "Voulez-vous exprimer quelque chose ?"
|
||||||
e: "ここに書いてください"
|
e: "Écrivez ici"
|
||||||
f: "あなたが書くのを待っています..."
|
f: "En attente de vos écrits"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
loading: "Chargement"
|
loading: "Chargement"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
update-available: "Une nouvelle version de Misskey est disponible({newer}, version actuelle: {current}). Recharger la page pour appliquer la mise à jour."
|
update-available: "Une nouvelle version de Misskey est disponible({newer}, version actuelle: {current}). Recharger la page pour appliquer la mise à jour."
|
||||||
my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté."
|
my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté."
|
||||||
widgets:
|
widgets:
|
||||||
analog-clock: "アナログ時計"
|
analog-clock: "Horloge analogique"
|
||||||
profile: "プロフィール"
|
profile: "Profil"
|
||||||
calendar: "カレンダー"
|
calendar: "Calendrier"
|
||||||
timemachine: "カレンダー(タイムマシン)"
|
timemachine: "カレンダー(タイムマシン)"
|
||||||
activity: "アクティビティ"
|
activity: "Activité"
|
||||||
rss: "RSSリーダー"
|
rss: "Lecteur de flux RSS"
|
||||||
memo: "メモ"
|
memo: "Note"
|
||||||
trends: "トレンド"
|
trends: "Tendances"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "Flux de photos"
|
||||||
slideshow: "スライドショー"
|
posts-monitor: "投稿チャート"
|
||||||
version: "バージョン"
|
slideshow: "Diaporama"
|
||||||
broadcast: "ブロードキャスト"
|
version: "Version"
|
||||||
notifications: "通知"
|
broadcast: "Diffusion"
|
||||||
users: "おすすめユーザー"
|
notifications: "Notifications"
|
||||||
polls: "投票"
|
users: "Utilisateurs"
|
||||||
|
polls: "Sondages"
|
||||||
post-form: "投稿フォーム"
|
post-form: "投稿フォーム"
|
||||||
messaging: "メッセージ"
|
messaging: "Messagerie"
|
||||||
server: "サーバー情報"
|
server: "Info sur le serveur"
|
||||||
donation: "寄付のお願い"
|
donation: "Dons"
|
||||||
nav: "ナビゲーション"
|
nav: "Navigation"
|
||||||
tips: "ヒント"
|
tips: "Conseils"
|
||||||
deck:
|
deck:
|
||||||
widgets: "ウィジェット"
|
widgets: "Widgets"
|
||||||
home: "ホーム"
|
home: "Accueil"
|
||||||
local: "ローカル"
|
local: "Local"
|
||||||
global: "グローバル"
|
global: "Global"
|
||||||
notifications: "通知"
|
notifications: "Notifications"
|
||||||
list: "リスト"
|
list: "Liste"
|
||||||
swap-left: "左に移動"
|
swap-left: "Déplacer à gauche"
|
||||||
swap-right: "右に移動"
|
swap-right: "Déplacer à droite"
|
||||||
remove: "カラムを削除"
|
swap-up: "Vers le haut"
|
||||||
add-column: "カラムを追加"
|
swap-down: "Vers le bas"
|
||||||
|
remove: "Supprimer"
|
||||||
|
add-column: "Ajouter une colonne"
|
||||||
|
rename: "Renommer"
|
||||||
|
stack-left: "Vers la gauche"
|
||||||
|
pop-right: "Vers la droite"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "Impossible de se connecter au server."
|
title: "Impossible de se connecter au server."
|
||||||
description: "Il y a soit un problème avec votre connexion internet, soit le serveur est hors-ligne ou en maintenance. Veuillez {ressayer} plus tard."
|
description: "Il y a soit un problème avec votre connexion internet, soit le serveur est hors-ligne ou en maintenance. Veuillez {ressayer} plus tard."
|
||||||
@@ -102,8 +108,8 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
no-server-desc: "Votre connexion est OK, mais il a été impossible de vous connecter au serveur de Misskey. Il y a des chances que le serveur soit hors-ligne ou en maintenance, veuillez ressayer plus tard."
|
no-server-desc: "Votre connexion est OK, mais il a été impossible de vous connecter au serveur de Misskey. Il y a des chances que le serveur soit hors-ligne ou en maintenance, veuillez ressayer plus tard."
|
||||||
success: "Connexion au serveur de Misskey reussie!"
|
success: "Connexion au serveur de Misskey reussie!"
|
||||||
success-desc: "La connexion au serveur a été reussie. Veuillez recharger la page."
|
success-desc: "La connexion au serveur a été reussie. Veuillez recharger la page."
|
||||||
flush: "キャッシュの削除"
|
flush: "Vider le cache"
|
||||||
set-version: "バージョン指定"
|
set-version: "Choisissez une version"
|
||||||
common/views/components/messaging.vue:
|
common/views/components/messaging.vue:
|
||||||
search-user: "Trouver un utilisateur"
|
search-user: "Trouver un utilisateur"
|
||||||
you: "Vous"
|
you: "Vous"
|
||||||
@@ -130,12 +136,12 @@ common/views/components/nav.vue:
|
|||||||
donors: "Donateurs"
|
donors: "Donateurs"
|
||||||
repository: "Repo"
|
repository: "Repo"
|
||||||
develop: "Développeurs"
|
develop: "Développeurs"
|
||||||
feedback: "フィードバック"
|
feedback: "Remarques"
|
||||||
common/views/components/note-menu.vue:
|
common/views/components/note-menu.vue:
|
||||||
favorite: "Favorite this note"
|
favorite: "Favorite this note"
|
||||||
pin: "Épingler sur votre profile"
|
pin: "Épingler sur votre profile"
|
||||||
delete: "削除"
|
delete: "Supprimer"
|
||||||
delete-confirm: "この投稿を削除しますか?"
|
delete-confirm: "Supprimer cette publication ?"
|
||||||
remote: "投稿元で見る"
|
remote: "投稿元で見る"
|
||||||
common/views/components/poll.vue:
|
common/views/components/poll.vue:
|
||||||
vote-to: "Voter pour '{}'"
|
vote-to: "Voter pour '{}'"
|
||||||
@@ -196,14 +202,14 @@ common/views/components/twitter-setting.vue:
|
|||||||
common/views/components/uploader.vue:
|
common/views/components/uploader.vue:
|
||||||
waiting: "En attente"
|
waiting: "En attente"
|
||||||
common/views/components/visibility-chooser.vue:
|
common/views/components/visibility-chooser.vue:
|
||||||
public: "公開"
|
public: "Public"
|
||||||
home: "ホーム"
|
home: "Accueil"
|
||||||
home-desc: "ホームタイムラインにのみ公開"
|
home-desc: "Publier sur le fil d'Accueil uniquement"
|
||||||
followers: "フォロワー"
|
followers: "Abonnés"
|
||||||
followers-desc: "自分のフォロワーにのみ公開"
|
followers-desc: "Publier à vos abonnés uniquement"
|
||||||
specified: "ダイレクト"
|
specified: "Direct"
|
||||||
specified-desc: "指定したユーザーにのみ公開"
|
specified-desc: "Publier aux utilisateurs mentionnés"
|
||||||
private: "非公開"
|
private: "Privé"
|
||||||
common/views/widgets/broadcast.vue:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Récuperation"
|
fetching: "Récuperation"
|
||||||
no-broadcasts: "No broadcasts"
|
no-broadcasts: "No broadcasts"
|
||||||
@@ -215,18 +221,21 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "Flux de photo"
|
title: "Flux de photo"
|
||||||
no-photos: "Pas de photos"
|
no-photos: "Pas de photos"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "Info sur le serveur"
|
title: "Info sur le serveur"
|
||||||
toggle: "Afficher les vues"
|
toggle: "Afficher les vues"
|
||||||
common/views/widgets/memo.vue:
|
common/views/widgets/memo.vue:
|
||||||
title: "メモ"
|
title: "Note"
|
||||||
memo: "ここに書いて!"
|
memo: "Écrivez ici !"
|
||||||
save: "保存"
|
save: "Enregistrer"
|
||||||
desktop/views/components/activity.chart.vue:
|
desktop/views/components/activity.chart.vue:
|
||||||
total: "Black ... Total"
|
total: "Black ... Total"
|
||||||
notes: "Blue ... Notes"
|
notes: "Bleu ... Notes"
|
||||||
replies: "Red ... Replies"
|
replies: "Rouge ... Réponses"
|
||||||
renotes: "Green ... Renotes"
|
renotes: "Vert ... Partages"
|
||||||
desktop/views/components/activity.vue:
|
desktop/views/components/activity.vue:
|
||||||
title: "Activitié"
|
title: "Activitié"
|
||||||
toggle: "Afficher les vues"
|
toggle: "Afficher les vues"
|
||||||
@@ -236,19 +245,19 @@ desktop/views/components/calendar.vue:
|
|||||||
next: "Mois prochain"
|
next: "Mois prochain"
|
||||||
go: "Cliquer pour naviguer"
|
go: "Cliquer pour naviguer"
|
||||||
desktop/views/components/choose-file-from-drive-window.vue:
|
desktop/views/components/choose-file-from-drive-window.vue:
|
||||||
choose-file: "ファイル選択中"
|
choose-file: "Sélection de fichiers"
|
||||||
upload: "PCからドライブにファイルをアップロード"
|
upload: "Téléverser des fichiers à partir de votre PC"
|
||||||
cancel: "キャンセル"
|
cancel: "Annuler"
|
||||||
ok: "決定"
|
ok: "OK"
|
||||||
choose-prompt: "ファイルを選択"
|
choose-prompt: "Choisir un fichier"
|
||||||
desktop/views/components/choose-folder-from-drive-window.vue:
|
desktop/views/components/choose-folder-from-drive-window.vue:
|
||||||
cancel: "キャンセル"
|
cancel: "Annuler"
|
||||||
ok: "決定"
|
ok: "OK"
|
||||||
choose-prompt: "フォルダを選択"
|
choose-prompt: "Choisir un dossier"
|
||||||
desktop/views/components/crop-window.vue:
|
desktop/views/components/crop-window.vue:
|
||||||
skip: "クロップをスキップ"
|
skip: "Ignorer la découpe"
|
||||||
cancel: "キャンセル"
|
cancel: "Annuler"
|
||||||
ok: "決定"
|
ok: "OK"
|
||||||
desktop/views/components/drive-window.vue:
|
desktop/views/components/drive-window.vue:
|
||||||
used: "utilisé"
|
used: "utilisé"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
@@ -301,65 +310,65 @@ desktop/views/components/drive.vue:
|
|||||||
upload: "Uploader un fichier"
|
upload: "Uploader un fichier"
|
||||||
url-upload: "Uploader d'un URL"
|
url-upload: "Uploader d'un URL"
|
||||||
desktop/views/components/follow-button.vue:
|
desktop/views/components/follow-button.vue:
|
||||||
following: "フォロー中"
|
following: "Abonnements"
|
||||||
follow: "フォロー"
|
follow: "Suivre"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "En attente d'approbation"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "Demande d'abonnement"
|
||||||
desktop/views/components/followers-window.vue:
|
desktop/views/components/followers-window.vue:
|
||||||
followers: "{} のフォロワー"
|
followers: "{} abonnés"
|
||||||
desktop/views/components/followers.vue:
|
desktop/views/components/followers.vue:
|
||||||
empty: "フォロワーはいないようです。"
|
empty: "Il semble que vous n'avez pas encore d'abonnés."
|
||||||
desktop/views/components/following-window.vue:
|
desktop/views/components/following-window.vue:
|
||||||
following: "{} のフォロー"
|
following: "Suit {}"
|
||||||
desktop/views/components/following.vue:
|
desktop/views/components/following.vue:
|
||||||
empty: "フォロー中のユーザーはいないようです。"
|
empty: "Vous ne suivez aucun compte."
|
||||||
desktop/views/components/friends-maker.vue:
|
desktop/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー:"
|
title: "Utilisateurs recommandés :"
|
||||||
empty: "おすすめのユーザーは見つかりませんでした。"
|
empty: "Impossible de trouver des utilisateurs à recommander."
|
||||||
fetching: "読み込んでいます"
|
fetching: "Chargement"
|
||||||
refresh: "もっと見る"
|
refresh: "Plus"
|
||||||
close: "閉じる"
|
close: "Fermer"
|
||||||
desktop/views/components/game-window.vue:
|
desktop/views/components/game-window.vue:
|
||||||
game: "オセロ"
|
game: "Othello"
|
||||||
desktop/views/components/home.vue:
|
desktop/views/components/home.vue:
|
||||||
done: "完了"
|
done: "Envoyer"
|
||||||
add-widget: "ウィジェットを追加:"
|
add-widget: "Ajouter un widget"
|
||||||
add: "追加"
|
add: "Ajouter"
|
||||||
desktop/views/input-dialog.vue:
|
desktop/views/input-dialog.vue:
|
||||||
cancel: "キャンセル"
|
cancel: "Annuler"
|
||||||
ok: "決定"
|
ok: "OK"
|
||||||
desktop/views/components/messaging-room-window.vue:
|
desktop/views/components/messaging-room-window.vue:
|
||||||
title: "メッセージ:"
|
title: "Messages :"
|
||||||
desktop/views/components/messaging-window.vue:
|
desktop/views/components/messaging-window.vue:
|
||||||
title: "Messagerie"
|
title: "Messagerie"
|
||||||
desktop/views/components/note-detail.vue:
|
desktop/views/components/note-detail.vue:
|
||||||
more: "会話をもっと読み込む"
|
more: "Charger davantage de conversations"
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
reposted-by: "{}がRenote"
|
reposted-by: "Republié par {}"
|
||||||
location: "位置情報"
|
location: "Géolocalisation"
|
||||||
renote: "Renote"
|
renote: "Republier"
|
||||||
add-reaction: "リアクション"
|
add-reaction: "Ajouter votre reaction"
|
||||||
desktop/views/components/notes.note.vue:
|
desktop/views/components/notes.note.vue:
|
||||||
reposted-by: "Reposté par {}"
|
reposted-by: "Reposté par {}"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
renote: "Renote"
|
renote: "Republier"
|
||||||
add-reaction: "Ajouter votre reaction"
|
add-reaction: "Ajouter votre reaction"
|
||||||
detail: "Afficher les détails"
|
detail: "Afficher les détails"
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
desktop/views/components/notes.vue:
|
desktop/views/components/notes.vue:
|
||||||
error: "読み込みに失敗しました。"
|
error: "Échec du chargement."
|
||||||
retry: "リトライ"
|
retry: "Réessayer"
|
||||||
desktop/views/components/notifications.vue:
|
desktop/views/components/notifications.vue:
|
||||||
more: "Plus"
|
more: "Plus"
|
||||||
empty: "Pas de notifications"
|
empty: "Pas de notifications"
|
||||||
desktop/views/components/post-form.vue:
|
desktop/views/components/post-form.vue:
|
||||||
reply-placeholder: "Répondre à cette note"
|
reply-placeholder: "Répondre à cette note"
|
||||||
quote-placeholder: "Citer cette note"
|
quote-placeholder: "Citer cette note"
|
||||||
submit: "投稿"
|
submit: "Poster"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
renote: "Renote"
|
renote: "Republier"
|
||||||
posted: "Posté!"
|
posted: "Posté!"
|
||||||
replied: "Répondu!"
|
replied: "Répondu!"
|
||||||
reposted: "Reposté!"
|
reposted: "Reposté!"
|
||||||
@@ -379,18 +388,18 @@ desktop/views/components/post-form-window.vue:
|
|||||||
attaches: "{} media joint(s)"
|
attaches: "{} media joint(s)"
|
||||||
uploading-media: "Upload du media {}"
|
uploading-media: "Upload du media {}"
|
||||||
desktop/views/components/progress-dialog.vue:
|
desktop/views/components/progress-dialog.vue:
|
||||||
waiting: "待機中"
|
waiting: "En attente"
|
||||||
desktop/views/components/renote-form.vue:
|
desktop/views/components/renote-form.vue:
|
||||||
quote: "Citer..."
|
quote: "Citer..."
|
||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
renote: "Renote"
|
renote: "Republier"
|
||||||
reposting: "Repost en cours..."
|
reposting: "Repost en cours..."
|
||||||
success: "Reposté!"
|
success: "Reposté!"
|
||||||
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?"
|
||||||
desktop/views/components/settings-window.vue:
|
desktop/views/components/settings-window.vue:
|
||||||
settings: "設定"
|
settings: "Paramètres"
|
||||||
desktop/views/components/settings.vue:
|
desktop/views/components/settings.vue:
|
||||||
profile: "Profil"
|
profile: "Profil"
|
||||||
notification: "Notification"
|
notification: "Notification"
|
||||||
@@ -403,67 +412,67 @@ desktop/views/components/settings.vue:
|
|||||||
2fa: "Vérification en deux étapes"
|
2fa: "Vérification en deux étapes"
|
||||||
other: "Autres"
|
other: "Autres"
|
||||||
license: "License"
|
license: "License"
|
||||||
behaviour: "動作"
|
behaviour: "Comportement"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "Chargement lors du défilement"
|
||||||
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
|
||||||
auto-popout: "ウィンドウの自動ポップアウト"
|
auto-popout: "Fenêtre contextuelle automatique"
|
||||||
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
|
auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
|
||||||
advanced: "詳細設定"
|
advanced: "Paramètres avancés"
|
||||||
api-via-stream: "ストリームを経由したAPIリクエスト"
|
api-via-stream: "Requête API via le flux"
|
||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
display: "デザインと表示"
|
display: "Affichage et design"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "Personnaliser l'Accueil"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "Mode nuit"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "Utiliser des icônes circulaires"
|
||||||
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
|
||||||
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
|
||||||
show-reply-target: "リプライ先を表示する"
|
show-reply-target: "リプライ先を表示する"
|
||||||
show-my-renotes: "自分の行ったRenoteをタイムラインに表示する"
|
show-my-renotes: "Afficher mes republications dans le fil"
|
||||||
show-renoted-my-notes: "Renoteされた自分の投稿をタイムラインに表示する"
|
show-renoted-my-notes: "Renoteされた自分の投稿をタイムラインに表示する"
|
||||||
show-maps: "マップの自動展開"
|
show-maps: "Afficher la carte"
|
||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
||||||
sound: "サウンド"
|
sound: "Son"
|
||||||
enable-sounds: "サウンドを有効にする"
|
enable-sounds: "Activer le son"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
||||||
volume: "ボリューム"
|
volume: "Volume"
|
||||||
test: "テスト"
|
test: "Test"
|
||||||
mobile: "モバイル"
|
mobile: "Mobile"
|
||||||
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
||||||
language: "言語"
|
language: "Langue"
|
||||||
pick-language: "言語を選択"
|
pick-language: "Sélectionner une langue"
|
||||||
recommended: "推奨"
|
recommended: "Recommandé"
|
||||||
auto: "自動"
|
auto: "Automatique"
|
||||||
specify-language: "言語を指定"
|
specify-language: "Spécifier la langue"
|
||||||
language-desc: "変更はページの再度読み込み後に反映されます。"
|
language-desc: "変更はページの再度読み込み後に反映されます。"
|
||||||
cache: "キャッシュ"
|
cache: "Cache"
|
||||||
clean-cache: "クリーンアップ"
|
clean-cache: "Nettoyage"
|
||||||
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
|
cache-warn: "クリーンアップを行うと、ブラウザに記憶されたアカウント情報のキャッシュ、書きかけの投稿・返信・メッセージ、およびその他のデータ(設定情報含む)が削除されます。クリーンアップを行った後はページを再度読み込みする必要があります。"
|
||||||
cache-cleared: "キャッシュを削除しました"
|
cache-cleared: "Cache nettoyé"
|
||||||
cache-cleared-desc: "ページを再度読み込みしてください。"
|
cache-cleared-desc: "Veuillez recharger la page."
|
||||||
auto-watch: "投稿の自動ウォッチ"
|
auto-watch: "投稿の自動ウォッチ"
|
||||||
auto-watch-desc: "リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。"
|
auto-watch-desc: "リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。"
|
||||||
about: "Misskeyについて"
|
about: "À propose de Misskey"
|
||||||
operator: "このサーバーの運営者"
|
operator: "L'admin de cette instance"
|
||||||
update: "Misskey Update"
|
update: "Mise à jour de Misskey"
|
||||||
version: "バージョン:"
|
version: "Version :"
|
||||||
latest-version: "最新のバージョン:"
|
latest-version: "Dernière version :"
|
||||||
update-checking: "アップデートを確認中"
|
update-checking: "Recherche de mises à jour"
|
||||||
do-update: "アップデートを確認"
|
do-update: "Rechercher des mises à jour"
|
||||||
update-settings: "詳細設定"
|
update-settings: "Paramètres avancés"
|
||||||
prevent-update: "アップデートを延期する(非推奨)"
|
prevent-update: "アップデートを延期する(非推奨)"
|
||||||
prevent-update-desc: "この設定をオンにしてもアップデートが反映される場合があります。この設定はこのデバイスのみ有効です。"
|
prevent-update-desc: "この設定をオンにしてもアップデートが反映される場合があります。この設定はこのデバイスのみ有効です。"
|
||||||
no-updates: "利用可能な更新はありません"
|
no-updates: "Aucune mise à jour disponible"
|
||||||
no-updates-desc: "お使いのMisskeyは最新です。"
|
no-updates-desc: "Votre Misskey est à jour."
|
||||||
update-available: "新しいバージョンが利用可能です"
|
update-available: "Nouvelle version disponible !"
|
||||||
update-available-desc: "ページを再度読み込みすると更新が適用されます。"
|
update-available-desc: "ページを再度読み込みすると更新が適用されます。"
|
||||||
advanced-settings: "高度な設定"
|
advanced-settings: "Réglages avancés"
|
||||||
debug-mode: "デバッグモードを有効にする"
|
debug-mode: "Activer le mode debug"
|
||||||
debug-mode-desc: "この設定はブラウザに記憶されます。"
|
debug-mode-desc: "Ce paramètre est stocké dans le navigateur."
|
||||||
experimental: "実験的機能を有効にする"
|
experimental: "Activer les fonctionnalités expérimentales"
|
||||||
experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。"
|
experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。"
|
||||||
tools: "ツール"
|
tools: "Outils"
|
||||||
task-manager: "タスクマネージャ"
|
task-manager: "Gestionnaire de tâches"
|
||||||
third-parties: "サードパーティ"
|
third-parties: "Services tiers"
|
||||||
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..."
|
||||||
@@ -487,10 +496,10 @@ desktop/views/components/settings.api.vue:
|
|||||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||||
regenerate-token: "Regenerer le token"
|
regenerate-token: "Regenerer le token"
|
||||||
token: "Token:"
|
token: "Jeton :"
|
||||||
enter-password: "Veuillez entrer le mot de passe"
|
enter-password: "Veuillez entrer le mot de passe"
|
||||||
desktop/views/components/settings.apps.vue:
|
desktop/views/components/settings.apps.vue:
|
||||||
no-apps: "連携しているアプリケーションはありません"
|
no-apps: "Aucune application autorisée"
|
||||||
desktop/views/components/settings.mute.vue:
|
desktop/views/components/settings.mute.vue:
|
||||||
no-users: "Aucun utilisateurs mis en sourdine"
|
no-users: "Aucun utilisateurs mis en sourdine"
|
||||||
desktop/views/components/settings.password.vue:
|
desktop/views/components/settings.password.vue:
|
||||||
@@ -508,26 +517,26 @@ desktop/views/components/settings.profile.vue:
|
|||||||
description: "Description"
|
description: "Description"
|
||||||
birthday: "Date de naissance"
|
birthday: "Date de naissance"
|
||||||
save: "Mettre à jour le profil"
|
save: "Mettre à jour le profil"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "Ce compte est un Bot"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "Ce compte est un Chat"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
media-count: "{}つのメディア"
|
media-count: "{} médias attachés"
|
||||||
poll: "投票"
|
poll: "Sondages"
|
||||||
desktop/views/components/taskmanager.vue:
|
desktop/views/components/taskmanager.vue:
|
||||||
title: "タスクマネージャ"
|
title: "Gestionnaire de tâches"
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "ホーム"
|
home: "Accueil"
|
||||||
local: "ローカル"
|
local: "Local"
|
||||||
global: "グローバル"
|
global: "Global"
|
||||||
list: "リスト"
|
list: "Listes"
|
||||||
desktop/views/components/ui.header.account.vue:
|
desktop/views/components/ui.header.account.vue:
|
||||||
profile: "Votre profil"
|
profile: "Votre profil"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
favorites: "Favorites"
|
favorites: "Favorites"
|
||||||
lists: "リスト"
|
lists: "Listes"
|
||||||
follow-requests: "フォロー申請"
|
follow-requests: "Demandes de suivi"
|
||||||
customize: "Modifications"
|
customize: "Modifications"
|
||||||
settings: "Réglages"
|
settings: "Réglages"
|
||||||
signout: "Déconnexion"
|
signout: "Déconnexion"
|
||||||
@@ -544,40 +553,40 @@ desktop/views/components/ui.header.post.vue:
|
|||||||
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:
|
||||||
title: "フォロー申請"
|
title: "Demandes de suivi"
|
||||||
accept: "承認"
|
accept: "Approuver"
|
||||||
reject: "拒否"
|
reject: "Refuser"
|
||||||
desktop/views/components/user-lists-window.vue:
|
desktop/views/components/user-lists-window.vue:
|
||||||
title: "リスト"
|
title: "Listes de l'utilisateur"
|
||||||
create-list: "リストを作成"
|
create-list: "Créer une liste"
|
||||||
desktop/views/components/user-preview.vue:
|
desktop/views/components/user-preview.vue:
|
||||||
notes: "投稿"
|
notes: "Publications"
|
||||||
following: "フォロー"
|
following: "Abonné à"
|
||||||
followers: "フォロワー"
|
followers: "Abonnés"
|
||||||
desktop/views/components/users-list.vue:
|
desktop/views/components/users-list.vue:
|
||||||
all: "すべて"
|
all: "Tout"
|
||||||
iknow: "知り合い"
|
iknow: "Vous connaissez"
|
||||||
load-more: "もっと"
|
load-more: "Afficher plus"
|
||||||
fetching: "読み込んでいます"
|
fetching: "Chargement ..."
|
||||||
desktop/views/components/users-list-item.vue:
|
desktop/views/components/users-list-item.vue:
|
||||||
followed: "フォローされています"
|
followed: "vous suit"
|
||||||
desktop/views/components/window.vue:
|
desktop/views/components/window.vue:
|
||||||
popout: "ポップアウト"
|
popout: "ポップアウト"
|
||||||
close: "閉じる"
|
close: "Fermer"
|
||||||
desktop/views/pages/welcome.vue:
|
desktop/views/pages/welcome.vue:
|
||||||
about: "詳しく..."
|
about: "à propos"
|
||||||
gotit: "わかった"
|
gotit: "J'ai compris !"
|
||||||
signin: "ログイン"
|
signin: "Connexion"
|
||||||
signup: "新規登録"
|
signup: "S'enregistrer"
|
||||||
signin-button: "やってる"
|
signin-button: "Se connecter"
|
||||||
signup-button: "やる"
|
signup-button: "S'inscrire"
|
||||||
timeline: "タイムライン"
|
timeline: "Fil d'actualité"
|
||||||
desktop/views/pages/drive.vue:
|
desktop/views/pages/drive.vue:
|
||||||
title: "Misskey Drive"
|
title: "Lecteur de Misskey"
|
||||||
desktop/views/pages/favorites.vue:
|
desktop/views/pages/favorites.vue:
|
||||||
more: "さらに読み込む"
|
more: "Plus de résultats"
|
||||||
desktop/views/pages/home-customize.vue:
|
desktop/views/pages/home-customize.vue:
|
||||||
title: "ホームのカスタマイズ"
|
title: "Personnaliser l'Accueil"
|
||||||
desktop/views/pages/note.vue:
|
desktop/views/pages/note.vue:
|
||||||
prev: "Note précédente"
|
prev: "Note précédente"
|
||||||
next: "Note suivante"
|
next: "Note suivante"
|
||||||
@@ -587,9 +596,9 @@ desktop/views/pages/selectdrive.vue:
|
|||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
upload: "Uploader un ou plusieurs fichier(s) depuis votre PC"
|
upload: "Uploader un ou plusieurs fichier(s) depuis votre PC"
|
||||||
desktop/views/pages/user-list.users.vue:
|
desktop/views/pages/user-list.users.vue:
|
||||||
users: "ユーザー"
|
users: "Utilisateurs"
|
||||||
add-user: "ユーザーを追加"
|
add-user: "Ajouter un utilisateur"
|
||||||
username: "ユーザー名"
|
username: "Nom d'utilisateur"
|
||||||
desktop/views/pages/user/user.followers-you-know.vue:
|
desktop/views/pages/user/user.followers-you-know.vue:
|
||||||
title: "Abonnés que vous connaissez"
|
title: "Abonnés que vous connaissez"
|
||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
@@ -617,10 +626,10 @@ desktop/views/pages/user/user.profile.vue:
|
|||||||
muted: "Muting"
|
muted: "Muting"
|
||||||
unmute: "Enlever la sourdine"
|
unmute: "Enlever la sourdine"
|
||||||
desktop/views/pages/user/user.timeline.vue:
|
desktop/views/pages/user/user.timeline.vue:
|
||||||
default: "投稿"
|
default: "Publications"
|
||||||
with-replies: "投稿と返信"
|
with-replies: "Publications et réponses"
|
||||||
with-media: "メディア"
|
with-media: "Média"
|
||||||
empty: "このユーザーはまだ何も投稿していないようです。"
|
empty: "Cet utilisateur n'a rien posté encore."
|
||||||
desktop/views/widgets/messaging.vue:
|
desktop/views/widgets/messaging.vue:
|
||||||
title: "Messagerie"
|
title: "Messagerie"
|
||||||
desktop/views/widgets/notifications.vue:
|
desktop/views/widgets/notifications.vue:
|
||||||
@@ -634,8 +643,8 @@ desktop/views/widgets/post-form.vue:
|
|||||||
title: "Post"
|
title: "Post"
|
||||||
note: "Post"
|
note: "Post"
|
||||||
desktop/views/widgets/profile.vue:
|
desktop/views/widgets/profile.vue:
|
||||||
update-banner: "クリックでバナー編集"
|
update-banner: "Cliquer pour éditer votre bannière"
|
||||||
update-avatar: "クリックでアバター編集"
|
update-avatar: "Cliquer pour éditer votre avatar"
|
||||||
desktop/views/widgets/trends.vue:
|
desktop/views/widgets/trends.vue:
|
||||||
title: "Tendances"
|
title: "Tendances"
|
||||||
refresh: "Afficher d'autres"
|
refresh: "Afficher d'autres"
|
||||||
@@ -655,13 +664,13 @@ mobile/views/components/drive.vue:
|
|||||||
folder-is-empty: "Ce dossier est vide"
|
folder-is-empty: "Ce dossier est vide"
|
||||||
prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>"
|
prompt: "何をしますか?(数字を入力してください): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>"
|
||||||
deletion-alert: "ごめんなさい!フォルダの削除は未実装です...。"
|
deletion-alert: "ごめんなさい!フォルダの削除は未実装です...。"
|
||||||
folder-name: "フォルダー名"
|
folder-name: "Nom du dossier"
|
||||||
root-rename-alert: "現在いる場所はルートで、フォルダではないため名前の変更はできません。名前を変更したいフォルダに移動してからやってください。"
|
root-rename-alert: "現在いる場所はルートで、フォルダではないため名前の変更はできません。名前を変更したいフォルダに移動してからやってください。"
|
||||||
root-move-alert: "現在いる場所はルートで、フォルダではないため移動はできません。移動したいフォルダに移動してからやってください。"
|
root-move-alert: "現在いる場所はルートで、フォルダではないため移動はできません。移動したいフォルダに移動してからやってください。"
|
||||||
url-prompt: "アップロードしたいファイルのURL"
|
url-prompt: "アップロードしたいファイルのURL"
|
||||||
uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。"
|
uploading: "アップロードをリクエストしました。アップロードが完了するまで時間がかかる場合があります。"
|
||||||
mobile/views/components/drive-file-detail.vue:
|
mobile/views/components/drive-file-detail.vue:
|
||||||
rename: "名前を変更"
|
rename: "Renommer"
|
||||||
mobile/views/components/drive-file-chooser.vue:
|
mobile/views/components/drive-file-chooser.vue:
|
||||||
select-file: "Choisissez un fichier"
|
select-file: "Choisissez un fichier"
|
||||||
mobile/views/components/drive-folder-chooser.vue:
|
mobile/views/components/drive-folder-chooser.vue:
|
||||||
@@ -676,72 +685,72 @@ mobile/views/components/follow-button.vue:
|
|||||||
following: "フォロー中"
|
following: "フォロー中"
|
||||||
follow: "Suivre"
|
follow: "Suivre"
|
||||||
request-pending: "フォロー許可待ち"
|
request-pending: "フォロー許可待ち"
|
||||||
follow-request: "フォロー申請"
|
follow-request: "Demande d'abonnement"
|
||||||
mobile/views/components/friends-maker.vue:
|
mobile/views/components/friends-maker.vue:
|
||||||
title: "気になるユーザーをフォロー"
|
title: "Abonnez-vous aux utilisateurs"
|
||||||
empty: "おすすめのユーザーは見つかりませんでした。"
|
empty: "おすすめのユーザーは見つかりませんでした。"
|
||||||
fetching: "読み込んでいます"
|
fetching: "Chargement"
|
||||||
refresh: "もっと見る"
|
refresh: "Voir plus"
|
||||||
close: "閉じる"
|
close: "Fermer"
|
||||||
mobile/views/components/note.vue:
|
mobile/views/components/note.vue:
|
||||||
reposted-by: "Renoté par {}"
|
reposted-by: "Renoté par {}"
|
||||||
more: "もっと見る"
|
more: "Voir plus"
|
||||||
less: "隠す"
|
less: "Masquer"
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
location: "位置情報"
|
location: "Géolocalisation"
|
||||||
mobile/views/components/note-detail.vue:
|
mobile/views/components/note-detail.vue:
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
reaction: "Réaction"
|
reaction: "Réaction"
|
||||||
reposted-by: "{}がRenote"
|
reposted-by: "Republié par {}"
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
location: "位置情報"
|
location: "Lieu"
|
||||||
mobile/views/components/note-preview.vue:
|
mobile/views/components/note-preview.vue:
|
||||||
admin: "admin"
|
admin: "admin"
|
||||||
bot: "bot"
|
bot: "bot"
|
||||||
cat: "cat"
|
cat: "chat"
|
||||||
mobile/views/components/note-sub.vue:
|
mobile/views/components/note-sub.vue:
|
||||||
admin: "admin"
|
admin: "admin"
|
||||||
bot: "bot"
|
bot: "bot"
|
||||||
cat: "cat"
|
cat: "chat"
|
||||||
mobile/views/components/notes.vue:
|
mobile/views/components/notes.vue:
|
||||||
failed: "読み込みに失敗しました。"
|
failed: "Échec du chargement."
|
||||||
retry: "リトライ"
|
retry: "Réessayer"
|
||||||
mobile/views/components/notifications.vue:
|
mobile/views/components/notifications.vue:
|
||||||
more: "Plus"
|
more: "Plus"
|
||||||
empty: "Pas de notifications"
|
empty: "Pas de notifications"
|
||||||
mobile/views/components/post-form.vue:
|
mobile/views/components/post-form.vue:
|
||||||
add-visible-user: "ユーザーを追加"
|
add-visible-user: "Ajouter un utilisateur"
|
||||||
submit: "Poster"
|
submit: "Poster"
|
||||||
reply: "返信"
|
reply: "Répondre"
|
||||||
renote: "Renote"
|
renote: "Republier"
|
||||||
quote-placeholder: "この投稿を引用... (オプション)"
|
quote-placeholder: "Citer ce billet ... (Facultatif)"
|
||||||
reply-placeholder: "Répondre à cette note"
|
reply-placeholder: "Répondre à cette note"
|
||||||
cw-placeholder: "内容への注釈 (オプション)"
|
cw-placeholder: "内容への注釈 (オプション)"
|
||||||
location-alert: "お使いの端末は位置情報に対応していません"
|
location-alert: "Votre appareil ne prend pas en charge les services de localisation"
|
||||||
error: "エラー"
|
error: "Erreur"
|
||||||
username-prompt: "ユーザー名を入力してください"
|
username-prompt: "Saisir un nom d'utilisateur"
|
||||||
mobile/views/components/sub-note-content.vue:
|
mobile/views/components/sub-note-content.vue:
|
||||||
private: "この投稿は非公開です"
|
private: "cette publication est privée"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "cette publication a été supprimée"
|
||||||
media-count: "{}つのメディア"
|
media-count: "{} médias attachés"
|
||||||
poll: "Sondage"
|
poll: "Sondage"
|
||||||
mobile/views/components/timeline.vue:
|
mobile/views/components/timeline.vue:
|
||||||
empty: "Pas de notes"
|
empty: "Pas de notes"
|
||||||
load-more: "Afficher plus"
|
load-more: "Afficher plus"
|
||||||
mobile/views/components/ui.nav.vue:
|
mobile/views/components/ui.nav.vue:
|
||||||
timeline: "タイムライン"
|
timeline: "Fil d'actualité"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
messaging: "Messages"
|
messaging: "Messages"
|
||||||
follow-requests: "フォロー申請"
|
follow-requests: "Demandes d'abonnement"
|
||||||
search: "Rechercher"
|
search: "Rechercher"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
favorites: "お気に入り"
|
favorites: "Favoris"
|
||||||
user-lists: "リスト"
|
user-lists: "Listes"
|
||||||
widgets: "ウィジェット"
|
widgets: "Modules"
|
||||||
game: "ゲーム"
|
game: "Jeux"
|
||||||
darkmode: "ダークモード"
|
darkmode: "Mode nuit"
|
||||||
settings: "Réglages"
|
settings: "Réglages"
|
||||||
about: "À propose de Misskey"
|
about: "À propose de Misskey"
|
||||||
mobile/views/components/user-timeline.vue:
|
mobile/views/components/user-timeline.vue:
|
||||||
@@ -753,29 +762,29 @@ mobile/views/components/users-list.vue:
|
|||||||
known: "Vous connaissez"
|
known: "Vous connaissez"
|
||||||
load-more: "Afficher plus"
|
load-more: "Afficher plus"
|
||||||
mobile/views/pages/favorites.vue:
|
mobile/views/pages/favorites.vue:
|
||||||
title: "お気に入り"
|
title: "Favoris"
|
||||||
mobile/views/pages/user-lists.vue:
|
mobile/views/pages/user-lists.vue:
|
||||||
title: "リスト"
|
title: "Listes"
|
||||||
enter-list-name: "リスト名を入力してください"
|
enter-list-name: "Nom de la liste"
|
||||||
mobile/views/pages/drive.vue:
|
mobile/views/pages/drive.vue:
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
more: "もっと見る"
|
more: "Afficher plus ..."
|
||||||
mobile/views/pages/followers.vue:
|
mobile/views/pages/followers.vue:
|
||||||
followers-of: "Abonnés de {}"
|
followers-of: "Abonnés de {}"
|
||||||
mobile/views/pages/following.vue:
|
mobile/views/pages/following.vue:
|
||||||
following-of: "Abonnements de {}"
|
following-of: "Abonnements de {}"
|
||||||
mobile/views/pages/home.vue:
|
mobile/views/pages/home.vue:
|
||||||
home: "ホーム"
|
home: "Accueil"
|
||||||
local: "ローカル"
|
local: "Local"
|
||||||
global: "グローバル"
|
global: "Global"
|
||||||
mobile/views/pages/messaging.vue:
|
mobile/views/pages/messaging.vue:
|
||||||
messaging: "Messagerie"
|
messaging: "Messagerie"
|
||||||
mobile/views/pages/messaging-room.vue:
|
mobile/views/pages/messaging-room.vue:
|
||||||
messaging: "Messagerie"
|
messaging: "Messagerie"
|
||||||
mobile/views/pages/received-follow-requests.vue:
|
mobile/views/pages/received-follow-requests.vue:
|
||||||
title: "フォロー申請"
|
title: "Demandes d'abonnement"
|
||||||
accept: "承認"
|
accept: "Approuver"
|
||||||
reject: "拒否"
|
reject: "Refuser"
|
||||||
mobile/views/pages/note.vue:
|
mobile/views/pages/note.vue:
|
||||||
title: "Post"
|
title: "Post"
|
||||||
prev: "Note précedante"
|
prev: "Note précedante"
|
||||||
@@ -784,19 +793,19 @@ mobile/views/pages/notifications.vue:
|
|||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
read-all: "Êtes vous sûr de vouloir marqués toutes les notifications non-lus en tant que lus?"
|
read-all: "Êtes vous sûr de vouloir marqués toutes les notifications non-lus en tant que lus?"
|
||||||
mobile/views/pages/settings/settings.profile.vue:
|
mobile/views/pages/settings/settings.profile.vue:
|
||||||
title: "プロフィール"
|
title: "Profil"
|
||||||
name: "名前"
|
name: "Nom"
|
||||||
account: "アカウント"
|
account: "Compte"
|
||||||
location: "場所"
|
location: "Lieu"
|
||||||
description: "自己紹介"
|
description: "Description"
|
||||||
birthday: "誕生日"
|
birthday: "Date de naissance"
|
||||||
avatar: "アイコン"
|
avatar: "Avatar"
|
||||||
banner: "バナー"
|
banner: "Bannière"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "Ce compte est un Bot"
|
||||||
save: "保存"
|
save: "Mettre à jour le profil"
|
||||||
saved: "プロフィールを保存しました"
|
saved: "Profil mis à jour avec succès"
|
||||||
uploading: "アップロード中"
|
uploading: "En cours d'envoi"
|
||||||
upload-failed: "アップロードに失敗しました"
|
upload-failed: "Échec de l'envoi"
|
||||||
mobile/views/pages/search.vue:
|
mobile/views/pages/search.vue:
|
||||||
search: "Chercher"
|
search: "Chercher"
|
||||||
empty: "Aucun message trouvé pour '{}' "
|
empty: "Aucun message trouvé pour '{}' "
|
||||||
@@ -804,39 +813,39 @@ mobile/views/pages/selectdrive.vue:
|
|||||||
select-file: "Choisissez un fichier"
|
select-file: "Choisissez un fichier"
|
||||||
mobile/views/pages/settings.vue:
|
mobile/views/pages/settings.vue:
|
||||||
signed-in-as: "Connecté en tant que {}"
|
signed-in-as: "Connecté en tant que {}"
|
||||||
lang: "言語"
|
lang: "Langue"
|
||||||
lang-tip: "変更はページの再読み込み後に反映されます。"
|
lang-tip: "Le rechargement de la page est requis afin d'appliquer les modifications."
|
||||||
recommended: "推奨"
|
recommended: "Recommandé"
|
||||||
auto: "自動"
|
auto: "Automatique"
|
||||||
specify-language: "言語を指定"
|
specify-language: "Spécifier la langue"
|
||||||
design: "デザインと表示"
|
design: "Affichage et design"
|
||||||
dark-mode: "ダークモード"
|
dark-mode: "Mode nuit"
|
||||||
i-am-under-limited-internet: "私は通信を制限されている"
|
i-am-under-limited-internet: "J'ai un accès Internet limité"
|
||||||
circle-icons: "円形のアイコンを使用"
|
circle-icons: "Utiliser des icônes circulaires"
|
||||||
timeline: "タイムライン"
|
timeline: "Fil d'actualité"
|
||||||
show-reply-target: "リプライ先を表示する"
|
show-reply-target: "リプライ先を表示する"
|
||||||
show-my-renotes: "自分の行ったRenoteを表示する"
|
show-my-renotes: "Afficher mes republications"
|
||||||
show-renoted-my-notes: "Renoteされた自分の投稿を表示する"
|
show-renoted-my-notes: "Renoteされた自分の投稿を表示する"
|
||||||
post-style: "投稿の表示スタイル"
|
post-style: "Style de la publication"
|
||||||
post-style-standard: "標準"
|
post-style-standard: "Standard"
|
||||||
post-style-smart: "スマート"
|
post-style-smart: "Intelligent"
|
||||||
behavior: "動作"
|
behavior: "Comportement"
|
||||||
fetch-on-scroll: "スクロールで自動読み込み"
|
fetch-on-scroll: "Chargement lors du défilement"
|
||||||
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
||||||
load-raw-images: "添付された画像を高画質で表示する"
|
load-raw-images: "Afficher les photos jointes en haute qualité"
|
||||||
load-remote-media: "リモートサーバーのメディアを表示する"
|
load-remote-media: "Afficher les médias sur le serveur distant"
|
||||||
twitter: "Twitter連携"
|
twitter: "Intégration à Twitter"
|
||||||
twitter-connect: "Twitterアカウントに接続する"
|
twitter-connect: "Se connecter à votre compte Twitter"
|
||||||
twitter-reconnect: "再接続する"
|
twitter-reconnect: "Reconnecter"
|
||||||
twitter-disconnect: "切断する"
|
twitter-disconnect: "Déconnexion"
|
||||||
update: "Misskey Update"
|
update: "Mise à jour de Misskey"
|
||||||
version: "バージョン:"
|
version: "Version :"
|
||||||
latest-version: "最新のバージョン:"
|
latest-version: "Dernière version :"
|
||||||
update-checking: "アップデートを確認中"
|
update-checking: "Recherche de mises à jour"
|
||||||
check-for-updates: "アップデートを確認"
|
check-for-updates: "Fréquence de vérification"
|
||||||
no-updates: "利用可能な更新はありません"
|
no-updates: "Aucune mise à jour disponible"
|
||||||
no-updates-desc: "お使いのMisskeyは最新です。"
|
no-updates-desc: "Votre Misskey est à jour."
|
||||||
update-available: "新しいバージョンが利用可能です"
|
update-available: "Nouvelle version disponible !"
|
||||||
update-available-desc: "ページを再度読み込みすると更新が適用されます。"
|
update-available-desc: "ページを再度読み込みすると更新が適用されます。"
|
||||||
settings: "Réglages"
|
settings: "Réglages"
|
||||||
signout: "Déconnexion"
|
signout: "Déconnexion"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -85,8 +86,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
|
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
@@ -244,6 +250,10 @@ common/views/widgets/photo-stream.vue:
|
|||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
|
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ meta:
|
|||||||
common:
|
common:
|
||||||
misskey: "Planeta Fediwersum"
|
misskey: "Planeta Fediwersum"
|
||||||
about-title: "⭐ Fediwersum"
|
about-title: "⭐ Fediwersum"
|
||||||
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
about: "Dziękujemy za znalezienie Misskey. Misskey jest <b>zdecentralizowaną platformą mikroblogową</b> powstałą na Ziemi. Ponieważ działa ona w Fediwersum (uniwersum, w którego skład wchodzi wiele sieci społecznościowych), jest ona połączona z innymi platformami społecznościowymi. Spróbujesz odpocząć od zatłoczoneo miasta i zanurzyć się w nowym Internecie?"
|
||||||
time:
|
time:
|
||||||
unknown: "nieznany"
|
unknown: "nieznany"
|
||||||
future: "w przyszłości"
|
future: "w przyszłości"
|
||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "Notatki"
|
memo: "Notatki"
|
||||||
trends: "Na czasie"
|
trends: "Na czasie"
|
||||||
photo-stream: "Photostream"
|
photo-stream: "Photostream"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "Pokaz slajdów"
|
slideshow: "Pokaz slajdów"
|
||||||
version: "Wersja"
|
version: "Wersja"
|
||||||
broadcast: "Transmisja"
|
broadcast: "Transmisja"
|
||||||
@@ -70,16 +71,21 @@ common:
|
|||||||
nav: "Nawigacja"
|
nav: "Nawigacja"
|
||||||
tips: "Wskazówki"
|
tips: "Wskazówki"
|
||||||
deck:
|
deck:
|
||||||
widgets: "ウィジェット"
|
widgets: "Widżety"
|
||||||
home: "ホーム"
|
home: "Strona główna"
|
||||||
local: "ローカル"
|
local: "Lokalne"
|
||||||
global: "グローバル"
|
global: "Globalne"
|
||||||
notifications: "通知"
|
notifications: "Powiadomienia"
|
||||||
list: "リスト"
|
list: "Listy"
|
||||||
swap-left: "左に移動"
|
swap-left: "Przesuń w lewo"
|
||||||
swap-right: "右に移動"
|
swap-right: "Przesuń w prawo"
|
||||||
remove: "カラムを削除"
|
swap-up: "Przenieś w górę"
|
||||||
add-column: "カラムを追加"
|
swap-down: "Przenieś w dół"
|
||||||
|
remove: "Usuń"
|
||||||
|
add-column: "Dodaj kolumnę"
|
||||||
|
rename: "Zmień nazwę"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "Nie udało się połączyć z serwerem"
|
title: "Nie udało się połączyć z serwerem"
|
||||||
description: "Wystąpił problem z Twoim połączeniem z Internetem, lub z serwerem. {Spróbuj ponownie} wkrótce."
|
description: "Wystąpił problem z Twoim połączeniem z Internetem, lub z serwerem. {Spróbuj ponownie} wkrótce."
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "Photostream"
|
title: "Photostream"
|
||||||
no-photos: "Brak zdjęć"
|
no-photos: "Brak zdjęć"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "Informacje o serwerze"
|
title: "Informacje o serwerze"
|
||||||
toggle: "Przełącz widok"
|
toggle: "Przełącz widok"
|
||||||
@@ -301,7 +310,7 @@ desktop/views/components/drive.vue:
|
|||||||
upload: "Wyślij plik"
|
upload: "Wyślij plik"
|
||||||
url-upload: "Wyślij z adresu URL"
|
url-upload: "Wyślij z adresu URL"
|
||||||
desktop/views/components/follow-button.vue:
|
desktop/views/components/follow-button.vue:
|
||||||
following: "フォロー中"
|
following: "Śledzisz"
|
||||||
follow: "Śledź"
|
follow: "Śledź"
|
||||||
request-pending: "Oczekiwanie na pozwolenie"
|
request-pending: "Oczekiwanie na pozwolenie"
|
||||||
follow-request: "Poproś o śledzenie"
|
follow-request: "Poproś o śledzenie"
|
||||||
@@ -534,7 +543,7 @@ desktop/views/components/ui.header.account.vue:
|
|||||||
dark: "Sprowadź ciemność"
|
dark: "Sprowadź ciemność"
|
||||||
desktop/views/components/ui.header.nav.vue:
|
desktop/views/components/ui.header.nav.vue:
|
||||||
home: "Strona główna"
|
home: "Strona główna"
|
||||||
deck: "デッキ"
|
deck: "Talia"
|
||||||
messaging: "Wiadomości"
|
messaging: "Wiadomości"
|
||||||
game: "Gra"
|
game: "Gra"
|
||||||
desktop/views/components/ui.header.notifications.vue:
|
desktop/views/components/ui.header.notifications.vue:
|
||||||
@@ -673,7 +682,7 @@ mobile/views/components/drive.file-detail.vue:
|
|||||||
hash: "Hash (md5)"
|
hash: "Hash (md5)"
|
||||||
exif: "EXIF"
|
exif: "EXIF"
|
||||||
mobile/views/components/follow-button.vue:
|
mobile/views/components/follow-button.vue:
|
||||||
following: "フォロー中"
|
following: "Śledzisz"
|
||||||
follow: "Śledź"
|
follow: "Śledź"
|
||||||
request-pending: "Oczekiwanie na pozwolenie"
|
request-pending: "Oczekiwanie na pozwolenie"
|
||||||
follow-request: "Poproś o śledzenie"
|
follow-request: "Poproś o śledzenie"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ common:
|
|||||||
memo: "メモ"
|
memo: "メモ"
|
||||||
trends: "トレンド"
|
trends: "トレンド"
|
||||||
photo-stream: "フォトストリーム"
|
photo-stream: "フォトストリーム"
|
||||||
|
posts-monitor: "投稿チャート"
|
||||||
slideshow: "スライドショー"
|
slideshow: "スライドショー"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
broadcast: "ブロードキャスト"
|
broadcast: "ブロードキャスト"
|
||||||
@@ -78,8 +79,13 @@ common:
|
|||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動"
|
||||||
|
swap-up: "上に移動"
|
||||||
|
swap-down: "下に移動"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加"
|
||||||
|
rename: "名前を変更"
|
||||||
|
stack-left: "左に重ねる"
|
||||||
|
pop-right: "右に出す"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
title: "サーバーに接続できません"
|
title: "サーバーに接続できません"
|
||||||
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
description: "インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから{再度お試し}ください。"
|
||||||
@@ -215,6 +221,9 @@ common/views/widgets/donation.vue:
|
|||||||
common/views/widgets/photo-stream.vue:
|
common/views/widgets/photo-stream.vue:
|
||||||
title: "フォトストリーム"
|
title: "フォトストリーム"
|
||||||
no-photos: "写真はありません"
|
no-photos: "写真はありません"
|
||||||
|
common/views/widgets/posts-monitor.vue:
|
||||||
|
title: "投稿チャート"
|
||||||
|
toggle: "表示を切り替え"
|
||||||
common/views/widgets/server.vue:
|
common/views/widgets/server.vue:
|
||||||
title: "サーバー情報"
|
title: "サーバー情報"
|
||||||
toggle: "表示を切り替え"
|
toggle: "表示を切り替え"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "2.27.3",
|
"version": "2.34.3",
|
||||||
"clientVersion": "1.0.6188",
|
"clientVersion": "1.0.6328",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -152,7 +152,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.0.8",
|
"mongodb": "3.0.10",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.10.0",
|
"nan": "2.10.0",
|
||||||
@@ -218,6 +218,6 @@
|
|||||||
"webpack-cli": "2.1.4",
|
"webpack-cli": "2.1.4",
|
||||||
"websocket": "1.0.26",
|
"websocket": "1.0.26",
|
||||||
"ws": "5.2.0",
|
"ws": "5.2.0",
|
||||||
"xev": "2.0.0"
|
"xev": "2.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ html
|
|||||||
| JavaScriptを有効にしてください
|
| JavaScriptを有効にしてください
|
||||||
br
|
br
|
||||||
| Please turn on your JavaScript
|
| Please turn on your JavaScript
|
||||||
div#ini: p
|
div#ini.
|
||||||
span .
|
<svg viewBox="0 0 50 50">
|
||||||
span .
|
<path fill=#{themeColor} d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z" />
|
||||||
span .
|
</svg>
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ import StreamManager from './stream-manager';
|
|||||||
import MiOS from '../../../mios';
|
import MiOS from '../../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server stream connection
|
* Notes stats stream connection
|
||||||
*/
|
*/
|
||||||
export class ServerStream extends Stream {
|
export class NotesStatsStream extends Stream {
|
||||||
constructor(os: MiOS) {
|
constructor(os: MiOS) {
|
||||||
super(os, 'server');
|
super(os, 'notes-stats');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ServerStreamManager extends StreamManager<ServerStream> {
|
export class NotesStatsStreamManager extends StreamManager<NotesStatsStream> {
|
||||||
private os: MiOS;
|
private os: MiOS;
|
||||||
|
|
||||||
constructor(os: MiOS) {
|
constructor(os: MiOS) {
|
||||||
@@ -22,7 +22,7 @@ export class ServerStreamManager extends StreamManager<ServerStream> {
|
|||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new ServerStream(this.os);
|
this.connection = new NotesStatsStream(this.os);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
30
src/client/app/common/scripts/streaming/server-stats.ts
Normal file
30
src/client/app/common/scripts/streaming/server-stats.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import Stream from './stream';
|
||||||
|
import StreamManager from './stream-manager';
|
||||||
|
import MiOS from '../../../mios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server stats stream connection
|
||||||
|
*/
|
||||||
|
export class ServerStatsStream extends Stream {
|
||||||
|
constructor(os: MiOS) {
|
||||||
|
super(os, 'server-stats');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ServerStatsStreamManager extends StreamManager<ServerStatsStream> {
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
|
constructor(os: MiOS) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.os = os;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConnection() {
|
||||||
|
if (this.connection == null) {
|
||||||
|
this.connection = new ServerStatsStream(this.os);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import Vue from 'vue';
|
|||||||
|
|
||||||
import analogClock from './analog-clock.vue';
|
import analogClock from './analog-clock.vue';
|
||||||
import menu from './menu.vue';
|
import menu from './menu.vue';
|
||||||
|
import noteHeader from './note-header.vue';
|
||||||
import signin from './signin.vue';
|
import signin from './signin.vue';
|
||||||
import signup from './signup.vue';
|
import signup from './signup.vue';
|
||||||
import forkit from './forkit.vue';
|
import forkit from './forkit.vue';
|
||||||
@@ -31,6 +32,7 @@ import welcomeTimeline from './welcome-timeline.vue';
|
|||||||
|
|
||||||
Vue.component('mk-analog-clock', analogClock);
|
Vue.component('mk-analog-clock', analogClock);
|
||||||
Vue.component('mk-menu', menu);
|
Vue.component('mk-menu', menu);
|
||||||
|
Vue.component('mk-note-header', noteHeader);
|
||||||
Vue.component('mk-signin', signin);
|
Vue.component('mk-signin', signin);
|
||||||
Vue.component('mk-signup', signup);
|
Vue.component('mk-signup', signup);
|
||||||
Vue.component('mk-forkit', forkit);
|
Vue.component('mk-forkit', forkit);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-menu">
|
<div class="mk-menu">
|
||||||
<div class="backdrop" ref="backdrop" @click="close"></div>
|
<div class="backdrop" ref="backdrop" @click="close"></div>
|
||||||
<div class="popover" :class="{ compact }" ref="popover">
|
<div class="popover" :class="{ hukidasi }" ref="popover">
|
||||||
<template v-for="item in items">
|
<template v-for="item in items">
|
||||||
<div v-if="item == null"></div>
|
<div v-if="item === null"></div>
|
||||||
<button v-else @click="clicked(item.onClick)" v-html="item.content"></button>
|
<button v-if="item" @click="clicked(item.action)" v-html="item.icon ? item.icon + ' ' + item.text : item.text"></button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,6 +16,11 @@ import * as anime from 'animejs';
|
|||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['source', 'compact', 'items'],
|
props: ['source', 'compact', 'items'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hukidasi: !this.compact
|
||||||
|
};
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const popover = this.$refs.popover as any;
|
const popover = this.$refs.popover as any;
|
||||||
@@ -24,18 +29,34 @@ export default Vue.extend({
|
|||||||
const width = popover.offsetWidth;
|
const width = popover.offsetWidth;
|
||||||
const height = popover.offsetHeight;
|
const height = popover.offsetHeight;
|
||||||
|
|
||||||
|
let left;
|
||||||
|
let top;
|
||||||
|
|
||||||
if (this.compact) {
|
if (this.compact) {
|
||||||
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
||||||
const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2);
|
const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2);
|
||||||
popover.style.left = (x - (width / 2)) + 'px';
|
left = (x - (width / 2));
|
||||||
popover.style.top = (y - (height / 2)) + 'px';
|
top = (y - (height / 2));
|
||||||
} else {
|
} else {
|
||||||
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
||||||
const y = rect.top + window.pageYOffset + this.source.offsetHeight;
|
const y = rect.top + window.pageYOffset + this.source.offsetHeight;
|
||||||
popover.style.left = (x - (width / 2)) + 'px';
|
left = (x - (width / 2));
|
||||||
popover.style.top = y + 'px';
|
top = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (left + width > window.innerWidth) {
|
||||||
|
left = window.innerWidth - width;
|
||||||
|
this.hukidasi = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top + height > window.innerHeight) {
|
||||||
|
top = window.innerHeight - height;
|
||||||
|
this.hukidasi = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
popover.style.left = left + 'px';
|
||||||
|
popover.style.top = top + 'px';
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.backdrop,
|
targets: this.$refs.backdrop,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
@@ -113,7 +134,7 @@ $border-color = rgba(27, 31, 35, 0.15)
|
|||||||
|
|
||||||
$balloon-size = 16px
|
$balloon-size = 16px
|
||||||
|
|
||||||
&:not(.compact)
|
&.hukidasi
|
||||||
margin-top $balloon-size
|
margin-top $balloon-size
|
||||||
transform-origin center -($balloon-size)
|
transform-origin center -($balloon-size)
|
||||||
|
|
||||||
|
|||||||
117
src/client/app/common/views/components/note-header.vue
Normal file
117
src/client/app/common/views/components/note-header.vue
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<header class="bvonvjxbwzaiskogyhbwgyxvcgserpmu">
|
||||||
|
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/>
|
||||||
|
<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
|
||||||
|
<span class="is-admin" v-if="note.user.isAdmin">admin</span>
|
||||||
|
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
||||||
|
<span class="is-cat" v-if="note.user.isCat">cat</span>
|
||||||
|
<span class="username"><mk-acct :user="note.user"/></span>
|
||||||
|
<div class="info">
|
||||||
|
<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span>
|
||||||
|
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
||||||
|
<router-link class="created-at" :to="note | notePage">
|
||||||
|
<mk-time :time="note.createdAt"/>
|
||||||
|
</router-link>
|
||||||
|
<span class="visibility" v-if="note.visibility != 'public'">
|
||||||
|
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
||||||
|
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
||||||
|
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
||||||
|
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mini: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
@import '~const.styl'
|
||||||
|
|
||||||
|
root(isDark)
|
||||||
|
display flex
|
||||||
|
align-items baseline
|
||||||
|
white-space nowrap
|
||||||
|
|
||||||
|
> .avatar
|
||||||
|
flex-shrink 0
|
||||||
|
margin-right 8px
|
||||||
|
width 20px
|
||||||
|
height 20px
|
||||||
|
border-radius 100%
|
||||||
|
|
||||||
|
> .name
|
||||||
|
display block
|
||||||
|
margin 0 .5em 0 0
|
||||||
|
padding 0
|
||||||
|
overflow hidden
|
||||||
|
color isDark ? #fff : #627079
|
||||||
|
font-size 1em
|
||||||
|
font-weight bold
|
||||||
|
text-decoration none
|
||||||
|
text-overflow ellipsis
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
text-decoration underline
|
||||||
|
|
||||||
|
> .is-admin
|
||||||
|
> .is-bot
|
||||||
|
> .is-cat
|
||||||
|
align-self center
|
||||||
|
margin 0 .5em 0 0
|
||||||
|
padding 1px 6px
|
||||||
|
font-size 80%
|
||||||
|
color isDark ? #758188 : #aaa
|
||||||
|
border solid 1px isDark ? #57616f : #ddd
|
||||||
|
border-radius 3px
|
||||||
|
|
||||||
|
&.is-admin
|
||||||
|
border-color isDark ? #d42c41 : #f56a7b
|
||||||
|
color isDark ? #d42c41 : #f56a7b
|
||||||
|
|
||||||
|
> .username
|
||||||
|
margin 0 .5em 0 0
|
||||||
|
overflow hidden
|
||||||
|
text-overflow ellipsis
|
||||||
|
color isDark ? #606984 : #ccc
|
||||||
|
|
||||||
|
> .info
|
||||||
|
margin-left auto
|
||||||
|
font-size 0.9em
|
||||||
|
|
||||||
|
> *
|
||||||
|
color isDark ? #606984 : #c0c0c0
|
||||||
|
|
||||||
|
> .mobile
|
||||||
|
margin-right 8px
|
||||||
|
|
||||||
|
> .app
|
||||||
|
margin-right 8px
|
||||||
|
padding-right 8px
|
||||||
|
border-right solid 1px isDark ? #1c2023 : #eaeaea
|
||||||
|
|
||||||
|
> .visibility
|
||||||
|
margin-left 8px
|
||||||
|
|
||||||
|
.bvonvjxbwzaiskogyhbwgyxvcgserpmu[data-darkmode]
|
||||||
|
root(true)
|
||||||
|
|
||||||
|
.bvonvjxbwzaiskogyhbwgyxvcgserpmu:not([data-darkmode])
|
||||||
|
root(false)
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -13,23 +13,23 @@ export default Vue.extend({
|
|||||||
items() {
|
items() {
|
||||||
const items = [];
|
const items = [];
|
||||||
items.push({
|
items.push({
|
||||||
content: '%i18n:@favorite%',
|
text: '%i18n:@favorite%',
|
||||||
onClick: this.favorite
|
action: this.favorite
|
||||||
});
|
});
|
||||||
if (this.note.userId == this.$store.state.i.id) {
|
if (this.note.userId == this.$store.state.i.id) {
|
||||||
items.push({
|
items.push({
|
||||||
content: '%i18n:@pin%',
|
text: '%i18n:@pin%',
|
||||||
onClick: this.pin
|
action: this.pin
|
||||||
});
|
});
|
||||||
items.push({
|
items.push({
|
||||||
content: '%i18n:@delete%',
|
text: '%i18n:@delete%',
|
||||||
onClick: this.del
|
action: this.del
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.note.uri) {
|
if (this.note.uri) {
|
||||||
items.push({
|
items.push({
|
||||||
content: '%i18n:@remote%',
|
text: '%i18n:@remote%',
|
||||||
onClick: () => {
|
action: () => {
|
||||||
window.open(this.note.uri, '_blank');
|
window.open(this.note.uri, '_blank');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default Vue.extend({
|
|||||||
created() {
|
created() {
|
||||||
if (this.mode == 'relative' || this.mode == 'detail') {
|
if (this.mode == 'relative' || this.mode == 'detail') {
|
||||||
this.tick();
|
this.tick();
|
||||||
this.tickId = setInterval(this.tick, 1000);
|
this.tickId = setInterval(this.tick, 10000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import wAnalogClock from './analog-clock.vue';
|
|||||||
import wVersion from './version.vue';
|
import wVersion from './version.vue';
|
||||||
import wRss from './rss.vue';
|
import wRss from './rss.vue';
|
||||||
import wServer from './server.vue';
|
import wServer from './server.vue';
|
||||||
|
import wPostsMonitor from './posts-monitor.vue';
|
||||||
import wMemo from './memo.vue';
|
import wMemo from './memo.vue';
|
||||||
import wBroadcast from './broadcast.vue';
|
import wBroadcast from './broadcast.vue';
|
||||||
import wCalendar from './calendar.vue';
|
import wCalendar from './calendar.vue';
|
||||||
@@ -22,6 +23,7 @@ Vue.component('mkw-tips', wTips);
|
|||||||
Vue.component('mkw-donation', wDonation);
|
Vue.component('mkw-donation', wDonation);
|
||||||
Vue.component('mkw-broadcast', wBroadcast);
|
Vue.component('mkw-broadcast', wBroadcast);
|
||||||
Vue.component('mkw-server', wServer);
|
Vue.component('mkw-server', wServer);
|
||||||
|
Vue.component('mkw-posts-monitor', wPostsMonitor);
|
||||||
Vue.component('mkw-memo', wMemo);
|
Vue.component('mkw-memo', wMemo);
|
||||||
Vue.component('mkw-rss', wRss);
|
Vue.component('mkw-rss', wRss);
|
||||||
Vue.component('mkw-version', wVersion);
|
Vue.component('mkw-version', wVersion);
|
||||||
|
|||||||
211
src/client/app/common/views/widgets/posts-monitor.vue
Normal file
211
src/client/app/common/views/widgets/posts-monitor.vue
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mkw-posts-monitor">
|
||||||
|
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
|
||||||
|
<template slot="header">%fa:chart-line%%i18n:@title%</template>
|
||||||
|
<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
|
||||||
|
|
||||||
|
<div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }" :data-darkmode="$store.state.device.darkmode">
|
||||||
|
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2">
|
||||||
|
<defs>
|
||||||
|
<linearGradient :id="localGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||||
|
<stop offset="0%" stop-color="hsl(200, 80%, 70%)"></stop>
|
||||||
|
<stop offset="100%" stop-color="hsl(90, 80%, 70%)"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<mask :id="localMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
|
||||||
|
<polygon
|
||||||
|
:points="localPolygonPoints"
|
||||||
|
fill="#fff"
|
||||||
|
fill-opacity="0.5"/>
|
||||||
|
<polyline
|
||||||
|
:points="localPolylinePoints"
|
||||||
|
fill="none"
|
||||||
|
stroke="#fff"
|
||||||
|
stroke-width="1"/>
|
||||||
|
<circle
|
||||||
|
:cx="localHeadX"
|
||||||
|
:cy="localHeadY"
|
||||||
|
r="1.5"
|
||||||
|
fill="#fff"/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
x="-2" y="-2"
|
||||||
|
:width="viewBoxX + 4" :height="viewBoxY + 4"
|
||||||
|
:style="`stroke: none; fill: url(#${ localGradientId }); mask: url(#${ localMaskId })`"/>
|
||||||
|
<text x="1" y="5">Local</text>
|
||||||
|
</svg>
|
||||||
|
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 1">
|
||||||
|
<defs>
|
||||||
|
<linearGradient :id="fediGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||||
|
<stop offset="0%" stop-color="hsl(200, 80%, 70%)"></stop>
|
||||||
|
<stop offset="100%" stop-color="hsl(90, 80%, 70%)"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<mask :id="fediMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
|
||||||
|
<polygon
|
||||||
|
:points="fediPolygonPoints"
|
||||||
|
fill="#fff"
|
||||||
|
fill-opacity="0.5"/>
|
||||||
|
<polyline
|
||||||
|
:points="fediPolylinePoints"
|
||||||
|
fill="none"
|
||||||
|
stroke="#fff"
|
||||||
|
stroke-width="1"/>
|
||||||
|
<circle
|
||||||
|
:cx="fediHeadX"
|
||||||
|
:cy="fediHeadY"
|
||||||
|
r="1.5"
|
||||||
|
fill="#fff"/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
x="-2" y="-2"
|
||||||
|
:width="viewBoxX + 4" :height="viewBoxY + 4"
|
||||||
|
:style="`stroke: none; fill: url(#${ fediGradientId }); mask: url(#${ fediMaskId })`"/>
|
||||||
|
<text x="1" y="5">Fedi</text>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</mk-widget-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import define from '../../../common/define-widget';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
|
export default define({
|
||||||
|
name: 'server',
|
||||||
|
props: () => ({
|
||||||
|
design: 0,
|
||||||
|
view: 0
|
||||||
|
})
|
||||||
|
}).extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
connection: null,
|
||||||
|
connectionId: null,
|
||||||
|
viewBoxY: 30,
|
||||||
|
stats: [],
|
||||||
|
fediGradientId: uuid(),
|
||||||
|
fediMaskId: uuid(),
|
||||||
|
localGradientId: uuid(),
|
||||||
|
localMaskId: uuid(),
|
||||||
|
fediPolylinePoints: '',
|
||||||
|
localPolylinePoints: '',
|
||||||
|
fediPolygonPoints: '',
|
||||||
|
localPolygonPoints: '',
|
||||||
|
fediHeadX: null,
|
||||||
|
fediHeadY: null,
|
||||||
|
localHeadX: null,
|
||||||
|
localHeadY: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
viewBoxX(): number {
|
||||||
|
return this.props.view == 0 ? 50 : 100;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
viewBoxX() {
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.connection = (this as any).os.streams.notesStatsStream.getConnection();
|
||||||
|
this.connectionId = (this as any).os.streams.notesStatsStream.use();
|
||||||
|
|
||||||
|
this.connection.on('stats', this.onStats);
|
||||||
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
|
this.connection.send({
|
||||||
|
type: 'requestLog',
|
||||||
|
id: Math.random().toString()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.connection.off('stats', this.onStats);
|
||||||
|
this.connection.off('statsLog', this.onStatsLog);
|
||||||
|
(this as any).os.streams.notesStatsStream.dispose(this.connectionId);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
if (this.props.view == 2) {
|
||||||
|
this.props.view = 0;
|
||||||
|
} else {
|
||||||
|
this.props.view++;
|
||||||
|
}
|
||||||
|
this.save();
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
if (this.props.design == 2) {
|
||||||
|
this.props.design = 0;
|
||||||
|
} else {
|
||||||
|
this.props.design++;
|
||||||
|
}
|
||||||
|
this.save();
|
||||||
|
},
|
||||||
|
draw() {
|
||||||
|
const stats = this.props.view == 0 ? this.stats.slice(-50) : this.stats;
|
||||||
|
const fediPeak = Math.max.apply(null, stats.map(x => x.all)) || 1;
|
||||||
|
const localPeak = Math.max.apply(null, stats.map(x => x.local)) || 1;
|
||||||
|
|
||||||
|
const fediPolylinePoints = stats.map((s, i) => [this.viewBoxX - ((stats.length - 1) - i), (1 - (s.all / fediPeak)) * this.viewBoxY]);
|
||||||
|
const localPolylinePoints = stats.map((s, i) => [this.viewBoxX - ((stats.length - 1) - i), (1 - (s.local / localPeak)) * this.viewBoxY]);
|
||||||
|
this.fediPolylinePoints = fediPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||||
|
this.localPolylinePoints = localPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||||
|
|
||||||
|
this.fediPolygonPoints = `${this.viewBoxX - (stats.length - 1)},${ this.viewBoxY } ${ this.fediPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
||||||
|
this.localPolygonPoints = `${this.viewBoxX - (stats.length - 1)},${ this.viewBoxY } ${ this.localPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
||||||
|
|
||||||
|
this.fediHeadX = fediPolylinePoints[fediPolylinePoints.length - 1][0];
|
||||||
|
this.fediHeadY = fediPolylinePoints[fediPolylinePoints.length - 1][1];
|
||||||
|
this.localHeadX = localPolylinePoints[localPolylinePoints.length - 1][0];
|
||||||
|
this.localHeadY = localPolylinePoints[localPolylinePoints.length - 1][1];
|
||||||
|
},
|
||||||
|
onStats(stats) {
|
||||||
|
this.stats.push(stats);
|
||||||
|
if (this.stats.length > 100) this.stats.shift();
|
||||||
|
this.draw();
|
||||||
|
},
|
||||||
|
onStatsLog(statsLog) {
|
||||||
|
statsLog.forEach(stats => this.onStats(stats));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
root(isDark)
|
||||||
|
&.dual
|
||||||
|
> svg
|
||||||
|
width 50%
|
||||||
|
float left
|
||||||
|
|
||||||
|
&:first-child
|
||||||
|
padding-right 5px
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
padding-left 5px
|
||||||
|
|
||||||
|
> svg
|
||||||
|
display block
|
||||||
|
padding 10px
|
||||||
|
width 100%
|
||||||
|
|
||||||
|
> text
|
||||||
|
font-size 5px
|
||||||
|
fill isDark ? rgba(#fff, 0.55) : rgba(#000, 0.55)
|
||||||
|
|
||||||
|
> tspan
|
||||||
|
opacity 0.5
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
clear both
|
||||||
|
|
||||||
|
.qpdmibaztplkylerhdbllwcokyrfxeyj[data-darkmode]
|
||||||
|
root(true)
|
||||||
|
|
||||||
|
.qpdmibaztplkylerhdbllwcokyrfxeyj:not([data-darkmode])
|
||||||
|
root(false)
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="cpu-memory">
|
<div class="cpu-memory">
|
||||||
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none">
|
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
|
<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||||
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
||||||
@@ -16,15 +16,20 @@
|
|||||||
fill="none"
|
fill="none"
|
||||||
stroke="#fff"
|
stroke="#fff"
|
||||||
stroke-width="1"/>
|
stroke-width="1"/>
|
||||||
|
<circle
|
||||||
|
:cx="cpuHeadX"
|
||||||
|
:cy="cpuHeadY"
|
||||||
|
r="1.5"
|
||||||
|
fill="#fff"/>
|
||||||
</mask>
|
</mask>
|
||||||
</defs>
|
</defs>
|
||||||
<rect
|
<rect
|
||||||
x="-1" y="-1"
|
x="-2" y="-2"
|
||||||
:width="viewBoxX + 2" :height="viewBoxY + 2"
|
:width="viewBoxX + 4" :height="viewBoxY + 4"
|
||||||
:style="`stroke: none; fill: url(#${ cpuGradientId }); mask: url(#${ cpuMaskId })`"/>
|
:style="`stroke: none; fill: url(#${ cpuGradientId }); mask: url(#${ cpuMaskId })`"/>
|
||||||
<text x="1" y="5">CPU <tspan>{{ cpuP }}%</tspan></text>
|
<text x="1" y="5">CPU <tspan>{{ cpuP }}%</tspan></text>
|
||||||
</svg>
|
</svg>
|
||||||
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none">
|
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
|
<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||||
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
||||||
@@ -40,11 +45,16 @@
|
|||||||
fill="none"
|
fill="none"
|
||||||
stroke="#fff"
|
stroke="#fff"
|
||||||
stroke-width="1"/>
|
stroke-width="1"/>
|
||||||
|
<circle
|
||||||
|
:cx="memHeadX"
|
||||||
|
:cy="memHeadY"
|
||||||
|
r="1.5"
|
||||||
|
fill="#fff"/>
|
||||||
</mask>
|
</mask>
|
||||||
</defs>
|
</defs>
|
||||||
<rect
|
<rect
|
||||||
x="-1" y="-1"
|
x="-2" y="-2"
|
||||||
:width="viewBoxX + 2" :height="viewBoxY + 2"
|
:width="viewBoxX + 4" :height="viewBoxY + 4"
|
||||||
:style="`stroke: none; fill: url(#${ memGradientId }); mask: url(#${ memMaskId })`"/>
|
:style="`stroke: none; fill: url(#${ memGradientId }); mask: url(#${ memMaskId })`"/>
|
||||||
<text x="1" y="5">MEM <tspan>{{ memP }}%</tspan></text>
|
<text x="1" y="5">MEM <tspan>{{ memP }}%</tspan></text>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -70,15 +80,25 @@ export default Vue.extend({
|
|||||||
memPolylinePoints: '',
|
memPolylinePoints: '',
|
||||||
cpuPolygonPoints: '',
|
cpuPolygonPoints: '',
|
||||||
memPolygonPoints: '',
|
memPolygonPoints: '',
|
||||||
|
cpuHeadX: null,
|
||||||
|
cpuHeadY: null,
|
||||||
|
memHeadX: null,
|
||||||
|
memHeadY: null,
|
||||||
cpuP: '',
|
cpuP: '',
|
||||||
memP: ''
|
memP: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
|
this.connection.on('statsLog', this.onStatsLog);
|
||||||
|
this.connection.send({
|
||||||
|
type: 'requestLog',
|
||||||
|
id: Math.random().toString()
|
||||||
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('stats', this.onStats);
|
this.connection.off('stats', this.onStats);
|
||||||
|
this.connection.off('statsLog', this.onStatsLog);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onStats(stats) {
|
onStats(stats) {
|
||||||
@@ -86,14 +106,24 @@ export default Vue.extend({
|
|||||||
this.stats.push(stats);
|
this.stats.push(stats);
|
||||||
if (this.stats.length > 50) this.stats.shift();
|
if (this.stats.length > 50) this.stats.shift();
|
||||||
|
|
||||||
this.cpuPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - s.cpu_usage) * this.viewBoxY}`).join(' ');
|
const cpuPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - s.cpu_usage) * this.viewBoxY]);
|
||||||
this.memPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - (s.mem.used / s.mem.total)) * this.viewBoxY}`).join(' ');
|
const memPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - (s.mem.used / s.mem.total)) * this.viewBoxY]);
|
||||||
|
this.cpuPolylinePoints = cpuPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||||
|
this.memPolylinePoints = memPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||||
|
|
||||||
this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
||||||
this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
||||||
|
|
||||||
|
this.cpuHeadX = cpuPolylinePoints[cpuPolylinePoints.length - 1][0];
|
||||||
|
this.cpuHeadY = cpuPolylinePoints[cpuPolylinePoints.length - 1][1];
|
||||||
|
this.memHeadX = memPolylinePoints[memPolylinePoints.length - 1][0];
|
||||||
|
this.memHeadY = memPolylinePoints[memPolylinePoints.length - 1][1];
|
||||||
|
|
||||||
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
|
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
|
||||||
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
|
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
|
||||||
|
},
|
||||||
|
onStatsLog(statsLog) {
|
||||||
|
statsLog.forEach(stats => this.onStats(stats));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ export default define({
|
|||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection = (this as any).os.streams.serverStream.getConnection();
|
this.connection = (this as any).os.streams.serverStatsStream.getConnection();
|
||||||
this.connectionId = (this as any).os.streams.serverStream.use();
|
this.connectionId = (this as any).os.streams.serverStatsStream.use();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
(this as any).os.streams.serverStream.dispose(this.connectionId);
|
(this as any).os.streams.serverStatsStream.dispose(this.connectionId);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggle() {
|
toggle() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg viewBox="0 0 21 7" preserveAspectRatio="none">
|
<svg viewBox="0 0 21 7">
|
||||||
<rect v-for="record in data" class="day"
|
<rect v-for="record in data" class="day"
|
||||||
width="1" height="1"
|
width="1" height="1"
|
||||||
:x="record.x" :y="record.date.weekday"
|
:x="record.x" :y="record.date.weekday"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
style="pointer-events: none;"/>
|
style="pointer-events: none;"/>
|
||||||
<rect class="today"
|
<rect class="today"
|
||||||
width="1" height="1"
|
width="1" height="1"
|
||||||
:x="data[data.length - 1].x" :y="data[data.length - 1].date.weekday"
|
:x="data[0].x" :y="data[0].date.weekday"
|
||||||
rx="1" ry="1"
|
rx="1" ry="1"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke-width="0.1"
|
stroke-width="0.1"
|
||||||
@@ -33,7 +33,7 @@ export default Vue.extend({
|
|||||||
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
||||||
|
|
||||||
let x = 0;
|
let x = 0;
|
||||||
this.data.reverse().forEach(d => {
|
this.data.slice().reverse().forEach(d => {
|
||||||
d.x = x;
|
d.x = x;
|
||||||
d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay();
|
d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none" @mousedown.prevent="onMousedown">
|
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" @mousedown.prevent="onMousedown">
|
||||||
<title>%i18n:@total%<br/>%i18n:@notes%<br/>%i18n:@replies%<br/>%i18n:@renotes%</title>
|
<title>%i18n:@total%<br/>%i18n:@notes%<br/>%i18n:@replies%<br/>%i18n:@renotes%</title>
|
||||||
<polyline
|
<polyline
|
||||||
:points="pointsNote"
|
:points="pointsNote"
|
||||||
@@ -55,7 +55,6 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.data.reverse();
|
|
||||||
this.data.forEach(d => d.total = d.notes + d.replies + d.renotes);
|
this.data.forEach(d => d.total = d.notes + d.replies + d.renotes);
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
@@ -63,10 +62,11 @@ export default Vue.extend({
|
|||||||
render() {
|
render() {
|
||||||
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
||||||
if (peak != 0) {
|
if (peak != 0) {
|
||||||
this.pointsNote = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.notes / peak)) * this.viewBoxY}`).join(' ');
|
const data = this.data.slice().reverse();
|
||||||
this.pointsReply = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' ');
|
this.pointsNote = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.notes / peak)) * this.viewBoxY}`).join(' ');
|
||||||
this.pointsRenote = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' ');
|
this.pointsReply = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' ');
|
||||||
this.pointsTotal = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
|
this.pointsRenote = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' ');
|
||||||
|
this.pointsTotal = data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMousedown(e) {
|
onMousedown(e) {
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="menu">
|
<ul class="menu">
|
||||||
<li v-for="(item, i) in menu" :class="item.type">
|
<li v-for="(item, i) in menu" :class="item ? item.type : item === null ? 'divider' : null">
|
||||||
<template v-if="item.type == 'item'">
|
<template v-if="item">
|
||||||
<p @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</p>
|
<template v-if="item.type == null || item.type == 'item'">
|
||||||
</template>
|
<p @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</p>
|
||||||
<template v-if="item.type == 'link'">
|
</template>
|
||||||
<a :href="item.href" :target="item.target" @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</a>
|
<template v-else-if="item.type == 'link'">
|
||||||
</template>
|
<a :href="item.href" :target="item.target" @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</a>
|
||||||
<template v-else-if="item.type == 'nest'">
|
</template>
|
||||||
<p><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}...<span class="caret">%fa:caret-right%</span></p>
|
<template v-else-if="item.type == 'nest'">
|
||||||
<me-nu :menu="item.menu" @x="click"/>
|
<p><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}...<span class="caret">%fa:caret-right%</span></p>
|
||||||
|
<me-nu :menu="item.menu" @x="click"/>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="context-menu" :style="{ left: `${x}px`, top: `${y}px` }" @contextmenu.prevent="() => {}">
|
<div class="context-menu" @contextmenu.prevent="() => {}">
|
||||||
<x-menu :menu="menu" @x="click"/>
|
<x-menu :menu="menu" @x="click"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -17,6 +17,23 @@ export default Vue.extend({
|
|||||||
props: ['x', 'y', 'menu'],
|
props: ['x', 'y', 'menu'],
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
const width = this.$el.offsetWidth;
|
||||||
|
const height = this.$el.offsetHeight;
|
||||||
|
|
||||||
|
let x = this.x;
|
||||||
|
let y = this.y;
|
||||||
|
|
||||||
|
if (x + width > window.innerWidth) {
|
||||||
|
x = window.innerWidth - width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y + height > window.innerHeight) {
|
||||||
|
y = window.innerHeight - height;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$el.style.left = x + 'px';
|
||||||
|
this.$el.style.top = y + 'px';
|
||||||
|
|
||||||
Array.from(document.querySelectorAll('body *')).forEach(el => {
|
Array.from(document.querySelectorAll('body *')).forEach(el => {
|
||||||
el.addEventListener('mousedown', this.onMousedown);
|
el.addEventListener('mousedown', this.onMousedown);
|
||||||
});
|
});
|
||||||
@@ -38,7 +55,7 @@ export default Vue.extend({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
click(item) {
|
click(item) {
|
||||||
if (item.onClick) item.onClick();
|
if (item.action) item.action();
|
||||||
this.close();
|
this.close();
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
@@ -59,7 +76,6 @@ root(isDark)
|
|||||||
$item-height = 38px
|
$item-height = 38px
|
||||||
$padding = 10px
|
$padding = 10px
|
||||||
|
|
||||||
display none
|
|
||||||
position fixed
|
position fixed
|
||||||
top 0
|
top 0
|
||||||
left 0
|
left 0
|
||||||
|
|||||||
@@ -66,37 +66,33 @@ export default Vue.extend({
|
|||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.rename%',
|
text: '%i18n:@contextmenu.rename%',
|
||||||
icon: '%fa:i-cursor%',
|
icon: '%fa:i-cursor%',
|
||||||
onClick: this.rename
|
action: this.rename
|
||||||
}, {
|
}, {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.copy-url%',
|
text: '%i18n:@contextmenu.copy-url%',
|
||||||
icon: '%fa:link%',
|
icon: '%fa:link%',
|
||||||
onClick: this.copyUrl
|
action: this.copyUrl
|
||||||
}, {
|
}, {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
href: `${this.file.url}?download`,
|
href: `${this.file.url}?download`,
|
||||||
text: '%i18n:@contextmenu.download%',
|
text: '%i18n:@contextmenu.download%',
|
||||||
icon: '%fa:download%',
|
icon: '%fa:download%',
|
||||||
}, {
|
}, null, {
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:common.delete%',
|
text: '%i18n:common.delete%',
|
||||||
icon: '%fa:R trash-alt%',
|
icon: '%fa:R trash-alt%',
|
||||||
onClick: this.deleteFile
|
action: this.deleteFile
|
||||||
}, {
|
}, null, {
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
type: 'nest',
|
type: 'nest',
|
||||||
text: '%i18n:@contextmenu.else-files%',
|
text: '%i18n:@contextmenu.else-files%',
|
||||||
menu: [{
|
menu: [{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.set-as-avatar%',
|
text: '%i18n:@contextmenu.set-as-avatar%',
|
||||||
onClick: this.setAsAvatar
|
action: this.setAsAvatar
|
||||||
}, {
|
}, {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.set-as-banner%',
|
text: '%i18n:@contextmenu.set-as-banner%',
|
||||||
onClick: this.setAsBanner
|
action: this.setAsBanner
|
||||||
}]
|
}]
|
||||||
}, {
|
}, {
|
||||||
type: 'nest',
|
type: 'nest',
|
||||||
@@ -104,7 +100,7 @@ export default Vue.extend({
|
|||||||
menu: [{
|
menu: [{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.add-app%...',
|
text: '%i18n:@contextmenu.add-app%...',
|
||||||
onClick: this.addApp
|
action: this.addApp
|
||||||
}]
|
}]
|
||||||
}], {
|
}], {
|
||||||
closed: () => {
|
closed: () => {
|
||||||
|
|||||||
@@ -56,26 +56,22 @@ export default Vue.extend({
|
|||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.move-to-this-folder%',
|
text: '%i18n:@contextmenu.move-to-this-folder%',
|
||||||
icon: '%fa:arrow-right%',
|
icon: '%fa:arrow-right%',
|
||||||
onClick: this.go
|
action: this.go
|
||||||
}, {
|
}, {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.show-in-new-window%',
|
text: '%i18n:@contextmenu.show-in-new-window%',
|
||||||
icon: '%fa:R window-restore%',
|
icon: '%fa:R window-restore%',
|
||||||
onClick: this.newWindow
|
action: this.newWindow
|
||||||
}, {
|
}, null, {
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.rename%',
|
text: '%i18n:@contextmenu.rename%',
|
||||||
icon: '%fa:i-cursor%',
|
icon: '%fa:i-cursor%',
|
||||||
onClick: this.rename
|
action: this.rename
|
||||||
}, {
|
}, null, {
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:common.delete%',
|
text: '%i18n:common.delete%',
|
||||||
icon: '%fa:R trash-alt%',
|
icon: '%fa:R trash-alt%',
|
||||||
onClick: this.deleteFolder
|
action: this.deleteFolder
|
||||||
}], {
|
}], {
|
||||||
closed: () => {
|
closed: () => {
|
||||||
this.isContextmenuShowing = false;
|
this.isContextmenuShowing = false;
|
||||||
|
|||||||
@@ -140,17 +140,17 @@ export default Vue.extend({
|
|||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.create-folder%',
|
text: '%i18n:@contextmenu.create-folder%',
|
||||||
icon: '%fa:R folder%',
|
icon: '%fa:R folder%',
|
||||||
onClick: this.createFolder
|
action: this.createFolder
|
||||||
}, {
|
}, {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.upload%',
|
text: '%i18n:@contextmenu.upload%',
|
||||||
icon: '%fa:upload%',
|
icon: '%fa:upload%',
|
||||||
onClick: this.selectLocalFile
|
action: this.selectLocalFile
|
||||||
}, {
|
}, {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
text: '%i18n:@contextmenu.url-upload%',
|
text: '%i18n:@contextmenu.url-upload%',
|
||||||
icon: '%fa:cloud-upload-alt%',
|
icon: '%fa:cloud-upload-alt%',
|
||||||
onClick: this.urlUpload
|
action: this.urlUpload
|
||||||
}]);
|
}]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<option value="post-form">%i18n:common.widgets.post-form%</option>
|
<option value="post-form">%i18n:common.widgets.post-form%</option>
|
||||||
<option value="messaging">%i18n:common.widgets.messaging%</option>
|
<option value="messaging">%i18n:common.widgets.messaging%</option>
|
||||||
<option value="memo">%i18n:common.widgets.memo%</option>
|
<option value="memo">%i18n:common.widgets.memo%</option>
|
||||||
|
<option value="posts-monitor">%i18n:common.widgets.posts-monitor%</option>
|
||||||
<option value="server">%i18n:common.widgets.server%</option>
|
<option value="server">%i18n:common.widgets.server%</option>
|
||||||
<option value="donation">%i18n:common.widgets.donation%</option>
|
<option value="donation">%i18n:common.widgets.donation%</option>
|
||||||
<option value="nav">%i18n:common.widgets.nav%</option>
|
<option value="nav">%i18n:common.widgets.nav%</option>
|
||||||
|
|||||||
@@ -2,22 +2,7 @@
|
|||||||
<div class="mk-note-preview" :title="title">
|
<div class="mk-note-preview" :title="title">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="note | notePage">
|
|
||||||
<mk-time :time="note.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="note.visibility != 'public'">
|
|
||||||
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-sub-note-content class="text" :note="note"/>
|
<mk-sub-note-content class="text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,43 +41,6 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .name
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #607073
|
|
||||||
font-size 1em
|
|
||||||
font-weight bold
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
text-decoration underline
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
overflow hidden
|
|
||||||
text-overflow ellipsis
|
|
||||||
color isDark ? #606984 : #d1d8da
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #b2b8bb
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
> .text
|
> .text
|
||||||
|
|||||||
@@ -2,25 +2,7 @@
|
|||||||
<div class="sub" :title="title">
|
<div class="sub" :title="title">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="note"/>
|
||||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="note.user.isAdmin">admin</span>
|
|
||||||
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
|
||||||
<span class="is-cat" v-if="note.user.isCat">cat</span>
|
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="note | notePage">
|
|
||||||
<mk-time :time="note.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="note.visibility != 'public'">
|
|
||||||
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-sub-note-content class="text" :note="note"/>
|
<mk-sub-note-content class="text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,57 +44,8 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
margin-bottom 2px
|
margin-bottom 2px
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #607073
|
|
||||||
font-size 1em
|
|
||||||
font-weight bold
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
text-decoration underline
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 5px
|
|
||||||
font-size 10px
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
color isDark ? #606984 : #d1d8da
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #b2b8bb
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
|
|||||||
@@ -14,26 +14,7 @@
|
|||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user"/>
|
<mk-avatar class="avatar" :user="p.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="p"/>
|
||||||
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="p.user.isAdmin">admin</span>
|
|
||||||
<span class="is-bot" v-if="p.user.isBot">bot</span>
|
|
||||||
<span class="is-cat" v-if="p.user.isCat">cat</span>
|
|
||||||
<span class="username"><mk-acct :user="p.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
|
||||||
<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="p | notePage">
|
|
||||||
<mk-time :time="p.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="p.visibility != 'public'">
|
|
||||||
<template v-if="p.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="p.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="p.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="p.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="p.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
||||||
@@ -409,64 +390,8 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
margin-bottom 4px
|
margin-bottom 4px
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #627079
|
|
||||||
font-size 1em
|
|
||||||
font-weight bold
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
text-decoration underline
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
padding 1px 6px
|
|
||||||
font-size 12px
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
overflow hidden
|
|
||||||
text-overflow ellipsis
|
|
||||||
color isDark ? #606984 : #ccc
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #c0c0c0
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 8px
|
|
||||||
|
|
||||||
> .app
|
|
||||||
margin-right 8px
|
|
||||||
padding-right 8px
|
|
||||||
border-right solid 1px isDark ? #1c2023 : #eaeaea
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 8px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ root(isDark)
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
overflow-wrap break-word
|
overflow-wrap break-word
|
||||||
font-size 12px
|
font-size 13px
|
||||||
border-bottom solid 1px isDark ? #1c2023 : rgba(#000, 0.05)
|
border-bottom solid 1px isDark ? #1c2023 : rgba(#000, 0.05)
|
||||||
|
|
||||||
&:last-child
|
&:last-child
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">%i18n:@customize%</button>
|
<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">%i18n:@customize%</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="div">
|
<div class="div">
|
||||||
|
<button class="ui" @click="updateWallpaper">%i18n:@choose-wallpaper%</button>
|
||||||
|
<button class="ui" @click="deleteWallpaper">%i18n:@delete-wallpaper%</button>
|
||||||
<mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/>
|
<mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/>
|
||||||
<mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
|
<mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
|
||||||
<mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
|
<mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
|
||||||
@@ -293,6 +295,20 @@ export default Vue.extend({
|
|||||||
this.$router.push('/i/customize-home');
|
this.$router.push('/i/customize-home');
|
||||||
this.$emit('done');
|
this.$emit('done');
|
||||||
},
|
},
|
||||||
|
updateWallpaper() {
|
||||||
|
(this as any).apis.chooseDriveFile({
|
||||||
|
multiple: false
|
||||||
|
}).then(file => {
|
||||||
|
(this as any).api('i/update', {
|
||||||
|
wallpaperId: file.id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteWallpaper() {
|
||||||
|
(this as any).api('i/update', {
|
||||||
|
wallpaperId: null
|
||||||
|
});
|
||||||
|
},
|
||||||
onChangeFetchOnScroll(v) {
|
onChangeFetchOnScroll(v) {
|
||||||
this.$store.dispatch('settings/set', {
|
this.$store.dispatch('settings/set', {
|
||||||
key: 'fetchOnScroll',
|
key: 'fetchOnScroll',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-ui">
|
<div class="mk-ui" :style="style">
|
||||||
<x-header class="header"/>
|
<x-header class="header" v-show="!zenMode"/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,6 +16,20 @@ export default Vue.extend({
|
|||||||
components: {
|
components: {
|
||||||
XHeader
|
XHeader
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
zenMode: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
style(): any {
|
||||||
|
if (!this.$store.getters.isSignedIn || this.$store.state.i.wallpaperUrl == null) return {};
|
||||||
|
return {
|
||||||
|
backgroundColor: this.$store.state.i.wallpaperColor && this.$store.state.i.wallpaperColor.length == 3 ? `rgb(${ this.$store.state.i.wallpaperColor.join(',') })` : null,
|
||||||
|
backgroundImage: `url(${ this.$store.state.i.wallpaperUrl })`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('keydown', this.onKeydown);
|
document.addEventListener('keydown', this.onKeydown);
|
||||||
},
|
},
|
||||||
@@ -30,6 +44,11 @@ export default Vue.extend({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
(this as any).apis.post();
|
(this as any).apis.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.which == 90) { // z
|
||||||
|
e.preventDefault();
|
||||||
|
this.zenMode = !this.zenMode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -40,6 +59,9 @@ export default Vue.extend({
|
|||||||
display flex
|
display flex
|
||||||
flex-direction column
|
flex-direction column
|
||||||
flex 1
|
flex 1
|
||||||
|
background-size cover
|
||||||
|
background-position center
|
||||||
|
background-attachment fixed
|
||||||
|
|
||||||
> .header
|
> .header
|
||||||
@media (max-width 1000px)
|
@media (max-width 1000px)
|
||||||
|
|||||||
35
src/client/app/desktop/views/pages/deck/deck.column-core.vue
Normal file
35
src/client/app/desktop/views/pages/deck/deck.column-core.vue
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<x-widgets-column v-if="column.type == 'widgets'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import XTlColumn from './deck.tl-column.vue';
|
||||||
|
import XNotificationsColumn from './deck.notifications-column.vue';
|
||||||
|
import XWidgetsColumn from './deck.widgets-column.vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XTlColumn,
|
||||||
|
XNotificationsColumn,
|
||||||
|
XWidgetsColumn
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
column: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow }">
|
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }"
|
||||||
<header :class="{ indicate }">
|
@dragover.prevent.stop="onDragover"
|
||||||
|
@dragenter.prevent="onDragenter"
|
||||||
|
@dragleave="onDragleave"
|
||||||
|
@drop.prevent.stop="onDrop"
|
||||||
|
>
|
||||||
|
<header :class="{ indicate: count > 0 }"
|
||||||
|
draggable="true"
|
||||||
|
@click="toggleActive"
|
||||||
|
@dragstart="onDragstart"
|
||||||
|
@dragend="onDragend"
|
||||||
|
@contextmenu.prevent.stop="onContextmenu"
|
||||||
|
>
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
<button ref="menu" @click="showMenu">%fa:caret-down%</button>
|
<span class="count" v-if="count > 0">({{ count }})</span>
|
||||||
|
<button ref="menu" @click.stop="showMenu">%fa:caret-down%</button>
|
||||||
</header>
|
</header>
|
||||||
<div ref="body">
|
<div ref="body" v-show="active">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,16 +25,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Menu from '../../../../common/views/components/menu.vue';
|
import Menu from '../../../../common/views/components/menu.vue';
|
||||||
|
import contextmenu from '../../../api/contextmenu';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
id: {
|
column: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false
|
required: false,
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
naked: {
|
naked: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -36,30 +58,69 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
inject: {
|
||||||
|
getColumnVm: { from: 'getColumnVm' }
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
indicate: false
|
count: 0,
|
||||||
|
active: true,
|
||||||
|
dragging: false,
|
||||||
|
draghover: false,
|
||||||
|
dropready: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
active(v) {
|
||||||
|
if (v && this.isScrollTop()) {
|
||||||
|
this.$emit('top');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dragging(v) {
|
||||||
|
this.$root.$emit(v ? 'deck.column.dragStart' : 'deck.column.dragEnd');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
column: this,
|
column: this,
|
||||||
isScrollTop: this.isScrollTop,
|
isScrollTop: this.isScrollTop,
|
||||||
indicate: v => this.indicate = v
|
count: v => this.count = v
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$refs.body.addEventListener('scroll', this.onScroll, { passive: true });
|
this.$refs.body.addEventListener('scroll', this.onScroll, { passive: true });
|
||||||
|
this.$root.$on('deck.column.dragStart', this.onOtherDragStart);
|
||||||
|
this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$refs.body.removeEventListener('scroll', this.onScroll);
|
this.$refs.body.removeEventListener('scroll', this.onScroll);
|
||||||
|
this.$root.$off('deck.column.dragStart', this.onOtherDragStart);
|
||||||
|
this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
onOtherDragStart() {
|
||||||
|
this.dropready = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
onOtherDragEnd() {
|
||||||
|
this.dropready = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleActive() {
|
||||||
|
if (!this.isStacked) return;
|
||||||
|
const vms = this.$store.state.settings.deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id));
|
||||||
|
if (this.active && vms.filter(vm => vm.$el.classList.contains('active')).length == 1) return;
|
||||||
|
this.active = !this.active;
|
||||||
|
},
|
||||||
|
|
||||||
isScrollTop() {
|
isScrollTop() {
|
||||||
return this.$refs.body.scrollTop == 0;
|
return this.active && this.$refs.body.scrollTop == 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
@@ -73,21 +134,60 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showMenu() {
|
getMenu() {
|
||||||
const items = [{
|
const items = [{
|
||||||
content: '%fa:arrow-left% %i18n:common.deck.swap-left%',
|
icon: '%fa:pencil-alt%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.rename%',
|
||||||
this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
|
action: () => {
|
||||||
|
(this as any).apis.input({
|
||||||
|
title: '%i18n:common.deck.rename%',
|
||||||
|
default: this.name,
|
||||||
|
allowEmpty: false
|
||||||
|
}).then(name => {
|
||||||
|
this.$store.dispatch('settings/renameDeckColumn', { id: this.column.id, name });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, null, {
|
||||||
|
icon: '%fa:arrow-left%',
|
||||||
|
text: '%i18n:common.deck.swap-left%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/swapLeftDeckColumn', this.column.id);
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%fa:arrow-right% %i18n:common.deck.swap-right%',
|
icon: '%fa:arrow-right%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.swap-right%',
|
||||||
this.$store.dispatch('settings/swapRightDeckColumn', this.id);
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/swapRightDeckColumn', this.column.id);
|
||||||
}
|
}
|
||||||
}, {
|
}, this.isStacked ? {
|
||||||
content: '%fa:trash-alt R% %i18n:common.deck.remove%',
|
icon: '%fa:arrow-up%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.swap-up%',
|
||||||
this.$store.dispatch('settings/removeDeckColumn', this.id);
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/swapUpDeckColumn', this.column.id);
|
||||||
|
}
|
||||||
|
} : undefined, this.isStacked ? {
|
||||||
|
icon: '%fa:arrow-down%',
|
||||||
|
text: '%i18n:common.deck.swap-down%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/swapDownDeckColumn', this.column.id);
|
||||||
|
}
|
||||||
|
} : undefined, null, {
|
||||||
|
icon: '%fa:window-restore R%',
|
||||||
|
text: '%i18n:common.deck.stack-left%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/stackLeftDeckColumn', this.column.id);
|
||||||
|
}
|
||||||
|
}, this.isStacked ? {
|
||||||
|
icon: '%fa:window-maximize R%',
|
||||||
|
text: '%i18n:common.deck.pop-right%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/popRightDeckColumn', this.column.id);
|
||||||
|
}
|
||||||
|
} : undefined, null, {
|
||||||
|
icon: '%fa:trash-alt R%',
|
||||||
|
text: '%i18n:common.deck.remove%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/removeDeckColumn', this.column.id);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -96,11 +196,63 @@ export default Vue.extend({
|
|||||||
this.menu.reverse().forEach(i => items.unshift(i));
|
this.menu.reverse().forEach(i => items.unshift(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
|
||||||
|
onContextmenu(e) {
|
||||||
|
contextmenu((this as any).os)(e, this.getMenu());
|
||||||
|
},
|
||||||
|
|
||||||
|
showMenu() {
|
||||||
this.os.new(Menu, {
|
this.os.new(Menu, {
|
||||||
source: this.$refs.menu,
|
source: this.$refs.menu,
|
||||||
compact: false,
|
compact: false,
|
||||||
items
|
items: this.getMenu()
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onDragstart(e) {
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
e.dataTransfer.setData('mk-deck-column', this.column.id);
|
||||||
|
this.dragging = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
onDragend(e) {
|
||||||
|
this.dragging = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
onDragover(e) {
|
||||||
|
// 自分自身がドラッグされている場合
|
||||||
|
if (this.dragging) {
|
||||||
|
// 自分自身にはドロップさせない
|
||||||
|
e.dataTransfer.dropEffect = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDeckColumn = e.dataTransfer.types[0] == 'mk-deck-column';
|
||||||
|
|
||||||
|
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||||
|
},
|
||||||
|
|
||||||
|
onDragenter() {
|
||||||
|
if (!this.dragging) this.draghover = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
onDragleave() {
|
||||||
|
this.draghover = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
onDrop(e) {
|
||||||
|
this.draghover = false;
|
||||||
|
this.$root.$emit('deck.column.dragEnd');
|
||||||
|
|
||||||
|
const id = e.dataTransfer.getData('mk-deck-column');
|
||||||
|
if (id != null && id != '') {
|
||||||
|
this.$store.dispatch('settings/swapDeckColumn', {
|
||||||
|
a: this.column.id,
|
||||||
|
b: id
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -112,18 +264,31 @@ export default Vue.extend({
|
|||||||
root(isDark)
|
root(isDark)
|
||||||
$header-height = 42px
|
$header-height = 42px
|
||||||
|
|
||||||
flex 1
|
width 330px
|
||||||
min-width 330px
|
min-width 330px
|
||||||
max-width 330px
|
|
||||||
height 100%
|
height 100%
|
||||||
background isDark ? #282C37 : #fff
|
background isDark ? #282C37 : #fff
|
||||||
border-radius 6px
|
border-radius 6px
|
||||||
box-shadow 0 2px 16px rgba(#000, 0.1)
|
box-shadow 0 2px 16px rgba(#000, 0.1)
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
&.narrow
|
&.draghover
|
||||||
|
box-shadow 0 0 0 2px rgba($theme-color, 0.8)
|
||||||
|
|
||||||
|
&.dragging
|
||||||
|
box-shadow 0 0 0 2px rgba($theme-color, 0.4)
|
||||||
|
|
||||||
|
&.dropready
|
||||||
|
*
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
&:not(.active)
|
||||||
|
flex-basis $header-height
|
||||||
|
min-height $header-height
|
||||||
|
|
||||||
|
&:not(.isStacked).narrow
|
||||||
|
width 285px
|
||||||
min-width 285px
|
min-width 285px
|
||||||
max-width 285px
|
|
||||||
|
|
||||||
&.naked
|
&.naked
|
||||||
background rgba(#000, isDark ? 0.25 : 0.1)
|
background rgba(#000, isDark ? 0.25 : 0.1)
|
||||||
@@ -140,9 +305,17 @@ root(isDark)
|
|||||||
z-index 1
|
z-index 1
|
||||||
line-height $header-height
|
line-height $header-height
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
|
font-size 14px
|
||||||
color isDark ? #e3e5e8 : #888
|
color isDark ? #e3e5e8 : #888
|
||||||
background isDark ? #313543 : #fff
|
background isDark ? #313543 : #fff
|
||||||
box-shadow 0 1px rgba(#000, 0.15)
|
box-shadow 0 1px rgba(#000, 0.15)
|
||||||
|
cursor pointer
|
||||||
|
|
||||||
|
&, *
|
||||||
|
user-select none
|
||||||
|
|
||||||
|
*:not(button)
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
&.indicate
|
&.indicate
|
||||||
box-shadow 0 3px 0 0 $theme-color
|
box-shadow 0 3px 0 0 $theme-color
|
||||||
@@ -151,12 +324,17 @@ root(isDark)
|
|||||||
[data-fa]
|
[data-fa]
|
||||||
margin-right 8px
|
margin-right 8px
|
||||||
|
|
||||||
|
> .count
|
||||||
|
margin-left 4px
|
||||||
|
opacity 0.5
|
||||||
|
|
||||||
> button
|
> button
|
||||||
position absolute
|
position absolute
|
||||||
top 0
|
top 0
|
||||||
right 0
|
right 0
|
||||||
width $header-height
|
width $header-height
|
||||||
line-height $header-height
|
line-height $header-height
|
||||||
|
font-size 16px
|
||||||
color isDark ? #9baec8 : #ccc
|
color isDark ? #9baec8 : #ccc
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ export default Vue.extend({
|
|||||||
list: {
|
list: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
mediaOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -30,6 +35,12 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
mediaOnly() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.connection) this.connection.close();
|
if (this.connection) this.connection.close();
|
||||||
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
||||||
@@ -52,6 +63,7 @@ export default Vue.extend({
|
|||||||
(this as any).api('notes/user-list-timeline', {
|
(this as any).api('notes/user-list-timeline', {
|
||||||
listId: this.list.id,
|
listId: this.list.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
|
mediaOnly: this.mediaOnly,
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
@@ -72,6 +84,7 @@ export default Vue.extend({
|
|||||||
listId: this.list.id,
|
listId: this.list.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
|
mediaOnly: this.mediaOnly,
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
});
|
});
|
||||||
@@ -89,6 +102,8 @@ export default Vue.extend({
|
|||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
|
if (this.mediaOnly && note.media.length == 0) return;
|
||||||
|
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,25 +2,7 @@
|
|||||||
<div class="fnlfosztlhtptnongximhlbykxblytcq">
|
<div class="fnlfosztlhtptnongximhlbykxblytcq">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||||
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="note.user.isAdmin">%i18n:@admin%</span>
|
|
||||||
<span class="is-bot" v-if="note.user.isBot">%i18n:@bot%</span>
|
|
||||||
<span class="is-cat" v-if="note.user.isCat">%i18n:@cat%</span>
|
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="note | notePage">
|
|
||||||
<mk-time :time="note.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="note.visibility != 'public'">
|
|
||||||
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-sub-note-content class="text" :note="note"/>
|
<mk-sub-note-content class="text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,66 +54,8 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
margin-bottom 2px
|
margin-bottom 2px
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .avatar
|
|
||||||
flex-shrink 0
|
|
||||||
margin-right 8px
|
|
||||||
width 18px
|
|
||||||
height 18px
|
|
||||||
border-radius 100%
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #607073
|
|
||||||
font-size 1em
|
|
||||||
font-weight 700
|
|
||||||
text-align left
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
text-decoration underline
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 5px
|
|
||||||
font-size 0.8em
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
text-align left
|
|
||||||
margin 0
|
|
||||||
color isDark ? #606984 : #d1d8da
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #b2b8bb
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
|
|||||||
@@ -14,25 +14,7 @@
|
|||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user"/>
|
<mk-avatar class="avatar" :user="p.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="p" :mini="true"/>
|
||||||
<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="p.user.isAdmin">admin</span>
|
|
||||||
<span class="is-bot" v-if="p.user.isBot">bot</span>
|
|
||||||
<span class="is-cat" v-if="p.user.isCat">cat</span>
|
|
||||||
<span class="username"><mk-acct :user="p.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="p | notePage">
|
|
||||||
<mk-time :time="p.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="p.visibility != 'public'">
|
|
||||||
<template v-if="p.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="p.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="p.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="p.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="p.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
||||||
@@ -218,7 +200,7 @@ export default Vue.extend({
|
|||||||
@import '~const.styl'
|
@import '~const.styl'
|
||||||
|
|
||||||
root(isDark)
|
root(isDark)
|
||||||
font-size 12px
|
font-size 13px
|
||||||
border-bottom solid 1px isDark ? #1c2023 : #eaeaea
|
border-bottom solid 1px isDark ? #1c2023 : #eaeaea
|
||||||
|
|
||||||
&:last-of-type
|
&:last-of-type
|
||||||
@@ -234,7 +216,7 @@ root(isDark)
|
|||||||
> .renote
|
> .renote
|
||||||
display flex
|
display flex
|
||||||
align-items center
|
align-items center
|
||||||
padding 8px 16px
|
padding 8px 16px 0 16px
|
||||||
line-height 28px
|
line-height 28px
|
||||||
white-space pre
|
white-space pre
|
||||||
color #9dbb00
|
color #9dbb00
|
||||||
@@ -292,62 +274,6 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .avatar
|
|
||||||
flex-shrink 0
|
|
||||||
margin-right 8px
|
|
||||||
width 20px
|
|
||||||
height 20px
|
|
||||||
border-radius 100%
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #627079
|
|
||||||
font-weight bold
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 6px
|
|
||||||
font-size 0.8em
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
overflow hidden
|
|
||||||
text-overflow ellipsis
|
|
||||||
color isDark ? #606984 : #ccc
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #c0c0c0
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
> .cw
|
> .cw
|
||||||
|
|||||||
@@ -28,19 +28,17 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { url } from '../../../config';
|
|
||||||
import getNoteSummary from '../../../../../renderers/get-note-summary';
|
|
||||||
|
|
||||||
import XNote from './deck.note.vue';
|
import XNote from './deck.note.vue';
|
||||||
|
|
||||||
const displayLimit = 30;
|
const displayLimit = 20;
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XNote
|
XNote
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: ['column', 'isScrollTop', 'indicate'],
|
inject: ['column', 'isScrollTop', 'count'],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
more: {
|
more: {
|
||||||
@@ -55,7 +53,6 @@ export default Vue.extend({
|
|||||||
requestInitPromise: null as () => Promise<any[]>,
|
requestInitPromise: null as () => Promise<any[]>,
|
||||||
notes: [],
|
notes: [],
|
||||||
queue: [],
|
queue: [],
|
||||||
unreadCount: 0,
|
|
||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false
|
moreFetching: false
|
||||||
};
|
};
|
||||||
@@ -73,6 +70,12 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
queue(q) {
|
||||||
|
this.count(q.length);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.column.$on('top', this.onTop);
|
this.column.$on('top', this.onTop);
|
||||||
this.column.$on('bottom', this.onBottom);
|
this.column.$on('bottom', this.onBottom);
|
||||||
@@ -141,7 +144,6 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.queue.push(note);
|
this.queue.push(note);
|
||||||
this.indicate(true);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -156,7 +158,6 @@ export default Vue.extend({
|
|||||||
releaseQueue() {
|
releaseQueue() {
|
||||||
this.queue.forEach(n => this.prepend(n, true));
|
this.queue.forEach(n => this.prepend(n, true));
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
this.indicate(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadMore() {
|
async loadMore() {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export default Vue.extend({
|
|||||||
root(isDark)
|
root(isDark)
|
||||||
> .notification
|
> .notification
|
||||||
padding 16px
|
padding 16px
|
||||||
font-size 12px
|
font-size 13px
|
||||||
overflow-wrap break-word
|
overflow-wrap break-word
|
||||||
|
|
||||||
&:after
|
&:after
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
||||||
<x-column :id="id">
|
<span slot="header">%fa:bell R%{{ name }}</span>
|
||||||
<span slot="header">%fa:bell R%%i18n:common.deck.notifications%</span>
|
|
||||||
|
|
||||||
<x-notifications/>
|
<x-notifications/>
|
||||||
</x-column>
|
</x-column>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -20,10 +18,21 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
id: {
|
column: {
|
||||||
type: String,
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
name(): string {
|
||||||
|
if (this.column.name) return this.column.name;
|
||||||
|
return '%i18n:common.deck.notifications%';
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -21,20 +21,27 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XNotification from './deck.notification.vue';
|
import XNotification from './deck.notification.vue';
|
||||||
|
|
||||||
|
const displayLimit = 20;
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XNotification
|
XNotification
|
||||||
},
|
},
|
||||||
|
|
||||||
|
inject: ['column', 'isScrollTop', 'count'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fetching: true,
|
fetching: true,
|
||||||
fetchingMoreNotifications: false,
|
fetchingMoreNotifications: false,
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
queue: [],
|
||||||
moreNotifications: false,
|
moreNotifications: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null
|
connectionId: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
_notifications(): any[] {
|
_notifications(): any[] {
|
||||||
return (this.notifications as any).map(notification => {
|
return (this.notifications as any).map(notification => {
|
||||||
@@ -46,12 +53,22 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
queue(q) {
|
||||||
|
this.count(q.length);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
this.connection = (this as any).os.stream.getConnection();
|
||||||
this.connectionId = (this as any).os.stream.use();
|
this.connectionId = (this as any).os.stream.use();
|
||||||
|
|
||||||
this.connection.on('notification', this.onNotification);
|
this.connection.on('notification', this.onNotification);
|
||||||
|
|
||||||
|
this.column.$on('top', this.onTop);
|
||||||
|
this.column.$on('bottom', this.onBottom);
|
||||||
|
|
||||||
const max = 10;
|
const max = 10;
|
||||||
|
|
||||||
(this as any).api('i/notifications', {
|
(this as any).api('i/notifications', {
|
||||||
@@ -66,15 +83,20 @@ export default Vue.extend({
|
|||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('notification', this.onNotification);
|
this.connection.off('notification', this.onNotification);
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
(this as any).os.stream.dispose(this.connectionId);
|
||||||
|
|
||||||
|
this.column.$off('top', this.onTop);
|
||||||
|
this.column.$off('bottom', this.onBottom);
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchMoreNotifications() {
|
fetchMoreNotifications() {
|
||||||
this.fetchingMoreNotifications = true;
|
this.fetchingMoreNotifications = true;
|
||||||
|
|
||||||
const max = 30;
|
const max = 20;
|
||||||
|
|
||||||
(this as any).api('i/notifications', {
|
(this as any).api('i/notifications', {
|
||||||
limit: max + 1,
|
limit: max + 1,
|
||||||
@@ -90,6 +112,7 @@ export default Vue.extend({
|
|||||||
this.fetchingMoreNotifications = false;
|
this.fetchingMoreNotifications = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onNotification(notification) {
|
onNotification(notification) {
|
||||||
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
@@ -97,7 +120,34 @@ export default Vue.extend({
|
|||||||
id: notification.id
|
id: notification.id
|
||||||
});
|
});
|
||||||
|
|
||||||
this.notifications.unshift(notification);
|
this.prepend(notification);
|
||||||
|
},
|
||||||
|
|
||||||
|
prepend(notification) {
|
||||||
|
if (this.isScrollTop()) {
|
||||||
|
// Prepend the notification
|
||||||
|
this.notifications.unshift(notification);
|
||||||
|
|
||||||
|
// オーバーフローしたら古い通知は捨てる
|
||||||
|
if (this.notifications.length >= displayLimit) {
|
||||||
|
this.notifications = this.notifications.slice(0, displayLimit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.queue.push(notification);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseQueue() {
|
||||||
|
this.queue.forEach(n => this.prepend(n));
|
||||||
|
this.queue = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
onTop() {
|
||||||
|
this.releaseQueue();
|
||||||
|
},
|
||||||
|
|
||||||
|
onBottom() {
|
||||||
|
this.fetchMoreNotifications();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<x-column :menu="menu" :name="name" :column="column" :is-stacked="isStacked">
|
||||||
<x-column :id="column.id">
|
<span slot="header">
|
||||||
<span slot="header">
|
<template v-if="column.type == 'home'">%fa:home%</template>
|
||||||
<template v-if="column.type == 'home'">%fa:home%%i18n:common.deck.home%</template>
|
<template v-if="column.type == 'local'">%fa:R comments%</template>
|
||||||
<template v-if="column.type == 'local'">%fa:R comments%%i18n:common.deck.local%</template>
|
<template v-if="column.type == 'global'">%fa:globe%</template>
|
||||||
<template v-if="column.type == 'global'">%fa:globe%%i18n:common.deck.global%</template>
|
<template v-if="column.type == 'list'">%fa:list%</template>
|
||||||
<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template>
|
<span>{{ name }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<x-list-tl v-if="column.type == 'list'" :list="column.list"/>
|
<div class="editor" v-if="edit">
|
||||||
<x-tl v-else :src="column.type"/>
|
<mk-switch v-model="column.isMediaOnly" @change="onChangeSettings" text="%i18n:@is-media-only%"/>
|
||||||
</x-column>
|
<mk-switch v-model="column.isMediaView" @change="onChangeSettings" text="%i18n:@is-media-view%"/>
|
||||||
</div>
|
</div>
|
||||||
|
<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly"/>
|
||||||
|
<x-tl v-else :src="column.type" :media-only="column.isMediaOnly"/>
|
||||||
|
</x-column>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -31,6 +34,42 @@ export default Vue.extend({
|
|||||||
column: {
|
column: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
edit: false,
|
||||||
|
menu: [{
|
||||||
|
icon: '%fa:cog%',
|
||||||
|
text: '%i18n:@edit%',
|
||||||
|
action: () => {
|
||||||
|
this.edit = !this.edit;
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
name(): string {
|
||||||
|
if (this.column.name) return this.column.name;
|
||||||
|
|
||||||
|
switch (this.column.type) {
|
||||||
|
case 'home': return '%i18n:common.deck.home%';
|
||||||
|
case 'local': return '%i18n:common.deck.local%';
|
||||||
|
case 'global': return '%i18n:common.deck.global%';
|
||||||
|
case 'list': return this.column.list.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChangeSettings(v) {
|
||||||
|
this.$store.dispatch('settings/saveDeck');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ export default Vue.extend({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: 'home'
|
default: 'home'
|
||||||
|
},
|
||||||
|
mediaOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -31,6 +36,12 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
mediaOnly() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
stream(): any {
|
stream(): any {
|
||||||
return this.src == 'home'
|
return this.src == 'home'
|
||||||
@@ -78,6 +89,7 @@ export default Vue.extend({
|
|||||||
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
(this as any).api(this.endpoint, {
|
(this as any).api(this.endpoint, {
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
|
mediaOnly: this.mediaOnly,
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
@@ -97,6 +109,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
const promise = (this as any).api(this.endpoint, {
|
const promise = (this as any).api(this.endpoint, {
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
|
mediaOnly: this.mediaOnly,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
@@ -116,6 +129,8 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
|
if (this.mediaOnly && note.media.length == 0) return;
|
||||||
|
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-ui :class="$style.root">
|
<mk-ui :class="$style.root">
|
||||||
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
|
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
|
||||||
<template v-for="column in columns">
|
<template v-for="ids in layout">
|
||||||
<x-widgets-column v-if="column.type == 'widgets'" :key="column.id" :column="column"/>
|
<div v-if="ids.length > 1" class="folder">
|
||||||
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/>
|
<template v-for="id, i in ids">
|
||||||
<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/>
|
<x-column-core :ref="id" :key="id" :column="columns.find(c => c.id == id)" :is-stacked="true"/>
|
||||||
<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/>
|
</template>
|
||||||
<x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/>
|
</div>
|
||||||
<x-tl-column v-if="column.type == 'list'" :key="column.id" :column="column"/>
|
<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])"/>
|
||||||
</template>
|
</template>
|
||||||
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
|
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,27 +16,34 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XTlColumn from './deck.tl-column.vue';
|
import XColumnCore from './deck.column-core.vue';
|
||||||
import XNotificationsColumn from './deck.notifications-column.vue';
|
|
||||||
import XWidgetsColumn from './deck.widgets-column.vue';
|
|
||||||
import Menu from '../../../../common/views/components/menu.vue';
|
import Menu from '../../../../common/views/components/menu.vue';
|
||||||
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XTlColumn,
|
XColumnCore
|
||||||
XNotificationsColumn,
|
|
||||||
XWidgetsColumn
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
columns() {
|
columns(): any[] {
|
||||||
if (this.$store.state.settings.deck == null) return [];
|
if (this.$store.state.settings.deck == null) return [];
|
||||||
return this.$store.state.settings.deck.columns;
|
return this.$store.state.settings.deck.columns;
|
||||||
|
},
|
||||||
|
layout(): any[] {
|
||||||
|
if (this.$store.state.settings.deck == null) return [];
|
||||||
|
if (this.$store.state.settings.deck.layout == null) return this.$store.state.settings.deck.columns.map(c => [c.id]);
|
||||||
|
return this.$store.state.settings.deck.layout;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
getColumnVm: this.getColumnVm
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.$store.state.settings.deck == null) {
|
if (this.$store.state.settings.deck == null) {
|
||||||
const deck = {
|
const deck = {
|
||||||
@@ -58,11 +65,23 @@ export default Vue.extend({
|
|||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deck.layout = deck.columns.map(c => [c.id]);
|
||||||
|
|
||||||
this.$store.dispatch('settings/set', {
|
this.$store.dispatch('settings/set', {
|
||||||
key: 'deck',
|
key: 'deck',
|
||||||
value: deck
|
value: deck
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 互換性のため
|
||||||
|
if (this.$store.state.settings.deck != null && this.$store.state.settings.deck.layout == null) {
|
||||||
|
this.$store.dispatch('settings/set', {
|
||||||
|
key: 'deck',
|
||||||
|
value: Object.assign({}, this.$store.state.settings.deck, {
|
||||||
|
layout: this.$store.state.settings.deck.columns.map(c => [c.id])
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -74,37 +93,45 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
getColumnVm(id) {
|
||||||
|
return this.$refs[id][0];
|
||||||
|
},
|
||||||
|
|
||||||
add() {
|
add() {
|
||||||
this.os.new(Menu, {
|
this.os.new(Menu, {
|
||||||
source: this.$refs.add,
|
source: this.$refs.add,
|
||||||
compact: true,
|
compact: true,
|
||||||
items: [{
|
items: [{
|
||||||
content: '%i18n:common.deck.home%',
|
icon: '%fa:home%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.home%',
|
||||||
|
action: () => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'home'
|
type: 'home'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%i18n:common.deck.local%',
|
icon: '%fa:comments R%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.local%',
|
||||||
|
action: () => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'local'
|
type: 'local'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%i18n:common.deck.global%',
|
icon: '%fa:globe%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.global%',
|
||||||
|
action: () => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'global'
|
type: 'global'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%i18n:common.deck.list%',
|
icon: '%fa:list%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.list%',
|
||||||
|
action: () => {
|
||||||
const w = (this as any).os.new(MkUserListsWindow);
|
const w = (this as any).os.new(MkUserListsWindow);
|
||||||
w.$once('choosen', list => {
|
w.$once('choosen', list => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
@@ -116,16 +143,18 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%i18n:common.deck.notifications%',
|
icon: '%fa:bell R%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.notifications%',
|
||||||
|
action: () => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'notifications'
|
type: 'notifications'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
content: '%i18n:common.deck.widgets%',
|
icon: '%fa:calculator%',
|
||||||
onClick: () => {
|
text: '%i18n:common.deck.widgets%',
|
||||||
|
action: () => {
|
||||||
this.$store.dispatch('settings/addDeckColumn', {
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'widgets',
|
type: 'widgets',
|
||||||
@@ -150,7 +179,6 @@ export default Vue.extend({
|
|||||||
root(isDark)
|
root(isDark)
|
||||||
display flex
|
display flex
|
||||||
flex 1
|
flex 1
|
||||||
justify-content center
|
|
||||||
padding 16px 0 16px 16px
|
padding 16px 0 16px 16px
|
||||||
overflow auto
|
overflow auto
|
||||||
|
|
||||||
@@ -160,6 +188,20 @@ root(isDark)
|
|||||||
&:last-of-type
|
&:last-of-type
|
||||||
margin-right 0
|
margin-right 0
|
||||||
|
|
||||||
|
&.folder
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
|
||||||
|
> *:not(:last-child)
|
||||||
|
margin-bottom 8px
|
||||||
|
|
||||||
|
> *
|
||||||
|
&:first-child
|
||||||
|
margin-left auto
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
margin-right auto
|
||||||
|
|
||||||
> button
|
> button
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
color isDark ? #93a0a5 : #888
|
color isDark ? #93a0a5 : #888
|
||||||
|
|||||||
@@ -1,57 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wtdtxvecapixsepjtcupubtsmometobz">
|
<x-column :menu="menu" :naked="true" :narrow="true" :name="name" :column="column" :is-stacked="isStacked" class="wtdtxvecapixsepjtcupubtsmometobz">
|
||||||
<x-column :id="column.id" :menu="menu" :naked="true" :narrow="true">
|
<span slot="header">%fa:calculator%{{ name }}</span>
|
||||||
<span slot="header">%fa:calculator%%i18n:common.deck.widgets%</span>
|
|
||||||
|
|
||||||
<div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
|
<div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
|
||||||
<template v-if="edit">
|
<template v-if="edit">
|
||||||
<header>
|
<header>
|
||||||
<select v-model="widgetAdderSelected">
|
<select v-model="widgetAdderSelected">
|
||||||
<option value="profile">%i18n:common.widgets.profile%</option>
|
<option value="profile">%i18n:common.widgets.profile%</option>
|
||||||
<option value="analog-clock">%i18n:common.widgets.analog-clock%</option>
|
<option value="analog-clock">%i18n:common.widgets.analog-clock%</option>
|
||||||
<option value="calendar">%i18n:common.widgets.calendar%</option>
|
<option value="calendar">%i18n:common.widgets.calendar%</option>
|
||||||
<option value="timemachine">%i18n:common.widgets.timemachine%</option>
|
<option value="timemachine">%i18n:common.widgets.timemachine%</option>
|
||||||
<option value="activity">%i18n:common.widgets.activity%</option>
|
<option value="activity">%i18n:common.widgets.activity%</option>
|
||||||
<option value="rss">%i18n:common.widgets.rss%</option>
|
<option value="rss">%i18n:common.widgets.rss%</option>
|
||||||
<option value="trends">%i18n:common.widgets.trends%</option>
|
<option value="trends">%i18n:common.widgets.trends%</option>
|
||||||
<option value="photo-stream">%i18n:common.widgets.photo-stream%</option>
|
<option value="photo-stream">%i18n:common.widgets.photo-stream%</option>
|
||||||
<option value="slideshow">%i18n:common.widgets.slideshow%</option>
|
<option value="slideshow">%i18n:common.widgets.slideshow%</option>
|
||||||
<option value="version">%i18n:common.widgets.version%</option>
|
<option value="version">%i18n:common.widgets.version%</option>
|
||||||
<option value="broadcast">%i18n:common.widgets.broadcast%</option>
|
<option value="broadcast">%i18n:common.widgets.broadcast%</option>
|
||||||
<option value="notifications">%i18n:common.widgets.notifications%</option>
|
<option value="notifications">%i18n:common.widgets.notifications%</option>
|
||||||
<option value="users">%i18n:common.widgets.users%</option>
|
<option value="users">%i18n:common.widgets.users%</option>
|
||||||
<option value="polls">%i18n:common.widgets.polls%</option>
|
<option value="polls">%i18n:common.widgets.polls%</option>
|
||||||
<option value="post-form">%i18n:common.widgets.post-form%</option>
|
<option value="post-form">%i18n:common.widgets.post-form%</option>
|
||||||
<option value="messaging">%i18n:common.widgets.messaging%</option>
|
<option value="messaging">%i18n:common.widgets.messaging%</option>
|
||||||
<option value="memo">%i18n:common.widgets.memo%</option>
|
<option value="memo">%i18n:common.widgets.memo%</option>
|
||||||
<option value="server">%i18n:common.widgets.server%</option>
|
<option value="posts-monitor">%i18n:common.widgets.posts-monitor%</option>
|
||||||
<option value="donation">%i18n:common.widgets.donation%</option>
|
<option value="server">%i18n:common.widgets.server%</option>
|
||||||
<option value="nav">%i18n:common.widgets.nav%</option>
|
<option value="donation">%i18n:common.widgets.donation%</option>
|
||||||
<option value="tips">%i18n:common.widgets.tips%</option>
|
<option value="nav">%i18n:common.widgets.nav%</option>
|
||||||
</select>
|
<option value="tips">%i18n:common.widgets.tips%</option>
|
||||||
<button @click="addWidget">%i18n:@add%</button>
|
</select>
|
||||||
</header>
|
<button @click="addWidget">%i18n:@add%</button>
|
||||||
<x-draggable
|
</header>
|
||||||
:list="column.widgets"
|
<x-draggable
|
||||||
:options="{ handle: '.handle', animation: 150 }"
|
:list="column.widgets"
|
||||||
@sort="onWidgetSort"
|
:options="{ handle: '.handle', animation: 150 }"
|
||||||
>
|
@sort="onWidgetSort"
|
||||||
<div v-for="widget in column.widgets" class="customize-container" :key="widget.id">
|
>
|
||||||
<header>
|
<div v-for="widget in column.widgets" class="customize-container" :key="widget.id">
|
||||||
<span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
|
<header>
|
||||||
</header>
|
<span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
|
||||||
<div @click="widgetFunc(widget.id)">
|
</header>
|
||||||
<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="deck"/>
|
<div @click="widgetFunc(widget.id)">
|
||||||
</div>
|
<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="deck"/>
|
||||||
</div>
|
</div>
|
||||||
</x-draggable>
|
</div>
|
||||||
</template>
|
</x-draggable>
|
||||||
<template v-else>
|
</template>
|
||||||
<component class="widget" v-for="widget in column.widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" platform="deck"/>
|
<template v-else>
|
||||||
</template>
|
<component class="widget" v-for="widget in column.widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" platform="deck"/>
|
||||||
</div>
|
</template>
|
||||||
</x-column>
|
</div>
|
||||||
</div>
|
</x-column>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -70,6 +69,10 @@ export default Vue.extend({
|
|||||||
column: {
|
column: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -81,10 +84,18 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
name(): string {
|
||||||
|
if (this.column.name) return this.column.name;
|
||||||
|
return '%i18n:common.deck.widgets%';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.menu = [{
|
this.menu = [{
|
||||||
content: '%fa:cog% %i18n:@edit%',
|
icon: '%fa:cog%',
|
||||||
onClick: () => {
|
text: '%i18n:@edit%',
|
||||||
|
action: () => {
|
||||||
this.edit = !this.edit;
|
this.edit = !this.edit;
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -32,42 +32,30 @@ body > noscript {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
cursor: wait;
|
cursor: wait;
|
||||||
}
|
}
|
||||||
#ini > p {
|
#ini > svg {
|
||||||
display: block;
|
position: absolute;
|
||||||
user-select: none;
|
top: 0;
|
||||||
margin: 32px;
|
right: 0;
|
||||||
font-size: 4em;
|
bottom: 0;
|
||||||
color: #555;
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
animation: ini 0.6s infinite linear;
|
||||||
}
|
}
|
||||||
#ini > p > span {
|
|
||||||
animation: ini 1.4s infinite ease-in-out both;
|
|
||||||
}
|
|
||||||
#ini > p > span:nth-child(1) {
|
|
||||||
animation-delay: 0s;
|
|
||||||
}
|
|
||||||
#ini > p > span:nth-child(2) {
|
|
||||||
animation-delay: 0.16s;
|
|
||||||
}
|
|
||||||
#ini > p > span:nth-child(3) {
|
|
||||||
animation-delay: 0.32s;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-darkmode] #ini {
|
html[data-darkmode] #ini {
|
||||||
background: #191b22;
|
background: #191b22;
|
||||||
}
|
}
|
||||||
html[data-darkmode] #ini > p {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ini {
|
@keyframes ini {
|
||||||
0%, 80%, 100% {
|
from {
|
||||||
opacity: 1;
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
40% {
|
to {
|
||||||
opacity: 0;
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import Progress from './common/scripts/loading';
|
|||||||
import Connection from './common/scripts/streaming/stream';
|
import Connection from './common/scripts/streaming/stream';
|
||||||
import { HomeStreamManager } from './common/scripts/streaming/home';
|
import { HomeStreamManager } from './common/scripts/streaming/home';
|
||||||
import { DriveStreamManager } from './common/scripts/streaming/drive';
|
import { DriveStreamManager } from './common/scripts/streaming/drive';
|
||||||
import { ServerStreamManager } from './common/scripts/streaming/server';
|
import { ServerStatsStreamManager } from './common/scripts/streaming/server-stats';
|
||||||
|
import { NotesStatsStreamManager } from './common/scripts/streaming/notes-stats';
|
||||||
import { MessagingIndexStreamManager } from './common/scripts/streaming/messaging-index';
|
import { MessagingIndexStreamManager } from './common/scripts/streaming/messaging-index';
|
||||||
import { OthelloStreamManager } from './common/scripts/streaming/othello';
|
import { OthelloStreamManager } from './common/scripts/streaming/othello';
|
||||||
|
|
||||||
@@ -104,14 +105,16 @@ export default class MiOS extends EventEmitter {
|
|||||||
localTimelineStream: LocalTimelineStreamManager;
|
localTimelineStream: LocalTimelineStreamManager;
|
||||||
globalTimelineStream: GlobalTimelineStreamManager;
|
globalTimelineStream: GlobalTimelineStreamManager;
|
||||||
driveStream: DriveStreamManager;
|
driveStream: DriveStreamManager;
|
||||||
serverStream: ServerStreamManager;
|
serverStatsStream: ServerStatsStreamManager;
|
||||||
|
notesStatsStream: NotesStatsStreamManager;
|
||||||
messagingIndexStream: MessagingIndexStreamManager;
|
messagingIndexStream: MessagingIndexStreamManager;
|
||||||
othelloStream: OthelloStreamManager;
|
othelloStream: OthelloStreamManager;
|
||||||
} = {
|
} = {
|
||||||
localTimelineStream: null,
|
localTimelineStream: null,
|
||||||
globalTimelineStream: null,
|
globalTimelineStream: null,
|
||||||
driveStream: null,
|
driveStream: null,
|
||||||
serverStream: null,
|
serverStatsStream: null,
|
||||||
|
notesStatsStream: null,
|
||||||
messagingIndexStream: null,
|
messagingIndexStream: null,
|
||||||
othelloStream: null
|
othelloStream: null
|
||||||
};
|
};
|
||||||
@@ -218,7 +221,8 @@ export default class MiOS extends EventEmitter {
|
|||||||
this.store = initStore(this);
|
this.store = initStore(this);
|
||||||
|
|
||||||
//#region Init stream managers
|
//#region Init stream managers
|
||||||
this.streams.serverStream = new ServerStreamManager(this);
|
this.streams.serverStatsStream = new ServerStatsStreamManager(this);
|
||||||
|
this.streams.notesStatsStream = new NotesStatsStreamManager(this);
|
||||||
|
|
||||||
this.once('signedin', () => {
|
this.once('signedin', () => {
|
||||||
// Init home stream manager
|
// Init home stream manager
|
||||||
|
|||||||
@@ -2,26 +2,7 @@
|
|||||||
<div class="mk-note-preview" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
<div class="mk-note-preview" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/>
|
|
||||||
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="note.user.isAdmin">%i18n:@admin%</span>
|
|
||||||
<span class="is-bot" v-if="note.user.isBot">%i18n:@bot%</span>
|
|
||||||
<span class="is-cat" v-if="note.user.isCat">%i18n:@cat%</span>
|
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="note | notePage">
|
|
||||||
<mk-time :time="note.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="note.visibility != 'public'">
|
|
||||||
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-sub-note-content class="text" :note="note"/>
|
<mk-sub-note-content class="text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -79,64 +60,8 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
margin-bottom 2px
|
margin-bottom 2px
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .avatar
|
|
||||||
flex-shrink 0
|
|
||||||
margin-right 8px
|
|
||||||
width 18px
|
|
||||||
height 18px
|
|
||||||
border-radius 100%
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #607073
|
|
||||||
font-size 1em
|
|
||||||
font-weight 700
|
|
||||||
text-align left
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 6px
|
|
||||||
font-size 0.8em
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
overflow hidden
|
|
||||||
text-overflow ellipsis
|
|
||||||
color isDark ? #606984 : #d1d8da
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #b2b8bb
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
|
|||||||
@@ -2,26 +2,7 @@
|
|||||||
<div class="sub" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
<div class="sub" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/>
|
|
||||||
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="note.user.isAdmin">%i18n:@admin%</span>
|
|
||||||
<span class="is-bot" v-if="note.user.isBot">%i18n:@bot%</span>
|
|
||||||
<span class="is-cat" v-if="note.user.isCat">%i18n:@cat%</span>
|
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="note | notePage">
|
|
||||||
<mk-time :time="note.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="note.visibility != 'public'">
|
|
||||||
<template v-if="note.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="note.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-sub-note-content class="text" :note="note"/>
|
<mk-sub-note-content class="text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,66 +73,8 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
margin-bottom 2px
|
margin-bottom 2px
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
> .avatar
|
|
||||||
flex-shrink 0
|
|
||||||
margin-right 8px
|
|
||||||
width 18px
|
|
||||||
height 18px
|
|
||||||
border-radius 100%
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #607073
|
|
||||||
font-size 1em
|
|
||||||
font-weight 700
|
|
||||||
text-align left
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
text-decoration underline
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 5px
|
|
||||||
font-size 0.8em
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
text-align left
|
|
||||||
margin 0
|
|
||||||
color isDark ? #606984 : #d1d8da
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #b2b8bb
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
|
|
||||||
|
|||||||
@@ -14,26 +14,7 @@
|
|||||||
<article>
|
<article>
|
||||||
<mk-avatar class="avatar" :user="p.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
<mk-avatar class="avatar" :user="p.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<mk-note-header class="header" :note="p" :mini="true"/>
|
||||||
<mk-avatar class="avatar" :user="p.user" v-if="$store.state.device.postStyle == 'smart'"/>
|
|
||||||
<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link>
|
|
||||||
<span class="is-admin" v-if="p.user.isAdmin">admin</span>
|
|
||||||
<span class="is-bot" v-if="p.user.isBot">bot</span>
|
|
||||||
<span class="is-cat" v-if="p.user.isCat">cat</span>
|
|
||||||
<span class="username"><mk-acct :user="p.user"/></span>
|
|
||||||
<div class="info">
|
|
||||||
<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span>
|
|
||||||
<router-link class="created-at" :to="p | notePage">
|
|
||||||
<mk-time :time="p.createdAt"/>
|
|
||||||
</router-link>
|
|
||||||
<span class="visibility" v-if="p.visibility != 'public'">
|
|
||||||
<template v-if="p.visibility == 'home'">%fa:home%</template>
|
|
||||||
<template v-if="p.visibility == 'followers'">%fa:unlock%</template>
|
|
||||||
<template v-if="p.visibility == 'specified'">%fa:envelope%</template>
|
|
||||||
<template v-if="p.visibility == 'private'">%fa:lock%</template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="p.cw != null" class="cw">
|
<p v-if="p.cw != null" class="cw">
|
||||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
||||||
@@ -358,65 +339,10 @@ root(isDark)
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 0
|
min-width 0
|
||||||
|
|
||||||
> header
|
> .header
|
||||||
display flex
|
|
||||||
align-items baseline
|
|
||||||
white-space nowrap
|
|
||||||
|
|
||||||
@media (min-width 500px)
|
@media (min-width 500px)
|
||||||
margin-bottom 2px
|
margin-bottom 2px
|
||||||
|
|
||||||
> .avatar
|
|
||||||
flex-shrink 0
|
|
||||||
margin-right 8px
|
|
||||||
width 20px
|
|
||||||
height 20px
|
|
||||||
border-radius 100%
|
|
||||||
|
|
||||||
> .name
|
|
||||||
display block
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 0
|
|
||||||
overflow hidden
|
|
||||||
color isDark ? #fff : #627079
|
|
||||||
font-weight bold
|
|
||||||
text-decoration none
|
|
||||||
text-overflow ellipsis
|
|
||||||
|
|
||||||
> .is-admin
|
|
||||||
> .is-bot
|
|
||||||
> .is-cat
|
|
||||||
align-self center
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
padding 1px 6px
|
|
||||||
font-size 0.8em
|
|
||||||
color isDark ? #758188 : #aaa
|
|
||||||
border solid 1px isDark ? #57616f : #ddd
|
|
||||||
border-radius 3px
|
|
||||||
|
|
||||||
&.is-admin
|
|
||||||
border-color isDark ? #d42c41 : #f56a7b
|
|
||||||
color isDark ? #d42c41 : #f56a7b
|
|
||||||
|
|
||||||
> .username
|
|
||||||
margin 0 0.5em 0 0
|
|
||||||
overflow hidden
|
|
||||||
text-overflow ellipsis
|
|
||||||
color isDark ? #606984 : #ccc
|
|
||||||
|
|
||||||
> .info
|
|
||||||
margin-left auto
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> *
|
|
||||||
color isDark ? #606984 : #c0c0c0
|
|
||||||
|
|
||||||
> .mobile
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
> .visibility
|
|
||||||
margin-left 6px
|
|
||||||
|
|
||||||
> .body
|
> .body
|
||||||
@media (min-width 700px)
|
@media (min-width 700px)
|
||||||
font-size 1.1em
|
font-size 1.1em
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<option value="rss">%i18n:common.widgets.rss%</option>
|
<option value="rss">%i18n:common.widgets.rss%</option>
|
||||||
<option value="photo-stream">%i18n:common.widgets.photo-stream%</option>
|
<option value="photo-stream">%i18n:common.widgets.photo-stream%</option>
|
||||||
<option value="slideshow">%i18n:common.widgets.slideshow%</option>
|
<option value="slideshow">%i18n:common.widgets.slideshow%</option>
|
||||||
|
<option value="posts-monitor">%i18n:common.widgets.posts-monitor%</option>
|
||||||
<option value="version">%i18n:common.widgets.version%</option>
|
<option value="version">%i18n:common.widgets.version%</option>
|
||||||
<option value="server">%i18n:common.widgets.server%</option>
|
<option value="server">%i18n:common.widgets.server%</option>
|
||||||
<option value="memo">%i18n:common.widgets.memo%</option>
|
<option value="memo">%i18n:common.widgets.memo%</option>
|
||||||
|
|||||||
@@ -173,23 +173,33 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addDeckColumn(state, column) {
|
addDeckColumn(state, column) {
|
||||||
if (state.deck.columns == null) state.deck.columns = [];
|
|
||||||
state.deck.columns.push(column);
|
state.deck.columns.push(column);
|
||||||
|
state.deck.layout.push([column.id]);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeDeckColumn(state, id) {
|
removeDeckColumn(state, id) {
|
||||||
if (state.deck.columns == null) return;
|
|
||||||
state.deck.columns = state.deck.columns.filter(c => c.id != id);
|
state.deck.columns = state.deck.columns.filter(c => c.id != id);
|
||||||
|
state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id));
|
||||||
|
},
|
||||||
|
|
||||||
|
swapDeckColumn(state, x) {
|
||||||
|
const a = x.a;
|
||||||
|
const b = x.b;
|
||||||
|
const aX = state.deck.layout.findIndex(ids => ids.indexOf(a) != -1);
|
||||||
|
const aY = state.deck.layout[aX].findIndex(id => id == a);
|
||||||
|
const bX = state.deck.layout.findIndex(ids => ids.indexOf(b) != -1);
|
||||||
|
const bY = state.deck.layout[bX].findIndex(id => id == b);
|
||||||
|
state.deck.layout[aX][aY] = b;
|
||||||
|
state.deck.layout[bX][bY] = a;
|
||||||
},
|
},
|
||||||
|
|
||||||
swapLeftDeckColumn(state, id) {
|
swapLeftDeckColumn(state, id) {
|
||||||
if (state.deck.columns == null) return;
|
state.deck.layout.some((ids, i) => {
|
||||||
state.deck.columns.some((c, i) => {
|
if (ids.indexOf(id) != -1) {
|
||||||
if (c.id == id) {
|
const left = state.deck.layout[i - 1];
|
||||||
const left = state.deck.columns[i - 1];
|
|
||||||
if (left) {
|
if (left) {
|
||||||
state.deck.columns[i - 1] = state.deck.columns[i];
|
state.deck.layout[i - 1] = state.deck.layout[i];
|
||||||
state.deck.columns[i] = left;
|
state.deck.layout[i] = left;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -197,31 +207,77 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
},
|
},
|
||||||
|
|
||||||
swapRightDeckColumn(state, id) {
|
swapRightDeckColumn(state, id) {
|
||||||
if (state.deck.columns == null) return;
|
state.deck.layout.some((ids, i) => {
|
||||||
state.deck.columns.some((c, i) => {
|
if (ids.indexOf(id) != -1) {
|
||||||
if (c.id == id) {
|
const right = state.deck.layout[i + 1];
|
||||||
const right = state.deck.columns[i + 1];
|
|
||||||
if (right) {
|
if (right) {
|
||||||
state.deck.columns[i + 1] = state.deck.columns[i];
|
state.deck.layout[i + 1] = state.deck.layout[i];
|
||||||
state.deck.columns[i] = right;
|
state.deck.layout[i] = right;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
swapUpDeckColumn(state, id) {
|
||||||
|
const ids = state.deck.layout.find(ids => ids.indexOf(id) != -1);
|
||||||
|
ids.some((x, i) => {
|
||||||
|
if (x == id) {
|
||||||
|
const up = ids[i - 1];
|
||||||
|
if (up) {
|
||||||
|
ids[i - 1] = id;
|
||||||
|
ids[i] = up;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
swapDownDeckColumn(state, id) {
|
||||||
|
const ids = state.deck.layout.find(ids => ids.indexOf(id) != -1);
|
||||||
|
ids.some((x, i) => {
|
||||||
|
if (x == id) {
|
||||||
|
const down = ids[i + 1];
|
||||||
|
if (down) {
|
||||||
|
ids[i + 1] = id;
|
||||||
|
ids[i] = down;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
stackLeftDeckColumn(state, id) {
|
||||||
|
const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1);
|
||||||
|
state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id));
|
||||||
|
const left = state.deck.layout[i - 1];
|
||||||
|
if (left) state.deck.layout[i - 1].push(id);
|
||||||
|
state.deck.layout = state.deck.layout.filter(ids => ids.length > 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
popRightDeckColumn(state, id) {
|
||||||
|
const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1);
|
||||||
|
state.deck.layout = state.deck.layout.map(ids => ids.filter(x => x != id));
|
||||||
|
state.deck.layout.splice(i + 1, 0, [id]);
|
||||||
|
state.deck.layout = state.deck.layout.filter(ids => ids.length > 0);
|
||||||
|
},
|
||||||
|
|
||||||
addDeckWidget(state, x) {
|
addDeckWidget(state, x) {
|
||||||
if (state.deck.columns == null) return;
|
|
||||||
const column = state.deck.columns.find(c => c.id == x.id);
|
const column = state.deck.columns.find(c => c.id == x.id);
|
||||||
if (column == null) return;
|
if (column == null) return;
|
||||||
column.widgets.unshift(x.widget);
|
column.widgets.unshift(x.widget);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeDeckWidget(state, x) {
|
removeDeckWidget(state, x) {
|
||||||
if (state.deck.columns == null) return;
|
|
||||||
const column = state.deck.columns.find(c => c.id == x.id);
|
const column = state.deck.columns.find(c => c.id == x.id);
|
||||||
if (column == null) return;
|
if (column == null) return;
|
||||||
column.widgets = column.widgets.filter(w => w.id != x.widget.id);
|
column.widgets = column.widgets.filter(w => w.id != x.widget.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
renameDeckColumn(state, x) {
|
||||||
|
const column = state.deck.columns.find(c => c.id == x.id);
|
||||||
|
if (column == null) return;
|
||||||
|
column.name = x.name;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -261,6 +317,11 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
ctx.dispatch('saveDeck');
|
ctx.dispatch('saveDeck');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
swapDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('swapDeckColumn', id);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
swapLeftDeckColumn(ctx, id) {
|
swapLeftDeckColumn(ctx, id) {
|
||||||
ctx.commit('swapLeftDeckColumn', id);
|
ctx.commit('swapLeftDeckColumn', id);
|
||||||
ctx.dispatch('saveDeck');
|
ctx.dispatch('saveDeck');
|
||||||
@@ -271,6 +332,26 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
ctx.dispatch('saveDeck');
|
ctx.dispatch('saveDeck');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
swapUpDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('swapUpDeckColumn', id);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
|
swapDownDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('swapDownDeckColumn', id);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
|
stackLeftDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('stackLeftDeckColumn', id);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
|
popRightDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('popRightDeckColumn', id);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
addDeckWidget(ctx, x) {
|
addDeckWidget(ctx, x) {
|
||||||
ctx.commit('addDeckWidget', x);
|
ctx.commit('addDeckWidget', x);
|
||||||
ctx.dispatch('saveDeck');
|
ctx.dispatch('saveDeck');
|
||||||
@@ -281,6 +362,11 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
ctx.dispatch('saveDeck');
|
ctx.dispatch('saveDeck');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renameDeckColumn(ctx, x) {
|
||||||
|
ctx.commit('renameDeckColumn', x);
|
||||||
|
ctx.dispatch('saveDeck');
|
||||||
|
},
|
||||||
|
|
||||||
addHomeWidget(ctx, widget) {
|
addHomeWidget(ctx, widget) {
|
||||||
ctx.commit('addHomeWidget', widget);
|
ctx.commit('addHomeWidget', widget);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ const uri = u && p
|
|||||||
*/
|
*/
|
||||||
import mongo from 'monk';
|
import mongo from 'monk';
|
||||||
|
|
||||||
const db = mongo(uri);
|
const db = mongo(uri, {
|
||||||
|
poolSize: 16,
|
||||||
|
keepAlive: 1
|
||||||
|
});
|
||||||
|
|
||||||
export default db;
|
export default db;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import ProgressBar from './utils/cli/progressbar';
|
|||||||
import EnvironmentInfo from './utils/environmentInfo';
|
import EnvironmentInfo from './utils/environmentInfo';
|
||||||
import MachineInfo from './utils/machineInfo';
|
import MachineInfo from './utils/machineInfo';
|
||||||
import DependencyInfo from './utils/dependencyInfo';
|
import DependencyInfo from './utils/dependencyInfo';
|
||||||
import stats from './utils/stats';
|
import serverStats from './server-stats';
|
||||||
|
import notesStats from './notes-stats';
|
||||||
|
|
||||||
import loadConfig from './config/load';
|
import loadConfig from './config/load';
|
||||||
import { Config } from './config/types';
|
import { Config } from './config/types';
|
||||||
@@ -49,7 +50,8 @@ function main() {
|
|||||||
masterMain(opt);
|
masterMain(opt);
|
||||||
|
|
||||||
ev.mount();
|
ev.mount();
|
||||||
stats();
|
serverStats();
|
||||||
|
notesStats();
|
||||||
} else {
|
} else {
|
||||||
workerMain(opt);
|
workerMain(opt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ import Following from './following';
|
|||||||
const Note = db.get<INote>('notes');
|
const Note = db.get<INote>('notes');
|
||||||
Note.createIndex('uri', { sparse: true, unique: true });
|
Note.createIndex('uri', { sparse: true, unique: true });
|
||||||
Note.createIndex('userId');
|
Note.createIndex('userId');
|
||||||
|
Note.createIndex({
|
||||||
|
createdAt: -1
|
||||||
|
});
|
||||||
export default Note;
|
export default Note;
|
||||||
|
|
||||||
export function isValidText(text: string): boolean {
|
export function isValidText(text: string): boolean {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type IUserBase = {
|
|||||||
usernameLower: string;
|
usernameLower: string;
|
||||||
avatarId: mongo.ObjectID;
|
avatarId: mongo.ObjectID;
|
||||||
bannerId: mongo.ObjectID;
|
bannerId: mongo.ObjectID;
|
||||||
|
wallpaperId: mongo.ObjectID;
|
||||||
data: any;
|
data: any;
|
||||||
description: string;
|
description: string;
|
||||||
pinnedNoteId: mongo.ObjectID;
|
pinnedNoteId: mongo.ObjectID;
|
||||||
@@ -412,6 +413,10 @@ export const pack = (
|
|||||||
? `${config.drive_url}/${_user.bannerId}`
|
? `${config.drive_url}/${_user.bannerId}`
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
_user.wallpaperUrl = _user.wallpaperId != null
|
||||||
|
? `${config.drive_url}/${_user.wallpaperId}`
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!meId || !meId.equals(_user.id) || !opts.detail) {
|
if (!meId || !meId.equals(_user.id) || !opts.detail) {
|
||||||
delete _user.avatarId;
|
delete _user.avatarId;
|
||||||
delete _user.bannerId;
|
delete _user.bannerId;
|
||||||
|
|||||||
22
src/notes-stats-child.ts
Normal file
22
src/notes-stats-child.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import Note from './models/note';
|
||||||
|
|
||||||
|
const interval = 5000;
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
const [all, local] = await Promise.all([Note.count({
|
||||||
|
createdAt: {
|
||||||
|
$gte: new Date(Date.now() - interval)
|
||||||
|
}
|
||||||
|
}), Note.count({
|
||||||
|
createdAt: {
|
||||||
|
$gte: new Date(Date.now() - interval)
|
||||||
|
},
|
||||||
|
'_user.host': null
|
||||||
|
})]);
|
||||||
|
|
||||||
|
const stats = {
|
||||||
|
all, local
|
||||||
|
};
|
||||||
|
|
||||||
|
process.send(stats);
|
||||||
|
}, interval);
|
||||||
20
src/notes-stats.ts
Normal file
20
src/notes-stats.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import * as childProcess from 'child_process';
|
||||||
|
import Xev from 'xev';
|
||||||
|
|
||||||
|
const ev = new Xev();
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
const log = [];
|
||||||
|
|
||||||
|
const p = childProcess.fork(__dirname + '/notes-stats-child.js');
|
||||||
|
|
||||||
|
p.on('message', stats => {
|
||||||
|
ev.emit('notesStats', stats);
|
||||||
|
log.push(stats);
|
||||||
|
if (log.length > 100) log.shift();
|
||||||
|
});
|
||||||
|
|
||||||
|
ev.on('requestNotesStatsLog', id => {
|
||||||
|
ev.emit('notesStatsLog:' + id, log);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -6,13 +6,19 @@ import Xev from 'xev';
|
|||||||
const ev = new Xev();
|
const ev = new Xev();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report stats regularly
|
* Report server stats regularly
|
||||||
*/
|
*/
|
||||||
export default function() {
|
export default function() {
|
||||||
|
const log = [];
|
||||||
|
|
||||||
|
ev.on('requestServerStatsLog', id => {
|
||||||
|
ev.emit('serverStatsLog:' + id, log);
|
||||||
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
osUtils.cpuUsage(cpuUsage => {
|
osUtils.cpuUsage(cpuUsage => {
|
||||||
const disk = diskusage.checkSync(os.platform() == 'win32' ? 'c:' : '/');
|
const disk = diskusage.checkSync(os.platform() == 'win32' ? 'c:' : '/');
|
||||||
ev.emit('stats', {
|
const stats = {
|
||||||
cpu_usage: cpuUsage,
|
cpu_usage: cpuUsage,
|
||||||
mem: {
|
mem: {
|
||||||
total: os.totalmem(),
|
total: os.totalmem(),
|
||||||
@@ -21,7 +27,10 @@ export default function() {
|
|||||||
disk,
|
disk,
|
||||||
os_uptime: os.uptime(),
|
os_uptime: os.uptime(),
|
||||||
process_uptime: process.uptime()
|
process_uptime: process.uptime()
|
||||||
});
|
};
|
||||||
|
ev.emit('serverStats', stats);
|
||||||
|
log.push(stats);
|
||||||
|
if (log.length > 50) log.shift();
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,11 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
|
|||||||
if (bannerIdErr) return rej('invalid bannerId param');
|
if (bannerIdErr) return rej('invalid bannerId param');
|
||||||
if (bannerId !== undefined) updates.bannerId = bannerId;
|
if (bannerId !== undefined) updates.bannerId = bannerId;
|
||||||
|
|
||||||
|
// Get 'wallpaperId' parameter
|
||||||
|
const [wallpaperId, wallpaperIdErr] = $.type(ID).optional().nullable().get(params.wallpaperId);
|
||||||
|
if (wallpaperIdErr) return rej('invalid wallpaperId param');
|
||||||
|
if (wallpaperId !== undefined) updates.wallpaperId = wallpaperId;
|
||||||
|
|
||||||
// Get 'isLocked' parameter
|
// Get 'isLocked' parameter
|
||||||
const [isLocked, isLockedErr] = $.bool.optional().get(params.isLocked);
|
const [isLocked, isLockedErr] = $.bool.optional().get(params.isLocked);
|
||||||
if (isLockedErr) return rej('invalid isLocked param');
|
if (isLockedErr) return rej('invalid isLocked param');
|
||||||
@@ -85,6 +90,16 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallpaperId) {
|
||||||
|
const wallpaper = await DriveFile.findOne({
|
||||||
|
_id: wallpaperId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (wallpaper != null && wallpaper.metadata.properties.avgColor) {
|
||||||
|
updates.wallpaperColor = wallpaper.metadata.properties.avgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: updates
|
$set: updates
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// テキストが無いかつ添付ファイルが無いかつRenoteも無いかつ投票も無かったらエラー
|
// テキストが無いかつ添付ファイルが無いかつRenoteも無いかつ投票も無かったらエラー
|
||||||
if (text === undefined && files === null && renote === null && poll === undefined) {
|
if ((text === undefined || text === null) && files === null && renote === null && poll === undefined) {
|
||||||
return rej('text, mediaIds, renoteId or poll is required');
|
return rej('text, mediaIds, renoteId or poll is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ module.exports = async (params, user) => {
|
|||||||
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
|
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get 'mediaOnly' parameter
|
||||||
|
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
|
||||||
|
if (mediaOnlyErr) throw 'invalid mediaOnly param';
|
||||||
|
|
||||||
// ミュートしているユーザーを取得
|
// ミュートしているユーザーを取得
|
||||||
const mutedUserIds = user ? (await Mute.find({
|
const mutedUserIds = user ? (await Mute.find({
|
||||||
muterId: user._id
|
muterId: user._id
|
||||||
@@ -64,6 +68,10 @@ module.exports = async (params, user) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediaOnly) {
|
||||||
|
query.mediaIds = { $exists: true, $ne: [] };
|
||||||
|
}
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
query._id = {
|
query._id = {
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ module.exports = async (params, user) => {
|
|||||||
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
|
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get 'mediaOnly' parameter
|
||||||
|
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
|
||||||
|
if (mediaOnlyErr) throw 'invalid mediaOnly param';
|
||||||
|
|
||||||
// ミュートしているユーザーを取得
|
// ミュートしているユーザーを取得
|
||||||
const mutedUserIds = user ? (await Mute.find({
|
const mutedUserIds = user ? (await Mute.find({
|
||||||
muterId: user._id
|
muterId: user._id
|
||||||
@@ -67,6 +71,10 @@ module.exports = async (params, user) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediaOnly) {
|
||||||
|
query.mediaIds = { $exists: true, $ne: [] };
|
||||||
|
}
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
query._id = {
|
query._id = {
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
|
|||||||
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
|
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
|
||||||
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
|
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
|
||||||
|
|
||||||
|
// Get 'mediaOnly' parameter
|
||||||
|
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
|
||||||
|
if (mediaOnlyErr) throw 'invalid mediaOnly param';
|
||||||
|
|
||||||
const [followings, mutedUserIds] = await Promise.all([
|
const [followings, mutedUserIds] = await Promise.all([
|
||||||
// フォローを取得
|
// フォローを取得
|
||||||
// Fetch following
|
// Fetch following
|
||||||
@@ -137,6 +141,12 @@ module.exports = async (params, user, app) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediaOnly) {
|
||||||
|
query.$and.push({
|
||||||
|
mediaIds: { $exists: true, $ne: [] }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
query._id = {
|
query._id = {
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
|
|||||||
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
|
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
|
||||||
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
|
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
|
||||||
|
|
||||||
|
// Get 'mediaOnly' parameter
|
||||||
|
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
|
||||||
|
if (mediaOnlyErr) throw 'invalid mediaOnly param';
|
||||||
|
|
||||||
// Get 'listId' parameter
|
// Get 'listId' parameter
|
||||||
const [listId, listIdErr] = $.type(ID).get(params.listId);
|
const [listId, listIdErr] = $.type(ID).get(params.listId);
|
||||||
if (listIdErr) throw 'invalid listId param';
|
if (listIdErr) throw 'invalid listId param';
|
||||||
@@ -146,6 +150,12 @@ module.exports = async (params, user, app) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediaOnly) {
|
||||||
|
query.$and.push({
|
||||||
|
mediaIds: { $exists: true, $ne: [] }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
query._id = {
|
query._id = {
|
||||||
|
|||||||
35
src/server/api/stream/notes-stats.ts
Normal file
35
src/server/api/stream/notes-stats.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import * as websocket from 'websocket';
|
||||||
|
import Xev from 'xev';
|
||||||
|
|
||||||
|
const ev = new Xev();
|
||||||
|
|
||||||
|
export default function(request: websocket.request, connection: websocket.connection): void {
|
||||||
|
const onStats = stats => {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: 'stats',
|
||||||
|
body: stats
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
connection.on('message', async data => {
|
||||||
|
const msg = JSON.parse(data.utf8Data);
|
||||||
|
|
||||||
|
switch (msg.type) {
|
||||||
|
case 'requestLog':
|
||||||
|
ev.once('notesStatsLog:' + msg.id, statsLog => {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: 'statsLog',
|
||||||
|
body: statsLog
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
ev.emit('requestNotesStatsLog', msg.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ev.addListener('notesStats', onStats);
|
||||||
|
|
||||||
|
connection.on('close', () => {
|
||||||
|
ev.removeListener('notesStats', onStats);
|
||||||
|
});
|
||||||
|
}
|
||||||
35
src/server/api/stream/server-stats.ts
Normal file
35
src/server/api/stream/server-stats.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import * as websocket from 'websocket';
|
||||||
|
import Xev from 'xev';
|
||||||
|
|
||||||
|
const ev = new Xev();
|
||||||
|
|
||||||
|
export default function(request: websocket.request, connection: websocket.connection): void {
|
||||||
|
const onStats = stats => {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: 'stats',
|
||||||
|
body: stats
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
connection.on('message', async data => {
|
||||||
|
const msg = JSON.parse(data.utf8Data);
|
||||||
|
|
||||||
|
switch (msg.type) {
|
||||||
|
case 'requestLog':
|
||||||
|
ev.once('serverStatsLog:' + msg.id, statsLog => {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: 'statsLog',
|
||||||
|
body: statsLog
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
ev.emit('requestServerStatsLog', msg.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ev.addListener('serverStats', onStats);
|
||||||
|
|
||||||
|
connection.on('close', () => {
|
||||||
|
ev.removeListener('serverStats', onStats);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import * as websocket from 'websocket';
|
|
||||||
import Xev from 'xev';
|
|
||||||
|
|
||||||
const ev = new Xev();
|
|
||||||
|
|
||||||
export default function(request: websocket.request, connection: websocket.connection): void {
|
|
||||||
const onStats = stats => {
|
|
||||||
connection.send(JSON.stringify({
|
|
||||||
type: 'stats',
|
|
||||||
body: stats
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
ev.addListener('stats', onStats);
|
|
||||||
|
|
||||||
connection.on('close', () => {
|
|
||||||
ev.removeListener('stats', onStats);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,8 @@ import messagingStream from './stream/messaging';
|
|||||||
import messagingIndexStream from './stream/messaging-index';
|
import messagingIndexStream from './stream/messaging-index';
|
||||||
import othelloGameStream from './stream/othello-game';
|
import othelloGameStream from './stream/othello-game';
|
||||||
import othelloStream from './stream/othello';
|
import othelloStream from './stream/othello';
|
||||||
import serverStream from './stream/server';
|
import serverStatsStream from './stream/server-stats';
|
||||||
|
import notesStatsStream from './stream/notes-stats';
|
||||||
import requestsStream from './stream/requests';
|
import requestsStream from './stream/requests';
|
||||||
import { ParsedUrlQuery } from 'querystring';
|
import { ParsedUrlQuery } from 'querystring';
|
||||||
import authenticate from './authenticate';
|
import authenticate from './authenticate';
|
||||||
@@ -28,8 +29,13 @@ module.exports = (server: http.Server) => {
|
|||||||
ws.on('request', async (request) => {
|
ws.on('request', async (request) => {
|
||||||
const connection = request.accept();
|
const connection = request.accept();
|
||||||
|
|
||||||
if (request.resourceURL.pathname === '/server') {
|
if (request.resourceURL.pathname === '/server-stats') {
|
||||||
serverStream(request, connection);
|
serverStatsStream(request, connection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.resourceURL.pathname === '/notes-stats') {
|
||||||
|
notesStatsStream(request, connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,8 +164,8 @@ export default async function(
|
|||||||
'metadata.deletedAt': { $exists: false }
|
'metadata.deletedAt': { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (much !== null) {
|
if (much) {
|
||||||
log('file with same hash is found');
|
log(`file with same hash is found: ${much._id}`);
|
||||||
return much;
|
return much;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user