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/.env | 2 ++ viewer/src/assets/scss/buefy.scss | 24 ++++++++---------------- viewer/src/assets/scss/global.scss | 11 +++++++++++ viewer/src/components/LdModeRadio.vue | 22 ++++++++++++++++++++++ viewer/src/locales/en.json | 8 ++++++-- viewer/src/plugins/fontawesome.ts | 4 ++-- viewer/src/store/galleryStore.ts | 21 +++++++++++++++++++-- viewer/src/store/uiStore.ts | 19 +++++++++++++++++++ viewer/src/views/Gallery.vue | 31 ++++++++++++++++--------------- viewer/src/views/GalleryDirectory.vue | 5 +---- viewer/src/views/GalleryImage.vue | 2 +- viewer/src/views/GallerySearch.vue | 25 +++++++++++++++++++++++++ viewer/src/views/GalleryThumbnail.vue | 10 ++++++++-- viewer/src/views/MainLayout.vue | 2 +- viewer/src/views/PanelLeft.vue | 9 +++++---- viewer/vue.config.js | 4 ++-- 16 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 viewer/src/components/LdModeRadio.vue create mode 100644 viewer/src/views/GallerySearch.vue diff --git a/viewer/.env b/viewer/.env index f256c63..d06d633 100644 --- a/viewer/.env +++ b/viewer/.env @@ -1,2 +1,4 @@ VUE_APP_I18N_LOCALE=en VUE_APP_I18N_FALLBACK_LOCALE=en +VUE_APP_DATA_URL=/gallery +VUE_APP_EXAMPLE_PROJECT=example diff --git a/viewer/src/assets/scss/buefy.scss b/viewer/src/assets/scss/buefy.scss index 5249899..b018fd3 100644 --- a/viewer/src/assets/scss/buefy.scss +++ b/viewer/src/assets/scss/buefy.scss @@ -5,28 +5,20 @@ @import "buefy_variables"; // 2. Setup your Custom Colors -$linkedin: #0077b5; -$linkedin-invert: findColorInvert($linkedin); -$twitter: #55acee; -$twitter-invert: findColorInvert($twitter); -$github: #333; -$github-invert: findColorInvert($github); +// $linkedin: #0077b5; +// $linkedin-invert: findColorInvert($linkedin); @import "~bulma/sass/utilities/derived-variables"; // 3. Add new color variables to the color map. $addColors: ( - "twitter": ( - $twitter, - $twitter-invert + "green": ( + $green, + $green-invert ), - "linkedin": ( - $linkedin, - $linkedin-invert - ), - "github": ( - $github, - $github-invert + "purple": ( + $purple, + $purple-invert ) ); $colors: map-merge($colors, $addColors); diff --git a/viewer/src/assets/scss/global.scss b/viewer/src/assets/scss/global.scss index 0bfeab9..5d12976 100644 --- a/viewer/src/assets/scss/global.scss +++ b/viewer/src/assets/scss/global.scss @@ -12,3 +12,14 @@ .nowrap { white-space: nowrap; } + +.flex { + display: flex; +} +.flex-column { + display: flex; + flex-direction: column; +} +.flex-center { + align-items: center; +} diff --git a/viewer/src/components/LdModeRadio.vue b/viewer/src/components/LdModeRadio.vue new file mode 100644 index 0000000..614bf33 --- /dev/null +++ b/viewer/src/components/LdModeRadio.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/viewer/src/locales/en.json b/viewer/src/locales/en.json index f24ac1f..d885872 100644 --- a/viewer/src/locales/en.json +++ b/viewer/src/locales/en.json @@ -1,5 +1,9 @@ { "tagInput.placeholder": "Tags", - "panelLeft.title": "Filters", - "tagInput.nomatch": "No match" + "panelLeft.filters": "Filters", + "tagInput.nomatch": "No match", + "panelLeft.mode": "Mode", + "mode.navigation": "Navigation", + "mode.search": "Search", + "search.no-results": "No results" } \ No newline at end of file diff --git a/viewer/src/plugins/fontawesome.ts b/viewer/src/plugins/fontawesome.ts index 9bf4dba..3af77b6 100644 --- a/viewer/src/plugins/fontawesome.ts +++ b/viewer/src/plugins/fontawesome.ts @@ -1,9 +1,9 @@ import Vue from "vue"; import { library } from "@fortawesome/fontawesome-svg-core"; -import { faExpandArrowsAlt } from "@fortawesome/free-solid-svg-icons"; +import { faExpandArrowsAlt, faFolder, faSearch } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; -library.add(faExpandArrowsAlt); +library.add(faExpandArrowsAlt, faFolder, faSearch); Vue.component("fa-icon", FontAwesomeIcon); 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"; + } } diff --git a/viewer/src/views/Gallery.vue b/viewer/src/views/Gallery.vue index 2020280..38199b9 100644 --- a/viewer/src/views/Gallery.vue +++ b/viewer/src/views/Gallery.vue @@ -1,17 +1,20 @@ diff --git a/viewer/src/views/GalleryImage.vue b/viewer/src/views/GalleryImage.vue index 07f8cc8..04d29d9 100644 --- a/viewer/src/views/GalleryImage.vue +++ b/viewer/src/views/GalleryImage.vue @@ -13,7 +13,7 @@ export default class GalleryImage extends Vue { @Prop({ required: true }) readonly image!: Gallery.Image; get imageSrc() { - return `/gallery${this.image.path}`; + return `${process.env.VUE_APP_DATA_URL}${this.image.path}`; } } diff --git a/viewer/src/views/GallerySearch.vue b/viewer/src/views/GallerySearch.vue new file mode 100644 index 0000000..887c1a3 --- /dev/null +++ b/viewer/src/views/GallerySearch.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/viewer/src/views/GalleryThumbnail.vue b/viewer/src/views/GalleryThumbnail.vue index 8e3e826..fdfd9d3 100644 --- a/viewer/src/views/GalleryThumbnail.vue +++ b/viewer/src/views/GalleryThumbnail.vue @@ -1,5 +1,11 @@ diff --git a/viewer/src/views/MainLayout.vue b/viewer/src/views/MainLayout.vue index 2afd4b9..2a87ff1 100644 --- a/viewer/src/views/MainLayout.vue +++ b/viewer/src/views/MainLayout.vue @@ -25,7 +25,7 @@ export default class MainLayout extends Vue { fetchGalleryItems() { this.isLoading = true; this.$galleryStore - .fetchGalleryItems("/gallery/index.json") + .fetchGalleryItems(`${process.env.VUE_APP_DATA_URL}/index.json`) .finally(() => (this.isLoading = false)) .catch(this.displayError); } diff --git a/viewer/src/views/PanelLeft.vue b/viewer/src/views/PanelLeft.vue index 4b5bce0..c187ce6 100644 --- a/viewer/src/views/PanelLeft.vue +++ b/viewer/src/views/PanelLeft.vue @@ -1,8 +1,9 @@ diff --git a/viewer/vue.config.js b/viewer/vue.config.js index f116619..dbf1551 100644 --- a/viewer/vue.config.js +++ b/viewer/vue.config.js @@ -12,9 +12,9 @@ module.exports = { port: 8085, serveIndex: true, before: (app, server, compiler) => { - app.get("/gallery/*", (req, res) => { + app.get(`${process.env.VUE_APP_DATA_URL}/*`, (req, res) => { const fs = require("fs"); - const fileName = req.url.replace(/^\/gallery/, "../example"); + const fileName = `../${process.env.VUE_APP_EXAMPLE_PROJECT}${req.url.slice(process.env.VUE_APP_DATA_URL.length)}`; const file = fs.readFileSync(decodeURIComponent(fileName)); res.end(file); }); -- cgit v1.2.3