From 62005141132da1e9761598fa3e4b35b4dab38a89 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sat, 21 Dec 2019 02:06:02 +0100 Subject: Implemented VueX and a basic UIStore with the fullscreen mutation Some renaming --- viewer/src/store/uiStore.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 viewer/src/store/uiStore.ts (limited to 'viewer/src/store') diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts new file mode 100644 index 0000000..c4143a1 --- /dev/null +++ b/viewer/src/store/uiStore.ts @@ -0,0 +1,15 @@ +import { createModule, mutation, action } from "vuex-class-component"; + +const VuexModule = createModule({ + namespaced: "uiStore", + strict: true +}) + +export default class UIStore extends VuexModule { + + fullscreen: boolean = false; + + @mutation toggleFullscreen() { + this.fullscreen = !this.fullscreen; + } +} -- cgit v1.2.3 From 9e4fdd6f38853d8a4a959901ab7902569de75484 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sat, 21 Dec 2019 08:08:54 +0100 Subject: viewer: Implemented the "example" project in devServer Display loader and error messages (not translated yet) Created a "GalleryStore" to fetch the JSon data from the gallery (currently from example) --- viewer/src/store/galleryStore.ts | 21 +++++++++++++++++++++ viewer/src/store/index.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 viewer/src/store/galleryStore.ts create mode 100644 viewer/src/store/index.ts (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts new file mode 100644 index 0000000..63e5109 --- /dev/null +++ b/viewer/src/store/galleryStore.ts @@ -0,0 +1,21 @@ +import { createModule, mutation, action } from "vuex-class-component"; + +const VuexModule = createModule({ + namespaced: "galleryStore", + strict: true +}) + +export default class GalleryStore extends VuexModule { + + galleryItems: Gallery.Item[] = []; + + @mutation setGalleryItems(galleryItems: Gallery.Item[]) { + this.galleryItems = galleryItems; + } + + @action async fetchGalleryItems(url: string) { + fetch(url) + .then(response => response.json()) + .then(this.setGalleryItems); + } +} \ No newline at end of file diff --git a/viewer/src/store/index.ts b/viewer/src/store/index.ts new file mode 100644 index 0000000..cadd8e3 --- /dev/null +++ b/viewer/src/store/index.ts @@ -0,0 +1,27 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import { extractVuexModule } from "vuex-class-component"; +import { createProxy } from "vuex-class-component"; +import UIStore from '@/store/uiStore'; +import GalleryStore from '@/store/galleryStore'; + +Vue.use(Vuex) + +const store = new Vuex.Store({ + modules: { + ...extractVuexModule(UIStore), + ...extractVuexModule(GalleryStore) + } +}); + +Vue.use((vue) => vue.prototype.$uiStore = createProxy(store, UIStore)); +Vue.use((vue) => vue.prototype.$galleryStore = createProxy(store, GalleryStore)); + +declare module 'vue/types/vue' { + interface Vue { + $uiStore: UIStore, + $galleryStore: GalleryStore + } +} + +export default store; -- cgit v1.2.3 From 3f21d10338afe8eab699aaaea060556579e4b3c3 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sat, 21 Dec 2019 10:33:21 +0100 Subject: viewer: Some renaming for better clarity Implemented a basic display of filenames with basic navigation --- viewer/src/store/galleryStore.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index 63e5109..4751561 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -7,9 +7,9 @@ const VuexModule = createModule({ export default class GalleryStore extends VuexModule { - galleryItems: Gallery.Item[] = []; + galleryItems: Gallery.Item | null = null; - @mutation setGalleryItems(galleryItems: Gallery.Item[]) { + @mutation setGalleryItems(galleryItems: Gallery.Item) { this.galleryItems = galleryItems; } @@ -18,4 +18,5 @@ export default class GalleryStore extends VuexModule { .then(response => response.json()) .then(this.setGalleryItems); } + } \ No newline at end of file -- cgit v1.2.3 From e34be1261d9219e5b2b92ebe271f609f11d55f63 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sun, 22 Dec 2019 03:50:40 +0100 Subject: vewer: Tags indexing and search input --- viewer/src/store/galleryStore.ts | 41 ++++++++++++++++++++++++++++++++++++---- viewer/src/store/uiStore.ts | 5 ++++- 2 files changed, 41 insertions(+), 5 deletions(-) (limited to 'viewer/src/store') 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({ export default class GalleryStore extends VuexModule { - galleryItems: Gallery.Item | null = null; + galleryItemsRoot: Gallery.Item | null = null; + tags: Tag.Index = {}; - @mutation setGalleryItems(galleryItems: Gallery.Item) { - this.galleryItems = galleryItems; + // --- + + @mutation setGalleryItemsRoot(galleryItemsRoot: Gallery.Item) { + this.galleryItemsRoot = galleryItemsRoot; + } + + @mutation private setTags(tags: Tag.Index) { + this.tags = tags; } + // --- + @action async fetchGalleryItems(url: string) { fetch(url) .then(response => response.json()) - .then(this.setGalleryItems); + .then(this.setGalleryItemsRoot) + .then(this.indexTags); } + @action async indexTags() { + let index = {}; + if (this.galleryItemsRoot) + GalleryStore.pushTagsForItem(index, this.galleryItemsRoot); + console.log(index); + this.setTags(index); + } + + private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { + console.log("IndexingTagsFor: ", item.path); + for (const tag of item.tags) { + const parts = tag.split('.'); + let lastPart: string | null = null; + for (const part of parts) { + if (!index[part]) index[part] = { tag: part, items: [], children: {} }; + index[part].items.push(item); + if (lastPart) index[lastPart].children[part] = index[part]; + lastPart = part; + } + } + if (item.properties.type === "directory") + item.properties.items.forEach(item => this.pushTagsForItem(index, item)); + } } \ 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"; const VuexModule = createModule({ namespaced: "uiStore", - strict: true + strict: false }) export default class UIStore extends VuexModule { fullscreen: boolean = false; + currentTags: Tag.Node[] = []; + + // --- @mutation toggleFullscreen() { this.fullscreen = !this.fullscreen; -- cgit v1.2.3 From dc251fffc2998f1cf4f8e9631928c4b92ac0d90e Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sun, 22 Dec 2019 07:40:55 +0100 Subject: viewer: Implemented the search by tags. Pushed the special urls to ENV. --- viewer/src/store/galleryStore.ts | 21 +++++++++++++++++++-- viewer/src/store/uiStore.ts | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index c875837..ca36a32 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -22,6 +22,7 @@ export default class GalleryStore extends VuexModule { // --- + // Fetches the gallery's JSON metadata @action async fetchGalleryItems(url: string) { fetch(url) .then(response => response.json()) @@ -29,14 +30,18 @@ export default class GalleryStore extends VuexModule { .then(this.indexTags); } + // Indexes the gallery @action async indexTags() { let index = {}; if (this.galleryItemsRoot) GalleryStore.pushTagsForItem(index, this.galleryItemsRoot); - console.log(index); + console.log("Index: ", index); this.setTags(index); } + // --- + + // Pushes all tags for a root item (and its children) to the index private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { console.log("IndexingTagsFor: ", item.path); for (const tag of item.tags) { @@ -44,7 +49,7 @@ export default class GalleryStore extends VuexModule { let lastPart: string | null = null; for (const part of parts) { if (!index[part]) index[part] = { tag: part, items: [], children: {} }; - index[part].items.push(item); + if (!index[part].items.includes(item)) index[part].items.push(item); if (lastPart) index[lastPart].children[part] = index[part]; lastPart = part; } @@ -52,4 +57,16 @@ export default class GalleryStore extends VuexModule { if (item.properties.type === "directory") item.properties.items.forEach(item => this.pushTagsForItem(index, item)); } + + // Searches for an item by path from a root item (navigation) + static searchCurrentItem(item: Gallery.Item, path: string): Gallery.Item | null { + if (path === item.path) return item; + if (item.properties.type === "directory" && path.startsWith(item.path)) { + const itemFound = item.properties.items + .map(item => this.searchCurrentItem(item, path)) + .find(item => Boolean(item)); + return itemFound || null; + } + return null; + } } \ No newline at end of file diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts index e04b507..4a6f487 100644 --- a/viewer/src/store/uiStore.ts +++ b/viewer/src/store/uiStore.ts @@ -8,11 +8,30 @@ const VuexModule = createModule({ export default class UIStore extends VuexModule { fullscreen: boolean = false; + mode: "navigation" | "search" = "navigation"; currentTags: Tag.Node[] = []; // --- + get isModeSearch() { + return this.mode === "search"; + } + + get isModeNavigation() { + return this.mode === "navigation"; + } + + // --- + @mutation toggleFullscreen() { this.fullscreen = !this.fullscreen; } + + @mutation setModeNavigation() { + this.mode = "navigation"; + } + + @mutation setModeSearch() { + this.mode = "search"; + } } -- cgit v1.2.3 From 7c2576b0cfb0a15b2a14f6f5ea96de16f0c23b44 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Tue, 24 Dec 2019 02:22:56 +0100 Subject: viewer: Plugin for Optional chaining and Coalesce. Implemented tag operations (intersection, addition, substraction). Unified Tag.Search --- viewer/src/store/galleryStore.ts | 2 +- viewer/src/store/uiStore.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index ca36a32..8a611ea 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -65,7 +65,7 @@ export default class GalleryStore extends VuexModule { const itemFound = item.properties.items .map(item => this.searchCurrentItem(item, path)) .find(item => Boolean(item)); - return itemFound || null; + return itemFound ?? null; } return null; } diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts index 4a6f487..25d2a28 100644 --- a/viewer/src/store/uiStore.ts +++ b/viewer/src/store/uiStore.ts @@ -9,7 +9,7 @@ export default class UIStore extends VuexModule { fullscreen: boolean = false; mode: "navigation" | "search" = "navigation"; - currentTags: Tag.Node[] = []; + currentTags: Tag.Search[] = []; // --- -- cgit v1.2.3 From a681accaa7617892bb7c53248aa9030a4eb47f50 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Sat, 28 Dec 2019 04:52:30 +0100 Subject: 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. --- viewer/src/store/galleryStore.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'viewer/src/store') 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 { // Pushes all tags for a root item (and its children) to the index private static pushTagsForItem(index: Tag.Index, item: Gallery.Item) { console.log("IndexingTagsFor: ", item.path); + if (item.properties.type === "directory") { + item.properties.items.forEach(item => this.pushTagsForItem(index, item)); + return; // Directories are not indexed + } for (const tag of item.tags) { const parts = tag.split('.'); let lastPart: string | null = null; @@ -54,8 +58,6 @@ export default class GalleryStore extends VuexModule { lastPart = part; } } - if (item.properties.type === "directory") - item.properties.items.forEach(item => this.pushTagsForItem(index, item)); } // Searches for an item by path from a root item (navigation) -- cgit v1.2.3 From 89bcb2dbe5b5e6eb8e8ba13ceecee2770dfe4cd4 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Thu, 9 Jan 2020 02:10:35 +0100 Subject: viewer: Changed "image" type to "picture". Adapted the code to the current compiler output format. The currentItem and currentPath are calculated in the store for easier multi-component access. Breadcrumb for current's position and navigation. --- viewer/src/store/galleryStore.ts | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index 179fbe2..2d17fd6 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -9,6 +9,7 @@ export default class GalleryStore extends VuexModule { galleryItemsRoot: Gallery.Item | null = null; tags: Tag.Index = {}; + currentPath: string = "/"; // --- @@ -20,6 +21,22 @@ export default class GalleryStore extends VuexModule { this.tags = tags; } + @mutation setCurrentPath(currentPath: string) { + this.currentPath = currentPath; + } + + get currentItemPath(): Gallery.Item[] { + const galleryItemsRoot = this.galleryItemsRoot; + if (galleryItemsRoot) + return GalleryStore.searchCurrentItemPath(galleryItemsRoot, this.currentPath); + return []; + } + + get currentItem(): Gallery.Item | null { + const currentItemPath = this.currentItemPath; + return currentItemPath.length > 0 ? currentItemPath[currentItemPath.length - 1] : null; + } + // --- // Fetches the gallery's JSON metadata @@ -61,14 +78,14 @@ export default class GalleryStore extends VuexModule { } // Searches for an item by path from a root item (navigation) - static searchCurrentItem(item: Gallery.Item, path: string): Gallery.Item | null { - if (path === item.path) return item; + private static searchCurrentItemPath(item: Gallery.Item, path: string): Gallery.Item[] { + if (path === item.path) return [item]; if (item.properties.type === "directory" && path.startsWith(item.path)) { - const itemFound = item.properties.items - .map(item => this.searchCurrentItem(item, path)) - .find(item => Boolean(item)); - return itemFound ?? null; + const itemChain = item.properties.items + .map(item => this.searchCurrentItemPath(item, path)) + .find(itemChain => itemChain.length > 0); + if (itemChain) return [item, ...itemChain]; } - return null; + return []; } } \ No newline at end of file -- cgit v1.2.3 From 27b51018525dbb7a6edb3073819d82245387ddd3 Mon Sep 17 00:00:00 2001 From: Zero~Informatique Date: Fri, 10 Jan 2020 22:22:22 +0100 Subject: viewer: license headers --- viewer/src/store/galleryStore.ts | 19 +++++++++++++++++++ viewer/src/store/index.ts | 19 +++++++++++++++++++ viewer/src/store/uiStore.ts | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) (limited to 'viewer/src/store') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index 2d17fd6..c4a039f 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -1,3 +1,22 @@ +/* ldgallery - A static generator which turns a collection of tagged +-- pictures into a searchable web gallery. +-- +-- Copyright (C) 2019-2020 Guillaume FOUET +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU Affero General Public License as +-- published by the Free Software Foundation, either version 3 of the +-- License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Affero General Public License for more details. +-- +-- You should have received a copy of the GNU Affero General Public License +-- along with this program. If not, see . +*/ + import { createModule, mutation, action } from "vuex-class-component"; const VuexModule = createModule({ diff --git a/viewer/src/store/index.ts b/viewer/src/store/index.ts index cadd8e3..0277fa4 100644 --- a/viewer/src/store/index.ts +++ b/viewer/src/store/index.ts @@ -1,3 +1,22 @@ +/* ldgallery - A static generator which turns a collection of tagged +-- pictures into a searchable web gallery. +-- +-- Copyright (C) 2019-2020 Guillaume FOUET +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU Affero General Public License as +-- published by the Free Software Foundation, either version 3 of the +-- License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Affero General Public License for more details. +-- +-- You should have received a copy of the GNU Affero General Public License +-- along with this program. If not, see . +*/ + import Vue from 'vue' import Vuex from 'vuex' import { extractVuexModule } from "vuex-class-component"; diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts index 25d2a28..6bcc538 100644 --- a/viewer/src/store/uiStore.ts +++ b/viewer/src/store/uiStore.ts @@ -1,3 +1,22 @@ +/* ldgallery - A static generator which turns a collection of tagged +-- pictures into a searchable web gallery. +-- +-- Copyright (C) 2019-2020 Guillaume FOUET +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU Affero General Public License as +-- published by the Free Software Foundation, either version 3 of the +-- License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Affero General Public License for more details. +-- +-- You should have received a copy of the GNU Affero General Public License +-- along with this program. If not, see . +*/ + import { createModule, mutation, action } from "vuex-class-component"; const VuexModule = createModule({ -- cgit v1.2.3