split-timeline: basic resizing

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/563/head
Varun Patil 2023-03-30 11:44:18 -07:00
parent dd00857ea0
commit 61b3c7de1c
1 changed files with 122 additions and 19 deletions

View File

@ -1,8 +1,18 @@
<template> <template>
<div class="container"> <div class="container">
<div class="primary"> <div class="primary" ref="primary">
<component :is="primary" /> <component :is="primary" />
</div> </div>
<div
class="separator"
ref="separator"
@pointerdown="sepDown"
@touchmove.passive="sepTouchMove"
@touchend.passive="pointerUp"
@touchcancel.passive="pointerUp"
></div>
<div class="timeline"> <div class="timeline">
<Timeline /> <Timeline />
</div> </div>
@ -13,6 +23,7 @@
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import Timeline from "./Timeline.vue"; import Timeline from "./Timeline.vue";
const MapSplitMatter = () => import("./top-matter/MapSplitMatter.vue"); const MapSplitMatter = () => import("./top-matter/MapSplitMatter.vue");
import { emit } from "@nextcloud/event-bus";
export default defineComponent({ export default defineComponent({
name: "SplitTimeline", name: "SplitTimeline",
@ -21,6 +32,11 @@ export default defineComponent({
Timeline, Timeline,
}, },
data: () => ({
pointerDown: false,
primaryPos: 0,
}),
computed: { computed: {
primary() { primary() {
switch (this.$route.name) { switch (this.$route.name) {
@ -31,6 +47,60 @@ export default defineComponent({
} }
}, },
}, },
beforeDestroy() {
this.pointerUp();
},
methods: {
isVertical() {
return globalThis.windowInnerWidth <= 768;
},
sepDown(event: PointerEvent) {
this.pointerDown = true;
// Get position of primary element
const primary = <HTMLDivElement>this.$refs.primary;
const rect = primary.getBoundingClientRect();
this.primaryPos = this.isVertical() ? rect.top : rect.left;
// Let touch handle itself
if (event.pointerType === "touch") return;
// Otherwise, handle pointer events on document
document.addEventListener("pointermove", this.documentPointerMove);
document.addEventListener("pointerup", this.pointerUp);
// Prevent text selection
event.preventDefault();
event.stopPropagation();
},
sepTouchMove(event: TouchEvent) {
if (!this.pointerDown) return;
this.setFlexBasis(event.touches[0]);
},
documentPointerMove(event: PointerEvent) {
if (!this.pointerDown || !event.buttons) return this.pointerUp();
this.setFlexBasis(event);
},
pointerUp() {
// Get rid of listeners on document quickly
this.pointerDown = false;
document.removeEventListener("pointermove", this.documentPointerMove);
document.removeEventListener("pointerup", this.pointerUp);
emit("memories:window:resize", null);
},
setFlexBasis(pos: { clientX: number; clientY: number }) {
const ref = this.isVertical() ? pos.clientY : pos.clientX;
const newWidth = Math.max(ref - this.primaryPos, 50);
(<HTMLDivElement>this.$refs.primary).style.flexBasis = `${newWidth}px`;
},
},
}); });
</script> </script>
@ -40,29 +110,62 @@ export default defineComponent({
height: 100%; height: 100%;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
}
.primary { > div {
width: 60%;
height: 100%;
}
.timeline {
flex: 1;
height: 100%; height: 100%;
max-height: 100%;
}
> .primary {
flex-basis: 60%;
flex-shrink: 0;
}
> .timeline {
flex-basis: auto;
flex-grow: 1;
padding-left: 8px; padding-left: 8px;
overflow: hidden;
}
> .separator {
flex-grow: 0;
flex-shrink: 0;
width: 5px;
background-color: gray;
opacity: 0.1;
cursor: col-resize;
margin: 0 0 0 auto;
transition: opacity 0.4s ease-out, background-color 0.4s ease-out;
}
> .separator:hover {
opacity: 0.4;
background-color: var(--color-primary);
}
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.container { .container {
flex-direction: column; flex-direction: column;
}
.primary { > div {
width: 100%; width: 100%;
height: 40%; height: unset;
} }
.timeline {
width: 100%; > .primary {
height: 60%; flex-basis: 40%;
}
> .timeline {
padding-left: 0; padding-left: 0;
} }
> .separator {
height: 5px;
width: 100%;
}
}
} }
</style> </style>