aboutsummaryrefslogtreecommitdiff
path: root/viewer/src
diff options
context:
space:
mode:
authorZero~Informatique2019-12-22 03:50:40 +0100
committerZero~Informatique2019-12-22 03:50:40 +0100
commite34be1261d9219e5b2b92ebe271f609f11d55f63 (patch)
treef9bb705d0b7ec819b48ddfd5a318642ca239aff3 /viewer/src
parentc2b4c5d144db17ebf2dc9de32ba25cc836831ae2 (diff)
downloadldgallery-e34be1261d9219e5b2b92ebe271f609f11d55f63.tar.gz
vewer: Tags indexing and search input
Diffstat (limited to 'viewer/src')
-rw-r--r--viewer/src/@types/tag/index.d.ts8
-rw-r--r--viewer/src/components/LdTagInput.vue40
-rw-r--r--viewer/src/locales/en.json4
-rw-r--r--viewer/src/store/galleryStore.ts41
-rw-r--r--viewer/src/store/uiStore.ts5
-rw-r--r--viewer/src/views/Gallery.vue6
-rw-r--r--viewer/src/views/MainLayout.vue7
-rw-r--r--viewer/src/views/PanelLeft.vue20
8 files changed, 120 insertions, 11 deletions
diff --git a/viewer/src/@types/tag/index.d.ts b/viewer/src/@types/tag/index.d.ts
new file mode 100644
index 0000000..6a027d4
--- /dev/null
+++ b/viewer/src/@types/tag/index.d.ts
@@ -0,0 +1,8 @@
1declare namespace Tag {
2 interface Node {
3 tag: string;
4 items: Gallery.Item[];
5 children: Index;
6 }
7 type Index = { [index: string]: Node };
8} \ No newline at end of file
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue
new file mode 100644
index 0000000..4edc1ce
--- /dev/null
+++ b/viewer/src/components/LdTagInput.vue
@@ -0,0 +1,40 @@
1<template>
2 <b-taginput
3 v-model="$uiStore.currentTags"
4 :placeholder="$t('tagInput.placeholder')"
5 autocomplete
6 :data="filteredTags"
7 field="tag"
8 type="is-black"
9 size="is-large"
10 class="panelTagInput"
11 @typing="getFilteredTags"
12 >
13 <template slot-scope="props">{{props.option.tag}} ({{props.option.items.length}})</template>
14 <template slot="empty">{{$t('tagInput.nomatch')}}</template>
15 </b-taginput>
16</template>
17
18<script lang="ts">
19import { Component, Vue } from "vue-property-decorator";
20
21@Component
22export default class LdTagInput extends Vue {
23 filteredTags: Tag.Node[] = [];
24
25 getFilteredTags(filter: string) {
26 const tags = this.$galleryStore.tags;
27 if (tags && filter)
28 this.filteredTags = Object.values(tags)
29 .filter(node => node.tag.includes(filter))
30 .sort((a, b) => b.items.length - a.items.length);
31 else this.filteredTags = [];
32 }
33}
34</script>
35
36<style lang="scss">
37.panelTagInput .autocomplete .dropdown-content {
38 max-height: 300px;
39}
40</style>
diff --git a/viewer/src/locales/en.json b/viewer/src/locales/en.json
index d966983..f24ac1f 100644
--- a/viewer/src/locales/en.json
+++ b/viewer/src/locales/en.json
@@ -1,3 +1,5 @@
1{ 1{
2 "message": "hello i18n !!" 2 "tagInput.placeholder": "Tags",
3 "panelLeft.title": "Filters",
4 "tagInput.nomatch": "No match"
3} \ No newline at end of file 5} \ No newline at end of file
diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts
index 4751561..c875837 100644
--- a/viewer/src/store/galleryStore.ts
+++ b/viewer/src/store/galleryStore.ts
@@ -7,16 +7,49 @@ const VuexModule = createModule({
7 7
8export default class GalleryStore extends VuexModule { 8export default class GalleryStore extends VuexModule {
9 9
10 galleryItems: Gallery.Item | null = null; 10 galleryItemsRoot: Gallery.Item | null = null;
11 tags: Tag.Index = {};
11 12
12 @mutation setGalleryItems(galleryItems: Gallery.Item) { 13 // ---
13 this.galleryItems = galleryItems; 14
15 @mutation setGalleryItemsRoot(galleryItemsRoot: Gallery.Item) {
16 this.galleryItemsRoot = galleryItemsRoot;
17 }
18
19 @mutation private setTags(tags: Tag.Index) {
20 this.tags = tags;
14 } 21 }
15 22
23 // ---
24
16 @action async fetchGalleryItems(url: string) { 25 @action async fetchGalleryItems(url: string) {
17 fetch(url) 26 fetch(url)
18 .then(response => response.json()) 27 .then(response => response.json())
19 .then(this.setGalleryItems); 28 .then(this.setGalleryItemsRoot)
29 .then(this.indexTags);
20 } 30 }
21 31
32 @action async indexTags() {
33 let index = {};
34 if (this.galleryItemsRoot)
35 GalleryStore.pushTagsForItem(index, this.galleryItemsRoot);
36 console.log(index);
37 this.setTags(index);
38 }
39
40 private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) {
41 console.log("IndexingTagsFor: ", item.path);
42 for (const tag of item.tags) {
43 const parts = tag.split('.');
44 let lastPart: string | null = null;
45 for (const part of parts) {
46 if (!index[part]) index[part] = { tag: part, items: [], children: {} };
47 index[part].items.push(item);
48 if (lastPart) index[lastPart].children[part] = index[part];
49 lastPart = part;
50 }
51 }
52 if (item.properties.type === "directory")
53 item.properties.items.forEach(item => this.pushTagsForItem(index, item));
54 }
22} \ No newline at end of file 55} \ No newline at end of file
diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts
index c4143a1..e04b507 100644
--- a/viewer/src/store/uiStore.ts
+++ b/viewer/src/store/uiStore.ts
@@ -2,12 +2,15 @@ import { createModule, mutation, action } from "vuex-class-component";
2 2
3const VuexModule = createModule({ 3const VuexModule = createModule({
4 namespaced: "uiStore", 4 namespaced: "uiStore",
5 strict: true 5 strict: false
6}) 6})
7 7
8export default class UIStore extends VuexModule { 8export default class UIStore extends VuexModule {
9 9
10 fullscreen: boolean = false; 10 fullscreen: boolean = false;
11 currentTags: Tag.Node[] = [];
12
13 // ---
11 14
12 @mutation toggleFullscreen() { 15 @mutation toggleFullscreen() {
13 this.fullscreen = !this.fullscreen; 16 this.fullscreen = !this.fullscreen;
diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue
index 954903a..2020280 100644
--- a/viewer/src/views/Gallery.vue
+++ b/viewer/src/views/Gallery.vue
@@ -13,7 +13,7 @@ import GalleryImage from "./GalleryImage.vue";
13@Component({ 13@Component({
14 components: { GalleryDirectory, GalleryImage }, 14 components: { GalleryDirectory, GalleryImage },
15}) 15})
16export default class Root extends Vue { 16export default class Gallery extends Vue {
17 @Prop(String) readonly pathMatch!: string; 17 @Prop(String) readonly pathMatch!: string;
18 18
19 get isDirectory(): boolean { 19 get isDirectory(): boolean {
@@ -25,8 +25,8 @@ export default class Root extends Vue {
25 } 25 }
26 26
27 get currentItem(): Gallery.Item | null { 27 get currentItem(): Gallery.Item | null {
28 const galleryItems = this.$galleryStore.galleryItems; 28 const galleryItemsRoot = this.$galleryStore.galleryItemsRoot;
29 if (galleryItems) return this.searchCurrentItem(galleryItems, this.pathMatch); 29 if (galleryItemsRoot) return this.searchCurrentItem(galleryItemsRoot, this.pathMatch);
30 return null; 30 return null;
31 } 31 }
32 32
diff --git a/viewer/src/views/MainLayout.vue b/viewer/src/views/MainLayout.vue
index 9f3a17b..2afd4b9 100644
--- a/viewer/src/views/MainLayout.vue
+++ b/viewer/src/views/MainLayout.vue
@@ -1,7 +1,7 @@
1<template> 1<template>
2 <div :class="{fullscreen: $uiStore.fullscreen}"> 2 <div :class="{fullscreen: $uiStore.fullscreen}">
3 <div class="layout layout-top">header</div> 3 <div class="layout layout-top">header</div>
4 <div class="layout layout-left">panel</div> 4 <panel-left class="layout layout-left" />
5 <router-view class="layout layout-content" /> 5 <router-view class="layout layout-content" />
6 <ld-button-fullscreen /> 6 <ld-button-fullscreen />
7 <b-loading :active="isLoading" is-full-page /> 7 <b-loading :active="isLoading" is-full-page />
@@ -10,8 +10,11 @@
10 10
11<script lang="ts"> 11<script lang="ts">
12import { Component, Vue } from "vue-property-decorator"; 12import { Component, Vue } from "vue-property-decorator";
13import PanelLeft from "./PanelLeft.vue";
13 14
14@Component 15@Component({
16 components: { PanelLeft },
17})
15export default class MainLayout extends Vue { 18export default class MainLayout extends Vue {
16 isLoading: boolean = false; 19 isLoading: boolean = false;
17 20
diff --git a/viewer/src/views/PanelLeft.vue b/viewer/src/views/PanelLeft.vue
new file mode 100644
index 0000000..4b5bce0
--- /dev/null
+++ b/viewer/src/views/PanelLeft.vue
@@ -0,0 +1,20 @@
1<template>
2 <div>
3 <b-field :label="$t('panelLeft.title')">
4 <ld-tag-input />
5 </b-field>
6 </div>
7</template>
8
9<script lang="ts">
10import { Component, Vue, Prop } from "vue-property-decorator";
11
12@Component
13export default class PanelLeft extends Vue {}
14</script>
15
16<style lang="scss">
17.label {
18 color: white;
19}
20</style>