1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-21 21:33:18 +01:00

Changes scroll progress to behave differently when fetching scroll back content. (#640)

This commit is contained in:
Amir Raminfar
2020-08-19 12:47:28 -07:00
committed by GitHub
parent 0c2e2430fd
commit b148367618
10 changed files with 158 additions and 56 deletions

View File

@@ -13,12 +13,14 @@
<router-view></router-view>
</pane>
<pane v-for="other in activeContainers" :key="other.id" v-if="!isMobile">
<scrollable-view>
<template v-slot:header>
<container-title :value="other.name" closable @close="removeActiveContainer(other)"></container-title>
</template>
<log-viewer-with-source :id="other.id"></log-viewer-with-source>
</scrollable-view>
<log-container
:id="other.id"
:title="other.name"
show-title
scrollable
closable
@close="removeActiveContainer(other)"
></log-container>
</pane>
</splitpanes>
</pane>
@@ -41,26 +43,22 @@
import { mapActions, mapGetters, mapState } from "vuex";
import { Splitpanes, Pane } from "splitpanes";
import LogViewerWithSource from "./components/LogViewerWithSource";
import ScrollableView from "./components/ScrollableView";
import LogContainer from "./components/LogContainer";
import SideMenu from "./components/SideMenu";
import MobileMenu from "./components/MobileMenu";
import Search from "./components/Search";
import ContainerTitle from "./components/ContainerTitle";
import Icon from "./components/Icon";
export default {
name: "App",
components: {
Icon,
LogViewerWithSource,
SideMenu,
LogContainer,
MobileMenu,
ScrollableView,
Splitpanes,
Pane,
Search,
ContainerTitle,
},
data() {
return {

View File

@@ -1,14 +1,12 @@
<template>
<div ref="observer" class="control" :class="{ 'is-loading': isLoading }"></div>
<div ref="observer" class="control"></div>
</template>
<script>
export default {
name: "InfiniteLoader",
data() {
return {
isLoading: false,
};
return {};
},
props: {
onLoadMore: Function,
@@ -21,9 +19,7 @@ export default {
if (this.onLoadMore && this.enabled) {
const scrollingParent = this.$el.closest("[data-scrolling]") || document.documentElement;
const previousHeight = scrollingParent.scrollHeight;
this.isLoading = true;
await this.onLoadMore();
this.isLoading = false;
this.$nextTick(() => (scrollingParent.scrollTop += scrollingParent.scrollHeight - previousHeight));
}
},

View File

@@ -0,0 +1,45 @@
<template>
<scrollable-view :scrollable="scrollable">
<template v-slot:header v-if="showTitle">
<container-title :value="title" :closable="closable" @close="$emit('close')"></container-title>
</template>
<template v-slot="{ setLoading }">
<log-viewer-with-source :id="id" @loading-more="setLoading($event)"></log-viewer-with-source>
</template>
</scrollable-view>
</template>
<script>
import LogViewerWithSource from "./LogViewerWithSource";
import ScrollableView from "./ScrollableView";
import ContainerTitle from "./ContainerTitle";
export default {
props: {
id: {
type: String,
},
title: {
type: String,
},
showTitle: {
type: Boolean,
default: false,
},
scrollable: {
type: Boolean,
default: false,
},
closable: {
type: Boolean,
default: false,
},
},
name: "LogContainer",
components: {
LogViewerWithSource,
ScrollableView,
ContainerTitle,
},
};
</script>

View File

@@ -60,6 +60,7 @@ export default {
async loadOlderLogs() {
if (this.messages.length < 300) return;
this.$emit("loading-more", true);
const to = this.messages[0].date;
const last = this.messages[299].date;
const delta = to - last;
@@ -74,6 +75,7 @@ export default {
.map((line) => this.parseMessage(line));
this.messages.unshift(...newMessages);
}
this.$emit("loading-more", false);
},
parseMessage(data) {
let i = data.indexOf(" ");

View File

@@ -1,5 +1,5 @@
<template>
<log-event-source :id="id" v-slot="eventSource">
<log-event-source :id="id" v-slot="eventSource" @loading-more="$emit('loading-more', $event)">
<log-viewer :messages="eventSource.messages"></log-viewer>
</log-event-source>
</template>

View File

@@ -8,9 +8,11 @@
>
<span></span> <span></span> <span></span>
</a>
<svg class="logo">
<use href="#logo"></use>
</svg>
<router-link :to="{ name: 'default' }">
<svg class="logo">
<use href="#logo"></use>
</svg>
</router-link>
<p class="menu-label is-hidden-mobile" :class="{ 'is-active': showNav }">Containers</p>
<ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
<li v-for="item in visibleContainers" :key="item.id">

View File

@@ -1,15 +1,22 @@
<template>
<div class="scroll-progress">
<svg width="100" height="100" viewBox="0 0 100 100">
<svg width="100" height="100" viewBox="0 0 100 100" :class="{ indeterminate }">
<circle r="44" cx="50" cy="50" :style="{ '--progress': scrollProgress }" />
</svg>
<div class="is-overlay columns is-vcentered is-centered has-text-weight-light">
<span class="column is-narrow is-paddingless is-size-2">
{{ Math.ceil(scrollProgress * 100) }}
</span>
<span class="column is-narrow is-paddingless">
%
</span>
<template v-if="indeterminate">
<div class="column is-narrow is-paddingless is-size-2">
&#8734;
</div>
</template>
<template v-else>
<span class="column is-narrow is-paddingless is-size-2">
{{ Math.ceil(scrollProgress * 100) }}
</span>
<span class="column is-narrow is-paddingless">
%
</span>
</template>
</div>
</div>
</template>
@@ -20,6 +27,16 @@ import throttle from "lodash.throttle";
export default {
name: "ScrollProgress",
props: {
indeterminate: {
default: false,
type: Boolean,
},
autoHide: {
default: true,
type: Boolean,
},
},
data() {
return {
scrollProgress: 0,
@@ -39,6 +56,9 @@ export default {
this.detachEvents();
this.attachEvents();
},
indeterminate() {
this.$nextTick(() => this.onScroll());
},
},
computed: {
...mapState(["activeContainers"]),
@@ -54,16 +74,18 @@ export default {
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",
}
);
if (this.autoHide) {
this.animation.cancel();
this.animation = this.$el.animate(
{ opacity: [1, 0] },
{
duration: 500,
delay: 2000,
fill: "both",
easing: "ease-out",
}
);
}
},
},
};
@@ -79,10 +101,46 @@ export default {
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke: var(--primary-color);
stroke-dashoffset: calc(276.32px - var(--progress) * 276.32px);
stroke-dashoffset: calc(276.32 - var(--progress) * 276.32);
stroke-dasharray: 276.32px 276.32px;
stroke-linecap: round;
stroke-width: 3;
will-change: stroke-dashoffset;
}
svg.indeterminate {
animation: 2s linear infinite svg-animation;
circle {
animation: 1.4s ease-in-out infinite both circle-animation;
}
}
}
@keyframes svg-animation {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
@keyframes circle-animation {
0%,
25% {
stroke-dashoffset: 275;
transform: rotate(0);
}
50%,
75% {
stroke-dashoffset: 70;
transform: rotate(45deg);
}
100% {
stroke-dashoffset: 275;
transform: rotate(360deg);
}
}
</style>

View File

@@ -5,9 +5,9 @@
</header>
<main ref="content" :data-scrolling="scrollable">
<div class="is-scrollbar-progress is-hidden-mobile">
<scroll-progress v-show="paused"></scroll-progress>
<scroll-progress v-show="paused" :indeterminate="loading" :auto-hide="!loading"></scroll-progress>
</div>
<slot></slot>
<slot :setLoading="setLoading"></slot>
<div ref="scrollObserver" class="is-scroll-observer"></div>
</main>
@@ -41,6 +41,7 @@ export default {
return {
paused: false,
hasMore: false,
loading: false,
};
},
mounted() {
@@ -73,6 +74,9 @@ export default {
this.$refs.scrollObserver.scrollIntoView({ behavior });
this.hasMore = false;
},
setLoading(loading) {
this.loading = loading;
},
},
};
</script>

View File

@@ -1,27 +1,24 @@
<template>
<scrollable-view :scrollable="activeContainers.length > 0">
<template v-slot:header v-if="activeContainers.length > 0">
<container-title :value="allContainersById[id].name"></container-title>
</template>
<log-viewer-with-source :id="id"></log-viewer-with-source>
</scrollable-view>
<log-container
:id="id"
:title="title"
:show-title="activeContainers.length > 0"
:scrollable="activeContainers.length > 0"
>
</log-container>
</template>
<script>
import { mapActions, mapGetters, mapState } from "vuex";
import LogViewerWithSource from "../components/LogViewerWithSource";
import ScrollableView from "../components/ScrollableView";
import ContainerTitle from "../components/ContainerTitle";
import LogContainer from "../components/LogContainer";
import store from "../store";
export default {
props: ["id", "name"],
props: ["id"],
name: "Container",
components: {
LogViewerWithSource,
ScrollableView,
ContainerTitle,
LogContainer,
},
data() {
return {

View File

@@ -51,7 +51,7 @@
</span>
</p>
</div>
<p class="panel-tabs">
<p class="panel-tabs" v-if="!search">
<a :class="{ 'is-active': sort === 'running' }" @click="sort = 'running'">Running</a>
<a :class="{ 'is-active': sort === 'all' }" @click="sort = 'all'">All</a>
</p>