388 lines
22 KiB
C#
388 lines
22 KiB
C#
using Htmx.ApiDemo.Templates.Components;
|
|
using Immediate.Apis.Shared;
|
|
using Immediate.Handlers.Shared;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Htmx.ApiDemo.Templates;
|
|
|
|
public sealed class UiDemo : UiDemoBase
|
|
{
|
|
// ── Buttons ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent BtnDefault { get; }
|
|
public IHtmxComponent BtnDestructive { get; }
|
|
public IHtmxComponent BtnOutline { get; }
|
|
public IHtmxComponent BtnSecondary { get; }
|
|
public IHtmxComponent BtnGhost { get; }
|
|
public IHtmxComponent BtnLink { get; }
|
|
public IHtmxComponent BtnSm { get; }
|
|
public IHtmxComponent BtnLg { get; }
|
|
|
|
// ── Inputs ───────────────────────────────────────────────────────────
|
|
public IHtmxComponent InputText { get; }
|
|
public IHtmxComponent InputEmail { get; }
|
|
public IHtmxComponent InputPassword { get; }
|
|
public IHtmxComponent InputSearch { get; }
|
|
|
|
// ── Select / Calendar / TimePicker ───────────────────────────────────
|
|
public IHtmxComponent SelectDemo { get; }
|
|
public IHtmxComponent CalendarDemo { get; }
|
|
public IHtmxComponent CalendarRangeDemo { get; }
|
|
public IHtmxComponent TimePickerDemo { get; }
|
|
public IHtmxComponent TimePicker12hDemo { get; }
|
|
|
|
// ── Badge ─────────────────────────────────────────────────────────────
|
|
public IHtmxComponent BadgeDefault { get; }
|
|
public IHtmxComponent BadgeSecondary { get; }
|
|
public IHtmxComponent BadgeDestructive { get; }
|
|
public IHtmxComponent BadgeOutline { get; }
|
|
|
|
// ── Card ──────────────────────────────────────────────────────────────
|
|
public IHtmxComponent CardDemo { get; }
|
|
|
|
// ── Separator ─────────────────────────────────────────────────────────
|
|
public IHtmxComponent SeparatorH { get; }
|
|
public IHtmxComponent SeparatorV { get; }
|
|
|
|
// ── Skeleton ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent SkeletonTitle { get; }
|
|
public IHtmxComponent SkeletonLine1 { get; }
|
|
public IHtmxComponent SkeletonLine2 { get; }
|
|
public IHtmxComponent SkeletonAvatar { get; }
|
|
|
|
// ── Avatar ────────────────────────────────────────────────────────────
|
|
public IHtmxComponent AvatarSm { get; }
|
|
public IHtmxComponent AvatarDefault { get; }
|
|
public IHtmxComponent AvatarLg { get; }
|
|
public IHtmxComponent AvatarImg { get; }
|
|
|
|
// ── Progress ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent Progress25 { get; }
|
|
public IHtmxComponent Progress60 { get; }
|
|
public IHtmxComponent Progress100 { get; }
|
|
|
|
// ── Alert ─────────────────────────────────────────────────────────────
|
|
public IHtmxComponent AlertDefault { get; }
|
|
public IHtmxComponent AlertDestructive { get; }
|
|
|
|
// ── Breadcrumb ────────────────────────────────────────────────────────
|
|
public IHtmxComponent BreadcrumbDemo { get; }
|
|
|
|
// ── Checkbox ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent CheckboxAccept { get; }
|
|
public IHtmxComponent CheckboxChecked { get; }
|
|
|
|
// ── RadioGroup ────────────────────────────────────────────────────────
|
|
public IHtmxComponent RadioGroupCol { get; }
|
|
public IHtmxComponent RadioGroupRow { get; }
|
|
|
|
// ── Switch ────────────────────────────────────────────────────────────
|
|
public IHtmxComponent SwitchOff { get; }
|
|
public IHtmxComponent SwitchOn { get; }
|
|
|
|
// ── Textarea ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent TextareaDemo { get; }
|
|
|
|
// ── Slider ────────────────────────────────────────────────────────────
|
|
public IHtmxComponent SliderDemo { get; }
|
|
|
|
// ── FileInput ─────────────────────────────────────────────────────────
|
|
public IHtmxComponent FileInputDemo { get; }
|
|
|
|
// ── Table ─────────────────────────────────────────────────────────────
|
|
public IHtmxComponent TableDemo { get; }
|
|
|
|
// ── Pagination ────────────────────────────────────────────────────────
|
|
public IHtmxComponent PaginationDemo { get; }
|
|
|
|
// ── Tabs ──────────────────────────────────────────────────────────────
|
|
public IHtmxComponent TabsDemo { get; }
|
|
|
|
// ── Accordion ─────────────────────────────────────────────────────────
|
|
public IHtmxComponent AccordionDemo { get; }
|
|
|
|
// ── Tooltip ───────────────────────────────────────────────────────────
|
|
public IHtmxComponent TooltipTop { get; }
|
|
public IHtmxComponent TooltipBottom { get; }
|
|
public IHtmxComponent TooltipRight { get; }
|
|
|
|
// ── Dialog ────────────────────────────────────────────────────────────
|
|
public IHtmxComponent DialogDemo { get; }
|
|
|
|
// ── Dropdown ──────────────────────────────────────────────────────────
|
|
public IHtmxComponent DropdownDemo { get; }
|
|
|
|
// ── Toast Viewport ────────────────────────────────────────────────────
|
|
public IHtmxComponent ToastViewportDemo { get; }
|
|
|
|
public UiDemo()
|
|
{
|
|
// Buttons
|
|
BtnDefault = new Button("Default");
|
|
BtnDestructive = new Button("Destructive", variant: "destructive");
|
|
BtnOutline = new Button("Outline", variant: "outline");
|
|
BtnSecondary = new Button("Secondary", variant: "secondary");
|
|
BtnGhost = new Button("Ghost", variant: "ghost");
|
|
BtnLink = new Button("Link", variant: "link");
|
|
BtnSm = new Button("Small", size: "sm");
|
|
BtnLg = new Button("Large", size: "lg");
|
|
|
|
// Inputs
|
|
InputText = new Input("username", label: "Username", placeholder: "Enter username");
|
|
InputEmail = new Input("email", inputType: "email", label: "Email", placeholder: "you@example.com");
|
|
InputPassword = new Input("password", inputType: "password", label: "Password", placeholder: "••••••••");
|
|
InputSearch = new Input("search", inputType: "search", label: "Search", placeholder: "Search…",
|
|
hxAttrs: "hx-get=\"/search\" hx-trigger=\"keyup changed delay:300ms\" hx-target=\"#search-results\"");
|
|
|
|
// Select / Calendar / TimePicker
|
|
SelectDemo = new Select(
|
|
id: "framework",
|
|
label: "Framework",
|
|
options: [("htmx", "HTMX"), ("react", "React"), ("vue", "Vue"), ("svelte", "Svelte")],
|
|
selectedValue: "htmx",
|
|
description: "Choose your preferred framework");
|
|
|
|
CalendarDemo = new Calendar(id: "demo-cal", name: "demo-date");
|
|
CalendarRangeDemo = new CalendarRange(id: "demo-calr", name: "demo-range");
|
|
TimePickerDemo = new TimePicker(name: "time-24h", label: "Time (24h)");
|
|
TimePicker12hDemo = new TimePicker(name: "time-12h", label: "Time (12h)", use12h: true);
|
|
|
|
// Badge
|
|
BadgeDefault = new Badge("Default");
|
|
BadgeSecondary = new Badge("Secondary", variant: "secondary");
|
|
BadgeDestructive = new Badge("Destructive", variant: "destructive");
|
|
BadgeOutline = new Badge("Outline", variant: "outline");
|
|
|
|
// Card
|
|
CardDemo = new Card(
|
|
title: "Component Card",
|
|
description: "A reusable card surface with header and footer.",
|
|
content: "<p class=\"text-sm text-muted-foreground\">Cards group related content and provide a contained, elevated surface for information.</p>",
|
|
footer: "<button type=\"button\" class=\"inline-flex items-center justify-center rounded-md bg-primary text-primary-foreground h-9 px-4 text-sm font-medium hover:bg-primary/90 transition-colors\">Action</button>");
|
|
|
|
// Separator
|
|
SeparatorH = new Separator();
|
|
SeparatorV = new Separator(orientation: "vertical");
|
|
|
|
// Skeleton
|
|
SkeletonTitle = new Skeleton("h-5 w-48");
|
|
SkeletonLine1 = new Skeleton("h-4 w-full");
|
|
SkeletonLine2 = new Skeleton("h-4 w-3/4");
|
|
SkeletonAvatar = new Skeleton("h-10 w-10 rounded-full");
|
|
|
|
// Avatar
|
|
AvatarSm = new Avatar("SM", size: "sm");
|
|
AvatarDefault = new Avatar("JD");
|
|
AvatarLg = new Avatar("AB", size: "lg");
|
|
AvatarImg = new Avatar("GitHub", src: "https://github.com/github.png", size: "default");
|
|
|
|
// Progress
|
|
Progress25 = new Progress(25);
|
|
Progress60 = new Progress(60);
|
|
Progress100 = new Progress(100);
|
|
|
|
// Alert
|
|
AlertDefault = new Alert("Information", description: "This is an informational alert with a default style.");
|
|
AlertDestructive = new Alert("Error", description: "Something went wrong. Please check your input.", variant: "destructive");
|
|
|
|
// Breadcrumb
|
|
BreadcrumbDemo = new Breadcrumb([
|
|
("Home", "/"),
|
|
("Components", "/components"),
|
|
("UI Demo", ""),
|
|
]);
|
|
|
|
// Checkbox
|
|
CheckboxAccept = new Checkbox("accept-terms", label: "Accept terms and conditions");
|
|
CheckboxChecked = new Checkbox("newsletter", label: "Subscribe to newsletter", @checked: true);
|
|
|
|
// RadioGroup
|
|
RadioGroupCol = new RadioGroup(
|
|
name: "plan-v",
|
|
label: "Plan (vertical)",
|
|
options: [
|
|
("starter", "Starter", true),
|
|
("pro", "Pro", false),
|
|
("enterprise", "Enterprise", false),
|
|
]);
|
|
RadioGroupRow = new RadioGroup(
|
|
name: "size-h",
|
|
label: "Size (horizontal)",
|
|
direction: "flex-row",
|
|
options: [
|
|
("sm", "SM", true),
|
|
("md", "MD", false),
|
|
("lg", "LG", false),
|
|
]);
|
|
|
|
// Switch
|
|
SwitchOff = new Switch("notif-off", label: "Notifications");
|
|
SwitchOn = new Switch("darkmode", label: "Dark mode", isChecked: true);
|
|
|
|
// Textarea
|
|
TextareaDemo = new Textarea(
|
|
id: "bio",
|
|
label: "Bio",
|
|
placeholder: "Tell us about yourself…",
|
|
description: "Max 200 characters.");
|
|
|
|
// Slider
|
|
SliderDemo = new Slider(id: "volume", label: "Volume", value: 40, description: "Drag to adjust");
|
|
|
|
// FileInput
|
|
FileInputDemo = new FileInput(
|
|
id: "avatar-upload",
|
|
label: "Profile picture",
|
|
accept: "image/*",
|
|
description: "PNG, JPG or GIF up to 2 MB.");
|
|
|
|
// Table
|
|
TableDemo = new Table(
|
|
headers: ["Name", "Role", "Status"],
|
|
rows: [
|
|
["Alice", "Admin", "Active"],
|
|
["Bob", "Editor", "Active"],
|
|
["Charlie", "Viewer", "Inactive"],
|
|
],
|
|
caption: "Team members");
|
|
|
|
// Pagination
|
|
PaginationDemo = new Pagination(current: 3, total: 7, urlPattern: "/ui-demo?page={0}");
|
|
|
|
// Tabs
|
|
TabsDemo = new Tabs("demo", [
|
|
("overview", "Overview", "<p class=\"text-sm text-muted-foreground\">This is the overview tab content.</p>"),
|
|
("settings", "Settings", "<p class=\"text-sm text-muted-foreground\">Manage your settings here.</p>"),
|
|
("billing", "Billing", "<p class=\"text-sm text-muted-foreground\">View billing information.</p>"),
|
|
]);
|
|
|
|
// Accordion
|
|
AccordionDemo = new Accordion("demo-acc", [
|
|
("What is htmx?", "htmx allows you to access AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML."),
|
|
("Is it production ready?", "Yes — htmx is used by thousands of projects in production worldwide."),
|
|
("Does it replace React?", "htmx is a different tool suited to server-driven UIs. Use whatever fits your team best."),
|
|
], openIndex: 0);
|
|
|
|
// Tooltip
|
|
TooltipTop = new Tooltip("Top tooltip", new Button("Hover me"), position: "top");
|
|
TooltipBottom = new Tooltip("Bottom tooltip", new Button("Bottom", variant: "secondary"), position: "bottom");
|
|
TooltipRight = new Tooltip("Right tooltip", new Button("Right", variant: "outline"), position: "right");
|
|
|
|
// Dialog
|
|
DialogDemo = new Dialog(
|
|
id: "demo-dialog",
|
|
title: "Are you sure?",
|
|
description: "This action cannot be undone.",
|
|
content: "Please confirm that you want to proceed with this operation.",
|
|
footer: "<button type=\"button\" data-dialog-close class=\"inline-flex items-center justify-center rounded-md border border-input bg-background h-9 px-4 text-sm font-medium hover:bg-accent transition-colors\">Cancel</button>" +
|
|
"<button type=\"button\" data-dialog-close class=\"inline-flex items-center justify-center rounded-md bg-primary text-primary-foreground h-9 px-4 text-sm font-medium hover:bg-primary/90 transition-colors\">Confirm</button>");
|
|
|
|
// Dropdown
|
|
DropdownDemo = new DropdownMenu(
|
|
trigger: new Button("Options ▾", variant: "outline"),
|
|
items: [
|
|
("Edit", "/edit", false),
|
|
("Duplicate", "/dup", false),
|
|
("", "", true), // separator
|
|
("Delete", "/delete", false),
|
|
]);
|
|
|
|
// Toast Viewport
|
|
ToastViewportDemo = new ToastViewport();
|
|
}
|
|
|
|
protected override void RenderBtnDefault(HtmxRenderContext ctx) => BtnDefault.Render(ctx);
|
|
protected override void RenderBtnDestructive(HtmxRenderContext ctx) => BtnDestructive.Render(ctx);
|
|
protected override void RenderBtnOutline(HtmxRenderContext ctx) => BtnOutline.Render(ctx);
|
|
protected override void RenderBtnSecondary(HtmxRenderContext ctx) => BtnSecondary.Render(ctx);
|
|
protected override void RenderBtnGhost(HtmxRenderContext ctx) => BtnGhost.Render(ctx);
|
|
protected override void RenderBtnLink(HtmxRenderContext ctx) => BtnLink.Render(ctx);
|
|
protected override void RenderBtnSm(HtmxRenderContext ctx) => BtnSm.Render(ctx);
|
|
protected override void RenderBtnLg(HtmxRenderContext ctx) => BtnLg.Render(ctx);
|
|
|
|
protected override void RenderInputText(HtmxRenderContext ctx) => InputText.Render(ctx);
|
|
protected override void RenderInputEmail(HtmxRenderContext ctx) => InputEmail.Render(ctx);
|
|
protected override void RenderInputPassword(HtmxRenderContext ctx) => InputPassword.Render(ctx);
|
|
protected override void RenderInputSearch(HtmxRenderContext ctx) => InputSearch.Render(ctx);
|
|
|
|
protected override void RenderSelectDemo(HtmxRenderContext ctx) => SelectDemo.Render(ctx);
|
|
protected override void RenderCalendarDemo(HtmxRenderContext ctx) => CalendarDemo.Render(ctx);
|
|
protected override void RenderCalendarRangeDemo(HtmxRenderContext ctx) => CalendarRangeDemo.Render(ctx);
|
|
protected override void RenderTimePickerDemo(HtmxRenderContext ctx) => TimePickerDemo.Render(ctx);
|
|
protected override void RenderTimePicker12hDemo(HtmxRenderContext ctx) => TimePicker12hDemo.Render(ctx);
|
|
|
|
protected override void RenderBadgeDefault(HtmxRenderContext ctx) => BadgeDefault.Render(ctx);
|
|
protected override void RenderBadgeSecondary(HtmxRenderContext ctx) => BadgeSecondary.Render(ctx);
|
|
protected override void RenderBadgeDestructive(HtmxRenderContext ctx) => BadgeDestructive.Render(ctx);
|
|
protected override void RenderBadgeOutline(HtmxRenderContext ctx) => BadgeOutline.Render(ctx);
|
|
|
|
protected override void RenderCardDemo(HtmxRenderContext ctx) => CardDemo.Render(ctx);
|
|
|
|
protected override void RenderSeparatorH(HtmxRenderContext ctx) => SeparatorH.Render(ctx);
|
|
protected override void RenderSeparatorV(HtmxRenderContext ctx) => SeparatorV.Render(ctx);
|
|
|
|
protected override void RenderSkeletonTitle(HtmxRenderContext ctx) => SkeletonTitle.Render(ctx);
|
|
protected override void RenderSkeletonLine1(HtmxRenderContext ctx) => SkeletonLine1.Render(ctx);
|
|
protected override void RenderSkeletonLine2(HtmxRenderContext ctx) => SkeletonLine2.Render(ctx);
|
|
protected override void RenderSkeletonAvatar(HtmxRenderContext ctx) => SkeletonAvatar.Render(ctx);
|
|
|
|
protected override void RenderAvatarSm(HtmxRenderContext ctx) => AvatarSm.Render(ctx);
|
|
protected override void RenderAvatarDefault(HtmxRenderContext ctx) => AvatarDefault.Render(ctx);
|
|
protected override void RenderAvatarLg(HtmxRenderContext ctx) => AvatarLg.Render(ctx);
|
|
protected override void RenderAvatarImg(HtmxRenderContext ctx) => AvatarImg.Render(ctx);
|
|
|
|
protected override void RenderProgress25(HtmxRenderContext ctx) => Progress25.Render(ctx);
|
|
protected override void RenderProgress60(HtmxRenderContext ctx) => Progress60.Render(ctx);
|
|
protected override void RenderProgress100(HtmxRenderContext ctx) => Progress100.Render(ctx);
|
|
|
|
protected override void RenderAlertDefault(HtmxRenderContext ctx) => AlertDefault.Render(ctx);
|
|
protected override void RenderAlertDestructive(HtmxRenderContext ctx) => AlertDestructive.Render(ctx);
|
|
|
|
protected override void RenderBreadcrumbDemo(HtmxRenderContext ctx) => BreadcrumbDemo.Render(ctx);
|
|
|
|
protected override void RenderCheckboxAccept(HtmxRenderContext ctx) => CheckboxAccept.Render(ctx);
|
|
protected override void RenderCheckboxChecked(HtmxRenderContext ctx) => CheckboxChecked.Render(ctx);
|
|
|
|
protected override void RenderRadioGroupCol(HtmxRenderContext ctx) => RadioGroupCol.Render(ctx);
|
|
protected override void RenderRadioGroupRow(HtmxRenderContext ctx) => RadioGroupRow.Render(ctx);
|
|
|
|
protected override void RenderSwitchOff(HtmxRenderContext ctx) => SwitchOff.Render(ctx);
|
|
protected override void RenderSwitchOn(HtmxRenderContext ctx) => SwitchOn.Render(ctx);
|
|
|
|
protected override void RenderTextareaDemo(HtmxRenderContext ctx) => TextareaDemo.Render(ctx);
|
|
protected override void RenderSliderDemo(HtmxRenderContext ctx) => SliderDemo.Render(ctx);
|
|
protected override void RenderFileInputDemo(HtmxRenderContext ctx)=> FileInputDemo.Render(ctx);
|
|
protected override void RenderTableDemo(HtmxRenderContext ctx) => TableDemo.Render(ctx);
|
|
protected override void RenderPaginationDemo(HtmxRenderContext ctx)=> PaginationDemo.Render(ctx);
|
|
protected override void RenderTabsDemo(HtmxRenderContext ctx) => TabsDemo.Render(ctx);
|
|
protected override void RenderAccordionDemo(HtmxRenderContext ctx)=> AccordionDemo.Render(ctx);
|
|
|
|
protected override void RenderTooltipTop(HtmxRenderContext ctx) => TooltipTop.Render(ctx);
|
|
protected override void RenderTooltipBottom(HtmxRenderContext ctx) => TooltipBottom.Render(ctx);
|
|
protected override void RenderTooltipRight(HtmxRenderContext ctx) => TooltipRight.Render(ctx);
|
|
|
|
protected override void RenderDialogDemo(HtmxRenderContext ctx) => DialogDemo.Render(ctx);
|
|
protected override void RenderDropdownDemo(HtmxRenderContext ctx) => DropdownDemo.Render(ctx);
|
|
|
|
protected override void RenderToastViewportDemo(HtmxRenderContext ctx) => ToastViewportDemo.Render(ctx);
|
|
}
|
|
|
|
|
|
[Handler]
|
|
[MapGet("/ui-demo")]
|
|
public static partial class GetUiDemoHandler
|
|
{
|
|
public class Query;
|
|
|
|
private static ValueTask<IResult> HandleAsync(
|
|
Query query,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
CancellationToken token)
|
|
{
|
|
var context = httpContextAccessor.HttpContext
|
|
?? throw new InvalidOperationException("HttpContext is not available.");
|
|
|
|
var page = new UiDemo();
|
|
return ValueTask.FromResult<IResult>(context.WriteHtmxPage(page, title: "UI Demo", appName: "HtmxApp", pageTitle: "UI Components"));
|
|
}
|
|
}
|