aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--viewer/ldgallery-viewer.7.md47
-rw-r--r--viewer/src/@types/gallery.d.ts2
-rw-r--r--viewer/src/@types/splashscreen.d.ts25
-rw-r--r--viewer/src/locales/en.json2
-rw-r--r--viewer/src/store/uiStore.ts29
-rw-r--r--viewer/src/views/MainLayout.vue46
-rw-r--r--viewer/src/views/SplashScreen.vue72
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
96without the ".json" extension, as a query parameter given before the page anchor; 96without the ".json" extension, as a query parameter given before the page anchor;
97for example, some alternative configuration named "config_2.json" can be loaded with "http://gallery/?config_2#". 97for example, some alternative configuration named "config_2.json" can be loaded with "http://gallery/?config_2#".
98 98
99splashScreen
100: Displays an information notice before opening the gallery (see below).
101
102
103# SPLASH SCREEN CONFIGURATION
104
105splashScreen.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
110splashScreen.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
114splashScreen.buttonAcknowledgeLabel
115: Optional label for the acknowledge button shown below the notice.
116 *Defaults to "Acknowledge"*
117
118splashScreen.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
126Viewer __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
20import { ItemType } from "./ItemType"; 20import { ItemType } from "./ItemType";
21import { SplashScreenConfig } from "./splashscreen";
21 22
22export type ItemSortStr = "title_asc" | "date_asc" | "date_desc"; 23export 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
31export interface Properties { 33export 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
20export 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
20import { Config } from "@/@types/gallery"; 20import { Config } from "@/@types/gallery";
21import { SplashScreenConfig } from "@/@types/splashscreen";
21import ItemComparators, { ItemSort } from "@/services/itemComparators"; 22import ItemComparators, { ItemSort } from "@/services/itemComparators";
22import { action, createModule, mutation } from "vuex-class-component"; 23import { 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
30const STORAGE_SPLASHSCREEN_VALIDATION = "splashScreenValidation";
31
29export default class UIStore extends VuexModule { 32export 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";
40import { Route } from "vue-router"; 39import { Route } from "vue-router";
41import PanelLeft from "./PanelLeft.vue";<