Next Preview Work Final

This commit is contained in:
2026-04-03 23:54:11 +02:00
parent 257107e198
commit a6705621d8
49 changed files with 1119 additions and 493 deletions

View File

@@ -171,7 +171,7 @@ const CartDemo = () => {
),
Span({ class: 'text-lg font-bold' }, () => `Total: $${total()}`)
]),
cart().length === 0
() => 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' }, [
@@ -187,6 +187,7 @@ const CartDemo = () => {
))
]);
};
$mount(CartDemo, '#demo-cart');
```
@@ -235,7 +236,7 @@ const InboxDemo = () => {
}
}, 'Mark all read')
]),
Div({ class: 'flex flex-col gap-2' }, messages().map(msg =>
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)
@@ -247,6 +248,7 @@ const InboxDemo = () => {
))
]);
};
$mount(InboxDemo, '#demo-inbox');
```

View File

@@ -125,20 +125,22 @@ $mount(TooltipDemo, '#demo-tooltip');
```javascript
const ErrorDemo = () => {
const email = $('');
const isValid = $(true);
const validate = (value) => {
const valid = value.includes('@') && value.includes('.');
isValid(valid);
email(value);
};
return Input({
type: 'email',
value: email,
error: () => !isValid() && email() ? 'Invalid email address' : '',
oninput: (e) => validate(e.target.value)
});
return Div({ class: 'w-full max-w-md' }, [
Input({
type: 'email',
value: email,
placeholder: 'Enter your email',
icon: 'icon-[lucide--mail]',
validate: (value) => {
if (!value) return '';
if (!value.includes('@')) return 'Email must contain @';
if (!value.includes('.')) return 'Email must contain .';
return '';
},
oninput: (e) => email(e.target.value)
})
]);
};
$mount(ErrorDemo, '#demo-error');
```

View File

