Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
47c45d48b1 | |||
cdd9585cb8 | |||
db60188847 | |||
21a2e5f415 | |||
2377c9b4cb | |||
296f6b1553 | |||
e15643ca46 | |||
9632ba40cc | |||
a2cdeeb6c7 | |||
a23857ce3c | |||
78677b3aa7 | |||
7dd264953f | |||
17af9c3ab6 | |||
4b49f8fbb8 | |||
e253225c66 | |||
6abb6f90f6 | |||
9fb2743a38 | |||
17792716a7 | |||
ae7282358e | |||
abc082f7c0 | |||
bf1163ae84 | |||
be74ca472a | |||
31b472fa47 | |||
b502627494 | |||
a8017369d0 | |||
3f0b5e4318 | |||
aea8f93e02 | |||
874411990b | |||
780268f70e | |||
3a8a374e87 | |||
488f36d491 | |||
4d48b0be99 | |||
44f3888c24 | |||
a76fb4c173 | |||
e4aa003157 | |||
247f334334 | |||
509cdae832 | |||
5ff59b3339 | |||
2b1a785f24 | |||
2c0b137848 | |||
ef68e633cf | |||
e9e63ba950 | |||
3fd6167e71 | |||
6b0573ded1 | |||
e2c3d4f2fb | |||
60229d73c9 | |||
c6cbadc514 | |||
3c3c67a34c |
@ -42,6 +42,7 @@ common:
|
||||
d: "Willst du etwas sagen?"
|
||||
e: "Schreib hier etwas!"
|
||||
f: "Warte darauf, das du schreibst."
|
||||
search: "検索"
|
||||
delete: "Löschen"
|
||||
loading: "Laden"
|
||||
ok: "OK"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
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: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "Analoge Uhr"
|
||||
profile: "Profil"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "Notizen"
|
||||
memo: "Schreib hier!"
|
||||
save: "Speichern"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Schwarz ... komplett"
|
||||
notes: "Blau ... Hinweise"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "Do you want to say something?"
|
||||
e: "Write here!"
|
||||
f: "Waiting for your writing."
|
||||
search: "Search"
|
||||
delete: "Delete"
|
||||
loading: "Loading"
|
||||
ok: "OK"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
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"
|
||||
show-reversi-board-labels: "Show row and column labels in Reversi"
|
||||
reversi:
|
||||
drawn: "Game Drawn"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "Analog clock"
|
||||
profile: "Profile"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "Sticky note"
|
||||
memo: "Write here!"
|
||||
save: "Save"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "Signed in as {}"
|
||||
following: "Following"
|
||||
follow: "Follow"
|
||||
request-pending: "Pending follow request"
|
||||
follow-request: "Follow request"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Mute"
|
||||
muted: "Muting"
|
||||
unmute: "Unmute"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "Posts"
|
||||
following: "Following"
|
||||
followers: "Followers"
|
||||
is-bot: "This account is a bot"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "Posts"
|
||||
with-replies: "Posts and replies"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "¿Quieres decir algo?"
|
||||
e: "¡Escribe aquí!"
|
||||
f: "Esperando a que escribas algo..."
|
||||
search: "検索"
|
||||
delete: "eliminar"
|
||||
loading: "cargando"
|
||||
ok: "OK"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
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: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "Reloj analógico"
|
||||
profile: "Perfil"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "Voulez-vous exprimer quelque chose ?"
|
||||
e: "Écrivez ici"
|
||||
f: "En attente de vos écrits"
|
||||
search: "検索"
|
||||
delete: "Supprimer"
|
||||
loading: "Chargement"
|
||||
ok: "OK"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
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: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "Horloge analogique"
|
||||
profile: "Profil"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "Pense-bête"
|
||||
memo: "Écrivez ici !"
|
||||
save: "Enregistrer"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Bleu ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Mettre en sourdine"
|
||||
muted: "Muting"
|
||||
unmute: "Enlever la sourdine"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "Publications"
|
||||
with-replies: "Publications et réponses"
|
||||
|
@ -5,7 +5,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl';
|
||||
export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl' | 'es';
|
||||
export type LocaleObject = { [key: string]: any };
|
||||
|
||||
const loadLang = (lang: LangKey) => yaml.safeLoad(
|
||||
@ -18,7 +18,8 @@ const langs: { [key: string]: LocaleObject } = {
|
||||
'en': loadLang('en'),
|
||||
'fr': loadLang('fr'),
|
||||
'ja': native,
|
||||
'pl': loadLang('pl')
|
||||
'pl': loadLang('pl'),
|
||||
'es': loadLang('es')
|
||||
};
|
||||
|
||||
Object.entries(langs).map(([, locale]) => {
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "言いたいことは?"
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
profile: "プロフィール"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -47,6 +47,7 @@ common:
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -54,6 +55,14 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
@ -271,6 +280,13 @@ common/views/widgets/memo.vue:
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -750,6 +766,12 @@ desktop/views/pages/user/user.profile.vue:
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "言いたいことは?"
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
profile: "プロフィール"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "Czy masz coś do powiedzenia?"
|
||||
e: "Napisz coś tutaj!"
|
||||
f: "Czekamy, aż coś napiszesz."
|
||||
search: "検索"
|
||||
delete: "Usuń"
|
||||
loading: "Ładowanie"
|
||||
ok: "OK"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
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"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "Zegar analogowy"
|
||||
profile: "Profil"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "Notatka"
|
||||
memo: "Napisz tutaj!"
|
||||
save: "Zapisz"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Czarny … Łącznie"
|
||||
notes: "Niebieski … Wpisy"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Wycisz"
|
||||
muted: "Wyciszyłeś"
|
||||
unmute: "Cofnij wyciszenie"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "Wpisy"
|
||||
with-replies: "Wpisy i odpowiedzi"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "言いたいことは?"
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
profile: "プロフィール"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "言いたいことは?"
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
profile: "プロフィール"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
@ -42,6 +42,7 @@ common:
|
||||
d: "言いたいことは?"
|
||||
e: "ここに書いてください"
|
||||
f: "あなたが書くのを待っています..."
|
||||
search: "検索"
|
||||
delete: "削除"
|
||||
loading: "読み込み中"
|
||||
ok: "わかった"
|
||||
@ -49,6 +50,13 @@ common:
|
||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
||||
reversi:
|
||||
drawn: "引き分け"
|
||||
my-turn: "あなたのターンです"
|
||||
opponent-turn: "相手のターンです"
|
||||
turn-of: "{}のターンです"
|
||||
past-turn-of: "{}のターン"
|
||||
widgets:
|
||||
analog-clock: "アナログ時計"
|
||||
profile: "プロフィール"
|
||||
@ -238,6 +246,12 @@ common/views/widgets/memo.vue:
|
||||
title: "付箋"
|
||||
memo: "ここに書いて!"
|
||||
save: "保存"
|
||||
common/views/pages/follow.vue:
|
||||
signed-in-as: "{}としてサインイン中"
|
||||
following: "フォロー中"
|
||||
follow: "フォロー"
|
||||
request-pending: "フォロー許可待ち"
|
||||
follow-request: "フォロー申請"
|
||||
desktop/views/components/activity.chart.vue:
|
||||
total: "Black ... Total"
|
||||
notes: "Blue ... Notes"
|
||||
@ -639,6 +653,11 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
is-bot: "このアカウントはBotです"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "投稿"
|
||||
with-replies: "投稿と返信"
|
||||
|
14
package.json
14
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "4.7.1",
|
||||
"clientVersion": "1.0.6735",
|
||||
"version": "4.13.0",
|
||||
"clientVersion": "1.0.6783",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
@ -65,7 +65,7 @@
|
||||
"@types/mocha": "5.2.3",
|
||||
"@types/mongodb": "3.0.21",
|
||||
"@types/ms": "0.7.30",
|
||||
"@types/node": "10.3.4",
|
||||
"@types/node": "10.3.5",
|
||||
"@types/nopt": "3.0.29",
|
||||
"@types/parse5": "5.0.0",
|
||||
"@types/pug": "2.0.4",
|
||||
@ -102,7 +102,7 @@
|
||||
"element-ui": "2.4.1",
|
||||
"emojilib": "2.2.12",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eslint": "4.19.1",
|
||||
"eslint": "5.0.0",
|
||||
"eslint-plugin-vue": "4.5.0",
|
||||
"eventemitter3": "3.1.0",
|
||||
"exif-js": "2.3.0",
|
||||
@ -124,7 +124,7 @@
|
||||
"gulp-typescript": "4.0.2",
|
||||
"gulp-uglify": "3.0.0",
|
||||
"gulp-util": "3.0.8",
|
||||
"hard-source-webpack-plugin": "0.8.1",
|
||||
"hard-source-webpack-plugin": "0.9.0",
|
||||
"highlight.js": "9.12.0",
|
||||
"html-minifier": "3.5.16",
|
||||
"http-signature": "1.2.0",
|
||||
@ -193,7 +193,7 @@
|
||||
"textarea-caret": "3.1.0",
|
||||
"tmp": "0.0.33",
|
||||
"ts-loader": "4.4.1",
|
||||
"ts-node": "6.1.2",
|
||||
"ts-node": "7.0.0",
|
||||
"tslint": "5.10.0",
|
||||
"typescript": "2.9.2",
|
||||
"typescript-eslint-parser": "16.0.0",
|
||||
@ -216,7 +216,7 @@
|
||||
"webpack": "4.12.0",
|
||||
"webpack-cli": "3.0.8",
|
||||
"websocket": "1.0.26",
|
||||
"ws": "5.2.0",
|
||||
"ws": "5.2.1",
|
||||
"xev": "2.0.1"
|
||||
},
|
||||
"greenkeeper": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mk-google">
|
||||
<input type="search" v-model="query" :placeholder="q">
|
||||
<button @click="search">検索</button>
|
||||
<button @click="search">%fa:search% %i18n:common.search%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -3,24 +3,39 @@
|
||||
<header><b>{{ blackUser.name }}</b>(黒) vs <b>{{ whiteUser.name }}</b>(白)</header>
|
||||
|
||||
<div style="overflow: hidden">
|
||||
<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ turnUser.name }}のターンです<mk-ellipsis/></p>
|
||||
<p class="turn" v-if="logPos != logs.length">{{ turnUser.name }}のターン</p>
|
||||
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">相手のターンです<mk-ellipsis/></p>
|
||||
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">あなたのターンです</p>
|
||||
<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', turnUser.name) }}<mk-ellipsis/></p>
|
||||
<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', turnUser.name) }}</p>
|
||||
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">%i18n:common.reversi.opponent-turn%<mk-ellipsis/></p>
|
||||
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">%i18n:common.reversi.my-turn%</p>
|
||||
<p class="result" v-if="game.isEnded && logPos == logs.length">
|
||||
<template v-if="game.winner"><b>{{ game.winner.name }}</b>の勝ち{{ game.settings.isLlotheo ? ' (ロセオ)' : '' }}</template>
|
||||
<template v-else>引き分け</template>
|
||||
<template v-else>%i18n:common.reversi.drawn%</template>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="board" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
|
||||
<div v-for="(stone, i) in o.board"
|
||||
:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
|
||||
@click="set(i)"
|
||||
:title="'[' + (o.transformPosToXy(i)[0] + 1) + ', ' + (o.transformPosToXy(i)[1] + 1) + '] (' + i + ')'"
|
||||
>
|
||||
<img v-if="stone === true" :src="`${blackUser.avatarUrl}?thumbnail&size=128`" alt="">
|
||||
<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
|
||||
<div class="board">
|
||||
<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
|
||||
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
|
||||
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
||||
</div>
|
||||
<div class="cells" :style="cellsStyle">
|
||||
<div v-for="(stone, i) in o.board"
|
||||
:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
|
||||
@click="set(i)"
|
||||
:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
|
||||
<img v-if="stone === true" :src="`${blackUser.avatarUrl}?thumbnail&size=128`" alt="">
|
||||
<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
|
||||
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
|
||||
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -92,6 +107,12 @@ export default Vue.extend({
|
||||
isMyTurn(): boolean {
|
||||
if (this.turnUser == null) return null;
|
||||
return this.turnUser.id == this.$store.state.i.id;
|
||||
},
|
||||
cellsStyle(): any {
|
||||
return {
|
||||
'grid-template-rows': `repeat(${ this.game.settings.map.length }, 1fr)`,
|
||||
'grid-template-columns': `repeat(${ this.game.settings.map[0].length }, 1fr)`
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@ -244,54 +265,99 @@ export default Vue.extend({
|
||||
border-bottom dashed 1px #c4cdd4
|
||||
|
||||
> .board
|
||||
display grid
|
||||
grid-gap 4px
|
||||
width 350px
|
||||
height 350px
|
||||
margin 0 auto
|
||||
|
||||
> div
|
||||
background transparent
|
||||
border-radius 6px
|
||||
overflow hidden
|
||||
$label-size = 16px
|
||||
$gap = 4px
|
||||
|
||||
*
|
||||
pointer-events none
|
||||
user-select none
|
||||
> .labels-x
|
||||
height $label-size
|
||||
padding 0 $label-size
|
||||
display flex
|
||||
|
||||
&.empty
|
||||
border solid 2px #eee
|
||||
> *
|
||||
flex 1
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
font-size 12px
|
||||
|
||||
&.empty.can
|
||||
background #eee
|
||||
&:first-child
|
||||
margin-left -($gap / 2)
|
||||
|
||||
&.empty.myTurn
|
||||
border-color #ddd
|
||||
&:last-child
|
||||
margin-right -($gap / 2)
|
||||
|
||||
&.can
|
||||
background #eee
|
||||
cursor pointer
|
||||
> .flex
|
||||
display flex
|
||||
|
||||
&:hover
|
||||
border-color darken($theme-color, 10%)
|
||||
background $theme-color
|
||||
> .labels-y
|
||||
width $label-size
|
||||
display flex
|
||||
flex-direction column
|
||||
|
||||
&:active
|
||||
background darken($theme-color, 10%)
|
||||
> *
|
||||
flex 1
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
font-size 12px
|
||||
|
||||
&.prev
|
||||
box-shadow 0 0 0 4px rgba($theme-color, 0.7)
|
||||
&:first-child
|
||||
margin-top -($gap / 2)
|
||||
|
||||
&.isEnded
|
||||
border-color #ddd
|
||||
&:last-child
|
||||
margin-bottom -($gap / 2)
|
||||
|
||||
&.none
|
||||
border-color transparent !important
|
||||
> .cells
|
||||
flex 1
|
||||
display grid
|
||||
grid-gap $gap
|
||||
|
||||
> img
|
||||
display block
|
||||
width 100%
|
||||
height 100%
|
||||
> div
|
||||
background transparent
|
||||
border-radius 6px
|
||||
overflow hidden
|
||||
|
||||
*
|
||||
pointer-events none
|
||||
user-select none
|
||||
|
||||
&.empty
|
||||
border solid 2px #eee
|
||||
|
||||
&.empty.can
|
||||
background #eee
|
||||
|
||||
&.empty.myTurn
|
||||
border-color #ddd
|
||||
|
||||
&.can
|
||||
background #eee
|
||||
cursor pointer
|
||||
|
||||
&:hover
|
||||
border-color darken($theme-color, 10%)
|
||||
background $theme-color
|
||||
|
||||
&:active
|
||||
background darken($theme-color, 10%)
|
||||
|
||||
&.prev
|
||||
box-shadow 0 0 0 4px rgba($theme-color, 0.7)
|
||||
|
||||
&.isEnded
|
||||
border-color #ddd
|
||||
|
||||
&.none
|
||||
border-color transparent !important
|
||||
|
||||
> img
|
||||
display block
|
||||
width 100%
|
||||
height 100%
|
||||
|
||||
> .graph
|
||||
display grid
|
||||
|
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="index" v-else>
|
||||
<h1>Misskey %fa:circle%thell%fa:circle R%</h1>
|
||||
<h1>Misskey Reversi</h1>
|
||||
<p>他のMisskeyユーザーとリバーシで対戦しよう</p>
|
||||
<div class="play">
|
||||
<el-button round>フリーマッチ(準備中)</el-button>
|
||||
|
215
src/client/app/common/views/pages/follow.vue
Normal file
215
src/client/app/common/views/pages/follow.vue
Normal file
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
|
||||
<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + myName + '</b>')"></div>
|
||||
|
||||
<main>
|
||||
<div class="banner" :style="bannerStyle"></div>
|
||||
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
|
||||
<div class="body">
|
||||
<router-link :to="user | userPage" class="name">{{ user | userName }}</router-link>
|
||||
<span class="username">@{{ user | acct }}</span>
|
||||
<div class="description">
|
||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<button
|
||||
:class="{ wait: followWait, active: user.isFollowing || user.hasPendingFollowRequestFromYou }"
|
||||
@click="onClick"
|
||||
:disabled="followWait">
|
||||
<template v-if="!followWait">
|
||||
<template v-if="user.hasPendingFollowRequestFromYou">%fa:hourglass-half% %i18n:@request-pending%</template>
|
||||
<template v-else-if="user.isFollowing">%fa:minus% %i18n:@following%</template>
|
||||
<template v-else-if="!user.isFollowing && user.isLocked">%fa:plus% %i18n:@follow-request%</template>
|
||||
<template v-else-if="!user.isFollowing && !user.isLocked">%fa:plus% %i18n:@follow%</template>
|
||||
</template>
|
||||
<template v-else>%fa:spinner .pulse .fw%</template>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import parseAcct from '../../../../../acct/parse';
|
||||
import getUserName from '../../../../../renderers/get-user-name';
|
||||
import Progress from '../../../common/scripts/loading';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
user: null,
|
||||
followWait: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
myName(): string {
|
||||
return Vue.filter('userName')(this.$store.state.i);
|
||||
},
|
||||
|
||||
bannerStyle(): any {
|
||||
if (this.user.bannerUrl == null) return {};
|
||||
return {
|
||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetch() {
|
||||
const acct = new URL(location.href).searchParams.get('acct');
|
||||
this.fetching = true;
|
||||
Progress.start();
|
||||
(this as any).api('users/show', parseAcct(acct)).then(user => {
|
||||
this.user = user;
|
||||
this.fetching = false;
|
||||
Progress.done();
|
||||
document.title = getUserName(this.user) + ' | Misskey';
|
||||
});
|
||||
},
|
||||
|
||||
async onClick() {
|
||||
this.followWait = true;
|
||||
|
||||
try {
|
||||
if (this.user.isFollowing) {
|
||||
this.user = await (this as any).api('following/delete', {
|
||||
userId: this.user.id
|
||||
});
|
||||
} else {
|
||||
if (this.user.isLocked && this.user.hasPendingFollowRequestFromYou) {
|
||||
this.user = await (this as any).api('following/requests/cancel', {
|
||||
userId: this.user.id
|
||||
});
|
||||
} else if (this.user.isLocked) {
|
||||
this.user = await (this as any).api('following/create', {
|
||||
userId: this.user.id
|
||||
});
|
||||
} else {
|
||||
this.user = await (this as any).api('following/create', {
|
||||
userId: this.user.id
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.followWait = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@import '~const.styl'
|
||||
|
||||
root(isDark)
|
||||
padding 32px
|
||||
max-width 500px
|
||||
margin 0 auto
|
||||
text-align center
|
||||
color isDark ? #9baec8 : #868c8c
|
||||
|
||||
$bg = isDark ? #282C37 : #fff
|
||||
|
||||
@media (max-width 400px)
|
||||
padding 16px
|
||||
|
||||
> .signed-in-as
|
||||
margin-bottom 16px
|
||||
font-size 14px
|
||||
color isDark ? #9baec8 : #9daab3
|
||||
|
||||
> main
|
||||
margin-bottom 16px
|
||||
background $bg
|
||||
border-radius 8px
|
||||
box-shadow 0 4px 12px rgba(#000, 0.1)
|
||||
overflow hidden
|
||||
|
||||
> .banner
|
||||
height 128px
|
||||
background-position center
|
||||
background-size cover
|
||||
|
||||
> .avatar
|
||||
display block
|
||||
margin -50px auto 0 auto
|
||||
width 100px
|
||||
height 100px
|
||||
border-radius 100%
|
||||
border solid 4px $bg
|
||||
|
||||
> .body
|
||||
padding 4px 32px 32px 32px
|
||||
|
||||
@media (max-width 400px)
|
||||
padding 4px 16px 16px 16px
|
||||
|
||||
> .name
|
||||
font-size 20px
|
||||
font-weight bold
|
||||
|
||||
> .username
|
||||
display block
|
||||
opacity 0.7
|
||||
|
||||
> .description
|
||||
margin-top 16px
|
||||
|
||||
> button
|
||||
display block
|
||||
user-select none
|
||||
cursor pointer
|
||||
padding 10px 16px
|
||||
margin 0
|
||||
width 100%
|
||||
min-width 150px
|
||||
font-size 14px
|
||||
font-weight bold
|
||||
color $theme-color
|
||||
background transparent
|
||||
outline none
|
||||
border solid 1px $theme-color
|
||||
border-radius 36px
|
||||
|
||||
&:hover
|
||||
background rgba($theme-color, 0.1)
|
||||
|
||||
&:active
|
||||
background rgba($theme-color, 0.2)
|
||||
|
||||
&.active
|
||||
color $theme-color-foreground
|
||||
background $theme-color
|
||||
|
||||
&:hover
|
||||
background lighten($theme-color, 10%)
|
||||
border-color lighten($theme-color, 10%)
|
||||
|
||||
&:active
|
||||
background darken($theme-color, 10%)
|
||||
border-color darken($theme-color, 10%)
|
||||
|
||||
&.wait
|
||||
cursor wait !important
|
||||
opacity 0.7
|
||||
|
||||
*
|
||||
pointer-events none
|
||||
|
||||
.syxhndwprovvuqhmyvveewmbqayniwkv[data-darkmode]
|
||||
root(true)
|
||||
|
||||
.syxhndwprovvuqhmyvveewmbqayniwkv:not([data-darkmode])
|
||||
root(false)
|
||||
|
||||
</style>
|
@ -36,6 +36,7 @@ import MkSearch from './views/pages/search.vue';
|
||||
import MkTag from './views/pages/tag.vue';
|
||||
import MkReversi from './views/pages/reversi.vue';
|
||||
import MkShare from './views/pages/share.vue';
|
||||
import MkFollow from '../common/views/pages/follow.vue';
|
||||
|
||||
/**
|
||||
* init
|
||||
@ -67,7 +68,8 @@ init(async (launch) => {
|
||||
{ path: '/reversi', component: MkReversi },
|
||||
{ path: '/reversi/:game', component: MkReversi },
|
||||
{ path: '/@:user', component: MkUser },
|
||||
{ path: '/notes/:note', component: MkNote }
|
||||
{ path: '/notes/:note', component: MkNote },
|
||||
{ path: '/authorize-follow', component: MkFollow }
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
<mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
|
||||
<span>%i18n:@show-maps-desc%</span>
|
||||
</mk-switch>
|
||||
<mk-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
@ -369,6 +370,12 @@ export default Vue.extend({
|
||||
value: v
|
||||
});
|
||||
},
|
||||
onChangeReversiBoardLabels(v) {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'reversiBoardLabels',
|
||||
value: v
|
||||
});
|
||||
},
|
||||
onChangeGradientWindowHeader(v) {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'gradientWindowHeader',
|
||||
|
@ -5,19 +5,33 @@
|
||||
<div class="fade"></div>
|
||||
<div class="title">
|
||||
<p class="name">{{ user | userName }}</p>
|
||||
<p class="username"><mk-acct :user="user"/></p>
|
||||
<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
|
||||
<div>
|
||||
<span class="username"><mk-acct :user="user"/></span>
|
||||
<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
|
||||
<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
|
||||
<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
|
||||
<div class="body">
|
||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
||||
<div class="description">
|
||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
||||
</div>
|
||||
<div class="status">
|
||||
<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span>
|
||||
<span class="following clickable" @click="showFollowing"><b>{{ user.followingCount | number }}</b>%i18n:@following%</span>
|
||||
<span class="followers clickable" @click="showFollowers"><b>{{ user.followersCount | number }}</b>%i18n:@followers%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkFollowingWindow from '../../components/following-window.vue';
|
||||
import MkFollowersWindow from '../../components/followers-window.vue';
|
||||
import * as age from 's-age';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['user'],
|
||||
@ -28,6 +42,10 @@ export default Vue.extend({
|
||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||
};
|
||||
},
|
||||
|
||||
age(): number {
|
||||
return age(this.user.profile.birthday);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -64,7 +82,19 @@ export default Vue.extend({
|
||||
(this as any).apis.updateBanner().then(i => {
|
||||
this.user.bannerUrl = i.bannerUrl;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
showFollowing() {
|
||||
(this as any).os.new(MkFollowingWindow, {
|
||||
user: this.user
|
||||
});
|
||||
},
|
||||
|
||||
showFollowers() {
|
||||
(this as any).os.new(MkFollowersWindow, {
|
||||
user: this.user
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@ -118,7 +148,6 @@ root(isDark)
|
||||
width 100%
|
||||
padding 0 0 8px 154px
|
||||
color #5e6367
|
||||
font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif
|
||||
|
||||
> .name
|
||||
display block
|
||||
@ -127,15 +156,15 @@ root(isDark)
|
||||
font-weight bold
|
||||
font-size 1.8em
|
||||
|
||||
> .username
|
||||
> .location
|
||||
display inline-block
|
||||
margin 0 16px 0 0
|
||||
line-height 20px
|
||||
opacity 0.8
|
||||
> div
|
||||
> *
|
||||
display inline-block
|
||||
margin-right 16px
|
||||
line-height 20px
|
||||
opacity 0.8
|
||||
|
||||
> i
|
||||
margin-right 4px
|
||||
&.username
|
||||
font-weight bold
|
||||
|
||||
> .avatar
|
||||
display block
|
||||
@ -151,6 +180,32 @@ root(isDark)
|
||||
padding 16px 16px 16px 154px
|
||||
color isDark ? #c5ced6 : #555
|
||||
|
||||
> .status
|
||||
margin-top 16px
|
||||
padding-top 16px
|
||||
border-top solid 1px rgba(#000, isDark ? 0.2 : 0.1)
|
||||
font-size 80%
|
||||
|
||||
> *
|
||||
display inline-block
|
||||
padding-right 16px
|
||||
margin-right 16px
|
||||
|
||||
&:not(:last-child)
|
||||
border-right solid 1px rgba(#000, isDark ? 0.2 : 0.1)
|
||||
|
||||
&.clickable
|
||||
cursor pointer
|
||||
|
||||
&:hover
|
||||
color isDark ? #fff : #000
|
||||
|
||||
> b
|
||||
margin-right 4px
|
||||
font-size 1rem
|
||||
font-weight bold
|
||||
color $theme-color
|
||||
|
||||
.header[data-darkmode]
|
||||
root(true)
|
||||
|
||||
|
@ -15,47 +15,17 @@
|
||||
</button>
|
||||
<button class="mute ui" @click="list">%fa:list% リストに追加</button>
|
||||
</div>
|
||||
<div class="birthday" v-if="user.host === null && user.profile.birthday">
|
||||
<p>%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
|
||||
</div>
|
||||
<div class="twitter" v-if="user.host === null && user.twitter">
|
||||
<p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></p>
|
||||
</div>
|
||||
<div class="status">
|
||||
<p class="notes-count">%fa:angle-right%<a>{{ user.notesCount }}</a><b>投稿</b></p>
|
||||
<p class="following">%fa:angle-right%<a @click="showFollowing">{{ user.followingCount }}</a>人を<b>フォロー</b></p>
|
||||
<p class="followers">%fa:angle-right%<a @click="showFollowers">{{ user.followersCount }}</a>人の<b>フォロワー</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as age from 's-age';
|
||||
import MkFollowingWindow from '../../components/following-window.vue';
|
||||
import MkFollowersWindow from '../../components/followers-window.vue';
|
||||
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['user'],
|
||||
computed: {
|
||||
age(): number {
|
||||
return age(this.user.profile.birthday);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
showFollowing() {
|
||||
(this as any).os.new(MkFollowingWindow, {
|
||||
user: this.user
|
||||
});
|
||||
},
|
||||
|
||||
showFollowers() {
|
||||
(this as any).os.new(MkFollowersWindow, {
|
||||
user: this.user
|
||||
});
|
||||
},
|
||||
|
||||
stalk() {
|
||||
(this as any).api('following/stalk', {
|
||||
userId: this.user.id
|
||||
@ -152,40 +122,6 @@ root(isDark)
|
||||
&:not(:last-child)
|
||||
margin-bottom 12px
|
||||
|
||||
> .birthday
|
||||
padding 16px
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 0
|
||||
|
||||
> i
|
||||
margin-right 8px
|
||||
|
||||
> .twitter
|
||||
padding 16px
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 0
|
||||
|
||||
> i
|
||||
margin-right 8px
|
||||
|
||||
> .status
|
||||
padding 16px
|
||||
color isDark ? #e3e7ea : #555
|
||||
border-bottom solid 1px isDark ? #21242f : #eee
|
||||
|
||||
> p
|
||||
margin 8px 0
|
||||
|
||||
> i
|
||||
margin-left 8px
|
||||
margin-right 8px
|
||||
|
||||
.profile[data-darkmode]
|
||||
root(true)
|
||||
|
||||
|
26
src/client/app/desktop/views/pages/user/user.twitter.vue
Normal file
26
src/client/app/desktop/views/pages/user/user.twitter.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="adsvaidqfznoartcbplullnejvxjphcn">
|
||||
<span>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['user']
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.adsvaidqfznoartcbplullnejvxjphcn
|
||||
padding 32px
|
||||
background #1a94f2
|
||||
border-radius 6px
|
||||
color #fff
|
||||
|
||||
a
|
||||
margin-left 8px
|
||||
color #fff
|
||||
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<mk-ui>
|
||||
<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
|
||||
<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
|
||||
<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
|
||||
<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
|
||||
<main>
|
||||
@ -11,6 +11,7 @@
|
||||
</div>
|
||||
<div class="side">
|
||||
<x-profile :user="user"/>
|
||||
<x-twitter :user="user" v-if="user.host === null && user.twitter"/>
|
||||
<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
|
||||
<mk-activity :user="user"/>
|
||||
<x-photos :user="user"/>
|
||||
@ -35,6 +36,7 @@ import XProfile from './user.profile.vue';
|
||||
import XPhotos from './user.photos.vue';
|
||||
import XFollowersYouKnow from './user.followers-you-know.vue';
|
||||
import XFriends from './user.friends.vue';
|
||||
import XTwitter from './user.twitter.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
@ -43,7 +45,8 @@ export default Vue.extend({
|
||||
XProfile,
|
||||
XPhotos,
|
||||
XFollowersYouKnow,
|
||||
XFriends
|
||||
XFriends,
|
||||
XTwitter
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -146,10 +149,10 @@ root(isDark)
|
||||
i
|
||||
color #ccc
|
||||
|
||||
.zwwan0di1v4356rmdbjmwnn32tptpdp2[data-darkmode]
|
||||
.xygkxeaeontfaokvqmiblezmhvhostak[data-darkmode]
|
||||
root(true)
|
||||
|
||||
.zwwan0di1v4356rmdbjmwnn32tptpdp2:not([data-darkmode])
|
||||
.xygkxeaeontfaokvqmiblezmhvhostak:not([data-darkmode])
|
||||
root(false)
|
||||
|
||||
</style>
|
||||
|
@ -38,6 +38,7 @@ import MkSettings from './views/pages/settings.vue';
|
||||
import MkReversi from './views/pages/reversi.vue';
|
||||
import MkTag from './views/pages/tag.vue';
|
||||
import MkShare from './views/pages/share.vue';
|
||||
import MkFollow from '../common/views/pages/follow.vue';
|
||||
|
||||
/**
|
||||
* init
|
||||
@ -80,7 +81,8 @@ init((launch) => {
|
||||
{ path: '/@:user', component: MkUser },
|
||||
{ path: '/@:user/followers', component: MkFollowers },
|
||||
{ path: '/@:user/following', component: MkFollowing },
|
||||
{ path: '/notes/:note', component: MkNote }
|
||||
{ path: '/notes/:note', component: MkNote },
|
||||
{ path: '/authorize-follow', component: MkFollow }
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
||||
<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
|
||||
<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
|
||||
<ui-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||
|
||||
<div>
|
||||
<div>%i18n:@timeline%</div>
|
||||
@ -182,6 +183,13 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
|
||||
onChangeReversiBoardLabels(v) {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'reversiBoardLabels',
|
||||
value: v
|
||||
});
|
||||
},
|
||||
|
||||
onChangeShowReplyTarget(v) {
|
||||
this.$store.dispatch('settings/set', {
|
||||
key: 'showReplyTarget',
|
||||
|
@ -19,7 +19,8 @@ const defaultSettings = {
|
||||
loadRemoteMedia: true,
|
||||
disableViaMobile: false,
|
||||
memo: null,
|
||||
iLikeSushi: false
|
||||
iLikeSushi: false,
|
||||
reversiBoardLabels: false
|
||||
};
|
||||
|
||||
const defaultDeviceSettings = {
|
||||
|
@ -9,7 +9,7 @@ export type TextElementSearch = {
|
||||
};
|
||||
|
||||
export default function(text: string) {
|
||||
const match = text.match(/^(.+?) 検索(\n|$)/);
|
||||
const match = text.match(/^(.+?) (検索|Search)(\n|$)/i);
|
||||
if (!match) return null;
|
||||
return {
|
||||
type: 'search',
|
||||
|
@ -47,16 +47,28 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
|
||||
|
||||
const object = await resolver.resolve(value) as any;
|
||||
|
||||
if (
|
||||
object == null ||
|
||||
object.type !== 'Person' ||
|
||||
typeof object.preferredUsername !== 'string' ||
|
||||
typeof object.inbox !== 'string' ||
|
||||
!validateUsername(object.preferredUsername) ||
|
||||
!isValidName(object.name == '' ? null : object.name)
|
||||
) {
|
||||
log(`invalid person: ${JSON.stringify(object, null, 2)}`);
|
||||
throw new Error('invalid person');
|
||||
if (object == null) {
|
||||
throw new Error('invalid person: object is null');
|
||||
}
|
||||
|
||||
if (object.type != 'Person' && object.type != 'Service') {
|
||||
throw new Error('invalid person: object is not a person or service');
|
||||
}
|
||||
|
||||
if (typeof object.preferredUsername !== 'string') {
|
||||
throw new Error('invalid person: preferredUsername is not a string');
|
||||
}
|
||||
|
||||
if (typeof object.inbox !== 'string') {
|
||||
throw new Error('invalid person: inbox is not a string');
|
||||
}
|
||||
|
||||
if (!validateUsername(object.preferredUsername)) {
|
||||
throw new Error('invalid person: invalid username');
|
||||
}
|
||||
|
||||
if (!isValidName(object.name == '' ? null : object.name)) {
|
||||
throw new Error('invalid person: invalid name');
|
||||
}
|
||||
|
||||
const person: IPerson = object;
|
||||
@ -81,6 +93,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
|
||||
|
||||
const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase();
|
||||
|
||||
const isBot = object.type == 'Service';
|
||||
|
||||
// Create user
|
||||
let user: IRemoteUser;
|
||||
try {
|
||||
@ -105,7 +119,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
|
||||
inbox: person.inbox,
|
||||
endpoints: person.endpoints,
|
||||
uri: person.id,
|
||||
url: person.url
|
||||
url: person.url,
|
||||
isBot
|
||||
}) as IRemoteUser;
|
||||
} catch (e) {
|
||||
// duplicate key error
|
||||
|
@ -7,7 +7,7 @@ export default (user: ILocalUser) => {
|
||||
const id = `${config.url}/users/${user._id}`;
|
||||
|
||||
return {
|
||||
type: 'Person',
|
||||
type: user.isBot ? 'Service' : 'Person',
|
||||
id,
|
||||
inbox: `${id}/inbox`,
|
||||
outbox: `${id}/outbox`,
|
||||
|
@ -11,7 +11,7 @@ import renderNote from '../remote/activitypub/renderer/note';
|
||||
import renderKey from '../remote/activitypub/renderer/key';
|
||||
import renderPerson from '../remote/activitypub/renderer/person';
|
||||
import renderOrderedCollection from '../remote/activitypub/renderer/ordered-collection';
|
||||
//import parseAcct from '../acct/parse';
|
||||
import parseAcct from '../acct/parse';
|
||||
import config from '../config';
|
||||
|
||||
// Init router
|
||||
@ -142,20 +142,6 @@ router.get('/@:user', async (ctx, next) => {
|
||||
|
||||
userInfo(ctx, user);
|
||||
});
|
||||
|
||||
// follow form
|
||||
router.get('/authorize-follow', async ctx => {
|
||||
/* TODO
|
||||
const { username, host } = parseAcct(ctx.query.acct);
|
||||
if (host === null) {
|
||||
res.sendStatus(422);
|
||||
return;
|
||||
}
|
||||
|
||||
const finger = await request(`https://${host}`)
|
||||
*/
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
export default router;
|
||||
|
@ -27,51 +27,30 @@ type Type = 'reply' | 'renote' | 'quote' | 'mention';
|
||||
class NotificationManager {
|
||||
private notifier: IUser;
|
||||
private note: any;
|
||||
private queue: Array<{
|
||||
notifiee: ILocalUser['_id'],
|
||||
type: Type;
|
||||
}> = [];
|
||||
|
||||
constructor(notifier: IUser, note: any) {
|
||||
this.notifier = notifier;
|
||||
this.note = note;
|
||||
}
|
||||
|
||||
public push(notifiee: ILocalUser['_id'], type: Type) {
|
||||
public async push(notifiee: ILocalUser['_id'], type: Type) {
|
||||
// 自分自身へは通知しない
|
||||
if (this.notifier._id.equals(notifiee)) return;
|
||||
|
||||
const exist = this.queue.find(x => x.notifiee.equals(notifiee));
|
||||
// ミュート情報を取得
|
||||
const mentioneeMutes = await Mute.find({
|
||||
muterId: notifiee
|
||||
});
|
||||
|
||||
if (exist) {
|
||||
// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
|
||||
if (type != 'mention') {
|
||||
exist.type = type;
|
||||
}
|
||||
} else {
|
||||
this.queue.push({
|
||||
notifiee, type
|
||||
const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
|
||||
|
||||
// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
|
||||
if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
|
||||
notify(notifiee, this.notifier._id, type, {
|
||||
noteId: this.note._id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public deliver() {
|
||||
this.queue.forEach(async x => {
|
||||
// ミュート情報を取得
|
||||
const mentioneeMutes = await Mute.find({
|
||||
muterId: x.notifiee
|
||||
});
|
||||
|
||||
const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
|
||||
|
||||
// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
|
||||
if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
|
||||
notify(x.notifiee, this.notifier._id, x.type, {
|
||||
noteId: this.note._id
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default async (user: IUser, data: {
|
||||
|
22
test/mfm.ts
22
test/mfm.ts
@ -93,6 +93,28 @@ describe('Text', () => {
|
||||
assert.equal(tokens[0].type, 'inline-code');
|
||||
assert.equal(tokens[0].content, '`var x = "Strawberry Pasta";`');
|
||||
});
|
||||
|
||||
it('search', () => {
|
||||
const tokens1 = analyze('a b c 検索');
|
||||
assert.deepEqual([
|
||||
{ type: 'search', content: 'a b c 検索', query: 'a b c'}
|
||||
], tokens1);
|
||||
|
||||
const tokens2 = analyze('a b c Search');
|
||||
assert.deepEqual([
|
||||
{ type: 'search', content: 'a b c Search', query: 'a b c'}
|
||||
], tokens2);
|
||||
|
||||
const tokens3 = analyze('a b c search');
|
||||
assert.deepEqual([
|
||||
{ type: 'search', content: 'a b c search', query: 'a b c'}
|
||||
], tokens3);
|
||||
|
||||
const tokens4 = analyze('a b c SEARCH');
|
||||
assert.deepEqual([
|
||||
{ type: 'search', content: 'a b c SEARCH', query: 'a b c'}
|
||||
], tokens4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('syntax highlighting', () => {
|
||||
|
Reference in New Issue
Block a user