Skip to content

Commit 116b8b9

Browse files
committed
feat(links): adds open links in background toggle
1 parent 2d507f4 commit 116b8b9

12 files changed

+75
-44
lines changed

src/components/common/list/ListItemPanel.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import ProgressTooltip from '~/components/common/tooltip/ProgressTooltip.vue';
1616
import { type ListScrollItem, type ShowProgress } from '~/models/list-scroll.model';
1717
1818
import { useShowStore } from '~/stores/data/show.store';
19-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
19+
import { useLinksStore } from '~/stores/settings/links.store';
2020
import { useI18n } from '~/utils';
2121
import { deCapitalise } from '~/utils/string.utils';
2222
@@ -92,7 +92,7 @@ const tooltipOptions = computed<PopoverProps>(() => ({
9292
delay: 500,
9393
}));
9494
95-
const { openTab } = useExtensionSettingsStore();
95+
const { openTab } = useLinksStore();
9696
const onTagClick = (url?: string) => {
9797
if (!url) return;
9898
openTab(url);

src/components/views/panel/MoviePanel.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
useListStore,
2323
} from '~/stores/data/list.store';
2424
import { useMovieStore, useMovieStoreRefs } from '~/stores/data/movie.store';
25-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
25+
import { useLinksStore } from '~/stores/settings/links.store';
2626
import { useI18n } from '~/utils';
2727
import { deCapitalise } from '~/utils/string.utils';
2828
@@ -191,7 +191,7 @@ const titleUrl = computed(() => {
191191
});
192192
});
193193
194-
const { openTab } = useExtensionSettingsStore();
194+
const { openTab } = useLinksStore();
195195
</script>
196196

197197
<template>

src/components/views/panel/PanelDetail.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { PropType } from 'vue';
55
import type { TagLink } from '~/models/tag.model';
66
77
import TagLinkComponent from '~/components/common/buttons/TagLink.vue';
8-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
8+
import { useLinksStore } from '~/stores/settings/links.store';
99
1010
defineProps({
1111
label: {
@@ -34,7 +34,7 @@ defineProps({
3434
},
3535
});
3636
37-
const { openTab } = useExtensionSettingsStore();
37+
const { openTab } = useLinksStore();
3838
</script>
3939

4040
<template>

src/components/views/panel/PanelOverview.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { NFlex, NH4, NSkeleton } from 'naive-ui';
33
44
import TitleLink from '~/components/common/buttons/TitleLink.vue';
5-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
5+
import { useLinksStore } from '~/stores/settings/links.store';
66
77
defineProps({
88
title: {
@@ -23,7 +23,7 @@ defineProps({
2323
},
2424
});
2525
26-
const { openTab } = useExtensionSettingsStore();
26+
const { openTab } = useLinksStore();
2727
</script>
2828

2929
<template>

src/components/views/panel/PersonPanel.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import PersonPanelOverview from '~/components/views/panel/PersonPanelOverview.vu
1111
1212
import { ResolveExternalLinks } from '~/settings/external.links';
1313
import { usePersonStore } from '~/stores/data/person.store';
14-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
14+
import { useLinksStore } from '~/stores/settings/links.store';
1515
import { useI18n } from '~/utils';
1616
import { deCapitalise } from '~/utils/string.utils';
1717
@@ -63,7 +63,7 @@ const titleUrl = computed(() => {
6363
});
6464
});
6565
66-
const { openTab } = useExtensionSettingsStore();
66+
const { openTab } = useLinksStore();
6767
</script>
6868

6969
<template>

src/components/views/panel/ShowPanel.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
useListStore,
2323
} from '~/stores/data/list.store';
2424
import { useShowStore } from '~/stores/data/show.store';
25-
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
25+
import { useLinksStore } from '~/stores/settings/links.store';
2626
import { useI18n } from '~/utils';
2727
import { deCapitalise } from '~/utils/string.utils';
2828
@@ -307,7 +307,7 @@ onMounted(() => {
307307
);
308308
});
309309
310-
const { openTab } = useExtensionSettingsStore();
310+
const { openTab } = useLinksStore();
311311
</script>
312312

313313
<template>

src/components/views/settings/SettingsCache.vue

