viewer: add sidebar

pull/175/head
Varun Patil 2022-11-05 19:04:48 -07:00 committed by Varun Patil
parent 464c0e819b
commit c2c4799696
3 changed files with 141 additions and 15 deletions

View File

@ -271,13 +271,13 @@ body {
} }
// Top bar is above everything else on mobile // Top bar is above everything else on mobile
#content-vue.has-top-bar { body.has-top-bar header {
@media (max-width: 1024px) { @media (max-width: 1024px) {
z-index: 3000; z-index: 0 !important;
} }
} }
#content-vue.has-viewer { body.has-viewer header {
z-index: 3000; z-index: 0 !important;
} }
// Patch viewer to remove the title and // Patch viewer to remove the title and

View File

@ -183,12 +183,11 @@ export default class SelectionManager extends Mixins(GlobalMixin, UserConfig) {
@Watch("show") @Watch("show")
onShowChange() { onShowChange() {
const elem = document.getElementById("content-vue");
const klass = "has-top-bar"; const klass = "has-top-bar";
if (this.show) { if (this.show) {
elem.classList.add(klass); document.body.classList.add(klass);
} else { } else {
elem.classList.remove(klass); document.body.classList.remove(klass);
} }
} }

View File

@ -1,8 +1,13 @@
<template> <template>
<div class="memories_viewer outer" v-if="show" :class="{ fullyOpened }"> <div
class="memories_viewer outer"
v-if="show"
:class="{ fullyOpened }"
:style="{ width: outerWidth }"
>
<div class="inner" ref="inner"> <div class="inner" ref="inner">
<div class="top-bar" v-if="photoswipe" :class="{ opened }"> <div class="top-bar" v-if="photoswipe" :class="{ opened }">
<NcActions :inline="3" container=".memories_viewer .pswp"> <NcActions :inline="4" container=".memories_viewer .pswp">
<NcActionButton <NcActionButton
:aria-label="t('memories', 'Delete')" :aria-label="t('memories', 'Delete')"
@click="deleteCurrent" @click="deleteCurrent"
@ -22,6 +27,16 @@
<StarOutlineIcon v-else :size="24" /> <StarOutlineIcon v-else :size="24" />
</template> </template>
</NcActionButton> </NcActionButton>
<NcActionButton
:aria-label="t('memories', 'Sidebar')"
@click="toggleSidebar"
:close-after-click="true"
>
{{ t("memories", "Sidebar") }}
<template #icon>
<InfoIcon :size="24" />
</template>
</NcActionButton>
<NcActionButton <NcActionButton
:aria-label="t('memories', 'Download')" :aria-label="t('memories', 'Download')"
@click="downloadCurrent" @click="downloadCurrent"
@ -45,6 +60,7 @@ import GlobalMixin from "../mixins/GlobalMixin";
import { IDay, IPhoto, IRow, IRowType } from "../types"; import { IDay, IPhoto, IRow, IRowType } from "../types";
import { NcActions, NcActionButton } from "@nextcloud/vue"; import { NcActions, NcActionButton } from "@nextcloud/vue";
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
import * as dav from "../services/DavRequests"; import * as dav from "../services/DavRequests";
import * as utils from "../services/Utils"; import * as utils from "../services/Utils";
@ -57,6 +73,7 @@ import DeleteIcon from "vue-material-design-icons/Delete.vue";
import StarIcon from "vue-material-design-icons/Star.vue"; import StarIcon from "vue-material-design-icons/Star.vue";
import StarOutlineIcon from "vue-material-design-icons/StarOutline.vue"; import StarOutlineIcon from "vue-material-design-icons/StarOutline.vue";
import DownloadIcon from "vue-material-design-icons/Download.vue"; import DownloadIcon from "vue-material-design-icons/Download.vue";
import InfoIcon from "vue-material-design-icons/InformationOutline.vue";
@Component({ @Component({
components: { components: {
@ -66,6 +83,7 @@ import DownloadIcon from "vue-material-design-icons/Download.vue";
StarIcon, StarIcon,
StarOutlineIcon, StarOutlineIcon,
DownloadIcon, DownloadIcon,
InfoIcon,
}, },
}) })
export default class Viewer extends Mixins(GlobalMixin) { export default class Viewer extends Mixins(GlobalMixin) {
@ -76,6 +94,9 @@ export default class Viewer extends Mixins(GlobalMixin) {
private show = false; private show = false;
private opened = false; private opened = false;
private fullyOpened = false; private fullyOpened = false;
private sidebarOpen = false;
private sidebarWidth = 400;
private outerWidth = "100vw";
/** Base dialog */ /** Base dialog */
private photoswipe: PhotoSwipe | null = null; private photoswipe: PhotoSwipe | null = null;
@ -87,6 +108,16 @@ export default class Viewer extends Mixins(GlobalMixin) {
private globalCount = 0; private globalCount = 0;
private globalAnchor = -1; private globalAnchor = -1;
mounted() {
subscribe("files:sidebar:opened", this.handleAppSidebarOpen);
subscribe("files:sidebar:closed", this.handleAppSidebarClose);
}
beforeDestroy() {
unsubscribe("files:sidebar:opened", this.handleAppSidebarOpen);
unsubscribe("files:sidebar:closed", this.handleAppSidebarClose);
}
/** Get the currently open photo */ /** Get the currently open photo */
private getCurrentPhoto() { private getCurrentPhoto() {
if (!this.list.length || !this.photoswipe) { if (!this.list.length || !this.photoswipe) {
@ -110,9 +141,41 @@ export default class Viewer extends Mixins(GlobalMixin) {
loop: false, loop: false,
bgOpacity: 1, bgOpacity: 1,
appendToEl: this.$refs.inner as HTMLElement, appendToEl: this.$refs.inner as HTMLElement,
getViewportSizeFn: () => {
const sidebarWidth = this.sidebarOpen ? this.sidebarWidth : 0;
this.outerWidth = `calc(100vw - ${sidebarWidth}px)`;
return {
x: window.innerWidth - sidebarWidth,
y: window.innerHeight,
};
},
...args, ...args,
}); });
// Debugging only
globalThis.photoswipe = this.photoswipe;
// Monkey patch for focus trapping in sidebar
const _onFocusIn = this.photoswipe.keyboard._onFocusIn;
this.photoswipe.keyboard._onFocusIn = (e: FocusEvent) => {
if (e.target instanceof HTMLElement) {
if (
e.target.closest("aside.app-sidebar") ||
e.target.closest(".v-popper__popper")
) {
return;
}
}
_onFocusIn.call(this.photoswipe.keyboard, e);
};
// Refresh sidebar on change
this.photoswipe.on("change", () => {
if (this.sidebarOpen) {
this.openSidebar();
}
});
// Make sure buttons are styled properly // Make sure buttons are styled properly
this.photoswipe.addFilter("uiElement", (element, data) => { this.photoswipe.addFilter("uiElement", (element, data) => {
// add button-vue class if button // add button-vue class if button
@ -128,16 +191,18 @@ export default class Viewer extends Mixins(GlobalMixin) {
}); });
// Put viewer over everything else // Put viewer over everything else
const contentElem = document.getElementById("content-vue");
const navElem = document.getElementById("app-navigation-vue"); const navElem = document.getElementById("app-navigation-vue");
const klass = "has-viewer"; const klass = "has-viewer";
this.photoswipe.on("beforeOpen", () => { this.photoswipe.on("beforeOpen", () => {
contentElem.classList.add(klass); document.body.classList.add(klass);
navElem.style.zIndex = "0"; navElem.style.zIndex = "0";
}); });
this.photoswipe.on("openingAnimationStart", () => { this.photoswipe.on("openingAnimationStart", () => {
this.fullyOpened = false; this.fullyOpened = false;
this.opened = true; this.opened = true;
if (this.sidebarOpen) {
this.openSidebar();
}
}); });
this.photoswipe.on("openingAnimationEnd", () => { this.photoswipe.on("openingAnimationEnd", () => {
this.fullyOpened = true; this.fullyOpened = true;
@ -145,9 +210,10 @@ export default class Viewer extends Mixins(GlobalMixin) {
this.photoswipe.on("close", () => { this.photoswipe.on("close", () => {
this.fullyOpened = false; this.fullyOpened = false;
this.opened = false; this.opened = false;
this.hideSidebar();
}); });
this.photoswipe.on("destroy", () => { this.photoswipe.on("destroy", () => {
contentElem.classList.remove(klass); document.body.classList.remove(klass);
navElem.style.zIndex = ""; navElem.style.zIndex = "";
// reset everything // reset everything
@ -398,6 +464,62 @@ export default class Viewer extends Mixins(GlobalMixin) {
if (!photo) return; if (!photo) return;
dav.downloadFilesByIds([photo]); dav.downloadFilesByIds([photo]);
} }
/** Open the sidebar */
private async openSidebar(photo?: IPhoto) {
const fInfo = await dav.getFiles([photo || this.getCurrentPhoto()]);
globalThis.OCA?.Files?.Sidebar?.setFullScreenMode?.(true);
globalThis.OCA.Files.Sidebar.open(fInfo[0].filename);
}
private async updateSizeWithoutAnim() {
const wasFullyOpened = this.fullyOpened;
this.fullyOpened = false;
this.photoswipe.updateSize();
await new Promise((resolve) => setTimeout(resolve, 200));
this.fullyOpened = wasFullyOpened;
}
private handleAppSidebarOpen() {
if (this.show && this.photoswipe) {
const sidebar: HTMLElement = document.querySelector("aside.app-sidebar");
if (sidebar) {
this.sidebarWidth = sidebar.offsetWidth - 2;
}
this.sidebarOpen = true;
this.updateSizeWithoutAnim();
}
}
private handleAppSidebarClose() {
if (this.show && this.photoswipe && this.fullyOpened) {
this.sidebarOpen = false;
this.updateSizeWithoutAnim();
}
}
/** Hide the sidebar, without marking it as closed */
private hideSidebar() {
globalThis.OCA?.Files?.Sidebar?.close();
globalThis.OCA?.Files?.Sidebar?.setFullScreenMode?.(false);
}
/** Close the sidebar */
private closeSidebar() {
this.hideSidebar();
this.sidebarOpen = false;
this.photoswipe.updateSize();
}
/** Toggle the sidebar visibility */
private toggleSidebar() {
if (this.sidebarOpen) {
this.closeSidebar();
} else {
this.openSidebar();
}
}
} }
</script> </script>
@ -405,8 +527,8 @@ export default class Viewer extends Mixins(GlobalMixin) {
.outer { .outer {
z-index: 3000; z-index: 3000;
width: 100vw; width: 100vw;
height: 30vh; height: 100vh;
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
overflow: hidden; overflow: hidden;
@ -415,7 +537,7 @@ export default class Viewer extends Mixins(GlobalMixin) {
.top-bar { .top-bar {
z-index: 100001; z-index: 100001;
position: fixed; position: absolute;
top: 8px; top: 8px;
right: 50px; right: 50px;
@ -435,6 +557,11 @@ export default class Viewer extends Mixins(GlobalMixin) {
transition: transform var(--pswp-transition-duration) ease !important; transition: transform var(--pswp-transition-duration) ease !important;
} }
.inner,
.inner :deep .pswp {
width: inherit;
}
:deep .pswp { :deep .pswp {
.pswp__button { .pswp__button {
color: white; color: white;