From 00510820a2794efcadbc83f7f8b54318fe198ecb Mon Sep 17 00:00:00 2001 From: Zéro~Informatique Date: Tue, 26 Jul 2022 08:44:34 +0200 Subject: viewer: migrate to vue 3, general refactoring and cleanup Non-exhaustive list of fixes and improvements done at the same time: - html default background to grey (avoids white flash during init) - unified links behavior - added more theme variables - removed the flex-expand transition (it wasn't working) and replaced it with a slide - fixed LdLoading not centered on the content - title on removable tags - fixed an issue with encoded URI from vue-router - unified Item resource URLs - removed the iframe for PlainTextViewer (it wasn't working properly) and replaced it with a pre - fixed clear and search buttons tabindex - fixed the information panel bumping up during the fade animation of tag's dropdown - fixed some focus outlines not appearing correctly - moved CSS variables to the :root context - Code cleaning GitHub: closes #217 GitHub: closes #300 GitHub: closes #297 GitHub: closes #105 GitHub: closes #267 GitHub: closes #275 GitHub: closes #228 GitHub: closes #215 GitHub: closes #112 --- viewer/src/store/galleryStore.ts | 201 ++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 118 deletions(-) (limited to 'viewer/src/store/galleryStore.ts') diff --git a/viewer/src/store/galleryStore.ts b/viewer/src/store/galleryStore.ts index e2adf18..7ee660a 100644 --- a/viewer/src/store/galleryStore.ts +++ b/viewer/src/store/galleryStore.ts @@ -1,7 +1,7 @@ /* ldgallery - A static generator which turns a collection of tagged -- pictures into a searchable web gallery. -- --- Copyright (C) 2019-2020 Guillaume FOUET +-- Copyright (C) 2019-2022 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 @@ -17,124 +17,89 @@ -- along with this program. If not, see . */ -import { Config, Index, Item } from "@/@types/gallery"; -import { TagCategory, TagIndex, TagSearch } from "@/@types/tag"; -import IndexFactory from "@/services/indexfactory"; -import Navigation from "@/services/navigation"; -import { action, createModule, mutation } from "vuex-class-component"; +import { Config, Index, Item } from '@/@types/gallery'; +import { TagCategory, TagIndex, TagSearch } from '@/@types/tag'; +import { useIndexFactory } from '@/services/indexFactory'; +import { useNavigation } from '@/services/navigation'; +import { defineStore } from 'pinia'; -const VuexModule = createModule({ - namespaced: "galleryStore", - strict: true, -}); - -export default class GalleryStore extends VuexModule { - config: Config | null = null; - galleryIndex: Index | null = null; - tagsIndex: TagIndex = {}; - tagsCategories: TagCategory[] = []; - currentPath: string | null = null; - currentSearch: TagSearch[] = []; - - // --- - - @mutation private setConfig(config: Config) { - this.config = config; - } - - @mutation setGalleryIndex(galleryIndex: Index) { - this.galleryIndex = Object.freeze(galleryIndex); - } - - @mutation private setTagsIndex(tagsIndex: TagIndex) { - this.tagsIndex = Object.freeze(tagsIndex); - } - - @mutation private setTagsCategories(tagsCategories: TagCategory[]) { - this.tagsCategories = tagsCategories; - } - - @mutation setCurrentPath(currentPath: string) { - this.currentPath = currentPath; - } - - @mutation setCurrentSearch(currentSearch: TagSearch[]) { - this.currentSearch = currentSearch; - } - - // --- - - get currentItemPath(): Item[] { - const root = this.galleryIndex?.tree; - if (root && this.currentPath) return Navigation.searchCurrentItemPath(root, this.currentPath); - return []; - } - - get currentItem(): Item | null { - const path = this.currentItemPath; - return path.length > 0 ? path[path.length - 1] : null; - } +const navigation = useNavigation(); +const indexFactory = useIndexFactory(); - get galleryTitle(): string { - return this.galleryIndex?.properties.galleryTitle ?? "ldgallery"; - } - - get resourceRoot(): string { - return process.env.VUE_APP_DATA_URL + this.config!.galleryRoot; - } - - // --- - - // Fetches the gallery's JSON config - @action async fetchConfig() { - await fetch(`${process.env.VUE_APP_DATA_URL}${GalleryStore.getUrlConfig()}`, { cache: "no-cache" }) - .then(GalleryStore.responseToJson) - .then(this.setConfig); - return this.config!; - } - - // Fetches the gallery's JSON metadata - @action async fetchGalleryItems() { - const root = this.config?.galleryRoot ?? ""; - const index = this.config?.galleryIndex ?? "index.json"; - await fetch(`${process.env.VUE_APP_DATA_URL}${root}${index}`, { cache: "no-cache" }) - .then(GalleryStore.responseToJson) - .then(this.setGalleryIndex) - .then(this.indexTags) - .then(this.indexTagCategories); - return this.galleryIndex!; - } - - // Indexes the gallery - @action async indexTags() { - const root = this.galleryIndex?.tree ?? null; - const index = IndexFactory.generateTags(root); - this.setTagsIndex(index); - return index; - } - - // Indexes the proposed categories - @action async indexTagCategories() { - const categories = IndexFactory.generateCategories(this.tagsIndex, this.galleryIndex?.properties.tagCategories); - this.setTagsCategories(categories); - return categories; - } - - // Searches for tags - @action async search(filters: string[]) { - const results = filters.flatMap(filter => IndexFactory.searchTags(this.tagsIndex, filter, true)); - this.setCurrentSearch(results); - return results; - } - - private static getUrlConfig() { - const search = window.location.search; - if (search.length > 1) return search.substr(1) + ".json"; - return "config.json"; - } +function getUrlConfig() { + const search = window.location.search; + if (search.length > 1) return search.substring(1) + '.json'; + return 'config.json'; +} - private static responseToJson(response: Response) { - if (!response.ok) throw new Error(`${response.status}: ${response.statusText}`); - return response.json(); - } +function responseToJson(response: Response) { + if (!response.ok) throw new Error(`${response.status}: ${response.statusText}`); + return response.json(); } + +export const useGalleryStore = defineStore('gallery', { + state: () => ({ + config: null as Config | null, + galleryIndex: null as Index | null, + tagsIndex: {} as TagIndex, + tagsCategories: [] as TagCategory[], + currentPath: null as string | null, + currentSearch: [] as TagSearch[], + }), + getters: { + currentItemPath(): Item[] { + const root = this.galleryIndex?.tree; + if (root && this.currentPath) return navigation.searchCurrentItemPath(root, this.currentPath); + return []; + }, + currentItem(): Item | null { + const path = this.currentItemPath; + return path.length > 0 ? path[path.length - 1] : null; + }, + galleryTitle(): string { + return this.galleryIndex?.properties.galleryTitle ?? 'ldgallery'; + }, + resourceRoot(): string { + return process.env.VUE_APP_DATA_URL + (this.config?.galleryRoot ?? ''); + }, + }, + actions: { + // Fetches the gallery's JSON config + async fetchConfig() { + await fetch(`${process.env.VUE_APP_DATA_URL}${getUrlConfig()}`, { cache: 'no-cache' }) + .then(responseToJson) + .then(v => (this.config = v)); + return this.config as Config; + }, + // Fetches the gallery's JSON metadata + async fetchGalleryItems() { + const root = this.config?.galleryRoot ?? ''; + const index = this.config?.galleryIndex ?? 'index.json'; + await fetch(`${process.env.VUE_APP_DATA_URL}${root}${index}`, { cache: 'no-cache' }) + .then(responseToJson) + .then(v => (this.galleryIndex = v)) + .then(this.indexTags) + .then(this.indexTagCategories); + return this.galleryIndex; + }, + // Indexes the gallery + async indexTags() { + const root = this.galleryIndex?.tree ?? null; + const index = indexFactory.generateTags(root); + this.tagsIndex = index; + return index; + }, + // Indexes the proposed categories + async indexTagCategories() { + const categories = indexFactory.generateCategories(this.tagsIndex, this.galleryIndex?.properties.tagCategories); + this.tagsCategories = categories; + return categories; + }, + // Searches for tags + async search(filters: string[]) { + const results = filters.flatMap(filter => indexFactory.searchTags(this.tagsIndex, filter, true)); + this.currentSearch = results; + return results; + }, + }, +}); -- cgit v1.2.3