diff options
Diffstat (limited to 'viewer/src/views')
27 files changed, 2259 insertions, 297 deletions
diff --git a/viewer/src/views/GalleryNavigation.vue b/viewer/src/views/GalleryNavigation.vue index 7c6d11b..b342c52 100644 --- a/viewer/src/views/GalleryNavigation.vue +++ b/viewer/src/views/GalleryNavigation.vue | |||
@@ -1,7 +1,7 @@ | |||
1 | <!-- ldgallery - A static generator which turns a collection of tagged | 1 | <!-- ldgallery - A static generator which turns a collection of tagged |
2 | -- pictures into a searchable web gallery. | 2 | -- pictures into a searchable web gallery. |
3 | -- | 3 | -- |
4 | -- Copyright (C) 2019-2020 Guillaume FOUET | 4 | -- Copyright (C) 2019-2022 Guillaume FOUET |
5 | -- | 5 | -- |
6 | -- This program is free software: you can redistribute it and/or modify | 6 | -- This program is free software: you can redistribute it and/or modify |
7 | -- it under the terms of the GNU Affero General Public License as | 7 | -- it under the terms of the GNU Affero General Public License as |
@@ -19,44 +19,65 @@ | |||
19 | 19 | ||
20 | <template> | 20 | <template> |
21 | <div> | 21 | <div> |
22 | <gallery-search v-if="query.length" :path="path" /> | 22 | <LdNotice |
23 | <gallery-directory v-else-if="checkType('directory')" :directory="$galleryStore.currentItem" /> | 23 | v-if="isError" |
24 | <ld-picture v-else-if="checkType('picture')" :picture="$galleryStore.currentItem" /> | 24 | :icon="faFolderOpen" |
25 | <div v-else>{{$t("gallery.unknowntype")}}</div> | 25 | :message="t('gallery.unknown-resource')" |
26 | /> | ||
27 | <GallerySearch v-else-if="isSearch" /> | ||
28 | <component | ||
29 | :is="componentName" | ||
30 | v-else | ||
31 | :key="componentKey" | ||
32 | :item="galleryStore.currentItem" | ||
33 | /> | ||
26 | </div> | 34 | </div> |
27 | </template> | 35 | </template> |
28 | 36 | ||
29 | <script lang="ts"> | 37 | <script setup lang="ts"> |
30 | import { Component, Vue, Prop, Watch } from "vue-property-decorator"; | 38 | import { ItemType } from '@/@types/itemType'; |
31 | import { Operation } from "@/@types/Operation"; | 39 | import LdNotice from '@/components/LdNotice.vue'; |
32 | import Navigation from "@/services/navigation"; | 40 | import { isDirectory } from '@/services/itemGuards'; |
33 | import GalleryDirectory from "./GalleryDirectory.vue"; | 41 | import { useGalleryStore } from '@/store/galleryStore'; |
34 | import GallerySearch from "@/views/GallerySearch.vue"; | 42 | import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; |
43 | import { computedEager } from '@vueuse/shared'; | ||
44 | import { computed, watchEffect } from 'vue'; | ||
45 | import { useI18n } from 'vue-i18n'; | ||
46 | import GallerySearch from './GallerySearch.vue'; | ||
47 | import { EpubViewer } from './item_handlers/async'; | ||
48 | import AudioViewer from './item_handlers/AudioViewer.vue'; | ||
49 | import DirectoryViewer from './item_handlers/DirectoryViewer.vue'; | ||
50 | import DownloadViewer from './item_handlers/DownloadViewer.vue'; | ||
51 | import MarkdownViewer from './item_handlers/MarkdownViewer.vue'; | ||
52 | import PdfViewer from './item_handlers/PdfViewer.vue'; | ||
53 | import PictureViewer from './item_handlers/PictureViewer.vue'; | ||
54 | import PlainTextViewer from './item_handlers/PlainTextViewer.vue'; | ||
55 | import VideoViewer from './item_handlers/VideoViewer.vue'; | ||
35 | 56 | ||
36 | @Component({ | 57 | const props = defineProps({ |
37 | components: { | 58 | path: { type: String, required: true }, |
38 | GalleryDirectory, | 59 | query: { type: Array<string>, required: true }, |
39 | GallerySearch, | 60 | }); |
40 | }, | ||
41 | }) | ||
42 | export default class GalleryNavigation extends Vue { | ||
43 | @Prop(String) readonly path!: string; | ||
44 | @Prop(Array) readonly query!: string[]; | ||
45 | 61 | ||
46 | mounted() { | 62 | const { t } = useI18n(); |
47 | this.pathChanged(); | 63 | const galleryStore = useGalleryStore(); |
48 | } | ||
49 | 64 | ||
50 | @Watch("path") | 65 | const COMPONENT_BY_TYPE: Record<ItemType, unknown> = { |
51 | pathChanged() { | 66 | directory: DirectoryViewer, |
52 | this.$galleryStore.setCurrentPath(this.path); | 67 | picture: PictureViewer, |
53 | } | 68 | plaintext: PlainTextViewer, |
69 | markdown: MarkdownViewer, | ||
70 | pdf: PdfViewer, | ||
71 | epub: EpubViewer, | ||
72 | video: VideoViewer, | ||
73 | audio: AudioViewer, | ||
74 | other: DownloadViewer, | ||
75 | }; | ||
54 | 76 | ||
55 | private checkType(type: Gallery.ItemType): boolean { | 77 | const isError = computedEager(() => !galleryStore.currentItem?.properties.type); |
56 | return Navigation.checkType(this.$galleryStore.currentItem, type); | 78 | const isSearch = computedEager(() => isDirectory(galleryStore.currentItem) && props.query.length > 0); |
57 | } | 79 | const componentName = computed(() => COMPONENT_BY_TYPE[galleryStore.currentItem?.properties.type ?? ItemType.OTHER]); |
58 | } | 80 | const componentKey = computed(() => galleryStore.currentItem?.path ?? ''); |
59 | </script> | ||
60 | 81 | ||
61 | <style lang="scss"> | 82 | watchEffect(() => (galleryStore.currentPath = props.path)); |
62 | </style> | 83 | </script> |
diff --git a/viewer/src/views/GallerySearch.vue b/viewer/src/views/GallerySearch.vue index e75a37e..d148b9c 100644 --- a/viewer/src/views/GallerySearch.vue +++ b/viewer/src/views/GallerySearch.vue | |||
@@ -1,7 +1,7 @@ | |||
1 | <!-- ldgallery - A static generator which turns a collection of tagged | 1 | <!-- ldgallery - A static generator which turns a collection of tagged |
2 | -- pictures into a searchable web gallery. | 2 | -- pictures into a searchable web gallery. |
3 | -- | 3 | -- |
4 | -- Copyright (C) 2019-2020 Guillaume FOUET | 4 | -- Copyright (C) 2019-2022 Guillaume FOUET |
5 | -- | 5 | -- |
6 | -- This program is free software: you can redistribute it and/or modify | 6 | -- This program is free software: you can redistribute it and/or modify |
7 | -- it under the terms of the GNU Affero General Public License as | 7 | -- it under the terms of the GNU Affero General Public License as |
@@ -18,43 +18,39 @@ | |||
18 | --> | 18 | --> |
19 | 19 | ||
20 | <template> | 20 | <template> |
21 | <ld-gallery :items="items()" :noresult="noResult()" /> | 21 | <GalleryTiles |
22 | :items="items.filteredByPath" | ||
23 | :noresult-message="noResult" | ||
24 | /> | ||
22 | </template> | 25 | </template> |
23 | 26 | ||
24 | <script lang="ts"> | 27 | <script setup lang="ts"> |
25 | import { Component, Vue, Prop } from "vue-property-decorator"; | 28 | import { useIndexSearch } from '@/services/indexSearch'; |
26 | import { Operation } from "@/@types/Operation"; | 29 | import { useGalleryStore } from '@/store/galleryStore'; |
27 | import IndexSearch from "@/services/indexsearch"; | 30 | import { useUiStore } from '@/store/uiStore'; |
28 | 31 | import { computed, onUnmounted } from 'vue'; | |
29 | @Component | 32 | import { useI18n } from 'vue-i18n'; |
30 | export default class GalleryPicture extends Vue { | 33 | import GalleryTiles from './GalleryTiles.vue'; |
31 | @Prop(String) readonly path!: string; | 34 | |
32 | 35 | const { t } = useI18n(); | |
33 | otherCount: Number = 0; | 36 | const uiStore = useUiStore(); |
34 | 37 | const galleryStore = useGalleryStore(); | |
35 | mounted() { | 38 | const indexSearch = useIndexSearch(); |
36 | this.$uiStore.toggleFullscreen(false); | 39 | |
37 | this.$uiStore.toggleSearchMode(true); | 40 | uiStore.toggleFullscreen(false); |
38 | } | 41 | uiStore.searchMode = true; |
39 | 42 | onUnmounted(() => { | |
40 | destroyed() { | 43 | uiStore.searchMode = false; |
41 | this.$uiStore.toggleSearchMode(false); | 44 | galleryStore.currentSearch = []; |
42 | this.$galleryStore.setCurrentSearch([]); | 45 | }); |
43 | } | 46 | |
44 | 47 | const items = computed(() => { | |
45 | items() { | 48 | const { currentPath, currentSearch } = galleryStore; |
46 | const searchResult = IndexSearch.search(this.$galleryStore.currentSearch); | 49 | if (!currentPath) return { searchResult: [], filteredByPath: [] }; |
47 | const filteredByPath = searchResult.filter(item => item.path.startsWith(this.path)); | 50 | const searchResult = indexSearch(currentSearch); |
48 | this.otherCount = searchResult.length - filteredByPath.length; | 51 | const filteredByPath = searchResult.filter(item => item.path.startsWith(currentPath)); |
49 | return filteredByPath; | 52 | return { searchResult, filteredByPath }; |
50 | } | 53 | }); |
51 | 54 | const otherCount = computed(() => items.value.searchResult.length - items.value.filteredByPath.length); | |
52 | noResult() { | 55 | const noResult = computed(() => t('search.no-result-fmt', [otherCount.value])); |
53 | const params = [this.otherCount, this.otherCount > 1 ? "s" : ""]; | ||
54 | return this.$t("search.no-results.otherfolders", params); | ||
55 | } | ||
56 | } | ||
57 | </script> | 56 | </script> |
58 | |||
59 | <style lang="scss"> | ||
60 | </style> |