From 5c48878dc558ff873e1633b9ad7abd3bee6b2fcb Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 19 Sep 2023 09:36:07 +0900 Subject: [PATCH 1/3] =?UTF-8?q?enhance(dev):=20=E9=96=A2=E6=95=B0=E5=91=BC?= =?UTF-8?q?=E3=81=B3=E5=87=BA=E3=81=97=E3=81=AE=E5=89=8D=E3=81=AB=E3=82=B9?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B9=E3=82=92=E5=85=A5=E3=82=8C=E3=82=8B?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=82=92=E8=A8=B1=E5=8F=AF=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/timeline.vue | 2 +- packages/shared/.eslintrc.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index f0ef2d10a1..307d77882b 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -58,7 +58,7 @@ let queue = $ref(0); let srcWhenNotSignin = $ref(isLocalTimelineAvailable ? 'local' : 'global'); const src = $computed({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin), set: (x) => saveSrc(x) }); -watch ($$(src), () => queue = 0); +watch($$(src), () => queue = 0); function queueUpdated(q: number): void { queue = q; diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js index 89d1151683..cb6bd56f9c 100644 --- a/packages/shared/.eslintrc.js +++ b/packages/shared/.eslintrc.js @@ -64,6 +64,7 @@ module.exports = { 'object-curly-spacing': ['error', 'always'], 'space-infix-ops': ['error'], 'space-before-blocks': ['error', 'always'], + 'func-call-spacing': ['error', 'never'], '@typescript-eslint/no-explicit-any': ['warn'], '@typescript-eslint/no-unused-vars': ['warn'], '@typescript-eslint/no-unnecessary-condition': ['warn'], From bec338aa006719d6ef004b5b351eebdf47a62b50 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 19 Sep 2023 09:44:05 +0900 Subject: [PATCH 2/3] Update .eslintrc.js --- packages/shared/.eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js index cb6bd56f9c..1ecad7ab75 100644 --- a/packages/shared/.eslintrc.js +++ b/packages/shared/.eslintrc.js @@ -64,7 +64,7 @@ module.exports = { 'object-curly-spacing': ['error', 'always'], 'space-infix-ops': ['error'], 'space-before-blocks': ['error', 'always'], - 'func-call-spacing': ['error', 'never'], + '@typescript-eslint/func-call-spacing': ['error', 'never'], '@typescript-eslint/no-explicit-any': ['warn'], '@typescript-eslint/no-unused-vars': ['warn'], '@typescript-eslint/no-unnecessary-condition': ['warn'], From 299c9c41188df46b64b04ba53cbded7a89998b6c Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 19 Sep 2023 10:58:42 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat(frontend):=20=E4=BB=BB=E6=84=8F?= =?UTF-8?q?=E3=81=AE=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=83=AA=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=82=92=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E3=83=94=E3=83=B3?= =?UTF-8?q?=E7=95=99=E3=82=81=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../frontend/src/pages/settings/general.vue | 23 +++++++++++++++++++ packages/frontend/src/pages/timeline.vue | 19 +++++++++++---- packages/frontend/src/store.ts | 10 +++++--- 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c2552145..683c0a85a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ - ローカリゼーションの更新 ### Client +- 任意のユーザーリストをタイムラインページにピン留めできるように + - 設定->クライアント設定->全般 から設定可能です - ノート詳細ページを改修 - 読み込み時のパフォーマンスが向上しました - リノート一覧、リアクション一覧がタブとして追加されました diff --git a/locales/index.d.ts b/locales/index.d.ts index ac714258e2..bf7aff75df 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1114,6 +1114,7 @@ export interface Locale { "renotes": string; "loadReplies": string; "loadConversation": string; + "pinnedList": string; "_announcement": { "forExistingUsers": string; "forExistingUsersDescription": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d97b09f63c..2f88128c98 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1111,6 +1111,7 @@ replies: "返信" renotes: "リノート" loadReplies: "返信を見る" loadConversation: "会話を見る" +pinnedList: "ピン留めされたリスト" _announcement: forExistingUsers: "既存ユーザーのみ" diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index b486e6d80f..ff498e4164 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -30,6 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.showFixedPostForm }} {{ i18n.ts.showFixedPostFormInChannel }} {{ i18n.ts.flagShowTimelineReplies }} + + + + {{ i18n.ts.add }} + {{ i18n.ts.remove }} + @@ -307,6 +313,23 @@ function removeEmojiIndex(lang: string) { os.promiseDialog(main()); } +async function setPinnedList() { + const lists = await os.api('users/lists/list'); + const { canceled, result: list } = await os.select({ + title: i18n.ts.selectList, + items: lists.map(x => ({ + value: x, text: x.name, + })), + }); + if (canceled) return; + + defaultStore.set('pinnedUserLists', [list]); +} + +function removePinnedList() { + defaultStore.set('pinnedUserLists', []); +} + let smashCount = 0; let smashTimer: number | null = null; function testNotification(): void { diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 307d77882b..c0b1f03ff0 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -16,7 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -102,10 +103,15 @@ async function chooseChannel(ev: MouseEvent): Promise { os.popupMenu(items, ev.currentTarget ?? ev.target); } -function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global'): void { +function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global' | `list:${string}`): void { + let userList = null; + if (newSrc.startsWith('userList:')) { + const id = newSrc.substring('userList:'.length); + userList = defaultStore.reactiveState.pinnedUserLists.value.find(l => l.id === id); + } defaultStore.set('tl', { - ...defaultStore.state.tl, src: newSrc, + userList, }); srcWhenNotSignin = newSrc; } @@ -125,7 +131,12 @@ function focus(): void { const headerActions = $computed(() => []); -const headerTabs = $computed(() => [{ +const headerTabs = $computed(() => [...(defaultStore.reactiveState.pinnedUserLists.value.map(l => ({ + key: 'list:' + l.id, + title: l.name, + icon: 'ti ti-star', + iconOnly: true, +}))), { key: 'home', title: i18n.ts._timelines.home, icon: 'ti ti-home', diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 787a584f83..4b8001bfb4 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -4,7 +4,7 @@ */ import { markRaw, ref } from 'vue'; -import misskey from 'misskey-js'; +import * as Misskey from 'misskey-js'; import { Storage } from './pizzax'; interface PostFormAction { @@ -163,10 +163,14 @@ export const defaultStore = markRaw(new Storage('base', { tl: { where: 'deviceAccount', default: { - src: 'home' as 'home' | 'local' | 'social' | 'global', - arg: null, + src: 'home' as 'home' | 'local' | 'social' | 'global' | `list:${string}`, + userList: null as Misskey.entities.UserList | null, }, }, + pinnedUserLists: { + where: 'deviceAccount', + default: [] as Misskey.entities.UserList[], + }, overridedDeviceKind: { where: 'device',