You've already forked AstralRinth
forked from didirus/AstralRinth
Loading bars (#113)
* Loading bars * remove print * remove print * remove class * Fix overlay
This commit is contained in:
@@ -2,12 +2,13 @@
|
||||
import { onMounted } from 'vue'
|
||||
import { RouterView, RouterLink } from 'vue-router'
|
||||
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon, Button } from 'omorphia'
|
||||
import { useTheming } from '@/store/state'
|
||||
import { useLoading, useTheming } from '@/store/state'
|
||||
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||
import { get } from '@/helpers/settings'
|
||||
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
|
||||
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
||||
import ModrinthLoadingIndicator from '@/components/modrinth-loading-indicator'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
@@ -16,6 +17,8 @@ onMounted(async () => {
|
||||
themeStore.setThemeState(settings)
|
||||
themeStore.collapsedNavigation = collapsed_navigation
|
||||
})
|
||||
|
||||
const loading = useLoading()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -106,9 +109,13 @@ onMounted(async () => {
|
||||
</section>
|
||||
</div>
|
||||
<div class="router-view">
|
||||
<ModrinthLoadingIndicator
|
||||
offset-height="var(--appbar-height)"
|
||||
offset-width="var(--sidebar-width)"
|
||||
/>
|
||||
<RouterView v-slot="{ Component }">
|
||||
<template v-if="Component">
|
||||
<Suspense>
|
||||
<Suspense @pending="loading.startLoading()" @resolve="loading.stopLoading()">
|
||||
<component :is="Component"></component>
|
||||
</Suspense>
|
||||
</template>
|
||||
@@ -120,18 +127,21 @@ onMounted(async () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
--appbar-height: 3.25rem;
|
||||
--sidebar-width: 5rem;
|
||||
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
|
||||
.view {
|
||||
width: var(--view-width);
|
||||
|
||||
&.expanded {
|
||||
width: var(--expanded-view-width);
|
||||
--sidebar-width: 13rem;
|
||||
}
|
||||
|
||||
width: calc(100% - var(--sidebar-width));
|
||||
|
||||
.appbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -219,9 +229,11 @@ onMounted(async () => {
|
||||
background: var(--color-raised-bg);
|
||||
|
||||
&.expanded {
|
||||
width: 13rem;
|
||||
max-width: 13rem;
|
||||
min-width: 13rem;
|
||||
--sidebar-width: 13rem;
|
||||
|
||||
width: var(--sidebar-width);
|
||||
max-width: var(--sidebar-width);
|
||||
min-width: var(--sidebar-width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
134
theseus_gui/src/components/modrinth-loading-indicator.js
Normal file
134
theseus_gui/src/components/modrinth-loading-indicator.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import { computed, defineComponent, h, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { useLoading } from '@/store/state.js'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
throttle: {
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
color: {
|
||||
type: [String, Boolean],
|
||||
default:
|
||||
'repeating-linear-gradient(to right, var(--color-brand) 0%, var(--color-brand) 100%)',
|
||||
},
|
||||
offsetWidth: {
|
||||
type: String,
|
||||
default: '208px',
|
||||
},
|
||||
offsetHeight: {
|
||||
type: String,
|
||||
default: '52px',
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const indicator = useLoadingIndicator({
|
||||
duration: props.duration,
|
||||
throttle: props.throttle,
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => indicator.clear)
|
||||
|
||||
const loading = useLoading()
|
||||
|
||||
watch(loading, (newValue) => {
|
||||
if (newValue.loading) {
|
||||
indicator.start()
|
||||
} else {
|
||||
indicator.finish()
|
||||
}
|
||||
})
|
||||
|
||||
return () =>
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
position: 'fixed',
|
||||
top: props.offsetHeight,
|
||||
right: 0,
|
||||
left: props.offsetWidth,
|
||||
pointerEvents: 'none',
|
||||
width: `calc((100vw - ${props.offsetWidth}) * ${indicator.progress.value / 100})`,
|
||||
height: `${props.height}px`,
|
||||
opacity: indicator.isLoading.value ? 1 : 0,
|
||||
background: props.color || undefined,
|
||||
backgroundSize: `${(100 / indicator.progress.value) * 100}% auto`,
|
||||
transition: 'width 0.1s, height 0.4s, opacity 0.4s',
|
||||
zIndex: 99,
|
||||
},
|
||||
},
|
||||
slots
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
function useLoadingIndicator(opts) {
|
||||
const progress = ref(0)
|
||||
const isLoading = ref(false)
|
||||
const step = computed(() => 10000 / opts.duration)
|
||||
|
||||
let _timer = null
|
||||
let _throttle = null
|
||||
|
||||
function start() {
|
||||
clear()
|
||||
progress.value = 0
|
||||
if (opts.throttle) {
|
||||
_throttle = setTimeout(() => {
|
||||
isLoading.value = true
|
||||
_startTimer()
|
||||
}, opts.throttle)
|
||||
} else {
|
||||
isLoading.value = true
|
||||
_startTimer()
|
||||
}
|
||||
}
|
||||
function finish() {
|
||||
progress.value = 100
|
||||
_hide()
|
||||
}
|
||||
|
||||
function clear() {
|
||||
clearInterval(_timer)
|
||||
clearTimeout(_throttle)
|
||||
_timer = null
|
||||
_throttle = null
|
||||
}
|
||||
|
||||
function _increase(num) {
|
||||
progress.value = Math.min(100, progress.value + num)
|
||||
}
|
||||
|
||||
function _hide() {
|
||||
clear()
|
||||
setTimeout(() => {
|
||||
isLoading.value = false
|
||||
setTimeout(() => {
|
||||
progress.value = 0
|
||||
}, 400)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function _startTimer() {
|
||||
_timer = setInterval(() => {
|
||||
_increase(step.value)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
return {
|
||||
progress,
|
||||
isLoading,
|
||||
start,
|
||||
finish,
|
||||
clear,
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>Add Instance</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -47,7 +47,7 @@ await getInstances()
|
||||
await Promise.all([getFeaturedModpacks(), getFeaturedMods()])
|
||||
|
||||
const unlisten = await profile_listener(async (e) => {
|
||||
if (e.event === 'edited') {
|
||||
if (e.event === 'created' || e.event === 'removed') {
|
||||
await getInstances()
|
||||
await Promise.all([getFeaturedModpacks(), getFeaturedMods()])
|
||||
}
|
||||
|
||||
13
theseus_gui/src/store/loading.js
Normal file
13
theseus_gui/src/store/loading.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useLoading = defineStore('loadingStore', {
|
||||
state: () => ({ loading: false }),
|
||||
actions: {
|
||||
startLoading() {
|
||||
this.loading = true
|
||||
},
|
||||
stopLoading() {
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useSearch } from './search'
|
||||
import { useTheming } from './theme'
|
||||
import { useBreadcrumbs } from './breadcrumbs'
|
||||
import { useLoading } from './loading'
|
||||
|
||||
export { useSearch, useTheming, useBreadcrumbs }
|
||||
export { useSearch, useTheming, useBreadcrumbs, useLoading }
|
||||
|
||||
Reference in New Issue
Block a user