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 page = usePage() | ||||||
| 
 | 
 | ||||||
| const tags = useRouteQuery<string[]>('tag', []) | const tags = useRouteQuery<string[]>('tag', [], { transform: (param: string | string[] | null) => (param === null ? [] : Array.isArray(param) ? param : [param]).filter(p => p.trim() !== '') }) | ||||||
| const tagList = useTags().model(tags.value) | 
 | ||||||
|  | const tagList = useTags(tags) | ||||||
| 
 | 
 | ||||||
| const q = useRouteQuery('query', '') | const q = useRouteQuery('query', '') | ||||||
| const query = ref(q.value ?? '') | const query = ref(q.value ?? '') | ||||||
|  | @ -152,6 +153,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value] | ||||||
|         autofocus |         autofocus | ||||||
|         :placeholder="labels.searchPlaceholder" |         :placeholder="labels.searchPlaceholder" | ||||||
|       /> |       /> | ||||||
|  |       {{ tagList }} | ||||||
|       <Pills |       <Pills | ||||||
|         v-model="tagList" |         v-model="tagList" | ||||||
|         :label="t('components.library.Albums.label.tags')" |         :label="t('components.library.Albums.label.tags')" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import type { paths } from '~/generated/types.ts' | import type { paths } from '~/generated/types.ts' | ||||||
| 
 | 
 | ||||||
| import { computed, ref } from 'vue' | import { computed, ref, type Ref } from 'vue' | ||||||
| import { useStore } from '~/store' | import { useStore } from '~/store' | ||||||
| import axios from 'axios' | import axios from 'axios' | ||||||
| 
 | 
 | ||||||
|  | @ -8,19 +8,15 @@ type Item = { type: 'custom' | 'preset', label: string } | ||||||
| type Model = { currents: Item[], others?: Item[] } | 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() |   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
 |   // Ignore quick successive fetch triggers
 | ||||||
|   const ignorePeriod = 500 |   const ignorePeriod = 500 | ||||||
| 
 | 
 | ||||||
|  | @ -30,11 +26,13 @@ export const useTags = <T> () => { | ||||||
|   // Wait after changing a tag before re-fetching
 |   // Wait after changing a tag before re-fetching
 | ||||||
|   const refetchInterval = 6000 |   const refetchInterval = 6000 | ||||||
| 
 | 
 | ||||||
|  |   // Number of tags to load on one page
 | ||||||
|   const maxTags = 100000 |   const maxTags = 100000 | ||||||
| 
 | 
 | ||||||
|   const lastFetched = ref<number>(0) |   const lastFetched = ref<number>(0) | ||||||
| 
 | 
 | ||||||
|   const fetch = async () => { |   const fetch = async () => { | ||||||
|  |     // console.log('FETCH TAGS')
 | ||||||
|     // Ignore subsequent fetch commands triggered in quick succession
 |     // Ignore subsequent fetch commands triggered in quick succession
 | ||||||
|     if (lastFetched.value + ignorePeriod > Date.now()) |     if (lastFetched.value + ignorePeriod > Date.now()) | ||||||
|       return |       return | ||||||
|  | @ -50,40 +48,48 @@ export const useTags = <T> () => { | ||||||
|       { params: { page: 1, page_size: maxTags } } |       { 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 => ({ |    * @returns v-model for `Pills` component | ||||||
|           currents: currents.map(tag => ({ |    */ | ||||||
|             label: tag, |   return computed({ | ||||||
|             type: tags.value.some(({ name }) => tag === name) ? 'preset' : 'custom' |     get () { | ||||||
|           })), |       // console.log("GET TAGS")
 | ||||||
|           others: tags.value |       return ({ | ||||||
|             .filter(({ name }) => !currents.includes(name)) |       // Get `currents` from parameter
 | ||||||
|             .map(({ name }) => ({ |       currents: currents.value.map(tag => ({ | ||||||
|               label: name, |         label: tag, | ||||||
|               type: 'preset' |         type: (store.state.ui.tags || []).some(({ name }) => tag === name) ? 'preset' : 'custom' | ||||||
|             })) |       } as const)), | ||||||
|         }), |  | ||||||
| 
 | 
 | ||||||
|         // Re-fetch after each new setting
 |       // Get `others` from cache
 | ||||||
|         set: function (_) { |       others: (store.state.ui.tags || []) | ||||||
|           window.setTimeout(fetch, refetchInterval) |         .filter(({ name }) => !currents.value.includes(name)) | ||||||
|           // TODO: Broadcast new custom tags so that other pills components can use them
 |         .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
 | // alternative ways to generate tags
 | ||||||
|  | // ...
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 upsiflu
						upsiflu