aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/components/LdProposition.vue
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/components/LdProposition.vue')
-rw-r--r--viewer/src/components/LdProposition.vue186
1 files changed, 0 insertions, 186 deletions
diff --git a/viewer/src/components/LdProposition.vue b/viewer/src/components/LdProposition.vue
deleted file mode 100644
index 07b27f5..0000000
--- a/viewer/src/components/LdProposition.vue
+++ /dev/null
@@ -1,186 +0,0 @@
1<!-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Guillaume FOUET
5-- 2020 Pacien TRAN-GIRARD
6--
7-- This program is free software: you can redistribute it and/or modify
8-- it under the terms of the GNU Affero General Public License as
9-- published by the Free Software Foundation, either version 3 of the
10-- License, or (at your option) any later version.
11--
12-- This program is distributed in the hope that it will be useful,
13-- but WITHOUT ANY WARRANTY; without even the implied warranty of
14-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15-- GNU Affero General Public License for more details.
16--
17-- You should have received a copy of the GNU Affero General Public License
18-- along with this program. If not, see <https://www.gnu.org/licenses/>.
19-->
20
21<template>
22 <div :class="$style.proposition">
23 <h2 v-if="showCategory && Object.keys(propositions).length" :class="[$style.subtitle, $style.category]">
24 {{ title }}
25 </h2>
26 <div v-for="proposed in proposedTags" :key="proposed.rawTag">
27 <a
28 class="link"
29 :class="$style.operationBtns"
30 :title="$t('tag-propositions.substraction')"
31 @click="add(Operation.SUBSTRACTION, proposed.rawTag)"
32 >
33 <fa-icon icon="minus" alt="[-]" />
34 </a>
35
36 <a
37 class="link"
38 :class="$style.operationBtns"
39 :title="$t('tag-propositions.addition')"
40 @click="add(Operation.ADDITION, proposed.rawTag)"
41 >
42 <fa-icon icon="plus" alt="[+]" />
43 </a>
44
45 <a
46 class="link"
47 :class="$style.operationTag"
48 :title="$t('tag-propositions.intersection')"
49 @click="add(Operation.INTERSECTION, proposed.rawTag)"
50 >{{ proposed.rawTag }}</a
51 >
52
53 <div class="disabled" :title="$t('tag-propositions.item-count')">{{ proposed.count }}</div>
54 </div>
55 <div v-if="showMoreCount > 0" :class="$style.showmore" @click="limit += showMoreCount">
56 {{ $t("tag-propositions.showmore", [showMoreCount]) }}<fa-icon icon="angle-double-down" />
57 </div>
58 </div>
59</template>
60
61<script lang="ts">
62import { Item, RawTag } from "@/@types/gallery";
63import { Operation } from "@/@types/Operation";
64import { TagIndex, TagNode, TagSearch } from "@/@types/tag";
65import { Component, Prop, PropSync, Vue, Watch } from "vue-property-decorator";
66
67@Component
68export default class LdProposition extends Vue {
69 @Prop() readonly category?: TagNode;
70 @Prop({ type: Boolean, required: true }) readonly showCategory!: boolean;
71 @Prop({ type: Array, required: true }) readonly currentTags!: string[];
72 @Prop({ required: true }) readonly tagsIndex!: TagIndex;
73 @PropSync("searchFilters", { type: Array, required: true }) model!: TagSearch[];
74
75 readonly INITIAL_TAG_DISPLAY_LIMIT = this.getInitialTagDisplayLimit();
76
77 limit: number = this.INITIAL_TAG_DISPLAY_LIMIT;
78
79 getInitialTagDisplayLimit() {
80 const limit = this.$galleryStore.config?.initialTagDisplayLimit ?? 10;
81 return limit >= 0 ? limit : 1000;
82 }
83
84 @Watch("$route")
85 onRouteChange() {
86 this.limit = this.INITIAL_TAG_DISPLAY_LIMIT;
87 }
88
89 get Operation() {
90 return Operation;
91 }
92
93 get propositions(): Record<string, number> {
94 const propositions: Record<string, number> = {};
95 if (this.model.length > 0) {
96 // Tags count from current search
97 this.extractDistinctItems(this.model)
98 .flatMap(item => item.tags)
99 .map(this.rightmost)
100 .filter(rawTag => this.tagsIndex[rawTag] && !this.model.find(search => search.tag === rawTag))
101 .forEach(rawTag => (propositions[rawTag] = (propositions[rawTag] ?? 0) + 1));
102 } else {
103 // Tags count from the current directory
104 this.currentTags
105 .flatMap(tag => tag.split(":"))
106 .map(tag => this.tagsIndex[tag])
107 .filter(Boolean)
108 .forEach(tagindex => (propositions[tagindex.tag] = tagindex.items.length));
109 }
110 return propositions;
111 }
112
113 get proposedTags() {
114 return Object.entries(this.propositions)
115 .sort((a, b) => b[1] - a[1])
116 .slice(0, this.limit)
117 .map(entry => ({ rawTag: entry[0], count: entry[1] }));
118 }
119
120 get showMoreCount(): number {
121 return Object.keys(this.propositions).length - Object.keys(this.proposedTags).length;
122 }
123
124 get title() {
125 return this.category?.tag ?? this.$t("panelLeft.propositions.other");
126 }
127
128 extractDistinctItems(currentTags: TagSearch[]): Item[] {
129 return [...new Set(currentTags.flatMap(tag => tag.items))];
130 }
131
132 rightmost(tag: RawTag): RawTag {
133 const dot = tag.lastIndexOf(":");
134 return dot <= 0 ? tag : tag.substr(dot + 1);
135 }
136
137 add(operation: Operation, rawTag: RawTag) {
138 const node = this.tagsIndex[rawTag];
139 const display = this.category ? `${operation}${this.category.tag}:${node.tag}` : `${operation}${node.tag}`;
140 this.model.push({ ...node, parent: this.category, operation, display });
141 }
142}
143</script>
144
145<style lang="scss" module>
146@import "~@/assets/scss/theme.scss";
147
148.proposition {
149 .subtitle {
150 background-color: $proposed-category-bgcolor;
151 width: 100%;
152 padding: 0 0 6px 0;
153 margin: 0;
154 text-align: center;
155 font-variant: small-caps;
156 }
157 > div {
158 display: flex;
159 align-items: center;
160 padding-right: 7px;
161 .operationTag {
162 text-overflow: ellipsis;
163 white-space: nowrap;
164 overflow: hidden;
165 flex-grow: 1;
166 cursor: pointer;
167 }
168 .operationBtns {
169 padding: 2px 7px;
170 cursor: pointer;
171 }
172 }
173 .showmore {
174 display: block;
175 text-align: right;
176 color: $palette-300;
177 cursor: pointer;
178 > svg {
179 margin-left: 10px;
180 }
181 &:hover {
182 color: $link-hover;
183 }
184 }
185}
186</style>