mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-22 21:45:13 +01:00
feat(frontend): 任意のユーザーリストをタイムラインページにピン留めできるように
This commit is contained in:
parent
bec338aa00
commit
299c9c4118
6 changed files with 49 additions and 7 deletions
|
@ -32,6 +32,8 @@
|
||||||
- ローカリゼーションの更新
|
- ローカリゼーションの更新
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
- 任意のユーザーリストをタイムラインページにピン留めできるように
|
||||||
|
- 設定->クライアント設定->全般 から設定可能です
|
||||||
- ノート詳細ページを改修
|
- ノート詳細ページを改修
|
||||||
- 読み込み時のパフォーマンスが向上しました
|
- 読み込み時のパフォーマンスが向上しました
|
||||||
- リノート一覧、リアクション一覧がタブとして追加されました
|
- リノート一覧、リアクション一覧がタブとして追加されました
|
||||||
|
|
1
locales/index.d.ts
vendored
1
locales/index.d.ts
vendored
|
@ -1114,6 +1114,7 @@ export interface Locale {
|
||||||
"renotes": string;
|
"renotes": string;
|
||||||
"loadReplies": string;
|
"loadReplies": string;
|
||||||
"loadConversation": string;
|
"loadConversation": string;
|
||||||
|
"pinnedList": string;
|
||||||
"_announcement": {
|
"_announcement": {
|
||||||
"forExistingUsers": string;
|
"forExistingUsers": string;
|
||||||
"forExistingUsersDescription": string;
|
"forExistingUsersDescription": string;
|
||||||
|
|
|
@ -1111,6 +1111,7 @@ replies: "返信"
|
||||||
renotes: "リノート"
|
renotes: "リノート"
|
||||||
loadReplies: "返信を見る"
|
loadReplies: "返信を見る"
|
||||||
loadConversation: "会話を見る"
|
loadConversation: "会話を見る"
|
||||||
|
pinnedList: "ピン留めされたリスト"
|
||||||
|
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "既存ユーザーのみ"
|
forExistingUsers: "既存ユーザーのみ"
|
||||||
|
|
|
@ -30,6 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch>
|
<MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch>
|
||||||
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
|
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
|
||||||
<MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
|
<MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
|
||||||
|
<MkFolder>
|
||||||
|
<template #label>{{ i18n.ts.pinnedList }}</template>
|
||||||
|
<!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
|
||||||
|
<MkButton v-if="defaultStore.reactiveState.pinnedUserLists.value.length === 0" @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
|
||||||
|
<MkButton v-else danger @click="removePinnedList()"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
|
||||||
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
@ -307,6 +313,23 @@ function removeEmojiIndex(lang: string) {
|
||||||
os.promiseDialog(main());
|
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 smashCount = 0;
|
||||||
let smashTimer: number | null = null;
|
let smashTimer: number | null = null;
|
||||||
function testNotification(): void {
|
function testNotification(): void {
|
||||||
|
|
|
@ -16,7 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTimeline
|
<MkTimeline
|
||||||
ref="tlComponent"
|
ref="tlComponent"
|
||||||
:key="src"
|
:key="src"
|
||||||
:src="src"
|
:src="src.split(':')[0]"
|
||||||
|
:list="src.split(':')[1]"
|
||||||
:sound="true"
|
:sound="true"
|
||||||
@queue="queueUpdated"
|
@queue="queueUpdated"
|
||||||
/>
|
/>
|
||||||
|
@ -102,10 +103,15 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
|
||||||
os.popupMenu(items, ev.currentTarget ?? ev.target);
|
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.set('tl', {
|
||||||
...defaultStore.state.tl,
|
|
||||||
src: newSrc,
|
src: newSrc,
|
||||||
|
userList,
|
||||||
});
|
});
|
||||||
srcWhenNotSignin = newSrc;
|
srcWhenNotSignin = newSrc;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +131,12 @@ function focus(): void {
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
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',
|
key: 'home',
|
||||||
title: i18n.ts._timelines.home,
|
title: i18n.ts._timelines.home,
|
||||||
icon: 'ti ti-home',
|
icon: 'ti ti-home',
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { markRaw, ref } from 'vue';
|
import { markRaw, ref } from 'vue';
|
||||||
import misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { Storage } from './pizzax';
|
import { Storage } from './pizzax';
|
||||||
|
|
||||||
interface PostFormAction {
|
interface PostFormAction {
|
||||||
|
@ -163,10 +163,14 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
tl: {
|
tl: {
|
||||||
where: 'deviceAccount',
|
where: 'deviceAccount',
|
||||||
default: {
|
default: {
|
||||||
src: 'home' as 'home' | 'local' | 'social' | 'global',
|
src: 'home' as 'home' | 'local' | 'social' | 'global' | `list:${string}`,
|
||||||
arg: null,
|
userList: null as Misskey.entities.UserList | null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
pinnedUserLists: {
|
||||||
|
where: 'deviceAccount',
|
||||||
|
default: [] as Misskey.entities.UserList[],
|
||||||
|
},
|
||||||
|
|
||||||
overridedDeviceKind: {
|
overridedDeviceKind: {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
|
|
Loading…
Reference in a new issue