aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/views/MainLayout.vue
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/views/MainLayout.vue')
-rw-r--r--viewer/src/views/MainLayout.vue93
1 files changed, 63 insertions, 30 deletions
diff --git a/viewer/src/views/MainLayout.vue b/viewer/src/views/MainLayout.vue
index 6ef9a3b..2347ba7 100644
--- a/viewer/src/views/MainLayout.vue
+++ b/viewer/src/views/MainLayout.vue
@@ -18,31 +18,55 @@
18--> 18-->
19 19
20<template> 20<template>
21 <div :class="{ fullscreen: $uiStore.fullscreen, fullwidth: $uiStore.fullWidth }"> 21 <div :class="{ [$style.fullscreen]: $uiStore.fullscreen, [$style.fullwidth]: $uiStore.fullWidth }">
22 <ld-title :gallery-title="$galleryStore.galleryTitle" :current-item="$galleryStore.currentItem" /> 22 <ld-title :gallery-title="$galleryStore.galleryTitle" :current-item="$galleryStore.currentItem" />
23 <panel-top v-if="isReady" class="layout layout-top" /> 23 <PanelTop v-if="isReady" :class="[$style.layout, $style.layoutTop]" />
24 <panel-left v-if="isReady" class="layout layout-left" /> 24 <PanelLeft v-if="isReady" :class="[$style.layout, $style.layoutLeft]" />
25 <router-view v-if="!isLoading" ref="content" class="layout layout-content scrollbar" /> 25 <b-loading v-if="isLoading" active />
26 <b-loading :active="isLoading" is-full-page /> 26 <SplashScreen
27 v-else-if="$uiStore.splashScreenEnabled"
28 :class="$style.layout"
29 @validation="$uiStore.validateSpashScreen()"
30 />
31 <router-view v-else ref="content" :class="[$style.layout, $style.layoutContent]" class="scrollbar" tabindex="01" />
27 <ld-key-press :keycode="27" @action="$uiStore.toggleFullscreen(false)" /> 32 <ld-key-press :keycode="27" @action="$uiStore.toggleFullscreen(false)" />
28 </div> 33 </div>
29</template> 34</template>
30 35
31<script lang="ts"> 36<script lang="ts">
32import { Component, Vue, Ref, Watch } from "vue-property-decorator"; 37import { ScrollPosition } from "@/@types/scrollposition";
38import { Component, Ref, Vue, Watch } from "vue-property-decorator";
39import { Route } from "vue-router";
33import PanelLeft from "./PanelLeft.vue"; 40import PanelLeft from "./PanelLeft.vue";
34import PanelTop from "./PanelTop.vue"; 41import PanelTop from "./PanelTop.vue";
35import { Route } from "vue-router"; 42import SplashScreen from "./SplashScreen.vue";
36 43
37@Component({ 44@Component({
38 components: { PanelLeft, PanelTop }, 45 components: {
46 PanelLeft,
47 PanelTop,
48 SplashScreen,
49 },
39}) 50})
40export default class MainLayout extends Vue { 51export default class MainLayout extends Vue {
41 @Ref() readonly content!: Vue; 52 @Ref() readonly content?: Vue;
42 53
43 isLoading: boolean = true; 54 isLoading: boolean = true;
44 scrollPositions: ScrollPosition = {}; 55 scrollPositions: ScrollPosition = {};
45 56
57 get contentDiv(): HTMLDivElement | null {
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 );
68 }
69
46 mounted() { 70 mounted() {
47 history.replaceState({ ldgallery: "ENTRYPOINT" }, ""); 71 history.replaceState({ ldgallery: "ENTRYPOINT" }, "");
48 this.fetchGalleryItems(); 72 this.fetchGalleryItems();
@@ -53,11 +77,16 @@ export default class MainLayout extends Vue {
53 document.body.removeEventListener("fullscreenchange", this.onFullscreenChange); 77 document.body.removeEventListener("fullscreenchange", this.onFullscreenChange);
54 } 78 }
55 79
80 moveFocusToContentDiv() {
81 setTimeout(() => this.contentDiv?.focus());
82 }
83
56 @Watch("$route") 84 @Watch("$route")
57 routeChanged(newRoute: Route, oldRoute: Route) { 85 routeChanged(newRoute: Route, oldRoute: Route) {
58 const el = this.content.$el; 86 if (!this.contentDiv) return;
59 this.scrollPositions[oldRoute.path] = el.scrollTop; 87 this.scrollPositions[oldRoute.path] = this.contentDiv.scrollTop;
60 this.$nextTick(() => (el.scrollTop = this.scrollPositions[newRoute.path])); 88 this.$nextTick(() => (this.contentDiv!.scrollTop = this.scrollPositions[newRoute.path]));
89 this.moveFocusToContentDiv();
61 } 90 }
62 91
63 fetchGalleryItems() { 92 fetchGalleryItems() {
@@ -66,18 +95,15 @@ export default class MainLayout extends Vue {
66 .fetchConfig() 95 .fetchConfig()
67 .then(this.$uiStore.initFromConfig) 96 .then(this.$uiStore.initFromConfig)
68 .then(this.$galleryStore.fetchGalleryItems) 97 .then(this.$galleryStore.fetchGalleryItems)
98 .then(this.moveFocusToContentDiv)
69 .finally(() => (this.isLoading = false)) 99 .finally(() => (this.isLoading = false))
70 .catch(this.displayError); 100 .catch(this.displayError);
71 } 101 }
72 102
73 get isReady() {
74 return !this.isLoading && this.$galleryStore.config && this.$galleryStore.currentPath !== null;
75 }
76
77 displayError(reason: any) { 103 displayError(reason: any) {
78 this.$buefy.snackbar.open({ 104 this.$buefy.snackbar.open({
79 message: `${reason}`, 105 message: `${reason}`,
80 actionText: "Retry", 106 actionText: this.$t("snack.retry"),
81 position: "is-top", 107 position: "is-top",
82 type: "is-danger", 108 type: "is-danger",
83 indefinite: true, 109 indefinite: true,
@@ -85,23 +111,28 @@ export default class MainLayout extends Vue {
85 }); 111 });
86 } 112 }
87 113
114 isFullscreenActive(): boolean {
115 return Boolean(document.fullscreenElement);
116 }
117
88 @Watch("$uiStore.fullscreen") 118 @Watch("$uiStore.fullscreen")
89 applyFullscreen(fullscreen: boolean) { 119 applyFullscreen(fullscreen: boolean) {
90 if (fullscreen && !document.fullscreen) document.body.requestFullscreen(); 120 const isFullscreenActive = this.isFullscreenActive();
91 else if (document.fullscreen) document.exitFullscreen(); 121 if (fullscreen && !isFullscreenActive) document.body.requestFullscreen();
122 else if (isFullscreenActive) document.exitFullscreen();
92 } 123 }
93 124
94 onFullscreenChange() { 125 onFullscreenChange() {
95 this.$uiStore.toggleFullscreen(document.fullscreen); 126 this.$uiStore.toggleFullscreen(this.isFullscreenActive());
96 } 127 }
97} 128}
98</script> 129</script>
99 130
100<style lang="scss"> 131<style lang="scss" module>
101@import "~@/assets/scss/theme.scss"; 132@import "~@/assets/scss/theme.scss";
102 133
103body, 134:global(body),
104html { 135:global(html) {
105 height: 100%; 136 height: 100%;
106 overflow: hidden; 137 overflow: hidden;
107 touch-action: none; 138 touch-action: none;
@@ -116,20 +147,23 @@ html {
116 bottom: 0; 147 bottom: 0;
117 left: 0; 148 left: 0;
118 right: 0; 149 right: 0;
119 &.layout-top { 150 &.layoutTop {
120 height: $layout-top; 151 height: $layout-top;
121 z-index: 1; 152 z-index: 1;
122 } 153 }
123 &.layout-left { 154 &.layoutLeft {
124 top: $layout-top; 155 top: $layout-top;
125 width: $layout-left; 156 width: $layout-left;
126 z-index: 2; 157 z-index: 2;
127 } 158 }
128 &.layout-content { 159 &.layoutContent {
129 top: var(--layout-top); 160 top: var(--layout-top);
130 left: var(--layout-left); 161 left: var(--layout-left);
131 z-index: 3; 162 z-index: 3;
132 overflow-x: hidden; 163 overflow-x: hidden;
164 &:focus {
165 outline: none;
166 }
133 } 167 }
134} 168}
135.fullscreen { 169.fullscreen {
@@ -146,17 +180,16 @@ html {
146} 180}
147 181
148.layout { 182.layout {
149 &.layout-top { 183 &.layoutTop {
150 background-color: $panel-top-bgcolor; 184 background-color: $panel-top-bgcolor;
151 color: $panel-top-txtcolor; 185 color: $panel-top-txtcolor;
152 } 186 }
153 &.layout-left { 187 &.layoutLeft {
154 background-color: $panel-left-bgcolor; 188 background-color: $panel-left-bgcolor;
155 color: $panel-left-txtcolor; 189 color: $panel-left-txtcolor;
156 } 190 }
157 &.layout-content { 191 &.layoutContent {
158 background-color: $content-bgcolor; 192 background-color: $content-bgcolor;
159 } 193 }
160} 194}
161// =====
162</style> 195</style>