harebear-ui 0.0.0-stage → 0.2.2
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/AGENTS.md +66 -0
- package/LICENSE +21 -0
- package/README.md +92 -2
- package/bin/harebear-ui.mjs +125 -0
- package/dist/components/admin/activity-feed.d.ts +15 -0
- package/dist/components/admin/activity-feed.js +50 -0
- package/dist/components/admin/app-shell.d.ts +47 -0
- package/dist/components/admin/app-shell.js +108 -0
- package/dist/components/admin/callout.d.ts +7 -0
- package/dist/components/admin/callout.js +18 -0
- package/dist/components/admin/key-value-grid.d.ts +11 -0
- package/dist/components/admin/key-value-grid.js +23 -0
- package/dist/components/admin/link-tile.d.ts +17 -0
- package/dist/components/admin/link-tile.js +36 -0
- package/dist/components/admin/page-header.d.ts +14 -0
- package/dist/components/admin/page-header.js +41 -0
- package/dist/components/admin/search-input.d.ts +12 -0
- package/dist/components/admin/search-input.js +32 -0
- package/dist/components/admin/stat-card.d.ts +20 -0
- package/dist/components/admin/stat-card.js +53 -0
- package/dist/components/admin/status.d.ts +12 -0
- package/dist/components/admin/status.js +32 -0
- package/dist/components/admin/timeline.d.ts +13 -0
- package/dist/components/admin/timeline.js +36 -0
- package/dist/components/admin/usage-meter.d.ts +17 -0
- package/dist/components/admin/usage-meter.js +43 -0
- package/dist/components/admin/user-chip.d.ts +14 -0
- package/dist/components/admin/user-chip.js +38 -0
- package/dist/components/ai/chat.d.ts +44 -0
- package/dist/components/ai/chat.js +151 -0
- package/dist/components/ai/code-block.d.ts +27 -0
- package/dist/components/ai/code-block.js +63 -0
- package/dist/components/ai/conversation-list.d.ts +18 -0
- package/dist/components/ai/conversation-list.js +30 -0
- package/dist/components/ai/model-picker.d.ts +21 -0
- package/dist/components/ai/model-picker.js +55 -0
- package/dist/components/ai/prompt-input.d.ts +27 -0
- package/dist/components/ai/prompt-input.js +99 -0
- package/dist/components/auth/auth.d.ts +85 -0
- package/dist/components/auth/auth.js +325 -0
- package/dist/components/data/bar-list.d.ts +14 -0
- package/dist/components/data/bar-list.js +27 -0
- package/dist/components/data/data-table.d.ts +70 -0
- package/dist/components/data/data-table.js +208 -0
- package/dist/components/data/sparkline.d.ts +16 -0
- package/dist/components/data/sparkline.js +72 -0
- package/dist/components/data/status-bars.d.ts +17 -0
- package/dist/components/data/status-bars.js +37 -0
- package/dist/components/data/trend-chart.d.ts +31 -0
- package/dist/components/data/trend-chart.js +136 -0
- package/dist/components/theme/theme-provider.d.ts +42 -0
- package/dist/components/theme/theme-provider.js +110 -0
- package/dist/components/theme/theme-toggle.d.ts +5 -0
- package/dist/components/theme/theme-toggle.js +21 -0
- package/dist/components/ui/accordion.d.ts +7 -0
- package/dist/components/ui/accordion.js +53 -0
- package/dist/components/ui/alert-dialog.d.ts +18 -0
- package/dist/components/ui/alert-dialog.js +99 -0
- package/dist/components/ui/alert.d.ts +10 -0
- package/dist/components/ui/alert.js +42 -0
- package/dist/components/ui/aspect-ratio.d.ts +3 -0
- package/dist/components/ui/aspect-ratio.js +11 -0
- package/dist/components/ui/attachment.d.ts +24 -0
- package/dist/components/ui/attachment.js +100 -0
- package/dist/components/ui/avatar.d.ts +11 -0
- package/dist/components/ui/avatar.js +49 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/badge.js +30 -0
- package/dist/components/ui/breadcrumb.d.ts +11 -0
- package/dist/components/ui/breadcrumb.js +70 -0
- package/dist/components/ui/bubble.d.ts +17 -0
- package/dist/components/ui/bubble.js +71 -0
- package/dist/components/ui/button-group.d.ts +11 -0
- package/dist/components/ui/button-group.js +39 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/button.js +55 -0
- package/dist/components/ui/calendar.d.ts +10 -0
- package/dist/components/ui/calendar.js +108 -0
- package/dist/components/ui/card.d.ts +11 -0
- package/dist/components/ui/card.js +55 -0
- package/dist/components/ui/carousel.d.ts +28 -0
- package/dist/components/ui/carousel.js +131 -0
- package/dist/components/ui/chart.d.ts +44 -0
- package/dist/components/ui/chart.js +148 -0
- package/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/components/ui/checkbox.js +19 -0
- package/dist/components/ui/code-block.d.ts +26 -0
- package/dist/components/ui/code-block.js +123 -0
- package/dist/components/ui/collapsible.d.ts +5 -0
- package/dist/components/ui/collapsible.js +23 -0
- package/dist/components/ui/combobox.d.ts +24 -0
- package/dist/components/ui/combobox.js +162 -0
- package/dist/components/ui/command.d.ts +18 -0
- package/dist/components/ui/command.js +86 -0
- package/dist/components/ui/context-menu.d.ts +31 -0
- package/dist/components/ui/context-menu.js +123 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/dialog.js +94 -0
- package/dist/components/ui/direction.d.ts +7 -0
- package/dist/components/ui/direction.js +12 -0
- package/dist/components/ui/drawer.d.ts +13 -0
- package/dist/components/ui/drawer.js +76 -0
- package/dist/components/ui/dropdown-menu.d.ts +29 -0
- package/dist/components/ui/dropdown-menu.js +126 -0
- package/dist/components/ui/empty.d.ts +11 -0
- package/dist/components/ui/empty.js +59 -0
- package/dist/components/ui/field.d.ts +24 -0
- package/dist/components/ui/field.js +109 -0
- package/dist/components/ui/hover-card.d.ts +6 -0
- package/dist/components/ui/hover-card.js +30 -0
- package/dist/components/ui/input-group.d.ts +16 -0
- package/dist/components/ui/input-group.js +77 -0
- package/dist/components/ui/input-otp.d.ts +11 -0
- package/dist/components/ui/input-otp.js +46 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/input.js +13 -0
- package/dist/components/ui/item.d.ts +23 -0
- package/dist/components/ui/item.js +117 -0
- package/dist/components/ui/kbd.d.ts +3 -0
- package/dist/components/ui/kbd.js +19 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.js +13 -0
- package/dist/components/ui/marker.d.ts +11 -0
- package/dist/components/ui/marker.js +39 -0
- package/dist/components/ui/menubar.d.ts +30 -0
- package/dist/components/ui/menubar.js +133 -0
- package/dist/components/ui/message-scroller.d.ts +10 -0
- package/dist/components/ui/message-scroller.js +59 -0
- package/dist/components/ui/message.d.ts +10 -0
- package/dist/components/ui/message.js +48 -0
- package/dist/components/ui/native-select.d.ts +8 -0
- package/dist/components/ui/native-select.js +37 -0
- package/dist/components/ui/navigation-menu.d.ts +14 -0
- package/dist/components/ui/navigation-menu.js +79 -0
- package/dist/components/ui/pagination.d.ts +17 -0
- package/dist/components/ui/pagination.js +79 -0
- package/dist/components/ui/popover.d.ts +10 -0
- package/dist/components/ui/popover.js +54 -0
- package/dist/components/ui/progress.d.ts +4 -0
- package/dist/components/ui/progress.js +18 -0
- package/dist/components/ui/questionnaire.d.ts +19 -0
- package/dist/components/ui/questionnaire.js +168 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.js +25 -0
- package/dist/components/ui/resizable.d.ts +7 -0
- package/dist/components/ui/resizable.js +27 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/scroll-area.js +35 -0
- package/dist/components/ui/select.d.ts +15 -0
- package/dist/components/ui/select.js +98 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +15 -0
- package/dist/components/ui/sheet.d.ts +14 -0
- package/dist/components/ui/sheet.js +88 -0
- package/dist/components/ui/sidebar.d.ts +69 -0
- package/dist/components/ui/sidebar.js +377 -0
- package/dist/components/ui/skeleton.d.ts +2 -0
- package/dist/components/ui/skeleton.js +12 -0
- package/dist/components/ui/slider.d.ts +4 -0
- package/dist/components/ui/slider.js +35 -0
- package/dist/components/ui/sonner.d.ts +3 -0
- package/dist/components/ui/sonner.js +29 -0
- package/dist/components/ui/spinner.d.ts +2 -0
- package/dist/components/ui/spinner.js +15 -0
- package/dist/components/ui/switch.d.ts +6 -0
- package/dist/components/ui/switch.js +18 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/table.js +65 -0
- package/dist/components/ui/tabs.d.ts +11 -0
- package/dist/components/ui/tabs.js +45 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/textarea.js +12 -0
- package/dist/components/ui/toggle-group.d.ts +10 -0
- package/dist/components/ui/toggle-group.js +50 -0
- package/dist/components/ui/toggle.d.ts +9 -0
- package/dist/components/ui/toggle.js +35 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/components/ui/tooltip.js +34 -0
- package/dist/components/ui/trace.d.ts +18 -0
- package/dist/components/ui/trace.js +74 -0
- package/dist/hooks/use-copy-to-clipboard.d.ts +5 -0
- package/dist/hooks/use-copy-to-clipboard.js +24 -0
- package/dist/hooks/use-highlighted-code.d.ts +2 -0
- package/dist/hooks/use-highlighted-code.js +54 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +17 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +94 -0
- package/dist/lib/highlighter.d.ts +9 -0
- package/dist/lib/highlighter.js +77 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.js +8 -0
- package/dist/shadcn-base.css +638 -0
- package/dist/styles.css +188 -0
- package/docs/COMPONENTS.md +405 -0
- package/llms.txt +36 -0
- package/package.json +119 -4
- package/skills/harebear-ui/SKILL.md +34 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface PageHeaderProps extends Omit<React.ComponentProps<"section">, "title"> {
|
|
3
|
+
title: React.ReactNode;
|
|
4
|
+
description?: React.ReactNode;
|
|
5
|
+
/** Small count shown next to the title, e.g. 248. */
|
|
6
|
+
count?: React.ReactNode;
|
|
7
|
+
/** Right-aligned controls (buttons, segmented filters). */
|
|
8
|
+
actions?: React.ReactNode;
|
|
9
|
+
/** Text above the title, e.g. a date. */
|
|
10
|
+
eyebrow?: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/** Page title row with description and actions. Wraps on narrow screens. */
|
|
13
|
+
declare function PageHeader({ title, description, count, actions, eyebrow, className, ...props }: PageHeaderProps): React.JSX.Element;
|
|
14
|
+
export { PageHeader };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Badge } from "../ui/badge.js";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/admin/page-header.tsx
|
|
6
|
+
/** Page title row with description and actions. Wraps on narrow screens. */
|
|
7
|
+
function PageHeader({ title, description, count, actions, eyebrow, className, ...props }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
9
|
+
"data-slot": "page-header",
|
|
10
|
+
className: cn("flex flex-wrap items-end justify-between gap-4", className),
|
|
11
|
+
...props,
|
|
12
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
13
|
+
className: "flex min-w-0 flex-col gap-1.5",
|
|
14
|
+
children: [
|
|
15
|
+
eyebrow && /* @__PURE__ */ jsx("p", {
|
|
16
|
+
className: "font-medium text-muted-foreground",
|
|
17
|
+
children: eyebrow
|
|
18
|
+
}),
|
|
19
|
+
/* @__PURE__ */ jsxs("div", {
|
|
20
|
+
className: "flex items-center gap-3",
|
|
21
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
22
|
+
className: "text-[28px] leading-tight font-semibold tracking-[-0.02em]",
|
|
23
|
+
children: title
|
|
24
|
+
}), count !== void 0 && /* @__PURE__ */ jsx(Badge, {
|
|
25
|
+
variant: "secondary",
|
|
26
|
+
className: "tabular-nums",
|
|
27
|
+
children: count
|
|
28
|
+
})]
|
|
29
|
+
}),
|
|
30
|
+
description && /* @__PURE__ */ jsx("p", {
|
|
31
|
+
className: "text-muted-foreground",
|
|
32
|
+
children: description
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
}), actions && /* @__PURE__ */ jsx("div", {
|
|
36
|
+
className: "flex flex-wrap items-center gap-2.5",
|
|
37
|
+
children: actions
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export { PageHeader };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface SearchInputProps extends Omit<React.ComponentProps<"input">, "size"> {
|
|
3
|
+
/** Keyboard hint shown at the right, e.g. "⌘K" or "/". Display only. */
|
|
4
|
+
shortcut?: React.ReactNode;
|
|
5
|
+
/** "lg" is the tall, pill-shaped hero search. */
|
|
6
|
+
size?: "default" | "lg";
|
|
7
|
+
/** Classes for the wrapping label. */
|
|
8
|
+
wrapperClassName?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Search field with leading icon and optional shortcut hint. */
|
|
11
|
+
declare function SearchInput({ shortcut, size, className, wrapperClassName, "aria-label": ariaLabel, ...props }: SearchInputProps): React.JSX.Element;
|
|
12
|
+
export { SearchInput };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Input } from "../ui/input.js";
|
|
3
|
+
import { Kbd } from "../ui/kbd.js";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { SearchIcon } from "lucide-react";
|
|
7
|
+
// src/components/admin/search-input.tsx
|
|
8
|
+
/** Search field with leading icon and optional shortcut hint. */
|
|
9
|
+
function SearchInput({ shortcut, size = "default", className, wrapperClassName, "aria-label": ariaLabel = "Search", ...props }) {
|
|
10
|
+
const lg = size === "lg";
|
|
11
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
12
|
+
"data-slot": "search-input",
|
|
13
|
+
className: cn("relative block", wrapperClassName),
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsx(SearchIcon, {
|
|
16
|
+
"aria-hidden": "true",
|
|
17
|
+
className: cn("pointer-events-none absolute top-1/2 size-[18px] -translate-y-1/2 text-muted-foreground", lg ? "left-5" : "left-3.5")
|
|
18
|
+
}),
|
|
19
|
+
/* @__PURE__ */ jsx(Input, {
|
|
20
|
+
type: "search",
|
|
21
|
+
"aria-label": ariaLabel,
|
|
22
|
+
className: cn(lg ? "h-13.5 rounded-full border-border bg-card pl-13.5 text-[15px] shadow-card md:text-[15px]" : "pl-10.5", shortcut ? lg ? "pr-15" : "pr-13" : void 0, className),
|
|
23
|
+
...props
|
|
24
|
+
}),
|
|
25
|
+
shortcut && /* @__PURE__ */ jsx(Kbd, {
|
|
26
|
+
className: cn("absolute top-1/2 -translate-y-1/2", lg ? "right-4.5" : "right-2.5"),
|
|
27
|
+
children: shortcut
|
|
28
|
+
})
|
|
29
|
+
]
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export { SearchInput };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface StatCardProps extends Omit<React.ComponentProps<"div">, "title"> {
|
|
3
|
+
label: React.ReactNode;
|
|
4
|
+
value: React.ReactNode;
|
|
5
|
+
/** Change text, e.g. "12.4%" or "18 ms". */
|
|
6
|
+
delta?: React.ReactNode;
|
|
7
|
+
/** Arrow direction for the delta. */
|
|
8
|
+
trend?: "up" | "down";
|
|
9
|
+
/** Whether the change is good (green) or bad (red). Defaults to trend === "up". */
|
|
10
|
+
positive?: boolean;
|
|
11
|
+
/** Text after the delta, e.g. "vs last month". */
|
|
12
|
+
note?: React.ReactNode;
|
|
13
|
+
/** Icon element shown top-right in a tinted circle. */
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
/** Optional sparkline series. */
|
|
16
|
+
data?: number[];
|
|
17
|
+
}
|
|
18
|
+
/** KPI tile: label, big number, delta badge, optional sparkline. */
|
|
19
|
+
declare function StatCard({ label, value, delta, trend, positive, note, icon, data, className, ...props }: StatCardProps): React.JSX.Element;
|
|
20
|
+
export { StatCard };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Badge } from "../ui/badge.js";
|
|
3
|
+
import { Card } from "../ui/card.js";
|
|
4
|
+
import { Sparkline } from "../data/sparkline.js";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { ArrowDownRightIcon, ArrowUpRightIcon } from "lucide-react";
|
|
8
|
+
// src/components/admin/stat-card.tsx
|
|
9
|
+
/** KPI tile: label, big number, delta badge, optional sparkline. */
|
|
10
|
+
function StatCard({ label, value, delta, trend = "up", positive, note, icon, data, className, ...props }) {
|
|
11
|
+
const good = positive ?? trend === "up";
|
|
12
|
+
const Arrow = trend === "up" ? ArrowUpRightIcon : ArrowDownRightIcon;
|
|
13
|
+
return /* @__PURE__ */ jsxs(Card, {
|
|
14
|
+
"data-slot": "stat-card",
|
|
15
|
+
className: cn("gap-3.5 px-5.5 pt-5.5 pb-4.5", className),
|
|
16
|
+
...props,
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsxs("div", {
|
|
19
|
+
className: "flex items-center justify-between gap-3",
|
|
20
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
21
|
+
className: "font-medium text-muted-foreground",
|
|
22
|
+
children: label
|
|
23
|
+
}), icon && /* @__PURE__ */ jsx("span", {
|
|
24
|
+
className: "grid size-8.5 shrink-0 place-items-center rounded-full bg-primary-soft text-primary [&_svg]:size-4",
|
|
25
|
+
children: icon
|
|
26
|
+
})]
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ jsx("div", {
|
|
29
|
+
className: "text-[30px] leading-none font-semibold tracking-[-0.02em] tabular-nums",
|
|
30
|
+
children: value
|
|
31
|
+
}),
|
|
32
|
+
(delta || note) && /* @__PURE__ */ jsxs("div", {
|
|
33
|
+
className: "flex items-center gap-2 text-[13px]",
|
|
34
|
+
children: [delta && /* @__PURE__ */ jsxs(Badge, {
|
|
35
|
+
variant: "secondary",
|
|
36
|
+
className: "gap-1 px-2",
|
|
37
|
+
children: [/* @__PURE__ */ jsx(Arrow, {
|
|
38
|
+
className: cn(good ? "text-success" : "text-destructive"),
|
|
39
|
+
strokeWidth: 2.2
|
|
40
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
41
|
+
className: "tabular-nums",
|
|
42
|
+
children: delta
|
|
43
|
+
})]
|
|
44
|
+
}), note && /* @__PURE__ */ jsx("span", {
|
|
45
|
+
className: "text-muted-foreground",
|
|
46
|
+
children: note
|
|
47
|
+
})]
|
|
48
|
+
}),
|
|
49
|
+
data && data.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data })
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export { StatCard };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Badge } from "../ui/badge.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export type StatusTone = "success" | "warning" | "danger" | "info" | "neutral";
|
|
4
|
+
/** Small colored dot. Use for status, legends, and project markers. */
|
|
5
|
+
declare function StatusDot({ tone, className, ...props }: React.ComponentProps<"span"> & {
|
|
6
|
+
tone?: StatusTone;
|
|
7
|
+
}): React.JSX.Element;
|
|
8
|
+
/** Pill with a status dot and label, e.g. Paid / Pending / Refunded. */
|
|
9
|
+
declare function StatusBadge({ tone, variant, children, className, ...props }: React.ComponentProps<typeof Badge> & {
|
|
10
|
+
tone?: StatusTone;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
export { StatusBadge, StatusDot };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Badge } from "../ui/badge.js";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/admin/status.tsx
|
|
6
|
+
const toneColor = {
|
|
7
|
+
success: "bg-success",
|
|
8
|
+
warning: "bg-warning",
|
|
9
|
+
danger: "bg-destructive",
|
|
10
|
+
info: "bg-primary",
|
|
11
|
+
neutral: "bg-muted-foreground"
|
|
12
|
+
};
|
|
13
|
+
/** Small colored dot. Use for status, legends, and project markers. */
|
|
14
|
+
function StatusDot({ tone = "neutral", className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx("span", {
|
|
16
|
+
"data-slot": "status-dot",
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
className: cn("inline-block size-2 shrink-0 rounded-full", toneColor[tone], className),
|
|
19
|
+
...props
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** Pill with a status dot and label, e.g. Paid / Pending / Refunded. */
|
|
23
|
+
function StatusBadge({ tone = "neutral", variant = "secondary", children, className, ...props }) {
|
|
24
|
+
return /* @__PURE__ */ jsxs(Badge, {
|
|
25
|
+
"data-slot": "status-badge",
|
|
26
|
+
variant,
|
|
27
|
+
className,
|
|
28
|
+
...props,
|
|
29
|
+
children: [/* @__PURE__ */ jsx(StatusDot, { tone }), children]
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export { StatusBadge, StatusDot };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StatusTone } from "./status.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export interface TimelineItem {
|
|
4
|
+
id?: string;
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
time: React.ReactNode;
|
|
7
|
+
tone?: StatusTone;
|
|
8
|
+
}
|
|
9
|
+
/** Vertical event list with connecting rail. */
|
|
10
|
+
declare function Timeline({ items, className, ...props }: Omit<React.ComponentProps<"ol">, "children"> & {
|
|
11
|
+
items: TimelineItem[];
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
export { Timeline };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
// src/components/admin/timeline.tsx
|
|
5
|
+
const dot = {
|
|
6
|
+
success: "bg-success",
|
|
7
|
+
warning: "bg-warning",
|
|
8
|
+
danger: "bg-destructive",
|
|
9
|
+
info: "bg-primary",
|
|
10
|
+
neutral: "bg-muted-foreground"
|
|
11
|
+
};
|
|
12
|
+
/** Vertical event list with connecting rail. */
|
|
13
|
+
function Timeline({ items, className, ...props }) {
|
|
14
|
+
return /* @__PURE__ */ jsx("ol", {
|
|
15
|
+
"data-slot": "timeline",
|
|
16
|
+
className: cn("flex flex-col", className),
|
|
17
|
+
...props,
|
|
18
|
+
children: items.map((t, i) => /* @__PURE__ */ jsxs("li", {
|
|
19
|
+
className: "flex gap-3.5",
|
|
20
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
21
|
+
className: "flex w-2.5 flex-col items-center pt-1.5",
|
|
22
|
+
children: [/* @__PURE__ */ jsx("span", { className: cn("size-2.5 shrink-0 rounded-full ring-3 ring-card", dot[t.tone ?? "info"]) }), i < items.length - 1 && /* @__PURE__ */ jsx("span", { className: "mt-1.5 mb-0.5 w-0.5 flex-1 rounded-full bg-chart-grid" })]
|
|
23
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
24
|
+
className: "flex flex-col gap-px pb-4 text-[13px]",
|
|
25
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
26
|
+
className: "font-medium",
|
|
27
|
+
children: t.title
|
|
28
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
29
|
+
className: "text-xs text-muted-foreground",
|
|
30
|
+
children: t.time
|
|
31
|
+
})]
|
|
32
|
+
})]
|
|
33
|
+
}, t.id ?? i))
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export { Timeline };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface UsageMeterProps extends Omit<React.ComponentProps<"div">, "children"> {
|
|
3
|
+
label: React.ReactNode;
|
|
4
|
+
/** 0-100. */
|
|
5
|
+
percent: number;
|
|
6
|
+
/** Bold value text at the right, e.g. "68%" or "34 GB". */
|
|
7
|
+
value?: React.ReactNode;
|
|
8
|
+
/** Muted text after the value, e.g. "of 50 GB". */
|
|
9
|
+
detail?: React.ReactNode;
|
|
10
|
+
/** Bar color (CSS color). Default primary. Use "var(--warning)" etc. for thresholds. */
|
|
11
|
+
color?: string;
|
|
12
|
+
/** Track color. Default muted. */
|
|
13
|
+
trackClassName?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Label/value row over a rounded bar. For storage, quotas, traffic share, CPU. */
|
|
16
|
+
declare function UsageMeter({ label, percent, value, detail, color, trackClassName, className, ...props }: UsageMeterProps): React.JSX.Element;
|
|
17
|
+
export { UsageMeter };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
// src/components/admin/usage-meter.tsx
|
|
5
|
+
/** Label/value row over a rounded bar. For storage, quotas, traffic share, CPU. */
|
|
6
|
+
function UsageMeter({ label, percent, value, detail, color, trackClassName, className, ...props }) {
|
|
7
|
+
const pct = Math.max(0, Math.min(100, percent));
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9
|
+
"data-slot": "usage-meter",
|
|
10
|
+
className: cn("flex flex-col gap-2", className),
|
|
11
|
+
...props,
|
|
12
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
13
|
+
className: "flex items-baseline justify-between gap-3 text-[13px]",
|
|
14
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
15
|
+
className: "font-medium",
|
|
16
|
+
children: label
|
|
17
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
18
|
+
className: "tabular-nums",
|
|
19
|
+
children: [value !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
20
|
+
className: "font-semibold",
|
|
21
|
+
children: value
|
|
22
|
+
}), detail !== void 0 && /* @__PURE__ */ jsxs("span", {
|
|
23
|
+
className: "text-muted-foreground",
|
|
24
|
+
children: [" ", detail]
|
|
25
|
+
})]
|
|
26
|
+
})]
|
|
27
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
28
|
+
role: "meter",
|
|
29
|
+
"aria-valuemin": 0,
|
|
30
|
+
"aria-valuemax": 100,
|
|
31
|
+
"aria-valuenow": pct,
|
|
32
|
+
className: cn("h-2 overflow-hidden rounded-full bg-muted", trackClassName),
|
|
33
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
34
|
+
className: "block h-full rounded-full bg-primary transition-[width]",
|
|
35
|
+
style: {
|
|
36
|
+
width: `${pct}%`,
|
|
37
|
+
background: color
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
})]
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export { UsageMeter };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Up to two initials from a name: "Maya Chen" -> "MC". */
|
|
3
|
+
export declare function initials(name: string): string;
|
|
4
|
+
export interface UserChipProps extends React.ComponentProps<"div"> {
|
|
5
|
+
name: string;
|
|
6
|
+
subtitle?: React.ReactNode;
|
|
7
|
+
avatarUrl?: string;
|
|
8
|
+
/** Trailing control, e.g. a menu button. */
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
size?: "sm" | "default" | "lg";
|
|
11
|
+
}
|
|
12
|
+
/** Avatar + name + secondary line. */
|
|
13
|
+
declare function UserChip({ name, subtitle, avatarUrl, action, size, className, ...props }: UserChipProps): React.JSX.Element;
|
|
14
|
+
export { UserChip };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar.js";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
// src/components/admin/user-chip.tsx
|
|
6
|
+
/** Up to two initials from a name: "Maya Chen" -> "MC". */
|
|
7
|
+
function initials(name) {
|
|
8
|
+
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase()).join("");
|
|
9
|
+
}
|
|
10
|
+
/** Avatar + name + secondary line. */
|
|
11
|
+
function UserChip({ name, subtitle, avatarUrl, action, size = "default", className, ...props }) {
|
|
12
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
13
|
+
"data-slot": "user-chip",
|
|
14
|
+
className: cn("flex min-w-0 items-center gap-3", className),
|
|
15
|
+
...props,
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ jsxs(Avatar, {
|
|
18
|
+
size,
|
|
19
|
+
children: [avatarUrl && /* @__PURE__ */ jsx(AvatarImage, {
|
|
20
|
+
src: avatarUrl,
|
|
21
|
+
alt: ""
|
|
22
|
+
}), /* @__PURE__ */ jsx(AvatarFallback, { children: initials(name) })]
|
|
23
|
+
}),
|
|
24
|
+
/* @__PURE__ */ jsxs("div", {
|
|
25
|
+
className: "min-w-0 flex-1 leading-snug",
|
|
26
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
27
|
+
className: cn("truncate font-medium", size === "lg" && "text-lg font-semibold"),
|
|
28
|
+
children: name
|
|
29
|
+
}), subtitle && /* @__PURE__ */ jsx("div", {
|
|
30
|
+
className: "truncate text-xs font-medium text-muted-foreground",
|
|
31
|
+
children: subtitle
|
|
32
|
+
})]
|
|
33
|
+
}),
|
|
34
|
+
action
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export { UserChip, initials };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Badge } from "../ui/badge.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export interface ChatThreadProps extends React.ComponentProps<"div"> {
|
|
4
|
+
/** Keep scrolled to the bottom as content grows, unless the user scrolled up. Default true. */
|
|
5
|
+
autoScroll?: boolean;
|
|
6
|
+
/** Classes for the centered inner column (max width 760px). */
|
|
7
|
+
contentClassName?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Scrollable message column. Put ChatMessage children inside; give it a bounded height (flex-1 in a column). */
|
|
10
|
+
declare function ChatThread({ autoScroll, className, contentClassName, children, ...props }: ChatThreadProps): React.JSX.Element;
|
|
11
|
+
export interface ChatMessageProps extends React.ComponentProps<"div"> {
|
|
12
|
+
role: "user" | "assistant";
|
|
13
|
+
/** Assistant avatar. Defaults to a sparkle in a tinted circle. */
|
|
14
|
+
avatar?: React.ReactNode;
|
|
15
|
+
/** Rendered under assistant content, usually <MessageActions />. */
|
|
16
|
+
actions?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/** One chat turn. User: right-aligned bubble. Assistant: avatar + free-flowing content. */
|
|
19
|
+
declare function ChatMessage({ role, avatar, actions, className, children, ...props }: ChatMessageProps): React.JSX.Element;
|
|
20
|
+
/** Tinted circle with an icon. Default assistant avatar. */
|
|
21
|
+
declare function AssistantAvatar({ icon, className }: {
|
|
22
|
+
icon?: React.ReactNode;
|
|
23
|
+
className?: string;
|
|
24
|
+
}): React.JSX.Element;
|
|
25
|
+
export interface MessageActionsProps extends React.ComponentProps<"div"> {
|
|
26
|
+
/** Text copied by the copy button. Omit to hide it. */
|
|
27
|
+
copyText?: string;
|
|
28
|
+
onRegenerate?: () => void;
|
|
29
|
+
onFeedback?: (value: "up" | "down") => void;
|
|
30
|
+
/** Currently selected feedback, for a pressed state. */
|
|
31
|
+
feedback?: "up" | "down" | null;
|
|
32
|
+
}
|
|
33
|
+
/** Copy / regenerate / thumbs row under an assistant message. Add more buttons as children. */
|
|
34
|
+
declare function MessageActions({ copyText, onRegenerate, onFeedback, feedback, className, children, ...props }: MessageActionsProps): React.JSX.Element;
|
|
35
|
+
/** Three pulsing dots while the assistant is generating. */
|
|
36
|
+
declare function TypingIndicator({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
37
|
+
export interface ToolCallProps extends React.ComponentProps<typeof Badge> {
|
|
38
|
+
/** "running" shows a spinner; "error" tints red. */
|
|
39
|
+
status?: "running" | "done" | "error";
|
|
40
|
+
icon?: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/** Outlined chip summarizing a tool call, e.g. "Read 2 notes from homelab/". */
|
|
43
|
+
declare function ToolCall({ status, icon, className, children, ...props }: ToolCallProps): React.JSX.Element;
|
|
44
|
+
export { AssistantAvatar, ChatMessage, ChatThread, MessageActions, ToolCall, TypingIndicator };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Badge } from "../ui/badge.js";
|
|
3
|
+
import { Button } from "../ui/button.js";
|
|
4
|
+
import { Spinner } from "../ui/spinner.js";
|
|
5
|
+
import { useCopyToClipboard } from "../../hooks/use-copy-to-clipboard.js";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { CheckIcon, CopyIcon, RefreshCwIcon, SparklesIcon, ThumbsDownIcon, ThumbsUpIcon } from "lucide-react";
|
|
10
|
+
// src/components/ai/chat.tsx
|
|
11
|
+
/** Scrollable message column. Put ChatMessage children inside; give it a bounded height (flex-1 in a column). */
|
|
12
|
+
function ChatThread({ autoScroll = true, className, contentClassName, children, ...props }) {
|
|
13
|
+
const ref = React.useRef(null);
|
|
14
|
+
const pinned = React.useRef(true);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
const el = ref.current;
|
|
17
|
+
if (!el || !autoScroll) return;
|
|
18
|
+
const inner = el.firstElementChild;
|
|
19
|
+
const stick = () => {
|
|
20
|
+
if (pinned.current) el.scrollTop = el.scrollHeight;
|
|
21
|
+
};
|
|
22
|
+
stick();
|
|
23
|
+
const ro = new ResizeObserver(stick);
|
|
24
|
+
if (inner) ro.observe(inner);
|
|
25
|
+
return () => ro.disconnect();
|
|
26
|
+
}, [autoScroll]);
|
|
27
|
+
return /* @__PURE__ */ jsx("div", {
|
|
28
|
+
ref,
|
|
29
|
+
"data-slot": "chat-thread",
|
|
30
|
+
role: "log",
|
|
31
|
+
"aria-live": "polite",
|
|
32
|
+
onScroll: (e) => {
|
|
33
|
+
const el = e.currentTarget;
|
|
34
|
+
pinned.current = el.scrollHeight - el.scrollTop - el.clientHeight < 48;
|
|
35
|
+
},
|
|
36
|
+
className: cn("min-h-0 flex-1 overflow-y-auto px-6 pt-6 pb-2", className),
|
|
37
|
+
...props,
|
|
38
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
39
|
+
className: cn("mx-auto flex max-w-190 flex-col gap-9", contentClassName),
|
|
40
|
+
children
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** One chat turn. User: right-aligned bubble. Assistant: avatar + free-flowing content. */
|
|
45
|
+
function ChatMessage({ role, avatar, actions, className, children, ...props }) {
|
|
46
|
+
if (role === "user") return /* @__PURE__ */ jsx("div", {
|
|
47
|
+
"data-slot": "chat-message",
|
|
48
|
+
"data-role": "user",
|
|
49
|
+
className: cn("flex justify-end", className),
|
|
50
|
+
...props,
|
|
51
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
52
|
+
className: "max-w-[80%] rounded-[calc(var(--radius-xl)*1.2)] rounded-br-sm bg-muted px-4.5 py-3 text-[15px] whitespace-pre-wrap",
|
|
53
|
+
children
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
57
|
+
"data-slot": "chat-message",
|
|
58
|
+
"data-role": "assistant",
|
|
59
|
+
className: cn("flex items-start gap-4", className),
|
|
60
|
+
...props,
|
|
61
|
+
children: [avatar ?? /* @__PURE__ */ jsx(AssistantAvatar, {}), /* @__PURE__ */ jsxs("div", {
|
|
62
|
+
className: "flex min-w-0 flex-1 flex-col gap-3.5",
|
|
63
|
+
children: [children, actions]
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Tinted circle with an icon. Default assistant avatar. */
|
|
68
|
+
function AssistantAvatar({ icon = /* @__PURE__ */ jsx(SparklesIcon, {}), className }) {
|
|
69
|
+
return /* @__PURE__ */ jsx("div", {
|
|
70
|
+
"data-slot": "assistant-avatar",
|
|
71
|
+
className: cn("grid size-8 shrink-0 place-items-center rounded-full bg-primary-soft text-primary [&_svg]:size-4", className),
|
|
72
|
+
children: icon
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Copy / regenerate / thumbs row under an assistant message. Add more buttons as children. */
|
|
76
|
+
function MessageActions({ copyText, onRegenerate, onFeedback, feedback, className, children, ...props }) {
|
|
77
|
+
const { copied, copy } = useCopyToClipboard();
|
|
78
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
79
|
+
"data-slot": "message-actions",
|
|
80
|
+
className: cn("-ml-2 flex gap-0.5", className),
|
|
81
|
+
...props,
|
|
82
|
+
children: [
|
|
83
|
+
copyText !== void 0 && /* @__PURE__ */ jsx(Button, {
|
|
84
|
+
type: "button",
|
|
85
|
+
variant: "ghost",
|
|
86
|
+
size: "icon-sm",
|
|
87
|
+
"aria-label": "Copy response",
|
|
88
|
+
onClick: () => copy(copyText),
|
|
89
|
+
children: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {})
|
|
90
|
+
}),
|
|
91
|
+
onRegenerate && /* @__PURE__ */ jsx(Button, {
|
|
92
|
+
type: "button",
|
|
93
|
+
variant: "ghost",
|
|
94
|
+
size: "icon-sm",
|
|
95
|
+
"aria-label": "Regenerate",
|
|
96
|
+
onClick: onRegenerate,
|
|
97
|
+
children: /* @__PURE__ */ jsx(RefreshCwIcon, {})
|
|
98
|
+
}),
|
|
99
|
+
onFeedback && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
100
|
+
type: "button",
|
|
101
|
+
variant: "ghost",
|
|
102
|
+
size: "icon-sm",
|
|
103
|
+
"aria-label": "Good response",
|
|
104
|
+
"aria-pressed": feedback === "up",
|
|
105
|
+
className: "aria-pressed:text-primary",
|
|
106
|
+
onClick: () => onFeedback("up"),
|
|
107
|
+
children: /* @__PURE__ */ jsx(ThumbsUpIcon, {})
|
|
108
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
109
|
+
type: "button",
|
|
110
|
+
variant: "ghost",
|
|
111
|
+
size: "icon-sm",
|
|
112
|
+
"aria-label": "Bad response",
|
|
113
|
+
"aria-pressed": feedback === "down",
|
|
114
|
+
className: "aria-pressed:text-primary",
|
|
115
|
+
onClick: () => onFeedback("down"),
|
|
116
|
+
children: /* @__PURE__ */ jsx(ThumbsDownIcon, {})
|
|
117
|
+
})] }),
|
|
118
|
+
children
|
|
119
|
+
]
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** Three pulsing dots while the assistant is generating. */
|
|
123
|
+
function TypingIndicator({ className, ...props }) {
|
|
124
|
+
return /* @__PURE__ */ jsx("div", {
|
|
125
|
+
"data-slot": "typing-indicator",
|
|
126
|
+
role: "status",
|
|
127
|
+
"aria-label": "Assistant is typing",
|
|
128
|
+
className: cn("flex gap-1.25 py-1", className),
|
|
129
|
+
...props,
|
|
130
|
+
children: [
|
|
131
|
+
0,
|
|
132
|
+
150,
|
|
133
|
+
300
|
|
134
|
+
].map((d) => /* @__PURE__ */ jsx("span", {
|
|
135
|
+
className: "inline-block size-1.5 animate-typing rounded-full bg-muted-foreground",
|
|
136
|
+
style: { animationDelay: `${d}ms` }
|
|
137
|
+
}, d))
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** Outlined chip summarizing a tool call, e.g. "Read 2 notes from homelab/". */
|
|
141
|
+
function ToolCall({ status = "done", icon, className, children, ...props }) {
|
|
142
|
+
return /* @__PURE__ */ jsxs(Badge, {
|
|
143
|
+
"data-slot": "tool-call",
|
|
144
|
+
"data-status": status,
|
|
145
|
+
variant: "outline",
|
|
146
|
+
className: cn("self-start bg-transparent text-muted-foreground", status === "error" && "border-destructive/40 text-destructive", className),
|
|
147
|
+
...props,
|
|
148
|
+
children: [status === "running" ? /* @__PURE__ */ jsx(Spinner, {}) : icon, children]
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
export { AssistantAvatar, ChatMessage, ChatThread, MessageActions, ToolCall, TypingIndicator };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CodeBlock } from "../ui/code-block.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export interface CodeSnippetProps extends Omit<React.ComponentProps<typeof CodeBlock>, "children"> {
|
|
4
|
+
code: string;
|
|
5
|
+
/** Language for the label and syntax highlighting, e.g. "bash", "tsx". Unknown languages render plain. */
|
|
6
|
+
language?: string;
|
|
7
|
+
/** Turn syntax highlighting off. Default on. */
|
|
8
|
+
highlight?: boolean;
|
|
9
|
+
lineNumbers?: boolean;
|
|
10
|
+
/** Hide the copy button. */
|
|
11
|
+
hideCopy?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One-prop code panel: language label, copy button, shiki highlighting (loaded
|
|
15
|
+
* lazily per language). Built on the CodeBlock primitives; use those directly
|
|
16
|
+
* for diffs, highlighted lines, or custom headers.
|
|
17
|
+
*/
|
|
18
|
+
declare function CodeSnippet({ code, language, highlight, lineNumbers, hideCopy, className, ...props }: CodeSnippetProps): React.JSX.Element;
|
|
19
|
+
/** Inline monospace span for commands and identifiers. */
|
|
20
|
+
declare function InlineCode({ className, ...props }: React.ComponentProps<"code">): React.JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* Typography for long-form and model output. Styles plain HTML children
|
|
23
|
+
* (p, ul, ol, li, strong, a, code, pre, h1-h4, blockquote, table), so it works
|
|
24
|
+
* with react-markdown or any HTML renderer.
|
|
25
|
+
*/
|
|
26
|
+
declare function Prose({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
27
|
+
export { CodeSnippet, InlineCode, Prose };
|