+9-8
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ const cacheOptions = Object.entries(CacheRetention).map(([key, value]) => ({
1919
value,
2020
}));
2121
22-
const loading = reactive({});
22+
const loading = reactive<Record<string | number, boolean>>({});
2323
24-
const onClick = async (fn: () => Promise<void>, index: number) => {
24+
const onClick = async (fn: () => unknown, index: number) => {
2525
loading[index] = true;
2626
2727
try {
@@ -41,10 +41,10 @@ const evictScopes = [
4141
label: i18n('evict_progress'),
4242
click: () =>
4343
Promise.all([
44-
TraktService.evict.progress.movies(),
45-
TraktService.evict.progress.shows(),
46-
TraktService.evict.collection.movies(),
47-
TraktService.evict.collection.shows(),
44+
TraktService.evict.progress.movie(),
45+
TraktService.evict.progress.show(),
46+
TraktService.evict.collection.movie(),
47+
TraktService.evict.collection.show(),
4848
]),
4949
},
5050
{ label: i18n('evict_calendar'), click: TraktService.evict.calendar },
@@ -57,8 +57,8 @@ const evictScopes = [
5757
TraktService.evict.favorites(),
5858
TraktService.evict.list(),
5959
TraktService.evict.lists(),
60-
TraktService.evict.collection.movies(),
61-
TraktService.evict.collection.shows(),
60+
TraktService.evict.collection.movie(),
61+
TraktService.evict.collection.show(),
6262
]),
6363
},
6464
{ label: i18n('evict_search'), click: TraktService.evict.search },
@@ -95,6 +95,7 @@ const container = ref();
9595
>
9696
<NSelect
9797
v-model:value="tmdbCacheRetention"
98+
class="form-select"
9899
:to="container"
99100
:options="cacheOptions"
100101
/>

src/components/views/settings/SettingsLinks.vue

+10-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { useI18n } from '~/utils';
3030
3131
const i18n = useI18n('settings', 'links');
3232
33-
const { linkDictionary, aliasEnabled } = useLinksStoreRefs();
33+
const { linkDictionary, aliasEnabled, openLinkInBackground } = useLinksStoreRefs();
3434
const { addLink, removeLink } = useLinksStore();
3535
3636
const form = reactive<CustomLinkDictionary>(structuredClone(toRaw(linkDictionary.value)));
@@ -113,6 +113,15 @@ const containerRef = ref<HTMLDivElement>();
113113
<template #unchecked>{{ i18n('hide', 'common', 'button') }}</template>
114114
</NSwitch>
115115
</NFormItem>
116+
<NFormItem label-placement="left" :show-feedback="false">
117+
<template #label>
118+
<span class="form-header">{{ i18n('label_open_in_background') }}</span>
119+
</template>
120+
<NSwitch v-model:value="openLinkInBackground" class="form-header-switch">
121+
<template #checked>{{ i18n('on', 'common', 'button') }}</template>
122+
<template #unchecked>{{ i18n('off', 'common', 'button') }}</template>
123+
</NSwitch>
124+
</NFormItem>
116125

117126
<!-- Content -->
118127
<NForm ref="formRef" :model="form">

src/i18n/en/common/button.json

+8
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,13 @@
3434
"common__button__evict": {
3535
"message": "Evict cache data",
3636
"description": "Button to evict an item from cache."
37+
},
38+
"common__button__on": {
39+
"message": "On",
40+
"description": "Button to turn on an item."
41+
},
42+
"common__button__off": {
43+
"message": "Off",
44+
"description": "Button to turn off an item."
3745
}
3846
}

src/i18n/en/settings/settings-links.json

+4
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,9 @@
2626
"settings__links__confirm_remove": {
2727
"message": "Remove this custom link?",
2828
"description": "Confirmation message for removing a custom link"
29+
},
30+
"settings__links__label_open_in_background": {
31+
"message": "Open links in background (popup stay active)",
32+
"description": "Label for the open in new tab checkbox"
2933
}
3034
}

src/stores/settings/extension.store.ts

+2-15
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ import { computed, reactive, ref, toRaw } from 'vue';
33

