diff options
author | Zero~Informatique | 2019-12-28 04:52:30 +0100 |
---|---|---|
committer | Zero~Informatique | 2019-12-28 04:53:01 +0100 |
commit | a681accaa7617892bb7c53248aa9030a4eb47f50 (patch) | |
tree | 0d04aee1ef36ffaae1b0fac0a61ef7dad8d38e7c /viewer | |
parent | deaed8a6737edc6e28c08e9c6734dde6e37a4016 (diff) | |
download | ldgallery-a681accaa7617892bb7c53248aa9030a4eb47f50.tar.gz |
viewer: Tag propositions. Disabled directory indexation.
Note: The propositions are not based on the current search results, but on the searched tags, which doesn't seem to be the correct way. We'll probably have to move the search results to a store for global visibility.
Diffstat (limited to 'viewer')
-rw-r--r-- | viewer/src/@types/gallery/index.d.ts | 3 | ||||
-rw-r--r-- | viewer/src/@types/tag/index.d.ts | 2 | ||||
-rw-r--r-- | viewer/src/components/LdProposition.vue | 75 | ||||
-rw-r--r-- | viewer/src/locales/en.json | 3 | ||||
-rw-r--r-- | viewer/src/plugins/fontawesome.ts | 6 | ||||
-rw-r--r-- | viewer/src/store/galleryStore.ts | 6 | ||||
-rw-r--r-- | viewer/src/views/PanelLeft.vue | 2 |
7 files changed, 91 insertions, 6 deletions
diff --git a/viewer/src/@types/gallery/index.d.ts b/viewer/src/@types/gallery/index.d.ts index b47c812..310c865 100644 --- a/viewer/src/@types/gallery/index.d.ts +++ b/viewer/src/@types/gallery/index.d.ts | |||
@@ -9,7 +9,7 @@ declare namespace Gallery { | |||
9 | title: string, | 9 | title: string, |
10 | date: string, | 10 | date: string, |
11 | description: string, | 11 | description: string, |
12 | tags: string[], | 12 | tags: RawTag[], |
13 | path: string, | 13 | path: string, |
14 | thumbnail: { | 14 | thumbnail: { |
15 | path: string, | 15 | path: string, |
@@ -28,4 +28,5 @@ declare namespace Gallery { | |||
28 | type: "directory", | 28 | type: "directory", |
29 | items: Item[] | 29 | items: Item[] |
30 | } | 30 | } |
31 | type RawTag = string; | ||
31 | } \ No newline at end of file | 32 | } \ No newline at end of file |
diff --git a/viewer/src/@types/tag/index.d.ts b/viewer/src/@types/tag/index.d.ts index 6a0c605..181f47a 100644 --- a/viewer/src/@types/tag/index.d.ts +++ b/viewer/src/@types/tag/index.d.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | declare namespace Tag { | 1 | declare namespace Tag { |
2 | interface Node { | 2 | interface Node { |
3 | tag: string; | 3 | tag: Gallery.RawTag; |
4 | items: Gallery.Item[]; | 4 | items: Gallery.Item[]; |
5 | children: Index; | 5 | children: Index; |
6 | } | 6 | } |
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> | ||
diff --git a/viewer/src/locales/en.json b/viewer/src/locales/en.json index d885872..4c9f5d4 100644 --- a/viewer/src/locales/en.json +++ b/viewer/src/locales/en.json | |||
@@ -5,5 +5,6 @@ | |||
5 | "panelLeft.mode": "Mode", | 5 | "panelLeft.mode": "Mode", |
6 | "mode.navigation": "Navigation", | 6 | "mode.navigation": "Navigation", |
7 | "mode.search": "Search", | 7 | "mode.search": "Search", |
8 | "search.no-results": "No results" | 8 | "search.no-results": "No results", |
9 | "panelLeft.propositions": "Proposed tags" | ||
9 | } \ No newline at end of file | 10 | } \ No newline at end of file |
diff --git a/viewer/src/plugins/fontawesome.ts b/viewer/src/plugins/fontawesome.ts index ba31c9e..7308afe 100644 --- a/viewer/src/plugins/fontawesome.ts +++ b/viewer/src/plugins/fontawesome.ts | |||
@@ -6,7 +6,9 @@ import { | |||
6 | faExpandArrowsAlt, | 6 | faExpandArrowsAlt, |
7 | faFolder, | 7 | faFolder, |
8 | faSearch, | 8 | faSearch, |
9 | faTag | 9 | faTag, |
10 | faPlus, | ||
11 | faMinus, | ||
10 | } from "@fortawesome/free-solid-svg-icons"; | 12 | } from "@fortawesome/free-solid-svg-icons"; |
11 | 13 | ||
12 | library.add( | 14 | library.add( |
@@ -14,6 +16,8 @@ library.add( | |||
14 | faFolder, | 16 | faFolder, |
15 | faSearch, | 17 | faSearch, |
16 | faTag, | 18 | faTag, |
19 | faPlus, | ||
20 | faMinus, | ||
17 | ); | 21 | ); |
18 | 22 | ||
19 | Vue.component("fa-icon", FontAwesomeIcon); | 23 | Vue.component("fa-icon", FontAwesomeIcon); |
diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index 8a611ea..179fbe2 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts | |||
@@ -44,6 +44,10 @@ export default class GalleryStore extends VuexModule { | |||
44 | // Pushes all tags for a root item (and its children) to the index | 44 | // Pushes all tags for a root item (and its children) to the index |
45 | private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { | 45 | private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { |
46 | console.log("IndexingTagsFor: ", item.path); | 46 | console.log("IndexingTagsFor: ", item.path); |
47 | if (item.properties.type === "directory") { | ||
48 | item.properties.items.forEach(item => this.pushTagsForItem(index, item)); | ||
49 | return; // Directories are not indexed | ||
50 | } | ||
47 | for (const tag of item.tags) { | 51 | for (const tag of item.tags) { |
48 | const parts = tag.split('.'); | 52 | const parts = tag.split('.'); |
49 | let lastPart: string | null = null; | 53 | let lastPart: string | null = null; |
@@ -54,8 +58,6 @@ export default class GalleryStore extends VuexModule { | |||
54 | lastPart = part; | 58 | lastPart = part; |
55 | } | 59 | } |
56 | } | 60 | } |
57 | if (item.properties.type === "directory") | ||
58 | item.properties.items.forEach(item => this.pushTagsForItem(index, item)); | ||
59 | } | 61 | } |
60 | 62 | ||
61 | // Searches for an item by path from a root item (navigation) | 63 | // Searches for an item by path from a root item (navigation) |
diff --git a/viewer/src/views/PanelLeft.vue b/viewer/src/views/PanelLeft.vue index c187ce6..df1fe54 100644 --- a/viewer/src/views/PanelLeft.vue +++ b/viewer/src/views/PanelLeft.vue | |||
@@ -4,6 +4,8 @@ | |||
4 | <ld-mode-radio /> | 4 | <ld-mode-radio /> |
5 | <h1>{{$t('panelLeft.filters')}}</h1> | 5 | <h1>{{$t('panelLeft.filters')}}</h1> |
6 | <ld-tag-input /> | 6 | <ld-tag-input /> |
7 | <h1>{{$t('panelLeft.propositions')}}</h1> | ||
8 | <ld-proposition /> | ||
7 | </div> | 9 | </div> |
8 | </template> | 10 | </template> |
9 | 11 | ||