diff --git a/packages/frontend/src/pages/following-feed.vue b/packages/frontend/src/pages/following-feed.vue index fac2857d46..d45f572739 100644 --- a/packages/frontend/src/pages/following-feed.vue +++ b/packages/frontend/src/pages/following-feed.vue @@ -39,13 +39,6 @@ SPDX-License-Identifier: AGPL-3.0-only - - - - diff --git a/packages/frontend/src/scripts/following-feed-utils.ts b/packages/frontend/src/scripts/following-feed-utils.ts new file mode 100644 index 0000000000..064d6b72e3 --- /dev/null +++ b/packages/frontend/src/scripts/following-feed-utils.ts @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { computed } from 'vue'; +import { defaultStore } from '@/store.js'; +import { deepMerge } from '@/scripts/merge.js'; +import { PageHeaderItem } from '@/types/page-header.js'; +import { i18n } from '@/i18n.js'; +import { popupMenu } from '@/os.js'; + +export const followingTab = 'following' as const; +export const mutualsTab = 'mutuals' as const; +export const followersTab = 'followers' as const; +export type FollowingFeedTab = typeof followingTab | typeof mutualsTab | typeof followersTab; + +export function createOptions(): PageHeaderItem { + const { + userList, + withNonPublic, + withQuotes, + withBots, + withReplies, + onlyFiles, + } = createModel(); + + return { + icon: 'ti ti-dots', + text: i18n.ts.options, + handler: ev => + popupMenu([ + { + type: 'switch', + text: i18n.ts.showNonPublicNotes, + ref: withNonPublic, + disabled: userList.value === 'followers', + }, + { + type: 'switch', + text: i18n.ts.showQuotes, + ref: withQuotes, + }, + { + type: 'switch', + text: i18n.ts.showBots, + ref: withBots, + }, + { + type: 'switch', + text: i18n.ts.showReplies, + ref: withReplies, + disabled: onlyFiles, + }, + { + type: 'divider', + }, + { + type: 'switch', + text: i18n.ts.fileAttachedOnly, + ref: onlyFiles, + disabled: withReplies, + }, + ], ev.currentTarget ?? ev.target), + }; +} + +export function createModel() { + const userList = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.userList, + set: value => saveFollowingFilter('userList', value), + }); + + const withNonPublic = computed({ + get: () => { + if (userList.value === 'followers') return false; + return defaultStore.reactiveState.followingFeed.value.withNonPublic; + }, + set: value => saveFollowingFilter('withNonPublic', value), + }); + const withQuotes = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.withQuotes, + set: value => saveFollowingFilter('withQuotes', value), + }); + const withBots = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.withBots, + set: value => saveFollowingFilter('withBots', value), + }); + const withReplies = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.withReplies, + set: value => saveFollowingFilter('withReplies', value), + }); + const onlyFiles = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.onlyFiles, + set: value => saveFollowingFilter('onlyFiles', value), + }); + + const remoteWarningDismissed = computed({ + get: () => defaultStore.reactiveState.followingFeed.value.remoteWarningDismissed, + set: value => saveFollowingFilter('remoteWarningDismissed', value), + }); + + return { + userList, + withNonPublic, + withQuotes, + withBots, + withReplies, + onlyFiles, + remoteWarningDismissed, + }; +} + +// Based on timeline.saveTlFilter() +function saveFollowingFilter(key: Key, value: (typeof defaultStore.state.followingFeed)[Key]) { + const out = deepMerge({ [key]: value }, defaultStore.state.followingFeed); + return defaultStore.set('followingFeed', out); +} diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 5d0395d774..fd84ad2e4d 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -11,7 +11,7 @@ import darkTheme from '@@/themes/d-ice.json5'; import { miLocalStorage } from './local-storage.js'; import { searchEngineMap } from './scripts/search-engine-map.js'; import type { SoundType } from '@/scripts/sound.js'; -import type { FollowingFeedTab } from '@/pages/following-feed.vue'; +import type { FollowingFeedTab } from '@/scripts/following-feed-utils.js'; import { Storage } from '@/pizzax.js'; interface PostFormAction {