diff options
Diffstat (limited to 'viewer/src/components')
-rw-r--r-- | viewer/src/components/LdProposition.vue | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/viewer/src/components/LdProposition.vue b/viewer/src/components/LdProposition.vue new file mode 100644 index 0000000..b23c14a --- /dev/null +++ b/viewer/src/components/LdProposition.vue | |||
@@ -0,0 +1,75 @@ | |||
1 | <template> | ||
2 | <div> | ||
3 | <div v-for="proposed in proposedTags" :key="proposed.rawTag" class="proposition"> | ||
4 | <fa-icon icon="minus" @click="add(Operation.SUBSTRACTION, proposed.rawTag)" /> | ||
5 | <span | ||
6 | @click="add(Operation.INTERSECTION, proposed.rawTag)" | ||
7 | >{{proposed.rawTag}} x{{proposed.count}}</span> | ||
8 | <fa-icon icon="plus" @click="add(Operation.ADDITION, proposed.rawTag)" /> | ||
9 | </div> | ||
10 | </div> | ||
11 | </template> | ||
12 | |||
13 | <script lang="ts"> | ||
14 | import { Component, Vue } from "vue-property-decorator"; | ||
15 | import { Operation } from "@/@types/tag/Operation"; | ||
16 | import Gallery from '../views/Gallery.vue'; | ||
17 | |||
18 | @Component | ||
19 | export default class LdTagInput extends Vue { | ||
20 | get Operation() { | ||
21 | return Operation; | ||
22 | } | ||
23 | |||
24 | get proposedTags() { | ||
25 | const currentTags = this.$uiStore.currentTags; | ||
26 | let propositions: { [index: string]: number } = {}; | ||
27 | if (currentTags.length > 0) { | ||
28 | // Tags count from current search | ||
29 | this.extractDistinctItems(currentTags) | ||
30 | .flatMap(item => item.tags) | ||
31 | .map(this.rightmost) | ||
32 | .filter(rawTag => !currentTags.find(currentTag => currentTag.tag === rawTag)) | ||
33 | .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1)); | ||
34 | } else { | ||
35 | // Tags count from the whole gallery | ||
36 | Object.entries(this.$galleryStore.tags) | ||
37 | .forEach(entry => (propositions[entry[0]] = entry[1].items.length)); | ||
38 | } | ||
39 | |||
40 | return Object.entries(propositions) | ||
41 | .sort((a,b) => b[1] - a[1]) | ||
42 | .map(entry => ({rawTag: entry[0], count: entry[1]})); | ||
43 | } | ||
44 | |||
45 | extractDistinctItems(currentTags: Tag.Search[]): Gallery.Item[] { | ||
46 | return [...new Set(currentTags.flatMap(tag => tag.items))]; | ||
47 | } | ||
48 | |||
49 | rightmost(tag: Gallery.RawTag): Gallery.RawTag { | ||
50 | const dot = tag.lastIndexOf("."); | ||
51 | return dot <= 0 ? tag : tag.substr(dot + 1); | ||
52 | } | ||
53 | |||
54 | add(operation: Operation, rawTag: Gallery.RawTag) { | ||
55 | const node = this.$galleryStore.tags[rawTag]; | ||
56 | const search: Tag.Search = { ...node, operation, display: `${operation}${node.tag}` }; | ||
57 | this.$uiStore.currentTags.push(search); | ||
58 | this.$uiStore.mode = "search"; | ||
59 | } | ||
60 | } | ||
61 | </script> | ||
62 | |||
63 | <style lang="scss"> | ||
64 | .proposition { | ||
65 | display: flex; | ||
66 | justify-content: space-between; | ||
67 | align-items: center; | ||
68 | margin: 10px; | ||
69 | color: lightcyan; | ||
70 | cursor: pointer; | ||
71 | } | ||
72 | .proposition span { | ||
73 | padding: 0 10px; | ||
74 | } | ||
75 | </style> | ||