diff options
Diffstat (limited to 'viewer/src/services/navigation.ts')
-rw-r--r-- | viewer/src/services/navigation.ts | 97 |
1 files changed, 58 insertions, 39 deletions
diff --git a/viewer/src/services/navigation.ts b/viewer/src/services/navigation.ts index fa17990..fb01169 100644 --- a/viewer/src/services/navigation.ts +++ b/viewer/src/services/navigation.ts | |||
@@ -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 |
@@ -17,14 +17,43 @@ | |||
17 | -- along with this program. If not, see <https://www.gnu.org/licenses/>. | 17 | -- along with this program. If not, see <https://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | export default class Navigation { | 20 | import { DirectoryItem, DownloadableItem, Item } from '@/@types/gallery'; |
21 | import { ItemType } from '@/@types/itemType'; | ||
22 | import { | ||
23 | faFile, | ||
24 | faFileAlt, | ||
25 | faFileAudio, | ||
26 | faFilePdf, | ||
27 | faBook, | ||
28 | faFileVideo, | ||
29 | faFolder, | ||
30 | faHome, | ||
31 | faImage, | ||
32 | IconDefinition, | ||
33 | } from '@fortawesome/free-solid-svg-icons'; | ||
34 | import { isDirectory } from './itemGuards'; | ||
21 | 35 | ||
36 | const ICON_BY_TYPE: Record<ItemType, IconDefinition> = { | ||
37 | directory: faFolder, | ||
38 | picture: faImage, | ||
39 | plaintext: faFileAlt, | ||
40 | markdown: faFileAlt, | ||
41 | pdf: faFilePdf, | ||
42 | epub: faBook, | ||
43 | video: faFileVideo, | ||
44 | audio: faFileAudio, | ||
45 | other: faFile, | ||
46 | }; | ||
47 | |||
48 | // --- | ||
49 | |||
50 | export const useNavigation = () => { | ||
22 | // Searches for an item by path from a root item (navigation) | 51 | // Searches for an item by path from a root item (navigation) |
23 | public static searchCurrentItemPath(root: Gallery.Item, path: string): Gallery.Item[] { | 52 | function searchCurrentItemPath(root: Item, path: string): Item[] { |
24 | if (path === root.path) return [root]; | 53 | if (path === root.path) return [root]; |
25 | if (root.properties.type === "directory" && path.startsWith(root.path)) { | 54 | if (isDirectory(root) && path.startsWith(root.path)) { |
26 | const itemChain = root.properties.items | 55 | const itemChain = root.properties.items |
27 | .map(item => this.searchCurrentItemPath(item, path)) | 56 | .map(item => searchCurrentItemPath(item, path)) |
28 | .find(itemChain => itemChain.length > 0); | 57 | .find(itemChain => itemChain.length > 0); |
29 | if (itemChain) return [root, ...itemChain]; | 58 | if (itemChain) return [root, ...itemChain]; |
30 | } | 59 | } |
@@ -32,49 +61,39 @@ export default class Navigation { | |||
32 | } | 61 | } |
33 | 62 | ||
34 | // Normalize a string to lowercase, no-accents | 63 | // Normalize a string to lowercase, no-accents |
35 | public static normalize(value: string) { | 64 | function normalize(value: string) { |
36 | return value | 65 | return value |
37 | .normalize("NFD") | 66 | .normalize('NFD') |
38 | .replace(/[\u0300-\u036f]/g, "") | 67 | .replace(/[\u0300-\u036f]/g, '') |
39 | .toLowerCase(); | 68 | .toLowerCase(); |
40 | } | 69 | } |
41 | 70 | ||
42 | // Checks if the type of an item matches | 71 | function getLastDirectory(itemPath: Item[]): DirectoryItem { |
43 | public static checkType(item: Gallery.Item | null, type: Gallery.ItemType): boolean { | ||
44 | return item?.properties.type === type ?? false; | ||
45 | } | ||
46 | |||
47 | public static getLastDirectory(itemPath: Gallery.Item[]): Gallery.Directory { | ||
48 | for (let idx = itemPath.length - 1; idx >= 0; idx--) { | 72 | for (let idx = itemPath.length - 1; idx >= 0; idx--) { |
49 | const item = itemPath[idx]; | 73 | const item = itemPath[idx]; |
50 | if (Navigation.checkType(item, "directory")) return item as Gallery.Directory; | 74 | if (isDirectory(item)) return item; |
51 | } | 75 | } |
52 | throw new Error("No directory found"); | 76 | throw new Error('No directory found'); |
53 | } | 77 | } |
54 | 78 | ||
55 | // Sort a list of items, moving the directories to the beginning of the list | 79 | // Get the icon for an item |
56 | public static directoriesFirst(items: Gallery.Item[]) { | 80 | function getIcon(item: Item): IconDefinition { |
57 | return [ | 81 | if (item.path.length <= 1) return faHome; |
58 | ...items | 82 | return ICON_BY_TYPE[item.properties.type]; |
59 | .filter(child => Navigation.checkType(child, "directory")) | ||
60 | .sort((a, b) => a.title.localeCompare(b.title)), | ||
61 | |||
62 | ...items | ||
63 | .filter(child => !Navigation.checkType(child, "directory")), | ||
64 | ]; | ||
65 | } | 83 | } |
66 | 84 | ||
67 | // Get the icon for an item | 85 | // Get the file name of an item, without its cache timestamp |
68 | public static getIcon(item: Gallery.Item): string { | 86 | function getFileName(item: Item): string { |
69 | if (item.path.length <= 1) return "home"; | 87 | if (isDirectory(item)) return item.title; |
70 | switch (item.properties.type) { | 88 | const timeStamped = (item as DownloadableItem).properties.resource.split('/').pop() ?? ''; |
71 | case "picture": | 89 | return timeStamped.split('?')[0]; |
72 | return "image"; | ||
73 | case "directory": | ||
74 | return "folder"; | ||
75 | case "other": | ||
76 | default: | ||
77 | return "file"; | ||
78 | } | ||
79 | } | 90 | } |
80 | } | 91 | |
92 | return { | ||
93 | searchCurrentItemPath, | ||
94 | normalize, | ||
95 | getLastDirectory, | ||
96 | getIcon, | ||
97 | getFileName, | ||
98 | }; | ||
99 | }; | ||