Files
sigpro-ui/docs/components/indicator.md
2026-04-03 23:54:11 +02:00

284 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
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.
# Indicator
Indicator component for adding badges, status markers, or notifications to elements. Perfect for showing counts, online status, or alerts.
## Tag
`Indicator`
## Props
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `value` | `string \| VNode \| Signal` | `-` | Content to display as indicator |
| `class` | `string` | `''` | Additional CSS classes for the badge |
| `children` | `VNode` | `-` | Element to attach the indicator to |
## Styling
Indicator uses **daisyUI Indicator and Badge classes**:
| Category | Keywords | Description |
| :--- | :--- | :--- |
| Position | `indicator-start`, `indicator-end`, `indicator-top`, `indicator-bottom` | Indicator position (default: top-end) |
| Badge Color | `badge-primary`, `badge-secondary`, `badge-accent`, `badge-info`, `badge-success`, `badge-warning`, `badge-error` | Badge visual variants |
| Badge Size | `badge-xs`, `badge-sm`, `badge-md`, `badge-lg` | Badge scale |
> For further details, check the [daisyUI Indicator Documentation](https://daisyui.com/components/indicator) Full reference for CSS classes.
### Example
```javascript
Indicator({ value: "3", class: "badge-primary" },
Button({ class: "btn" }, "Notifications")
);
```
## Live Examples
### Basic Indicator
<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"></div>
</div>
</div>
```javascript
const BasicDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
Indicator({ value: '3', class: 'badge-primary' },
Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '📦')
),
Indicator({ value: '99+', class: 'badge-secondary' },
Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔')
),
Indicator({ value: 'New', class: 'badge-accent' },
Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '✨')
)
]);
};
$mount(BasicDemo, '#demo-basic');
```
### Online Status Indicator
<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-status" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-wrap gap-8 justify-center"></div>
</div>
</div>
```javascript
const StatusDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
Indicator({ value: '●', class: 'badge-success badge-xs' },
Div({ class: 'avatar placeholder' }, [
Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JD')
])
),
Indicator({ value: '●', class: 'badge-warning badge-xs' },
Div({ class: 'avatar placeholder' }, [
Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JS')
])
),
Indicator({ value: '●', class: 'badge-error badge-xs' },
Div({ class: 'avatar placeholder' }, [
Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'BC')
])
)
]);
};
$mount(StatusDemo, '#demo-status');
```
### Reactive Counter
<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 flex flex-col gap-4 items-center"></div>
</div>
</div>
```javascript
const ReactiveDemo = () => {
const count = $(0);
return Div({ class: 'flex flex-col gap-4 items-center' }, [
Indicator({
value: () => count() > 0 ? count() : null,
class: 'badge-primary'
},
Button({
class: 'btn btn-lg btn-primary',
onclick: () => count(count() + 1)
}, 'Notifications')
),
Div({ class: 'flex gap-2' }, [
Button({
class: 'btn btn-sm',
onclick: () => count(Math.max(0, count() - 1))
}, 'Decrease'),
Button({
class: 'btn btn-sm btn-ghost',
onclick: () => count(0)
}, 'Clear')
])
]);
};
$mount(ReactiveDemo, '#demo-reactive');
```
### Shopping Cart
<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-cart" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const CartDemo = () => {
const cart = $([
{ id: 1, name: 'Product 1', price: 29 },
{ id: 2, name: 'Product 2', price: 49 }
]);
const addItem = () => {
const newId = Math.max(...cart().map(i => i.id), 0) + 1;
cart([...cart(), { id: newId, name: `Product ${newId}`, price: Math.floor(Math.random() * 100) + 10 }]);
Toast('Item added to cart', 'alert-success', 1500);
};
const removeItem = (id) => {
cart(cart().filter(item => item.id !== id));
Toast('Item removed', 'alert-info', 1500);
};
const total = () => cart().reduce((sum, item) => sum + item.price, 0);
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex justify-between items-center' }, [
Indicator({
value: () => cart().length,
class: 'badge-primary'
},
Button({ class: 'btn', onclick: addItem }, '🛒 Add to Cart')
),
Span({ class: 'text-lg font-bold' }, () => `Total: $${total()}`)
]),
() => cart().length === 0
? Div({ class: 'alert alert-soft text-center' }, 'Cart is empty')
: Div({ class: 'flex flex-col gap-2' }, cart().map(item =>
Div({ class: 'flex justify-between items-center p-2 bg-base-200 rounded-lg' }, [
Span({}, item.name),
Div({ class: 'flex gap-2 items-center' }, [
Span({ class: 'text-sm font-bold' }, `$${item.price}`),
Button({
class: 'btn btn-xs btn-ghost btn-circle',
onclick: () => removeItem(item.id)
}, '✕')
])
])
))
]);
};
$mount(CartDemo, '#demo-cart');
```
### Email Inbox
<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-inbox" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const InboxDemo = () => {
const unread = $(3);
const messages = $([
{ id: 1, from: 'john@example.com', subject: 'Meeting tomorrow', read: false },
{ id: 2, from: 'jane@example.com', subject: 'Project update', read: false },
{ id: 3, from: 'bob@example.com', subject: 'Question about design', read: false },
{ id: 4, from: 'alice@example.com', subject: 'Weekly report', read: true }
]);
const markAsRead = (id) => {
const msg = messages().find(m => m.id === id);
if (!msg.read) {
msg.read = true;
messages([...messages()]);
unread(unread() - 1);
}
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex justify-between items-center' }, [
Indicator({
value: () => unread(),
class: 'badge-primary'
},
Span({ class: 'text-lg font-bold' }, 'Inbox')
),
Button({
class: 'btn btn-sm btn-ghost',
onclick: () => {
messages().forEach(m => m.read = true);
messages([...messages()]);
unread(0);
}
}, 'Mark all read')
]),
Div({ class: 'flex flex-col gap-2' }, () => messages().map(msg =>
Div({
class: `p-3 rounded-lg cursor-pointer transition-all ${msg.read ? 'bg-base-200 opacity-60' : 'bg-primary/10 border-l-4 border-primary'}`,
onclick: () => markAsRead(msg.id)
}, [
Div({ class: 'font-medium' }, msg.from),
Div({ class: 'text-sm' }, msg.subject),
!msg.read && Span({ class: 'badge badge-xs badge-primary mt-1' }, 'New')
])
))
]);
};
$mount(InboxDemo, '#demo-inbox');
```
### 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-wrap gap-8 justify-center"></div>
</div>
</div>
```javascript
const VariantsDemo = () => {
return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
Indicator({ value: '3', class: 'badge-primary badge-sm' },
Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '📧')
),
Indicator({ value: '99+', class: 'badge-secondary badge-md' },
Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔')
),
Indicator({ value: '●', class: 'badge-success badge-xs' },
Div({ class: 'avatar' }, [
Div({ class: 'w-10 h-10 rounded-full bg-primary' })
])
),
Indicator({ value: '!', class: 'badge-error badge-sm' },
Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '⚠️')
)
]);
};
$mount(VariantsDemo, '#demo-variants');
```