1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-21 21:33:18 +01:00
Files
dozzle/assets/components/ScrollableView.vue
Amir Raminfar 412a10256d Vue3 (#1594)
* WIP vue3

* WIP vue3

* WIP vue3

* Migrates to vitejs

* Fixes js tests and removes not needed modules

* Fixes unmount

* Updates to use css instead for space

* Fixes tests and rebases one more time

* Uses orgua

* Fixes migrations bugs with oruga and fixes scroll

* Fixes v-deep

* Fixes icons to prod

* Fixes icons to prod

* Adds favicon back

* Transitions some to composition api

* Updates another component to comp api

* Cleans defineProps

* Updates log messages

* Moves more to compose api

* Cleans up styles and rewrites event source

* Tries to fix DOMPurify

* Removes postcss

* WIP typescript

* Improves importing

* Converts all to ts

* Converts main to ts

* Makes changes for tsconfig

* Moves more to ts

* Adds typing to store

* More typing

* Updates to ts

* Updates the rest to ts

* Fixes computes

* Fixes unmount

* Adds cypress with custom base fixed

* Fixes jest tests

* Fixes golang tests

* Adds gitignore for cypress

* Removes int in favor of e2e with cypress

* Tries to fix int tests again

* Adds title

* Updates e2e tests

* Uses vue for isMobile

* Removes app spec

* Cleans up docker

* Adds drop down for settings

* Fixes bug with restart

* Fixes scroll up bug

* Adds tests for light mode
2021-11-16 10:55:44 -08:00

165 lines
3.7 KiB
Vue

<template>
<section :class="{ 'is-full-height-scrollable': scrollable }">
<header v-if="$slots.header">
<slot name="header"></slot>
</header>
<main ref="content" :data-scrolling="scrollable ? true : undefined">
<div class="is-scrollbar-progress is-hidden-mobile">
<scroll-progress v-show="paused" :indeterminate="loading" :auto-hide="!loading"></scroll-progress>
</div>
<slot :setLoading="setLoading"></slot>
<div ref="scrollObserver" class="is-scroll-observer"></div>
</main>
<div class="is-scrollbar-notification">
<transition name="fade">
<button class="button" :class="hasMore ? 'has-more' : ''" @click="scrollToBottom('instant')" v-show="paused">
<mdi-light-chevron-double-down />
</button>
</transition>
</div>
</section>
</template>
<script lang="ts">
export default {
props: {
scrollable: {
type: Boolean,
default: true,
},
},
name: "ScrollableView",
data() {
return {
paused: false,
hasMore: false,
loading: false,
mutationObserver: null,
intersectionObserver: null,
};
},
mounted() {
const { content } = this.$refs;
this.mutationObserver = new MutationObserver((e) => {
if (!this.paused) {
this.scrollToBottom("instant");
} else {
const record = e[e.length - 1];
if (
record.target.children[record.target.children.length - 1] == record.addedNodes[record.addedNodes.length - 1]
) {
this.hasMore = true;
}
}
});
this.mutationObserver.observe(content, { childList: true, subtree: true });
this.intersectionObserver = new IntersectionObserver(
(entries) => (this.paused = entries[0].intersectionRatio == 0),
{ threshholds: [0, 1], rootMargin: "80px 0px" }
);
this.intersectionObserver.observe(this.$refs.scrollObserver);
},
beforeUnmount() {
this.mutationObserver.disconnect();
this.intersectionObserver.disconnect();
},
methods: {
scrollToBottom(behavior = "instant") {
this.$refs.scrollObserver.scrollIntoView({ behavior });
this.hasMore = false;
},
setLoading(loading) {
this.loading = loading;
},
},
};
</script>
<style scoped lang="scss">
section {
display: flex;
flex-direction: column;
header {
position: sticky;
top: 0;
background: var(--body-background-color);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
&.is-full-height-scrollable {
height: 100vh;
min-height: 0;
}
main {
flex: 1;
overflow: auto;
scroll-snap-type: y proximity;
}
.is-scrollbar-progress {
text-align: right;
margin-right: 110px;
.scroll-progress {
position: fixed;
top: 60px;
z-index: 2;
}
}
.is-scroll-observer {
height: 1px;
}
.is-scrollbar-notification {
text-align: right;
margin-right: 65px;
button {
position: fixed;
bottom: 30px;
background-color: var(--secondary-color);
transition: background-color 1s ease-out;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
border: none !important;
color: #222;
&.has-more {
background-color: var(--primary-color);
animation-name: bounce;
animation-duration: 1000ms;
animation-fill-mode: both;
color: #fff;
}
}
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-30px);
}
60% {
transform: translateY(-15px);
}
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.15s ease-in;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
}
</style>