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

add AppLoadingBar component #673

Open
wants to merge 12 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/components/AppLoadingBar/AppLoadingBar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<script lang="ts">
import { tweened } from 'svelte/motion'

import { El, type AppLoadingBarProps } from '$lib/components'

type $$Props = AppLoadingBarProps

export let cssPrefix: $$Props['cssPrefix'] = 'app-loading-bar'
export let tag: $$Props['tag'] = 'div'

/**
* The Color of loading bar
*/
export let color: $$Props['color'] = 'primary'
/**
* The amount of time that loading will take
*/
export let duration: $$Props['duration'] = 1000
/**
* Always show loading bar in top of page
*/
export let fixedPosition: $$Props['fixedPosition'] = false
/**
* Use Indeterminate prop when you don't know how long the loading will take
*/
export let indeterminate: $$Props['indeterminate'] = false
/**
* Show and start the loading when component mounted
*/
export let show: $$Props['show'] = false

let MAX: number = 100
let interval: NodeJS.Timer
let total: number = 0
let value = tweened<number>(0, { duration })

$: if ($value > (max * 95) / 100) clearInterval(interval)
$: if (show) start()
$: max = MAX + total
$: width = ($value * 100) / max

$: cssProps = {
color,
fixedPosition,
indeterminate,
show,
}

/**
* Show component and start the loading animation
*/
export function start() {
show = true
value.set(0, { duration: 0 })
if (interval) clearInterval(interval)
increment()
interval = setInterval(increment, duration)
}
/**
* Add a task that Loading Bar should wait until it's done
* @param number
*/
export function push(number = MAX / 4) {
show = true
total += number
}
/**
* finish previously added task.
* @param number
*/
export function pop(number = MAX / 4) {
total -= number
if (total > 0) return
total = 0
done()
}
/**
* Finish loading animation and remove LoadingBar from page.
*/
export function done() {
clearInterval(interval)
value.set(max, { duration: duration! / 2 })
setTimeout(() => (show = false), duration! / 2)
}
function increment() {
$value += (MAX - $value) / 4
}
</script>

<El {...$$restProps} {cssProps} {tag} {cssPrefix}>
<El tag="div" cssPrefix="{cssPrefix}-body" style="width: {width}%;" cssProps={{ color }} />
</El>
9 changes: 9 additions & 0 deletions src/components/AppLoadingBar/AppLoadingBar.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { ElProps } from '../Base'

export interface AppLoadingBarProps extends Partial<ElProps> {
color?: Colors
duration?: number
fixedPosition?: boolean
indeterminate?: boolean
show?: boolean
}
2 changes: 2 additions & 0 deletions src/components/AppLoadingBar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as AppLoadingBar } from './AppLoadingBar.svelte'
export * from './AppLoadingBar.types'
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './Accordion'
export * from './Alert'
export * from './App'
export * from './AppLoadingBar'
export * from './Avatar'
export * from './Badge'
export * from './El'
Expand Down
45 changes: 5 additions & 40 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
App,
AppBody,
AppFooter,
AppLoadingBar,
type ContainerMaxWidths,
El,
Offcanvas,
Expand All @@ -20,47 +21,18 @@

let container: ContainerMaxWidths = 'md'
let theme: Themes = 'light'
let progressValue = 0
let updater: any
let showDocs = false
let showTopNav = false

export let maximum = 0.999
export let intervalTime = 700
export let stepSizes = [0, 0.005, 0.01, 0.02]

const getIncrement = (number: number) => {
if (number >= 0 && number < 0.2) return 0.1
else if (number >= 0.2 && number < 0.5) return 0.04
else if (number >= 0.5 && number < 0.8) return 0.02
else if (number >= 0.8 && number < 0.99) return 0.005
return 0.00001
}
const startInterval = () => {
if (typeof window !== 'undefined') {
updater = setInterval(() => {
const randomStep = stepSizes[Math.floor(Math.random() * stepSizes.length)]
const step = getIncrement(progressValue) + randomStep
if (progressValue < maximum) {
progressValue = progressValue + step
}
if (progressValue > maximum) {
clearInterval(updater)
}
}, intervalTime)
}
}
let loadingBar: any

beforeNavigate(() => {
progressValue = 0
loadingBar?.start()
showDocs = false
showTopNav = false
startInterval()
})

afterNavigate(() => {
progressValue = 1
clearInterval(updater)
loadingBar?.done()
})

const onThemeChange = () => (theme === 'light' ? (theme = 'dark') : (theme = 'light'))
Expand All @@ -79,14 +51,7 @@
</svelte:head>

