2022-09-06 01:51:57 +00:00
|
|
|
import {theme} from 'app/client/ui2018/cssVars';
|
2024-05-17 19:14:34 +00:00
|
|
|
import {DomArg, keyframes, Observable, observable, styled} from 'grainjs';
|
2020-10-02 15:10:00 +00:00
|
|
|
|
|
|
|
const rotate360 = keyframes(`
|
|
|
|
from { transform: rotate(45deg); }
|
|
|
|
75% { transform: rotate(405deg); }
|
|
|
|
to { transform: rotate(405deg); }
|
|
|
|
`);
|
|
|
|
|
2022-08-11 15:09:03 +00:00
|
|
|
const flash = keyframes(`
|
|
|
|
0% {
|
2022-09-06 01:51:57 +00:00
|
|
|
background-color: ${theme.loaderFg};
|
2022-08-11 15:09:03 +00:00
|
|
|
}
|
|
|
|
50%, 100% {
|
2022-09-06 01:51:57 +00:00
|
|
|
background-color: ${theme.loaderBg};
|
2022-08-11 15:09:03 +00:00
|
|
|
}
|
|
|
|
`);
|
|
|
|
|
2020-10-02 15:10:00 +00:00
|
|
|
/**
|
|
|
|
* Creates a 32x32 pixel loading spinner. Use by calling `loadingSpinner()`.
|
|
|
|
*/
|
|
|
|
export const loadingSpinner = styled('div', `
|
|
|
|
display: inline-block;
|
|
|
|
box-sizing: border-box;
|
|
|
|
width: 32px;
|
|
|
|
height: 32px;
|
|
|
|
border-radius: 32px;
|
2022-09-06 01:51:57 +00:00
|
|
|
border: 4px solid ${theme.loaderBg};
|
|
|
|
border-top-color: ${theme.loaderFg};
|
2020-10-02 15:10:00 +00:00
|
|
|
animation: ${rotate360} 1s ease-out infinite;
|
|
|
|
`);
|
2022-08-11 15:09:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a three-dots loading animation. Use by calling `loadingDots()`.
|
|
|
|
*/
|
|
|
|
export function loadingDots(...args: DomArg<HTMLDivElement>[]) {
|
|
|
|
return cssLoadingDotsContainer(
|
|
|
|
cssLoadingDot(cssLoadingDot.cls('-left')),
|
|
|
|
cssLoadingDot(cssLoadingDot.cls('-middle')),
|
|
|
|
cssLoadingDot(cssLoadingDot.cls('-right')),
|
|
|
|
...args,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-05-17 19:14:34 +00:00
|
|
|
export function watchPromise<T extends (...args: any[]) => any>(fun: T): T & {busy: Observable<boolean>} {
|
|
|
|
const loading = observable(false);
|
|
|
|
const result = async (...args: any) => {
|
|
|
|
loading.set(true);
|
|
|
|
try {
|
|
|
|
return await fun(...args);
|
|
|
|
} finally {
|
|
|
|
if (!loading.isDisposed()) {
|
|
|
|
loading.set(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return Object.assign(result, {busy: loading}) as any;
|
|
|
|
}
|
|
|
|
|
2022-08-11 15:09:03 +00:00
|
|
|
const cssLoadingDotsContainer = styled('div', `
|
|
|
|
--dot-size: 10px;
|
|
|
|
display: inline-flex;
|
|
|
|
column-gap: calc(var(--dot-size) / 2);
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssLoadingDot = styled('div', `
|
|
|
|
border-radius: 50%;
|
|
|
|
width: var(--dot-size);
|
|
|
|
height: var(--dot-size);
|
2022-09-06 01:51:57 +00:00
|
|
|
background-color: ${theme.loaderFg};
|
|
|
|
color: ${theme.loaderFg};
|
2022-08-11 15:09:03 +00:00
|
|
|
animation: ${flash} 1s alternate infinite;
|
|
|
|
|
|
|
|
&-left {
|
|
|
|
animation-delay: 0s;
|
|
|
|
}
|
|
|
|
&-middle {
|
|
|
|
animation-delay: 0.25s;
|
|
|
|
}
|
|
|
|
&-right {
|
|
|
|
animation-delay: 0.5s;
|
|
|
|
}
|
|
|
|
`);
|