Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

Commit 3eb7fa3

Browse files
committed
#658 - Add AppLoadingBar component
1 parent b323322 commit 3eb7fa3

File tree

7 files changed

+180
-39
lines changed

7 files changed

+180
-39
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<script lang="ts">
2+
import { get_current_component } from 'svelte/internal'
3+
import { tweened } from 'svelte/motion'
4+
5+
import { forwardEventsBuilder } from '$lib/directives'
6+
import type { Colors } from '$lib/types'
7+
import { classname } from '$lib/utils'
8+
9+
import { El } from '../Base'
10+
import type { AppLoadingBarProps } from './AppLoadingBar.types'
11+
12+
type $$Props = AppLoadingBarProps
13+
14+
export let cssPrefix: $$Props['cssPrefix'] = 'app-loading-bar'
15+
export let tag: $$Props['tag'] = 'div'
16+
17+
/**
18+
* The Color of loading bar
19+
*/
20+
export let color: $$Props['color'] = 'primary'
21+
/**
22+
* The amount of time that loading will take
23+
*/
24+
export let duration: $$Props['duration'] = 1000
25+
/**
26+
* Always show loading bar in top of page
27+
*/
28+
export let fixedPosition: $$Props['fixedPosition'] = false
29+
/**
30+
* Use Indeterminate prop when you don't know how long the loading will take
31+
*/
32+
export let indeterminate: $$Props['indeterminate'] = false
33+
/**
34+
* Show and start the loading when component mounted
35+
*/
36+
export let show: $$Props['show'] = false
37+
38+
let MAX: number = 100
39+
let interval: NodeJS.Timer
40+
let total: number = 0
41+
let value = tweened<number>(0, { duration })
42+
43+
$: if ($value > (max * 95) / 100) clearInterval(interval)
44+
$: if (show) start()
45+
$: max = MAX + total
46+
$: width = ($value * 100) / max
47+
48+
$: cssProps = {
49+
color,
50+
fixedPosition,
51+
indeterminate,
52+
show,
53+
}
54+
55+
/**
56+
* Show component and start the loading animation
57+
*/
58+
export function start() {
59+
show = true
60+
value.set(0, { duration: 0 })
61+
if (interval) clearInterval(interval)
62+
interval = setInterval(increment, duration)
63+
}
64+
/**
65+
* Add a task that Loading Bar should wait until it's done
66+
* @param number
67+
*/
68+
export function push(number = MAX / 4) {
69+
show = true
70+
total += number
71+
}
72+
/**
73+
* finish previously added task.
74+
* @param number
75+
*/
76+
export function pop(number = MAX / 4) {
77+
total -= number
78+
if (total > 0) return
79+
total = 0
80+
done()
81+
}
82+
/**
83+
* Finish loading animation and remove LoadingBar from page.
84+
*/
85+
export function done() {
86+
clearInterval(interval)
87+
value.set(max, { duration: duration! / 2 })
88+
setTimeout(() => (show = false), duration! / 2)
89+
}
90+
function increment() {
91+
$value += (MAX - $value) / 4
92+
}
93+
</script>
94+
95+
<El {...$$restProps} {cssProps} {tag} {cssPrefix}>
96+
<El tag="div" cssPrefix="{cssPrefix}-body" style="width: {width}%;" cssProps={{ color }} />
97+
</El>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { ElProps } from '../Base'
2+
3+
export interface AppLoadingBarProps extends Partial<ElProps> {
4+
color?: Colors
5+
duration?: number
6+
fixedPosition?: boolean
7+
indeterminate?: boolean
8+
show?: boolean
9+
}

src/components/AppLoadingBar/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as AppLoadingBar } from './AppLoadingBar.svelte'

src/components/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './Base'
22
export * from './Accordion'
33
export * from './Alert'
44
export * from './App'
5+
export * from './AppLoadingBar'
56
export * from './Avatar'
67
export * from './Badge'
78
export * from './Base'

src/routes/+layout.svelte

