Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
19bdd4fa2a | ||
![]() |
9d8391583f | ||
![]() |
6037b0acc5 | ||
![]() |
09c5efc161 | ||
![]() |
16c2aefe7b | ||
![]() |
06cfa207fc | ||
![]() |
0be8bbc19f | ||
![]() |
bad85375de | ||
![]() |
6c11a7a6c4 | ||
![]() |
6f38c6f339 | ||
![]() |
fb1d727db9 | ||
![]() |
d98d286dc4 | ||
![]() |
1be279dbaa | ||
![]() |
90e6feeb4c | ||
![]() |
f1f9f235c7 | ||
![]() |
eb3f938281 | ||
![]() |
d6ef923134 | ||
![]() |
5b01577810 | ||
![]() |
2a111d472a | ||
![]() |
a8809e89b9 | ||
![]() |
1ab9a49d01 | ||
![]() |
f92c116564 | ||
![]() |
b54539b647 | ||
![]() |
87fc6522fb | ||
![]() |
b0408d1d6e | ||
![]() |
39779ca8d5 | ||
![]() |
8c34f7559d | ||
![]() |
740c7c2476 | ||
![]() |
abd43dd471 | ||
![]() |
c24b5410bc | ||
![]() |
cde7d0f463 | ||
![]() |
54548c3ed0 | ||
![]() |
221d1edf0f | ||
![]() |
02e75f9539 | ||
![]() |
6bed2ff106 | ||
![]() |
f3e1e4d1da | ||
![]() |
370f6384d9 | ||
![]() |
0105587d04 | ||
![]() |
e327970ab9 | ||
![]() |
9e247f39ff | ||
![]() |
6ba4fa50b9 | ||
![]() |
f5e130f2a6 | ||
![]() |
cd5dcd87b0 | ||
![]() |
54f319af0e | ||
![]() |
96949059cf | ||
![]() |
763368db99 | ||
![]() |
f622ea654f | ||
![]() |
70c4e6c287 | ||
![]() |
d7692e875a | ||
![]() |
0a94010668 | ||
![]() |
d45121a93b | ||
![]() |
a55e3fb225 | ||
![]() |
426b2f5858 | ||
![]() |
3d10b5e538 | ||
![]() |
b639599620 | ||
![]() |
63c51c6ee0 | ||
![]() |
f39934c274 | ||
![]() |
adec1643bf | ||
![]() |
229ea7d3ab | ||
![]() |
03899f042d |
18
README.md
18
README.md
@@ -5,8 +5,6 @@
|
||||
|
||||
[![][travis-badge]][travis-link]
|
||||
[![][dependencies-badge]][dependencies-link]
|
||||
[![][himawari-badge]][himasaku]
|
||||
[![][sakurako-badge]][himasaku]
|
||||
[](http://makeapullrequest.com) [](https://greenkeeper.io/)
|
||||
|
||||
> Lead Maintainer: [syuilo][syuilo-link]
|
||||
@@ -49,9 +47,9 @@ If you want to...
|
||||
[![Backers][backers-image]][support-url]
|
||||
[![Sponsors][sponsors-image]][support-url]
|
||||
|
||||
| ![][ooo-icon] |
|
||||
|:-:|
|
||||
| [ooo][ooo-link] |
|
||||
| ![][nagarus-icon] | ![][dansup-icon] |
|
||||
|:-:|:-:|
|
||||
| [nagarus][nagarus-link] | [dansup][dansup-link] |
|
||||
|
||||
:four_leaf_clover: Copyright
|
||||
----------------------------------------------------------------
|
||||
@@ -67,9 +65,6 @@ Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
|
||||
[travis-badge]: http://img.shields.io/travis/syuilo/misskey/master.svg?style=flat-square
|
||||
[dependencies-link]: https://david-dm.org/syuilo/misskey
|
||||
[dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square
|
||||
[himasaku]: https://himasaku.net
|
||||
[himawari-badge]: https://img.shields.io/badge/%E5%8F%A4%E8%B0%B7-%E5%90%91%E6%97%A5%E8%91%B5-1684c5.svg?style=flat-square
|
||||
[sakurako-badge]: https://img.shields.io/badge/%E5%A4%A7%E5%AE%A4-%E6%AB%BB%E5%AD%90-efb02a.svg?style=flat-square
|
||||
|
||||
[backer-url]: #backers
|
||||
[backer-badge]: https://opencollective.com/misskey/backers/badge.svg
|
||||
@@ -82,5 +77,8 @@ Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
|
||||
[syuilo-link]: https://syuilo.com
|
||||
[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
|
||||
|
||||
[ooo-link]: https://www.patreon.com/user/creators?u=11601413
|
||||
[ooo-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/11601413/20cb15f209924302b399b99d3c98b850?token-time=2145916800&token-hash=IO31nK6VZCMWBWU2VAk2c824BX2QZ4DNPKyHHZXS0iw%3D
|
||||
[nagarus-link]: https://www.patreon.com/user/creators?u=11601413
|
||||
[nagarus-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/11601413/20cb15f209924302b399b99d3c98b850?token-time=2145916800&token-hash=IO31nK6VZCMWBWU2VAk2c824BX2QZ4DNPKyHHZXS0iw%3D
|
||||
[dansup-link]: https://www.patreon.com/dansup
|
||||
[dansup-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb?token-time=2145916800&token-hash=opXAM_pnhUTuN1jCA6p_Nn_YsaqohY465YFjWFqMEEE%3D
|
||||
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "Löschen"
|
||||
loading: "Laden"
|
||||
ok: "OK"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden"
|
||||
my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet."
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "Delete"
|
||||
loading: "Loading"
|
||||
ok: "OK"
|
||||
update-available-title: "Update available"
|
||||
update-available: "A new version of Misskey is now available({newer}, the current version is {current}). Reload the page to apply updates."
|
||||
my-token-regenerated: "Your token has been renewed so you will be signed out."
|
||||
i-like-sushi: "I like sushi rather than pudding"
|
||||
@@ -229,7 +230,7 @@ common/views/widgets/posts-monitor.vue:
|
||||
common/views/widgets/hashtags.vue:
|
||||
title: "Hashtags"
|
||||
count: "{} users mentioned"
|
||||
empty: "トレンドなし"
|
||||
empty: "No trend"
|
||||
common/views/widgets/server.vue:
|
||||
title: "Server info"
|
||||
toggle: "Toggle views"
|
||||
@@ -318,7 +319,7 @@ desktop/views/components/drive.vue:
|
||||
desktop/views/components/follow-button.vue:
|
||||
following: "Following"
|
||||
follow: "Follow"
|
||||
request-pending: "フォロー許可待ち"
|
||||
request-pending: "Pending follow request"
|
||||
follow-request: "Follow request"
|
||||
desktop/views/components/followers-window.vue:
|
||||
followers: "{}'s followers"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "Frequently replied"
|
||||
loading: "Loading"
|
||||
no-users: "No users"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "This account has been suspended."
|
||||
is-remote: "This user is a remote user, so the information is not accurate. "
|
||||
view-remote: "See accurate information"
|
||||
@@ -697,7 +698,7 @@ mobile/views/components/drive.file-detail.vue:
|
||||
mobile/views/components/follow-button.vue:
|
||||
following: "Following"
|
||||
follow: "Follow"
|
||||
request-pending: "フォロー許可待ち"
|
||||
request-pending: "Pending follow request"
|
||||
follow-request: "Follow request"
|
||||
mobile/views/components/friends-maker.vue:
|
||||
title: "Let's follow users"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "eliminar"
|
||||
loading: "cargando"
|
||||
ok: "OK"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Hay disponible una nueva versión de Misskey ({newer}, la versión actual es {current}). Refresca la página para aplicar las actualizaciones."
|
||||
my-token-regenerated: "Tu token se ha regenerado vas a ser desconectado."
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "Supprimer"
|
||||
loading: "Chargement"
|
||||
ok: "OK"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
|
||||
my-token-regenerated: "Votre token vient d'être généré, vous allez maintenant être déconnecté."
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,9 +621,9 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "Personnes qui répondent le plus"
|
||||
loading: "Chargement en cours"
|
||||
no-users: "Pas d'utilisateurs"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
is-suspended: "This account has been suspended."
|
||||
is-remote: "Cet utilisateur n'est pas un utilisateur de Misskey. Certaines informations peuvent être erronées "
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "Cet utilisateur n'est pas un utilisateur de Misskey. Certaines informations peuvent être erronées"
|
||||
view-remote: "Voir les informations détaillées"
|
||||
desktop/views/pages/user/user.home.vue:
|
||||
last-used-at: "Last used at"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "Usuń"
|
||||
loading: "Ładowanie"
|
||||
ok: "OK"
|
||||
update-available-title: "Aktualizacja jest dostępna"
|
||||
update-available: "Nowa wersja Misskey jest dostępna ({newer}, obecna to {current}). Odśwież stronę, aby zastosować aktualizację."
|
||||
my-token-regenerated: "Twój token został wygenerowany. Zostaniesz wylogowany."
|
||||
i-like-sushi: "Wolę sushi od puddingu"
|
||||
@@ -86,8 +87,8 @@ common:
|
||||
remove: "Usuń"
|
||||
add-column: "Dodaj kolumnę"
|
||||
rename: "Zmień nazwę"
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
stack-left: "Przypnij do lewej"
|
||||
pop-right: "Odepnij w prawo"
|
||||
common/views/components/connect-failed.vue:
|
||||
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."
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "Najbardziej aktywni"
|
||||
loading: "Ładowanie"
|
||||
no-users: "Brak użytkowników"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "To konto zostało zawieszone."
|
||||
is-remote: "To jest użytkownik zdalnej instancji, informacje mogą nie być w pełni dokładne."
|
||||
view-remote: "Wyświetl dokładne informacje"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
@@ -45,6 +45,7 @@ common:
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
update-available-title: "更新があります"
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
@@ -620,7 +621,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
title: "よく話すユーザー"
|
||||
loading: "読み込み中"
|
||||
no-users: "よく話すユーザーはいません"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
is-remote: "このユーザーはリモートユーザーです。"
|
||||
view-remote: "正確な情報を見る"
|
||||
|
16
package.json
16
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "4.5.0",
|
||||
"clientVersion": "1.0.6668",
|
||||
"version": "4.7.0",
|
||||
"clientVersion": "1.0.6728",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
@@ -49,20 +49,20 @@
|
||||
"@types/js-yaml": "3.11.1",
|
||||
"@types/jsdom": "11.0.6",
|
||||
"@types/koa": "2.0.46",
|
||||
"@types/koa-bodyparser": "4.2.0",
|
||||
"@types/koa-bodyparser": "5.0.0",
|
||||
"@types/koa-compress": "2.0.8",
|
||||
"@types/koa-favicon": "2.0.19",
|
||||
"@types/koa-logger": "3.1.0",
|
||||
"@types/koa-mount": "3.0.1",
|
||||
"@types/koa-multer": "1.0.0",
|
||||
"@types/koa-router": "7.0.28",
|
||||
"@types/koa-router": "7.0.30",
|
||||
"@types/koa-send": "4.1.1",
|
||||
"@types/koa-views": "2.0.3",
|
||||
"@types/koa__cors": "2.2.2",
|
||||
"@types/kue": "0.11.9",
|
||||
"@types/license-checker": "15.0.0",
|
||||
"@types/mkdirp": "0.5.2",
|
||||
"@types/mocha": "5.2.2",
|
||||
"@types/mocha": "5.2.3",
|
||||
"@types/mongodb": "3.0.21",
|
||||
"@types/ms": "0.7.30",
|
||||
"@types/node": "10.3.4",
|
||||
@@ -80,7 +80,7 @@
|
||||
"@types/speakeasy": "2.0.2",
|
||||
"@types/tmp": "0.0.33",
|
||||
"@types/uuid": "3.4.3",
|
||||
"@types/webpack": "4.4.1",
|
||||
"@types/webpack": "4.4.2",
|
||||
"@types/webpack-stream": "3.2.10",
|
||||
"@types/websocket": "0.0.39",
|
||||
"@types/ws": "5.1.2",
|
||||
@@ -193,7 +193,7 @@
|
||||
"textarea-caret": "3.1.0",
|
||||
"tmp": "0.0.33",
|
||||
"ts-loader": "4.4.1",
|
||||
"ts-node": "6.1.1",
|
||||
"ts-node": "6.1.2",
|
||||
"tslint": "5.10.0",
|
||||
"typescript": "2.9.2",
|
||||
"typescript-eslint-parser": "16.0.0",
|
||||
@@ -211,7 +211,7 @@
|
||||
"vuedraggable": "2.16.0",
|
||||
"vuex": "3.0.1",
|
||||
"vuex-persistedstate": "^2.5.4",
|
||||
"web-push": "3.3.1",
|
||||
"web-push": "3.3.2",
|
||||
"webfinger.js": "2.6.6",
|
||||
"webpack": "4.12.0",
|
||||
"webpack-cli": "3.0.8",
|
||||
|
@@ -1,16 +0,0 @@
|
||||
export default function(note) {
|
||||
if (note.text == null) return true;
|
||||
|
||||
let txt = note.text;
|
||||
|
||||
if (note.media) {
|
||||
note.media.forEach(file => {
|
||||
txt = txt.replace(file.url, '');
|
||||
if (file.src) txt = txt.replace(file.src, '');
|
||||
});
|
||||
|
||||
if (txt == '') return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@@ -20,34 +20,6 @@ export default function(type, data): Notification {
|
||||
icon: data.url + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'mention':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんから:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'reply':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんから返信:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'quote':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんが引用:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'reaction':
|
||||
return {
|
||||
title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`,
|
||||
body: getNoteSummary(data.note),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'unread_messaging_message':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんからメッセージ:`,
|
||||
@@ -62,6 +34,40 @@ export default function(type, data): Notification {
|
||||
icon: data.parent.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'notification':
|
||||
switch (data.type) {
|
||||
case 'mention':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんから:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'reply':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんから返信:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'quote':
|
||||
return {
|
||||
title: `${getUserName(data.user)}さんが引用:`,
|
||||
body: getNoteSummary(data),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
case 'reaction':
|
||||
return {
|
||||
title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`,
|
||||
body: getNoteSummary(data.note),
|
||||
icon: data.user.avatarUrl + '?thumbnail&size=64'
|
||||
};
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ root(isDark)
|
||||
> .is-admin
|
||||
> .is-bot
|
||||
> .is-cat
|
||||
flex-shrink 0
|
||||
align-self center
|
||||
margin 0 .5em 0 0
|
||||
padding 1px 6px
|
||||
@@ -89,6 +90,7 @@ root(isDark)
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
color isDark ? #606984 : #ccc
|
||||
flex-shrink 10000
|
||||
|
||||
> .info
|
||||
margin-left auto
|
||||
|
@@ -24,6 +24,13 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
max: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
@@ -37,6 +44,7 @@ export default Vue.extend({
|
||||
fetch(cb?) {
|
||||
this.fetching = true;
|
||||
(this as any).api('notes', {
|
||||
limit: this.max,
|
||||
local: true,
|
||||
reply: false,
|
||||
renote: false,
|
||||
|
@@ -6,7 +6,9 @@
|
||||
<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
|
||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||
<p class="empty" v-else-if="stats.length == 0">%fa:exclamation-circle%%i18n:@empty%</p>
|
||||
<transition-group v-else tag="div" name="chart">
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!-- <transition-group v-else tag="div" name="chart"> -->
|
||||
<div>
|
||||
<div v-for="stat in stats" :key="stat.tag">
|
||||
<div class="tag">
|
||||
<router-link :to="`/tags/${ stat.tag }`" :title="stat.tag">#{{ stat.tag }}</router-link>
|
||||
@@ -14,7 +16,8 @@
|
||||
</div>
|
||||
<x-chart class="chart" :src="stat.chart"/>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
<!-- </transition-group> -->
|
||||
</div>
|
||||
</mk-widget-container>
|
||||
</div>
|
||||
|
@@ -115,6 +115,15 @@ function registerNotifications(stream: HomeStreamManager) {
|
||||
});
|
||||
|
||||
function attach(connection) {
|
||||
connection.on('notification', notification => {
|
||||
const _n = composeNotification('notification', notification);
|
||||
const n = new Notification(_n.title, {
|
||||
body: _n.body,
|
||||
icon: _n.icon
|
||||
});
|
||||
setTimeout(n.close.bind(n), 6000);
|
||||
});
|
||||
|
||||
connection.on('drive_file_created', file => {
|
||||
const _n = composeNotification('drive_file_created', file);
|
||||
const n = new Notification(_n.title, {
|
||||
@@ -124,33 +133,6 @@ function registerNotifications(stream: HomeStreamManager) {
|
||||
setTimeout(n.close.bind(n), 5000);
|
||||
});
|
||||
|
||||
connection.on('mention', note => {
|
||||
const _n = composeNotification('mention', note);
|
||||
const n = new Notification(_n.title, {
|
||||
body: _n.body,
|
||||
icon: _n.icon
|
||||
});
|
||||
setTimeout(n.close.bind(n), 6000);
|
||||
});
|
||||
|
||||
connection.on('reply', note => {
|
||||
const _n = composeNotification('reply', note);
|
||||
const n = new Notification(_n.title, {
|
||||
body: _n.body,
|
||||
icon: _n.icon
|
||||
});
|
||||
setTimeout(n.close.bind(n), 6000);
|
||||
});
|
||||
|
||||
connection.on('quote', note => {
|
||||
const _n = composeNotification('quote', note);
|
||||
const n = new Notification(_n.title, {
|
||||
body: _n.body,
|
||||
icon: _n.icon
|
||||
});
|
||||
setTimeout(n.close.bind(n), 6000);
|
||||
});
|
||||
|
||||
connection.on('unread_messaging_message', message => {
|
||||
const _n = composeNotification('unread_messaging_message', message);
|
||||
const n = new Notification(_n.title, {
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<a class="rp" v-if="p.renote">RP:</a>
|
||||
</div>
|
||||
<div class="media" v-if="p.media.length > 0">
|
||||
@@ -75,7 +75,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import dateStringify from '../../../common/scripts/date-stringify';
|
||||
import canHideText from '../../../common/scripts/can-hide-text';
|
||||
import parse from '../../../../../mfm/parse';
|
||||
|
||||
import MkPostFormWindow from './post-form-window.vue';
|
||||
@@ -190,8 +189,6 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
canHideText,
|
||||
|
||||
capture(withHandler = false) {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection.send({
|
||||
@@ -473,10 +470,10 @@ root(isDark)
|
||||
|
||||
> *
|
||||
display inline-block
|
||||
margin 0 8px 0 0
|
||||
margin 0 0 4px 6px
|
||||
padding 2px 8px 2px 16px
|
||||
font-size 90%
|
||||
color #8d969e
|
||||
color $theme-color
|
||||
background isDark ? #313543 : #edf0f3
|
||||
border-radius 4px
|
||||
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!--<transition-group name="mk-notes" class="transition">-->
|
||||
<div class="notes">
|
||||
<template v-for="(note, i) in _notes">
|
||||
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
|
||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||
@@ -18,6 +19,7 @@
|
||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
<!--</transition-group>-->
|
||||
|
||||
<footer v-if="more">
|
||||
@@ -222,6 +224,7 @@ root(isDark)
|
||||
> *
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> .notes
|
||||
> .date
|
||||
display block
|
||||
margin 0
|
||||
|
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div class="mk-notifications">
|
||||
<div class="notifications" v-if="notifications.length != 0">
|
||||
<transition-group name="mk-notifications" class="transition">
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!-- <transition-group name="mk-notifications" class="transition"> -->
|
||||
<div>
|
||||
<template v-for="(notification, i) in _notifications">
|
||||
<div class="notification" :class="notification.type" :key="notification.id">
|
||||
<mk-time :time="notification.createdAt"/>
|
||||
@@ -95,7 +97,8 @@
|
||||
<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</transition-group>
|
||||
</div>
|
||||
<!-- </transition-group> -->
|
||||
</div>
|
||||
<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
|
||||
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
|
||||
@@ -201,7 +204,7 @@ root(isDark)
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> .notifications
|
||||
> *
|
||||
> div
|
||||
> .notification
|
||||
margin 0
|
||||
padding 16px
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
|
||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
||||
</div>
|
||||
<div class="media" v-if="p.media.length > 0">
|
||||
@@ -68,7 +68,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import parse from '../../../../../../mfm/parse';
|
||||
import canHideText from '../../../../common/scripts/can-hide-text';
|
||||
|
||||
import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
|
||||
import MkReactionPicker from '../../../../common/views/components/reaction-picker.vue';
|
||||
@@ -148,8 +147,6 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
canHideText,
|
||||
|
||||
capture(withHandler = false) {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection.send({
|
||||
@@ -381,10 +378,10 @@ root(isDark)
|
||||
|
||||
> *
|
||||
display inline-block
|
||||
margin 0 8px 0 0
|
||||
margin 0 0 4px 6px
|
||||
padding 2px 8px 2px 16px
|
||||
font-size 90%
|
||||
color #8d969e
|
||||
color $theme-color
|
||||
background isDark ? #313543 : #edf0f3
|
||||
border-radius 4px
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!--<transition-group name="mk-notes" class="transition">-->
|
||||
<div class="notes">
|
||||
<template v-for="(note, i) in _notes">
|
||||
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/>
|
||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||
@@ -16,6 +17,7 @@
|
||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
<!--</transition-group>-->
|
||||
|
||||
<footer v-if="more">
|
||||
@@ -199,6 +201,7 @@ root(isDark)
|
||||
> *
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> .notes
|
||||
> .date
|
||||
display block
|
||||
margin 0
|
||||
|
@@ -126,7 +126,7 @@ root(isDark)
|
||||
> .friend-form
|
||||
padding 16px
|
||||
text-align center
|
||||
border-top solid 1px #eee
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> .followed
|
||||
margin 12px 0 0 0
|
||||
@@ -144,7 +144,7 @@ root(isDark)
|
||||
> .action-form
|
||||
padding 16px
|
||||
text-align center
|
||||
border-top solid 1px #eee
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> *
|
||||
width 100%
|
||||
@@ -154,8 +154,8 @@ root(isDark)
|
||||
|
||||
> .birthday
|
||||
padding 16px
|
||||
color #555
|
||||
border-top solid 1px #eee
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 0
|
||||
@@ -165,8 +165,8 @@ root(isDark)
|
||||
|
||||
> .twitter
|
||||
padding 16px
|
||||
color #555
|
||||
border-top solid 1px #eee
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 0
|
||||
@@ -176,8 +176,8 @@ root(isDark)
|
||||
|
||||
> .status
|
||||
padding 16px
|
||||
color #555
|
||||
border-top solid 1px #eee
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 8px 0
|
||||
|
@@ -92,7 +92,7 @@ root(isDark)
|
||||
&.is-suspended
|
||||
color isDark ? #ffb4b4 : #570808
|
||||
background isDark ? #611d1d : #ffdbdb
|
||||
border solid 1px isDarl ? #d64a4a : #e09696
|
||||
border solid 1px isDark ? #d64a4a : #e09696
|
||||
|
||||
&.is-remote
|
||||
color isDark ? #ffbd3e : #573c08
|
||||
@@ -113,6 +113,7 @@ root(isDark)
|
||||
|
||||
> .main
|
||||
flex 1
|
||||
min-width 0 // SEE: http://kudakurage.hatenadiary.com/entry/2016/04/01/232722
|
||||
margin-right 16px
|
||||
|
||||
> .timeline
|
||||
@@ -121,6 +122,7 @@ root(isDark)
|
||||
|
||||
> .side
|
||||
width 275px
|
||||
flex-shrink 0
|
||||
|
||||
> p
|
||||
display block
|
||||
|
@@ -7,6 +7,13 @@
|
||||
</button>
|
||||
<div class="body" :style="{ backgroundImage: `url('${ welcomeBgUrl }')` }">
|
||||
<div class="container">
|
||||
<div class="info">
|
||||
<span>%i18n:common.misskey% <b>{{ host }}</b></span>
|
||||
<span class="stats" v-if="stats">
|
||||
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
|
||||
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<main>
|
||||
<div class="about">
|
||||
<h1 v-if="name">{{ name }}</h1>
|
||||
@@ -19,12 +26,8 @@
|
||||
<mk-signin/>
|
||||
</div>
|
||||
</main>
|
||||
<div class="info">
|
||||
<span>%i18n:common.misskey% <b>{{ host }}</b></span>
|
||||
<span class="stats" v-if="stats">
|
||||
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
|
||||
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
|
||||
</span>
|
||||
<div class="hashtags">
|
||||
<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
|
||||
</div>
|
||||
<mk-nav class="nav"/>
|
||||
</div>
|
||||
@@ -32,7 +35,7 @@
|
||||
<img src="assets/title.dark.svg" alt="Misskey">
|
||||
</div>
|
||||
<div class="tl">
|
||||
<mk-welcome-timeline/>
|
||||
<mk-welcome-timeline :max="20"/>
|
||||
</div>
|
||||
<modal name="signup" width="500px" height="auto" scrollable>
|
||||
<header :class="$style.signupFormHeader">%i18n:@signup%</header>
|
||||
@@ -54,13 +57,18 @@ export default Vue.extend({
|
||||
host,
|
||||
name,
|
||||
description,
|
||||
pointerInterval: null
|
||||
pointerInterval: null,
|
||||
tags: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('stats').then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
|
||||
(this as any).api('hashtags/trend').then(stats => {
|
||||
this.tags = stats.map(x => x.tag);
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.point();
|
||||
@@ -161,6 +169,20 @@ root(isDark)
|
||||
$loginWidth = 340px
|
||||
$width = $aboutWidth + $loginWidth
|
||||
|
||||
> .info
|
||||
margin 0 auto 16px auto
|
||||
width $width
|
||||
font-size 14px
|
||||
color #fff
|
||||
|
||||
> .stats
|
||||
margin-left 16px
|
||||
padding-left 16px
|
||||
border-left solid 1px #fff
|
||||
|
||||
> *
|
||||
margin-right 16px
|
||||
|
||||
> main
|
||||
display flex
|
||||
margin auto
|
||||
@@ -199,24 +221,19 @@ root(isDark)
|
||||
> .login
|
||||
width $loginWidth
|
||||
padding 16px 32px 32px 32px
|
||||
background #f5f5f5
|
||||
background isDark ? #2e3440 : #f5f5f5
|
||||
|
||||
> .info
|
||||
> .hashtags
|
||||
margin 16px auto
|
||||
padding 12px
|
||||
width $width
|
||||
font-size 14px
|
||||
color #fff
|
||||
background rgba(#000, 0.2)
|
||||
background rgba(#000, 0.3)
|
||||
border-radius 8px
|
||||
|
||||
> .stats
|
||||
margin-left 16px
|
||||
padding-left 16px
|
||||
border-left solid 1px #fff
|
||||
|
||||
> *
|
||||
margin-right 16px
|
||||
> *
|
||||
display inline-block
|
||||
margin 14px
|
||||
|
||||
> .nav
|
||||
display block
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
||||
</div>
|
||||
<div class="media" v-if="p.media.length > 0">
|
||||
@@ -69,7 +69,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import parse from '../../../../../mfm/parse';
|
||||
import canHideText from '../../../common/scripts/can-hide-text';
|
||||
|
||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
||||
@@ -165,8 +164,6 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
canHideText,
|
||||
|
||||
capture(withHandler = false) {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection.send({
|
||||
@@ -424,10 +421,10 @@ root(isDark)
|
||||
|
||||
> *
|
||||
display inline-block
|
||||
margin 0 8px 0 0
|
||||
margin 0 0 4px 6px
|
||||
padding 2px 8px 2px 16px
|
||||
font-size 90%
|
||||
color #8d969e
|
||||
color $theme-color
|
||||
background isDark ? #313543 : #edf0f3
|
||||
border-radius 4px
|
||||
|
||||
|
@@ -13,7 +13,9 @@
|
||||
<button @click="resolveInitPromise">%i18n:@retry%</button>
|
||||
</div>
|
||||
|
||||
<transition-group name="mk-notes" class="transition">
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!-- <transition-group name="mk-notes" class="transition"> -->
|
||||
<div class="transition">
|
||||
<template v-for="(note, i) in _notes">
|
||||
<mk-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
|
||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||
@@ -21,7 +23,8 @@
|
||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</transition-group>
|
||||
</div>
|
||||
<!-- </transition-group> -->
|
||||
|
||||
<footer v-if="more">
|
||||
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
|
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="mk-notifications">
|
||||
<transition-group name="mk-notifications" class="transition notifications">
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!-- <transition-group name="mk-notifications" class="transition notifications"> -->
|
||||
<div class="transition notifications">
|
||||
<template v-for="(notification, i) in _notifications">
|
||||
<mk-notification :notification="notification" :key="notification.id"/>
|
||||
<p class="date" :key="notification.id + '_date'" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date">
|
||||
@@ -8,7 +10,8 @@
|
||||
<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</transition-group>
|
||||
</div>
|
||||
<!-- </transition-group> -->
|
||||
|
||||
<button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
|
||||
<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>
|
||||
|
@@ -14,6 +14,9 @@
|
||||
<div class="tl">
|
||||
<mk-welcome-timeline/>
|
||||
</div>
|
||||
<div class="hashtags">
|
||||
<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
|
||||
</div>
|
||||
<div class="stats" v-if="stats">
|
||||
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
|
||||
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
|
||||
@@ -37,13 +40,18 @@ export default Vue.extend({
|
||||
stats: null,
|
||||
host,
|
||||
name,
|
||||
description
|
||||
description,
|
||||
tags: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('stats').then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
|
||||
(this as any).api('hashtags/trend').then(stats => {
|
||||
this.tags = stats.map(x => x.tag);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -116,12 +124,22 @@ export default Vue.extend({
|
||||
box-shadow 0 1px 3px rgba(#000, 0.075), inset 0 0 5px rgba(#000, 0.2)
|
||||
|
||||
> .tl
|
||||
margin 16px 0
|
||||
|
||||
> *
|
||||
max-height 300px
|
||||
border-radius 6px
|
||||
overflow auto
|
||||
-webkit-overflow-scrolling touch
|
||||
|
||||
> .hashtags
|
||||
border solid 2px #ddd
|
||||
border-radius 8px
|
||||
|
||||
> *
|
||||
display inline-block
|
||||
margin 16px
|
||||
|
||||
> .stats
|
||||
margin 16px 0
|
||||
padding 8px
|
||||
|
@@ -4,6 +4,7 @@ import Mute from '../models/mute';
|
||||
import { pack } from '../models/notification';
|
||||
import stream from './stream';
|
||||
import User from '../models/user';
|
||||
import pushSw from '../publishers/push-sw';
|
||||
|
||||
export default (
|
||||
notifiee: mongo.ObjectID,
|
||||
@@ -26,9 +27,10 @@ export default (
|
||||
|
||||
resolve(notification);
|
||||
|
||||
const packed = await pack(notification);
|
||||
|
||||
// Publish notification event
|
||||
stream(notifiee, 'notification',
|
||||
await pack(notification));
|
||||
stream(notifiee, 'notification', packed);
|
||||
|
||||
// Update flag
|
||||
User.update({ _id: notifiee }, {
|
||||
@@ -52,7 +54,9 @@ export default (
|
||||
}
|
||||
//#endregion
|
||||
|
||||
stream(notifiee, 'unread_notification', await pack(notification));
|
||||
stream(notifiee, 'unread_notification', packed);
|
||||
|
||||
pushSw(notifiee, 'notification', packed);
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
@@ -629,8 +629,7 @@ const endpoints: Endpoint[] = [
|
||||
},
|
||||
|
||||
{
|
||||
name: 'hashtags/trend',
|
||||
withCredential: true
|
||||
name: 'hashtags/trend'
|
||||
},
|
||||
|
||||
{
|
||||
|
@@ -12,7 +12,6 @@ import notify from '../../publishers/notify';
|
||||
import NoteWatching from '../../models/note-watching';
|
||||
import watch from './watch';
|
||||
import Mute from '../../models/mute';
|
||||
import pushSw from '../../publishers/push-sw';
|
||||
import event from '../../publishers/stream';
|
||||
import parse from '../../mfm/parse';
|
||||
import { IApp } from '../../models/app';
|
||||
@@ -20,56 +19,56 @@ import UserList from '../../models/user-list';
|
||||
import resolveUser from '../../remote/resolve-user';
|
||||
import Meta from '../../models/meta';
|
||||
|
||||
type Reason = 'reply' | 'quote' | 'mention';
|
||||
type Type = 'reply' | 'renote' | 'quote' | 'mention';
|
||||
|
||||
/**
|
||||
* ServiceWorkerへの通知を担当
|
||||
* 通知を担当
|
||||
*/
|
||||
class NotificationManager {
|
||||
private user: IUser;
|
||||
private notifier: IUser;
|
||||
private note: any;
|
||||
private list: Array<{
|
||||
user: ILocalUser['_id'],
|
||||
reason: Reason;
|
||||
private queue: Array<{
|
||||
notifiee: ILocalUser['_id'],
|
||||
type: Type;
|
||||
}> = [];
|
||||
|
||||
constructor(user: IUser, note: any) {
|
||||
this.user = user;
|
||||
constructor(notifier: IUser, note: any) {
|
||||
this.notifier = notifier;
|
||||
this.note = note;
|
||||
}
|
||||
|
||||
public push(user: ILocalUser['_id'], reason: Reason) {
|
||||
public push(notifiee: ILocalUser['_id'], type: Type) {
|
||||
// 自分自身へは通知しない
|
||||
if (this.user._id.equals(user)) return;
|
||||
if (this.notifier._id.equals(notifiee)) return;
|
||||
|
||||
const exist = this.list.find(x => x.user.equals(user));
|
||||
const exist = this.queue.find(x => x.notifiee.equals(notifiee));
|
||||
|
||||
if (exist) {
|
||||
// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
|
||||
if (reason != 'mention') {
|
||||
exist.reason = reason;
|
||||
if (type != 'mention') {
|
||||
exist.type = type;
|
||||
}
|
||||
} else {
|
||||
this.list.push({
|
||||
user, reason
|
||||
this.queue.push({
|
||||
notifiee, type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public deliver() {
|
||||
this.list.forEach(async x => {
|
||||
const mentionee = x.user;
|
||||
|
||||
this.queue.forEach(async x => {
|
||||
// ミュート情報を取得
|
||||
const mentioneeMutes = await Mute.find({
|
||||
muterId: mentionee
|
||||
muterId: x.notifiee
|
||||
});
|
||||
|
||||
const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
|
||||
|
||||
// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
|
||||
if (!mentioneesMutedUserIds.includes(this.user._id.toString())) {
|
||||
pushSw(mentionee, x.reason, this.note);
|
||||
if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
|
||||
notify(x.notifiee, this.notifier._id, x.type, {
|
||||
noteId: this.note._id
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -264,10 +263,6 @@ export default async (user: IUser, data: {
|
||||
if (data.renote && data.renote.userId.equals(u._id)) return;
|
||||
|
||||
// Create notification
|
||||
notify(u._id, user._id, 'mention', {
|
||||
noteId: note._id
|
||||
});
|
||||
|
||||
nm.push(u._id, 'mention');
|
||||
});
|
||||
|
||||
@@ -371,11 +366,6 @@ export default async (user: IUser, data: {
|
||||
}
|
||||
});
|
||||
|
||||
// (自分自身へのリプライでない限りは)通知を作成
|
||||
notify(data.reply.userId, user._id, 'reply', {
|
||||
noteId: note._id
|
||||
});
|
||||
|
||||
// Fetch watchers
|
||||
NoteWatching.find({
|
||||
noteId: data.reply._id,
|
||||
@@ -388,9 +378,7 @@ export default async (user: IUser, data: {
|
||||
}
|
||||
}).then(watchers => {
|
||||
watchers.forEach(watcher => {
|
||||
notify(watcher.userId, user._id, 'reply', {
|
||||
noteId: note._id
|
||||
});
|
||||
nm.push(watcher.userId, 'reply');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -399,6 +387,7 @@ export default async (user: IUser, data: {
|
||||
watch(user._id, data.reply);
|
||||
}
|
||||
|
||||
// (自分自身へのリプライでない限りは)通知を作成
|
||||
nm.push(data.reply.userId, 'reply');
|
||||
}
|
||||
|
||||
@@ -406,9 +395,7 @@ export default async (user: IUser, data: {
|
||||
if (data.renote) {
|
||||
// Notify
|
||||
const type = data.text ? 'quote' : 'renote';
|
||||
notify(data.renote.userId, user._id, type, {
|
||||
noteId: note._id
|
||||
});
|
||||
nm.push(data.renote.userId, type);
|
||||
|
||||
// Fetch watchers
|
||||
NoteWatching.find({
|
||||
@@ -420,9 +407,7 @@ export default async (user: IUser, data: {
|
||||
}
|
||||
}).then(watchers => {
|
||||
watchers.forEach(watcher => {
|
||||
notify(watcher.userId, user._id, type, {
|
||||
noteId: note._id
|
||||
});
|
||||
nm.push(watcher.userId, type);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { IUser, pack as packUser, isLocalUser, isRemoteUser } from '../../../models/user';
|
||||
import Note, { INote, pack as packNote } from '../../../models/note';
|
||||
import { IUser, isLocalUser, isRemoteUser } from '../../../models/user';
|
||||
import Note, { INote } from '../../../models/note';
|
||||
import NoteReaction from '../../../models/note-reaction';
|
||||
import { publishNoteStream } from '../../../publishers/stream';
|
||||
import notify from '../../../publishers/notify';
|
||||
import pushSw from '../../../publishers/push-sw';
|
||||
import NoteWatching from '../../../models/note-watching';
|
||||
import watch from '../watch';
|
||||
import renderLike from '../../../remote/activitypub/renderer/like';
|
||||
@@ -54,12 +53,6 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise
|
||||
});
|
||||
}
|
||||
|
||||
pushSw(note.userId, 'reaction', {
|
||||
user: await packUser(user, note.userId),
|
||||
note: await packNote(note, note.userId),
|
||||
reaction: reaction
|
||||
});
|
||||
|
||||
// Fetch watchers
|
||||
NoteWatching
|
||||
.find({
|
||||
|
@@ -1,3 +0,0 @@
|
||||
// https://github.com/Microsoft/TypeScript/issues/12215
|
||||
export type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
|
||||
export type Omit<T, K extends keyof T> = { [P in Diff<keyof T, K>]: T[P] };
|
Reference in New Issue
Block a user