refactor(ui): isolate session components (#33670)
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import { Collapsible } from "@kobalte/core/collapsible"
|
||||
import { type ComponentProps, type JSX, Show, createMemo, splitProps } from "solid-js"
|
||||
import "./tool-error-card-v2.css"
|
||||
|
||||
function BanIcon() {
|
||||
return (
|
||||
<svg
|
||||
data-slot="tool-error-card-ban"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M3.44283 12.5575L12.5495 3.45081M14.4446 8.00011C14.4446 11.5593 11.5593 14.4446 8.00011 14.4446C4.44094 14.4446 1.55566 11.5593 1.55566 8.00011C1.55566 4.44094 4.44094 1.55566 8.00011 1.55566C11.5593 1.55566 14.4446 4.44094 14.4446 8.00011Z"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/** duo-progress-25: faint track ring + ~25% solid arc (Figma OpenCode DS) */
|
||||
function LoaderIcon() {
|
||||
const r = 5.9
|
||||
return (
|
||||
<svg
|
||||
data-slot="tool-error-card-loader"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<g transform="translate(8 8)">
|
||||
<circle
|
||||
r={r}
|
||||
fill="none"
|
||||
stroke="var(--v2-icon-icon-base)"
|
||||
stroke-width="1"
|
||||
stroke-opacity="0.3"
|
||||
transform="rotate(-90)"
|
||||
/>
|
||||
<circle
|
||||
r={r}
|
||||
fill="none"
|
||||
stroke="var(--v2-icon-icon-base)"
|
||||
stroke-width="1"
|
||||
pathLength="100"
|
||||
stroke-dasharray="25 75"
|
||||
transform="rotate(-90)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function ChevronIcon() {
|
||||
return (
|
||||
<svg
|
||||
data-slot="tool-error-card-chevron"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M5.90795 9.62425C5.61628 9.81865 5.25 9.57825 5.25 9.19235V4.80837C5.25 4.42247 5.61628 4.18204 5.90795 4.37648L9.1959 6.56846C9.48535 6.7614 9.48535 7.2393 9.1959 7.43224L5.90795 9.62425Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export interface ToolErrorCardV2Props extends Omit<ComponentProps<"div">, "children" | "title"> {
|
||||
title: JSX.Element | string
|
||||
subtitle: JSX.Element | string
|
||||
suffix?: JSX.Element | string
|
||||
loading?: boolean
|
||||
open?: boolean
|
||||
defaultOpen?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
/** When set, subtitle renders as a link (clicks do not toggle expand). */
|
||||
subtitleHref?: string
|
||||
}
|
||||
|
||||
export function ToolErrorCardV2(props: ToolErrorCardV2Props) {
|
||||
const [local, rest] = splitProps(props, [
|
||||
"title",
|
||||
"subtitle",
|
||||
"suffix",
|
||||
"loading",
|
||||
"open",
|
||||
"defaultOpen",
|
||||
"onOpenChange",
|
||||
"subtitleHref",
|
||||
"class",
|
||||
"classList",
|
||||
])
|
||||
|
||||
const hasSuffix = createMemo(() => {
|
||||
const s = local.suffix
|
||||
if (s == null) return false
|
||||
if (typeof s === "string") return s.length > 0
|
||||
return true
|
||||
})
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
{...rest}
|
||||
data-component="tool-error-card"
|
||||
open={local.open}
|
||||
defaultOpen={local.defaultOpen}
|
||||
onOpenChange={local.onOpenChange}
|
||||
disabled={!hasSuffix()}
|
||||
aria-busy={local.loading ? true : undefined}
|
||||
classList={{
|
||||
...local.classList,
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
<Collapsible.Trigger as="div" role="button" data-slot="tool-error-card-trigger">
|
||||
<span data-slot="tool-error-card-icon-wrap">
|
||||
<Show when={local.loading} fallback={<BanIcon />}>
|
||||
<LoaderIcon />
|
||||
</Show>
|
||||
</span>
|
||||
<div data-slot="tool-error-card-main">
|
||||
<div data-slot="tool-error-card-labels">
|
||||
<span data-slot="tool-error-card-title">{local.title}</span>
|
||||
<span data-slot="tool-error-card-sep" aria-hidden="true">
|
||||
·
|
||||
</span>
|
||||
<Show
|
||||
when={local.subtitleHref}
|
||||
fallback={<span data-slot="tool-error-card-subtitle">{local.subtitle}</span>}
|
||||
>
|
||||
<a
|
||||
data-slot="tool-error-card-subtitle"
|
||||
href={local.subtitleHref!}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
{local.subtitle}
|
||||
</a>
|
||||
</Show>
|
||||
<Show when={hasSuffix()}>
|
||||
<span data-slot="tool-error-card-chevron-wrap">
|
||||
<ChevronIcon />
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
<Show when={hasSuffix()}>
|
||||
<Collapsible.Content data-slot="tool-error-card-content">
|
||||
<div data-slot="tool-error-card-suffix">{local.suffix}</div>
|
||||
</Collapsible.Content>
|
||||
</Show>
|
||||
</Collapsible>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user