aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--viewer/.eslintrc.js2
-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
-rw-r--r--viewer/visualstudio.code-workspace1
10 files changed, 122 insertions, 12 deletions
diff --git a/viewer/.eslintrc.js b/viewer/.eslintrc.js
index 095216b..996c4f3 100644
--- a/viewer/.eslintrc.js
+++ b/viewer/.eslintrc.js
@@ -11,7 +11,7 @@ module.exports = {
11 ], 11 ],
12 12
13 rules: { 13 rules: {
14 "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 14 "no-console": "off",
15 "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", 15 "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
16 'vue/attribute-hyphenation': 'warn', 16 'vue/attribute-hyphenation': 'warn',
17 'vue/html-closing-bracket-spacing': 'warn', 17 'vue/html-closing-bracket-spacing': 'warn',
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>