Files
sigpro-ui/docs/components/alert.md
2026-04-01 00:01:35 +02:00

522 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Alert
Alert component for displaying contextual messages, notifications, and feedback with different severity levels. Supports soft and solid variants.
## Tag
`Alert`
## Props
| Prop | Type | Default | Description |
| :----------- | :--------------------------- | :---------- | :----------------------------------------------- |
| `type` | `string` | `'info'` | Alert type: 'info', 'success', 'warning', 'error' |
| `soft` | `boolean \| Signal<boolean>` | `true` | Use soft variant (subtle background) |
| `actions` | `VNode \| function` | `-` | Optional action buttons or content |
| `message` | `string \| VNode \| Signal` | `-` | Alert message content |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
| `children` | `string \| VNode` | `-` | Alert content (alternative to `message`) |
## Live Examples
### Basic Alerts
<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-col gap-3"></div>
</div>
</div>
```javascript
const BasicDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: 'This is an informational message.' }),
Alert({ type: 'success', message: 'Operation completed successfully!' }),
Alert({ type: 'warning', message: 'Please review your input before proceeding.' }),
Alert({ type: 'error', message: 'An error occurred while processing your request.' })
]);
};
$mount(BasicDemo, '#demo-basic');
```
### Soft vs Solid 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-3"></div>
</div>
</div>
```javascript
const VariantsDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', soft: true, message: 'Soft info alert (default)' }),
Alert({ type: 'info', soft: false, message: 'Solid info alert' }),
Alert({ type: 'success', soft: true, message: 'Soft success alert' }),
Alert({ type: 'success', soft: false, message: 'Solid success alert' })
]);
};
$mount(VariantsDemo, '#demo-variants');
```
### With Actions
<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-actions" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const ActionsDemo = () => {
const showUndo = $(false);
const deletedItem = $(null);
const deleteItem = (item) => {
deletedItem(item);
showUndo(true);
setTimeout(() => {
if (showUndo()) {
showUndo(false);
Toast('Item permanently deleted', 'alert-info', 2000);
}
}, 5000);
};
const undoDelete = () => {
showUndo(false);
Toast(`Restored: ${deletedItem()}`, 'alert-success', 2000);
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2' }, [
Button({ class: 'btn btn-sm', onclick: () => deleteItem('Document A') }, 'Delete Document A'),
Button({ class: 'btn btn-sm', onclick: () => deleteItem('Document B') }, 'Delete Document B')
]),
() => showUndo() ? Alert({
type: 'warning',
soft: true,
message: `Deleted: ${deletedItem()}`,
actions: Button({
class: 'btn btn-sm btn-primary',
onclick: undoDelete
}, 'Undo')
}) : null
]);
};
$mount(ActionsDemo, '#demo-actions');
```
### Dismissible Alert
<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-dismissible" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const DismissibleDemo = () => {
const visible = $(true);
return Div({ class: 'flex flex-col gap-3' }, [
() => visible() ? Alert({
type: 'info',
message: 'This alert can be dismissed. Click the X button to close.',
actions: Button({
class: 'btn btn-xs btn-circle btn-ghost',
onclick: () => visible(false)
}, '✕')
}) : null,
() => !visible() ? Button({
class: 'btn btn-sm btn-ghost',
onclick: () => visible(true)
}, 'Show Alert') : null
]);
};
$mount(DismissibleDemo, '#demo-dismissible');
```
### Reactive Alert
<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-reactive" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ReactiveDemo = () => {
const email = $('');
const error = $('');
const validateEmail = (value) => {
email(value);
if (value && !value.includes('@')) {
error('Please enter a valid email address');
} else {
error('');
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Input({
label: 'Email Address',
placeholder: 'Enter your email',
value: email,
oninput: (e) => validateEmail(e.target.value)
}),
() => error() ? Alert({ type: 'error', message: error() }) : null,
() => email() && !error() ? Alert({
type: 'success',
message: `Valid email: ${email()}`
}) : null
]);
};
$mount(ReactiveDemo, '#demo-reactive');
```
### Form Validation
<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-form" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const FormDemo = () => {
const name = $('');
const email = $('');
const submitted = $(false);
const errors = $({ name: '', email: '' });
const validate = () => {
const newErrors = {
name: name().trim() ? '' : 'Name is required',
email: email().trim() ? (email().includes('@') ? '' : 'Invalid email') : 'Email is required'
};
errors(newErrors);
return !newErrors.name && !newErrors.email;
};
const handleSubmit = () => {
if (validate()) {
submitted(true);
setTimeout(() => submitted(false), 3000);
Toast('Form submitted successfully!', 'alert-success', 2000);
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'text-lg font-bold' }, 'Contact Form'),
Input({
label: 'Name',
value: name,
error: () => errors().name,
oninput: (e) => {
name(e.target.value);
validate();
}
}),
Input({
label: 'Email',
value: email,
error: () => errors().email,
oninput: (e) => {
email(e.target.value);
validate();
}
}),
Button({ class: 'btn btn-primary', onclick: handleSubmit }, 'Submit'),
() => submitted() ? Alert({
type: 'success',
message: 'Thank you! We will contact you soon.'
}) : null,
() => (errors().name || errors().email) ? Alert({
type: 'error',
message: 'Please fix the errors above before submitting.'
}) : null
]);
};
$mount(FormDemo, '#demo-form');
```
### Icon Alerts
<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-icons" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const IconsDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: 'Information alert with custom icon' }),
Alert({ type: 'success', message: 'Success alert with custom icon' }),
Alert({ type: 'warning', message: 'Warning alert with custom icon' }),
Alert({ type: 'error', message: 'Error alert with custom icon' })
]);
};
$mount(IconsDemo, '#demo-icons');
```
### All Types
<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-all" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const AllTypesDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: ' This is an info alert' }),
Alert({ type: 'success', message: '✅ This is a success alert' }),
Alert({ type: 'warning', message: '⚠️ This is a warning alert' }),
Alert({ type: 'error', message: '❌ This is an error alert' })
]);
};
$mount(AllTypesDemo, '#demo-all');
```
<script>
(function() {
const initAlertExamples = () => {
// 1. Basic Alerts
const basicTarget = document.querySelector('#demo-basic');
if (basicTarget && !basicTarget.hasChildNodes()) {
const BasicDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: 'This is an informational message.' }),
Alert({ type: 'success', message: 'Operation completed successfully!' }),
Alert({ type: 'warning', message: 'Please review your input before proceeding.' }),
Alert({ type: 'error', message: 'An error occurred while processing your request.' })
]);
};
$mount(BasicDemo, basicTarget);
}
// 2. Soft vs Solid Variants
const variantsTarget = document.querySelector('#demo-variants');
if (variantsTarget && !variantsTarget.hasChildNodes()) {
const VariantsDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', soft: true, message: 'Soft info alert (default)' }),
Alert({ type: 'info', soft: false, message: 'Solid info alert' }),
Alert({ type: 'success', soft: true, message: 'Soft success alert' }),
Alert({ type: 'success', soft: false, message: 'Solid success alert' })
]);
};
$mount(VariantsDemo, variantsTarget);
}
// 3. With Actions
const actionsTarget = document.querySelector('#demo-actions');
if (actionsTarget && !actionsTarget.hasChildNodes()) {
const ActionsDemo = () => {
const showUndo = $(false);
const deletedItem = $(null);
const deleteItem = (item) => {
deletedItem(item);
showUndo(true);
setTimeout(() => {
if (showUndo()) {
showUndo(false);
Toast('Item permanently deleted', 'alert-info', 2000);
}
}, 5000);
};
const undoDelete = () => {
showUndo(false);
Toast(`Restored: ${deletedItem()}`, 'alert-success', 2000);
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2' }, [
Button({ class: 'btn btn-sm', onclick: () => deleteItem('Document A') }, 'Delete Document A'),
Button({ class: 'btn btn-sm', onclick: () => deleteItem('Document B') }, 'Delete Document B')
]),
() => showUndo() ? Alert({
type: 'warning',
soft: true,
message: `Deleted: ${deletedItem()}`,
actions: Button({
class: 'btn btn-sm btn-primary',
onclick: undoDelete
}, 'Undo')
}) : null
]);
};
$mount(ActionsDemo, actionsTarget);
}
// 4. Dismissible Alert
const dismissibleTarget = document.querySelector('#demo-dismissible');
if (dismissibleTarget && !dismissibleTarget.hasChildNodes()) {
const DismissibleDemo = () => {
const visible = $(true);
return Div({ class: 'flex flex-col gap-3' }, [
() => visible() ? Alert({
type: 'info',
message: 'This alert can be dismissed. Click the X button to close.',
actions: Button({
class: 'btn btn-xs btn-circle btn-ghost',
onclick: () => visible(false)
}, '✕')
}) : null,
() => !visible() ? Button({
class: 'btn btn-sm btn-ghost',
onclick: () => visible(true)
}, 'Show Alert') : null
]);
};
$mount(DismissibleDemo, dismissibleTarget);
}
// 5. Reactive Alert
const reactiveTarget = document.querySelector('#demo-reactive');
if (reactiveTarget && !reactiveTarget.hasChildNodes()) {
const ReactiveDemo = () => {
const email = $('');
const error = $('');
const validateEmail = (value) => {
email(value);
if (value && !value.includes('@')) {
error('Please enter a valid email address');
} else {
error('');
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Input({
label: 'Email Address',
placeholder: 'Enter your email',
value: email,
oninput: (e) => validateEmail(e.target.value)
}),
() => error() ? Alert({ type: 'error', message: error() }) : null,
() => email() && !error() ? Alert({
type: 'success',
message: `Valid email: ${email()}`
}) : null
]);
};
$mount(ReactiveDemo, reactiveTarget);
}
// 6. Form Validation
const formTarget = document.querySelector('#demo-form');
if (formTarget && !formTarget.hasChildNodes()) {
const FormDemo = () => {
const name = $('');
const email = $('');
const submitted = $(false);
const errors = $({ name: '', email: '' });
const validate = () => {
const newErrors = {
name: name().trim() ? '' : 'Name is required',
email: email().trim() ? (email().includes('@') ? '' : 'Invalid email') : 'Email is required'
};
errors(newErrors);
return !newErrors.name && !newErrors.email;
};
const handleSubmit = () => {
if (validate()) {
submitted(true);
setTimeout(() => submitted(false), 3000);
Toast('Form submitted successfully!', 'alert-success', 2000);
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'text-lg font-bold' }, 'Contact Form'),
Input({
label: 'Name',
value: name,
error: () => errors().name,
oninput: (e) => {
name(e.target.value);
validate();
}
}),
Input({
label: 'Email',
value: email,
error: () => errors().email,
oninput: (e) => {
email(e.target.value);
validate();
}
}),
Button({ class: 'btn btn-primary', onclick: handleSubmit }, 'Submit'),
() => submitted() ? Alert({
type: 'success',
message: 'Thank you! We will contact you soon.'
}) : null,
() => (errors().name || errors().email) ? Alert({
type: 'error',
message: 'Please fix the errors above before submitting.'
}) : null
]);
};
$mount(FormDemo, formTarget);
}
// 7. Icon Alerts
const iconsTarget = document.querySelector('#demo-icons');
if (iconsTarget && !iconsTarget.hasChildNodes()) {
const IconsDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: 'Information alert with custom icon' }),
Alert({ type: 'success', message: 'Success alert with custom icon' }),
Alert({ type: 'warning', message: 'Warning alert with custom icon' }),
Alert({ type: 'error', message: 'Error alert with custom icon' })
]);
};
$mount(IconsDemo, iconsTarget);
}
// 8. All Types
const allTarget = document.querySelector('#demo-all');
if (allTarget && !allTarget.hasChildNodes()) {
const AllTypesDemo = () => {
return Div({ class: 'flex flex-col gap-3' }, [
Alert({ type: 'info', message: ' This is an info alert' }),
Alert({ type: 'success', message: '✅ This is a success alert' }),
Alert({ type: 'warning', message: '⚠️ This is a warning alert' }),
Alert({ type: 'error', message: '❌ This is an error alert' })
]);
};
$mount(AllTypesDemo, allTarget);
}
};
initAlertExamples();
if (window.$docsify) {
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
hook.doneEach(initAlertExamples);
});
}
})();
</script>