@franco_roura/module-01 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/README.md +64 -2
- package/dist/charts.d.ts +3 -0
- package/dist/charts.js +3 -0
- package/dist/components/alert-dialog.d.ts +19 -0
- package/dist/components/alert-dialog.js +101 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/amount.d.ts +24 -0
- package/dist/components/amount.js +27 -0
- package/dist/components/amount.js.map +1 -0
- package/dist/components/appearance-pickers.d.ts +9 -0
- package/dist/components/appearance-pickers.js +65 -0
- package/dist/components/appearance-pickers.js.map +1 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.js +28 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/budget-meter.d.ts +18 -0
- package/dist/components/budget-meter.js +38 -0
- package/dist/components/budget-meter.js.map +1 -0
- package/dist/components/button.d.ts +13 -0
- package/dist/components/button.js +54 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/calendar.d.ts +7 -0
- package/dist/components/calendar.js +52 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/category-icon.d.ts +33 -0
- package/dist/components/category-icon.js +49 -0
- package/dist/components/category-icon.js.map +1 -0
- package/dist/components/chart.d.ts +44 -0
- package/dist/components/chart.js +147 -0
- package/dist/components/chart.js.map +1 -0
- package/dist/components/charts.d.ts +52 -0
- package/dist/components/charts.js +482 -0
- package/dist/components/charts.js.map +1 -0
- package/dist/components/checkbox.d.ts +5 -0
- package/dist/components/checkbox.js +21 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/combobox.d.ts +32 -0
- package/dist/components/combobox.js +100 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/command.d.ts +19 -0
- package/dist/components/command.js +86 -0
- package/dist/components/command.js.map +1 -0
- package/dist/components/cta-banner.d.ts +14 -0
- package/dist/components/cta-banner.js +39 -0
- package/dist/components/cta-banner.js.map +1 -0
- package/dist/components/date-picker.d.ts +19 -0
- package/dist/components/date-picker.js +107 -0
- package/dist/components/date-picker.js.map +1 -0
- package/dist/components/dialog.d.ts +18 -0
- package/dist/components/dialog.js +99 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/dropdown-menu.d.ts +26 -0
- package/dist/components/dropdown-menu.js +123 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/field.d.ts +30 -0
- package/dist/components/field.js +53 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/footer.d.ts +18 -0
- package/dist/components/footer.js +40 -0
- package/dist/components/footer.js.map +1 -0
- package/dist/components/fx-converter.d.ts +22 -0
- package/dist/components/fx-converter.js +91 -0
- package/dist/components/fx-converter.js.map +1 -0
- package/dist/components/hero.d.ts +28 -0
- package/dist/components/hero.js +83 -0
- package/dist/components/hero.js.map +1 -0
- package/dist/components/hud.d.ts +41 -0
- package/dist/components/hud.js +108 -0
- package/dist/components/hud.js.map +1 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.js +14 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.js +15 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/media-card.d.ts +29 -0
- package/dist/components/media-card.js +80 -0
- package/dist/components/media-card.js.map +1 -0
- package/dist/components/money-input.d.ts +10 -0
- package/dist/components/money-input.js +30 -0
- package/dist/components/money-input.js.map +1 -0
- package/dist/components/multi-combobox.d.ts +27 -0
- package/dist/components/multi-combobox.js +101 -0
- package/dist/components/multi-combobox.js.map +1 -0
- package/dist/components/nav-bar.d.ts +21 -0
- package/dist/components/nav-bar.js +44 -0
- package/dist/components/nav-bar.js.map +1 -0
- package/dist/components/panel.d.ts +27 -0
- package/dist/components/panel.js +49 -0
- package/dist/components/panel.js.map +1 -0
- package/dist/components/popover.d.ts +11 -0
- package/dist/components/popover.js +56 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/select.d.ts +16 -0
- package/dist/components/select.js +128 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.js +17 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.d.ts +15 -0
- package/dist/components/sheet.js +87 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.js +13 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/sonner.d.ts +5 -0
- package/dist/components/sonner.js +44 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/spec-readout.d.ts +11 -0
- package/dist/components/spec-readout.js +25 -0
- package/dist/components/spec-readout.js.map +1 -0
- package/dist/components/split-flap.d.ts +12 -0
- package/dist/components/split-flap.js +77 -0
- package/dist/components/split-flap.js.map +1 -0
- package/dist/components/tabs.d.ts +12 -0
- package/dist/components/tabs.js +47 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/tag.d.ts +16 -0
- package/dist/components/tag.js +26 -0
- package/dist/components/tag.js.map +1 -0
- package/dist/components/terminal.d.ts +10 -0
- package/dist/components/terminal.js +20 -0
- package/dist/components/terminal.js.map +1 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.js +13 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/timeline-entry.d.ts +26 -0
- package/dist/components/timeline-entry.js +63 -0
- package/dist/components/timeline-entry.js.map +1 -0
- package/dist/components/toggle-group.d.ts +10 -0
- package/dist/components/toggle-group.js +49 -0
- package/dist/components/toggle-group.js.map +1 -0
- package/dist/components/toggle.d.ts +10 -0
- package/dist/components/toggle.js +37 -0
- package/dist/components/toggle.js.map +1 -0
- package/dist/components/tooltip.d.ts +8 -0
- package/dist/components/tooltip.js +36 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/finance.d.ts +10 -0
- package/dist/finance.js +10 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +33 -0
- package/dist/lib/category-icons.d.ts +80 -0
- package/dist/lib/category-icons.js +102 -0
- package/dist/lib/category-icons.js.map +1 -0
- package/dist/lib/fault.d.ts +7 -0
- package/dist/lib/fault.js +28 -0
- package/dist/lib/fault.js.map +1 -0
- package/dist/lib/form-flow.d.ts +15 -0
- package/dist/lib/form-flow.js +50 -0
- package/dist/lib/form-flow.js.map +1 -0
- package/dist/lib/fx.d.ts +39 -0
- package/dist/lib/fx.js +98 -0
- package/dist/lib/fx.js.map +1 -0
- package/dist/lib/money.d.ts +19 -0
- package/dist/lib/money.js +55 -0
- package/dist/lib/money.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +3 -0
- package/dist/lib/use-media-query.js +15 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.js +26 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/site.d.ts +10 -0
- package/dist/site.js +10 -0
- package/dist/styles.css +2 -0
- package/dist/theme.css +391 -0
- package/dist/tokens.css +181 -0
- package/guidelines/AlertDialog.md +9 -0
- package/guidelines/Amount.md +10 -0
- package/guidelines/AppearancePickers.md +8 -0
- package/guidelines/Badge.md +11 -0
- package/guidelines/BudgetMeter.md +11 -0
- package/guidelines/Button.md +16 -0
- package/guidelines/Calendar.md +8 -0
- package/guidelines/CategoryIcon.md +10 -0
- package/guidelines/Charts.md +12 -0
- package/guidelines/Checkbox.md +8 -0
- package/guidelines/Combobox.md +18 -0
- package/guidelines/Command.md +8 -0
- package/guidelines/Crosshair.md +7 -0
- package/guidelines/CtaBanner.md +8 -0
- package/guidelines/DatePicker.md +11 -0
- package/guidelines/Dialog.md +9 -0
- package/guidelines/DropdownMenu.md +9 -0
- package/guidelines/Field.md +22 -0
- package/guidelines/Footer.md +7 -0
- package/guidelines/FxConverter.md +12 -0
- package/guidelines/GlassPanel.md +8 -0
- package/guidelines/Grill.md +7 -0
- package/guidelines/Hero.md +9 -0
- package/guidelines/HudLabel.md +8 -0
- package/guidelines/Input.md +9 -0
- package/guidelines/Label.md +7 -0
- package/guidelines/MediaCard.md +8 -0
- package/guidelines/MoneyInput.md +10 -0
- package/guidelines/MultiCombobox.md +11 -0
- package/guidelines/NavBar.md +10 -0
- package/guidelines/Panel.md +10 -0
- package/guidelines/Popover.md +8 -0
- package/guidelines/README.md +100 -0
- package/guidelines/SectionHeader.md +9 -0
- package/guidelines/Select.md +9 -0
- package/guidelines/Separator.md +8 -0
- package/guidelines/Sheet.md +9 -0
- package/guidelines/Skeleton.md +8 -0
- package/guidelines/SpecReadout.md +7 -0
- package/guidelines/SplitFlap.md +9 -0
- package/guidelines/StatusLed.md +8 -0
- package/guidelines/Tabs.md +9 -0
- package/guidelines/Tag.md +9 -0
- package/guidelines/Terminal.md +7 -0
- package/guidelines/Textarea.md +8 -0
- package/guidelines/TickRuler.md +8 -0
- package/guidelines/TimelineEntry.md +8 -0
- package/guidelines/Toaster.md +9 -0
- package/guidelines/Toggle.md +9 -0
- package/guidelines/Tooltip.md +8 -0
- package/package.json +103 -4
- package/tokens/tokens.json +739 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { DropdownMenu } from "radix-ui";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
|
6
|
+
// src/components/dropdown-menu.tsx
|
|
7
|
+
function DropdownMenu$1({ ...props }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Root, {
|
|
9
|
+
"data-slot": "dropdown-menu",
|
|
10
|
+
...props
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function DropdownMenuPortal({ ...props }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Portal, {
|
|
15
|
+
"data-slot": "dropdown-menu-portal",
|
|
16
|
+
...props
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function DropdownMenuTrigger({ ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Trigger, {
|
|
21
|
+
"data-slot": "dropdown-menu-trigger",
|
|
22
|
+
...props
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function DropdownMenuContent({ className, sideOffset = 4, ...props }) {
|
|
26
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu.Content, {
|
|
27
|
+
"data-slot": "dropdown-menu-content",
|
|
28
|
+
sideOffset,
|
|
29
|
+
className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-float data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className),
|
|
30
|
+
...props
|
|
31
|
+
}) });
|
|
32
|
+
}
|
|
33
|
+
function DropdownMenuGroup({ ...props }) {
|
|
34
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Group, {
|
|
35
|
+
"data-slot": "dropdown-menu-group",
|
|
36
|
+
...props
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
40
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Item, {
|
|
41
|
+
"data-slot": "dropdown-menu-item",
|
|
42
|
+
"data-inset": inset,
|
|
43
|
+
"data-variant": variant,
|
|
44
|
+
className: cn("relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", className),
|
|
45
|
+
...props
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function DropdownMenuCheckboxItem({ className, children, checked, ...props }) {
|
|
49
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.CheckboxItem, {
|
|
50
|
+
"data-slot": "dropdown-menu-checkbox-item",
|
|
51
|
+
className: cn("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
52
|
+
checked,
|
|
53
|
+
...props,
|
|
54
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
55
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
56
|
+
children: /* @__PURE__ */ jsx(DropdownMenu.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) })
|
|
57
|
+
}), children]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function DropdownMenuRadioGroup({ ...props }) {
|
|
61
|
+
return /* @__PURE__ */ jsx(DropdownMenu.RadioGroup, {
|
|
62
|
+
"data-slot": "dropdown-menu-radio-group",
|
|
63
|
+
...props
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function DropdownMenuRadioItem({ className, children, ...props }) {
|
|
67
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.RadioItem, {
|
|
68
|
+
"data-slot": "dropdown-menu-radio-item",
|
|
69
|
+
className: cn("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
|
|
70
|
+
...props,
|
|
71
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
72
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
73
|
+
children: /* @__PURE__ */ jsx(DropdownMenu.ItemIndicator, { children: /* @__PURE__ */ jsx(CircleIcon, { className: "size-2 fill-current" }) })
|
|
74
|
+
}), children]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function DropdownMenuLabel({ className, inset, ...props }) {
|
|
78
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Label, {
|
|
79
|
+
"data-slot": "dropdown-menu-label",
|
|
80
|
+
"data-inset": inset,
|
|
81
|
+
className: cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className),
|
|
82
|
+
...props
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function DropdownMenuSeparator({ className, ...props }) {
|
|
86
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Separator, {
|
|
87
|
+
"data-slot": "dropdown-menu-separator",
|
|
88
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
89
|
+
...props
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function DropdownMenuShortcut({ className, ...props }) {
|
|
93
|
+
return /* @__PURE__ */ jsx("span", {
|
|
94
|
+
"data-slot": "dropdown-menu-shortcut",
|
|
95
|
+
className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className),
|
|
96
|
+
...props
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function DropdownMenuSub({ ...props }) {
|
|
100
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Sub, {
|
|
101
|
+
"data-slot": "dropdown-menu-sub",
|
|
102
|
+
...props
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
|
|
106
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, {
|
|
107
|
+
"data-slot": "dropdown-menu-sub-trigger",
|
|
108
|
+
"data-inset": inset,
|
|
109
|
+
className: cn("flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", className),
|
|
110
|
+
...props,
|
|
111
|
+
children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto size-4" })]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function DropdownMenuSubContent({ className, ...props }) {
|
|
115
|
+
return /* @__PURE__ */ jsx(DropdownMenu.SubContent, {
|
|
116
|
+
"data-slot": "dropdown-menu-sub-content",
|
|
117
|
+
className: cn("z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-float data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className),
|
|
118
|
+
...props
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
export { DropdownMenu$1 as DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=dropdown-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","DropdownMenuPrimitive"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../lib/utils\";\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\";\nimport { DropdownMenu as DropdownMenuPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nfunction DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />;\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-float data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-float data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":";;;;;;AAOA,SAASA,eAAa,EAAE,GAAG,SAAkE;CAC3F,OAAO,oBAACC,aAAsB,MAAvB;EAA4B,aAAU;EAAgB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,mBAAmB,EAC1B,GAAG,SACyD;CAC5D,OAAO,oBAACA,aAAsB,QAAvB;EAA8B,aAAU;EAAuB,GAAI;CAAQ,CAAA;AACpF;AAEA,SAAS,oBAAoB,EAC3B,GAAG,SAC0D;CAC7D,OAAO,oBAACA,aAAsB,SAAvB;EAA+B,aAAU;EAAwB,GAAI;CAAQ,CAAA;AACtF;AAEA,SAAS,oBAAoB,EAC3B,WACA,aAAa,GACb,GAAG,SAC0D;CAC7D,OACE,oBAACA,aAAsB,QAAvB,EAAA,UACE,oBAACA,aAAsB,SAAvB;EACE,aAAU;EACE;EACZ,WAAW,GACT,6jBACA,SACF;EACA,GAAI;CACL,CAAA,EAC2B,CAAA;AAElC;AAEA,SAAS,kBAAkB,EAAE,GAAG,SAAmE;CACjG,OAAO,oBAACA,aAAsB,OAAvB;EAA6B,aAAU;EAAsB,GAAI;CAAQ,CAAA;AAClF;AAEA,SAAS,iBAAiB,EACxB,WACA,OACA,UAAU,WACV,GAAG,SAIF;CACD,OACE,oBAACA,aAAsB,MAAvB;EACE,aAAU;EACV,cAAY;EACZ,gBAAc;EACd,WAAW,GACT,ujBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,yBAAyB,EAChC,WACA,UACA,SACA,GAAG,SAC+D;CAClE,OACE,qBAACA,aAAsB,cAAvB;EACE,aAAU;EACV,WAAW,GACT,gTACA,SACF;EACS;EACT,GAAI;EAPN,UAAA,CASE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,aAAsB,eAAvB,EAAA,UACE,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA,EACI,CAAA;EACjC,CAAA,GACL,QACiC;;AAExC;AAEA,SAAS,uBAAuB,EAC9B,GAAG,SAC6D;CAChE,OAAO,oBAACA,aAAsB,YAAvB;EAAkC,aAAU;EAA4B,GAAI;CAAQ,CAAA;AAC7F;AAEA,SAAS,sBAAsB,EAC7B,WACA,UACA,GAAG,SAC4D;CAC/D,OACE,qBAACA,aAAsB,WAAvB;EACE,aAAU;EACV,WAAW,GACT,gTACA,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,aAAsB,eAAvB,EAAA,UACE,oBAAC,YAAD,EAAY,WAAU,sBAAuB,CAAA,EACV,CAAA;EACjC,CAAA,GACL,QAC8B;;AAErC;AAEA,SAAS,kBAAkB,EACzB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAACA,aAAsB,OAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GAAG,qDAAqD,SAAS;EAC5E,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4D;CAC/D,OACE,oBAACA,aAAsB,WAAvB;EACE,aAAU;EACV,WAAW,GAAG,6BAA6B,SAAS;EACpD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAAuC;CACnF,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,yDAAyD,SAAS;EAChF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EAAE,GAAG,SAAiE;CAC7F,OAAO,oBAACA,aAAsB,KAAvB;EAA2B,aAAU;EAAoB,GAAI;CAAQ,CAAA;AAC9E;AAEA,SAAS,uBAAuB,EAC9B,WACA,OACA,UACA,GAAG,SAGF;CACD,OACE,qBAACA,aAAsB,YAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,8WACA,SACF;EACA,GAAI;EAPN,UAAA,CASG,UACD,oBAAC,kBAAD,EAAkB,WAAU,iBAAkB,CAAA,CACd;;AAEtC;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAACA,aAAsB,YAAvB;EACE,aAAU;EACV,WAAW,GACT,ofACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** The fault LED: a small danger dot with a tint halo that blinks as it appears. */
|
|
3
|
+
export declare function FaultLed({ className }: {
|
|
4
|
+
className?: string;
|
|
5
|
+
}): React.JSX.Element;
|
|
6
|
+
/**
|
|
7
|
+
* Announces an error to screen readers without showing a line under the control; the visible
|
|
8
|
+
* cue is the red label with its fault LED. Renders nothing without children.
|
|
9
|
+
*/
|
|
10
|
+
export declare function FieldError({ children }: {
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
}): React.JSX.Element | null;
|
|
13
|
+
/** Field label; when invalid it turns danger with a fault LED in front. */
|
|
14
|
+
export declare function FieldLabel({ htmlFor, invalid, className, children }: {
|
|
15
|
+
htmlFor?: string;
|
|
16
|
+
invalid?: boolean;
|
|
17
|
+
className?: string;
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
}): React.JSX.Element;
|
|
20
|
+
/** Label + control + help text, stacked. Pass the control's id as `htmlFor`. */
|
|
21
|
+
export declare function Field({ label, htmlFor, error, help, className, children }: {
|
|
22
|
+
label: React.ReactNode;
|
|
23
|
+
htmlFor?: string;
|
|
24
|
+
/** Turns the label red with a fault LED; the message is announced, not shown. */
|
|
25
|
+
error?: React.ReactNode;
|
|
26
|
+
help?: React.ReactNode;
|
|
27
|
+
className?: string;
|
|
28
|
+
children: React.ReactNode;
|
|
29
|
+
}): React.JSX.Element;
|
|
30
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Label } from "./label.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
// src/components/field.tsx
|
|
5
|
+
/** The fault LED: a small danger dot with a tint halo that blinks as it appears. */
|
|
6
|
+
function FaultLed({ className }) {
|
|
7
|
+
return /* @__PURE__ */ jsx("span", {
|
|
8
|
+
"aria-hidden": true,
|
|
9
|
+
className: cn("led-blink inline-block size-1.5 shrink-0 rounded-full bg-danger shadow-[0_0_0_3px_var(--color-danger-tint)]", className)
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Announces an error to screen readers without showing a line under the control; the visible
|
|
14
|
+
* cue is the red label with its fault LED. Renders nothing without children.
|
|
15
|
+
*/
|
|
16
|
+
function FieldError({ children }) {
|
|
17
|
+
if (!children) return null;
|
|
18
|
+
return /* @__PURE__ */ jsx("span", {
|
|
19
|
+
role: "alert",
|
|
20
|
+
className: "sr-only",
|
|
21
|
+
children
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Field label; when invalid it turns danger with a fault LED in front. */
|
|
25
|
+
function FieldLabel({ htmlFor, invalid, className, children }) {
|
|
26
|
+
return /* @__PURE__ */ jsxs(Label, {
|
|
27
|
+
htmlFor,
|
|
28
|
+
"data-invalid": invalid || void 0,
|
|
29
|
+
className: cn("text-body-sm", invalid ? "text-danger" : "text-ink-soft", className),
|
|
30
|
+
children: [invalid && /* @__PURE__ */ jsx(FaultLed, {}), children]
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Label + control + help text, stacked. Pass the control's id as `htmlFor`. */
|
|
34
|
+
function Field({ label, htmlFor, error, help, className, children }) {
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
36
|
+
className: cn("flex min-w-0 flex-col gap-1.5", className),
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ jsx(FieldLabel, {
|
|
39
|
+
htmlFor,
|
|
40
|
+
invalid: Boolean(error),
|
|
41
|
+
children: label
|
|
42
|
+
}),
|
|
43
|
+
children,
|
|
44
|
+
error ? /* @__PURE__ */ jsx(FieldError, { children: error }) : help ? /* @__PURE__ */ jsx("p", {
|
|
45
|
+
className: "text-body-sm text-ink-soft",
|
|
46
|
+
children: help
|
|
47
|
+
}) : null
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export { FaultLed, Field, FieldError, FieldLabel };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.js","names":[],"sources":["../../src/components/field.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport type * as React from \"react\";\nimport { Label } from \"./label\";\n\n/** The fault LED: a small danger dot with a tint halo that blinks as it appears. */\nexport function FaultLed({ className }: { className?: string }) {\n return (\n <span\n aria-hidden\n className={cn(\n \"led-blink inline-block size-1.5 shrink-0 rounded-full bg-danger shadow-[0_0_0_3px_var(--color-danger-tint)]\",\n className,\n )}\n />\n );\n}\n\n/**\n * Announces an error to screen readers without showing a line under the control; the visible\n * cue is the red label with its fault LED. Renders nothing without children.\n */\nexport function FieldError({ children }: { children?: React.ReactNode }) {\n if (!children) return null;\n return (\n <span role=\"alert\" className=\"sr-only\">\n {children}\n </span>\n );\n}\n\n/** Field label; when invalid it turns danger with a fault LED in front. */\nexport function FieldLabel({\n htmlFor,\n invalid,\n className,\n children,\n}: {\n htmlFor?: string;\n invalid?: boolean;\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <Label\n htmlFor={htmlFor}\n data-invalid={invalid || undefined}\n className={cn(\"text-body-sm\", invalid ? \"text-danger\" : \"text-ink-soft\", className)}\n >\n {invalid && <FaultLed />}\n {children}\n </Label>\n );\n}\n\n/** Label + control + help text, stacked. Pass the control's id as `htmlFor`. */\nexport function Field({\n label,\n htmlFor,\n error,\n help,\n className,\n children,\n}: {\n label: React.ReactNode;\n htmlFor?: string;\n /** Turns the label red with a fault LED; the message is announced, not shown. */\n error?: React.ReactNode;\n help?: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn(\"flex min-w-0 flex-col gap-1.5\", className)}>\n <FieldLabel htmlFor={htmlFor} invalid={Boolean(error)}>\n {label}\n </FieldLabel>\n {children}\n {error ? (\n <FieldError>{error}</FieldError>\n ) : help ? (\n <p className=\"text-body-sm text-ink-soft\">{help}</p>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;AAKA,SAAgB,SAAS,EAAE,aAAqC;CAC9D,OACE,oBAAC,QAAD;EACE,eAAA;EACA,WAAW,GACT,+GACA,SACF;CACD,CAAA;AAEL;;;;;AAMA,SAAgB,WAAW,EAAE,YAA4C;CACvE,IAAI,CAAC,UAAU,OAAO;CACtB,OACE,oBAAC,QAAD;EAAM,MAAK;EAAQ,WAAU;EAC1B;CACG,CAAA;AAEV;;AAGA,SAAgB,WAAW,EACzB,SACA,SACA,WACA,YAMC;CACD,OACE,qBAAC,OAAD;EACW;EACT,gBAAc,WAAW,KAAA;EACzB,WAAW,GAAG,gBAAgB,UAAU,gBAAgB,iBAAiB,SAAS;EAHpF,UAAA,CAKG,WAAW,oBAAC,UAAD,CAAW,CAAA,GACtB,QACI;;AAEX;;AAGA,SAAgB,MAAM,EACpB,OACA,SACA,OACA,MACA,WACA,YASC;CACD,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,iCAAiC,SAAS;EAA7D,UAAA;GACE,oBAAC,YAAD;IAAqB;IAAS,SAAS,QAAQ,KAAK;IACjD,UAAA;GACS,CAAA;GACX;GACA,QACC,oBAAC,YAAD,EAAA,UAAa,MAAkB,CAAA,IAC7B,OACF,oBAAC,KAAD;IAAG,WAAU;IAA8B,UAAA;GAAQ,CAAA,IACjD;EACD;;AAET"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type FooterLink = {
|
|
3
|
+
label: string;
|
|
4
|
+
href: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
};
|
|
7
|
+
export type FooterProps = {
|
|
8
|
+
links?: FooterLink[];
|
|
9
|
+
/** Microprint on the left, e.g. a build stamp. */
|
|
10
|
+
left?: React.ReactNode;
|
|
11
|
+
/** Microprint on the right, e.g. coordinates. */
|
|
12
|
+
right?: React.ReactNode;
|
|
13
|
+
rulerLabels?: string[];
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/** Page footer: a tick ruler, then microprint either side of bracketed links. */
|
|
17
|
+
export declare function Footer({ links, left, right, rulerLabels, className }: FooterProps): React.JSX.Element;
|
|
18
|
+
//# sourceMappingURL=footer.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Button } from "./button.js";
|
|
3
|
+
import { TickRuler } from "./hud.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/footer.tsx
|
|
6
|
+
/** Page footer: a tick ruler, then microprint either side of bracketed links. */
|
|
7
|
+
function Footer({ links, left, right, rulerLabels, className }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("footer", {
|
|
9
|
+
className: cn("flex flex-col gap-4 pt-8 pb-6", className),
|
|
10
|
+
children: [/* @__PURE__ */ jsx(TickRuler, { labels: rulerLabels }), /* @__PURE__ */ jsxs("div", {
|
|
11
|
+
className: "flex flex-wrap items-center justify-between gap-6",
|
|
12
|
+
children: [
|
|
13
|
+
/* @__PURE__ */ jsx("span", {
|
|
14
|
+
className: "hud-sm text-ink-soft",
|
|
15
|
+
children: left
|
|
16
|
+
}),
|
|
17
|
+
/* @__PURE__ */ jsx("div", {
|
|
18
|
+
className: "flex flex-wrap gap-1",
|
|
19
|
+
children: links?.map((link) => /* @__PURE__ */ jsx(Button, {
|
|
20
|
+
variant: "bracket",
|
|
21
|
+
asChild: true,
|
|
22
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
23
|
+
href: link.href,
|
|
24
|
+
target: link.target,
|
|
25
|
+
rel: link.target === "_blank" ? "noopener noreferrer" : void 0,
|
|
26
|
+
children: link.label
|
|
27
|
+
})
|
|
28
|
+
}, link.label))
|
|
29
|
+
}),
|
|
30
|
+
/* @__PURE__ */ jsx("span", {
|
|
31
|
+
className: "hud-sm text-ink-soft",
|
|
32
|
+
children: right
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
})]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export { Footer };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"footer.js","names":[],"sources":["../../src/components/footer.tsx"],"sourcesContent":["import type * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { TickRuler } from \"./hud\";\n\nexport type FooterLink = {\n label: string;\n href: string;\n target?: string;\n};\n\nexport type FooterProps = {\n links?: FooterLink[];\n /** Microprint on the left, e.g. a build stamp. */\n left?: React.ReactNode;\n /** Microprint on the right, e.g. coordinates. */\n right?: React.ReactNode;\n rulerLabels?: string[];\n className?: string;\n};\n\n/** Page footer: a tick ruler, then microprint either side of bracketed links. */\nexport function Footer({ links, left, right, rulerLabels, className }: FooterProps) {\n return (\n <footer className={cn(\"flex flex-col gap-4 pt-8 pb-6\", className)}>\n <TickRuler labels={rulerLabels} />\n <div className=\"flex flex-wrap items-center justify-between gap-6\">\n <span className=\"hud-sm text-ink-soft\">{left}</span>\n <div className=\"flex flex-wrap gap-1\">\n {links?.map((link) => (\n <Button key={link.label} variant=\"bracket\" asChild>\n <a\n href={link.href}\n target={link.target}\n rel={link.target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n >\n {link.label}\n </a>\n </Button>\n ))}\n </div>\n <span className=\"hud-sm text-ink-soft\">{right}</span>\n </div>\n </footer>\n );\n}\n"],"mappings":";;;;;;AAsBA,SAAgB,OAAO,EAAE,OAAO,MAAM,OAAO,aAAa,aAA0B;CAClF,OACE,qBAAC,UAAD;EAAQ,WAAW,GAAG,iCAAiC,SAAS;EAAhE,UAAA,CACE,oBAAC,WAAD,EAAW,QAAQ,YAAc,CAAA,GACjC,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,QAAD;KAAM,WAAU;KAAwB,UAAA;IAAW,CAAA;IACnD,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,OAAO,KAAK,SACX,oBAAC,QAAD;MAAyB,SAAQ;MAAU,SAAA;MACzC,UAAA,oBAAC,KAAD;OACE,MAAM,KAAK;OACX,QAAQ,KAAK;OACb,KAAK,KAAK,WAAW,WAAW,wBAAwB,KAAA;OAEvD,UAAA,KAAK;MACL,CAAA;KACG,GARK,KAAK,KAQV,CACT;IACE,CAAA;IACL,oBAAC,QAAD;KAAM,WAAU;KAAwB,UAAA;IAAY,CAAA;GACjD;EACC,CAAA,CAAA;;AAEZ"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FxState } from "../lib/fx.js";
|
|
2
|
+
type Currency = {
|
|
3
|
+
code: string;
|
|
4
|
+
minorUnits: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Three linked inputs for a cross-currency transfer: amount sent, amount received and rate.
|
|
8
|
+
* Editing one recomputes the least recently edited of the other two (see lib/fx.ts).
|
|
9
|
+
* Controlled: keep the FxState in the parent (start from `initialFxState()`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function FxConverter({ id: rootId, from, to, value, onChange, invalid, className }: {
|
|
12
|
+
/** Id of the root, e.g. to fault all three fields with `fault(id)`. */
|
|
13
|
+
id?: string;
|
|
14
|
+
from: Currency;
|
|
15
|
+
to: Currency;
|
|
16
|
+
value: FxState;
|
|
17
|
+
onChange: (next: FxState) => void;
|
|
18
|
+
invalid?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
}): import("react").JSX.Element;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=fx-converter.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { editFx } from "../lib/fx.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { FieldLabel } from "./field.js";
|
|
5
|
+
import { MoneyInput } from "./money-input.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { useId } from "react";
|
|
8
|
+
// src/components/fx-converter.tsx
|
|
9
|
+
/**
|
|
10
|
+
* Three linked inputs for a cross-currency transfer: amount sent, amount received and rate.
|
|
11
|
+
* Editing one recomputes the least recently edited of the other two (see lib/fx.ts).
|
|
12
|
+
* Controlled: keep the FxState in the parent (start from `initialFxState()`).
|
|
13
|
+
*/
|
|
14
|
+
function FxConverter({ id: rootId, from, to, value, onChange, invalid, className }) {
|
|
15
|
+
const id = useId();
|
|
16
|
+
const c = {
|
|
17
|
+
fromMinorUnits: from.minorUnits,
|
|
18
|
+
toMinorUnits: to.minorUnits
|
|
19
|
+
};
|
|
20
|
+
const edit = (field) => (e) => onChange(editFx(value, field, e.target.value, c));
|
|
21
|
+
const next = value.order[0];
|
|
22
|
+
return /* @__PURE__ */ jsx("div", {
|
|
23
|
+
id: rootId,
|
|
24
|
+
"data-fault-group": true,
|
|
25
|
+
className: cn("@container", className),
|
|
26
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
27
|
+
className: "grid gap-3 @lg:grid-cols-3",
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsx(FxRow, {
|
|
30
|
+
id: `${id}-from`,
|
|
31
|
+
label: `Sent (${from.code})`,
|
|
32
|
+
computed: next === "from",
|
|
33
|
+
invalid,
|
|
34
|
+
children: /* @__PURE__ */ jsx(MoneyInput, {
|
|
35
|
+
id: `${id}-from`,
|
|
36
|
+
currency: from.code,
|
|
37
|
+
value: value.from,
|
|
38
|
+
onChange: edit("from"),
|
|
39
|
+
"aria-invalid": invalid || void 0
|
|
40
|
+
})
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ jsx(FxRow, {
|
|
43
|
+
id: `${id}-to`,
|
|
44
|
+
label: `Received (${to.code})`,
|
|
45
|
+
computed: next === "to",
|
|
46
|
+
invalid,
|
|
47
|
+
children: /* @__PURE__ */ jsx(MoneyInput, {
|
|
48
|
+
id: `${id}-to`,
|
|
49
|
+
currency: to.code,
|
|
50
|
+
value: value.to,
|
|
51
|
+
onChange: edit("to"),
|
|
52
|
+
"aria-invalid": invalid || void 0
|
|
53
|
+
})
|
|
54
|
+
}),
|
|
55
|
+
/* @__PURE__ */ jsx(FxRow, {
|
|
56
|
+
id: `${id}-rate`,
|
|
57
|
+
label: `Rate (${to.code} per ${from.code})`,
|
|
58
|
+
computed: next === "rate",
|
|
59
|
+
invalid,
|
|
60
|
+
children: /* @__PURE__ */ jsx(MoneyInput, {
|
|
61
|
+
id: `${id}-rate`,
|
|
62
|
+
currency: "×",
|
|
63
|
+
placeholder: "0.000000",
|
|
64
|
+
value: value.rate,
|
|
65
|
+
onChange: edit("rate"),
|
|
66
|
+
"aria-invalid": invalid || void 0
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function FxRow({ id, label, computed, invalid, children }) {
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
75
|
+
className: "flex min-w-0 flex-col gap-1.5",
|
|
76
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
77
|
+
className: "flex items-baseline justify-between gap-2",
|
|
78
|
+
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
79
|
+
htmlFor: id,
|
|
80
|
+
invalid,
|
|
81
|
+
children: label
|
|
82
|
+
}), computed && /* @__PURE__ */ jsx("span", {
|
|
83
|
+
className: "hud-sm text-hud-mark",
|
|
84
|
+
children: "auto"
|
|
85
|
+
})]
|
|
86
|
+
}), children]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export { FxConverter };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=fx-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-converter.js","names":[],"sources":["../../src/components/fx-converter.tsx"],"sourcesContent":["\"use client\";\n\nimport { editFx, type FxCurrencies, type FxField, type FxState } from \"../lib/fx\";\nimport { cn } from \"../lib/utils\";\nimport { useId } from \"react\";\nimport { FieldLabel } from \"./field\";\nimport { MoneyInput } from \"./money-input\";\n\ntype Currency = { code: string; minorUnits: number };\n\n/**\n * Three linked inputs for a cross-currency transfer: amount sent, amount received and rate.\n * Editing one recomputes the least recently edited of the other two (see lib/fx.ts).\n * Controlled: keep the FxState in the parent (start from `initialFxState()`).\n */\nexport function FxConverter({\n id: rootId,\n from,\n to,\n value,\n onChange,\n invalid,\n className,\n}: {\n /** Id of the root, e.g. to fault all three fields with `fault(id)`. */\n id?: string;\n from: Currency;\n to: Currency;\n value: FxState;\n onChange: (next: FxState) => void;\n invalid?: boolean;\n className?: string;\n}) {\n const id = useId();\n const c: FxCurrencies = { fromMinorUnits: from.minorUnits, toMinorUnits: to.minorUnits };\n const edit = (field: FxField) => (e: React.ChangeEvent<HTMLInputElement>) =>\n onChange(editFx(value, field, e.target.value, c));\n // The field that will be recomputed next is the oldest one; mark it so users can see it.\n const next = value.order[0];\n\n // Columns follow the converter's own width (it lives in sheets and narrow cards), not the viewport.\n return (\n <div id={rootId} data-fault-group className={cn(\"@container\", className)}>\n <div className=\"grid gap-3 @lg:grid-cols-3\">\n <FxRow\n id={`${id}-from`}\n label={`Sent (${from.code})`}\n computed={next === \"from\"}\n invalid={invalid}\n >\n <MoneyInput\n id={`${id}-from`}\n currency={from.code}\n value={value.from}\n onChange={edit(\"from\")}\n aria-invalid={invalid || undefined}\n />\n </FxRow>\n <FxRow\n id={`${id}-to`}\n label={`Received (${to.code})`}\n computed={next === \"to\"}\n invalid={invalid}\n >\n <MoneyInput\n id={`${id}-to`}\n currency={to.code}\n value={value.to}\n onChange={edit(\"to\")}\n aria-invalid={invalid || undefined}\n />\n </FxRow>\n <FxRow\n id={`${id}-rate`}\n label={`Rate (${to.code} per ${from.code})`}\n computed={next === \"rate\"}\n invalid={invalid}\n >\n <MoneyInput\n id={`${id}-rate`}\n currency=\"×\"\n placeholder=\"0.000000\"\n value={value.rate}\n onChange={edit(\"rate\")}\n aria-invalid={invalid || undefined}\n />\n </FxRow>\n </div>\n </div>\n );\n}\n\nfunction FxRow({\n id,\n label,\n computed,\n invalid,\n children,\n}: {\n id: string;\n label: string;\n computed: boolean;\n invalid?: boolean;\n children: React.ReactNode;\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <FieldLabel htmlFor={id} invalid={invalid}>\n {label}\n </FieldLabel>\n {computed && <span className=\"hud-sm text-hud-mark\">auto</span>}\n </div>\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,SAAgB,YAAY,EAC1B,IAAI,QACJ,MACA,IACA,OACA,UACA,SACA,aAUC;CACD,MAAM,KAAK,MAAM;CACjB,MAAM,IAAkB;EAAE,gBAAgB,KAAK;EAAY,cAAc,GAAG;CAAW;CACvF,MAAM,QAAQ,WAAoB,MAChC,SAAS,OAAO,OAAO,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC;CAElD,MAAM,OAAO,MAAM,MAAM;CAGzB,OACE,oBAAC,OAAD;EAAK,IAAI;EAAQ,oBAAA;EAAiB,WAAW,GAAG,cAAc,SAAS;EACrE,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,OAAD;KACE,IAAI,GAAG,GAAG;KACV,OAAO,SAAS,KAAK,KAAK;KAC1B,UAAU,SAAS;KACV;KAET,UAAA,oBAAC,YAAD;MACE,IAAI,GAAG,GAAG;MACV,UAAU,KAAK;MACf,OAAO,MAAM;MACb,UAAU,KAAK,MAAM;MACrB,gBAAc,WAAW,KAAA;KAC1B,CAAA;IACI,CAAA;IACP,oBAAC,OAAD;KACE,IAAI,GAAG,GAAG;KACV,OAAO,aAAa,GAAG,KAAK;KAC5B,UAAU,SAAS;KACV;KAET,UAAA,oBAAC,YAAD;MACE,IAAI,GAAG,GAAG;MACV,UAAU,GAAG;MACb,OAAO,MAAM;MACb,UAAU,KAAK,IAAI;MACnB,gBAAc,WAAW,KAAA;KAC1B,CAAA;IACI,CAAA;IACP,oBAAC,OAAD;KACE,IAAI,GAAG,GAAG;KACV,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,KAAK;KACzC,UAAU,SAAS;KACV;KAET,UAAA,oBAAC,YAAD;MACE,IAAI,GAAG,GAAG;MACV,UAAS;MACT,aAAY;MACZ,OAAO,MAAM;MACb,UAAU,KAAK,MAAM;MACrB,gBAAc,WAAW,KAAA;KAC1B,CAAA;IACI,CAAA;GACJ;;CACF,CAAA;AAET;AAEA,SAAS,MAAM,EACb,IACA,OACA,UACA,SACA,YAOC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,YAAD;IAAY,SAAS;IAAa;IAC/B,UAAA;GACS,CAAA,GACX,YAAY,oBAAC,QAAD;IAAM,WAAU;IAAuB,UAAA;GAAU,CAAA,CAC3D;EACJ,CAAA,GAAA,QACE;;AAET"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SpecItem } from "./spec-readout.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export type HeroProps = {
|
|
4
|
+
/** The page title or product name, set in display-xl. One per page. */
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
/** The line under the title, in HUD type: a tagline, a category, a role. */
|
|
7
|
+
subtitle?: React.ReactNode;
|
|
8
|
+
lead?: React.ReactNode;
|
|
9
|
+
/** Buttons under the lead. */
|
|
10
|
+
actions?: React.ReactNode;
|
|
11
|
+
specs?: SpecItem[];
|
|
12
|
+
/** An image for the studio frame: a product shot, a screenshot, a portrait. Without it the frame shows a crosshair. */
|
|
13
|
+
image?: React.ReactNode;
|
|
14
|
+
imageLabel?: string;
|
|
15
|
+
/** Replaces the studio frame and grill entirely. */
|
|
16
|
+
media?: React.ReactNode;
|
|
17
|
+
serial?: string;
|
|
18
|
+
coords?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
/** Studio-backdrop frame for the hero image, with an inner ring and a microprint tag. */
|
|
22
|
+
export declare function HeroFrame({ image, label }: {
|
|
23
|
+
image?: React.ReactNode;
|
|
24
|
+
label?: string;
|
|
25
|
+
}): React.JSX.Element;
|
|
26
|
+
/** The opening part of a page: title, subtitle, lead, actions and specs beside an image. */
|
|
27
|
+
export declare function Hero({ title, subtitle, lead, actions, specs, image, imageLabel, media, serial, coords, className }: HeroProps): React.JSX.Element;
|
|
28
|
+
//# sourceMappingURL=hero.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Crosshair, Grill } from "./hud.js";
|
|
3
|
+
import { SpecReadout } from "./spec-readout.js";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/hero.tsx
|
|
6
|
+
/** Studio-backdrop frame for the hero image, with an inner ring and a microprint tag. */
|
|
7
|
+
function HeroFrame({ image, label }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
className: "relative flex h-60 w-50 items-center justify-center overflow-hidden rounded-md bg-studio [&>img]:size-full [&>img]:object-cover",
|
|
10
|
+
children: [
|
|
11
|
+
image ?? /* @__PURE__ */ jsx(Crosshair, { className: "size-5 text-ink/45" }),
|
|
12
|
+
/* @__PURE__ */ jsx("span", {
|
|
13
|
+
"aria-hidden": true,
|
|
14
|
+
className: "pointer-events-none absolute inset-3.5 rounded-sm shadow-[inset_0_0_0_1px_rgba(255,255,255,0.55)]"
|
|
15
|
+
}),
|
|
16
|
+
label && /* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: "hud-sm absolute bottom-2.5 left-2.5 text-ink",
|
|
18
|
+
children: label
|
|
19
|
+
})
|
|
20
|
+
]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** The opening part of a page: title, subtitle, lead, actions and specs beside an image. */
|
|
24
|
+
function Hero({ title, subtitle, lead, actions, specs, image, imageLabel, media, serial, coords, className }) {
|
|
25
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
26
|
+
className: cn("relative drop-float", className),
|
|
27
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
28
|
+
"aria-hidden": true,
|
|
29
|
+
className: "absolute -top-1.5 left-6 z-10 h-3 w-18 rounded-full bg-signal md:left-16"
|
|
30
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
31
|
+
className: "relative grid gap-12 rounded-xl bg-shell notch-lg px-6 pt-12 pb-8 md:grid-cols-[1fr_auto] md:px-16 md:pt-16 md:pb-12",
|
|
32
|
+
children: [
|
|
33
|
+
serial && /* @__PURE__ */ jsx("span", {
|
|
34
|
+
className: "hud-sm absolute top-6 left-6 text-hud-mark md:left-16",
|
|
35
|
+
children: serial
|
|
36
|
+
}),
|
|
37
|
+
/* @__PURE__ */ jsxs("div", {
|
|
38
|
+
className: "flex min-w-0 flex-col gap-6",
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx("h1", {
|
|
41
|
+
className: "font-display text-display-lg text-ink md:text-display-xl",
|
|
42
|
+
children: title
|
|
43
|
+
}),
|
|
44
|
+
subtitle && /* @__PURE__ */ jsx("p", {
|
|
45
|
+
className: "hud text-signal-ink",
|
|
46
|
+
children: subtitle
|
|
47
|
+
}),
|
|
48
|
+
lead && /* @__PURE__ */ jsx("p", {
|
|
49
|
+
className: "max-w-[36em] text-body-lg text-ink-soft",
|
|
50
|
+
children: lead
|
|
51
|
+
}),
|
|
52
|
+
actions && /* @__PURE__ */ jsx("div", {
|
|
53
|
+
className: "flex flex-wrap items-center gap-3",
|
|
54
|
+
children: actions
|
|
55
|
+
}),
|
|
56
|
+
specs && /* @__PURE__ */ jsx(SpecReadout, { items: specs })
|
|
57
|
+
]
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ jsxs("div", {
|
|
60
|
+
className: "flex flex-col items-start gap-4 md:items-end",
|
|
61
|
+
children: [media ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(HeroFrame, {
|
|
62
|
+
image,
|
|
63
|
+
label: imageLabel
|
|
64
|
+
}), /* @__PURE__ */ jsx(Grill, {
|
|
65
|
+
count: 4,
|
|
66
|
+
slotWidth: 28,
|
|
67
|
+
gap: "8px"
|
|
68
|
+
})] }), coords && /* @__PURE__ */ jsx("span", {
|
|
69
|
+
className: "hud-sm text-hud-mark",
|
|
70
|
+
children: coords
|
|
71
|
+
})]
|
|
72
|
+
}),
|
|
73
|
+
/* @__PURE__ */ jsx(Crosshair, {
|
|
74
|
+
tone: "signal",
|
|
75
|
+
className: "absolute right-3.5 bottom-3.5"
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
})]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export { Hero, HeroFrame };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=hero.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hero.js","names":[],"sources":["../../src/components/hero.tsx"],"sourcesContent":["import type * as React from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Crosshair, Grill } from \"./hud\";\nimport { type SpecItem, SpecReadout } from \"./spec-readout\";\n\nexport type HeroProps = {\n /** The page title or product name, set in display-xl. One per page. */\n title: React.ReactNode;\n /** The line under the title, in HUD type: a tagline, a category, a role. */\n subtitle?: React.ReactNode;\n lead?: React.ReactNode;\n /** Buttons under the lead. */\n actions?: React.ReactNode;\n specs?: SpecItem[];\n /** An image for the studio frame: a product shot, a screenshot, a portrait. Without it the frame shows a crosshair. */\n image?: React.ReactNode;\n imageLabel?: string;\n /** Replaces the studio frame and grill entirely. */\n media?: React.ReactNode;\n serial?: string;\n coords?: string;\n className?: string;\n};\n\n/** Studio-backdrop frame for the hero image, with an inner ring and a microprint tag. */\nexport function HeroFrame({ image, label }: { image?: React.ReactNode; label?: string }) {\n return (\n <div className=\"relative flex h-60 w-50 items-center justify-center overflow-hidden rounded-md bg-studio [&>img]:size-full [&>img]:object-cover\">\n {image ?? <Crosshair className=\"size-5 text-ink/45\" />}\n <span\n aria-hidden\n className=\"pointer-events-none absolute inset-3.5 rounded-sm shadow-[inset_0_0_0_1px_rgba(255,255,255,0.55)]\"\n />\n {label && <span className=\"hud-sm absolute bottom-2.5 left-2.5 text-ink\">{label}</span>}\n </div>\n );\n}\n\n/** The opening part of a page: title, subtitle, lead, actions and specs beside an image. */\nexport function Hero({\n title,\n subtitle,\n lead,\n actions,\n specs,\n image,\n imageLabel,\n media,\n serial,\n coords,\n className,\n}: HeroProps) {\n return (\n <section className={cn(\"relative drop-float\", className)}>\n <span\n aria-hidden\n className=\"absolute -top-1.5 left-6 z-10 h-3 w-18 rounded-full bg-signal md:left-16\"\n />\n <div className=\"relative grid gap-12 rounded-xl bg-shell notch-lg px-6 pt-12 pb-8 md:grid-cols-[1fr_auto] md:px-16 md:pt-16 md:pb-12\">\n {serial && (\n <span className=\"hud-sm absolute top-6 left-6 text-hud-mark md:left-16\">{serial}</span>\n )}\n <div className=\"flex min-w-0 flex-col gap-6\">\n <h1 className=\"font-display text-display-lg text-ink md:text-display-xl\">{title}</h1>\n {subtitle && <p className=\"hud text-signal-ink\">{subtitle}</p>}\n {lead && <p className=\"max-w-[36em] text-body-lg text-ink-soft\">{lead}</p>}\n {actions && <div className=\"flex flex-wrap items-center gap-3\">{actions}</div>}\n {specs && <SpecReadout items={specs} />}\n </div>\n <div className=\"flex flex-col items-start gap-4 md:items-end\">\n {media ?? (\n <>\n <HeroFrame image={image} label={imageLabel} />\n <Grill count={4} slotWidth={28} gap=\"8px\" />\n </>\n )}\n {coords && <span className=\"hud-sm text-hud-mark\">{coords}</span>}\n </div>\n <Crosshair tone=\"signal\" className=\"absolute right-3.5 bottom-3.5\" />\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;AAyBA,SAAgB,UAAU,EAAE,OAAO,SAAsD;CACvF,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACG,SAAS,oBAAC,WAAD,EAAW,WAAU,qBAAsB,CAAA;GACrD,oBAAC,QAAD;IACE,eAAA;IACA,WAAU;GACX,CAAA;GACA,SAAS,oBAAC,QAAD;IAAM,WAAU;IAAgD,UAAA;GAAY,CAAA;EACnF;;AAET;;AAGA,SAAgB,KAAK,EACnB,OACA,UACA,MACA,SACA,OACA,OACA,YACA,OACA,QACA,QACA,aACY;CACZ,OACE,qBAAC,WAAD;EAAS,WAAW,GAAG,uBAAuB,SAAS;EAAvD,UAAA,CACE,oBAAC,QAAD;GACE,eAAA;GACA,WAAU;EACX,CAAA,GACD,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,UACC,oBAAC,QAAD;KAAM,WAAU;KAAyD,UAAA;IAAa,CAAA;IAExF,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,oBAAC,MAAD;OAAI,WAAU;OAA4D,UAAA;MAAU,CAAA;MACnF,YAAY,oBAAC,KAAD;OAAG,WAAU;OAAuB,UAAA;MAAY,CAAA;MAC5D,QAAQ,oBAAC,KAAD;OAAG,WAAU;OAA2C,UAAA;MAAQ,CAAA;MACxE,WAAW,oBAAC,OAAD;OAAK,WAAU;OAAqC,UAAA;MAAa,CAAA;MAC5E,SAAS,oBAAC,aAAD,EAAa,OAAO,MAAQ,CAAA;KACnC;;IACL,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,SACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,WAAD;MAAkB;MAAO,OAAO;KAAa,CAAA,GAC7C,oBAAC,OAAD;MAAO,OAAO;MAAG,WAAW;MAAI,KAAI;KAAO,CAAA,CAC3C,EAAA,CAAA,GAEH,UAAU,oBAAC,QAAD;MAAM,WAAU;MAAwB,UAAA;KAAa,CAAA,CAC7D;;IACL,oBAAC,WAAD;KAAW,MAAK;KAAS,WAAU;IAAiC,CAAA;GACjE;EACE,CAAA,CAAA;;AAEb"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** 12px plus-mark used as a registration mark on corners and frames. Decorative. */
|
|
3
|
+
export declare function Crosshair({ tone, className, ...props }: React.ComponentProps<"svg"> & {
|
|
4
|
+
tone?: "signal";
|
|
5
|
+
}): React.JSX.Element;
|
|
6
|
+
/** Mono overline: signal code chip, label, a seam rule and an optional end marker. */
|
|
7
|
+
export declare function HudLabel({ code, end, rule, className, children, ...props }: React.ComponentProps<"div"> & {
|
|
8
|
+
code?: string;
|
|
9
|
+
end?: React.ReactNode;
|
|
10
|
+
rule?: boolean;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
/** Measurement-tape strip: major ticks every 40px, minor every 8px. Decorative. */
|
|
13
|
+
export declare function TickRuler({ labels, className }: {
|
|
14
|
+
labels?: string[];
|
|
15
|
+
className?: string;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
/** LED dot with a word next to it. Color never carries the meaning alone. */
|
|
18
|
+
export declare function StatusLed({ tone, className, children, ...props }: React.ComponentProps<"span"> & {
|
|
19
|
+
tone?: "on" | "signal" | "off";
|
|
20
|
+
}): React.JSX.Element;
|
|
21
|
+
/** Pegboard slots: the product grill. Decorative. */
|
|
22
|
+
export declare function Grill({ count, slotWidth, gap, tone, className }: {
|
|
23
|
+
count?: number;
|
|
24
|
+
/** Slot width in px. Defaults to 36. */
|
|
25
|
+
slotWidth?: number;
|
|
26
|
+
/** Gap between slots as a CSS length. Defaults to 10px. */
|
|
27
|
+
gap?: string;
|
|
28
|
+
tone?: "signal" | "on-signal";
|
|
29
|
+
className?: string;
|
|
30
|
+
}): React.JSX.Element;
|
|
31
|
+
/** Section heading: HUD label with code above a Michroma title and an optional aside. */
|
|
32
|
+
export declare function SectionHeader({ title, code, label, aside, ruler, as: Tag, className }: {
|
|
33
|
+
title: React.ReactNode;
|
|
34
|
+
code?: string;
|
|
35
|
+
label?: React.ReactNode;
|
|
36
|
+
aside?: React.ReactNode;
|
|
37
|
+
ruler?: boolean;
|
|
38
|
+
as?: "h1" | "h2" | "h3";
|
|
39
|
+
className?: string;
|
|
40
|
+
}): React.JSX.Element;
|
|
41
|
+
//# sourceMappingURL=hud.d.ts.map
|