23 KiB
23 KiB
SigPro Demo – Atomic Components
Accordion
const accName = "demo-acc";
mount(
div({ class: "space-y-2" }, [
Accordion({ class: "collapse-arrow bg-base-100 border border-base-300" }, [
AccordionRadio({ name: accName, checked: true }),
AccordionTitle({}, "What is SigPro?"),
AccordionContent({}, "A lightweight UI library built on DaisyUI and a fine‑grained reactivity system."),
]),
Accordion({ class: "collapse-arrow bg-base-100 border border-base-300" }, [
AccordionRadio({ name: accName }),
AccordionTitle({}, "Why use it?"),
AccordionContent({}, "No build step, minimal boilerplate, and all components are just functions."),
]),
Accordion({ class: "collapse-arrow bg-base-100 border border-base-300" }, [
AccordionRadio({ name: accName }),
AccordionTitle({}, "Browser support?"),
AccordionContent({}, "All modern browsers that support ES2020+"),
]),
]),
"#demo-accordion"
);
Alert
mount(
Alert({ class: "alert-info" }, [
Icon({}, "icon-[lucide--info]"),
span({}, "You have 2 new messages"),
]),
"#demo-alert"
);
Autocomplete
const fruitQuery = $("");
const fruitResults = $([]);
const fruits = ["Apple", "Banana", "Orange", "Mango", "Carrot", "Broccoli", "Spinach", "Potato"];
Filter(fruitQuery, fruits, fruitResults);
const colorQuery = $("");
const colorResults = $([]);
const colors = ["Red", "Blue", "Green", "Yellow", "Black", "White", "Purple", "Cyan"];
Filter(colorQuery, colors, colorResults);
const autocompleteCombo = (query, results, placeholder) =>
Combo({ class: "p-2 bg-base-100 rounded-box shadow-xl max-h-60 overflow-y-auto border border-base-300 z-50" },
LabelInput({}, [
Icon({}, "icon-[lucide--search]"),
Input({ placeholder, value: query, oninput: (e) => query(e.target.value) })
]),
{ content: Menu({ class: "flex-col flex-nowrap w-full p-0" },
each(results, (item) =>
MenuItem({ label: item, onclick: () => { query(item); hide() } })
)
)}
);
mount(
div({ class: "flex flex-col gap-10" }, [
div({}, [
h3({ class: "font-bold mb-2" }, "Fruits:"),
autocompleteCombo(fruitQuery, fruitResults, "Search fruit..."),
span({ class: "text-xs" }, () => `Signal: ${fruitQuery()}`),
]),
div({}, [
h3({ class: "font-bold mb-2" }, "Colors:"),
autocompleteCombo(colorQuery, colorResults, "Search color..."),
span({ class: "text-xs" }, () => `Signal: ${colorQuery()}`),
]),
]),
"#demo-autocomplete"
);
Avatar & AvatarGroup
mount(
div({ class: "flex flex-col gap-4" }, [
Avatar({ class: "w-24 rounded-full" },
img({ src: "https://img.daisyui.com/images/profile/demo/kenobee@192.webp" })
),
AvatarGroup({}, [
Avatar({ class: "w-12" }, img({ src: "https://img.daisyui.com/images/profile/demo/kenobee@192.webp" })),
Avatar({ class: "w-12" }, img({ src: "https://img.daisyui.com/images/profile/demo/anakeen@192.webp" })),
Avatar({ class: "w-12" }, img({ src: "https://img.daisyui.com/images/profile/demo/kenobee@192.webp" })),
]),
]),
"#demo-avatar"
);
Badge
mount(
div({ class: "flex gap-2" }, [
Badge({}, "New"),
Badge({ class: "badge-outline" }, "Sale"),
Badge({ class: "badge-error" }, "Deleted"),
]),
"#demo-badge"
);
Breadcrumbs
mount(
Breadcrumbs({}, [
ul({}, [
li({}, a({ href: "#" }, "Home")),
li({}, a({ href: "#" }, "Docs")),
li({}, span({ class: "font-bold" }, "Components")),
]),
]),
"#demo-breadcrumbs"
);
Button
const count = $(0);
mount(
div({ class: "flex gap-2 items-center" }, [
Button({ class: "btn-primary", onclick: () => count(count() + 1) },
() => `Clicked ${count()} times`
),
Button({ class: "btn-outline", disabled: true }, "Disabled"),
]),
"#demo-button"
);
Calendar
const calendarRange = $({ start: "2026-04-01", end: "2026-04-15", startHour: 9, endHour: 18 });
mount(
Calendar({
value: calendarRange,
range: true,
hour: true,
onChange: (val) => console.log("Range:", val),
}),
"#demo-calendar"
);
Card, CardTitle, CardBody & CardActions
mount(
Card({ class: "w-80 bg-base-100 shadow-xl" }, [
CardBody({}, [
CardTitle({}, "Card Title"),
p({}, "This is a card with title, body and actions."),
CardActions({ class: "justify-end" }, [
Button({ class: "btn-primary btn-sm" }, "Buy"),
]),
]),
]),
"#demo-card"
);
Carousel & CarouselItem
mount(
Carousel({ class: "carousel-vertical rounded-box h-96" }, [
CarouselItem({ class: "h-full" },
img({ src: "https://img.daisyui.com/images/stock/photo-1559703248-dcaaec9fab78.webp" })
),
CarouselItem({ class: "h-full" },
img({ src: "https://img.daisyui.com/images/stock/photo-1565098772267-60af42b81ef2.webp" })
),
CarouselItem({ class: "h-full" },
img({ src: "https://img.daisyui.com/images/stock/photo-1572635148818-ef6fd45eb394.webp" })
),
]),
"#demo-carousel"
);
Chat, ChatImage, ChatHeader, ChatBubble & ChatFooter
mount(
div({ class: "flex flex-col gap-4" }, [
Chat({ class: "chat-start" }, [
ChatImage({}, img({ src: "https://img.daisyui.com/images/profile/demo/kenobee@192.webp", alt: "Obi-Wan" })),
ChatHeader({}, ["Obi-Wan Kenobi", time({ class: "text-xs opacity-50" }, "12:45")]),
ChatBubble({}, "You were the Chosen One!"),
ChatFooter({ class: "opacity-50" }, "Delivered"),
]),
Chat({ class: "chat-end" }, [
ChatImage({}, img({ src: "https://img.daisyui.com/images/profile/demo/anakeen@192.webp", alt: "Anakin" })),
ChatHeader({}, ["Anakin", time({ class: "text-xs opacity-50" }, "12:46")]),
ChatBubble({}, "I hate you!"),
ChatFooter({ class: "opacity-50" }, "Seen at 12:46"),
]),
]),
"#demo-chat"
);
Checkbox
const checked = $(false);
mount(
div({ class: "flex items-center gap-2" }, [
Checkbox({ checked, onchange: (e) => checked(e.target.checked) }),
span({}, () => `Accept terms (${checked() ? "Yes" : "No"})`),
]),
"#demo-checkbox"
);
Colorpicker & ColorPalette
const color = $("#000000");
mount(
div({ class: "flex flex-col gap-4" }, [
Combo({ class: "p-0" },
LabelInput({ class: "flex items-center gap-2 cursor-pointer" }, [
div({ class: "size-5 rounded-sm", style: () => `background-color: ${color() || "#000"}` }),
span({ class: () => `grow text-left truncate ${!color() ? "opacity-50" : ""}` }, () => color() || "Pick a color"),
() => color() ? span({ class: "btn-ghost btn-xs btn-circle -mr-2", onmousedown: (e) => { e.stopPropagation(); color(null); } }, Icon({}, "icon-[lucide--x]")) : null
]),
{ content: ColorPalette({ value: color, onchange: (c) => { color(c); hide(); } }) }
),
p({}, () => `Selected: ${color()}`),
]),
"#demo-colorpicker"
);
Datepicker
const dateRange = $(null);
const displayRange = $(() => {
const v = dateRange();
if (!v) return "";
if (typeof v === "string") return v;
if (v.start && v.end) return `${v.start} - ${v.end}`;
if (v.start) return `${v.start}...`;
return "";
});
mount(
Combo({ class: "p-0" },
LabelInput({ class: "flex items-center gap-2 cursor-pointer" }, [
Icon({}, "icon-[lucide--calendar]"),
span({ class: () => `grow text-left truncate ${!displayRange() ? "opacity-50" : ""}` }, () => displayRange() || "Select date range"),
() => displayRange() ? span({ class: "btn-ghost btn-xs btn-circle -mr-2", onmousedown: (e) => { e.stopPropagation(); dateRange(null); } }, Icon({}, "icon-[lucide--x]")) : null
]),
{ content: Calendar({ value: dateRange, range: true, hour: true, onChange: (v) => { dateRange(v); if (v?.end) hide(); } }) }
),
"#demo-datepicker"
);
Divider
mount(
div({ class: "flex flex-col gap-2" }, [
p({ class: "card bg-base-300 rounded-box grid h-20 place-items-center" }, "Above"),
Divider({}, "OR"),
p({ class: "card bg-base-300 rounded-box grid h-20 place-items-center" }, "Below"),
]),
"#demo-divider"
);
Drawer
const leftOpen = $(false);
const rightOpen = $(false);
mount(
Drawer({ class: () => leftOpen() ? "drawer-open" : "" }, [
DrawerToggle({ id: "left-drawer", checked: leftOpen }),
DrawerContent({}, [
Drawer({ class: () => `drawer-end ${rightOpen() ? "drawer-open" : ""}` }, [
DrawerToggle({ id: "right-drawer", checked: rightOpen }),
DrawerContent({}, [
div({ class: "p-4" }, [
h3({ class: "text-lg font-bold" }, "Central Panel"),
label({ for: "left-drawer", class: "btn" }, "Open Left"),
label({ for: "right-drawer", class: "btn ml-2" }, "Open Right"),
p({}, "Main Content..."),
]),
]),
DrawerSide({}, [
DrawerOverlay({ for: "right-drawer" }),
div({ class: "min-h-full bg-base-200 w-60 p-4" }, h4({ class: "font-semibold" }, "Right Menu")),
]),
]),
]),
DrawerSide({}, [
DrawerOverlay({ for: "left-drawer" }),
div({ class: "min-h-full bg-base-200 w-60 p-4" }, h4({ class: "font-semibold" }, "Left Menu")),
]),
]),
"#demo-drawer"
);
Dropdown, DropdownButton & DropdownContent
mount(
div({ class: "flex gap-4" }, [
Dropdown({}, [
DropdownButton({}, "Options"),
DropdownContent({ class: "menu bg-base-100 rounded-box w-52 p-2 shadow" }, [
Menu({}, [
MenuItem({ label: "Edit", onclick: () => hide() }),
MenuItem({ label: "Delete", onclick: () => hide() }),
MenuItem({ label: "Archive", onclick: () => hide() }),
]),
]),
]),
Dropdown({ class: "dropdown-bottom dropdown-end" }, [
DropdownButton({}, "More"),
DropdownContent({ class: "menu bg-base-100 rounded-box w-40 p-2 shadow" },
Menu({}, [
MenuItem({ label: "Profile", onclick: (e) => { e.preventDefault(); hide(); } }),
MenuItem({ label: "Logout", onclick: (e) => { e.preventDefault(); hide(); } }),
])
),
]),
]),
"#demo-dropdown"
);
Fab
mount(
Fab({ icon: "R", class: "btn-lg btn-circle btn-secondary" }, [
Button({}, "C"),
Button({}, "B"),
Button({}, "A"),
]),
"#demo-fab"
);
Fieldset
mount(
div({ class: "flex gap-4" }, [
Fieldset({ class: "bg-base-200 border-base-300 rounded-box w-xs border gap-3 p-4", label: "Personal Info" }, [
LabelFloating({}, [
span({}, "Name"),
Input({ placeholder: "", value: $("") }),
]),
LabelFloating({}, [
span({}, "Country"),
Select({}, [
SelectOption({}, "Spain"),
SelectOption({}, "France"),
SelectOption({}, "Italy"),
]),
]),
]),
Fieldset({ class: "bg-base-200 p-4 rounded-box", label: "Any content" }, [
div({}, "Any content"),
]),
]),
"#demo-fieldset"
);
Fileinput
const files = $([]);
const drag = $(false);
const error = $(null);
const maxMB = 5;
const processFiles = (fileList) => {
const arr = [...fileList];
if (arr.some(f => f.size > maxMB * (1 << 20))) return error(`Max ${maxMB}MB`);
error(null);
files([...files(), ...arr]);
};
mount(
div({ class: "w-full" }, [
FileDrag({
drag: drag(),
ondrag: (v) => drag(v),
ondrop: processFiles
}, [
div({ class: "flex items-center gap-3 w-full text-sm opacity-70" }, [
Icon({}, "icon-[lucide--upload]"),
span({ class: "grow truncate" }, "Upload files"),
span({ class: "text-[10px] opacity-40" }, maxMB + "MB"),
]),
FileInput({ onchange: processFiles }),
]),
() => error() && FileError({ message: error() }),
() => files().length > 0 && FilePreview({
files: files(),
onremove: (i) => files(files().filter((_, j) => j !== i))
}),
]),
"#demo-fileinput"
);
Icon
mount(
div({ class: "flex gap-4 text-xl" }, [
Icon({}, "icon-[lucide--home]"),
Icon({}, "icon-[lucide--settings]"),
"❤️",
]),
"#demo-icon"
);
Indicator
mount(
Indicator({ value: "3" }, [
Button({ class: "btn-circle" }, Icon({}, "icon-[lucide--bell]")),
]),
"#demo-indicator"
);
Input
const username = $("");
const password = $("");
mount(
div({ class: "flex flex-col gap-4 w-80" }, [
LabelFloating({}, [
span({}, "Username"),
div({ class: "input" }, [
Icon({}, "icon-[lucide--user]"),
Input({ class: "grow border-none", placeholder: "", value: username }),
]),
]),
LabelFloating({}, [
span({}, "Password"),
div({ class: "input" }, [
Icon({}, "icon-[lucide--lock]"),
InputPass({ class: "grow border-none", placeholder: "", value: password }),
]),
]),
]),
"#demo-input"
);
Kbd
mount(
p({}, ["Press ", Kbd({}, "Ctrl"), " + ", Kbd({}, "S"), " to save"]),
"#demo-kbd"
);
List & ListRows
const people = $([
{ name: "Alice", online: true },
{ name: "Bob", online: false },
]);
mount(
div({ class: "flex flex-col gap-4" }, [
List({ class: "bg-base-100 rounded-box shadow-md" }, [
each(people, (p) =>
li({ class: "list-row" }, [
Badge({ class: p.online ? "badge-success" : "badge-ghost" }),
p.name,
])
),
]),
Divider({}, "OR"),
List({ class: "bg-base-100 rounded-box shadow-md" }, [
ListRows({
items: people,
render: (p) => [
Badge({ class: p.online ? "badge-success" : "badge-ghost" }),
p.name,
],
}),
]),
]),
"#demo-list"
);
Loading
mount(Loading({ class: "loading-lg text-primary" }), "#demo-loading");
Menu
mount(
Menu({ class: "w-56 bg-base-200 rounded-box" }, [
MenuItem({ label: "Dashboard", onclick: () => hide() }),
li({}, details({ open: true }, [
summary({}, "Settings"),
Menu({}, [
MenuItem({ label: "Profile", onclick: () => hide() }),
MenuItem({ label: "Account", onclick: () => hide() }),
]),
])),
MenuItem({ label: "Logout", onclick: () => alert("Logout") }),
]),
"#demo-menu"
);
Modal
const modalRef = { current: null };
mount(
div({}, [
Button({ class: "btn", onclick: () => modalRef.current?.showModal() }, "Open modal"),
Modal({ ref: (el) => modalRef.current = el }, [
ModalBox({}, [
h3({ class: "text-lg font-bold" }, "Congratulations!"),
p({ class: "py-4" }, "You have successfully created a reactive DaisyUI modal with SigPro."),
ModalAction({}, [
form({ method: "dialog" }, [
Button({}, "Close"),
]),
]),
]),
ModalBackdrop(),
]),
]),
"#demo-modal"
);
Navbar
mount(
Navbar({ class: "bg-base-300 rounded-box" }, [
div({ class: "flex-1" }, a({ class: "btn btn-ghost text-xl" }, "SigPro")),
div({ class: "flex-none" }, Button({ class: "btn-square btn-ghost" }, Icon({}, "icon-[lucide--menu]"))),
]),
"#demo-navbar"
);
Progress
const progressVal = $(35);
mount(
div({ class: "flex flex-col gap-2" }, [
span({}, () => `${progressVal()}%`),
Progress({ value: progressVal, max: 100, class: "w-56" }),
]),
"#demo-progress"
);
Radial Progress
const radialVal = $(70);
mount(
Radial({ value: radialVal, class: "text-primary" }, () => `${radialVal()}%`),
"#demo-radial"
);
Radio
const option = $("a");
mount(
div({ class: "flex gap-4" }, [
label({ class: "flex items-center gap-2" }, [
Radio({ name: "demo-radio", value: "a", checked: () => option() === "a", onchange: () => option("a") }),
"Option A",
]),
label({ class: "flex items-center gap-2" }, [
Radio({ name: "demo-radio", value: "b", checked: () => option() === "b", onchange: () => option("b") }),
"Option B",
]),
]),
"#demo-radio"
);
Range
const rangeValue = $(25);
mount(
div({ class: "flex flex-col gap-2 w-60" }, [
Range({ min: 0, max: 100, value: rangeValue, class: "range-sm" }),
span({}, () => `Value: ${rangeValue()}`),
]),
"#demo-range"
);
Rating & RatingItems
const stars = $(3);
mount(
Rating({}, [
RatingItems({ count: 5, value: stars, name: "demo-rating", class: "mask-star-2" }),
]),
"#demo-rating"
);
Select
const choice = $("css");
mount(
LabelFloating({}, [
span({}, "Tech"),
LabelSelect({}, [
Select({ value: choice, onchange: (e) => choice(e.target.value) }, [
SelectOption({ value: "" }, "Pick a language"),
SelectOption({ value: "html" }, "HTML"),
SelectOption({ value: "css" }, "CSS"),
SelectOption({ value: "js" }, "JavaScript"),
]),
]),
]),
"#demo-select"
);
Skeleton & SkeletonText
mount(
div({ class: "flex flex-col gap-4 w-52" }, [
Skeleton({ class: "h-32" }),
SkeletonText({ class: "h-4" }),
SkeletonText({ class: "h-4 w-3/4" }),
]),
"#demo-skeleton"
);
Stack
mount(
Stack({ class: "w-48" }, [
img({ src: "https://img.daisyui.com/images/stock/photo-1572635148818-ef6fd45eb394.webp", class: "rounded-box" }),
img({ src: "https://img.daisyui.com/images/stock/photo-1565098772267-60af42b81ef2.webp", class: "rounded-box" }),
img({ src: "https://img.daisyui.com/images/stock/photo-1559703248-dcaaec9fab78.webp", class: "rounded-box" }),
]),
"#demo-stack"
);
Stats & Stat
mount(
Stats({ class: "w-full" }, [
Stat({}, [
StatTitle({}, "Downloads"),
StatValue({}, "1,200"),
StatDesc({}, "↑ 21% from last month"),
]),
Stat({}, [
StatTitle({}, "New Users"),
StatValue({}, "450"),
StatDesc({}, "↑ 14% from last month"),
]),
Stat({}, [
StatTitle({}, "Revenue"),
StatValue({}, "$89k"),
StatDesc({}, "↓ 1% from last month"),
]),
]),
"#demo-stats"
);
Steps & Step
mount(
Steps({ class: "steps-horizontal w-full" }, [
Step({ dataContent: "1", class: "step-primary" }, "Register"),
Step({ dataContent: "2", class: "step-primary" }, "Choose plan"),
Step({ dataContent: "3" }, "Purchase"),
Step({ dataContent: "4" }, "Enjoy"),
]),
"#demo-steps"
);
Swap (Toggle)
const isDark = $(false);
mount(
Swap({ class: "text-2xl" }, [
SwapToggle({ value: isDark, class: "swap-rotate" }),
SwapOn({}, Icon({}, "icon-[lucide--moon]")),
SwapOff({}, Icon({}, "icon-[lucide--sun]")),
]),
"#demo-swap"
);
Table
const tableData = $([
{ id: 1, name: "Alice", role: "Admin" },
{ id: 2, name: "Bob", role: "User" },
{ id: 3, name: "Charlie", role: "User" },
]);
mount(
Table({ class: "w-full" }, [
TableHead({}, TableRow({}, [
TableTh({}, "Name"),
TableTh({}, "Role"),
TableTh({}, "Action"),
])),
TableBody({},
each(tableData, (item) =>
TableRow({}, [
TableTd({ class: "font-bold" }, item.name),
TableTd({}, item.role),
TableTd({}, Button({ class: "btn-xs", onclick: () => alert(`Edit ${item.name}`) }, "Edit")),
])
)
),
]),
"#demo-table"
);
Tabs
const tabsSignal = $([
{ label: "Tab A", content: "Content of tab A", open: true },
{ label: "Tab B", content: "Content of tab B", closable: true },
{ label: "Tab C", content: "Content of tab C" },
]);
mount(
Tabs({ class: "tabs-box" },
each(tabsSignal, (tab, i) =>
Tab({
name: "demo-tabs",
label: tab.label,
content: tab.content,
checked: tab.open || false,
tabs: tabsSignal,
index: i,
closable: tab.closable || false,
})
)
),
"#demo-tabs"
);
Textarea
const bio = $("");
mount(
Textarea({ class: "w-80", placeholder: "Write something...", value: bio }),
"#demo-textarea"
);
Textrotate
mount(
Textrotate({ class: "text-2xl font-bold" }, [
span({}, "Hello"),
span({}, "Bonjour"),
span({}, "Hola"),
]),
"#demo-textrotate"
);
Timeline
mount(
Timeline({ class: "timeline-vertical" }, [
li({}, [
div({ class: "timeline-start" }, "2024"),
div({ class: "timeline-middle" }, Icon({}, "icon-[lucide--check]")),
div({ class: "timeline-end timeline-box" }, "Project started"),
]),
li({}, [
div({ class: "timeline-start" }, "2025"),
div({ class: "timeline-middle" }, Icon({}, "icon-[lucide--clock]")),
div({ class: "timeline-end timeline-box" }, "First prototype"),
]),
]),
"#demo-timeline"
);
Toast
mount(
div({ class: "flex flex-wrap gap-2" }, [
Button({ class: "btn", onclick: () => Toast("File saved!") }, "Simple"),
Button({ class: "btn", onclick: () => Toast("Error!", "alert-error", 5000) }, "Error (5s)"),
Button({
class: "btn",
onclick: () =>
Toast(
div({ class: "flex items-center gap-2" }, [
Icon({}, "icon-[lucide--check]"),
span({}, "Report generated"),
]),
"alert-success"
),
}, "With icon"),
Button({
class: "btn",
onclick: () =>
Toast(
div({ class: "flex flex-col" }, [
strong({}, "ATTENTION!"),
span({}, "Error saving!"),
button({ class: "btn btn-xs mt-1", onclick: () => console.log("Retry") }, "Retry"),
]),
"alert-warning",
7000
),
}, "Complex"),
]),
"#demo-toast"
);
Toggle
const toggleActive = $(false);
mount(
Toggle({
checked: toggleActive,
onchange: (e) => toggleActive(e.target.checked),
class: "toggle-primary",
}),
"#demo-toggle"
);
Tooltip
mount(
Tooltip({ tip: "Save changes", class: "tooltip-right tooltip-primary" },
Button({ class: "btn" }, "Save")
),
"#demo-tooltip"
);