44
import { TraktService } from '~/services/trakt.service';
55
import { storage } from '~/utils/browser/browser-storage.utils';
6-
import { createTab } from '~/utils/browser/browser.utils';
76
import { CacheRetention } from '~/utils/cache.utils';
87
import { debounce } from '~/utils/debounce.utils';
98

109
type ExtensionSettings = {
11-
openLinksInNewTab: boolean;
12-
cacheRetention: number;
10+
cacheRetention: CacheRetentionState;
1311
restoreRoute: boolean;
1412
progressTab: boolean;
1513
logLevel: string;
@@ -28,7 +26,6 @@ const DefaultCacheRetention: CacheRetentionState = {
2826
} as const;
2927

3028
export const useExtensionSettingsStore = defineStore('settings.extension', () => {
31-
const openLinksInNewTab = ref(true);
3229
const cacheRetention = reactive(DefaultCacheRetention);
3330
const restoreRoute = ref(true);
3431
const progressTab = ref(false);
@@ -37,7 +34,6 @@ export const useExtensionSettingsStore = defineStore('settings.extension', () =>
3734

3835
const clearState = () => {
3936
Object.assign(cacheRetention, DefaultCacheRetention);
40-
openLinksInNewTab.value = true;
4137
restoreRoute.value = true;
4238
progressTab.value = false;
4339
logLevel.value = 'info';
@@ -46,7 +42,6 @@ export const useExtensionSettingsStore = defineStore('settings.extension', () =>
4642
const saveState = debounce(
4743
() =>
4844
storage.sync.set('settings.extension', {
49-
openLinksInNewTab: openLinksInNewTab.value,
5045
cacheRetention: toRaw(cacheRetention),
5146
restoreRoute: restoreRoute.value,
5247
progressTab: progressTab.value,
@@ -60,13 +55,12 @@ export const useExtensionSettingsStore = defineStore('settings.extension', () =>
6055
if (retention.tmdb !== undefined) cacheRetention.tmdb = retention.tmdb;
6156
if (retention.tvdb !== undefined) cacheRetention.tvdb = retention.tvdb;
6257
TraktService.changeRetention(cacheRetention);
63-
if (persist) saveState().catch(err => console.error('Failed to save extension settings', { value, err }));
58+
if (persist) saveState().catch(err => console.error('Failed to save extension settings', { retention, err }));
6459
};
6560

6661
const restoreState = async () => {
6762
const restored = await storage.sync.get<ExtensionSettings>('settings.extension');
6863

69-
if (restored?.openLinksInNewTab !== undefined) openLinksInNewTab.value = restored.openLinksInNewTab;
7064
if (restored?.cacheRetention !== undefined) setRetention(restored.cacheRetention, false);
7165
if (restored?.restoreRoute !== undefined) restoreRoute.value = restored.restoreRoute;
7266
if (restored?.progressTab !== undefined) progressTab.value = restored.progressTab;
@@ -77,18 +71,11 @@ export const useExtensionSettingsStore = defineStore('settings.extension', () =>
7771
await restoreState();
7872
};
7973

80-
const openTab = (url?: string) => {
81-
if (!url) return;
82-
createTab({ url, active: openLinksInNewTab.value });
83-
};
84-
8574
return {
8675
initExtensionSettingsStore,
8776
saveState,
8877
clearState,
8978
restoreRoute,
90-
openLinksInNewTab,
91-
openTab,
9279
progressTab,
9380
logLevel,
9481
traktCacheRetention: computed({

src/stores/settings/links.store.ts

+30-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { computed, reactive, ref, type Ref } from 'vue';
44
import type { TagLink } from '~/models/tag.model';
55

66
import { storage } from '~/utils/browser/browser-storage.utils';
7+
import { createTab } from '~/utils/browser/browser.utils';
78
import { debounce } from '~/utils/debounce.utils';
89

910
export const CustomLinkScope = {
@@ -52,8 +53,14 @@ export type CustomLinkDictionary = Record<number, CustomLink>;
5253
type CustomLinkScopeDictionary = Partial<Record<CustomLinkScopes, CustomLinkDictionary>>;
5354
type AliasDictionary = Partial<Record<AliasScope, Record<string, string>>>;
5455

56+
type LinksStoreState = {
57+
enabled: boolean;
58+
backgroundLink: boolean;
59+
};
60+
5561
export const useLinksStore = defineStore('settings.links', () => {
5662
const enabled = ref(false);
63+
const backgroundLink = ref(false);
5764
const aliasDictionary = reactive<AliasDictionary>({});
5865

5966
const linkDictionary = reactive<CustomLinkDictionary>({});
@@ -65,7 +72,7 @@ export const useLinksStore = defineStore('settings.links', () => {
6572
Object.assign(linkScopeDictionary, {});
6673
};
6774

68-
const saveState = debounce(() => storage.sync.set('settings.links', { enabled: enabled.value }), 1000);
75+
const saveState = debounce(() => storage.sync.set('settings.links', { enabled: enabled.value, backgroundLink: backgroundLink.value }), 1000);
6976
const saveAlias = debounce(() => storage.sync.set('settings.links.aliases', aliasDictionary), 1000);
7077
const saveLinks = debounce(() => storage.sync.set('settings.links.links', linkDictionary), 1000);
7178

@@ -88,25 +95,26 @@ export const useLinksStore = defineStore('settings.links', () => {
8895

8996
// add new scopes
9097
if (link.scopes) Object.values(link.scopes).forEach(scope => addToScope(scope, link));
91-
saveLinks().catch(console.error);
98+
saveLinks().catch(err => console.error('Failed to save link', { link, err }));
9299
};
93100

94101
const removeLink = (id: CustomLink['id']) => {
95102
const link = linkDictionary[id];
96103
if (!link) return;
97104
if (linkDictionary[link.id]) delete linkDictionary[link.id];
98105
if (link.scopes) Object.values(link.scopes).forEach(scope => removeFromScope(scope, link.id));
99-
saveLinks().catch(console.error);
106+
saveLinks().catch(err => console.error('Failed to save link', { id, err }));
100107
};
101108

102109
const restoreState = async () => {
103-
const [restoredState, restoredAliases, restoredLinks] = await Promise.all([
104-
storage.sync.get<{ enabled: boolean }>('settings.links'),
110+
const [restoredState, restoredAliases, restoredLinks]: [LinksStoreState, AliasDictionary, CustomLinkDictionary] = await Promise.all([
111+
storage.sync.get<LinksStoreState>('settings.links'),
105112
storage.sync.get<AliasDictionary>('settings.links.aliases'),
106113
storage.sync.get<CustomLinkDictionary>('settings.links.links'),
107114
]);
108115

109-
if (restoredState.enabled !== undefined) enabled.value = restoredState.enabled;
116+
if (restoredState?.enabled !== undefined) enabled.value = restoredState.enabled;
117+
if (restoredState?.backgroundLink !== undefined) backgroundLink.value = restoredState.backgroundLink;
110118
if (restoredAliases) Object.assign(aliasDictionary, restoredAliases);
111119
if (restoredLinks) {
112120
Object.values(restoredLinks)
@@ -140,11 +148,25 @@ export const useLinksStore = defineStore('settings.links', () => {
140148
get: () => enabled.value,
141149
set: (value: boolean) => {
142150
enabled.value = value;
143-
saveState().catch(err => console.error('Failed to save state', { value, err }));
151+
saveState().catch(err => console.error('Failed to save link settings', { value, err }));
152+
},
153+
});
154+
155+
const openLinkInBackground = computed({
156+
get: () => backgroundLink.value,
157+
set: (value: boolean) => {
158+
backgroundLink.value = value;
159+
console.info('Open links in new tab', value);
160+
saveState().catch(err => console.error('Failed to save link settings.', { value, err }));
144161
},
145162
});
146163

147-
return { initLinksStore, clearState, linkDictionary, addLink, removeLink, getLinks, getAlias, aliasEnabled };
164+
const openTab = (url?: string) => {
165+
if (!url) return;
166+
createTab({ url, active: !openLinkInBackground.value });
167+
};
168+
169+
return { initLinksStore, clearState, linkDictionary, addLink, removeLink, getLinks, getAlias, aliasEnabled, openLinkInBackground, openTab };
148170
});
149171

150172
export const useLinksStoreRefs = () => storeToRefs(useLinksStore());

0 commit comments

Comments
 (0)