diff --git a/frontend/src/composables/useTabQuery.js b/frontend/src/composables/useTabQuery.js new file mode 100644 index 0000000..57b39ae --- /dev/null +++ b/frontend/src/composables/useTabQuery.js @@ -0,0 +1,30 @@ +import { ref, watch } from 'vue' +import { useRoute, useRouter } from 'vue-router' + +// Two-way bind a tab ref with the ?tab= query param: the initial value comes +// from the URL (when it names a valid tab) else `defaultTab` — a string, or a +// function for a state-dependent default. Tab changes push to the URL via +// router.replace (no history spam); URL changes (back/forward) flow back into +// the ref. Returns { tab, resolve } where resolve() re-applies the URL-or- +// default rule (callers re-run it when their default inputs change). +export function useTabQuery(validTabs, defaultTab) { + const route = useRoute() + const router = useRouter() + + const resolveDefault = () => + (typeof defaultTab === 'function' ? defaultTab() : defaultTab) + const resolve = () => + (validTabs.includes(route.query.tab) ? route.query.tab : resolveDefault()) + + const tab = ref(resolve()) + + watch(tab, (t) => { + if (route.query.tab === t) return + router.replace({ query: { ...route.query, tab: t } }) + }) + watch(() => route.query.tab, (q) => { + if (q && validTabs.includes(q) && tab.value !== q) tab.value = q + }) + + return { tab, resolve } +} diff --git a/frontend/src/views/ArtistView.vue b/frontend/src/views/ArtistView.vue index 876b9d8..0dcf90f 100644 --- a/frontend/src/views/ArtistView.vue +++ b/frontend/src/views/ArtistView.vue @@ -39,30 +39,26 @@