feat(front): [WIP] couple tagsList to query
This commit is contained in:
		
							parent
							
								
									c2c0a2aa79
								
							
						
					
					
						commit
						e9e42c53b9
					
				|  | @ -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')" | ||||
|  |  | |||
|  | @ -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 ({ | ||||
|   fetch(); | ||||
| 
 | ||||
|   /** | ||||
|      * @param currents Initial selected tags | ||||
|    * @returns v-model for `Pills` component | ||||
|    */ | ||||
|     model: (currents: string[] = []) => { | ||||
|       fetch(); | ||||
|   return computed({ | ||||
| 
 | ||||
|         // Get currents initially from parameter. Get others from backend.
 | ||||
|         get: (): Model => ({ | ||||
|           currents: currents.map(tag => ({ | ||||
|     get () { | ||||
|       // console.log("GET TAGS")
 | ||||
|       return ({ | ||||
|       // Get `currents` from parameter
 | ||||
|       currents: currents.value.map(tag => ({ | ||||
|         label: tag, | ||||
|             type: tags.value.some(({ name }) => tag === name) ? 'preset' : 'custom' | ||||
|           })), | ||||
|           others: tags.value | ||||
|             .filter(({ name }) => !currents.includes(name)) | ||||
|         type: (store.state.ui.tags || []).some(({ name }) => tag === name) ? 'preset' : 'custom' | ||||
|       } as const)), | ||||
| 
 | ||||
|       // 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
 | ||||
|         set: function (_) { | ||||
|       window.setTimeout(fetch, refetchInterval) | ||||
|           // TODO: Broadcast new custom tags so that other pills components can use them
 | ||||
|     } | ||||
|     }) | ||||
|     } | ||||
|   }) | ||||
| }) | ||||
| } | ||||
| 
 | ||||
| // alternative ways to generate tags
 | ||||
| // ...
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 upsiflu
						upsiflu