+8-39
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,22 @@
11
<script type="ts">
2-
import { App, AppBody, AppFooter, Avatar, El, Page, Progress } from '@ubeac/svelte'
2+
import type { SvelteComponentDev } from 'svelte/internal'
3+
4+
import { App, AppBody, AppFooter, AppLoadingBar, Avatar, El, Page, Progress } from '@ubeac/svelte'
35
import type { Themes } from '@ubeac/svelte'
46
import 'bootstrap/dist/js/bootstrap.bundle.min.js'
57
6-
import { browser } from '$app/environment'
78
import { afterNavigate, beforeNavigate } from '$app/navigation'
89
910
let container: ContainerMaxWidths = 'md'
1011
let theme: Themes = 'light'
11-
let progressValue = 0
12-
let updater: any
13-
14-
export let maximum = 0.999
15-
export let intervalTime = 700
16-
export let stepSizes = [0, 0.005, 0.01, 0.02]
17-
18-
const getIncrement = (number: number) => {
19-
if (number >= 0 && number < 0.2) return 0.1
20-
else if (number >= 0.2 && number < 0.5) return 0.04
21-
else if (number >= 0.5 && number < 0.8) return 0.02
22-
else if (number >= 0.8 && number < 0.99) return 0.005
23-
return 0.00001
24-
}
25-
const startInterval = () => {
26-
if (browser) {
27-
updater = setInterval(() => {
28-
const randomStep = stepSizes[Math.floor(Math.random() * stepSizes.length)]
29-
const step = getIncrement(progressValue) + randomStep
30-
if (progressValue < maximum) {
31-
progressValue = progressValue + step
32-
}
33-
if (progressValue > maximum) {
34-
clearInterval(updater)
35-
}
36-
}, intervalTime)
37-
}
38-
}
12+
let loadingBar: SvelteComponentDev
3913
4014
beforeNavigate(() => {
41-
progressValue = 0
42-
startInterval()
15+
loadingBar.start()
4316
})
4417
4518
afterNavigate(() => {
46-
progressValue = 1
47-
clearInterval(updater)
19+
loadingBar.done()
4820
})
4921
5022
const onThemeChange = () => (theme === 'light' ? (theme = 'dark') : (theme = 'light'))
@@ -55,11 +27,8 @@
5527
</svelte:head>
5628

5729
<App {theme}>
58-
<div class="sticky-top">
59-
<div class="position-relative">
60-
<Progress col position="absolute" color="primary" style="height: 3px;" value={progressValue * 100} />
61-
</div>
62-
</div>
30+
<AppLoadingBar fixed color="primary" bind:this={loadingBar} />
31+
6332
<header class="navbar navbar-expand-md navbar-light d-print-none">
6433
<div class="container-xl">
6534
<button
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
$prefix-app-loading-bar: $prefix + 'app-loading-bar';
2+
3+
.#{$prefix-app-loading-bar} {
4+
overflow: hidden;
5+
display: none;
6+
position: relative;
7+
height: 0.25rem;
8+
width: 100%;
9+
10+
&-fixed-position {
11+
position: fixed;
12+
z-index: 10;
13+
top: 0;
14+
left: 0;
15+
}
16+
17+
&-indeterminate>&-body {
18+
animation: #{$prefix-app-loading-bar}-animation 1s linear infinite;
19+
}
20+
21+
&-show {
22+
display: block;
23+
}
24+
25+
&-body {
26+
height: 100%;
27+
position: absolute;
28+
left: 0;
29+
top: 0;
30+
border-radius: 0.125rem;
31+
32+
33+
}
34+
35+
36+
@each $color,
37+
$value in $theme-colors {
38+
&-color-#{$color} {
39+
@extend .bg-#{$color}-lt;
40+
}
41+
42+
&-body-color-#{$color} {
43+
@extend .bg-#{$color};
44+
}
45+
}
46+
}
47+
48+
@keyframes #{$prefix-app-loading-bar}-animation {
49+
0% {
50+
left: 0%;
51+
width: 0%;
52+
}
53+
54+
50% {
55+
left: 10%;
56+
width: 80%;
57+
}
58+
59+
100% {
60+
left: 100%;
61+
width: 0%;
62+
}
63+
}

src/scss/tabler/components/index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@import './accordion';
22
@import './alert';
33
@import './app';
4+
@import './app-loading-bar';
45
@import './avatar';
56
@import './avatar-list';
67
@import './badge';

0 commit comments

Comments
 (0)