294 lines
10 KiB
Markdown
294 lines
10 KiB
Markdown
# Timeline
|
||
|
||
Timeline component for displaying chronological events, steps, or progress with customizable icons and content.
|
||
|
||
## Tag
|
||
|
||
`Timeline`
|
||
|
||
## Props
|
||
|
||
| Prop | Type | Default | Description |
|
||
| :--- | :--- | :--- | :--- |
|
||
| `items` | `Array<TimelineItem> \| Signal` | `[]` | Timeline items to display |
|
||
| `vertical` | `boolean \| Signal<boolean>` | `true` | Vertical or horizontal orientation |
|
||
| `compact` | `boolean \| Signal<boolean>` | `false` | Compact mode with less padding |
|
||
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
|
||
|
||
### TimelineItem Structure
|
||
|
||
| Property | Type | Description |
|
||
| :--- | :--- | :--- |
|
||
| `title` | `string \| VNode \| Signal` | Event title or main text |
|
||
| `detail` | `string \| VNode \| Signal` | Additional details or description |
|
||
| `icon` | `string \| VNode` | Custom icon (overrides type) |
|
||
| `type` | `string` | Type: `'success'`, `'warning'`, `'error'`, `'info'` |
|
||
| `completed` | `boolean` | Whether event is completed (affects connector) |
|
||
|
||
## Styling
|
||
|
||
Timeline supports all **daisyUI Timeline classes**:
|
||
|
||
| Category | Keywords | Description |
|
||
| :--- | :--- | :--- |
|
||
| Base | `timeline`, `timeline-vertical`, `timeline-horizontal` | Timeline orientation |
|
||
| Size | `timeline-compact` | Compact spacing variant |
|
||
| Color | `bg-primary`, `bg-success`, `bg-warning`, `bg-error`, `bg-info` | Icon background colors |
|
||
|
||
> For further details, check the [daisyUI Timeline Documentation](https://daisyui.com/components/timeline) – Full reference for CSS classes.
|
||
|
||
## Live Examples
|
||
|
||
### Basic Timeline
|
||
|
||
<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"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const BasicDemo = () => {
|
||
const events = [
|
||
{ title: 'Project Started', detail: 'Initial planning and setup', type: 'info', completed: true },
|
||
{ title: 'Design Phase', detail: 'UI/UX design completed', type: 'success', completed: true },
|
||
{ title: 'Development', detail: 'Core features implemented', type: 'warning', completed: false },
|
||
{ title: 'Testing', detail: 'Quality assurance', type: 'info', completed: false },
|
||
{ title: 'Launch', detail: 'Production deployment', type: 'success', completed: false }
|
||
];
|
||
|
||
return Timeline({ items: events });
|
||
};
|
||
Mount(BasicDemo, '#demo-basic');
|
||
```
|
||
|
||
### Horizontal Timeline
|
||
|
||
<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-horizontal" class="bg-base-100 p-6 rounded-xl border border-base-300 overflow-x-auto"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const HorizontalDemo = () => {
|
||
const steps = [
|
||
{ title: 'Step 1', detail: 'Requirements', type: 'success', completed: true },
|
||
{ title: 'Step 2', detail: 'Design', type: 'success', completed: true },
|
||
{ title: 'Step 3', detail: 'Development', type: 'warning', completed: false },
|
||
{ title: 'Step 4', detail: 'Testing', type: 'info', completed: false },
|
||
{ title: 'Step 5', detail: 'Deploy', type: 'info', completed: false }
|
||
];
|
||
|
||
return Timeline({
|
||
items: steps,
|
||
vertical: false,
|
||
class: 'min-w-[600px]'
|
||
});
|
||
};
|
||
Mount(HorizontalDemo, '#demo-horizontal');
|
||
```
|
||
|
||
### Compact Timeline
|
||
|
||
<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-compact" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const CompactDemo = () => {
|
||
const activities = [
|
||
{ title: 'User login', detail: '10:30 AM', type: 'success', completed: true },
|
||
{ title: 'Viewed dashboard', detail: '10:32 AM', type: 'info', completed: true },
|
||
{ title: 'Updated profile', detail: '10:45 AM', type: 'success', completed: true },
|
||
{ title: 'Made purchase', detail: '11:00 AM', type: 'warning', completed: false }
|
||
];
|
||
|
||
return Timeline({
|
||
items: activities,
|
||
compact: true
|
||
});
|
||
};
|
||
Mount(CompactDemo, '#demo-compact');
|
||
```
|
||
|
||
### Custom Icons
|
||
|
||
<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"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const IconsDemo = () => {
|
||
const milestones = [
|
||
{ title: 'Kickoff', detail: 'Project kickoff meeting', icon: '🚀', completed: true },
|
||
{ title: 'MVP', detail: 'Minimum viable product', icon: '💡', completed: true },
|
||
{ title: 'Beta', detail: 'Beta release', icon: '⚙️', completed: false },
|
||
{ title: 'Launch', detail: 'Public launch', icon: '🎉', completed: false }
|
||
];
|
||
|
||
return Timeline({ items: milestones });
|
||
};
|
||
Mount(IconsDemo, '#demo-icons');
|
||
```
|
||
|
||
### Reactive Timeline
|
||
|
||
<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 currentStep = $(0);
|
||
const steps = [
|
||
{ title: 'Order Placed', detail: 'Your order has been confirmed', type: 'success' },
|
||
{ title: 'Processing', detail: 'Payment verified, preparing shipment', type: 'success' },
|
||
{ title: 'Shipped', detail: 'Package on the way', type: 'warning' },
|
||
{ title: 'Delivered', detail: 'Arriving soon', type: 'info' }
|
||
];
|
||
|
||
const items = () => steps.map((step, idx) => ({
|
||
...step,
|
||
completed: idx < currentStep()
|
||
}));
|
||
|
||
const nextStep = () => {
|
||
if (currentStep() < steps.length) {
|
||
currentStep(currentStep() + 1);
|
||
Toast(`Step ${currentStep()}: ${steps[currentStep() - 1].title}`, 'alert-info', 1500);
|
||
}
|
||
};
|
||
|
||
const reset = () => {
|
||
currentStep(0);
|
||
Toast('Order tracking reset', 'alert-warning', 1500);
|
||
};
|
||
|
||
return Div({ class: 'flex flex-col gap-4' }, [
|
||
Timeline({ items: items }),
|
||
Div({ class: 'flex gap-2 justify-center mt-4' }, [
|
||
Button({
|
||
class: 'btn btn-primary btn-sm',
|
||
onclick: nextStep,
|
||
disabled: () => currentStep() >= steps.length
|
||
}, 'Next Step'),
|
||
Button({
|
||
class: 'btn btn-ghost btn-sm',
|
||
onclick: reset,
|
||
disabled: () => currentStep() === 0
|
||
}, 'Reset')
|
||
])
|
||
]);
|
||
};
|
||
Mount(ReactiveDemo, '#demo-reactive');
|
||
```
|
||
|
||
### Order Status Tracker
|
||
|
||
<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-order" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const OrderDemo = () => {
|
||
const status = $('pending'); // ← empezar en 'pending'
|
||
|
||
const statusMap = {
|
||
pending: { title: 'Order Pending', detail: 'Awaiting confirmation', type: 'warning' },
|
||
confirmed: { title: 'Order Confirmed', detail: 'Payment received', type: 'info' },
|
||
processing: { title: 'Processing', detail: 'Preparing your order', type: 'info' },
|
||
shipped: { title: 'Shipped', detail: 'Package in transit', type: 'info' },
|
||
delivered: { title: 'Delivered', detail: 'Order completed', type: 'success' }
|
||
};
|
||
|
||
const statusOrder = ['pending', 'confirmed', 'processing', 'shipped', 'delivered'];
|
||
const currentIndex = () => statusOrder.indexOf(status());
|
||
|
||
const items = () => statusOrder.map((key, idx) => ({
|
||
...statusMap[key],
|
||
completed: idx < currentIndex()
|
||
}));
|
||
|
||
return Div({ class: 'flex flex-col gap-4' }, [
|
||
Timeline({ items, compact: true }),
|
||
Div({ class: 'flex gap-2 justify-center flex-wrap mt-4' }, statusOrder.map(s =>
|
||
Button({
|
||
class: () => `btn btn-xs ${status() === s ? 'btn-primary' : 'btn-ghost'}`,
|
||
onclick: () => status(s)
|
||
}, statusMap[s].title)
|
||
))
|
||
]);
|
||
};
|
||
Mount(OrderDemo, '#demo-order');
|
||
```
|
||
|
||
### Company History
|
||
|
||
<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-history" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const HistoryDemo = () => {
|
||
const milestones = [
|
||
{ title: '2015 - Founded', detail: 'Company started with 3 employees', type: 'success', completed: true },
|
||
{ title: '2017 - First Product', detail: 'Launched first software product', type: 'success', completed: true },
|
||
{ title: '2019 - Series A', detail: 'Raised $5M, expanded to 50 employees', type: 'success', completed: true },
|
||
{ title: '2022 - Global Expansion', detail: 'Opened offices in Europe and Asia', type: 'info', completed: true },
|
||
{ title: '2024 - AI Integration', detail: 'Launched AI-powered features', type: 'warning', completed: false },
|
||
{ title: '2026 - Future Goals', detail: 'Aiming for market leadership', type: 'info', completed: false }
|
||
];
|
||
|
||
return Timeline({ items: milestones });
|
||
};
|
||
Mount(HistoryDemo, '#demo-history');
|
||
```
|
||
|
||
### 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-8"></div>
|
||
</div>
|
||
</div>
|
||
|
||
```javascript
|
||
const VariantsDemo = () => {
|
||
const sampleItems = [
|
||
{ title: 'Event 1', detail: 'Description here', type: 'success', completed: true },
|
||
{ title: 'Event 2', detail: 'Description here', type: 'warning', completed: false },
|
||
{ title: 'Event 3', detail: 'Description here', type: 'info', completed: false }
|
||
];
|
||
|
||
return Div({ class: 'flex flex-col gap-8' }, [
|
||
Div({ class: 'text-sm font-bold' }, 'Vertical Timeline'),
|
||
Timeline({ items: sampleItems }),
|
||
|
||
Div({ class: 'text-sm font-bold mt-4' }, 'Horizontal Timeline'),
|
||
Timeline({ items: sampleItems, vertical: false, class: 'min-w-[500px]' }),
|
||
|
||
Div({ class: 'text-sm font-bold mt-4' }, 'Compact Timeline'),
|
||
Timeline({ items: sampleItems, compact: true })
|
||
]);
|
||
};
|
||
Mount(VariantsDemo, '#demo-variants');
|
||
``` |