diff options
author | Zero~Informatique | 2019-12-22 11:26:53 +0100 |
---|---|---|
committer | Zero~Informatique | 2019-12-22 11:26:53 +0100 |
commit | 06c4d9299bb684805051355555fa89f0d440d194 (patch) | |
tree | 42bb1ac1fdcd44ba1edeef65fa94239fcf53fc77 /viewer/src | |
parent | dc251fffc2998f1cf4f8e9631928c4b92ac0d90e (diff) | |
download | ldgallery-06c4d9299bb684805051355555fa89f0d440d194.tar.gz |
viewer: Implemented tag category and disambiguation filtering
Diffstat (limited to 'viewer/src')
-rw-r--r-- | viewer/src/@types/tag/index.d.ts | 4 | ||||
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 52 | ||||
-rw-r--r-- | viewer/src/plugins/fontawesome.ts | 4 |
3 files changed, 48 insertions, 12 deletions
diff --git a/viewer/src/@types/tag/index.d.ts b/viewer/src/@types/tag/index.d.ts index 6a027d4..30bbebb 100644 --- a/viewer/src/@types/tag/index.d.ts +++ b/viewer/src/@types/tag/index.d.ts | |||
@@ -4,5 +4,9 @@ declare namespace Tag { | |||
4 | items: Gallery.Item[]; | 4 | items: Gallery.Item[]; |
5 | children: Index; | 5 | children: Index; |
6 | } | 6 | } |
7 | interface NodeWithParent extends Node { | ||
8 | parent: Node; | ||
9 | } | ||
10 | type Search = Node | NodeWithParent; | ||
7 | type Index = { [index: string]: Node }; | 11 | type Index = { [index: string]: Node }; |
8 | } \ No newline at end of file | 12 | } \ No newline at end of file |
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue index 4edc1ce..4121cd7 100644 --- a/viewer/src/components/LdTagInput.vue +++ b/viewer/src/components/LdTagInput.vue | |||
@@ -3,14 +3,16 @@ | |||
3 | v-model="$uiStore.currentTags" | 3 | v-model="$uiStore.currentTags" |
4 | :placeholder="$t('tagInput.placeholder')" | 4 | :placeholder="$t('tagInput.placeholder')" |
5 | autocomplete | 5 | autocomplete |
6 | ellipsis | ||
7 | attached | ||
6 | :data="filteredTags" | 8 | :data="filteredTags" |
7 | field="tag" | 9 | field="tag" |
8 | type="is-black" | 10 | type="is-black" |
9 | size="is-large" | 11 | icon="tag" |
10 | class="panelTagInput" | 12 | class="panelTagInput" |
11 | @typing="getFilteredTags" | 13 | @typing="searchTags" |
12 | > | 14 | > |
13 | <template slot-scope="props">{{props.option.tag}} ({{props.option.items.length}})</template> | 15 | <template slot-scope="props">{{displayOption(props.option)}}</template> |
14 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> | 16 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> |
15 | </b-taginput> | 17 | </b-taginput> |
16 | </template> | 18 | </template> |
@@ -20,15 +22,45 @@ import { Component, Vue } from "vue-property-decorator"; | |||
20 | 22 | ||
21 | @Component | 23 | @Component |
22 | export default class LdTagInput extends Vue { | 24 | export default class LdTagInput extends Vue { |
23 | filteredTags: Tag.Node[] = []; | 25 | filteredTags: Tag.Search[] = []; |
24 | 26 | ||
25 | getFilteredTags(filter: string) { | 27 | displayOption(option: Tag.Search): string { |
28 | return `${option.tag} (${option.items.length})`; | ||
29 | } | ||
30 | |||
31 | searchTags(filter: string) { | ||
26 | const tags = this.$galleryStore.tags; | 32 | const tags = this.$galleryStore.tags; |
27 | if (tags && filter) | 33 | let search: Tag.Search[] = []; |
28 | this.filteredTags = Object.values(tags) | 34 | if (tags && filter) { |
29 | .filter(node => node.tag.includes(filter)) | 35 | if (filter.includes(":")) { |
30 | .sort((a, b) => b.items.length - a.items.length); | 36 | const filterParts = filter.split(":"); |
31 | else this.filteredTags = []; | 37 | search = this.searchTagsFromFilterWithCategory(tags, filterParts[0], filterParts[1]); |
38 | } else { | ||
39 | search = this.searchTagsFromFilter(tags, filter); | ||
40 | } | ||
41 | } | ||
42 | this.filteredTags = this.cleanupAndSort(search); | ||
43 | } | ||
44 | |||
45 | searchTagsFromFilterWithCategory(tags: Tag.Index, category: string, disambiguation: string): Tag.NodeWithParent[] { | ||
46 | return Object.values(tags) | ||
47 | .filter(node => node.tag.includes(category)) | ||
48 | .flatMap(node => | ||
49 | Object.values(node.children) | ||
50 | .filter(child => child.tag.includes(disambiguation)) | ||
51 | .map(child => ({ ...child, parent: node, tag: `${node.tag}:${child.tag}` })) | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | searchTagsFromFilter(tags: Tag.Index, filter: string): Tag.Node[] { | ||
56 | return Object.values(tags).filter(node => node.tag.includes(filter)); | ||
57 | } | ||
58 | |||
59 | cleanupAndSort(search: Tag.Search[]): Tag.Search[] { | ||
60 | const currentTags = this.$uiStore.currentTags; | ||
61 | return search | ||
62 | .filter(node => !currentTags.find(currentTag => currentTag.tag === node.tag)) | ||
63 | .sort((a, b) => b.items.length - a.items.length); | ||
32 | } | 64 | } |
33 | } | 65 | } |
34 | </script> | 66 | </script> |
diff --git a/viewer/src/plugins/fontawesome.ts b/viewer/src/plugins/fontawesome.ts index 3af77b6..e129c57 100644 --- a/viewer/src/plugins/fontawesome.ts +++ b/viewer/src/plugins/fontawesome.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import Vue from "vue"; | 1 | import Vue from "vue"; |
2 | 2 | ||
3 | import { library } from "@fortawesome/fontawesome-svg-core"; | 3 | import { library } from "@fortawesome/fontawesome-svg-core"; |
4 | import { faExpandArrowsAlt, faFolder, faSearch } from "@fortawesome/free-solid-svg-icons"; | 4 | import { faExpandArrowsAlt, faFolder, faSearch, faTag } from "@fortawesome/free-solid-svg-icons"; |
5 | import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; | 5 | import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; |
6 | 6 | ||
7 | library.add(faExpandArrowsAlt, faFolder, faSearch); | 7 | library.add(faExpandArrowsAlt, faFolder, faSearch, faTag); |
8 | 8 | ||
9 | Vue.component("fa-icon", FontAwesomeIcon); | 9 | Vue.component("fa-icon", FontAwesomeIcon); |