@@ -8,23 +8,23 @@ List component with custom item rendering, headers, and reactive data binding.
## Props
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `items` | `Array \| Signal<Array>` | `[]` | Data array to display |
| `header` | `string \| VNode \| Signal` | `-` | Optional header content |
| `render` | `function(item, index)` | Required | Custom render function for each item |
| `keyFn` | `function(item, index)` | `(item, idx) => idx` | Unique key function for items |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
| Prop | Type | Default | Description |
| :------- | :-------------------------- | :------------------- | :------------------------------------------ |
| `items` | `Array \| Signal<Array>` | `[]` | Data array to display |
| `header` | `string \| VNode \| Signal` | `-` | Optional header content |
| `render` | `function(item, index)` | Required | Custom render function for each item |
| `keyFn` | `function(item, index)` | `(item, idx) => idx` | Unique key function for items |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
## Styling
List supports all **daisyUI List classes**:
| Category | Keywords | Description |
| :--- | :--- | :--- |
| Base | `list` | Base list styling |
| Variant | `list-row` | Row styling for list items |
| Background | `bg-base-100` | Background color |
| Category | Keywords | Description |
| :--------- | :------------ | :------------------------- |
| Base | `list` | Base list styling |
| Variant | `list-row` | Row styling for list items |
| Background | `bg-base-100` | Background color |
> For further details, check the [daisyUI List Documentation](https://daisyui.com/components/list) Full reference for CSS classes.
@@ -41,16 +41,17 @@ List supports all **daisyUI List classes**:
```javascript
const BasicDemo = () => {
const items = ['Apple', 'Banana', 'Orange', 'Grape', 'Mango'];
const items = ["Apple", "Banana", "Orange", "Grape", "Mango"];
return List({
items: items,
render: (item) => Div({ class: 'p-3 hover:bg-base-200 transition-colors' }, [
Span({ class: 'font-medium' }, item)
])
render: (item) =>
Div({ class: "p-3 hover:bg-base-200 transition-colors" }, [
Span({ class: "font-medium" }, item),
]),
});
};
$mount(BasicDemo, '#demo-basic');
$mount(BasicDemo, "#demo-basic");
```
### With Header
@@ -65,22 +66,31 @@ $mount(BasicDemo, '#demo-basic');
```javascript
const HeaderDemo = () => {
const users = [
{ name: 'John Doe', email: 'john@example.com', status: 'active' },
{ name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
{ name: 'Bob Johnson', email: 'bob@example.com', status: 'active' }
{ name: "John Doe", email: "john@example.com", status: "active" },
{ name: "Jane Smith", email: "jane@example.com", status: "inactive" },
{ name: "Bob Johnson", email: "bob@example.com", status: "active" },
];
return List({
items: users,
header: Div({ class: 'p-3 bg-primary/10 font-bold border-b border-base-300' }, 'Active Users'),
render: (user) => Div({ class: 'p-3 border-b border-base-300 hover:bg-base-200' }, [
Div({ class: 'font-medium' }, user.name),
Div({ class: 'text-sm opacity-70' }, user.email),
Span({ class: `badge badge-sm ${user.status === 'active' ? 'badge-success' : 'badge-ghost'} mt-1` }, user.status)
])
header: Div(
{ class: "p-3 bg-primary/10 font-bold border-b border-base-300" },
"Active Users",
),
render: (user) =>
Div({ class: "p-3 border-b border-base-300 hover:bg-base-200" }, [
Div({ class: "font-medium" }, user.name),
Div({ class: "text-sm opacity-70" }, user.email),
Span(
{
class: `badge badge-sm ${user.status === "active" ? "badge-success" : "badge-ghost"} mt-1`,
},
user.status,
),
]),
});
};
$mount(HeaderDemo, '#demo-header');
$mount(HeaderDemo, "#demo-header");
```
### With Icons
@@ -95,25 +105,36 @@ $mount(HeaderDemo, '#demo-header');
```javascript
const IconsDemo = () => {
const settings = [
{ icon: '🔊', label: 'Sound', description: 'Adjust volume and notifications' },
{ icon: '🌙', label: 'Display', description: 'Brightness and dark mode' },
{ icon: '🔒', label: 'Privacy', description: 'Security settings' },
{ icon: '🌐', label: 'Network', description: 'WiFi and connections' }
{
icon: "🔊",
label: "Sound",
description: "Adjust volume and notifications",
},
{ icon: "🌙", label: "Display", description: "Brightness and dark mode" },
{ icon: "🔒", label: "Privacy", description: "Security settings" },
{ icon: "🌐", label: "Network", description: "WiFi and connections" },
];
return List({
items: settings,
render: (item) => Div({ class: 'flex gap-3 p-3 hover:bg-base-200 transition-colors cursor-pointer' }, [
Div({ class: 'text-2xl' }, item.icon),
Div({ class: 'flex-1' }, [
Div({ class: 'font-medium' }, item.label),
Div({ class: 'text-sm opacity-60' }, item.description)
]),
Span({ class: 'opacity-40' }, '→')
])
render: (item) =>
Div(
{
class:
"flex gap-3 p-3 hover:bg-base-200 transition-colors cursor-pointer",
},
[
Div({ class: "text-2xl" }, item.icon),
Div({ class: "flex-1" }, [
Div({ class: "font-medium" }, item.label),
Div({ class: "text-sm opacity-60" }, item.description),
]),
Span({ class: "opacity-40" }, "→"),
],
),
});
};
$mount(IconsDemo, '#demo-icons');
$mount(IconsDemo, "#demo-icons");
```
### With Badges
@@ -128,24 +149,52 @@ $mount(IconsDemo, '#demo-icons');
```javascript
const BadgesDemo = () => {
const notifications = [
{ id: 1, message: 'New comment on your post', time: '5 min ago', unread: true },
{ id: 2, message: 'Your order has been shipped', time: '1 hour ago', unread: true },
{ id: 3, message: 'Welcome to the platform!', time: '2 days ago', unread: false },
{ id: 4, message: 'Weekly digest available', time: '3 days ago', unread: false }
{
id: 1,
message: "New comment on your post",
time: "5 min ago",
unread: true,
},
{
id: 2,
message: "Your order has been shipped",
time: "1 hour ago",
unread: true,
},
{
id: 3,
message: "Welcome to the platform!",
time: "2 days ago",
unread: false,
},
{
id: 4,
message: "Weekly digest available",
time: "3 days ago",
unread: false,
},
];
return List({
items: notifications,
render: (item) => Div({ class: `flex justify-between items-center p-3 border-b border-base-300 hover:bg-base-200 ${item.unread ? 'bg-primary/5' : ''}` }, [
Div({ class: 'flex-1' }, [
Div({ class: 'font-medium' }, item.message),
Div({ class: 'text-xs opacity-50' }, item.time)
]),
item.unread ? Span({ class: 'badge badge-primary badge-sm' }, 'New') : null
])
render: (item) =>
Div(
{
class: `flex justify-between items-center p-3 border-b border-base-300 hover:bg-base-200 ${item.unread ? "bg-primary/5" : ""}`,
},
[
Div({ class: "flex-1" }, [
Div({ class: "font-medium" }, item.message),
Div({ class: "text-xs opacity-50" }, item.time),
]),
item.unread
? Span({ class: "badge badge-primary badge-sm" }, "New")
: null,
],
),
});
};
$mount(BadgesDemo, '#demo-badges');
$mount(BadgesDemo, "#demo-badges");
```
### Interactive List
@@ -161,38 +210,49 @@ $mount(BadgesDemo, '#demo-badges');
const InteractiveDemo = () => {
const selected = $(null);
const items = [
{ id: 1, name: 'Project Alpha', status: 'In Progress' },
{ id: 2, name: 'Project Beta', status: 'Planning' },
{ id: 3, name: 'Project Gamma', status: 'Completed' },
{ id: 4, name: 'Project Delta', status: 'Review' }
{ id: 1, name: "Project Alpha", status: "In Progress" },
{ id: 2, name: "Project Beta", status: "Planning" },
{ id: 3, name: "Project Gamma", status: "Completed" },
{ id: 4, name: "Project Delta", status: "Review" },
];
const statusColors = {
'In Progress': 'badge-warning',
'Planning': 'badge-info',
'Completed': 'badge-success',
'Review': 'badge-accent'
"In Progress": "badge-warning",
Planning: "badge-info",
Completed: "badge-success",
Review: "badge-accent",
};
return Div({ class: 'flex flex-col gap-4' }, [
return Div({ class: "flex flex-col gap-4" }, [
List({
items: items,
render: (item) => Div({
class: `p-3 cursor-pointer transition-all hover:bg-base-200 ${selected() === item.id ? 'bg-primary/10 border-l-4 border-primary' : 'border-l-4 border-transparent'}`,
onclick: () => selected(item.id)
}, [
Div({ class: 'flex justify-between items-center' }, [
Div({ class: 'font-medium' }, item.name),
Span({ class: `badge ${statusColors[item.status]}` }, item.status)
])
])
render: (item) =>
Div(
{
class: `p-3 cursor-pointer transition-all hover:bg-base-200 ${selected() === item.id ? "bg-primary/10 border-l-4 border-primary" : "border-l-4 border-transparent"}`,
onclick: () => selected(item.id),
},
[
Div({ class: "flex justify-between items-center" }, [
Div({ class: "font-medium" }, item.name),
Span(
{ class: `badge ${statusColors[item.status]}` },
item.status,
),
]),
],
),
}),
() => selected()
? Div({ class: 'alert alert-info' }, `Selected: ${items.find(i => i.id === selected()).name}`)
: Div({ class: 'alert alert-soft' }, 'Select a project to see details')
() =>
selected()
? Div(
{ class: "alert alert-info" },
`Selected: ${items.find((i) => i.id === selected()).name}`,
)
: Div({ class: "alert alert-soft" }, "Select a project to see details"),
]);
};
$mount(InteractiveDemo, '#demo-interactive');
$mount(InteractiveDemo, "#demo-interactive");
```
### Reactive List (Todo App)
@@ -223,9 +283,7 @@ const ReactiveDemo = () => {
};
const toggleTodo = (id) => {
todos(todos().map(t =>
t.id === id ? { ...t, done: !t.done } : t
));
todos(todos().map(t => t.id === id ? { ...t, done: !t.done } : t));
};
const deleteTodo = (id) => {
@@ -233,13 +291,12 @@ const ReactiveDemo = () => {
};
const pendingCount = () => todos().filter(t => !t.done).length;
$watch(()=> console.log(pendingCount()));
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-2' }, [
Input({
placeholder: 'Add new task...',
value: newTodo,
class: 'flex-1',
oninput: (e) => newTodo(e.target.value),
onkeypress: (e) => e.key === 'Enter' && addTodo()
}),
@@ -247,24 +304,32 @@ const ReactiveDemo = () => {
]),
List({
items: todos,
render: (todo) => Div({ class: `flex items-center gap-3 p-2 border-b border-base-300 hover:bg-base-200 ${todo.done ? 'opacity-60' : ''}` }, [
Checkbox({
value: todo.done,
onclick: () => toggleTodo(todo.id)
}),
Span({
class: `flex-1 ${todo.done ? 'line-through' : ''}`,
onclick: () => toggleTodo(todo.id)
}, todo.text),
Button({
class: 'btn btn-ghost btn-xs btn-circle',
onclick: () => deleteTodo(todo.id)
}, '✕')
])
render: (item) => {
// Esta función busca siempre el estado actual del item dentro del signal
const it = () => todos().find(t => t.id === item.id) || item;
return Div({
class: () => `flex items-center gap-3 p-2 border-b border-base-300 ${it().done ? 'opacity-60' : ''}`
}, [
Checkbox({
value: () => it().done,
onclick: () => toggleTodo(item.id)
}),
Span({
class: () => `flex-1 ${it().done ? 'line-through' : ''}`,
onclick: () => toggleTodo(item.id)
}, () => it().text),
Button({
class: 'btn btn-ghost btn-xs btn-circle',
onclick: () => deleteTodo(item.id)
}, '✕')
]);
}
}),
Div({ class: 'text-sm opacity-70 mt-2' }, () => `${pendingCount()} tasks remaining`)
]);
};
$mount(ReactiveDemo, '#demo-reactive');
```
@@ -280,27 +345,45 @@ $mount(ReactiveDemo, '#demo-reactive');
```javascript
const AvatarDemo = () => {
const contacts = [
{ name: 'Alice Johnson', role: 'Developer', avatar: 'A', online: true },
{ name: 'Bob Smith', role: 'Designer', avatar: 'B', online: false },
{ name: 'Charlie Brown', role: 'Manager', avatar: 'C', online: true },
{ name: 'Diana Prince', role: 'QA Engineer', avatar: 'D', online: false }
{ name: "Alice Johnson", role: "Developer", avatar: "A", online: true },
{ name: "Bob Smith", role: "Designer", avatar: "B", online: false },
{ name: "Charlie Brown", role: "Manager", avatar: "C", online: true },
{ name: "Diana Prince", role: "QA Engineer", avatar: "D", online: false },
];
return List({
items: contacts,
render: (contact) => Div({ class: 'flex gap-3 p-3 hover:bg-base-200 transition-colors' }, [
Div({ class: `avatar ${contact.online ? 'online' : 'offline'}`, style: 'width: 48px' }, [
Div({ class: 'rounded-full bg-primary text-primary-content flex items-center justify-center w-12 h-12 font-bold' }, contact.avatar)
render: (contact) =>
Div({ class: "flex gap-3 p-3 hover:bg-base-200 transition-colors" }, [
Div(
{
class: `avatar ${contact.online ? "online" : "offline"}`,
style: "width: 48px",
},
[
Div(
{
class:
"rounded-full bg-primary text-primary-content flex items-center justify-center w-12 h-12 font-bold",
},
contact.avatar,
),
],
),
Div({ class: "flex-1" }, [
Div({ class: "font-medium" }, contact.name),
Div({ class: "text-sm opacity-60" }, contact.role),
]),
Div(
{
class: `badge badge-sm ${contact.online ? "badge-success" : "badge-ghost"}`,
},
contact.online ? "Online" : "Offline",
),
]),
Div({ class: 'flex-1' }, [
Div({ class: 'font-medium' }, contact.name),
Div({ class: 'text-sm opacity-60' }, contact.role)
]),
Div({ class: `badge badge-sm ${contact.online ? 'badge-success' : 'badge-ghost'}` }, contact.online ? 'Online' : 'Offline')
])
});
};
$mount(AvatarDemo, '#demo-avatar');
$mount(AvatarDemo, "#demo-avatar");
```
### All Variants
@@ -314,29 +397,29 @@ $mount(AvatarDemo, '#demo-avatar');
```javascript
const VariantsDemo = () => {
const items = ['Item 1', 'Item 2', 'Item 3'];
return Div({ class: 'flex flex-col gap-6' }, [
Div({ class: 'text-sm font-bold' }, 'Default List'),
const items = ["Item 1", "Item 2", "Item 3"];
return Div({ class: "flex flex-col gap-6" }, [
Div({ class: "text-sm font-bold" }, "Default List"),
List({
items: items,
render: (item) => Div({ class: 'p-2' }, item)
render: (item) => Div({ class: "p-2" }, item),
}),
Div({ class: 'text-sm font-bold mt-2' }, 'With Shadow'),
Div({ class: "text-sm font-bold mt-2" }, "With Shadow"),
List({
items: items,
render: (item) => Div({ class: 'p-2' }, item),
class: 'shadow-lg'
render: (item) => Div({ class: "p-2" }, item),
class: "shadow-lg",
}),
Div({ class: 'text-sm font-bold mt-2' }, 'Rounded Corners'),
Div({ class: "text-sm font-bold mt-2" }, "Rounded Corners"),
List({
items: items,
render: (item) => Div({ class: 'p-2' }, item),
class: 'rounded-box overflow-hidden'
})
render: (item) => Div({ class: "p-2" }, item),
class: "rounded-box overflow-hidden",
}),
]);
};
$mount(VariantsDemo, '#demo-variants');
```
$mount(VariantsDemo, "#demo-variants");
```

View File

@@ -140,41 +140,6 @@ const ReactiveDemo = () => {
$mount(ReactiveDemo, '#demo-reactive');
```
### With Trend Indicators
<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-trends" class="bg-base-100 p-6 rounded-xl border border-base-300 grid grid-cols-1 md:grid-cols-3 gap-4"></div>
</div>
</div>
```javascript
const TrendsDemo = () => {
return Div({ class: 'grid grid-cols-1 md:grid-cols-3 gap-4' }, [
Stat({
label: 'Weekly Sales',
value: '$12,345',
desc: Div({ class: 'text-success' }, '↗︎ 15% increase'),
icon: Span({ class: 'text-2xl' }, '📈')
}),
Stat({
label: 'Bounce Rate',
value: '42%',
desc: Div({ class: 'text-error' }, '↘︎ 3% from last week'),
icon: Span({ class: 'text-2xl' }, '📉')
}),
Stat({
label: 'Avg. Session',
value: '4m 32s',
desc: Div({ class: 'text-warning' }, '↗︎ 12 seconds'),
icon: Span({ class: 'text-2xl' }, '⏱️')
})
]);
};
$mount(TrendsDemo, '#demo-trends');
```
### Multiple Stats in Row
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">

View File

@@ -294,27 +294,22 @@ $mount(ColorsDemo, '#demo-colors');
const AllPositionsDemo = () => {
return Div({ class: 'grid grid-cols-3 gap-4 justify-items-center' }, [
Div({ class: 'col-start-2' }, [
Tooltip({ tip: 'Top tooltip', class: 'tooltip-top' }, [
Tooltip({ tip: 'Top tooltip', ui: 'tooltip-top' }, [
Button({ class: 'btn btn-sm w-24' }, 'Top')
])
]),
Div({ class: 'col-start-1 row-start-2' }, [
Tooltip({ tip: 'Left tooltip', class: 'tooltip-left' }, [
Tooltip({ tip: 'Left tooltip', ui: 'tooltip-left' }, [
Button({ class: 'btn btn-sm w-24' }, 'Left')
])
]),
Div({ class: 'col-start-2 row-start-2' }, [
Tooltip({ tip: 'Center tooltip', class: 'tooltip' }, [
Button({ class: 'btn btn-sm w-24' }, 'Center')
])
]),
Div({ class: 'col-start-3 row-start-2' }, [
Tooltip({ tip: 'Right tooltip', class: 'tooltip-right' }, [
Tooltip({ tip: 'Right tooltip', ui: 'tooltip-right' }, [
Button({ class: 'btn btn-sm w-24' }, 'Right')
])
]),
Div({ class: 'col-start-2 row-start-3' }, [
Tooltip({ tip: 'Bottom tooltip', class: 'tooltip-bottom' }, [
Tooltip({ tip: 'Bottom tooltip', ui: 'tooltip-bottom' }, [
Button({ class: 'btn btn-sm w-24' }, 'Bottom')
])
])