feat(front): [WIP] couple tagsList to query

This commit is contained in:
upsiflu 2025-04-01 09:34:06 +02:00
parent c2c0a2aa79
commit e9e42c53b9
2 changed files with 50 additions and 42 deletions

View File

@ -48,8 +48,9 @@ const props = withDefaults(defineProps<Props>(), {
const page = usePage()
const tags = useRouteQuery<string[]>('tag', [])
const tagList = useTags().model(tags.value)
const tags = useRouteQuery<string[]>('tag', [], { transform: (param: string | string[] | null) => (param === null ? [] : Array.isArray(param) ? param : [param]).filter(p => p.trim() !== '') })
const tagList = useTags(tags)
const q = useRouteQuery('query', '')
const query = ref(q.value ?? '')
@ -152,6 +153,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
autofocus
:placeholder="labels.searchPlaceholder"
/>
{{ tagList }}
<Pills
v-model="tagList"
:label="t('components.library.Albums.label.tags')"

View File

@ -1,6 +1,6 @@
import type { paths } from '~/generated/types.ts'
import { computed, ref } from 'vue'
import { computed, ref, type Ref } from 'vue'
import { useStore } from '~/store'
import axios from 'axios'
@ -8,19 +8,15 @@ type Item = { type: 'custom' | 'preset', label: string }
type Model = { currents: Item[], others?: Item[] }
/**
* Load and cache all tags
* Load and cache all tags.
* - Two-way binding with store (any change to the store will be reflected in `others`)
* - Two-way binding with ref
* @param currents Selected tags
* @returns an object with `currents` and `others`, ready to be used inside
*/
export const useTags = <T> () => {
export const useTags = (currents: Ref<string[], string[]>) => {
const store = useStore()
// Two-way bind with store
const tags = computed({
get: () => store.state.ui.tags || [],
set: function(value) {
store.commit('ui/tags', value)
}
})
// Ignore quick successive fetch triggers
const ignorePeriod = 500
@ -30,11 +26,13 @@ export const useTags = <T> () => {
// Wait after changing a tag before re-fetching
const refetchInterval = 6000
// Number of tags to load on one page
const maxTags = 100000
const lastFetched = ref<number>(0)
const fetch = async () => {
// console.log('FETCH TAGS')
// Ignore subsequent fetch commands triggered in quick succession
if (lastFetched.value + ignorePeriod > Date.now())
return
@ -50,40 +48,48 @@ export const useTags = <T> () => {
{ params: { page: 1, page_size: maxTags } }
)
tags.value = response.data.results
// console.log('TAGS RESPONSE.data.results', response.data.results)
store.commit('ui/tags', response.data.results)
}
return ({
/**
* @param currents Initial selected tags
* @returns v-model for `Pills` component
*/
model: (currents: string[] = []) => {
fetch();
return computed({
fetch();
// Get currents initially from parameter. Get others from backend.
get: (): Model => ({
currents: currents.map(tag => ({
label: tag,
type: tags.value.some(({ name }) => tag === name) ? 'preset' : 'custom'
})),
others: tags.value
.filter(({ name }) => !currents.includes(name))
.map(({ name }) => ({
label: name,
type: 'preset'
}))
}),
/**
* @returns v-model for `Pills` component
*/
return computed({
get () {
// console.log("GET TAGS")
return ({
// Get `currents` from parameter
currents: currents.value.map(tag => ({
label: tag,
type: (store.state.ui.tags || []).some(({ name }) => tag === name) ? 'preset' : 'custom'
} as const)),
// Re-fetch after each new setting
set: function (_) {
window.setTimeout(fetch, refetchInterval)
// TODO: Broadcast new custom tags so that other pills components can use them
}
})
// Get `others` from cache
others: (store.state.ui.tags || [])
.filter(({ name }) => !currents.value.includes(name))
.map(({ name }) => ({
label: name,
type: 'preset'
} as const))
})},
set (model) {
// console.log('SET TAGS', response.data.results)
// Set parameter `currents` from `model.currents`
currents.value = model.currents.map(({ label }) => label)
// Set runtime-only options from `model.others` and `model.current`
// TODO: Broadcast new custom tags so that other pills components can use them
// Re-fetch after each new setting
window.setTimeout(fetch, refetchInterval)
}
})
})
}
// alternative ways to generate tags
// ...