mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-27 15:41:45 +01:00
Adds progress notification bar (#526)
This commit is contained in:
103
assets/components/ScrollProgress.vue
Normal file
103
assets/components/ScrollProgress.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div class="scroll-progress">
|
||||
<svg width="100" height="100" viewBox="0 0 100 100">
|
||||
<circle r="44" cx="50" cy="50" :style="{ '--progress': scrollProgress }" />
|
||||
</svg>
|
||||
<div class="percent columns is-vcentered is-centered">
|
||||
<span class="column is-narrow is-paddingless is-size-2">
|
||||
{{ Math.ceil(scrollProgress * 100) }}
|
||||
</span>
|
||||
<span class="column is-narrow is-paddingless">
|
||||
%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import throttle from "lodash.throttle";
|
||||
|
||||
export default {
|
||||
name: "ScrollProgress",
|
||||
data() {
|
||||
return {
|
||||
scrollProgress: 0,
|
||||
animation: { cancel: () => {} },
|
||||
parentElement: document,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.onScrollThrottled = throttle(this.onScroll, 150);
|
||||
},
|
||||
mounted() {
|
||||
this.attachEvents();
|
||||
this.$once("hook:beforeDestroy", this.detachEvents);
|
||||
},
|
||||
watch: {
|
||||
activeContainers() {
|
||||
this.detachEvents();
|
||||
this.attachEvents();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(["activeContainers"]),
|
||||
},
|
||||
methods: {
|
||||
attachEvents() {
|
||||
this.parentElement = this.$el.closest("[data-scrolling]") || document;
|
||||
this.parentElement.addEventListener("scroll", this.onScrollThrottled);
|
||||
},
|
||||
detachEvents() {
|
||||
this.parentElement.removeEventListener("scroll", this.onScrollThrottled);
|
||||
},
|
||||
onScroll() {
|
||||
const p = this.parentElement == document ? document.documentElement : this.parentElement;
|
||||
this.scrollProgress = p.scrollTop / (p.scrollHeight - p.clientHeight);
|
||||
this.animation.cancel();
|
||||
this.animation = this.$el.animate(
|
||||
{ opacity: [1, 0] },
|
||||
{
|
||||
duration: 500,
|
||||
delay: 2000,
|
||||
fill: "both",
|
||||
easing: "ease-out",
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.scroll-progress {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
circle {
|
||||
fill: #000;
|
||||
fill-opacity: 0.6;
|
||||
transition: stroke-dashoffset 0.35s ease-out;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: 50% 50%;
|
||||
stroke: #00d1b2;
|
||||
stroke-dashoffset: calc(276.32 - var(--progress) * 276.32);
|
||||
stroke-dasharray: 276.32 276.32;
|
||||
stroke-width: 3;
|
||||
will-change: stroke-dashoffset;
|
||||
html.has-light-theme & {
|
||||
fill-opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.percent {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
html.has-light-theme & {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,10 +4,14 @@
|
||||
<slot name="header"></slot>
|
||||
</header>
|
||||
<main ref="content" :data-scrolling="scrollable">
|
||||
<div class="scrollbar-progress">
|
||||
<scroll-progress v-show="paused"></scroll-progress>
|
||||
</div>
|
||||
<slot></slot>
|
||||
<div ref="scrollObserver"></div>
|
||||
</main>
|
||||
<div class="scroll-bar-notification">
|
||||
|
||||
<div class="scrollbar-notification">
|
||||
<transition name="fade">
|
||||
<button
|
||||
class="button"
|
||||
@@ -24,6 +28,7 @@
|
||||
|
||||
<script>
|
||||
import Icon from "./Icon";
|
||||
import ScrollProgress from "./ScrollProgress";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -34,6 +39,7 @@ export default {
|
||||
},
|
||||
components: {
|
||||
Icon,
|
||||
ScrollProgress,
|
||||
},
|
||||
name: "ScrollableView",
|
||||
data() {
|
||||
@@ -85,7 +91,16 @@ section {
|
||||
scroll-snap-type: y proximity;
|
||||
}
|
||||
|
||||
.scroll-bar-notification {
|
||||
.scrollbar-progress {
|
||||
text-align: right;
|
||||
margin-right: 125px;
|
||||
.scroll-progress {
|
||||
position: fixed;
|
||||
top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar-notification {
|
||||
text-align: right;
|
||||
margin-right: 65px;
|
||||
button {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Dozzle</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata&display=swap" rel="stylesheet" />
|
||||
<script type="application/json" id="config__json">
|
||||
{
|
||||
"base": "{{ .Base }}",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"dompurify": "^2.0.11",
|
||||
"hotkeys-js": "^3.8.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"semver": "^7.3.2",
|
||||
"splitpanes": "^2.2.1",
|
||||
"store": "^2.0.12",
|
||||
|
||||
@@ -5630,6 +5630,11 @@ lodash.templatesettings@^4.0.0:
|
||||
dependencies:
|
||||
lodash._reinterpolate "^3.0.0"
|
||||
|
||||
lodash.throttle@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
||||
Reference in New Issue
Block a user