diff options
author | Zero~Informatique | 2021-07-03 05:06:44 +0200 |
---|---|---|
committer | pacien | 2021-07-04 17:40:01 +0200 |
commit | 928c501dda0c3580e3cb0389efc16fc1dde16b68 (patch) | |
tree | 6425d3d394408bedd35fb663826bf20e3bf615ea | |
parent | ac160f6879f9a2c74ca77c1c34742d24e69bf570 (diff) | |
download | ldgallery-928c501dda0c3580e3cb0389efc16fc1dde16b68.tar.gz |
viewer: optional user-defined markdown splash screen
GitHub: closes #284
-rw-r--r-- | viewer/ldgallery-viewer.7.md | 47 | ||||
-rw-r--r-- | viewer/src/@types/gallery.d.ts | 2 | ||||
-rw-r--r-- | viewer/src/@types/splashscreen.d.ts | 25 | ||||
-rw-r--r-- | viewer/src/locales/en.json | 2 | ||||
-rw-r--r-- | viewer/src/store/uiStore.ts | 29 | ||||
-rw-r--r-- | viewer/src/views/MainLayout.vue | 46 | ||||
-rw-r--r-- | viewer/src/views/SplashScreen.vue | 72 |
7 files changed, 205 insertions, 18 deletions
diff --git a/viewer/ldgallery-viewer.7.md b/viewer/ldgallery-viewer.7.md index 96070dc..5012e3b 100644 --- a/viewer/ldgallery-viewer.7.md +++ b/viewer/ldgallery-viewer.7.md | |||
@@ -96,6 +96,53 @@ An alternative viewer configuration file located in the viewer's directory can b | |||
96 | without the ".json" extension, as a query parameter given before the page anchor; | 96 | without the ".json" extension, as a query parameter given before the page anchor; |
97 | for example, some alternative configuration named "config_2.json" can be loaded with "http://gallery/?config_2#". | 97 | for example, some alternative configuration named "config_2.json" can be loaded with "http://gallery/?config_2#". |
98 | 98 | ||
99 | splashScreen | ||
100 | : Displays an information notice before opening the gallery (see below). | ||
101 | |||
102 | |||
103 | # SPLASH SCREEN CONFIGURATION | ||
104 | |||
105 | splashScreen.resource | ||
106 | : Absolute or relative path to the information notice. The user is prompted to explicitly acknowledge such notice before being allowed to browse the gallery. | ||
107 | Rich text formatting is possible through the use of the [GitHub Flavoured Markdown syntax][GFM]. | ||
108 | Inline HTML and CSS are also supported. | ||
109 | |||
110 | splashScreen.dontshowagainUID | ||
111 | : Optional unique ID; when set, the information notice will appear only the first time it is proposed to the user. To display the notice again, change this UID. | ||
112 | When left empty, the notice will appear every time. | ||
113 | |||
114 | splashScreen.buttonAcknowledgeLabel | ||
115 | : Optional label for the acknowledge button shown below the notice. | ||
116 | *Defaults to "Acknowledge"* | ||
117 | |||
118 | splashScreen.style | ||
119 | : Optional CSS attributes for the information notice's container. | ||
120 | String or JSON formats are supported. | ||
121 | |||
122 | [GFM]: https://github.github.com/gfm/ | ||
123 | |||
124 | # CONFIGURATION EXAMPLE | ||
125 | |||
126 | Viewer __config.json__: | ||
127 | |||
128 | ```json | ||
129 | { | ||
130 | "galleryRoot": "./gallery/", | ||
131 | "galleryIndex": "index.json", | ||
132 | "initialItemSort": "date_desc", | ||
133 | "initialTagDisplayLimit": 10, | ||
134 | "splashScreen": { | ||
135 | "resource": "./splashscreen.md", | ||
136 | "dontshowagainUID": "v001", | ||
137 | "buttonAcknowledgeLabel": "I agree", | ||
138 | "style": { | ||
139 | "max-width": "45em", | ||
140 | "font-size": "20px", | ||
141 | "padding-top": "20vh" | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | ``` | ||
99 | 146 | ||
100 | # PROGRESSIVE WEB APPLICATION | 147 | # PROGRESSIVE WEB APPLICATION |
101 | 148 | ||
diff --git a/viewer/src/@types/gallery.d.ts b/viewer/src/@types/gallery.d.ts index d9e7534..9011f19 100644 --- a/viewer/src/@types/gallery.d.ts +++ b/viewer/src/@types/gallery.d.ts | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | import { ItemType } from "./ItemType"; | 20 | import { ItemType } from "./ItemType"; |
21 | import { SplashScreenConfig } from "./splashscreen"; | ||
21 | 22 | ||
22 | export type ItemSortStr = "title_asc" | "date_asc" | "date_desc"; | 23 | export type ItemSortStr = "title_asc" | "date_asc" | "date_desc"; |
23 | 24 | ||
@@ -26,6 +27,7 @@ export interface Config { | |||
26 | galleryIndex?: string; | 27 | galleryIndex?: string; |
27 | initialItemSort?: ItemSortStr; | 28 | initialItemSort?: ItemSortStr; |
28 | initialTagDisplayLimit?: number; | 29 | initialTagDisplayLimit?: number; |
30 | splashScreen?: SplashScreenConfig; | ||
29 | } | 31 | } |
30 | 32 | ||
31 | export interface Properties { | 33 | export interface Properties { |
diff --git a/viewer/src/@types/splashscreen.d.ts b/viewer/src/@types/splashscreen.d.ts new file mode 100644 index 0000000..bd79f80 --- /dev/null +++ b/viewer/src/@types/splashscreen.d.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | /* ldgallery - A static generator which turns a collection of tagged | ||
2 | -- pictures into a searchable web gallery. | ||
3 | -- | ||
4 | -- Copyright (C) 2019-2021 Guillaume FOUET | ||
5 | -- | ||
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 | ||
8 | -- published by the Free Software Foundation, either version 3 of the | ||
9 | -- License, or (at your option) any later version. | ||
10 | -- | ||
11 | -- This program is distributed in the hope that it will be useful, | ||
12 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | -- GNU Affero General Public License for more details. | ||
15 | -- | ||
16 | -- You should have received a copy of the GNU Affero General Public License | ||
17 | -- along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | export interface SplashScreenConfig { | ||
21 | resource?: string; | ||
22 | dontshowagainUID?: string; | ||
23 | buttonAcknowledgeLabel?: string; | ||
24 | style?: any; | ||
25 | } | ||
diff --git a/viewer/src/locales/en.json b/viewer/src/locales/en.json index b21262a..d0a7a26 100644 --- a/viewer/src/locales/en.json +++ b/viewer/src/locales/en.json | |||
@@ -14,6 +14,8 @@ | |||
14 | "panelLeft.propositions": "Related filters", | 14 | "panelLeft.propositions": "Related filters", |
15 | "panelLeft.propositions.other": "other filters", | 15 | "panelLeft.propositions.other": "other filters", |
16 | "search.no-result-fmt": "No result<br>({0} match in other folders) | No result<br>({0} matches in other folders)", | 16 | "search.no-result-fmt": "No result<br>({0} match in other folders) | No result<br>({0} matches in other folders)", |
17 | "snack.retry": "Retry", | ||
18 | "splashScreen.button.acknowledge": "Acknowledge", | ||
17 | "tag-propositions.addition": "Include all items with this tag", | 19 | "tag-propositions.addition": "Include all items with this tag", |
18 | "tag-propositions.intersection": "Search for this tag", | 20 | "tag-propositions.intersection": "Search for this tag", |
19 | "tag-propositions.item-count": "Item count", | 21 | "tag-propositions.item-count": "Item count", |
diff --git a/viewer/src/store/uiStore.ts b/viewer/src/store/uiStore.ts index f5bb898..2c45136 100644 --- a/viewer/src/store/uiStore.ts +++ b/viewer/src/store/uiStore.ts | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | import { Config } from "@/@types/gallery"; | 20 | import { Config } from "@/@types/gallery"; |
21 | import { SplashScreenConfig } from "@/@types/splashscreen"; | ||
21 | import ItemComparators, { ItemSort } from "@/services/itemComparators"; | 22 | import ItemComparators, { ItemSort } from "@/services/itemComparators"; |
22 | import { action, createModule, mutation } from "vuex-class-component"; | 23 | import { action, createModule, mutation } from "vuex-class-component"; |
23 | 24 | ||
@@ -26,12 +27,17 @@ const VuexModule = createModule({ | |||
26 | strict: true, | 27 | strict: true, |
27 | }); | 28 | }); |
28 | 29 | ||
30 | const STORAGE_SPLASHSCREEN_VALIDATION = "splashScreenValidation"; | ||
31 | |||
29 | export default class UIStore extends VuexModule { | 32 | export default class UIStore extends VuexModule { |
30 | fullscreen: boolean = false; | 33 | fullscreen: boolean = false; |
31 | fullWidth: boolean = window.innerWidth < Number(process.env.VUE_APP_FULLWIDTH_LIMIT); | 34 | fullWidth: boolean = window.innerWidth < Number(process.env.VUE_APP_FULLWIDTH_LIMIT); |
32 | searchMode: boolean = false; | 35 | searchMode: boolean = false; |
33 | sort: ItemSort = ItemComparators.DEFAULT; | 36 | sort: ItemSort = ItemComparators.DEFAULT; |
34 | 37 | ||
38 | splashScreenConfig: SplashScreenConfig | null = null; | ||
39 | splashScreenEnabled: boolean = false; | ||
40 | |||
35 | // --- | 41 | // --- |
36 | 42 | ||
37 | @mutation toggleFullscreen(value?: boolean) { | 43 | @mutation toggleFullscreen(value?: boolean) { |
@@ -50,11 +56,34 @@ export default class UIStore extends VuexModule { | |||
50 | this.sort = sort; | 56 | this.sort = sort; |
51 | } | 57 | } |
52 | 58 | ||
59 | @mutation setSplashScreenConfig(splashScreenConfig: SplashScreenConfig) { | ||
60 | this.splashScreenConfig = splashScreenConfig; | ||
61 | } | ||
62 | |||
63 | @mutation setSplashScreenEnabled(enabled: boolean) { | ||
64 | this.splashScreenEnabled = enabled; | ||
65 | } | ||
66 | |||
67 | // --- | ||
68 | |||
53 | @action async initFromConfig(config: Config) { | 69 | @action async initFromConfig(config: Config) { |
54 | if (config.initialItemSort) { | 70 | if (config.initialItemSort) { |
55 | const itemSort = ItemComparators.ITEM_SORTS[config.initialItemSort]; | 71 | const itemSort = ItemComparators.ITEM_SORTS[config.initialItemSort]; |
56 | if (itemSort) this.setSort(itemSort); | 72 | if (itemSort) this.setSort(itemSort); |
57 | else throw new Error("Unknown sort type: " + config.initialItemSort); | 73 | else throw new Error("Unknown sort type: " + config.initialItemSort); |
58 | } | 74 | } |
75 | if (config.splashScreen) { | ||
76 | this.setSplashScreenConfig(config.splashScreen); | ||
77 | const uid = config.splashScreen.dontshowagainUID; | ||
78 | this.setSplashScreenEnabled(!uid || localStorage.getItem(STORAGE_SPLASHSCREEN_VALIDATION) !== uid); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | // --- | ||
83 | |||
84 | @action async validateSpashScreen() { | ||
85 | this.setSplashScreenEnabled(false); | ||
86 | const uid = this.splashScreenConfig?.dontshowagainUID; | ||
87 | if (uid) localStorage.setItem(STORAGE_SPLASHSCREEN_VALIDATION, String(uid)); | ||
59 | } | 88 | } |
60 | } | 89 | } |
diff --git a/viewer/src/views/MainLayout.vue b/viewer/src/views/MainLayout.vue index c54f183..2347ba7 100644 --- a/viewer/src/views/MainLayout.vue +++ b/viewer/src/views/MainLayout.vue | |||
@@ -22,14 +22,13 @@ | |||
22 | <ld-title :gallery-title="$galleryStore.galleryTitle" :current-item="$galleryStore.currentItem" /> | 22 | <ld-title :gallery-title="$galleryStore.galleryTitle" :current-item="$galleryStore.currentItem" /> |
23 | <PanelTop v-if="isReady" :class="[$style.layout, $style.layoutTop]" /> | 23 | <PanelTop v-if="isReady" :class="[$style.layout, $style.layoutTop]" /> |
24 | <PanelLeft v-if="isReady" :class="[$style.layout, $style.layoutLeft]" /> | 24 | <PanelLeft v-if="isReady" :class="[$style.layout, $style.layoutLeft]" /> |
25 | <router-view | 25 | <b-loading v-if="isLoading" active /> |
26 | v-if="!isLoading" | 26 | <SplashScreen |
27 | ref="content" | 27 | v-else-if="$uiStore.splashScreenEnabled" |
28 | :class="[$style.layout, $style.layoutContent]" | 28 | :class="$style.layout" |
29 | class="scrollbar" | 29 | @validation="$uiStore.validateSpashScreen()" |
30 | tabindex="01" | ||
31 | /> | 30 | /> |
32 | <b-loading :active="isLoading" is-full-page /> | 31 | <router-view v-else ref="content" :class="[$style.layout, $style.layoutContent]" class="scrollbar" tabindex="01" /> |
33 | <ld-key-press :keycode="27" @action="$uiStore.toggleFullscreen(false)" /> | 32 | <ld-key-press :keycode="27" @action="$uiStore.toggleFullscreen(false)" /> |
34 | </div> | 33 | </div> |
35 | </template> | 34 | </template> |
@@ -40,18 +39,32 @@ import { Component, Ref, Vue, Watch } from "vue-property-decorator"; | |||