diff options
author | OzoneGrif | 2020-04-04 02:36:03 +0200 |
---|---|---|
committer | GitHub | 2020-04-04 02:36:03 +0200 |
commit | c26ab69997d1d552fda72b8fd88d5910fc91b779 (patch) | |
tree | aea8a7801c1445e71d966ca3a0532200abf2c724 /viewer/src/components | |
parent | 332b208d3fdc91d29181c8f42ef5ff9b1fd1f09a (diff) | |
parent | 84090e0f534cfa8bf601ae6df21e5df695fd149a (diff) | |
download | ldgallery-c26ab69997d1d552fda72b8fd88d5910fc91b779.tar.gz |
Merge pull request #172 from pacien/tag-categories
Feature: tag categories
Diffstat (limited to 'viewer/src/components')
-rw-r--r-- | viewer/src/components/LdProposition.vue | 52 | ||||
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 9 |
2 files changed, 43 insertions, 18 deletions
diff --git a/viewer/src/components/LdProposition.vue b/viewer/src/components/LdProposition.vue index 3357777..c69a7c3 100644 --- a/viewer/src/components/LdProposition.vue +++ b/viewer/src/components/LdProposition.vue | |||
@@ -19,8 +19,9 @@ | |||
19 | --> | 19 | --> |
20 | 20 | ||
21 | <template> | 21 | <template> |
22 | <div> | 22 | <div class="proposition"> |
23 | <div v-for="proposed in proposedTags" :key="proposed.rawTag" class="proposition"> | 23 | <h2 v-if="showCategory && proposedTags.length" class="subtitle category">{{title}}</h2> |
24 | <div v-for="proposed in proposedTags" :key="proposed.rawTag"> | ||
24 | <a | 25 | <a |
25 | class="operation-btns link" | 26 | class="operation-btns link" |
26 | :title="$t('tag-propositions.substraction')" | 27 | :title="$t('tag-propositions.substraction')" |
@@ -54,6 +55,8 @@ import { Operation } from "@/@types/Operation"; | |||
54 | 55 | ||
55 | @Component | 56 | @Component |
56 | export default class LdProposition extends Vue { | 57 | export default class LdProposition extends Vue { |
58 | @Prop() readonly category?: Tag.Node; | ||
59 | @Prop({ type: Boolean, required: true }) readonly showCategory!: boolean; | ||
57 | @Prop({ type: Array, required: true }) readonly currentTags!: string[]; | 60 | @Prop({ type: Array, required: true }) readonly currentTags!: string[]; |
58 | @Prop({ required: true }) readonly tagsIndex!: Tag.Index; | 61 | @Prop({ required: true }) readonly tagsIndex!: Tag.Index; |
59 | @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[]; | 62 | @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[]; |
@@ -69,13 +72,14 @@ export default class LdProposition extends Vue { | |||
69 | this.extractDistinctItems(this.model) | 72 | this.extractDistinctItems(this.model) |
70 | .flatMap(item => item.tags) | 73 | .flatMap(item => item.tags) |
71 | .map(this.rightmost) | 74 | .map(this.rightmost) |
72 | .filter(rawTag => !this.model.find(search => search.tag === rawTag)) | 75 | .filter(rawTag => this.tagsIndex[rawTag] && !this.model.find(search => search.tag === rawTag)) |
73 | .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1)); | 76 | .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1)); |
74 | } else { | 77 | } else { |
75 | // Tags count from the current directory | 78 | // Tags count from the current directory |
76 | this.currentTags | 79 | this.currentTags |
77 | .flatMap(tag => tag.split(":")) | 80 | .flatMap(tag => tag.split(":")) |
78 | .map(tag => this.tagsIndex[tag]) | 81 | .map(tag => this.tagsIndex[tag]) |
82 | .filter(Boolean) | ||
79 | .forEach(tagindex => (propositions[tagindex.tag] = tagindex.items.length)); | 83 | .forEach(tagindex => (propositions[tagindex.tag] = tagindex.items.length)); |
80 | } | 84 | } |
81 | 85 | ||
@@ -84,6 +88,10 @@ export default class LdProposition extends Vue { | |||
84 | .map(entry => ({ rawTag: entry[0], count: entry[1] })); | 88 | .map(entry => ({ rawTag: entry[0], count: entry[1] })); |
85 | } | 89 | } |
86 | 90 | ||
91 | get title() { | ||
92 | return this.category?.tag ?? this.$t("panelLeft.propositions.other"); | ||
93 | } | ||
94 | |||
87 | extractDistinctItems(currentTags: Tag.Search[]): Gallery.Item[] { | 95 | extractDistinctItems(currentTags: Tag.Search[]): Gallery.Item[] { |
88 | return [...new Set(currentTags.flatMap(tag => tag.items))]; | 96 | return [...new Set(currentTags.flatMap(tag => tag.items))]; |
89 | } | 97 | } |
@@ -95,8 +103,8 @@ export default class LdProposition extends Vue { | |||
95 | 103 | ||
96 | add(operation: Operation, rawTag: Gallery.RawTag) { | 104 | add(operation: Operation, rawTag: Gallery.RawTag) { |
97 | const node = this.tagsIndex[rawTag]; | 105 | const node = this.tagsIndex[rawTag]; |
98 | const search: Tag.Search = { ...node, operation, display: `${operation}${node.tag}` }; | 106 | const display = this.category ? `${operation}${this.category.tag}:${node.tag}` : `${operation}${node.tag}`; |
99 | this.model.push(search); | 107 | this.model.push({ ...node, parent: this.category, operation, display }); |
100 | } | 108 | } |
101 | } | 109 | } |
102 | </script> | 110 | </script> |
@@ -105,19 +113,29 @@ export default class LdProposition extends Vue { | |||
105 | @import "@/assets/scss/theme.scss"; | 113 | @import "@/assets/scss/theme.scss"; |
106 | 114 | ||
107 | .proposition { | 115 | .proposition { |
108 | display: flex; | 116 | .subtitle { |
109 | align-items: center; | 117 | background-color: $proposed-category-bgcolor; |
110 | padding-right: 7px; | 118 | width: 100%; |
111 | .operation-tag { | 119 | padding: 0 0 6px 0; |
112 | text-overflow: ellipsis; | 120 | margin: 0; |
113 | white-space: nowrap; | 121 | text-align: center; |
114 | overflow: hidden; | 122 | font-variant: small-caps; |
115 | flex-grow: 1; | ||
116 | cursor: pointer; | ||
117 | } | 123 | } |
118 | .operation-btns { | 124 | > div { |
119 | padding: 2px 7px; | 125 | display: flex; |
120 | cursor: pointer; | 126 | align-items: center; |
127 | padding-right: 7px; | ||
128 | .operation-tag { | ||
129 | text-overflow: ellipsis; | ||
130 | white-space: nowrap; | ||
131 | overflow: hidden; | ||
132 | flex-grow: 1; | ||
133 | cursor: pointer; | ||
134 | } | ||
135 | .operation-btns { | ||
136 | padding: 2px 7px; | ||
137 | cursor: pointer; | ||
138 | } | ||
121 | } | 139 | } |
122 | } | 140 | } |
123 | </style> | 141 | </style> |
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue index b1b9e3e..6b6e749 100644 --- a/viewer/src/components/LdTagInput.vue +++ b/viewer/src/components/LdTagInput.vue | |||
@@ -57,10 +57,17 @@ export default class LdTagInput extends Vue { | |||
57 | return `${option.display} (${option.items.length})`; | 57 | return `${option.display} (${option.items.length})`; |
58 | } | 58 | } |
59 | 59 | ||
60 | filterAlreadyPresent(newSearch: Tag.Search) { | ||
61 | return !this.model.find( | ||
62 | currentSearch => | ||
63 | currentSearch.tag === newSearch.tag && (!currentSearch.parent || currentSearch.parent === newSearch.parent) | ||
64 | ); | ||
65 | } | ||
66 | |||
60 | searchTags(filter: string) { | 67 | searchTags(filter: string) { |
61 | this.currentFilter = filter; | 68 | this.currentFilter = filter; |
62 | this.filteredTags = IndexFactory.searchTags(this.tagsIndex, filter, false) | 69 | this.filteredTags = IndexFactory.searchTags(this.tagsIndex, filter, false) |
63 | .filter(newSearch => !this.model.find(currentSearch => currentSearch.tag === newSearch.tag)) | 70 | .filter(this.filterAlreadyPresent) |
64 | .sort((a, b) => b.items.length - a.items.length); | 71 | .sort((a, b) => b.items.length - a.items.length); |
65 | } | 72 | } |
66 | 73 | ||