feat(Layout): add loading spinner component and to layout
Reusable spinner component Apply spinner to layout to show a "loading state" between transitions, the spinner only shows if the transition is taking more than .2 secconds
This commit is contained in:
parent
d770f51948
commit
a1528a2ad8
3 changed files with 109 additions and 1 deletions
|
|
@ -102,3 +102,7 @@ li:not(:last-child) {
|
|||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.d-none {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
63
src/components/Spinner.astro
Normal file
63
src/components/Spinner.astro
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
interface Props {
|
||||
size?: number;
|
||||
color?: string;
|
||||
bgColor?: string;
|
||||
}
|
||||
|
||||
const {size = 200, color= "#cad3f5", bgColor} = Astro.props;
|
||||
---
|
||||
|
||||
<div class="spinner">
|
||||
<div class="container">
|
||||
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path class="animation animation-normal" d="M4 24C4 35.0457 12.9543 44 24 44V44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4" stroke={color} stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path class="animation animation-reverse" d="M36 24C36 17.3726 30.6274 12 24 12C17.3726 12 12 17.3726 12 24C12 30.6274 17.3726 36 24 36V36" stroke={color} stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<style define:vars={{size: `${size}px`, bgColor: bgColor ?? "var(--prj-bg)"}}>
|
||||
.spinner {
|
||||
background: var(--bgColor);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 10px 0px -10px 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: var(--size);
|
||||
}
|
||||
|
||||
.animation {
|
||||
animation: rotate 1.5s linear infinite;
|
||||
transform-box: fill-box;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.animation-normal {
|
||||
animation-direction: normal;
|
||||
}
|
||||
|
||||
.animation-reverse {
|
||||
animation-direction: reverse;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,9 +4,11 @@ export interface Props {
|
|||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
import '../assets/style/global.css';
|
||||
import Navbar from '../components/Navbar.astro';
|
||||
import Spinner from '../components/Spinner.astro';
|
||||
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
|
@ -28,12 +30,51 @@ import Navbar from '../components/Navbar.astro';
|
|||
<Navbar />
|
||||
</header>
|
||||
<main transition:animate="fade">
|
||||
<div id="layout-loading-spinner" class="d-none">
|
||||
<Spinner />
|
||||
</div>
|
||||
<slot />
|
||||
</main>
|
||||
<style>
|
||||
header > :global(*) {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
body > main {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Position spinner in the center of the screen instead of the center of it's parent */
|
||||
/* This is because the height of the main div can change */
|
||||
/* but we still want the background to hide the content */
|
||||
#layout-loading-spinner :global(.spinner) :global(svg) {
|
||||
position: fixed;
|
||||
width: 200px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
document.addEventListener('astro:before-preparation', (ev) => {
|
||||
const originalLoader = ev.loader;
|
||||
ev.loader = async function () {
|
||||
const spinner = document.querySelector('#layout-loading-spinner');
|
||||
|
||||
// Only show the animation if page load is > than timeout seconds
|
||||
const timeoutId = setTimeout(
|
||||
() => spinner.classList.remove('d-none'),
|
||||
200,
|
||||
);
|
||||
|
||||
await originalLoader();
|
||||
|
||||
// cancel timeout if is not run yet
|
||||
clearTimeout(timeoutId);
|
||||
// spinner.classList.add('d-none');
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue