diff options
Diffstat (limited to 'viewer/src/components')
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 48 | ||||
-rw-r--r-- | viewer/src/components/index.ts | 2 |
2 files changed, 41 insertions, 9 deletions
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue index 4121cd7..daca62d 100644 --- a/viewer/src/components/LdTagInput.vue +++ b/viewer/src/components/LdTagInput.vue | |||
@@ -6,11 +6,14 @@ | |||
6 | ellipsis | 6 | ellipsis |
7 | attached | 7 | attached |
8 | :data="filteredTags" | 8 | :data="filteredTags" |
9 | field="tag" | 9 | field="display" |
10 | type="is-black" | 10 | type="is-black" |
11 | icon="tag" | 11 | icon="tag" |
12 | size="is-medium" | ||
12 | class="panelTagInput" | 13 | class="panelTagInput" |
13 | @typing="searchTags" | 14 | @typing="searchTags" |
15 | @add="onAdd" | ||
16 | @remove="onRemove" | ||
14 | > | 17 | > |
15 | <template slot-scope="props">{{displayOption(props.option)}}</template> | 18 | <template slot-scope="props">{{displayOption(props.option)}}</template> |
16 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> | 19 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> |
@@ -19,41 +22,70 @@ | |||
19 | 22 | ||
20 | <script lang="ts"> | 23 | <script lang="ts"> |
21 | import { Component, Vue } from "vue-property-decorator"; | 24 | import { Component, Vue } from "vue-property-decorator"; |
25 | import { Operation } from "@/@types/tag/Operation"; | ||
22 | 26 | ||
23 | @Component | 27 | @Component |
24 | export default class LdTagInput extends Vue { | 28 | export default class LdTagInput extends Vue { |
25 | filteredTags: Tag.Search[] = []; | 29 | filteredTags: Tag.Search[] = []; |
26 | 30 | ||
31 | onAdd(e: any) { | ||
32 | this.$uiStore.mode = "search"; | ||
33 | } | ||
34 | |||
35 | onRemove() { | ||
36 | if (this.$uiStore.currentTags.length === 0) this.$uiStore.mode = "navigation"; | ||
37 | } | ||
38 | |||
27 | displayOption(option: Tag.Search): string { | 39 | displayOption(option: Tag.Search): string { |
28 | return `${option.tag} (${option.items.length})`; | 40 | return `${option.display} (${option.items.length})`; |
41 | } | ||
42 | |||
43 | extractOperation(filter: string) { | ||
44 | const first = filter.slice(0, 1); | ||
45 | switch (first) { | ||
46 | case Operation.ADDITION: | ||
47 | case Operation.SUBSTRACTION: | ||
48 | return first; | ||
49 | default: | ||
50 | return Operation.INTERSECTION; | ||
51 | } | ||
29 | } | 52 | } |
30 | 53 | ||
31 | searchTags(filter: string) { | 54 | searchTags(filter: string) { |
32 | const tags = this.$galleryStore.tags; | 55 | const tags = this.$galleryStore.tags; |
33 | let search: Tag.Search[] = []; | 56 | let search: Tag.Search[] = []; |
34 | if (tags && filter) { | 57 | if (tags && filter) { |
58 | const operation = this.extractOperation(filter); | ||
59 | if (operation !== Operation.INTERSECTION) filter = filter.slice(1); | ||
35 | if (filter.includes(":")) { | 60 | if (filter.includes(":")) { |
36 | const filterParts = filter.split(":"); | 61 | const filterParts = filter.split(":"); |
37 | search = this.searchTagsFromFilterWithCategory(tags, filterParts[0], filterParts[1]); | 62 | search = this.searchTagsFromFilterWithCategory(tags, operation, filterParts[0], filterParts[1]); |
38 | } else { | 63 | } else { |
39 | search = this.searchTagsFromFilter(tags, filter); | 64 | search = this.searchTagsFromFilter(tags, operation, filter); |
40 | } | 65 | } |
41 | } | 66 | } |
42 | this.filteredTags = this.cleanupAndSort(search); | 67 | this.filteredTags = this.cleanupAndSort(search); |
43 | } | 68 | } |
44 | 69 | ||
45 | searchTagsFromFilterWithCategory(tags: Tag.Index, category: string, disambiguation: string): Tag.NodeWithParent[] { | 70 | searchTagsFromFilterWithCategory( |
71 | tags: Tag.Index, | ||
72 | operation: Operation, | ||
73 | category: string, | ||
74 | disambiguation: string | ||
75 | ): Tag.Search[] { | ||
46 | return Object.values(tags) | 76 | return Object.values(tags) |
47 | .filter(node => node.tag.includes(category)) | 77 | .filter(node => node.tag.includes(category)) |
48 | .flatMap(node => | 78 | .flatMap(node => |
49 | Object.values(node.children) | 79 | Object.values(node.children) |
50 | .filter(child => child.tag.includes(disambiguation)) | 80 | .filter(child => child.tag.includes(disambiguation)) |
51 | .map(child => ({ ...child, parent: node, tag: `${node.tag}:${child.tag}` })) | 81 | .map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` })) |
52 | ); | 82 | ); |
53 | } | 83 | } |
54 | 84 | ||
55 | searchTagsFromFilter(tags: Tag.Index, filter: string): Tag.Node[] { | 85 | searchTagsFromFilter(tags: Tag.Index, operation: Operation, filter: string): Tag.Search[] { |
56 | return Object.values(tags).filter(node => node.tag.includes(filter)); | 86 | return Object.values(tags) |
87 | .filter(node => node.tag.includes(filter)) | ||
88 | .map(node => ({ ...node, operation, display: `${operation}${node.tag}` })); | ||
57 | } | 89 | } |
58 | 90 | ||
59 | cleanupAndSort(search: Tag.Search[]): Tag.Search[] { | 91 | cleanupAndSort(search: Tag.Search[]): Tag.Search[] { |
diff --git a/viewer/src/components/index.ts b/viewer/src/components/index.ts index 1406b34..4586f62 100644 --- a/viewer/src/components/index.ts +++ b/viewer/src/components/index.ts | |||
@@ -17,6 +17,6 @@ requireComponent.keys().forEach(fileName => { | |||
17 | // Look for the component options on `.default`, which will | 17 | // Look for the component options on `.default`, which will |
18 | // exist if the component was exported with `export default`, | 18 | // exist if the component was exported with `export default`, |
19 | // otherwise fall back to module's root. | 19 | // otherwise fall back to module's root. |
20 | componentConfig.default || componentConfig | 20 | componentConfig.default ?? componentConfig |
21 | ) | 21 | ) |
22 | }) \ No newline at end of file | 22 | }) \ No newline at end of file |