Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7d1ab6102f | ||
![]() |
77ddd778be | ||
![]() |
890ecb693f | ||
![]() |
209fe7dcaf | ||
![]() |
e0d6f7c7c4 | ||
![]() |
5d3fe9599b | ||
![]() |
0fe0b6d254 | ||
![]() |
b794216eaf | ||
![]() |
1fccde38f6 | ||
![]() |
41bd436d3e | ||
![]() |
c66155ed48 | ||
![]() |
627bd410fa | ||
![]() |
41a3932c6b | ||
![]() |
785b8d7846 | ||
![]() |
622c8f9598 | ||
![]() |
ef978a6364 | ||
![]() |
d95fbe1c6b | ||
![]() |
d4ffddc2ab | ||
![]() |
3d497cedfc | ||
![]() |
e8de29ae79 | ||
![]() |
b622946844 | ||
![]() |
d013f78cc7 | ||
![]() |
2afbafdb3b | ||
![]() |
67148114a8 | ||
![]() |
7903140ec2 | ||
![]() |
cefd296200 | ||
![]() |
99d1c15851 | ||
![]() |
a3107ab26f | ||
![]() |
854cfae75b | ||
![]() |
36ab82957d | ||
![]() |
de9f54386c | ||
![]() |
7f43820765 | ||
![]() |
955e907e7f | ||
![]() |
4c18022e7d | ||
![]() |
509f59e46d | ||
![]() |
f14c372f5e |
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -32,7 +32,7 @@ common:
|
|||||||
paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。"
|
paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。"
|
||||||
paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。"
|
paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。"
|
||||||
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
|
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
|
||||||
gotit: "Got it!"
|
gotit: "Verstanden!"
|
||||||
notification:
|
notification:
|
||||||
file-uploaded: "Datei hochgeladen!"
|
file-uploaded: "Datei hochgeladen!"
|
||||||
message-from: "Nachricht von {}:"
|
message-from: "Nachricht von {}:"
|
||||||
@@ -175,7 +175,7 @@ auth/views/form.vue:
|
|||||||
permission-ask: "このアプリは次の権限を要求しています:"
|
permission-ask: "このアプリは次の権限を要求しています:"
|
||||||
account-read: "アカウントの情報を見る。"
|
account-read: "アカウントの情報を見る。"
|
||||||
account-write: "アカウントの情報を操作する。"
|
account-write: "アカウントの情報を操作する。"
|
||||||
note-write: "投稿する。"
|
note-write: "Senden."
|
||||||
like-write: "いいねしたりいいね解除する。"
|
like-write: "いいねしたりいいね解除する。"
|
||||||
following-write: "フォローしたりフォロー解除する。"
|
following-write: "フォローしたりフォロー解除する。"
|
||||||
drive-read: "ドライブを見る。"
|
drive-read: "ドライブを見る。"
|
||||||
@@ -186,14 +186,14 @@ auth/views/form.vue:
|
|||||||
accept: "Zugriff erlauben."
|
accept: "Zugriff erlauben."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
loading: "Lädt"
|
loading: "Lädt"
|
||||||
denied: "アプリケーションの連携をキャンセルしました。"
|
denied: "Autorisierung der Anwendung wurde verweigert."
|
||||||
denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
|
denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
|
||||||
already-authorized: "このアプリは既に連携済みです"
|
already-authorized: "Diese Anwendung ist bereits autorisiert."
|
||||||
allowed: "アプリケーションの連携を許可しました"
|
allowed: "Autorisierung der Anwendung wurde erlaubt."
|
||||||
callback-url: "アプリケーションに戻っています"
|
callback-url: "アプリケーションに戻っています"
|
||||||
please-go-back: "アプリケーションに戻って、やっていってください。"
|
please-go-back: "Bitte gehen Sie zurück zur Anwendung."
|
||||||
error: "セッションが存在しません。"
|
error: "Sitzung ist nicht vorhanden."
|
||||||
sign-in: "サインインしてください"
|
sign-in: "Bitte melde dich an."
|
||||||
common/views/components/games/reversi/reversi.vue:
|
common/views/components/games/reversi/reversi.vue:
|
||||||
matching:
|
matching:
|
||||||
waiting-for: "Warten auf {}"
|
waiting-for: "Warten auf {}"
|
||||||
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "API-Anfrage über WebSocket statt native Aktualisierungs-API (für bessere Leistung). Diese Einstellung wird im Browser gespeichert."
|
api-via-stream-desc: "API-Anfrage über WebSocket statt native Aktualisierungs-API (für bessere Leistung). Diese Einstellung wird im Browser gespeichert."
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Erscheinungsbild und Anzeige"
|
display: "Erscheinungsbild und Anzeige"
|
||||||
customize: "Startseite anpassen"
|
customize: "Startseite anpassen"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "API request is performed via the WebSocket connection instead of native fetch API (for better performance). This setting is stored in the browser."
|
api-via-stream-desc: "API request is performed via the WebSocket connection instead of native fetch API (for better performance). This setting is stored in the browser."
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Design and display"
|
display: "Design and display"
|
||||||
customize: "Customize home layout"
|
customize: "Customize home layout"
|
||||||
wallpaper: "Wallpaper"
|
wallpaper: "Wallpaper"
|
||||||
@@ -884,7 +885,7 @@ desktop/views/components/ui.header.account.vue:
|
|||||||
admin: "Admin"
|
admin: "Admin"
|
||||||
settings: "Settings"
|
settings: "Settings"
|
||||||
signout: "Sign out"
|
signout: "Sign out"
|
||||||
dark: "Submerge in dark"
|
dark: "Toggle dark mode"
|
||||||
desktop/views/components/ui.header.nav.vue:
|
desktop/views/components/ui.header.nav.vue:
|
||||||
home: "Home"
|
home: "Home"
|
||||||
deck: "Deck"
|
deck: "Deck"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "Las peticiones de las API se realizan por conexiones WebSocket en lugar de las tradicionales (para una mejora en el rendimiento). Esta función depende del navegador."
|
api-via-stream-desc: "Las peticiones de las API se realizan por conexiones WebSocket en lugar de las tradicionales (para una mejora en el rendimiento). Esta función depende del navegador."
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Diseño y pantalla"
|
display: "Diseño y pantalla"
|
||||||
customize: "Personaliza la página principal"
|
customize: "Personaliza la página principal"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -106,11 +106,11 @@ common:
|
|||||||
my-token-regenerated: "Votre jeton vient d’être généré, vous allez maintenant être déconnecté."
|
my-token-regenerated: "Votre jeton vient d’être généré, vous allez maintenant être déconnecté."
|
||||||
i-like-sushi: "Je préfère les sushis plutôt que le pudding"
|
i-like-sushi: "Je préfère les sushis plutôt que le pudding"
|
||||||
show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi"
|
show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi"
|
||||||
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
|
use-contrast-reversi-stones: "Icône avec contraste sur Reversi"
|
||||||
verified-user: "Compte vérifié"
|
verified-user: "Compte vérifié"
|
||||||
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "Toujours afficher les contenus sensibles"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "Toujours marquer les notes ayant des attachements comme sensibles"
|
||||||
show-full-acct: "Afficher l’adresse complète de l’utilisateur"
|
show-full-acct: "Afficher l’adresse complète de l’utilisateur"
|
||||||
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
||||||
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
||||||
@@ -417,24 +417,24 @@ common/views/components/trends.vue:
|
|||||||
count: "{} utilisateurs·rices mentionnés·es"
|
count: "{} utilisateurs·rices mentionnés·es"
|
||||||
empty: "Aucune tendance"
|
empty: "Aucune tendance"
|
||||||
common/views/components/profile-editor.vue:
|
common/views/components/profile-editor.vue:
|
||||||
title: "プロフィール"
|
title: "Profil"
|
||||||
name: "名前"
|
name: "Nom"
|
||||||
account: "アカウント"
|
account: "Compte"
|
||||||
location: "場所"
|
location: "Lieu"
|
||||||
description: "自己紹介"
|
description: "À propos de moi"
|
||||||
birthday: "誕生日"
|
birthday: "Date de naissance"
|
||||||
avatar: "アイコン"
|
avatar: "Avatar"
|
||||||
banner: "バナー"
|
banner: "Bannière"
|
||||||
is-cat: "このアカウントはCatです"
|
is-cat: "Ce compte est un Chat"
|
||||||
is-bot: "このアカウントはBotです"
|
is-bot: "Ce compte est un Bot"
|
||||||
is-locked: "フォローを承認制にする"
|
is-locked: "Demandes d’abonnements requièrent l’approbation"
|
||||||
careful-bot: "Botからのフォローだけ承認制にする"
|
careful-bot: "Botからのフォローだけ承認制にする"
|
||||||
advanced: "その他"
|
advanced: "Avancé"
|
||||||
privacy: "プライバシー"
|
privacy: "Vie privée"
|
||||||
save: "保存"
|
save: "Mettre à jour le profil"
|
||||||
saved: "プロフィールを保存しました"
|
saved: "Profil mis à jour avec succès"
|
||||||
uploading: "アップロード中"
|
uploading: "En cours d'envoi …"
|
||||||
upload-failed: "アップロードに失敗しました"
|
upload-failed: "Échec de l'envoi"
|
||||||
common/views/widgets/broadcast.vue:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Récupération"
|
fetching: "Récupération"
|
||||||
no-broadcasts: "Aucune annonce"
|
no-broadcasts: "Aucune annonce"
|
||||||
@@ -660,9 +660,9 @@ desktop/views/components/note-detail.vue:
|
|||||||
renote: "Republier"
|
renote: "Republier"
|
||||||
add-reaction: "Ajouter votre reaction"
|
add-reaction: "Ajouter votre reaction"
|
||||||
desktop/views/components/note.vue:
|
desktop/views/components/note.vue:
|
||||||
reposted-by: "{}がRenote"
|
reposted-by: "Partagé par {}"
|
||||||
reply: "返信"
|
reply: "Répondre"
|
||||||
renote: "Renote"
|
renote: "Partager"
|
||||||
add-reaction: "リアクション"
|
add-reaction: "リアクション"
|
||||||
detail: "詳細"
|
detail: "詳細"
|
||||||
private: "この投稿は非公開です"
|
private: "この投稿は非公開です"
|
||||||
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Affichage et design"
|
display: "Affichage et design"
|
||||||
customize: "Personnaliser l'Accueil"
|
customize: "Personnaliser l'Accueil"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -836,6 +836,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
|
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、WebSocket接続を経由してAPIリクエストが行われんで(パフォーマンス向上するかも、知らんけど)。オフにすると、ネイティブの fetch API が利用されるで。この設定はこのデバイスのみ有効やで。"
|
api-via-stream-desc: "この設定をオンにすると、WebSocket接続を経由してAPIリクエストが行われんで(パフォーマンス向上するかも、知らんけど)。オフにすると、ネイティブの fetch API が利用されるで。この設定はこのデバイスのみ有効やで。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "見た感じ"
|
display: "見た感じ"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "API-verzoek wordt uitgevoerd via de WebSocket-verbinding i.p.v. de ingebouwde ophaal-API (voor verbeterde prestaties). Deze instelling wordt opgeslagen in je browser."
|
api-via-stream-desc: "API-verzoek wordt uitgevoerd via de WebSocket-verbinding i.p.v. de ingebouwde ophaal-API (voor verbeterde prestaties). Deze instelling wordt opgeslagen in je browser."
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Ontwerp en weergave"
|
display: "Ontwerp en weergave"
|
||||||
customize: "Startpagina aanpassen"
|
customize: "Startpagina aanpassen"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "Wygląd i wyświetlanie"
|
display: "Wygląd i wyświetlanie"
|
||||||
customize: "Dostosuj stronę główną"
|
customize: "Dostosuj stronę główną"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -747,6 +747,7 @@ desktop/views/components/settings.vue:
|
|||||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||||
deck-nav: "デッキ内ナビゲーション"
|
deck-nav: "デッキ内ナビゲーション"
|
||||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||||
|
deck-default: "デッキをデフォルトのUIにする"
|
||||||
display: "デザインと表示"
|
display: "デザインと表示"
|
||||||
customize: "ホームをカスタマイズ"
|
customize: "ホームをカスタマイズ"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.23.1",
|
"version": "10.27.0",
|
||||||
"clientVersion": "1.0.10732",
|
"clientVersion": "1.0.10768",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
"qrcode": "1.3.0",
|
"qrcode": "1.3.0",
|
||||||
"ratelimiter": "3.2.0",
|
"ratelimiter": "3.2.0",
|
||||||
"recaptcha-promise": "0.1.3",
|
"recaptcha-promise": "0.1.3",
|
||||||
"reconnecting-websocket": "4.1.9",
|
"reconnecting-websocket": "4.1.10",
|
||||||
"redis": "2.8.0",
|
"redis": "2.8.0",
|
||||||
"request": "2.88.0",
|
"request": "2.88.0",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
|
@@ -46,6 +46,16 @@ const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): a
|
|||||||
|
|
||||||
const ignoreElemens = ['input', 'textarea'];
|
const ignoreElemens = ['input', 'textarea'];
|
||||||
|
|
||||||
|
function match(e: KeyboardEvent, patterns: action['patterns']): boolean {
|
||||||
|
const key = e.code.toLowerCase();
|
||||||
|
return patterns.some(pattern => pattern.which.includes(key) &&
|
||||||
|
pattern.ctrl == e.ctrlKey &&
|
||||||
|
pattern.shift == e.shiftKey &&
|
||||||
|
pattern.alt == e.altKey &&
|
||||||
|
e.metaKey == false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
Vue.directive('hotkey', {
|
Vue.directive('hotkey', {
|
||||||
@@ -55,37 +65,27 @@ export default {
|
|||||||
const actions = getKeyMap(binding.value);
|
const actions = getKeyMap(binding.value);
|
||||||
|
|
||||||
// flatten
|
// flatten
|
||||||
const reservedKeys = concat(concat(actions.map(a => a.patterns.map(p => p.which))));
|
const reservedKeys = concat(actions.map(a => a.patterns));
|
||||||
|
|
||||||
el.dataset.reservedKeys = reservedKeys.map(key => `'${key}'`).join(' ');
|
el._misskey_reservedKeys = reservedKeys;
|
||||||
|
|
||||||
el._keyHandler = (e: KeyboardEvent) => {
|
el._keyHandler = (e: KeyboardEvent) => {
|
||||||
const key = e.code.toLowerCase();
|
const targetReservedKeys = document.activeElement ? ((document.activeElement as any)._misskey_reservedKeys || []) : [];
|
||||||
|
|
||||||
const targetReservedKeys = document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeys || '' : '';
|
|
||||||
if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return;
|
if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return;
|
||||||
|
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (el._hotkey_global && targetReservedKeys.includes(`'${key}'`)) break;
|
const matched = match(e, action.patterns);
|
||||||
|
|
||||||
const matched = action.patterns.some(pattern => {
|
|
||||||
const matched = pattern.which.includes(key) &&
|
|
||||||
pattern.ctrl == e.ctrlKey &&
|
|
||||||
pattern.shift == e.shiftKey &&
|
|
||||||
pattern.alt == e.altKey &&
|
|
||||||
e.metaKey == false;
|
|
||||||
|
|
||||||
if (matched) {
|
if (matched) {
|
||||||
|
if (el._hotkey_global) {
|
||||||
|
if (match(e, targetReservedKeys)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
action.callback(e);
|
action.callback(e);
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (matched) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,14 +29,18 @@ export default (opts: Opts = {}) => ({
|
|||||||
computed: {
|
computed: {
|
||||||
keymap(): any {
|
keymap(): any {
|
||||||
return {
|
return {
|
||||||
'r|left': () => this.reply(true),
|
'r': () => this.reply(true),
|
||||||
'e|a|plus': () => this.react(true),
|
'e|a|plus': () => this.react(true),
|
||||||
'q|right': () => this.renote(true),
|
'q': () => this.renote(true),
|
||||||
'f|b': this.favorite,
|
'f|b': this.favorite,
|
||||||
'delete|ctrl+d': this.del,
|
'delete|ctrl+d': this.del,
|
||||||
'ctrl+q|ctrl+right': this.renoteDirectly,
|
'ctrl+q': this.renoteDirectly,
|
||||||
'up|k|shift+tab': this.focusBefore,
|
'up|k|shift+tab': this.focusBefore,
|
||||||
'down|j|tab': this.focusAfter,
|
'down|j|tab': this.focusAfter,
|
||||||
|
'shift+up': () => this.$emit('parentFocus', 'up'),
|
||||||
|
'shift+down': () => this.$emit('parentFocus', 'down'),
|
||||||
|
'shift+left': () => this.$emit('parentFocus', 'left'),
|
||||||
|
'shift+right': () => this.$emit('parentFocus', 'right'),
|
||||||
'esc': this.blur,
|
'esc': this.blur,
|
||||||
'm|o': () => this.menu(true),
|
'm|o': () => this.menu(true),
|
||||||
's': this.toggleShowContent,
|
's': this.toggleShowContent,
|
||||||
|
@@ -21,6 +21,7 @@ import updateAvatar from './api/update-avatar';
|
|||||||
import updateBanner from './api/update-banner';
|
import updateBanner from './api/update-banner';
|
||||||
|
|
||||||
import MkIndex from './views/pages/index.vue';
|
import MkIndex from './views/pages/index.vue';
|
||||||
|
import MkHome from './views/pages/home.vue';
|
||||||
import MkDeck from './views/pages/deck/deck.vue';
|
import MkDeck from './views/pages/deck/deck.vue';
|
||||||
import MkAdmin from './views/pages/admin/admin.vue';
|
import MkAdmin from './views/pages/admin/admin.vue';
|
||||||
import MkStats from './views/pages/stats/stats.vue';
|
import MkStats from './views/pages/stats/stats.vue';
|
||||||
@@ -54,6 +55,7 @@ init(async (launch) => {
|
|||||||
mode: 'history',
|
mode: 'history',
|
||||||
routes: [
|
routes: [
|
||||||
{ path: '/', name: 'index', component: MkIndex },
|
{ path: '/', name: 'index', component: MkIndex },
|
||||||
|
{ path: '/home', name: 'home', component: MkHome },
|
||||||
{ path: '/deck', name: 'deck', component: MkDeck },
|
{ path: '/deck', name: 'deck', component: MkDeck },
|
||||||
{ path: '/admin', name: 'admin', component: MkAdmin },
|
{ path: '/admin', name: 'admin', component: MkAdmin },
|
||||||
{ path: '/stats', name: 'stats', component: MkStats },
|
{ path: '/stats', name: 'stats', component: MkStats },
|
||||||
@@ -64,7 +66,7 @@ init(async (launch) => {
|
|||||||
{ path: '/i/drive/folder/:folder', component: MkDrive },
|
{ path: '/i/drive/folder/:folder', component: MkDrive },
|
||||||
{ path: '/selectdrive', component: MkSelectDrive },
|
{ path: '/selectdrive', component: MkSelectDrive },
|
||||||
{ path: '/search', component: MkSearch },
|
{ path: '/search', component: MkSearch },
|
||||||
{ path: '/tags/:tag', component: MkTag },
|
{ path: '/tags/:tag', name: 'tag', component: MkTag },
|
||||||
{ path: '/share', component: MkShare },
|
{ path: '/share', component: MkShare },
|
||||||
{ path: '/reversi/:game?', component: MkReversi },
|
{ path: '/reversi/:game?', component: MkReversi },
|
||||||
{ path: '/@:user', name: 'user', component: MkUser },
|
{ path: '/@:user', name: 'user', component: MkUser },
|
||||||
|
@@ -35,7 +35,7 @@
|
|||||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||||
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||||
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
||||||
<a class="rp" v-if="appearNote.renote">RP:</a>
|
<a class="rp" v-if="appearNote.renote">RN:</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="appearNote.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<mk-media-list :media-list="appearNote.files"/>
|
<mk-media-list :media-list="appearNote.files"/>
|
||||||
|
@@ -38,7 +38,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import * as config from '../../../config';
|
import * as config from '../../../config';
|
||||||
import getNoteSummary from '../../../../../misc/get-note-summary';
|
|
||||||
|
|
||||||
import XNote from './note.vue';
|
import XNote from './note.vue';
|
||||||
|
|
||||||
@@ -61,7 +60,6 @@ export default Vue.extend({
|
|||||||
requestInitPromise: null as () => Promise<any[]>,
|
requestInitPromise: null as () => Promise<any[]>,
|
||||||
notes: [],
|
notes: [],
|
||||||
queue: [],
|
queue: [],
|
||||||
unreadCount: 0,
|
|
||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false
|
moreFetching: false
|
||||||
};
|
};
|
||||||
@@ -80,12 +78,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('visibilitychange', this.onVisibilitychange, false);
|
|
||||||
window.addEventListener('scroll', this.onScroll, { passive: true });
|
window.addEventListener('scroll', this.onScroll, { passive: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.removeEventListener('visibilitychange', this.onVisibilitychange);
|
|
||||||
window.removeEventListener('scroll', this.onScroll);
|
window.removeEventListener('scroll', this.onScroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -147,10 +143,9 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// 投稿が自分のものではないかつ、タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
|
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
|
||||||
if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) {
|
if (document.hidden || !this.isScrollTop()) {
|
||||||
this.unreadCount++;
|
this.$store.commit('pushBehindNote', note);
|
||||||
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isScrollTop()) {
|
if (this.isScrollTop()) {
|
||||||
@@ -195,21 +190,9 @@ export default Vue.extend({
|
|||||||
this.moreFetching = false;
|
this.moreFetching = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
clearNotification() {
|
|
||||||
this.unreadCount = 0;
|
|
||||||
document.title = (this as any).os.instanceName;
|
|
||||||
},
|
|
||||||
|
|
||||||
onVisibilitychange() {
|
|
||||||
if (!document.hidden) {
|
|
||||||
this.clearNotification();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if (this.isScrollTop()) {
|
if (this.isScrollTop()) {
|
||||||
this.releaseQueue();
|
this.releaseQueue();
|
||||||
this.clearNotification();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll !== false) {
|
||||||
|
@@ -97,6 +97,9 @@
|
|||||||
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
||||||
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
|
<ui-switch v-model="deckDefault">%i18n:@deck-default%</ui-switch>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
||||||
<ui-switch v-model="useShadow">%i18n:@use-shadow%</ui-switch>
|
<ui-switch v-model="useShadow">%i18n:@use-shadow%</ui-switch>
|
||||||
@@ -366,6 +369,11 @@ export default Vue.extend({
|
|||||||
set(value) { this.$store.commit('device/set', { key: 'deckColumnAlign', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'deckColumnAlign', value }); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deckDefault: {
|
||||||
|
get() { return this.$store.state.device.deckDefault; },
|
||||||
|
set(value) { this.$store.commit('device/set', { key: 'deckDefault', value }); }
|
||||||
|
},
|
||||||
|
|
||||||
enableSounds: {
|
enableSounds: {
|
||||||
get() { return this.$store.state.device.enableSounds; },
|
get() { return this.$store.state.device.enableSounds; },
|
||||||
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
||||||
<a class="reply" v-if="note.replyId">%fa:reply%</a>
|
<a class="reply" v-if="note.replyId">%fa:reply%</a>
|
||||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
||||||
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
|
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
|
||||||
</div>
|
</div>
|
||||||
<details v-if="note.files.length > 0">
|
<details v-if="note.files.length > 0">
|
||||||
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
|
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
|
||||||
|
@@ -2,18 +2,22 @@
|
|||||||
<div class="nav">
|
<div class="nav">
|
||||||
<ul>
|
<ul>
|
||||||
<template v-if="$store.getters.isSignedIn">
|
<template v-if="$store.getters.isSignedIn">
|
||||||
<li class="home" :class="{ active: $route.name == 'index' }" @click="goToTop">
|
<template v-if="$store.state.device.deckDefault">
|
||||||
<router-link to="/">
|
<li class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop">
|
||||||
%fa:home%
|
<router-link to="/">%fa:columns%<p>%i18n:@deck%</p></router-link>
|
||||||
<p>%i18n:@home%</p>
|
</li>
|
||||||
</router-link>
|
<li class="home" :class="{ active: $route.name == 'home' }" @click="goToTop">
|
||||||
|
<router-link to="/home">%fa:home%<p>%i18n:@home%</p></router-link>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<li class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop">
|
||||||
|
<router-link to="/">%fa:home%<p>%i18n:@home%</p></router-link>
|
||||||
</li>
|
</li>
|
||||||
<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
<li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
||||||
<router-link to="/deck">
|
<router-link to="/deck">%fa:columns%<p>%i18n:@deck%</p></router-link>
|
||||||
%fa:columns%
|
|
||||||
<p>%i18n:@deck%</p>
|
|
||||||
</router-link>
|
|
||||||
</li>
|
</li>
|
||||||
|
</template>
|
||||||
<li class="messaging">
|
<li class="messaging">
|
||||||
<a @click="messaging">
|
<a @click="messaging">
|
||||||
%fa:comments%
|
%fa:comments%
|
||||||
|
@@ -6,12 +6,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav" v-if="$store.getters.isSignedIn">
|
<div class="nav" v-if="$store.getters.isSignedIn">
|
||||||
<div class="home" :class="{ active: $route.name == 'index' }" @click="goToTop">
|
<template v-if="$store.state.device.deckDefault">
|
||||||
|
<div class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop">
|
||||||
|
<router-link to="/">%fa:columns%</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="home" :class="{ active: $route.name == 'home' }" @click="goToTop">
|
||||||
|
<router-link to="/home">%fa:home%</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop">
|
||||||
<router-link to="/">%fa:home%</router-link>
|
<router-link to="/">%fa:home%</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
||||||
<router-link to="/deck">%fa:columns%</router-link>
|
<router-link to="/deck">%fa:columns%</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
<div class="messaging">
|
<div class="messaging">
|
||||||
<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a>
|
<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-widgets-column v-if="column.type == 'widgets'" :column="column" :is-stacked="isStacked"/>
|
<x-widgets-column v-if="column.type == 'widgets'" :column="column" :is-stacked="isStacked"/>
|
||||||
<x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked"/>
|
<x-notifications-column v-else-if="column.type == 'notifications'" :column="column" :is-stacked="isStacked"/>
|
||||||
<x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'home'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'local'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-tl-column v-else-if="column.type == 'hybrid'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'hybrid'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'global'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked"/>
|
<x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
<x-direct-column v-else-if="column.type == 'direct'" :column="column" :is-stacked="isStacked"/>
|
<x-direct-column v-else-if="column.type == 'direct'" :column="column" :is-stacked="isStacked" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -38,6 +38,16 @@ export default Vue.extend({
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
focus() {
|
||||||
|
this.$children[0].focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
||||||
<span slot="header">%fa:envelope R%{{ name }}</span>
|
<span slot="header">%fa:envelope R%{{ name }}</span>
|
||||||
|
|
||||||
<x-direct/>
|
<x-direct @parentFocus="parentFocus"/>
|
||||||
</x-column>
|
</x-column>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -34,5 +34,15 @@ export default Vue.extend({
|
|||||||
return '%i18n:common.deck.direct%';
|
return '%i18n:common.deck.direct%';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
focus() {
|
||||||
|
this.$refs.tl.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-notes ref="timeline" :more="existMore ? more : null"/>
|
<x-notes ref="timeline" :more="existMore ? more : null" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -58,6 +58,7 @@ export default Vue.extend({
|
|||||||
}, rej);
|
}, rej);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
@@ -82,12 +83,21 @@ export default Vue.extend({
|
|||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
if (note.visibility == 'specified') {
|
if (note.visibility == 'specified') {
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.timeline.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<x-column>
|
||||||
|
<span slot="header">
|
||||||
|
%fa:hashtag%<span>{{ tag }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<x-hashtag-tl :tag-tl="tagTl"/>
|
||||||
|
</x-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import XColumn from './deck.column.vue';
|
||||||
|
import XHashtagTl from './deck.hashtag-tl.vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XColumn,
|
||||||
|
XHashtagTl
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
tagTl(): any {
|
||||||
|
return {
|
||||||
|
query: [[this.tag]]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/>
|
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -80,6 +80,7 @@ export default Vue.extend({
|
|||||||
}, rej);
|
}, rej);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
@@ -105,12 +106,21 @@ export default Vue.extend({
|
|||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
if (this.mediaOnly && note.files.length == 0) return;
|
if (this.mediaOnly && note.files.length == 0) return;
|
||||||
|
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.timeline.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/>
|
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -84,6 +84,7 @@ export default Vue.extend({
|
|||||||
}, rej);
|
}, rej);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
@@ -109,18 +110,29 @@ export default Vue.extend({
|
|||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
if (this.mediaOnly && note.files.length == 0) return;
|
if (this.mediaOnly && note.files.length == 0) return;
|
||||||
|
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
},
|
},
|
||||||
|
|
||||||
onUserAdded() {
|
onUserAdded() {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
onUserRemoved() {
|
onUserRemoved() {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.timeline.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
||||||
<span slot="header">%fa:at%{{ name }}</span>
|
<span slot="header">%fa:at%{{ name }}</span>
|
||||||
|
|
||||||
<x-mentions/>
|
<x-mentions ref="tl" @parentFocus="parentFocus"/>
|
||||||
</x-column>
|
</x-column>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -34,5 +34,15 @@ export default Vue.extend({
|
|||||||
return '%i18n:common.deck.mentions%';
|
return '%i18n:common.deck.mentions%';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
focus() {
|
||||||
|
this.$refs.tl.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-notes ref="timeline" :more="existMore ? more : null"/>
|
<x-notes ref="timeline" :more="existMore ? more : null" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -57,6 +57,7 @@ export default Vue.extend({
|
|||||||
}, rej);
|
}, rej);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
@@ -80,10 +81,19 @@ export default Vue.extend({
|
|||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
onNote(note) {
|
||||||
// Prepend a note
|
// Prepend a note
|
||||||
(this.$refs.timeline as any).prepend(note);
|
(this.$refs.timeline as any).prepend(note);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.timeline.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -14,10 +14,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||||
<!--<transition-group name="mk-notes" class="transition">-->
|
<!--<transition-group name="mk-notes" class="transition" ref="notes">-->
|
||||||
<div class="notes">
|
<div class="notes" ref="notes">
|
||||||
<template v-for="(note, i) in _notes">
|
<template v-for="(note, i) in _notes">
|
||||||
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView" :mini="true"/>
|
<x-note
|
||||||
|
:note="note"
|
||||||
|
:key="note.id"
|
||||||
|
@update:note="onNoteUpdated(i, $event)"
|
||||||
|
:media-view="mediaView"
|
||||||
|
:mini="true"
|
||||||
|
@parentFocus="parentFocus"/>
|
||||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||||
<span>%fa:angle-up%{{ note._datetext }}</span>
|
<span>%fa:angle-up%{{ note._datetext }}</span>
|
||||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||||
@@ -102,7 +108,11 @@ export default Vue.extend({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
focus() {
|
focus() {
|
||||||
(this.$el as any).children[0].focus();
|
(this.$refs.notes as any).children[0].focus ? (this.$refs.notes as any).children[0].focus() : (this.$refs.notes as any).$el.children[0].focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
},
|
},
|
||||||
|
|
||||||
onNoteUpdated(i, note) {
|
onNoteUpdated(i, note) {
|
||||||
@@ -154,6 +164,11 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
|
||||||
|
if (document.hidden || !this.isScrollTop()) {
|
||||||
|
this.$store.commit('pushBehindNote', note);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isScrollTop()) {
|
if (this.isScrollTop()) {
|
||||||
// Prepend the note
|
// Prepend the note
|
||||||
this.notes.unshift(note);
|
this.notes.unshift(note);
|
||||||
|
@@ -14,9 +14,28 @@
|
|||||||
<ui-switch v-model="column.isMediaOnly" @change="onChangeSettings">%i18n:@is-media-only%</ui-switch>
|
<ui-switch v-model="column.isMediaOnly" @change="onChangeSettings">%i18n:@is-media-only%</ui-switch>
|
||||||
<ui-switch v-model="column.isMediaView" @change="onChangeSettings">%i18n:@is-media-view%</ui-switch>
|
<ui-switch v-model="column.isMediaView" @change="onChangeSettings">%i18n:@is-media-view%</ui-switch>
|
||||||
</div>
|
</div>
|
||||||
<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
|
|
||||||
<x-hashtag-tl v-else-if="column.type == 'hashtag'" :tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
|
<x-list-tl v-if="column.type == 'list'"
|
||||||
<x-tl v-else :src="column.type" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
|
:list="column.list"
|
||||||
|
:media-only="column.isMediaOnly"
|
||||||
|
:media-view="column.isMediaView"
|
||||||
|
ref="tl"
|
||||||
|
@parentFocus="parentFocus"
|
||||||
|
/>
|
||||||
|
<x-hashtag-tl v-else-if="column.type == 'hashtag'"
|
||||||
|
:tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)"
|
||||||
|
:media-only="column.isMediaOnly"
|
||||||
|
:media-view="column.isMediaView"
|
||||||
|
ref="tl"
|
||||||
|
@parentFocus="parentFocus"
|
||||||
|
/>
|
||||||
|
<x-tl v-else
|
||||||
|
:src="column.type"
|
||||||
|
:media-only="column.isMediaOnly"
|
||||||
|
:media-view="column.isMediaView"
|
||||||
|
ref="tl"
|
||||||
|
@parentFocus="parentFocus"
|
||||||
|
/>
|
||||||
</x-column>
|
</x-column>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -77,7 +96,15 @@ export default Vue.extend({
|
|||||||
methods: {
|
methods: {
|
||||||
onChangeSettings(v) {
|
onChangeSettings(v) {
|
||||||
this.$store.dispatch('settings/saveDeck');
|
this.$store.dispatch('settings/saveDeck');
|
||||||
}
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.tl.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/>
|
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView" @parentFocus="parentFocus"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -143,7 +143,11 @@ export default Vue.extend({
|
|||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
(this.$refs.timeline as any).focus();
|
(this.$refs.timeline as any).focus();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
parentFocus(direction) {
|
||||||
|
this.$emit('parentFocus', direction);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,17 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-ui :class="$style.root">
|
<mk-ui :class="$style.root">
|
||||||
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :style="style" :class="{ center: $store.state.device.deckColumnAlign == 'center' }">
|
<div class="qlvquzbjribqcaozciifydkngcwtyzje" ref="body" :style="style" :class="{ center: $store.state.device.deckColumnAlign == 'center' }" v-hotkey.global="keymap">
|
||||||
<template v-for="ids in layout">
|
<template v-for="ids in layout">
|
||||||
<div v-if="ids.length > 1" class="folder">
|
<div v-if="ids.length > 1" class="folder">
|
||||||
<template v-for="id, i in ids">
|
<template v-for="id, i in ids">
|
||||||
<x-column-core :ref="id" :key="id" :column="columns.find(c => c.id == id)" :is-stacked="true"/>
|
<x-column-core :ref="id" :key="id" :column="columns.find(c => c.id == id)" :is-stacked="true" @parentFocus="moveFocus(id, $event)"/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])"/>
|
<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])" @parentFocus="moveFocus(ids[0], $event)"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="temporaryColumn">
|
<template v-if="temporaryColumn">
|
||||||
<x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/>
|
<x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/>
|
||||||
<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/>
|
<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/>
|
||||||
|
<x-hashtag-column v-else-if="temporaryColumn.type == 'tag'" :tag="temporaryColumn.tag" :key="temporaryColumn.tag"/>
|
||||||
</template>
|
</template>
|
||||||
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
|
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,6 +26,7 @@ import Menu from '../../../../common/views/components/menu.vue';
|
|||||||
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
||||||
import XUserColumn from './deck.user-column.vue';
|
import XUserColumn from './deck.user-column.vue';
|
||||||
import XNoteColumn from './deck.note-column.vue';
|
import XNoteColumn from './deck.note-column.vue';
|
||||||
|
import XHashtagColumn from './deck.hashtag-column.vue';
|
||||||
|
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
@@ -32,7 +34,8 @@ export default Vue.extend({
|
|||||||
components: {
|
components: {
|
||||||
XColumnCore,
|
XColumnCore,
|
||||||
XUserColumn,
|
XUserColumn,
|
||||||
XNoteColumn
|
XNoteColumn,
|
||||||
|
XHashtagColumn
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
@@ -55,6 +58,25 @@ export default Vue.extend({
|
|||||||
|
|
||||||
temporaryColumn(): any {
|
temporaryColumn(): any {
|
||||||
return this.$store.state.device.deckTemporaryColumn;
|
return this.$store.state.device.deckTemporaryColumn;
|
||||||
|
},
|
||||||
|
|
||||||
|
keymap(): any {
|
||||||
|
return {
|
||||||
|
't': this.focus
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
temporaryColumn() {
|
||||||
|
if (this.temporaryColumn != null) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.body.scrollTo({
|
||||||
|
left: this.$refs.body.scrollWidth - this.$refs.body.clientWidth,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -143,6 +165,15 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
} else if (to.name == 'tag') {
|
||||||
|
this.$store.commit('device/set', {
|
||||||
|
key: 'deckTemporaryColumn',
|
||||||
|
value: {
|
||||||
|
type: 'tag',
|
||||||
|
tag: to.params.tag
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -253,6 +284,71 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
// Flatten array of arrays
|
||||||
|
const ids = [].concat.apply([], this.layout);
|
||||||
|
const firstTl = ids.find(id => this.isTlColumn(id));
|
||||||
|
|
||||||
|
if (firstTl) {
|
||||||
|
this.$refs[firstTl][0].focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
moveFocus(id, direction) {
|
||||||
|
let targetColumn;
|
||||||
|
|
||||||
|
if (direction == 'right') {
|
||||||
|
const currentColumnIndex = this.layout.findIndex(ids => ids.includes(id));
|
||||||
|
this.layout.some((ids, i) => {
|
||||||
|
if (i <= currentColumnIndex) return false;
|
||||||
|
const tl = ids.find(id => this.isTlColumn(id));
|
||||||
|
if (tl) {
|
||||||
|
targetColumn = tl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (direction == 'left') {
|
||||||
|
const currentColumnIndex = [...this.layout].reverse().findIndex(ids => ids.includes(id));
|
||||||
|
[...this.layout].reverse().some((ids, i) => {
|
||||||
|
if (i <= currentColumnIndex) return false;
|
||||||
|
const tl = ids.find(id => this.isTlColumn(id));
|
||||||
|
if (tl) {
|
||||||
|
targetColumn = tl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (direction == 'down') {
|
||||||
|
const currentColumn = this.layout.find(ids => ids.includes(id));
|
||||||
|
const currentIndex = currentColumn.indexOf(id);
|
||||||
|
currentColumn.some((_id, i) => {
|
||||||
|
if (i <= currentIndex) return false;
|
||||||
|
if (this.isTlColumn(_id)) {
|
||||||
|
targetColumn = _id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (direction == 'up') {
|
||||||
|
const currentColumn = [...this.layout.find(ids => ids.includes(id))].reverse();
|
||||||
|
const currentIndex = currentColumn.indexOf(id);
|
||||||
|
currentColumn.some((_id, i) => {
|
||||||
|
if (i <= currentIndex) return false;
|
||||||
|
if (this.isTlColumn(_id)) {
|
||||||
|
targetColumn = _id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetColumn) {
|
||||||
|
this.$refs[targetColumn][0].focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isTlColumn(id) {
|
||||||
|
const column = this.columns.find(c => c.id === id);
|
||||||
|
return ['home', 'local', 'hybrid', 'global', 'list', 'hashtag', 'mentions', 'direct'].includes(column.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -1,16 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="$store.getters.isSignedIn ? 'home' : 'welcome'"></component>
|
<component :is="page"></component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Home from './home.vue';
|
import Home from './home.vue';
|
||||||
import Welcome from './welcome.vue';
|
import Welcome from './welcome.vue';
|
||||||
|
import Deck from './deck/deck.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
Home,
|
Home,
|
||||||
|
Deck,
|
||||||
Welcome
|
Welcome
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
page(): string {
|
||||||
|
if (!this.$store.getters.isSignedIn) return 'welcome';
|
||||||
|
return this.$store.state.device.deckDefault ? 'deck' : 'home';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -161,6 +161,12 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (!document.hidden) {
|
||||||
|
os.store.commit('clearBehindNotes');
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
Vue.mixin({
|
Vue.mixin({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||||
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||||
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
||||||
<a class="rp" v-if="appearNote.renote != null">RP:</a>
|
<a class="rp" v-if="appearNote.renote != null">RN:</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="appearNote.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<mk-media-list :media-list="appearNote.files"/>
|
<mk-media-list :media-list="appearNote.files"/>
|
||||||
|
@@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import getNoteSummary from '../../../../../misc/get-note-summary';
|
|
||||||
|
|
||||||
const displayLimit = 30;
|
const displayLimit = 30;
|
||||||
|
|
||||||
@@ -54,7 +53,6 @@ export default Vue.extend({
|
|||||||
requestInitPromise: null as () => Promise<any[]>,
|
requestInitPromise: null as () => Promise<any[]>,
|
||||||
notes: [],
|
notes: [],
|
||||||
queue: [],
|
queue: [],
|
||||||
unreadCount: 0,
|
|
||||||
fetching: true,
|
fetching: true,
|
||||||
moreFetching: false
|
moreFetching: false
|
||||||
};
|
};
|
||||||
@@ -83,12 +81,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('visibilitychange', this.onVisibilitychange, false);
|
|
||||||
window.addEventListener('scroll', this.onScroll, { passive: true });
|
window.addEventListener('scroll', this.onScroll, { passive: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.removeEventListener('visibilitychange', this.onVisibilitychange);
|
|
||||||
window.removeEventListener('scroll', this.onScroll);
|
window.removeEventListener('scroll', this.onScroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -146,10 +142,9 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// 投稿が自分のものではないかつ、タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
|
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
|
||||||
if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) {
|
if (document.hidden || !this.isScrollTop()) {
|
||||||
this.unreadCount++;
|
this.$store.commit('pushBehindNote', note);
|
||||||
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isScrollTop()) {
|
if (this.isScrollTop()) {
|
||||||
@@ -187,21 +182,9 @@ export default Vue.extend({
|
|||||||
this.moreFetching = false;
|
this.moreFetching = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
clearNotification() {
|
|
||||||
this.unreadCount = 0;
|
|
||||||
document.title = (this as any).os.instanceName;
|
|
||||||
},
|
|
||||||
|
|
||||||
onVisibilitychange() {
|
|
||||||
if (!document.hidden) {
|
|
||||||
this.clearNotification();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if (this.isScrollTop()) {
|
if (this.isScrollTop()) {
|
||||||
this.releaseQueue();
|
this.releaseQueue();
|
||||||
this.clearNotification();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll !== false) {
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
||||||
<a class="reply" v-if="note.replyId">%fa:reply%</a>
|
<a class="reply" v-if="note.replyId">%fa:reply%</a>
|
||||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
||||||
<a class="rp" v-if="note.renoteId">RP: ...</a>
|
<a class="rp" v-if="note.renoteId">RN: ...</a>
|
||||||
</div>
|
</div>
|
||||||
<details v-if="note.files.length > 0">
|
<details v-if="note.files.length > 0">
|
||||||
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
|
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
|
||||||
|
@@ -5,6 +5,7 @@ import * as nestedProperty from 'nested-property';
|
|||||||
import MiOS from './mios';
|
import MiOS from './mios';
|
||||||
import { hostname } from './config';
|
import { hostname } from './config';
|
||||||
import { erase } from '../../prelude/array';
|
import { erase } from '../../prelude/array';
|
||||||
|
import getNoteSummary from '../../misc/get-note-summary';
|
||||||
|
|
||||||
const defaultSettings = {
|
const defaultSettings = {
|
||||||
home: null,
|
home: null,
|
||||||
@@ -60,7 +61,8 @@ const defaultDeviceSettings = {
|
|||||||
navbar: 'top',
|
navbar: 'top',
|
||||||
deckColumnAlign: 'center',
|
deckColumnAlign: 'center',
|
||||||
mobileNotificationPosition: 'bottom',
|
mobileNotificationPosition: 'bottom',
|
||||||
deckTemporaryColumn: null
|
deckTemporaryColumn: null,
|
||||||
|
deckDefault: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (os: MiOS) => new Vuex.Store({
|
export default (os: MiOS) => new Vuex.Store({
|
||||||
@@ -72,7 +74,8 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
i: null,
|
i: null,
|
||||||
indicate: false,
|
indicate: false,
|
||||||
uiHeaderHeight: 0,
|
uiHeaderHeight: 0,
|
||||||
navHook: null
|
navHook: null,
|
||||||
|
behindNotes: []
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
@@ -98,6 +101,18 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
|
|
||||||
navHook(state, callback) {
|
navHook(state, callback) {
|
||||||
state.navHook = callback;
|
state.navHook = callback;
|
||||||
|
},
|
||||||
|
|
||||||
|
pushBehindNote(state, note) {
|
||||||
|
if (note.userId === state.i.id) return;
|
||||||
|
if (state.behindNotes.some(n => n.id === note.id)) return;
|
||||||
|
state.behindNotes.push(note);
|
||||||
|
document.title = `(${state.behindNotes.length}) ${getNoteSummary(note)}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearBehindNotes(state) {
|
||||||
|
state.behindNotes = [];
|
||||||
|
document.title = os.instanceName;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -25,9 +25,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr><td><kbd class="key">↑</kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr>
|
<tr><td><kbd class="key">↑</kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr>
|
||||||
<tr><td><kbd class="key">↓</kbd>, <kbd class="key">J</kbd>, <kbd class="key">Tab</kbd></td><td>下の投稿にフォーカスを移動</td><td>-</td></tr>
|
<tr><td><kbd class="key">↓</kbd>, <kbd class="key">J</kbd>, <kbd class="key">Tab</kbd></td><td>下の投稿にフォーカスを移動</td><td>-</td></tr>
|
||||||
<tr><td><kbd class="key">←</kbd>, <kbd class="key">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
|
<tr><td><kbd class="key">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
|
||||||
<tr><td><kbd class="key">→</kbd>, <kbd class="key">Q</kbd></td><td>Renoteフォームを開く</td><td><b>Q</b>uote</td></tr>
|
<tr><td><kbd class="key">Q</kbd></td><td>Renoteフォームを開く</td><td><b>Q</b>uote</td></tr>
|
||||||
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">→</kbd></kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
|
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
|
||||||
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
|
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
|
||||||
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
|
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
|
||||||
<tr><td><kbd class="key">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
|
<tr><td><kbd class="key">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
|
||||||
@@ -86,6 +86,19 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
## デッキ
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>投稿にフォーカスした状態で<kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">↑</kbd></kbd></td><td>上のカラムにフォーカス</td><td>-</td></tr>
|
||||||
|
<tr><td>投稿にフォーカスした状態で<kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">↓</kbd></kbd></td><td>下のカラムにフォーカス</td><td>-</td></tr>
|
||||||
|
<tr><td>投稿にフォーカスした状態で<kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">→</kbd></kbd></td><td>右のカラムにフォーカス</td><td>-</td></tr>
|
||||||
|
<tr><td>投稿にフォーカスした状態で<kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">←</kbd></kbd></td><td>左のカラムにフォーカス</td><td>-</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
# 例
|
# 例
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
@@ -38,9 +38,9 @@ const summarize = (note: any): string => {
|
|||||||
// Renoteのとき
|
// Renoteのとき
|
||||||
if (note.renoteId) {
|
if (note.renoteId) {
|
||||||
if (note.renote) {
|
if (note.renote) {
|
||||||
summary += ` RP: ${summarize(note.renote)}`;
|
summary += ` RN: ${summarize(note.renote)}`;
|
||||||
} else {
|
} else {
|
||||||
summary += ' RP: ...';
|
summary += ' RN: ...';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user