<App {theme}>
{#if progressValue < 1}
<div class="sticky-top">
<div class="position-relative">
<Progress col position="absolute" color="primary" style="height: 3px;" value={progressValue * 100} />
</div>
</div>
{/if}

<AppLoadingBar bind:this={loadingBar} fixedPosition color="primary" />
<header class="navbar navbar-expand-md navbar-light d-print-none align-items-center px-3">
<div class="container-xl d-none d-md-block">
<div class="row">
Expand Down
62 changes: 62 additions & 0 deletions src/routes/docs/components/app-loading-bars/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script>
import { Doc, Preview } from '$lib/components'
import AppLoadingBarColors from './AppLoadingBarColors.svelte'
import AppLoadingBarDefault from './AppLoadingBarDefault.svelte'
import AppLoadingBarDuration from './AppLoadingBarDuration.svelte'
import AppLoadingBarFixedPosition from './AppLoadingBarFixedPosition.svelte'
import AppLoadingBarIndeterminate from './AppLoadingBarIndeterminate.svelte'
import AppLoadingBarMethods from './AppLoadingBarMethods.svelte'
import AppLoadingBarTable from './AppLoadingBarTable.svelte'
</script>

<h1>AppLoadingBar</h1>
<p>TODO</p>

<Doc title="Default">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarDefault.svelte">
<AppLoadingBarDefault />
</Preview>

<Doc title="Colors">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarColors.svelte">
<AppLoadingBarColors />
</Preview>

<Doc title="Methods">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarMethods.svelte">
<AppLoadingBarMethods />
</Preview>

<Doc title="Fixed Position">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarFixedPosition.svelte">
<AppLoadingBarFixedPosition />
</Preview>

<Doc title="Indeterminate">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarIndeterminate.svelte">
<AppLoadingBarIndeterminate />
</Preview>

<Doc title="Duration">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarDuration.svelte">
<AppLoadingBarDuration />
</Preview>

<Doc title="Example Usage">
<!-- -->
</Doc>
<Preview src="./AppLoadingBarTable.svelte">
<AppLoadingBarTable />
</Preview>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
import { AppLoadingBar, Button, FormSelect } from '@ubeac/svelte/components'
import { COLORS } from '@ubeac/svelte/types'

let show = false
let color = 'primary'
</script>

<FormSelect label="Choose a Color" items={COLORS} bind:value={color} />
<Button on:click={() => (show = true)}>Show</Button>
<Button on:click={() => (show = false)}>Hide</Button>

<AppLoadingBar {color} {show} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { AppLoadingBar, Button } from '@ubeac/svelte/components'

let show = false
</script>

<Button on:click={() => (show = true)}>Show</Button>

<AppLoadingBar {show} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script>
import { AppLoadingBar, Button } from '@ubeac/svelte/components'

let show = false
</script>

<Button on:click={() => (show = true)}>Show</Button>

<br />
1000:
<AppLoadingBar {show} />

<br />
2000:
<AppLoadingBar duration={2000} {show} />

<br />
5000:
<AppLoadingBar duration={5000} {show} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { AppLoadingBar, Button } from '@ubeac/svelte/components'

let show = false
</script>

<Button on:click={() => (show = true)}>Show</Button>

<AppLoadingBar fixedPosition {show} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { AppLoadingBar, Button } from '@ubeac/svelte/components'

let show = false
</script>

<Button on:click={() => (show = true)}>Show</Button>

<AppLoadingBar indeterminate {show} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { AppLoadingBar, Button } from '@ubeac/svelte'

let loadingBar: any

let show = false
</script>

<Button on:click={() => loadingBar.start()}>Start</Button>
<Button on:click={() => loadingBar.done()}>End</Button>
<Button on:click={() => loadingBar.push()}>Push</Button>
<Button on:click={() => loadingBar.pop()}>Pop</Button>

<AppLoadingBar bind:this={loadingBar} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import { Button, Card, Table, TableBody, TableHead, TableRow } from '@ubeac/svelte/components'
import AppLoadingBar from '@ubeac/svelte/components/AppLoadingBar/AppLoadingBar.svelte'
import TableCell from '@ubeac/svelte/components/Table/TableCell.svelte'

let todos: any[] = []
let loadingBar: any

async function fetchData() {
loadingBar.start()
todos = await fetch('https://jsonplaceholder.typicode.com/todos').then((res) => res.json())
loadingBar.done()
}
</script>

<Button on:click={fetchData}>Fetch Data</Button>

<Card>
<AppLoadingBar indeterminate bind:this={loadingBar} />
<Table>
<TableHead>
<TableCell>User ID</TableCell>
<TableCell>ID</TableCell>
<TableCell>Title</TableCell>
<TableCell>Completed</TableCell>
</TableHead>
<TableBody>
{#each todos.splice(0, 10) as todo}
<TableRow>
<TableCell>{todo.userId}</TableCell>
<TableCell>{todo.id}</TableCell>
<TableCell>{todo.title}</TableCell>
<TableCell>{todo.completed}</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
</Card>
5 changes: 5 additions & 0 deletions src/routes/docs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export const navigations = [
title: 'Alert',
icon: 'star',
},
{
route: base_component_path + 'app-loading-bars',
title: 'AppLoadingBar',
icon: 'star',
},
{
route: base_component_path + 'autocompletes',
title: 'Autocomplete',
Expand Down
Loading