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 /viewer/src/views | |
parent | ac160f6879f9a2c74ca77c1c34742d24e69bf570 (diff) | |
download | ldgallery-928c501dda0c3580e3cb0389efc16fc1dde16b68.tar.gz |
viewer: optional user-defined markdown splash screen
GitHub: closes #284
Diffstat (limited to 'viewer/src/views')
-rw-r--r-- | viewer/src/views/MainLayout.vue | 46 | ||||
-rw-r--r-- | viewer/src/views/SplashScreen.vue | 72 |
2 files changed, 100 insertions, 18 deletions
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"; | |||
40 | import { Route } from "vue-router"; | 39 | import { Route } from "vue-router"; |
41 | import PanelLeft from "./PanelLeft.vue"; | 40 | import PanelLeft from "./PanelLeft.vue"; |
42 | import PanelTop from "./PanelTop.vue"; | 41 | import PanelTop from "./PanelTop.vue"; |
42 | import SplashScreen from "./SplashScreen.vue"; | ||
43 | 43 | ||
44 | @Component({ | 44 | @Component({ |
45 | components: { PanelLeft, PanelTop }, | 45 | components: { |
46 | PanelLeft, | ||
47 | PanelTop, | ||
48 | SplashScreen, | ||
49 | }, | ||
46 | }) | 50 | }) |
47 | export default class MainLayout extends Vue { | 51 | export default class MainLayout extends Vue { |
48 | @Ref() readonly content!: Vue; | 52 | @Ref() readonly content?: Vue; |
49 | 53 | ||
50 | isLoading: boolean = true; | 54 | isLoading: boolean = true; |
51 | scrollPositions: ScrollPosition = {}; | 55 | scrollPositions: ScrollPosition = {}; |
52 | 56 | ||
53 | get contentDiv() { | 57 | get contentDiv(): HTMLDivElement | null { |
54 | return this.content.$el as HTMLDivElement; | 58 | return (this.content?.$el as HTMLDivElement) ?? null; |
59 | } | ||
60 | |||
61 | get isReady(): boolean { | ||
62 | return ( | ||
63 | !this.$uiStore.splashScreenEnabled && | ||
64 | !this.isLoading && | ||
65 | this.$galleryStore.config !== null && | ||
66 | this.$galleryStore.currentPath !== null | ||
67 | ); | ||
55 | } | 68 | } |
56 | 69 | ||
57 | mounted() { | 70 | mounted() { |
@@ -65,13 +78,14 @@ export default class MainLayout extends Vue { | |||
65 | } | 78 | } |
66 | 79 | ||
67 | moveFocusToContentDiv() { | 80 | moveFocusToContentDiv() { |
68 | setTimeout(() => this.contentDiv.focus()); | 81 | setTimeout(() => this.contentDiv?.focus()); |
69 | } | 82 | } |
70 | 83 | ||
71 | @Watch("$route") | 84 | @Watch("$route") |
72 | routeChanged(newRoute: Route, oldRoute: Route) { | 85 | routeChanged(newRoute: Route, oldRoute: Route) { |
86 | if (!this.contentDiv) return; | ||
73 | this.scrollPositions[oldRoute.path] = this.contentDiv.scrollTop; | 87 | this.scrollPositions[oldRoute.path] = this.contentDiv.scrollTop; |
74 | this.$nextTick(() => (this.contentDiv.scrollTop = this.scrollPositions[newRoute.path])); | 88 | this.$nextTick(() => (this.contentDiv!.scrollTop = this.scrollPositions[newRoute.path])); |
75 | this.moveFocusToContentDiv(); | 89 | this.moveFocusToContentDiv(); |
76 | } | 90 | } |
77 | 91 | ||
@@ -86,14 +100,10 @@ export default class MainLayout extends Vue { | |||
86 | .catch(this.displayError); | 100 | .catch(this.displayError); |
87 | } | 101 | } |
88 | 102 | ||
89 | get isReady() { | ||
90 | return !this.isLoading && this.$galleryStore.config && this.$galleryStore.currentPath !== null; | ||
91 | } | ||
92 | |||
93 | displayError(reason: any) { | 103 | displayError(reason: any) { |
94 | this.$buefy.snackbar.open({ | 104 | this.$buefy.snackbar.open({ |
95 | message: `${reason}`, | 105 | message: `${reason}`, |
96 | actionText: "Retry", | 106 | actionText: this.$t("snack.retry"), |
97 | position: "is-top", | 107 | position: "is-top", |
98 | type: "is-danger", | 108 | type: "is-danger", |
99 | indefinite: true, | 109 | indefinite: true, |
diff --git a/viewer/src/views/SplashScreen.vue b/viewer/src/views/SplashScreen.vue new file mode 100644 index 0000000..808567e --- /dev/null +++ b/viewer/src/views/SplashScreen.vue | |||
@@ -0,0 +1,72 @@ | |||
1 | <template> | ||
2 | <b-loading v-if="isLoading" active /> | ||
3 | <div v-else-if="markdown" :class="$style.splashscreen" class="scrollbar"> | ||
4 | <Markdown :style="config.style" class="flex-grow-1" :markdown="markdown" /> | ||
5 | <b-button size="is-large" :label="buttonAcknowledgeLabel" :class="$style.buttonAcknowledge" @click="validation" /> | ||
6 | </div> | ||
7 | </template> | ||
8 | |||
9 | <script lang="ts"> | ||
10 | import { SplashScreenConfig } from "@/@types/splashscreen"; | ||
11 | import { Markdown } from "@/components/async"; | ||
12 | import FetchWithCheck from "@/services/fetchWithCheck"; | ||
13 | import { TranslateResult } from "vue-i18n"; | ||
14 | import { Component, Emit, Vue } from "vue-property-decorator"; | ||
15 | |||
16 | @Component({ | ||
17 | components: { | ||
18 | Markdown, | ||
19 | }, | ||
20 | }) | ||
21 | export default class SplashScreen extends Vue { | ||
22 | isLoading: boolean = true; | ||
23 | markdown: string | null = null; | ||
24 | |||
25 | get config(): SplashScreenConfig { | ||
26 | return this.$uiStore.splashScreenConfig!; | ||
27 | } | ||
28 | |||
29 | created() { | ||
30 | this.fetchMarkdown(); | ||
31 | } | ||
32 | |||
33 | fetchMarkdown() { | ||
34 | FetchWithCheck.get(`${process.env.VUE_APP_DATA_URL}${this.config.resource}?${this.config.dontshowagainUID ?? ""}`) | ||
35 | .then(response => response.text()) | ||
36 | .then(text => (this.markdown = text)) | ||
37 | .finally(() => (this.isLoading = false)) | ||
38 | .catch(this.displayError); | ||
39 | } | ||
40 | |||
41 | displayError(reason: any) { | ||
42 | this.$buefy.snackbar.open({ | ||
43 | message: `${reason}`, | ||
44 | actionText: this.$t("snack.retry"), | ||
45 | position: "is-top", | ||
46 | type: "is-danger", | ||
47 | indefinite: true, | ||
48 | onAction: this.fetchMarkdown, | ||
49 | }); | ||
50 | } | ||
51 | |||
52 | get buttonAcknowledgeLabel(): TranslateResult { | ||
53 | return this.config.buttonAcknowledgeLabel ?? this.$t("splashScreen.button.acknowledge"); | ||
54 | } | ||
55 | |||
56 | @Emit() | ||
57 | validation() {} | ||
58 | } | ||
59 | </script> | ||
60 | |||
61 | <style lang="scss" module> | ||
62 | .splashscreen { | ||
63 | display: flex; | ||
64 | flex-flow: column; | ||
65 | align-items: center; | ||
66 | padding: 32px; | ||
67 | } | ||
68 | .buttonAcknowledge { | ||
69 | min-width: 310px; | ||
70 | align-self: center; | ||
71 | } | ||
72 | </style> | ||