Files
sigpro-ui/docs/components_old/loading.md
2026-04-02 19:31:39 +02:00

598 lines
21 KiB
Markdown

# Loading
Loading spinner component for indicating loading states with customizable size and colors.
## Tag
`Loading`
## Props
| Prop | Type | Default | Description |
| :----------- | :--------------------------- | :--------------- | :----------------------------------------------- |
| `$show` | `boolean \| Signal<boolean>` | `true` | Show/hide the loading spinner |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI loading variants)|
## Live Examples
### Basic Loading
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-wrap gap-8 justify-center items-center"></div>
</div>
</div>
```javascript
const BasicDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Loading({ $show: true, class: 'loading-spinner' }),
Loading({ $show: true, class: 'loading-dots' }),
Loading({ $show: true, class: 'loading-ring' }),
Loading({ $show: true, class: 'loading-ball' }),
Loading({ $show: true, class: 'loading-bars' }),
Loading({ $show: true, class: 'loading-infinity' })
]);
};
$mount(BasicDemo, '#demo-basic');
```
### Loading Sizes
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-sizes" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-wrap gap-8 justify-center items-center"></div>
</div>
</div>
```javascript
const SizesDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-xs' }),
Div({ class: 'text-xs mt-2' }, 'Extra Small')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-sm' }),
Div({ class: 'text-xs mt-2' }, 'Small')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-md' }),
Div({ class: 'text-xs mt-2' }, 'Medium')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-lg' }),
Div({ class: 'text-xs mt-2' }, 'Large')
])
]);
};
$mount(SizesDemo, '#demo-sizes');
```
### Loading Colors
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-colors" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-wrap gap-8 justify-center items-center"></div>
</div>
</div>
```javascript
const ColorsDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Loading({ $show: true, class: 'loading-spinner text-primary' }),
Loading({ $show: true, class: 'loading-spinner text-secondary' }),
Loading({ $show: true, class: 'loading-spinner text-accent' }),
Loading({ $show: true, class: 'loading-spinner text-info' }),
Loading({ $show: true, class: 'loading-spinner text-success' }),
Loading({ $show: true, class: 'loading-spinner text-warning' }),
Loading({ $show: true, class: 'loading-spinner text-error' })
]);
};
$mount(ColorsDemo, '#demo-colors');
```
### Button Loading State
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-button" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-4 items-center"></div>
</div>
</div>
```javascript
const ButtonDemo = () => {
const isLoading = $(false);
const handleClick = async () => {
isLoading(true);
await new Promise(resolve => setTimeout(resolve, 2000));
isLoading(false);
Toast('Operation completed!', 'alert-success', 2000);
};
return Div({ class: 'flex flex-col gap-4 items-center' }, [
Button({
class: 'btn btn-primary',
loading: isLoading,
onclick: handleClick
}, 'Submit'),
Div({ class: 'text-sm opacity-70' }, 'Click the button to see loading state')
]);
};
$mount(ButtonDemo, '#demo-button');
```
### Async Data Loading
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-async" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const AsyncDemo = () => {
const loading = $(false);
const data = $(null);
const error = $(null);
const loadData = async () => {
loading(true);
error(null);
data(null);
try {
await new Promise(resolve => setTimeout(resolve, 2000));
const result = {
users: 1234,
posts: 5678,
comments: 9012
};
data(result);
Toast('Data loaded successfully!', 'alert-success', 2000);
} catch (err) {
error('Failed to load data');
Toast('Error loading data', 'alert-error', 2000);
} finally {
loading(false);
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex justify-center' }, [
Button({
class: 'btn btn-primary',
onclick: loadData,
disabled: () => loading()
}, loading() ? 'Loading...' : 'Load Data')
]),
Div({ class: 'relative min-h-[200px] flex items-center justify-center' }, [
() => loading() ? Loading({ $show: true, class: 'loading-spinner loading-lg' }) : null,
() => data() ? Div({ class: 'grid grid-cols-3 gap-4 w-full' }, [
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Users'),
Div({ class: 'stat-value' }, data().users)
]),
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Posts'),
Div({ class: 'stat-value' }, data().posts)
]),
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Comments'),
Div({ class: 'stat-value' }, data().comments)
])
]) : null,
() => error() ? Alert({ type: 'error', message: error() }) : null
])
]);
};
$mount(AsyncDemo, '#demo-async');
```
### Full Page Loading
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-fullpage" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const FullpageDemo = () => {
const isLoading = $(false);
const simulatePageLoad = () => {
isLoading(true);
setTimeout(() => {
isLoading(false);
Toast('Page loaded!', 'alert-success', 2000);
}, 2000);
};
return Div({ class: 'relative' }, [
Div({ class: 'flex justify-center p-8' }, [
Button({
class: 'btn btn-primary',
onclick: simulatePageLoad
}, 'Simulate Page Load')
]),
() => isLoading() ? Loading({ $show: true, class: 'loading-spinner loading-lg' }) : null
]);
};
$mount(FullpageDemo, '#demo-fullpage');
```
### Conditional Loading
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-conditional" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ConditionalDemo = () => {
const loadingState = $('idle');
const content = $('');
const simulateAction = (action) => {
loadingState('loading');
setTimeout(() => {
content(`Action: ${action} completed at ${new Date().toLocaleTimeString()}`);
loadingState('success');
setTimeout(() => loadingState('idle'), 1500);
}, 1500);
};
const loadingStates = {
idle: null,
loading: Loading({ $show: true, class: 'loading-spinner text-primary' }),
success: Alert({ type: 'success', message: '✓ Done!' })
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2 justify-center' }, [
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Save')
}, 'Save'),
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Update')
}, 'Update'),
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Delete')
}, 'Delete')
]),
Div({ class: 'flex justify-center min-h-[100px] items-center' }, [
() => loadingStates[loadingState()],
() => content() && loadingState() === 'idle' ? Div({ class: 'text-center' }, content()) : null
])
]);
};
$mount(ConditionalDemo, '#demo-conditional');
```
### All Variants
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-6"></div>
</div>
</div>
```javascript
const VariantsDemo = () => {
return Div({ class: 'flex flex-col gap-6' }, [
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Spinner'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-xs' }),
Loading({ $show: true, class: 'loading-spinner loading-sm' }),
Loading({ $show: true, class: 'loading-spinner loading-md' }),
Loading({ $show: true, class: 'loading-spinner loading-lg' })
])
]),
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Dots'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-dots loading-xs' }),
Loading({ $show: true, class: 'loading-dots loading-sm' }),
Loading({ $show: true, class: 'loading-dots loading-md' }),
Loading({ $show: true, class: 'loading-dots loading-lg' })
])
]),
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Ring'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-ring loading-xs' }),
Loading({ $show: true, class: 'loading-ring loading-sm' }),
Loading({ $show: true, class: 'loading-ring loading-md' }),
Loading({ $show: true, class: 'loading-ring loading-lg' })
])
])
]);
};
$mount(VariantsDemo, '#demo-variants');
```
<script>
(function() {
const initLoadingExamples = () => {
// 1. Basic Loading
const basicTarget = document.querySelector('#demo-basic');
if (basicTarget && !basicTarget.hasChildNodes()) {
const BasicDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Loading({ $show: true, class: 'loading-spinner' }),
Loading({ $show: true, class: 'loading-dots' }),
Loading({ $show: true, class: 'loading-ring' }),
Loading({ $show: true, class: 'loading-ball' }),
Loading({ $show: true, class: 'loading-bars' }),
Loading({ $show: true, class: 'loading-infinity' })
]);
};
$mount(BasicDemo, basicTarget);
}
// 2. Loading Sizes
const sizesTarget = document.querySelector('#demo-sizes');
if (sizesTarget && !sizesTarget.hasChildNodes()) {
const SizesDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-xs' }),
Div({ class: 'text-xs mt-2' }, 'Extra Small')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-sm' }),
Div({ class: 'text-xs mt-2' }, 'Small')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-md' }),
Div({ class: 'text-xs mt-2' }, 'Medium')
]),
Div({ class: 'text-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-lg' }),
Div({ class: 'text-xs mt-2' }, 'Large')
])
]);
};
$mount(SizesDemo, sizesTarget);
}
// 3. Loading Colors
const colorsTarget = document.querySelector('#demo-colors');
if (colorsTarget && !colorsTarget.hasChildNodes()) {
const ColorsDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center items-center' }, [
Loading({ $show: true, class: 'loading-spinner text-primary' }),
Loading({ $show: true, class: 'loading-spinner text-secondary' }),
Loading({ $show: true, class: 'loading-spinner text-accent' }),
Loading({ $show: true, class: 'loading-spinner text-info' }),
Loading({ $show: true, class: 'loading-spinner text-success' }),
Loading({ $show: true, class: 'loading-spinner text-warning' }),
Loading({ $show: true, class: 'loading-spinner text-error' })
]);
};
$mount(ColorsDemo, colorsTarget);
}
// 4. Button Loading State
const buttonTarget = document.querySelector('#demo-button');
if (buttonTarget && !buttonTarget.hasChildNodes()) {
const ButtonDemo = () => {
const isLoading = $(false);
const handleClick = async () => {
isLoading(true);
await new Promise(resolve => setTimeout(resolve, 2000));
isLoading(false);
Toast('Operation completed!', 'alert-success', 2000);
};
return Div({ class: 'flex flex-col gap-4 items-center' }, [
Button({
class: 'btn btn-primary',
loading: isLoading,
onclick: handleClick
}, 'Submit'),
Div({ class: 'text-sm opacity-70' }, 'Click the button to see loading state')
]);
};
$mount(ButtonDemo, buttonTarget);
}
// 5. Async Data Loading
const asyncTarget = document.querySelector('#demo-async');
if (asyncTarget && !asyncTarget.hasChildNodes()) {
const AsyncDemo = () => {
const loading = $(false);
const data = $(null);
const error = $(null);
const loadData = async () => {
loading(true);
error(null);
data(null);
try {
await new Promise(resolve => setTimeout(resolve, 2000));
const result = {
users: 1234,
posts: 5678,
comments: 9012
};
data(result);
Toast('Data loaded successfully!', 'alert-success', 2000);
} catch (err) {
error('Failed to load data');
Toast('Error loading data', 'alert-error', 2000);
} finally {
loading(false);
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex justify-center' }, [
Button({
class: 'btn btn-primary',
onclick: loadData,
disabled: () => loading()
}, loading() ? 'Loading...' : 'Load Data')
]),
Div({ class: 'relative min-h-[200px] flex items-center justify-center' }, [
() => loading() ? Loading({ $show: true, class: 'loading-spinner loading-lg' }) : null,
() => data() ? Div({ class: 'grid grid-cols-3 gap-4 w-full' }, [
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Users'),
Div({ class: 'stat-value' }, data().users)
]),
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Posts'),
Div({ class: 'stat-value' }, data().posts)
]),
Div({ class: 'stat' }, [
Div({ class: 'stat-title' }, 'Comments'),
Div({ class: 'stat-value' }, data().comments)
])
]) : null,
() => error() ? Alert({ type: 'error', message: error() }) : null
])
]);
};
$mount(AsyncDemo, asyncTarget);
}
// 6. Full Page Loading
const fullpageTarget = document.querySelector('#demo-fullpage');
if (fullpageTarget && !fullpageTarget.hasChildNodes()) {
const FullpageDemo = () => {
const isLoading = $(false);
const simulatePageLoad = () => {
isLoading(true);
setTimeout(() => {
isLoading(false);
Toast('Page loaded!', 'alert-success', 2000);
}, 2000);
};
return Div({ class: 'relative' }, [
Div({ class: 'flex justify-center p-8' }, [
Button({
class: 'btn btn-primary',
onclick: simulatePageLoad
}, 'Simulate Page Load')
]),
() => isLoading() ? Loading({ $show: true, class: 'loading-spinner loading-lg' }) : null
]);
};
$mount(FullpageDemo, fullpageTarget);
}
// 7. Conditional Loading
const conditionalTarget = document.querySelector('#demo-conditional');
if (conditionalTarget && !conditionalTarget.hasChildNodes()) {
const ConditionalDemo = () => {
const loadingState = $('idle');
const content = $('');
const simulateAction = (action) => {
loadingState('loading');
setTimeout(() => {
content(`Action: ${action} completed at ${new Date().toLocaleTimeString()}`);
loadingState('success');
setTimeout(() => loadingState('idle'), 1500);
}, 1500);
};
const loadingStates = {
idle: null,
loading: Loading({ $show: true, class: 'loading-spinner text-primary' }),
success: Alert({ type: 'success', message: '✓ Done!' })
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2 justify-center' }, [
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Save')
}, 'Save'),
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Update')
}, 'Update'),
Button({
class: 'btn btn-sm',
onclick: () => simulateAction('Delete')
}, 'Delete')
]),
Div({ class: 'flex justify-center min-h-[100px] items-center' }, [
() => loadingStates[loadingState()],
() => content() && loadingState() === 'idle' ? Div({ class: 'text-center' }, content()) : null
])
]);
};
$mount(ConditionalDemo, conditionalTarget);
}
// 8. All Variants
const variantsTarget = document.querySelector('#demo-variants');
if (variantsTarget && !variantsTarget.hasChildNodes()) {
const VariantsDemo = () => {
return Div({ class: 'flex flex-col gap-6' }, [
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Spinner'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-spinner loading-xs' }),
Loading({ $show: true, class: 'loading-spinner loading-sm' }),
Loading({ $show: true, class: 'loading-spinner loading-md' }),
Loading({ $show: true, class: 'loading-spinner loading-lg' })
])
]),
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Dots'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-dots loading-xs' }),
Loading({ $show: true, class: 'loading-dots loading-sm' }),
Loading({ $show: true, class: 'loading-dots loading-md' }),
Loading({ $show: true, class: 'loading-dots loading-lg' })
])
]),
Div({ class: 'text-center' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Ring'),
Div({ class: 'flex gap-4 justify-center' }, [
Loading({ $show: true, class: 'loading-ring loading-xs' }),
Loading({ $show: true, class: 'loading-ring loading-sm' }),
Loading({ $show: true, class: 'loading-ring loading-md' }),
Loading({ $show: true, class: 'loading-ring loading-lg' })
])
])
]);
};
$mount(VariantsDemo, variantsTarget);
}
};
initLoadingExamples();
if (window.$docsify) {
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
hook.doneEach(initLoadingExamples);
});
}
})();
</script>