@sentry/junior-dashboard 0.248.0 → 0.249.0
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/dist/app.js +2 -2
- package/dist/client.js +36 -35
- package/dist/index.js +2 -2
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/App.tsx +1 -5
- package/src/client/components/ActorAvatar.tsx +7 -4
- package/src/client/components/AutomationCard.tsx +2 -2
- package/src/client/components/Button.tsx +12 -11
- package/src/client/components/ConversationList.tsx +3 -3
- package/src/client/components/ConversationSummary.tsx +2 -1
- package/src/client/components/DetailList.tsx +3 -3
- package/src/client/components/Drawer.tsx +2 -2
- package/src/client/components/EmptyTelemetry.tsx +1 -1
- package/src/client/components/Field.tsx +1 -2
- package/src/client/components/FilterBar.tsx +6 -6
- package/src/client/components/Metric.tsx +4 -4
- package/src/client/components/Notice.tsx +7 -7
- package/src/client/components/PageContentSkeleton.tsx +2 -2
- package/src/client/components/Pagination.tsx +2 -2
- package/src/client/components/ParticipantAvatarStack.tsx +4 -4
- package/src/client/components/ProfileMenu.tsx +5 -7
- package/src/client/components/README.md +122 -58
- package/src/client/components/SearchInput.tsx +4 -3
- package/src/client/components/SegmentedNav.tsx +10 -17
- package/src/client/components/SegmentedTabs.tsx +3 -3
- package/src/client/components/Select.tsx +1 -1
- package/src/client/components/SelectableRow.tsx +2 -2
- package/src/client/components/Skeleton.tsx +1 -1
- package/src/client/components/StatusChip.tsx +1 -1
- package/src/client/components/StatusDot.tsx +1 -1
- package/src/client/components/TextInput.tsx +1 -1
- package/src/client/components/Tooltip.tsx +2 -2
- package/src/client/components/VersionDriftBanner.tsx +2 -2
- package/src/client/components/charts/ActivityChart.tsx +5 -6
- package/src/client/components/charts/CacheWrites.tsx +3 -3
- package/src/client/components/charts/ChartHeader.tsx +4 -4
- package/src/client/components/charts/ChartLegend.tsx +1 -1
- package/src/client/components/charts/InputCacheChart.tsx +5 -5
- package/src/client/components/charts/WorkspaceUsageChart.tsx +4 -11
- package/src/client/components/controls/DirectorySortSelect.tsx +2 -2
- package/src/client/components/directory/DirectoryMetric.tsx +2 -2
- package/src/client/components/directory/DirectoryRowsSkeleton.tsx +5 -5
- package/src/client/components/directory/DirectoryTable.tsx +3 -3
- package/src/client/components/layout/CardHeader.tsx +4 -4
- package/src/client/components/layout/DashboardChrome.tsx +9 -3
- package/src/client/components/layout/DashboardHeader.tsx +7 -7
- package/src/client/components/layout/PageHeader.tsx +2 -2
- package/src/client/components/layout/SecondaryNavigation.tsx +7 -14
- package/src/client/components/layout/SectionIntro.tsx +1 -1
- package/src/client/components/layout/SectionTitle.tsx +1 -1
- package/src/client/components/metrics/StatCard.tsx +2 -2
- package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
- package/src/client/conversations/ConversationBrief.tsx +4 -4
- package/src/client/conversations/ConversationChildAgents.tsx +7 -4
- package/src/client/conversations/ConversationComposer.tsx +8 -7
- package/src/client/conversations/ConversationHeader.tsx +5 -5
- package/src/client/conversations/ConversationHeaderActions.tsx +9 -9
- package/src/client/conversations/ConversationHomeList.tsx +3 -3
- package/src/client/conversations/ConversationListStatusIcon.tsx +1 -1
- package/src/client/conversations/ConversationMemories.tsx +4 -4
- package/src/client/conversations/ConversationMeta.tsx +10 -10
- package/src/client/conversations/ConversationPage.tsx +2 -1
- package/src/client/conversations/ConversationSidebar.tsx +6 -6
- package/src/client/conversations/ConversationUsageBreakdown.tsx +4 -4
- package/src/client/conversations/ConversationWorkspace.tsx +1 -1
- package/src/client/conversations/ConversationWorkspaceLoading.tsx +4 -4
- package/src/client/conversations/CopyMarkdownButton.tsx +1 -1
- package/src/client/conversations/EventUsage.tsx +2 -2
- package/src/client/conversations/PendingMailboxStack.tsx +5 -5
- package/src/client/conversations/README.md +9 -0
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +39 -23
- package/src/client/conversations/ToolFrame.tsx +36 -14
- package/src/client/conversations/TranscriptActivityGroup.tsx +10 -3
- package/src/client/conversations/TranscriptAttachmentsDeliveredView.tsx +4 -6
- package/src/client/conversations/TranscriptContextEventView.tsx +2 -2
- package/src/client/conversations/TranscriptEventView.tsx +1 -1
- package/src/client/conversations/TranscriptMarkdown.tsx +3 -3
- package/src/client/conversations/TranscriptMessageContextView.tsx +7 -7
- package/src/client/conversations/TranscriptMessageView.tsx +2 -6
- package/src/client/conversations/TranscriptRailEvent.tsx +20 -8
- package/src/client/conversations/TranscriptReasoningView.tsx +12 -12
- package/src/client/conversations/TranscriptStructuredEventView.tsx +16 -11
- package/src/client/conversations/TranscriptSubagentView.tsx +64 -39
- package/src/client/conversations/TranscriptText.tsx +5 -4
- package/src/client/conversations/TranscriptToolView.tsx +9 -11
- package/src/client/conversations/TranscriptTurnContextView.tsx +3 -3
- package/src/client/conversations/TranscriptView.tsx +3 -3
- package/src/client/conversations/UsageCard.tsx +1 -1
- package/src/client/conversations/eventTranscript.ts +7 -0
- package/src/client/conversations/transcriptMarkdownLinks.ts +2 -4
- package/src/client/conversations/transcriptStyles.ts +1 -1
- package/src/client/pages/PersonalTokensPage.tsx +4 -4
- package/src/client/pages/admin/AdminPage.tsx +2 -2
- package/src/client/pages/automations/AutomationCostChart.tsx +2 -2
- package/src/client/pages/automations/AutomationDetailsDrawer.tsx +5 -10
- package/src/client/pages/automations/AutomationEditor.tsx +1 -1
- package/src/client/pages/automations/AutomationExecutionChart.tsx +2 -2
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +2 -2
- package/src/client/pages/automations/AutomationExecutionsPage.tsx +4 -4
- package/src/client/pages/automations/AutomationRow.tsx +4 -4
- package/src/client/pages/automations/AutomationRunsPage.tsx +3 -3
- package/src/client/pages/automations/AutomationScheduleFields.tsx +1 -1
- package/src/client/pages/automations/AutomationVersionsPage.tsx +1 -1
- package/src/client/pages/code/CodeActivityChart.tsx +7 -6
- package/src/client/pages/code/CodeChangeRow.tsx +1 -1
- package/src/client/pages/code/CodePage.tsx +5 -5
- package/src/client/pages/code/RepositoryPage.tsx +2 -2
- package/src/client/pages/dev/ComponentsPage.tsx +40 -146
- package/src/client/pages/dev/TranscriptActivityFixtures.tsx +206 -0
- package/src/client/pages/locations/LocationDetailPage.tsx +4 -4
- package/src/client/pages/locations/LocationDirectory.tsx +1 -1
- package/src/client/pages/locations/PrivateActivityCard.tsx +3 -3
- package/src/client/pages/memory/MemoryCostChart.tsx +3 -5
- package/src/client/pages/memory/MemoryDetailsDrawer.tsx +5 -5
- package/src/client/pages/memory/MemoryPage.tsx +15 -15
- package/src/client/pages/memory/MemoryTimeline.tsx +3 -5
- package/src/client/pages/people/ContributionGrid.tsx +8 -5
- package/src/client/pages/people/PersonProfilePage.tsx +3 -6
- package/src/client/pages/people/ProfilePluginReports.tsx +2 -2
- package/src/client/pages/system/GuardianActivity.tsx +9 -9
- package/src/client/pages/system/PluginBarChart.tsx +4 -6
- package/src/client/pages/system/PluginDetails.tsx +11 -7
- package/src/client/pages/system/PluginPanels.tsx +8 -8
- package/src/client/pages/system/PluginReportRecordSet.tsx +14 -14
- package/src/client/pages/system/PluginReports.tsx +7 -11
- package/src/client/pages/system/SkillInventory.tsx +9 -9
- package/src/client/pages/system/SystemActivity.tsx +1 -1
- package/src/client/pages/system/SystemPage.tsx +3 -6
- package/src/client/pages/system/WorkspaceDetails.tsx +2 -5
- package/src/client/pages/system/WorkspaceEditor.tsx +2 -2
- package/src/client/pages/system/WorkspaceList.tsx +2 -2
- package/src/client/pages/user/PluginUserPage.tsx +3 -3
- package/src/client/styles.ts +5 -4
- package/src/client/types.ts +2 -0
- package/src/tailwind.css +36 -38
|
@@ -18,10 +18,10 @@ export type ToggleButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const buttonClassName =
|
|
21
|
-
"inline-flex h-9 max-w-full items-center gap-2 rounded border border-dashboard-border-emphasis bg-dashboard-surface-raised px-3 font-
|
|
21
|
+
"inline-flex h-9 max-w-full items-center justify-center gap-2 rounded-md border border-dashboard-border-emphasis bg-dashboard-surface-raised px-3 font-sans text-sm font-medium leading-none text-dashboard-text transition-colors hover:border-dashboard-border-heavy hover:bg-dashboard-surface-hover hover:text-dashboard-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus";
|
|
22
22
|
|
|
23
23
|
const dangerButtonClassName =
|
|
24
|
-
"inline-flex h-9 max-w-full items-center justify-center gap-
|
|
24
|
+
"inline-flex h-9 max-w-full items-center justify-center gap-2 rounded-md border border-dashboard-border-strong bg-transparent px-3 font-sans text-sm font-medium leading-none text-dashboard-text-muted transition-colors hover:border-rose-300/40 hover:text-rose-300 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-rose-300/55";
|
|
25
25
|
|
|
26
26
|
/** Render the dashboard's standard bordered command button surface. */
|
|
27
27
|
export function Button({
|
|
@@ -36,16 +36,16 @@ export function Button({
|
|
|
36
36
|
<button
|
|
37
37
|
{...props}
|
|
38
38
|
className={cn(
|
|
39
|
-
"font-
|
|
39
|
+
"font-sans transition-colors disabled:cursor-not-allowed disabled:opacity-50",
|
|
40
40
|
size === "icon"
|
|
41
41
|
? cn(
|
|
42
|
-
"grid size-9 place-items-center rounded-md border-0 bg-transparent p-0 focus-visible:outline focus-visible:outline-1 disabled:hover:!bg-transparent",
|
|
42
|
+
"grid size-9 place-items-center rounded-md border-0 bg-transparent p-0 focus-visible:outline-2 focus-visible:outline-offset-1 disabled:hover:!bg-transparent",
|
|
43
43
|
isDanger
|
|
44
44
|
? "text-dashboard-text-muted hover:!bg-rose-300/10 hover:!text-rose-300 focus-visible:outline-rose-300/55 disabled:hover:!text-dashboard-text-muted"
|
|
45
|
-
: "text-dashboard-text-muted hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-
|
|
45
|
+
: "text-dashboard-text-muted hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-dashboard-focus disabled:hover:!text-dashboard-text-muted",
|
|
46
46
|
)
|
|
47
47
|
: tone === "primary"
|
|
48
|
-
? "inline-flex h-9 items-center justify-center gap-2 rounded border border-dashboard-text-solid bg-dashboard-text-solid px-3 font-sans text-sm font-
|
|
48
|
+
? "inline-flex h-9 items-center justify-center gap-2 rounded-md border border-dashboard-text-solid bg-dashboard-text-solid px-3 font-sans text-sm font-medium leading-none text-dashboard-text-inverse hover:border-dashboard-text-subtle hover:bg-dashboard-text-subtle disabled:hover:border-dashboard-text-solid disabled:hover:bg-dashboard-text-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus"
|
|
49
49
|
: isDanger
|
|
50
50
|
? cn(
|
|
51
51
|
dangerButtonClassName,
|
|
@@ -96,21 +96,22 @@ export function ToggleButton({
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const toggleButtonBase: Record<ToggleButtonVariant, string> = {
|
|
99
|
-
pill: "cursor-pointer rounded border px-2 py-1 font-
|
|
99
|
+
pill: "cursor-pointer rounded-md border px-2 py-1 font-sans text-xs font-medium leading-tight transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
100
100
|
segment:
|
|
101
|
-
"h-7 min-w-10 cursor-pointer rounded border px-2 font-
|
|
102
|
-
text: "cursor-pointer border-0 bg-transparent px-1.5 py-1 font-
|
|
101
|
+
"inline-flex h-7 min-w-10 cursor-pointer items-center justify-center rounded-md border px-2 font-sans text-xs font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
102
|
+
text: "cursor-pointer rounded-sm border-0 bg-transparent px-1.5 py-1 font-sans font-medium underline-offset-4 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
const toggleButtonPressed: Record<ToggleButtonVariant, string> = {
|
|
106
106
|
pill: "border-dashboard-border-heavy bg-dashboard-text-solid text-dashboard-text-inverse",
|
|
107
|
-
segment:
|
|
107
|
+
segment:
|
|
108
|
+
"border-dashboard-border-interactive bg-dashboard-surface-active text-dashboard-text",
|
|
108
109
|
text: "text-dashboard-text underline decoration-dashboard-text-solid",
|
|
109
110
|
};
|
|
110
111
|
|
|
111
112
|
const toggleButtonIdle: Record<ToggleButtonVariant, string> = {
|
|
112
113
|
pill: "border-dashboard-border-strong bg-dashboard-surface-raised text-dashboard-text-muted hover:border-dashboard-border-interactive hover:bg-dashboard-surface-hover hover:text-dashboard-text",
|
|
113
114
|
segment:
|
|
114
|
-
"border-
|
|
115
|
+
"border-transparent bg-transparent text-dashboard-text-muted hover:bg-dashboard-fill-hover hover:text-dashboard-text",
|
|
115
116
|
text: "text-dashboard-text-muted hover:text-dashboard-text",
|
|
116
117
|
};
|
|
@@ -28,7 +28,7 @@ export function ConversationList(props: {
|
|
|
28
28
|
return (
|
|
29
29
|
<div className="min-w-0" role="table">
|
|
30
30
|
<div
|
|
31
|
-
className="sticky top-0 z-[1] grid grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-3 py-2.5 font-
|
|
31
|
+
className="sticky top-0 z-[1] grid grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-3 py-2.5 font-sans font-medium text-xs text-dashboard-text-muted max-md:hidden"
|
|
32
32
|
role="row"
|
|
33
33
|
>
|
|
34
34
|
<div>Conversation</div>
|
|
@@ -85,8 +85,8 @@ function conversationRecordClass(
|
|
|
85
85
|
selected: boolean | undefined,
|
|
86
86
|
): string {
|
|
87
87
|
return cn(
|
|
88
|
-
"group grid min-w-0 cursor-pointer grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 overflow-hidden border-b border-b-
|
|
88
|
+
"group grid min-w-0 cursor-pointer grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 overflow-hidden border-b border-b-dashboard-border-subtle px-3 py-3 text-left text-inherit no-underline transition-colors hover:bg-dashboard-fill-soft max-md:grid-cols-1 max-md:px-4 max-md:py-4",
|
|
89
89
|
status === "idle" && "saturate-50",
|
|
90
|
-
selected && "bg-
|
|
90
|
+
selected && "bg-dashboard-accent/[0.045]",
|
|
91
91
|
);
|
|
92
92
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
conversationParticipants,
|
|
12
12
|
ParticipantAvatarStack,
|
|
13
13
|
} from "./ParticipantAvatarStack";
|
|
14
|
+
import { cn, dashboardInlineLinkClass } from "../styles";
|
|
14
15
|
|
|
15
16
|
/** Render the shared conversation title and identity. */
|
|
16
17
|
export function ConversationSummary(props: { conversation: Conversation }) {
|
|
@@ -38,7 +39,7 @@ function ConversationIdentity(props: { conversation: Conversation }) {
|
|
|
38
39
|
{location && props.conversation.locationId ? (
|
|
39
40
|
<>
|
|
40
41
|
<Link
|
|
41
|
-
className="font-semibold
|
|
42
|
+
className={cn("font-semibold", dashboardInlineLinkClass)}
|
|
42
43
|
onClick={(event: MouseEvent<HTMLAnchorElement>) =>
|
|
43
44
|
event.stopPropagation()
|
|
44
45
|
}
|
|
@@ -7,7 +7,7 @@ export function DetailList(props: { children: ReactNode; className?: string }) {
|
|
|
7
7
|
return (
|
|
8
8
|
<dl
|
|
9
9
|
className={cn(
|
|
10
|
-
"grid gap-px overflow-hidden rounded border border-
|
|
10
|
+
"grid gap-px overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-fill-hover",
|
|
11
11
|
props.className,
|
|
12
12
|
)}
|
|
13
13
|
>
|
|
@@ -23,8 +23,8 @@ export function Detail(props: {
|
|
|
23
23
|
valueClassName?: string;
|
|
24
24
|
}) {
|
|
25
25
|
return (
|
|
26
|
-
<div className="min-w-0 bg-
|
|
27
|
-
<dt className="font-
|
|
26
|
+
<div className="min-w-0 bg-dashboard-bg-elevated px-3 py-3">
|
|
27
|
+
<dt className="font-sans font-medium text-xs text-dashboard-text-muted">
|
|
28
28
|
{props.label}
|
|
29
29
|
</dt>
|
|
30
30
|
<dd
|
|
@@ -112,7 +112,7 @@ export function Drawer(props: {
|
|
|
112
112
|
/>
|
|
113
113
|
<aside
|
|
114
114
|
className={cn(
|
|
115
|
-
"absolute top-0 right-0 grid h-full w-full grid-rows-[auto_minmax(0,1fr)] bg-dashboard-bg-elevated shadow-[-20px_0_60px_rgba(0,0,0,0.45)] md:border-l md:border-dashboard-border-
|
|
115
|
+
"absolute top-0 right-0 grid h-full w-full grid-rows-[auto_minmax(0,1fr)] bg-dashboard-bg-elevated shadow-[-20px_0_60px_rgba(0,0,0,0.45)] md:border-l md:border-dashboard-border-strong",
|
|
116
116
|
props.width === "wide"
|
|
117
117
|
? "md:w-[min(760px,94vw)]"
|
|
118
118
|
: props.width === "narrow"
|
|
@@ -120,7 +120,7 @@ export function Drawer(props: {
|
|
|
120
120
|
: "md:w-[min(560px,94vw)]",
|
|
121
121
|
)}
|
|
122
122
|
>
|
|
123
|
-
<header className="relative grid grid-cols-[minmax(0,1fr)_auto] gap-3 border-b border-dashboard-border
|
|
123
|
+
<header className="relative grid grid-cols-[minmax(0,1fr)_auto] gap-3 border-b border-dashboard-border bg-dashboard-bg-elevated px-4 py-3 pt-[max(0.75rem,env(safe-area-inset-top))] md:px-5">
|
|
124
124
|
<div className="min-w-0">{props.header}</div>
|
|
125
125
|
<div className="flex items-start gap-1.5">
|
|
126
126
|
{props.actions}
|
|
@@ -3,7 +3,7 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
/** Render the dashboard empty-state block with quiet warning context. */
|
|
4
4
|
export function EmptyTelemetry(props: { children: ReactNode }) {
|
|
5
5
|
return (
|
|
6
|
-
<div className="min-w-0 rounded-lg border border-
|
|
6
|
+
<div className="min-w-0 rounded-lg border border-dashboard-border-strong bg-dashboard-bg px-4 py-3 text-base leading-relaxed text-dashboard-text-muted">
|
|
7
7
|
{props.children}
|
|
8
8
|
</div>
|
|
9
9
|
);
|
|
@@ -5,8 +5,7 @@ import { cn } from "../styles";
|
|
|
5
5
|
export type FieldSize = "compact" | "default";
|
|
6
6
|
|
|
7
7
|
const labelClass: Record<FieldSize, string> = {
|
|
8
|
-
compact:
|
|
9
|
-
"font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted",
|
|
8
|
+
compact: "font-sans font-medium text-xs text-dashboard-text-muted",
|
|
10
9
|
default: "text-sm font-semibold text-dashboard-text",
|
|
11
10
|
};
|
|
12
11
|
|
|
@@ -41,7 +41,7 @@ export function FilterGroup(props: {
|
|
|
41
41
|
}) {
|
|
42
42
|
return (
|
|
43
43
|
<div className={cn("min-w-0", props.className)}>
|
|
44
|
-
<div className="mb-2 font-
|
|
44
|
+
<div className="mb-2 font-sans font-medium text-xs text-dashboard-text-muted">
|
|
45
45
|
{props.label}
|
|
46
46
|
</div>
|
|
47
47
|
<div
|
|
@@ -71,7 +71,7 @@ export function FilterTabList(props: {
|
|
|
71
71
|
return (
|
|
72
72
|
<div
|
|
73
73
|
aria-label={props.ariaLabel}
|
|
74
|
-
className="grid min-w-0 grid-cols-3 gap-1 border-b border-
|
|
74
|
+
className="grid min-w-0 grid-cols-3 gap-1 border-b border-dashboard-border-subtle sm:flex sm:overflow-x-auto"
|
|
75
75
|
role="tablist"
|
|
76
76
|
>
|
|
77
77
|
{props.items.map((item) => {
|
|
@@ -80,9 +80,9 @@ export function FilterTabList(props: {
|
|
|
80
80
|
<button
|
|
81
81
|
aria-selected={selected}
|
|
82
82
|
className={cn(
|
|
83
|
-
"relative flex min-w-0 cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-2.5 font-
|
|
83
|
+
"relative flex min-w-0 cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-2.5 font-sans font-medium text-xs transition-colors after:absolute after:inset-x-2 after:bottom-0 after:h-px sm:shrink-0 sm:justify-start",
|
|
84
84
|
selected
|
|
85
|
-
? "text-
|
|
85
|
+
? "text-dashboard-accent-text after:bg-dashboard-accent"
|
|
86
86
|
: "text-dashboard-text-muted after:bg-transparent hover:text-dashboard-text",
|
|
87
87
|
)}
|
|
88
88
|
key={item.value || "all"}
|
|
@@ -96,8 +96,8 @@ export function FilterTabList(props: {
|
|
|
96
96
|
className={cn(
|
|
97
97
|
"rounded-sm border px-1.5 py-0.5 text-xs",
|
|
98
98
|
selected
|
|
99
|
-
? "border-
|
|
100
|
-
: "border-
|
|
99
|
+
? "border-dashboard-accent/20 bg-dashboard-accent/10 text-dashboard-accent-text"
|
|
100
|
+
: "border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted",
|
|
101
101
|
)}
|
|
102
102
|
>
|
|
103
103
|
{item.count.toLocaleString("en-US")}
|
|
@@ -28,10 +28,10 @@ function TooltipLines(props: { lines: MetricTooltipLine[] }) {
|
|
|
28
28
|
: cn(
|
|
29
29
|
"col-span-2 block min-w-0 break-words text-dashboard-text",
|
|
30
30
|
line.valueStyle === "heading" &&
|
|
31
|
-
"font-
|
|
31
|
+
"font-sans tabular-nums font-semibold text-dashboard-text",
|
|
32
32
|
line.valueStyle === "heading" &&
|
|
33
33
|
index > 0 &&
|
|
34
|
-
"mt-1 border-t border-
|
|
34
|
+
"mt-1 border-t border-dashboard-border-strong pt-2",
|
|
35
35
|
)
|
|
36
36
|
}
|
|
37
37
|
key={`${index}-${line.label ?? ""}-${line.value}-${line.live ? "live" : ""}`}
|
|
@@ -88,7 +88,7 @@ export function MetricValue(props: {
|
|
|
88
88
|
<Tooltip
|
|
89
89
|
align={props.align}
|
|
90
90
|
className={cn(
|
|
91
|
-
"w-[calc(100vw-2rem)] max-w-80 rounded-lg border border-
|
|
91
|
+
"w-[calc(100vw-2rem)] max-w-80 rounded-lg border border-dashboard-border-emphasis bg-dashboard-bg text-left text-xs font-normal text-dashboard-text-muted shadow-xl shadow-black/35",
|
|
92
92
|
props.tooltipCard ? "p-3 leading-snug" : "px-3 py-2 leading-relaxed",
|
|
93
93
|
)}
|
|
94
94
|
content={
|
|
@@ -106,7 +106,7 @@ export function MetricValue(props: {
|
|
|
106
106
|
>
|
|
107
107
|
<span
|
|
108
108
|
className={cn(
|
|
109
|
-
"inline-flex border-b border-dotted border-
|
|
109
|
+
"inline-flex border-b border-dotted border-dashboard-border-interactive outline-none transition-colors hover:border-dashboard-border-heavy focus-visible:border-dashboard-border-heavy",
|
|
110
110
|
props.className,
|
|
111
111
|
)}
|
|
112
112
|
tabIndex={0}
|
|
@@ -31,8 +31,8 @@ export function Notice({
|
|
|
31
31
|
return (
|
|
32
32
|
<div
|
|
33
33
|
className={cn(
|
|
34
|
-
"overflow-hidden rounded-xl shadow-[0_16px_40px_rgba(0,0,0,0.5)]",
|
|
35
|
-
isError ? "
|
|
34
|
+
"overflow-hidden rounded-xl border bg-dashboard-surface-raised shadow-[0_16px_40px_rgba(0,0,0,0.5)]",
|
|
35
|
+
isError ? "border-rose-300/25" : "border-dashboard-border-strong",
|
|
36
36
|
)}
|
|
37
37
|
>
|
|
38
38
|
<div className="flex min-w-0 items-center gap-3 px-3 py-3">
|
|
@@ -42,7 +42,7 @@ export function Notice({
|
|
|
42
42
|
"grid size-8 shrink-0 place-items-center rounded-lg",
|
|
43
43
|
isError
|
|
44
44
|
? "bg-rose-300/15 text-rose-100"
|
|
45
|
-
: "bg-
|
|
45
|
+
: "bg-dashboard-accent/10 text-dashboard-accent-text/80",
|
|
46
46
|
)}
|
|
47
47
|
>
|
|
48
48
|
<Icon aria-hidden="true" size={16} />
|
|
@@ -61,7 +61,7 @@ export function Notice({
|
|
|
61
61
|
{detail ? (
|
|
62
62
|
<div
|
|
63
63
|
className={cn(
|
|
64
|
-
"mt-0.5 truncate font-
|
|
64
|
+
"mt-0.5 truncate font-sans text-xs",
|
|
65
65
|
isError ? "text-rose-100/70" : "text-dashboard-text-muted",
|
|
66
66
|
)}
|
|
67
67
|
>
|
|
@@ -89,10 +89,10 @@ export function NoticeAction({
|
|
|
89
89
|
{...props}
|
|
90
90
|
className={cn(
|
|
91
91
|
"shrink-0 cursor-pointer px-3 py-1.5 text-xs transition focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-40",
|
|
92
|
-
isError ? "focus:ring-rose-300/40" : "focus:ring-
|
|
92
|
+
isError ? "focus:ring-rose-300/40" : "focus:ring-dashboard-focus/35",
|
|
93
93
|
isError
|
|
94
|
-
? "rounded-lg bg-rose-200/15 font-
|
|
95
|
-
: "rounded-lg bg-
|
|
94
|
+
? "rounded-lg bg-rose-200/15 font-sans font-medium text-rose-50 hover:bg-rose-200/25"
|
|
95
|
+
: "rounded-lg bg-dashboard-accent/10 font-sans font-medium text-dashboard-accent-text hover:bg-dashboard-accent/20",
|
|
96
96
|
className,
|
|
97
97
|
)}
|
|
98
98
|
type={type}
|
|
@@ -96,7 +96,7 @@ function LibrarySkeleton() {
|
|
|
96
96
|
return (
|
|
97
97
|
<>
|
|
98
98
|
<div className="flex flex-wrap items-end justify-between gap-4">
|
|
99
|
-
<SkeletonBone className="h-7 w-56 rounded bg-dashboard-fill-soft" />
|
|
99
|
+
<SkeletonBone className="h-7 w-56 rounded-md bg-dashboard-fill-soft" />
|
|
100
100
|
<SkeletonBone className="h-10 w-full max-w-md rounded-lg border border-dashboard-border-subtle bg-dashboard-fill-faint sm:w-72" />
|
|
101
101
|
</div>
|
|
102
102
|
<div
|
|
@@ -108,7 +108,7 @@ function LibrarySkeleton() {
|
|
|
108
108
|
className="flex items-center justify-between gap-2 px-3 py-2.5 sm:justify-start"
|
|
109
109
|
key={index}
|
|
110
110
|
>
|
|
111
|
-
<SkeletonBone className="h-3 w-12 rounded bg-dashboard-fill-soft" />
|
|
111
|
+
<SkeletonBone className="h-3 w-12 rounded-md bg-dashboard-fill-soft" />
|
|
112
112
|
<SkeletonBone className="h-5 w-8 rounded-sm border border-dashboard-border-subtle bg-dashboard-fill-faint" />
|
|
113
113
|
</div>
|
|
114
114
|
))}
|
|
@@ -61,7 +61,7 @@ export function PagePagination(props: {
|
|
|
61
61
|
props.className,
|
|
62
62
|
)}
|
|
63
63
|
>
|
|
64
|
-
<p className="m-0 font-
|
|
64
|
+
<p className="m-0 font-sans tabular-nums text-xs text-dashboard-text-muted">
|
|
65
65
|
Showing {start.toLocaleString("en-US")}-{end.toLocaleString("en-US")} of{" "}
|
|
66
66
|
{props.total.toLocaleString("en-US")}
|
|
67
67
|
</p>
|
|
@@ -74,7 +74,7 @@ export function PagePagination(props: {
|
|
|
74
74
|
>
|
|
75
75
|
<ChevronLeft aria-hidden="true" size={16} />
|
|
76
76
|
</Button>
|
|
77
|
-
<span className="min-w-16 text-center font-
|
|
77
|
+
<span className="min-w-16 text-center font-sans tabular-nums text-xs text-dashboard-text-muted">
|
|
78
78
|
{current} / {props.pageCount}
|
|
79
79
|
</span>
|
|
80
80
|
<Button
|
|
@@ -45,7 +45,7 @@ function ParticipantTooltipContent(props: { participant: ActorIdentity }) {
|
|
|
45
45
|
<span className="grid gap-0.5 font-sans">
|
|
46
46
|
<span className="font-semibold text-dashboard-text">{name}</span>
|
|
47
47
|
{email && email !== name ? (
|
|
48
|
-
<span className="font-
|
|
48
|
+
<span className="font-sans text-dashboard-text-muted">{email}</span>
|
|
49
49
|
) : null}
|
|
50
50
|
</span>
|
|
51
51
|
);
|
|
@@ -60,7 +60,7 @@ function Avatar(props: {
|
|
|
60
60
|
<Tooltip
|
|
61
61
|
content={<ParticipantTooltipContent participant={props.participant} />}
|
|
62
62
|
focusable
|
|
63
|
-
triggerClassName="-ml-1
|
|
63
|
+
triggerClassName="-ml-1 first:ml-0 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
|
|
64
64
|
>
|
|
65
65
|
<span
|
|
66
66
|
aria-label={label}
|
|
@@ -116,14 +116,14 @@ export function ParticipantAvatarStack(props: ParticipantAvatarStackProps) {
|
|
|
116
116
|
</span>
|
|
117
117
|
}
|
|
118
118
|
focusable
|
|
119
|
-
triggerClassName="-ml-1
|
|
119
|
+
triggerClassName="-ml-1 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
|
|
120
120
|
>
|
|
121
121
|
<span
|
|
122
122
|
aria-label={`${hidden.length} more participants: ${hidden
|
|
123
123
|
.map(participantDescription)
|
|
124
124
|
.join("; ")}`}
|
|
125
125
|
className={cn(
|
|
126
|
-
"relative inline-grid shrink-0 place-items-center rounded-full border-2 border-dashboard-bg bg-dashboard-
|
|
126
|
+
"relative inline-grid shrink-0 place-items-center rounded-full border-2 border-dashboard-bg bg-dashboard-surface-active font-sans font-semibold tabular-nums leading-none text-dashboard-text-muted focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus",
|
|
127
127
|
props.size === "list" ? "size-6 text-2xs" : "size-7 text-xs",
|
|
128
128
|
)}
|
|
129
129
|
onKeyDown={(event) => event.stopPropagation()}
|
|
@@ -155,7 +155,7 @@ export function ProfileMenu({
|
|
|
155
155
|
) : null}
|
|
156
156
|
</div>
|
|
157
157
|
</div>
|
|
158
|
-
<div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 font-
|
|
158
|
+
<div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 font-sans text-xs tabular-nums text-dashboard-text-muted">
|
|
159
159
|
<span>
|
|
160
160
|
7d{" "}
|
|
161
161
|
<span className="font-semibold text-dashboard-text">
|
|
@@ -230,11 +230,9 @@ export function ProfileMenu({
|
|
|
230
230
|
return (
|
|
231
231
|
<div
|
|
232
232
|
aria-label={`Personal model spend: 7 days ${sevenDaySpend}, 30 days ${thirtyDaySpend}`}
|
|
233
|
-
className="grid gap-1.5 rounded-lg border border-dashboard-border bg-dashboard-fill-soft px-3 py-2.5 font-
|
|
233
|
+
className="grid gap-1.5 rounded-lg border border-dashboard-border bg-dashboard-fill-soft px-3 py-2.5 font-sans text-xs tabular-nums text-dashboard-text-muted"
|
|
234
234
|
>
|
|
235
|
-
<span className="text-xs font-medium
|
|
236
|
-
Spend
|
|
237
|
-
</span>
|
|
235
|
+
<span className="text-xs font-medium">Spend</span>
|
|
238
236
|
<span className="whitespace-nowrap">
|
|
239
237
|
7d{" "}
|
|
240
238
|
<span className="font-semibold text-dashboard-text">
|
|
@@ -254,7 +252,7 @@ export function ProfileMenu({
|
|
|
254
252
|
if (variant === "sheet-links") {
|
|
255
253
|
// Match primary sheet rows exactly.
|
|
256
254
|
const sheetItemClass = cn(
|
|
257
|
-
"rounded-lg border-0 bg-transparent px-3 py-3 text-left font-
|
|
255
|
+
"rounded-lg border-0 bg-transparent px-3 py-3 text-left font-sans text-sm font-medium no-underline transition-colors hover:bg-dashboard-fill-soft focus-visible:bg-dashboard-fill-soft focus-visible:outline-none",
|
|
258
256
|
dashboardInteractiveTextClass,
|
|
259
257
|
);
|
|
260
258
|
return (
|
|
@@ -313,7 +311,7 @@ export function ProfileMenu({
|
|
|
313
311
|
{name}
|
|
314
312
|
</p>
|
|
315
313
|
{name !== email ? (
|
|
316
|
-
<p className="mt-0.5 mb-0 truncate font-
|
|
314
|
+
<p className="mt-0.5 mb-0 truncate font-sans text-xs text-dashboard-text-muted">
|
|
317
315
|
{email}
|
|
318
316
|
</p>
|
|
319
317
|
) : null}
|
|
@@ -1,55 +1,128 @@
|
|
|
1
1
|
# Dashboard UI kit
|
|
2
2
|
|
|
3
3
|
Shared dashboard components live here. Feature pages compose these surfaces
|
|
4
|
-
instead of copying Tailwind blocks.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
4
|
+
instead of copying Tailwind blocks. See `policies/frontend-components.md` for
|
|
5
|
+
the policy. `pnpm dashboard-style:check` enforces the token rules below.
|
|
6
|
+
|
|
7
|
+
## Foundations
|
|
8
|
+
|
|
9
|
+
Tokens live in the `@theme` block of `src/tailwind.css`. Light mode does not
|
|
10
|
+
exist yet. Keep every color in a token so a second theme can redefine them.
|
|
11
|
+
|
|
12
|
+
- **Surfaces.** Use the surface ladder, darkest to lightest: `bg`,
|
|
13
|
+
`bg-elevated` (drawers), `surface-panel` (sidebar, cards, bubbles),
|
|
14
|
+
`surface-raised` (buttons, tooltips), `control`, `surface-hover`,
|
|
15
|
+
`surface-active` (selected rows). Use `fill-*` for translucent fills and
|
|
16
|
+
`overlay-*` for scrims. Do not use `white/*` or `black/*` fills, borders, or
|
|
17
|
+
rings, or hex surface colors. Shadows may use black.
|
|
18
|
+
- **Borders.** Use `border-subtle` for hairlines inside a surface,
|
|
19
|
+
`border` for card edges, `border-strong` for shell edges, and
|
|
20
|
+
`border-emphasis` or `border-interactive` for controls and hover.
|
|
21
|
+
- **Text.** Brightest to dimmest: `text-solid`, `text`, `text-subtle`,
|
|
22
|
+
`text-muted`, `text-faint`.
|
|
23
|
+
- **Accent.** Lavender is the one brand accent. Use `accent` for icons,
|
|
24
|
+
active markers, and tinted fills, such as `bg-dashboard-accent/10`. Use
|
|
25
|
+
`accent-text` for links and accent text. Keep Tailwind palette colors for
|
|
26
|
+
status (info, success, warning, error) and for categorical chart, event, and
|
|
27
|
+
subagent colors.
|
|
28
|
+
- **Focus.** Use `outline-dashboard-focus` for keyboard focus. Do not use other
|
|
29
|
+
colors for focus rings.
|
|
30
|
+
- **Type faces.** `font-sans` is the UI face for prose, controls, navigation,
|
|
31
|
+
labels, and names. `font-display` is for headings, record titles, and large
|
|
32
|
+
metric values. `font-mono` is for machine values: code, ids, paths, file
|
|
33
|
+
names, tool names, and raw payloads. Show counts, times, and prices in
|
|
34
|
+
`font-sans tabular-nums`.
|
|
35
|
+
- **Type scale.** Use the named steps `text-2xs` through `text-4xl`. Keep
|
|
36
|
+
`text-2xs` for compact badges and chart annotations.
|
|
37
|
+
- **Labels.** Section, card, field, and column labels use
|
|
38
|
+
`font-sans text-xs font-medium text-dashboard-text-muted` in sentence case.
|
|
39
|
+
Do not use uppercase or letter spacing for labels.
|
|
40
|
+
- **Radius.** Controls and chips use `rounded-md`. Cards, list rows, and panels
|
|
41
|
+
use `rounded-lg`. The composer, menus, and transcript object cards use
|
|
42
|
+
`rounded-xl`. Avatars and count badges use `rounded-full`.
|
|
43
|
+
|
|
44
|
+
## Shared class helpers
|
|
45
|
+
|
|
46
|
+
`src/client/styles.ts` holds the few class strings that many components share.
|
|
47
|
+
|
|
48
|
+
- `cn` joins class names.
|
|
49
|
+
- `dashboardContainerClass` sets the page width.
|
|
50
|
+
- `dashboardInlineLinkClass` styles a neutral underlined link inside prose.
|
|
51
|
+
- `dashboardInteractiveTextClass` styles muted text that brightens on hover.
|
|
52
|
+
- `dashboardComposerSurfaceClass` styles the composer surface.
|
|
53
|
+
|
|
54
|
+
## Components
|
|
55
|
+
|
|
56
|
+
### Primitives
|
|
57
|
+
|
|
58
|
+
- **Actions.** `Button` (`default`, `primary`, `danger`, and `size="icon"`) and
|
|
59
|
+
`ButtonLink`. Form pages use `Button tone="primary"` for their one main save
|
|
60
|
+
action. Use `ToggleButton` variants (`pill`, `segment`, `text`) for pressed
|
|
61
|
+
states, not one-off styles.
|
|
62
|
+
- **Forms.** `Field` (`default`, `compact`), `TextInput`, `TextArea`, `Select`,
|
|
63
|
+
and `SearchInput`. Use `TextInput size="comfortable"` for larger mobile
|
|
64
|
+
controls. Use `TextArea prose` for instructions, not code. `Field error`
|
|
65
|
+
renders an error at `<htmlFor>-error`. The owning control must set
|
|
66
|
+
`aria-invalid` and `aria-describedby`. `Select` matches native text controls.
|
|
67
|
+
- **Status.** Use `StatusDot` for dense table or list markers. Use `StatusChip`
|
|
68
|
+
when the label must stay visible. `StatusChip` is a small dot and
|
|
69
|
+
sentence-case text, with no border or fill. It is not a control.
|
|
70
|
+
- **Messages.** Use `Notice` for compact transient messages and `FormNotice`
|
|
71
|
+
for wrapping form recovery text.
|
|
72
|
+
- **Overlays.** `Drawer` owns dismissal, focus trapping, focus return, scroll
|
|
73
|
+
locking, and panel layout. Context panels use it, not a separate modal.
|
|
74
|
+
`Tooltip` and `IconButtonTooltip` own hover text.
|
|
75
|
+
- **Identity.** `ActorAvatar`, `ParticipantAvatarStack`, and `ObjectIcon`.
|
|
76
|
+
`ObjectIcon` owns native Ticket, Code change, Automation, Deployment, and
|
|
77
|
+
Item icons. It uses the shared type and status mapping and the original
|
|
78
|
+
Octicons paths. Do not replace it with a provider logo or a status-only icon.
|
|
79
|
+
- **Loading.** Use `Skeleton` for placeholder leaves and `PageContentSkeleton`
|
|
80
|
+
variants for page bodies. Use `PageRouteLoading` when a page keeps its real
|
|
81
|
+
header above a body skeleton. Use a feature-owned loading component for
|
|
82
|
+
distinct geometry, such as conversations.
|
|
83
|
+
|
|
84
|
+
### Navigation
|
|
85
|
+
|
|
86
|
+
The dashboard has three navigation levels. Each has its own look, so the
|
|
87
|
+
levels stay distinct.
|
|
88
|
+
|
|
89
|
+
- **App navigation** in `layout/DashboardHeader` uses pills.
|
|
90
|
+
- **Page links** use `SegmentedNav`, through `layout/SecondaryNavigation`. They
|
|
91
|
+
are underline tabs that sit on the header border. With `fill`, links share
|
|
92
|
+
the row width while their labels fit. Rows that do not fit scroll sideways.
|
|
93
|
+
- **Panel switches** use `SegmentedTabs`, which draws a pill track. Pass the
|
|
94
|
+
selected value, items, change handler, and panel content. It owns tab and
|
|
95
|
+
panel labels and keyboard focus.
|
|
96
|
+
|
|
97
|
+
Keep collection filters in `FilterTabList`.
|
|
98
|
+
|
|
99
|
+
### Patterns
|
|
100
|
+
|
|
101
|
+
- **Layout.** `layout/` holds the shell chrome, page headers, cards, and
|
|
102
|
+
section titles. `DashboardChrome` owns the sticky header block and its one
|
|
103
|
+
bottom border.
|
|
104
|
+
- **Directory tables and metrics.** `directory/` and `metrics/`.
|
|
105
|
+
- **Charts.** Activity time-series charts own bucket labels in
|
|
106
|
+
`charts/ActivityChart` (`formatActivityDate` for axes,
|
|
107
|
+
`ActivityChartTooltip` and `formatActivityTooltipDate` for hover labels). New
|
|
108
|
+
day or hour charts compose those helpers. They do not format UTC bucket keys
|
|
109
|
+
inline.
|
|
110
|
+
- **Conversation mobile geometry** is a hard ownership edge:
|
|
111
|
+
- `layout/VisualViewportShell` owns the fixed shell, visualViewport CSS
|
|
112
|
+
variables, and body lock.
|
|
113
|
+
- `conversations/ChatLayout` owns the scroll-above-dock frame for reply
|
|
114
|
+
threads.
|
|
115
|
+
- `conversations/ComposerDock` owns the reply bottom pad and dock chrome.
|
|
116
|
+
|
|
117
|
+
Pages pass children only. Home and create are one landing surface, not a
|
|
118
|
+
dock, and must not use `ComposerDock`. Do not add viewport height, offset, or
|
|
119
|
+
bottom safe-area math in page modules.
|
|
120
|
+
|
|
121
|
+
### Features
|
|
122
|
+
|
|
123
|
+
Feature surfaces stay under `conversations/` or `pages/` until two real callers
|
|
124
|
+
share them. Transcript layout stays in `conversations/`. See
|
|
125
|
+
[Transcript components](../conversations/README.md) for ownership.
|
|
53
126
|
|
|
54
127
|
## Rules
|
|
55
128
|
|
|
@@ -58,12 +131,3 @@ instead of copying Tailwind blocks.
|
|
|
58
131
|
- Add gallery fixtures under `/dev/<section>` for new or changed shared
|
|
59
132
|
components. Keep the `/dev` index as the catalog only.
|
|
60
133
|
- One-off page glue may stay inline when extraction only adds indirection.
|
|
61
|
-
|
|
62
|
-
See `policies/frontend-components.md`.
|
|
63
|
-
|
|
64
|
-
Use `TextInput size="comfortable"` for larger mobile form controls.
|
|
65
|
-
Form pages use `Button tone="primary"` for their one main save action. Use
|
|
66
|
-
`TextArea prose` for instructions rather than code. `Field error` renders an
|
|
67
|
-
error at `<htmlFor>-error`; the owning control must set `aria-invalid` and
|
|
68
|
-
`aria-describedby`. `Select` matches native text controls. Use `FormNotice` for
|
|
69
|
-
wrapping form recovery text; use `Notice` for compact transient messages.
|
|
@@ -30,7 +30,7 @@ export function SearchInput(props: {
|
|
|
30
30
|
<input
|
|
31
31
|
aria-label={props.label}
|
|
32
32
|
className={cn(
|
|
33
|
-
"w-full rounded-
|
|
33
|
+
"w-full rounded-md border border-dashboard-border font-sans text-sm text-dashboard-text outline-none transition-colors placeholder:text-dashboard-text-muted/70 hover:border-dashboard-border-emphasis focus:border-dashboard-focus",
|
|
34
34
|
searchInputClass[size],
|
|
35
35
|
)}
|
|
36
36
|
onChange={(event) => props.onChange(event.currentTarget.value)}
|
|
@@ -49,7 +49,8 @@ const searchIconClass: Record<SearchInputSize, string> = {
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
const searchInputClass: Record<SearchInputSize, string> = {
|
|
52
|
-
compact:
|
|
52
|
+
compact:
|
|
53
|
+
"h-9 bg-dashboard-overlay-soft pr-3 pl-8 focus:ring-1 focus:ring-dashboard-focus/25",
|
|
53
54
|
default:
|
|
54
|
-
"h-10 bg-dashboard-overlay-soft pr-3 pl-9 focus:ring-
|
|
55
|
+
"h-10 bg-dashboard-overlay-soft pr-3 pl-9 focus:ring-1 focus:ring-dashboard-focus/25",
|
|
55
56
|
};
|