mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-17 09:36:33 +03:00
refactor(webui): unify shared shape system
This commit is contained in:
@@ -59,7 +59,7 @@ export function FeishuAssistantsPanel({
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
footer: (
|
footer: (
|
||||||
<div className="mt-4 overflow-hidden rounded-[16px] border border-border/70 bg-background px-4 py-4">
|
<div className="mt-4 overflow-hidden rounded-floating border border-border/70 bg-background px-4 py-4">
|
||||||
<div className="text-[13px] font-semibold text-foreground">
|
<div className="text-[13px] font-semibold text-foreground">
|
||||||
{tx("custom.createAnother", "Create another assistant")}
|
{tx("custom.createAnother", "Create another assistant")}
|
||||||
</div>
|
</div>
|
||||||
@@ -144,7 +144,7 @@ function FeishuInstanceAction({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="mt-3 rounded-[12px] border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
<div className="mt-3 rounded-control border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ export function WeixinPanel({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="min-h-full rounded-[20px] bg-settings-surface p-5">
|
<aside className="min-h-full rounded-panel bg-settings-surface p-5">
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="flex items-start justify-between gap-4">
|
||||||
<div className="flex min-w-0 items-start gap-3">
|
<div className="flex min-w-0 items-start gap-3">
|
||||||
<WeixinLogo showBrandLogos={showBrandLogos} />
|
<WeixinLogo showBrandLogos={showBrandLogos} />
|
||||||
@@ -251,7 +251,7 @@ export function WeixinPanel({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{runtimeError ? (
|
{runtimeError ? (
|
||||||
<div className="mt-4 rounded-[12px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive">
|
<div className="mt-4 rounded-control border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive">
|
||||||
{runtimeError}
|
{runtimeError}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -304,7 +304,7 @@ export function WeixinPanel({
|
|||||||
{saveError ? (
|
{saveError ? (
|
||||||
<div
|
<div
|
||||||
role="alert"
|
role="alert"
|
||||||
className="rounded-[12px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive"
|
className="rounded-control border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive"
|
||||||
>
|
>
|
||||||
{saveError}
|
{saveError}
|
||||||
</div>
|
</div>
|
||||||
@@ -413,7 +413,7 @@ function WeixinLogo({ showBrandLogos }: { showBrandLogos: boolean }) {
|
|||||||
const { logoUrl, onLogoError, onLogoLoad } = useLogoFallback(logoUrls);
|
const { logoUrl, onLogoError, onLogoLoad } = useLogoFallback(logoUrls);
|
||||||
if (showBrandLogos && logoUrl) {
|
if (showBrandLogos && logoUrl) {
|
||||||
return (
|
return (
|
||||||
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-[12px] bg-background">
|
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-control bg-background">
|
||||||
<img
|
<img
|
||||||
src={logoUrl}
|
src={logoUrl}
|
||||||
alt=""
|
alt=""
|
||||||
@@ -428,7 +428,7 @@ function WeixinLogo({ showBrandLogos }: { showBrandLogos: boolean }) {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-background text-[11px] font-bold"
|
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-control bg-background text-[11px] font-bold"
|
||||||
style={{ color: "#07C160" }}
|
style={{ color: "#07C160" }}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
|
|||||||
+1
-1
@@ -563,7 +563,7 @@ function PairingCodePopup({
|
|||||||
aria-label={t("app.pairing.title", { defaultValue: "Pair a chat user" })}
|
aria-label={t("app.pairing.title", { defaultValue: "Pair a chat user" })}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed right-4 top-[calc(0.75rem+env(safe-area-inset-top))] z-[70]",
|
"fixed right-4 top-[calc(0.75rem+env(safe-area-inset-top))] z-[70]",
|
||||||
"w-[min(calc(100vw-2rem),24rem)] rounded-[24px]",
|
"w-[min(calc(100vw-2rem),24rem)] rounded-modal",
|
||||||
floatingSurfaceElevationClassName,
|
floatingSurfaceElevationClassName,
|
||||||
"p-4",
|
"p-4",
|
||||||
"animate-in fade-in-0 slide-in-from-top-2 duration-200",
|
"animate-in fade-in-0 slide-in-from-top-2 duration-200",
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export function AttachmentTile({ attachment, className, inline = false, variant
|
|||||||
title={attachment.name ?? undefined}
|
title={attachment.name ?? undefined}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex max-w-[18rem] items-center gap-2 rounded-[14px]",
|
"flex max-w-[18rem] items-center gap-2 rounded-control",
|
||||||
"border border-border/60 bg-muted/40 px-3 py-2 text-xs text-muted-foreground",
|
"border border-border/60 bg-muted/40 px-3 py-2 text-xs text-muted-foreground",
|
||||||
"transition-colors hover:bg-muted/55 hover:text-foreground",
|
"transition-colors hover:bg-muted/55 hover:text-foreground",
|
||||||
variant === "compact" && "max-w-[14rem] rounded-xl px-2.5 py-1.5 text-[11.5px]",
|
variant === "compact" && "max-w-[14rem] rounded-xl px-2.5 py-1.5 text-[11.5px]",
|
||||||
@@ -109,7 +109,7 @@ export function AttachmentTile({ attachment, className, inline = false, variant
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex max-w-[18rem] items-center gap-2 rounded-[14px]",
|
"flex max-w-[18rem] items-center gap-2 rounded-control",
|
||||||
"border border-border/60 bg-muted/35 px-3 py-2 text-xs text-muted-foreground",
|
"border border-border/60 bg-muted/35 px-3 py-2 text-xs text-muted-foreground",
|
||||||
variant === "compact" && "max-w-[14rem] rounded-xl px-2.5 py-1.5 text-[11.5px]",
|
variant === "compact" && "max-w-[14rem] rounded-xl px-2.5 py-1.5 text-[11.5px]",
|
||||||
className,
|
className,
|
||||||
@@ -139,7 +139,7 @@ function AttachmentFrame({
|
|||||||
variant?: "default" | "compact";
|
variant?: "default" | "compact";
|
||||||
}) {
|
}) {
|
||||||
const frameClassName = cn(
|
const frameClassName = cn(
|
||||||
"not-prose my-3 block w-fit max-w-full overflow-hidden rounded-[14px]",
|
"not-prose my-3 block w-fit max-w-full overflow-hidden rounded-control",
|
||||||
"border border-border/60 bg-muted/40",
|
"border border-border/60 bg-muted/40",
|
||||||
attachment.kind === "image" && "bg-background/85",
|
attachment.kind === "image" && "bg-background/85",
|
||||||
attachment.kind === "video" ? "w-[min(100%,32rem)]" : "",
|
attachment.kind === "video" ? "w-[min(100%,32rem)]" : "",
|
||||||
|
|||||||
@@ -807,7 +807,7 @@ export const ChatList = memo(function ChatList({
|
|||||||
actionMenus.openFromContextMenu(event, actionMenuId)
|
actionMenus.openFromContextMenu(event, actionMenuId)
|
||||||
)}
|
)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex min-w-0 max-w-full items-center gap-1 rounded-[0.65rem] px-2 text-[13px]",
|
"group flex min-w-0 max-w-full items-center gap-1 rounded-control px-2 text-[13px]",
|
||||||
SIDEBAR_SELECTION_ITEM_CLASS,
|
SIDEBAR_SELECTION_ITEM_CLASS,
|
||||||
compact ? "min-h-7" : "min-h-8",
|
compact ? "min-h-7" : "min-h-8",
|
||||||
topicActive
|
topicActive
|
||||||
@@ -1081,7 +1081,7 @@ function WorkbenchTabHeader({
|
|||||||
data-workbench-tab
|
data-workbench-tab
|
||||||
onContextMenu={(event) => actionMenus.openFromContextMenu(event, actionMenuId)}
|
onContextMenu={(event) => actionMenus.openFromContextMenu(event, actionMenuId)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/tab flex min-w-0 items-center gap-0.5 rounded-[0.65rem] px-1.5 text-sidebar-foreground/85",
|
"group/tab flex min-w-0 items-center gap-0.5 rounded-control px-1.5 text-sidebar-foreground/85",
|
||||||
collapsed ? "min-h-6" : "min-h-7",
|
collapsed ? "min-h-6" : "min-h-7",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -1281,7 +1281,7 @@ function ActivePaneRows({
|
|||||||
actionMenus.openFromContextMenu(event, actionMenuId)
|
actionMenus.openFromContextMenu(event, actionMenuId)
|
||||||
)}
|
)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/pane flex min-w-0 max-w-full items-center gap-1 rounded-[0.65rem] px-2 text-[13px]",
|
"group/pane flex min-w-0 max-w-full items-center gap-1 rounded-control px-2 text-[13px]",
|
||||||
SIDEBAR_SELECTION_ITEM_CLASS,
|
SIDEBAR_SELECTION_ITEM_CLASS,
|
||||||
compact ? "min-h-7" : "min-h-8",
|
compact ? "min-h-7" : "min-h-8",
|
||||||
active
|
active
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ export function CliAppMentionToken({
|
|||||||
<span
|
<span
|
||||||
data-testid={`${testIdPrefix}-cli-mention-logo-${app.name}`}
|
data-testid={`${testIdPrefix}-cli-mention-logo-${app.name}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute left-1/2 top-1/2 grid place-items-center overflow-hidden rounded-[3px]",
|
"absolute left-1/2 top-1/2 grid place-items-center overflow-hidden rounded-mark",
|
||||||
"-translate-x-1/2 -translate-y-1/2",
|
"-translate-x-1/2 -translate-y-1/2",
|
||||||
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
||||||
)}
|
)}
|
||||||
@@ -260,7 +260,7 @@ export function McpPresetMentionToken({
|
|||||||
<span
|
<span
|
||||||
data-testid={`${testIdPrefix}-mcp-mention-logo-${preset.name}`}
|
data-testid={`${testIdPrefix}-mcp-mention-logo-${preset.name}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute left-1/2 top-1/2 grid place-items-center overflow-hidden rounded-[3px]",
|
"absolute left-1/2 top-1/2 grid place-items-center overflow-hidden rounded-mark",
|
||||||
"-translate-x-1/2 -translate-y-1/2",
|
"-translate-x-1/2 -translate-y-1/2",
|
||||||
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export function CodeBlock({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"not-prose relative overflow-hidden",
|
"not-prose relative overflow-hidden",
|
||||||
hasChrome && "rounded-[18px] bg-secondary/70",
|
hasChrome && "rounded-floating bg-secondary/70",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
data-language={language || t("code.fallbackLanguage")}
|
data-language={language || t("code.fallbackLanguage")}
|
||||||
|
|||||||
@@ -96,16 +96,16 @@ export function DeleteConfirm({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter className="mt-7 !grid grid-cols-1 gap-3 space-x-0 sm:grid-cols-2 sm:space-x-0">
|
<AlertDialogFooter className="mt-6 !grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||||
<AlertDialogCancel
|
<AlertDialogCancel
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
className="mt-0 h-11 w-full min-w-0 rounded-full border-0 bg-muted/70 px-5 text-[15px] font-semibold text-foreground shadow-none hover:bg-muted"
|
className="mt-0 w-full min-w-0"
|
||||||
>
|
>
|
||||||
{t("deleteConfirm.cancel")}
|
{t("deleteConfirm.cancel")}
|
||||||
</AlertDialogCancel>
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
className="h-11 w-full min-w-0 !whitespace-normal rounded-full bg-destructive px-5 text-center text-[15px] font-semibold text-destructive-foreground shadow-none hover:bg-destructive/90"
|
className="w-full min-w-0 !whitespace-normal bg-destructive text-center text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
{hasAutomations
|
{hasAutomations
|
||||||
? t("deleteConfirm.confirmWithAutomations")
|
? t("deleteConfirm.confirmWithAutomations")
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export function FilePreviewPanel({
|
|||||||
) : null}
|
) : null}
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"min-w-0 truncate rounded-[4px] px-1 py-0.5",
|
"min-w-0 truncate rounded-mark px-1 py-0.5",
|
||||||
isLast
|
isLast
|
||||||
? "font-medium text-foreground"
|
? "font-medium text-foreground"
|
||||||
: "max-w-[26vw] shrink text-muted-foreground/78",
|
: "max-w-[26vw] shrink text-muted-foreground/78",
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export function FileReferenceChip({
|
|||||||
"text-sky-600 transition-colors hover:text-sky-700",
|
"text-sky-600 transition-colors hover:text-sky-700",
|
||||||
"dark:text-sky-300 dark:hover:text-sky-200",
|
"dark:text-sky-300 dark:hover:text-sky-200",
|
||||||
interactive && [
|
interactive && [
|
||||||
"cursor-pointer rounded-[5px]",
|
"cursor-pointer rounded-compact",
|
||||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-400/45",
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-400/45",
|
||||||
],
|
],
|
||||||
)}
|
)}
|
||||||
@@ -110,7 +110,7 @@ export function FileReferenceChip({
|
|||||||
sideOffset={8}
|
sideOffset={8}
|
||||||
collisionPadding={12}
|
collisionPadding={12}
|
||||||
className={cn(
|
className={cn(
|
||||||
"max-w-[min(38rem,calc(100vw-2rem))] rounded-[10px]",
|
"max-w-[min(38rem,calc(100vw-2rem))] rounded-control",
|
||||||
"px-2.5 py-1.5",
|
"px-2.5 py-1.5",
|
||||||
"break-all font-mono text-[11px] leading-snug text-popover-foreground",
|
"break-all font-mono text-[11px] leading-snug text-popover-foreground",
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export function ImageLightbox({
|
|||||||
alt={current.name ?? ""}
|
alt={current.name ?? ""}
|
||||||
decoding="async"
|
decoding="async"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className="max-h-[92vh] max-w-[94vw] select-none rounded-[6px] object-contain shadow-2xl"
|
className="max-h-[92vh] max-w-[94vw] select-none rounded-compact object-contain shadow-2xl"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px]",
|
"relative grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-mark",
|
||||||
"border border-border/65 bg-background text-muted-foreground",
|
"border border-border/65 bg-background text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
@@ -459,7 +459,7 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
|
|||||||
<img
|
<img
|
||||||
src={favicon}
|
src={favicon}
|
||||||
alt=""
|
alt=""
|
||||||
className="h-3 w-3 rounded-[2px] object-contain"
|
className="h-3 w-3 rounded-mark object-contain"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer"
|
referrerPolicy="no-referrer"
|
||||||
@@ -745,7 +745,7 @@ export default function MarkdownTextRenderer({
|
|||||||
},
|
},
|
||||||
mark({ children: markdownChildren }) {
|
mark({ children: markdownChildren }) {
|
||||||
return (
|
return (
|
||||||
<mark className="rounded-[5px] bg-yellow-200/75 px-1 py-0.5 text-inherit dark:bg-yellow-300/25">
|
<mark className="rounded-compact bg-yellow-200/75 px-1 py-0.5 text-inherit dark:bg-yellow-300/25">
|
||||||
{markdownChildren}
|
{markdownChildren}
|
||||||
</mark>
|
</mark>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ export function MessageBubble({
|
|||||||
<p
|
<p
|
||||||
data-temporary-message={temporary ? "true" : undefined}
|
data-temporary-message={temporary ? "true" : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
"ml-auto w-fit max-w-full min-w-0 rounded-[18px] px-4 py-2",
|
"ml-auto w-fit max-w-full min-w-0 rounded-floating px-4 py-2",
|
||||||
"text-left text-[16px]/[1.75] whitespace-pre-wrap [overflow-wrap:anywhere]",
|
"text-left text-[16px]/[1.75] whitespace-pre-wrap [overflow-wrap:anywhere]",
|
||||||
temporary
|
temporary
|
||||||
? "border border-dashed border-muted-foreground/40 bg-transparent"
|
? "border border-dashed border-muted-foreground/40 bg-transparent"
|
||||||
@@ -499,7 +499,7 @@ function UserQuotedContext({ text, label }: { text: string; label: string }) {
|
|||||||
return (
|
return (
|
||||||
<blockquote
|
<blockquote
|
||||||
className={cn(
|
className={cn(
|
||||||
"ml-auto flex w-fit max-w-full min-w-0 items-start gap-2 rounded-[14px]",
|
"ml-auto flex w-fit max-w-full min-w-0 items-start gap-2 rounded-control",
|
||||||
"border border-border/60 bg-muted/35 px-3 py-2 text-left text-muted-foreground",
|
"border border-border/60 bg-muted/35 px-3 py-2 text-left text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
@@ -718,8 +718,8 @@ function UserImageCell({
|
|||||||
const tileClasses = cn(
|
const tileClasses = cn(
|
||||||
"relative overflow-hidden border border-border/60 bg-muted/40",
|
"relative overflow-hidden border border-border/60 bg-muted/40",
|
||||||
size === "large"
|
size === "large"
|
||||||
? "w-[min(100%,34rem)] rounded-[20px] bg-transparent"
|
? "w-[min(100%,34rem)] rounded-panel bg-transparent"
|
||||||
: "h-24 w-24 rounded-[14px]",
|
: "h-24 w-24 rounded-control",
|
||||||
"shadow-[0_6px_18px_-14px_rgba(0,0,0,0.45)]",
|
"shadow-[0_6px_18px_-14px_rgba(0,0,0,0.45)]",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -44,41 +44,38 @@ export function RenameChatDialog({
|
|||||||
<Dialog open={open} onOpenChange={(next) => {
|
<Dialog open={open} onOpenChange={(next) => {
|
||||||
if (!next) onCancel();
|
if (!next) onCancel();
|
||||||
}}>
|
}}>
|
||||||
<DialogContent className="max-w-sm rounded-[20px] p-5 sm:p-6">
|
<DialogContent className="max-w-sm">
|
||||||
<form
|
<form
|
||||||
className="grid gap-5"
|
className="grid gap-4"
|
||||||
onSubmit={(event) => {
|
onSubmit={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!trimmed) return;
|
if (!trimmed) return;
|
||||||
onConfirm(trimmed);
|
onConfirm(trimmed);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogHeader className="space-y-1 text-left">
|
<DialogHeader className="text-left">
|
||||||
<DialogTitle className="text-xl leading-tight">
|
<DialogTitle>{dialogTitle ?? t("chat.renameTitle")}</DialogTitle>
|
||||||
{dialogTitle ?? t("chat.renameTitle")}
|
<DialogDescription>
|
||||||
</DialogTitle>
|
|
||||||
<DialogDescription className="leading-relaxed">
|
|
||||||
{description ?? t("chat.renameDescription")}
|
{description ?? t("chat.renameDescription")}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Input
|
<Input
|
||||||
className="h-11 rounded-xl border-border/80 bg-muted/20 px-3.5 text-[15px]"
|
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(event) => setValue(event.target.value)}
|
onChange={(event) => setValue(event.target.value)}
|
||||||
placeholder={placeholder ?? t("chat.renamePlaceholder")}
|
placeholder={placeholder ?? t("chat.renamePlaceholder")}
|
||||||
autoFocus
|
autoFocus
|
||||||
maxLength={160}
|
maxLength={160}
|
||||||
/>
|
/>
|
||||||
<DialogFooter className="gap-2 pt-1 sm:space-x-0">
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
className="min-w-20 rounded-xl"
|
className="min-w-20"
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
>
|
>
|
||||||
{t("deleteConfirm.cancel")}
|
{t("deleteConfirm.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="min-w-20 rounded-xl" type="submit" disabled={!trimmed}>
|
<Button className="min-w-20" type="submit" disabled={!trimmed}>
|
||||||
{t("chat.renameSave")}
|
{t("chat.renameSave")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ export function SessionSearchDialog({
|
|||||||
showCloseButton={false}
|
showCloseButton={false}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex max-h-[min(40rem,calc(100vh-2rem))] w-[calc(100vw-2rem)] max-w-[42rem] flex-col gap-0 overflow-hidden p-0",
|
"flex max-h-[min(40rem,calc(100vh-2rem))] w-[calc(100vw-2rem)] max-w-[42rem] flex-col gap-0 overflow-hidden p-0",
|
||||||
"rounded-[22px]",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<DialogTitle className="sr-only">{t("sidebar.searchAria")}</DialogTitle>
|
<DialogTitle className="sr-only">{t("sidebar.searchAria")}</DialogTitle>
|
||||||
@@ -183,7 +182,7 @@ export function SessionSearchDialog({
|
|||||||
onMouseEnter={() => setHighlightedIndex(index)}
|
onMouseEnter={() => setHighlightedIndex(index)}
|
||||||
aria-current={active ? "page" : undefined}
|
aria-current={active ? "page" : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
"grid min-h-[54px] w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-3 rounded-[11px] px-3 py-2 text-left transition-colors",
|
"grid min-h-[54px] w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-3 rounded-control px-3 py-2 text-left transition-colors",
|
||||||
highlighted
|
highlighted
|
||||||
? "bg-muted text-foreground"
|
? "bg-muted text-foreground"
|
||||||
: "text-foreground hover:bg-muted",
|
: "text-foreground hover:bg-muted",
|
||||||
|
|||||||
@@ -621,7 +621,7 @@ export function SettingsPage({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex h-48 items-center justify-center rounded-[22px] bg-settings-surface text-sm text-muted-foreground">
|
<div className="flex h-48 items-center justify-center rounded-panel bg-settings-surface text-sm text-muted-foreground">
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
{t("settings.status.loading")}
|
{t("settings.status.loading")}
|
||||||
</div>
|
</div>
|
||||||
@@ -640,7 +640,7 @@ export function SettingsPage({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="rounded-[18px] border border-destructive/20 bg-destructive/5 px-4 py-3 text-[13px] text-destructive">
|
<div className="rounded-floating border border-destructive/20 bg-destructive/5 px-4 py-3 text-[13px] text-destructive">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export function SettingsSidebar({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={`${t("settings.sidebar.title")}: ${activeLabel}`}
|
aria-label={`${t("settings.sidebar.title")}: ${activeLabel}`}
|
||||||
className="touch-target flex h-11 w-full items-center gap-2.5 rounded-[14px] bg-sidebar-accent px-3 text-left text-[13px] font-medium text-foreground transition-colors hover:bg-sidebar-accent/80 lg:hidden"
|
className="touch-target flex h-11 w-full items-center gap-2.5 rounded-control bg-sidebar-accent px-3 text-left text-[13px] font-medium text-foreground transition-colors hover:bg-sidebar-accent/80 lg:hidden"
|
||||||
>
|
>
|
||||||
<ActiveIcon className="h-4 w-4 shrink-0" strokeWidth={2} aria-hidden />
|
<ActiveIcon className="h-4 w-4 shrink-0" strokeWidth={2} aria-hidden />
|
||||||
<span className="min-w-0 flex-1 truncate">{activeLabel}</span>
|
<span className="min-w-0 flex-1 truncate">{activeLabel}</span>
|
||||||
@@ -176,7 +176,7 @@ export function SettingsSidebar({
|
|||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={onLogout}
|
onClick={onLogout}
|
||||||
className="h-9 w-full justify-start gap-2 rounded-[10px] px-2.5 text-[13px] font-medium text-muted-foreground hover:bg-destructive/8 hover:text-destructive"
|
className="h-9 w-full justify-start gap-2 rounded-control px-2.5 text-[13px] font-medium text-muted-foreground hover:bg-destructive/8 hover:text-destructive"
|
||||||
>
|
>
|
||||||
<LogOut className="h-4 w-4" aria-hidden />
|
<LogOut className="h-4 w-4" aria-hidden />
|
||||||
{t("app.account.logout")}
|
{t("app.account.logout")}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export function SkillsCatalogSettings({ skills }: { skills: SkillSummary[] }) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{view === "installed" ? (
|
{view === "installed" ? (
|
||||||
<section className="overflow-hidden rounded-[22px] bg-settings-surface">
|
<section className="overflow-hidden rounded-panel bg-settings-surface">
|
||||||
<div className="flex flex-col gap-3 px-4 pb-2 pt-4 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-3 px-4 pb-2 pt-4 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div className="relative w-full sm:max-w-[320px]">
|
<div className="relative w-full sm:max-w-[320px]">
|
||||||
<Search
|
<Search
|
||||||
@@ -114,7 +114,7 @@ export function SkillsCatalogSettings({ skills }: { skills: SkillSummary[] }) {
|
|||||||
aria-label={t("settings.skills.searchInstalled", {
|
aria-label={t("settings.skills.searchInstalled", {
|
||||||
defaultValue: "Search installed skills",
|
defaultValue: "Search installed skills",
|
||||||
})}
|
})}
|
||||||
className="h-9 rounded-[11px] bg-background pl-9 text-[13px]"
|
className="h-9 bg-background pl-9 text-[13px]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
@@ -220,7 +220,7 @@ function SkillCatalogRow({
|
|||||||
})}
|
})}
|
||||||
onClick={() => onSelect(skill)}
|
onClick={() => onSelect(skill)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex w-full min-w-0 items-center gap-3 rounded-[14px] px-2 py-3 text-left",
|
"group flex w-full min-w-0 items-center gap-3 rounded-control px-2 py-3 text-left",
|
||||||
"transition-colors duration-150",
|
"transition-colors duration-150",
|
||||||
"hover:bg-muted/70",
|
"hover:bg-muted/70",
|
||||||
"focus-visible:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
"focus-visible:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
||||||
@@ -436,7 +436,7 @@ function SkillDetailSheet({
|
|||||||
{t("settings.skills.loadingDetail", { defaultValue: "Loading skill details..." })}
|
{t("settings.skills.loadingDetail", { defaultValue: "Loading skill details..." })}
|
||||||
</div>
|
</div>
|
||||||
) : loadFailed ? (
|
) : loadFailed ? (
|
||||||
<div className="mt-8 rounded-[16px] bg-destructive/10 px-3 py-3 text-sm text-destructive">
|
<div className="mt-8 rounded-floating bg-destructive/10 px-3 py-3 text-sm text-destructive">
|
||||||
{t("settings.skills.loadFailed", { defaultValue: "Could not load skill details." })}
|
{t("settings.skills.loadFailed", { defaultValue: "Could not load skill details." })}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -484,7 +484,7 @@ function SkillDetailSheet({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{actionError ? (
|
{actionError ? (
|
||||||
<div className="rounded-[14px] bg-destructive/10 px-3 py-2.5 text-[13px] text-destructive">
|
<div className="rounded-control bg-destructive/10 px-3 py-2.5 text-[13px] text-destructive">
|
||||||
{actionError}
|
{actionError}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -533,7 +533,7 @@ function SkillDetailSheet({
|
|||||||
</Sheet>
|
</Sheet>
|
||||||
|
|
||||||
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
|
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
|
||||||
<AlertDialogContent className="rounded-[20px]">
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>
|
<AlertDialogTitle>
|
||||||
{t("settings.skills.deleteConfirmTitle", {
|
{t("settings.skills.deleteConfirmTitle", {
|
||||||
@@ -574,7 +574,7 @@ function RawInstructionsBlock({ markdown }: { markdown: string }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<details className="group rounded-[18px] border border-border/45 bg-muted/20 px-3 py-3">
|
<details className="group rounded-floating border border-border/45 bg-muted/20 px-3 py-3">
|
||||||
<summary className="flex min-h-11 cursor-pointer select-none items-center justify-between gap-3 text-[13px] font-medium text-foreground/90 transition-colors hover:text-foreground">
|
<summary className="flex min-h-11 cursor-pointer select-none items-center justify-between gap-3 text-[13px] font-medium text-foreground/90 transition-colors hover:text-foreground">
|
||||||
<span>
|
<span>
|
||||||
{t("settings.skills.instructionsTitle", { defaultValue: "Skill instructions" })}
|
{t("settings.skills.instructionsTitle", { defaultValue: "Skill instructions" })}
|
||||||
@@ -583,7 +583,7 @@ function RawInstructionsBlock({ markdown }: { markdown: string }) {
|
|||||||
SKILL.md
|
SKILL.md
|
||||||
</code>
|
</code>
|
||||||
</summary>
|
</summary>
|
||||||
<div className="mt-3 overflow-hidden rounded-[14px] border border-border/35 bg-background/70">
|
<div className="mt-3 overflow-hidden rounded-control border border-border/35 bg-background/70">
|
||||||
<pre
|
<pre
|
||||||
className={cn(
|
className={cn(
|
||||||
"max-h-[min(42vh,32rem)] overflow-auto overscroll-contain px-3.5 py-3 pr-4",
|
"max-h-[min(42vh,32rem)] overflow-auto overscroll-contain px-3.5 py-3 pr-4",
|
||||||
@@ -625,7 +625,7 @@ function RequirementsSection({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[18px] border border-amber-500/20 bg-amber-500/[0.06] p-4">
|
<section className="rounded-floating border border-amber-500/20 bg-amber-500/[0.06] p-4">
|
||||||
<div className="flex items-start gap-2.5">
|
<div className="flex items-start gap-2.5">
|
||||||
<CircleAlert
|
<CircleAlert
|
||||||
className="mt-0.5 h-4 w-4 shrink-0 text-amber-700 dark:text-amber-300"
|
className="mt-0.5 h-4 w-4 shrink-0 text-amber-700 dark:text-amber-300"
|
||||||
@@ -648,7 +648,7 @@ function RequirementsSection({
|
|||||||
{installOptions.map((option) => (
|
{installOptions.map((option) => (
|
||||||
<div
|
<div
|
||||||
key={`${option.id}:${option.command}`}
|
key={`${option.id}:${option.command}`}
|
||||||
className="flex min-w-0 items-center gap-2 rounded-[12px] bg-background/80 px-3 py-2"
|
className="flex min-w-0 items-center gap-2 rounded-control bg-background/80 px-3 py-2"
|
||||||
>
|
>
|
||||||
<Terminal className="h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden />
|
<Terminal className="h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden />
|
||||||
<code className="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[11px] text-foreground/80">
|
<code className="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[11px] text-foreground/80">
|
||||||
@@ -661,7 +661,7 @@ function RequirementsSection({
|
|||||||
})}
|
})}
|
||||||
title={option.label}
|
title={option.label}
|
||||||
onClick={() => void copyCommand(option.command)}
|
onClick={() => void copyCommand(option.command)}
|
||||||
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-[9px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground sm:h-7 sm:w-7"
|
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-control text-muted-foreground transition-colors hover:bg-muted hover:text-foreground sm:h-7 sm:w-7"
|
||||||
>
|
>
|
||||||
{copiedCommand === option.command ? (
|
{copiedCommand === option.command ? (
|
||||||
<Check className="h-3.5 w-3.5 text-emerald-600" aria-hidden />
|
<Check className="h-3.5 w-3.5 text-emerald-600" aria-hidden />
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export function SkillsMarketplace({
|
|||||||
aria-label={t("settings.skills.marketplaceSearchLabel", {
|
aria-label={t("settings.skills.marketplaceSearchLabel", {
|
||||||
defaultValue: "Search skills",
|
defaultValue: "Search skills",
|
||||||
})}
|
})}
|
||||||
className="h-11 rounded-[14px] bg-settings-surface pl-9"
|
className="h-11 rounded-control bg-settings-surface pl-9"
|
||||||
/>
|
/>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<span
|
<span
|
||||||
@@ -226,13 +226,13 @@ export function SkillsMarketplace({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="rounded-[14px] bg-destructive/10 px-3 py-2.5 text-[13px] text-destructive">
|
<div className="rounded-control bg-destructive/10 px-3 py-2.5 text-[13px] text-destructive">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{query.trim().length < 2 ? (
|
{query.trim().length < 2 ? (
|
||||||
<section className="overflow-hidden rounded-[22px] bg-settings-surface">
|
<section className="overflow-hidden rounded-panel bg-settings-surface">
|
||||||
<div className="flex flex-col items-start gap-2 px-4 pb-2 pt-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">
|
<div className="flex flex-col items-start gap-2 px-4 pb-2 pt-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">
|
||||||
<h2 className="text-[14px] font-semibold">
|
<h2 className="text-[14px] font-semibold">
|
||||||
{t("settings.skills.marketplaceTrendingTitle", {
|
{t("settings.skills.marketplaceTrendingTitle", {
|
||||||
@@ -271,14 +271,14 @@ export function SkillsMarketplace({
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
) : !loading && visibleResults.length === 0 && !error ? (
|
) : !loading && visibleResults.length === 0 && !error ? (
|
||||||
<div className="rounded-[22px] bg-settings-surface px-5 py-12 text-center text-sm text-muted-foreground">
|
<div className="rounded-panel bg-settings-surface px-5 py-12 text-center text-sm text-muted-foreground">
|
||||||
{t("settings.skills.marketplaceEmpty", {
|
{t("settings.skills.marketplaceEmpty", {
|
||||||
query: query.trim(),
|
query: query.trim(),
|
||||||
defaultValue: "No skills found for “{{query}}”.",
|
defaultValue: "No skills found for “{{query}}”.",
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="overflow-hidden rounded-[22px] bg-settings-surface">
|
<div className="overflow-hidden rounded-panel bg-settings-surface">
|
||||||
<MarketplaceSkillGroups
|
<MarketplaceSkillGroups
|
||||||
skills={visibleResults}
|
skills={visibleResults}
|
||||||
installedNames={installedNames}
|
installedNames={installedNames}
|
||||||
@@ -296,9 +296,9 @@ export function SkillsMarketplace({
|
|||||||
if (!open) setSelected(null);
|
if (!open) setSelected(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AlertDialogContent className="rounded-[20px]">
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<div className="mb-1 flex h-10 w-10 items-center justify-center rounded-[12px] bg-amber-500/10 text-amber-700 dark:text-amber-300">
|
<div className="mb-1 flex h-10 w-10 items-center justify-center rounded-control bg-amber-500/10 text-amber-700 dark:text-amber-300">
|
||||||
<ShieldAlert className="h-5 w-5" aria-hidden />
|
<ShieldAlert className="h-5 w-5" aria-hidden />
|
||||||
</div>
|
</div>
|
||||||
<AlertDialogTitle>
|
<AlertDialogTitle>
|
||||||
@@ -316,7 +316,7 @@ export function SkillsMarketplace({
|
|||||||
"This third-party skill comes from {{provider}} ({{source}}) and may include instructions or executable scripts.",
|
"This third-party skill comes from {{provider}} ({{source}}) and may include instructions or executable scripts.",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<span className="flex flex-wrap items-center gap-2 rounded-md bg-muted px-2 py-1.5 text-[12px] text-foreground">
|
<span className="flex flex-wrap items-center gap-2 rounded-control bg-muted px-2 py-1.5 text-[12px] text-foreground">
|
||||||
{selected ? <ProviderMark provider={selected.provider} /> : null}
|
{selected ? <ProviderMark provider={selected.provider} /> : null}
|
||||||
<code>{selected?.source}</code>
|
<code>{selected?.source}</code>
|
||||||
{selected?.version ? <span>v{selected.version}</span> : null}
|
{selected?.version ? <span>v{selected.version}</span> : null}
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ export function TokenUsageHeatmap({
|
|||||||
<span
|
<span
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
className={cn(
|
className={cn(
|
||||||
"aspect-square w-full rounded-[2px] transition-transform hover:scale-110 sm:rounded-[4px]",
|
"aspect-square w-full rounded-mark transition-transform hover:scale-110",
|
||||||
tokenUsageCellClass(level, cell.future),
|
tokenUsageCellClass(level, cell.future),
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export function ChannelLogo({
|
|||||||
if (showBrandLogos && logoUrl) {
|
if (showBrandLogos && logoUrl) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="grid h-10 w-10 shrink-0 place-items-center rounded-[12px] bg-background"
|
className="grid h-10 w-10 shrink-0 place-items-center rounded-control bg-background"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={logoUrl}
|
src={logoUrl}
|
||||||
@@ -154,7 +154,7 @@ export function ChannelLogo({
|
|||||||
if (Icon) {
|
if (Icon) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-background"
|
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-control bg-background"
|
||||||
style={{ color }}
|
style={{ color }}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
@@ -165,7 +165,7 @@ export function ChannelLogo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[12px] bg-background text-[11px] font-bold"
|
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-control bg-background text-[11px] font-bold"
|
||||||
style={{ color }}
|
style={{ color }}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
@@ -275,7 +275,7 @@ export function ChannelRuntimeError({
|
|||||||
}) {
|
}) {
|
||||||
if (!message) return null;
|
if (!message) return null;
|
||||||
return (
|
return (
|
||||||
<div className={`${className} rounded-[12px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive`}>
|
<div className={`${className} rounded-control border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-5 text-destructive`}>
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export function ChannelInstancesPanel({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="min-h-full rounded-[20px] bg-settings-surface p-5">
|
<aside className="min-h-full rounded-panel bg-settings-surface p-5">
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="flex min-w-0 items-start gap-3">
|
<div className="flex min-w-0 items-start gap-3">
|
||||||
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
||||||
@@ -177,7 +177,7 @@ export function ChannelInstancesPanel({
|
|||||||
<article
|
<article
|
||||||
key={instance.id}
|
key={instance.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
"overflow-hidden rounded-[18px] transition-colors",
|
"overflow-hidden rounded-floating transition-colors",
|
||||||
expanded
|
expanded
|
||||||
? "bg-background"
|
? "bg-background"
|
||||||
: "bg-background/70 hover:bg-muted",
|
: "bg-background/70 hover:bg-muted",
|
||||||
@@ -313,7 +313,7 @@ export function ChannelInstancesPanel({
|
|||||||
{customization.footer}
|
{customization.footer}
|
||||||
|
|
||||||
{notice ? (
|
{notice ? (
|
||||||
<div className="mt-3 rounded-[12px] border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
<div className="mt-3 rounded-control border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
||||||
{notice}
|
{notice}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -251,8 +251,8 @@ export function ChannelQrConnectFlow({
|
|||||||
return (
|
return (
|
||||||
<div className="mt-3 space-y-3">
|
<div className="mt-3 space-y-3">
|
||||||
{pending ? (
|
{pending ? (
|
||||||
<div className="grid gap-4 rounded-[14px] border border-border/70 p-4 sm:grid-cols-[auto_minmax(0,1fr)]">
|
<div className="grid gap-4 rounded-control border border-border/70 p-4 sm:grid-cols-[auto_minmax(0,1fr)]">
|
||||||
<div className="grid h-[196px] w-[196px] place-items-center rounded-[14px] border border-border/60 bg-background">
|
<div className="grid h-[196px] w-[196px] place-items-center rounded-control border border-border/60 bg-background">
|
||||||
{qrDataUrl ? (
|
{qrDataUrl ? (
|
||||||
<img
|
<img
|
||||||
src={qrDataUrl}
|
src={qrDataUrl}
|
||||||
@@ -293,20 +293,20 @@ export function ChannelQrConnectFlow({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{succeeded && !suppressSucceeded ? (
|
{succeeded && !suppressSucceeded ? (
|
||||||
<div className="flex items-center gap-2 rounded-[12px] border border-emerald-500/20 px-3 py-2 text-[12px] font-medium text-emerald-700 dark:text-emerald-200">
|
<div className="flex items-center gap-2 rounded-control border border-emerald-500/20 px-3 py-2 text-[12px] font-medium text-emerald-700 dark:text-emerald-200">
|
||||||
<Check className="h-3.5 w-3.5" aria-hidden />
|
<Check className="h-3.5 w-3.5" aria-hidden />
|
||||||
{displayMessage ?? labels.connected}
|
{displayMessage ?? labels.connected}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{connect && ["expired", "failed", "cancelled"].includes(connect.status) ? (
|
{connect && ["expired", "failed", "cancelled"].includes(connect.status) ? (
|
||||||
<div className="rounded-[12px] border border-border/60 px-3 py-2 text-[12px] leading-5 text-muted-foreground">
|
<div className="rounded-control border border-border/60 px-3 py-2 text-[12px] leading-5 text-muted-foreground">
|
||||||
{displayMessage || labels.stopped}
|
{displayMessage || labels.stopped}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="rounded-[12px] border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
<div className="rounded-control border border-destructive/20 px-3 py-2 text-[12px] leading-5 text-destructive">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export function ChannelCatalogRow({
|
|||||||
aria-pressed={selected}
|
aria-pressed={selected}
|
||||||
onClick={onSelect}
|
onClick={onSelect}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex w-full min-w-0 items-center gap-3 rounded-[14px] px-3 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border/80",
|
"group flex w-full min-w-0 items-center gap-3 rounded-control px-3 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border/80",
|
||||||
selected ? "bg-background" : "hover:bg-muted",
|
selected ? "bg-background" : "hover:bg-muted",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -187,7 +187,7 @@ export function ChannelSetupPanel({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="min-h-full rounded-[20px] bg-settings-surface p-5">
|
<aside className="min-h-full rounded-panel bg-settings-surface p-5">
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="flex items-start justify-between gap-4">
|
||||||
<div className="flex min-w-0 items-start gap-3">
|
<div className="flex min-w-0 items-start gap-3">
|
||||||
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
||||||
@@ -482,7 +482,7 @@ function ChannelSetupSurface({
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{setup.command ? (
|
{setup.command ? (
|
||||||
<code className="mt-3 block rounded-[10px] border border-border/50 bg-muted/45 px-2.5 py-2 font-mono text-[11px] leading-5 text-foreground">
|
<code className="mt-3 block rounded-control border border-border/50 bg-muted/45 px-2.5 py-2 font-mono text-[11px] leading-5 text-foreground">
|
||||||
{setup.command}
|
{setup.command}
|
||||||
</code>
|
</code>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -538,7 +538,7 @@ function ChannelSetupSurface({
|
|||||||
{notice ? (
|
{notice ? (
|
||||||
<div
|
<div
|
||||||
role="status"
|
role="status"
|
||||||
className="rounded-[12px] bg-muted/55 px-3 py-2.5 text-[12px] leading-5 text-muted-foreground"
|
className="rounded-control bg-muted/55 px-3 py-2.5 text-[12px] leading-5 text-muted-foreground"
|
||||||
>
|
>
|
||||||
{notice}
|
{notice}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ export function ChannelGuideLink({
|
|||||||
"inline-flex max-w-full items-center gap-2 bg-background/80 font-semibold text-foreground transition-colors hover:bg-background",
|
"inline-flex max-w-full items-center gap-2 bg-background/80 font-semibold text-foreground transition-colors hover:bg-background",
|
||||||
compact
|
compact
|
||||||
? "shrink-0 rounded-full py-1 pl-1 pr-2.5 text-[11.5px]"
|
? "shrink-0 rounded-full py-1 pl-1 pr-2.5 text-[11.5px]"
|
||||||
: "mt-3 rounded-[12px] py-1.5 pl-1.5 pr-3 text-[12px]",
|
: "mt-3 rounded-control py-1.5 pl-1.5 pr-3 text-[12px]",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"grid shrink-0 place-items-center overflow-hidden bg-muted/70 font-bold",
|
"grid shrink-0 place-items-center overflow-hidden bg-muted/70 font-bold",
|
||||||
compact ? "h-5 w-5 rounded-full text-[9px]" : "h-6 w-6 rounded-[7px] text-[10px]",
|
compact ? "h-5 w-5 rounded-full text-[9px]" : "h-6 w-6 rounded-compact text-[10px]",
|
||||||
)}
|
)}
|
||||||
style={{ color }}
|
style={{ color }}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
@@ -231,7 +231,7 @@ export function ChannelProviderPresets({
|
|||||||
<div
|
<div
|
||||||
role="radiogroup"
|
role="radiogroup"
|
||||||
aria-label={t("settings.channels.providerPreset", { defaultValue: "Provider" })}
|
aria-label={t("settings.channels.providerPreset", { defaultValue: "Provider" })}
|
||||||
className="grid rounded-[10px] bg-muted p-0.5 text-[12px] font-medium text-muted-foreground"
|
className="grid rounded-control bg-muted p-0.5 text-[12px] font-medium text-muted-foreground"
|
||||||
style={{ gridTemplateColumns: `repeat(${presets.length}, minmax(0, 1fr))` }}
|
style={{ gridTemplateColumns: `repeat(${presets.length}, minmax(0, 1fr))` }}
|
||||||
>
|
>
|
||||||
{presets.map((preset) => (
|
{presets.map((preset) => (
|
||||||
@@ -245,7 +245,7 @@ export function ChannelProviderPresets({
|
|||||||
onApply(preset);
|
onApply(preset);
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"min-h-8 rounded-[8px] px-2 py-1.5 transition-colors hover:text-foreground",
|
"min-h-8 rounded-compact px-2 py-1.5 transition-colors hover:text-foreground",
|
||||||
selected === preset.id && "bg-background text-foreground",
|
selected === preset.id && "bg-background text-foreground",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -370,7 +370,7 @@ export function ChannelSetupSteps({
|
|||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
{tryIt ? (
|
{tryIt ? (
|
||||||
<div className="mt-3 rounded-[12px] bg-background/75 px-3 py-2 text-[12px] text-muted-foreground">
|
<div className="mt-3 rounded-control bg-background/75 px-3 py-2 text-[12px] text-muted-foreground">
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
{tx("settings.channels.tryIt", "Try it")}
|
{tx("settings.channels.tryIt", "Try it")}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export function CredentialForm({
|
|||||||
<span
|
<span
|
||||||
role="radiogroup"
|
role="radiogroup"
|
||||||
aria-label={field.label}
|
aria-label={field.label}
|
||||||
className="mt-1 grid rounded-[10px] bg-muted p-0.5 text-[12px] font-medium text-muted-foreground"
|
className="mt-1 grid rounded-control bg-muted p-0.5 text-[12px] font-medium text-muted-foreground"
|
||||||
style={{ gridTemplateColumns: `repeat(${field.options.length}, minmax(0, 1fr))` }}
|
style={{ gridTemplateColumns: `repeat(${field.options.length}, minmax(0, 1fr))` }}
|
||||||
>
|
>
|
||||||
{field.options.map((option) => (
|
{field.options.map((option) => (
|
||||||
@@ -170,7 +170,7 @@ export function CredentialForm({
|
|||||||
aria-checked={selectedOption === option.value}
|
aria-checked={selectedOption === option.value}
|
||||||
onClick={() => onChange(field.key, option.value)}
|
onClick={() => onChange(field.key, option.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"min-h-8 rounded-[8px] px-2 py-1.5 transition-colors hover:text-foreground",
|
"min-h-8 rounded-compact px-2 py-1.5 transition-colors hover:text-foreground",
|
||||||
selectedOption === option.value
|
selectedOption === option.value
|
||||||
&& "bg-background text-foreground ring-1 ring-inset ring-border/45",
|
&& "bg-background text-foreground ring-1 ring-inset ring-border/45",
|
||||||
)}
|
)}
|
||||||
@@ -200,7 +200,7 @@ export function CredentialForm({
|
|||||||
value={values[field.key] ?? ""}
|
value={values[field.key] ?? ""}
|
||||||
onChange={(event) => onChange(field.key, event.target.value)}
|
onChange={(event) => onChange(field.key, event.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-9 rounded-[10px] border-border/60 bg-muted/35 text-[13px]",
|
"h-9 rounded-control border-border/60 bg-muted/35 text-[13px]",
|
||||||
showSecretToggle && "pr-9",
|
showSecretToggle && "pr-9",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export function ModelPresetDeleteDialog({
|
|||||||
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
||||||
return (
|
return (
|
||||||
<Dialog open={preset !== null} onOpenChange={onOpenChange}>
|
<Dialog open={preset !== null} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="max-w-[440px] rounded-[24px]">
|
<DialogContent className="max-w-[440px]">
|
||||||
<DialogHeader className="text-left">
|
<DialogHeader className="text-left">
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{tx("settings.models.deletePresetTitle", "Delete model preset?")}
|
{tx("settings.models.deletePresetTitle", "Delete model preset?")}
|
||||||
@@ -130,11 +130,10 @@ export function ModelPresetDeleteDialog({
|
|||||||
)}
|
)}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter className="gap-2 sm:space-x-0">
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="rounded-full"
|
|
||||||
disabled={deleting}
|
disabled={deleting}
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
>
|
>
|
||||||
@@ -143,7 +142,6 @@ export function ModelPresetDeleteDialog({
|
|||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
className="rounded-full"
|
|
||||||
disabled={deleting}
|
disabled={deleting}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
@@ -343,7 +341,7 @@ export function ModelsSettings({
|
|||||||
<div
|
<div
|
||||||
id="model-preset-editor"
|
id="model-preset-editor"
|
||||||
data-testid="model-preset-editor"
|
data-testid="model-preset-editor"
|
||||||
className="mx-3 mb-3 divide-y divide-border/45 overflow-hidden rounded-[18px] border border-border/45 bg-background/80 shadow-sm motion-reduce:animate-none animate-in fade-in-0 slide-in-from-top-1 duration-200 sm:mx-5 lg:mx-auto lg:w-[calc(100%-2.5rem)] lg:max-w-6xl"
|
className="mx-3 mb-3 divide-y divide-border/45 overflow-hidden rounded-floating border border-border/45 bg-background/80 shadow-sm motion-reduce:animate-none animate-in fade-in-0 slide-in-from-top-1 duration-200 sm:mx-5 lg:mx-auto lg:w-[calc(100%-2.5rem)] lg:max-w-6xl"
|
||||||
>
|
>
|
||||||
{creating ? (
|
{creating ? (
|
||||||
<div className="flex min-h-[52px] items-center px-4 py-3 sm:px-5">
|
<div className="flex min-h-[52px] items-center px-4 py-3 sm:px-5">
|
||||||
@@ -527,7 +525,7 @@ export function ModelsSettings({
|
|||||||
{!settings.model_call_order_editable ? (
|
{!settings.model_call_order_editable ? (
|
||||||
<div className="flex flex-col gap-4 px-4 py-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">
|
<div className="flex flex-col gap-4 px-4 py-4 sm:flex-row sm:items-center sm:justify-between sm:px-5">
|
||||||
<div className="flex min-w-0 items-start gap-3">
|
<div className="flex min-w-0 items-start gap-3">
|
||||||
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-[12px] bg-muted text-muted-foreground">
|
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-control bg-muted text-muted-foreground">
|
||||||
<ListOrdered className="h-4 w-4" aria-hidden />
|
<ListOrdered className="h-4 w-4" aria-hidden />
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
@@ -674,7 +672,7 @@ export function ModelsSettings({
|
|||||||
aria-controls={isSelected ? "model-preset-editor" : undefined}
|
aria-controls={isSelected ? "model-preset-editor" : undefined}
|
||||||
disabled={!preset}
|
disabled={!preset}
|
||||||
onClick={() => preset && selectPreset(preset, key)}
|
onClick={() => preset && selectPreset(preset, key)}
|
||||||
className="flex min-w-0 flex-1 items-center gap-3 rounded-[12px] text-left outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
className="flex min-w-0 flex-1 items-center gap-3 rounded-control text-left outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
>
|
>
|
||||||
{ordered ? (
|
{ordered ? (
|
||||||
<span className="grid h-7 w-7 shrink-0 place-items-center rounded-full bg-muted font-mono text-[11px] font-semibold tabular-nums text-muted-foreground">
|
<span className="grid h-7 w-7 shrink-0 place-items-center rounded-full bg-muted font-mono text-[11px] font-semibold tabular-nums text-muted-foreground">
|
||||||
@@ -841,7 +839,7 @@ function ModelAdvancedFields({
|
|||||||
const value = Number(event.target.value);
|
const value = Number(event.target.value);
|
||||||
if (Number.isFinite(value)) onChange({ maxTokens: value });
|
if (Number.isFinite(value)) onChange({ maxTokens: value });
|
||||||
}}
|
}}
|
||||||
className="h-9 rounded-[12px] text-[13px]"
|
className="h-9 text-[13px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -858,7 +856,7 @@ function ModelAdvancedFields({
|
|||||||
const value = Number(event.target.value);
|
const value = Number(event.target.value);
|
||||||
if (Number.isFinite(value)) onChange({ temperature: value });
|
if (Number.isFinite(value)) onChange({ temperature: value });
|
||||||
}}
|
}}
|
||||||
className="h-9 rounded-[12px] text-[13px]"
|
className="h-9 text-[13px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -887,7 +885,7 @@ function ModelAdvancedFields({
|
|||||||
placeholder={tx("settings.values.default", "Default")}
|
placeholder={tx("settings.values.default", "Default")}
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="h-9 rounded-[12px] text-[13px]"
|
className="h-9 text-[13px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ export function ProviderOAuthLoginDialog({
|
|||||||
if (!open) onClose();
|
if (!open) onClose();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogContent className="w-[min(calc(100vw-2rem),28rem)] rounded-[24px]">
|
<DialogContent className="w-[min(calc(100vw-2rem),28rem)]">
|
||||||
<form
|
<form
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
onSubmit={(event) => {
|
onSubmit={(event) => {
|
||||||
@@ -296,7 +296,7 @@ export function ProviderOAuthLoginDialog({
|
|||||||
: t("settings.oauth.localCodeHelp")}
|
: t("settings.oauth.localCodeHelp")}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex items-center gap-2 rounded-[14px] border border-border/45 bg-muted/35 px-3 py-2.5 text-[12px] text-muted-foreground">
|
<div className="flex items-center gap-2 rounded-control border border-border/45 bg-muted/35 px-3 py-2.5 text-[12px] text-muted-foreground">
|
||||||
{expectsCallbackUrl && remoteBrowserAccess ? (
|
{expectsCallbackUrl && remoteBrowserAccess ? (
|
||||||
<Clipboard className="h-3.5 w-3.5 shrink-0" aria-hidden />
|
<Clipboard className="h-3.5 w-3.5 shrink-0" aria-hidden />
|
||||||
) : (
|
) : (
|
||||||
@@ -341,12 +341,12 @@ export function ProviderOAuthLoginDialog({
|
|||||||
{error ? (
|
{error ? (
|
||||||
<p
|
<p
|
||||||
role="alert"
|
role="alert"
|
||||||
className="rounded-[14px] border border-destructive/20 bg-destructive/5 px-3 py-2.5 text-[12px] text-destructive"
|
className="rounded-control border border-destructive/20 bg-destructive/5 px-3 py-2.5 text-[12px] text-destructive"
|
||||||
>
|
>
|
||||||
{error}
|
{error}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<DialogFooter className="gap-2 sm:space-x-0">
|
<DialogFooter>
|
||||||
<Button type="button" variant="outline" onClick={onOpenAuthorization}>
|
<Button type="button" variant="outline" onClick={onOpenAuthorization}>
|
||||||
<ExternalLink className="mr-2 h-4 w-4" aria-hidden />
|
<ExternalLink className="mr-2 h-4 w-4" aria-hidden />
|
||||||
{expectsCallbackUrl
|
{expectsCallbackUrl
|
||||||
@@ -380,7 +380,7 @@ function ProviderRequestOptions({
|
|||||||
const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
|
const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden rounded-[18px] border border-border/45 bg-background/75">
|
<div className="overflow-hidden rounded-floating border border-border/45 bg-background/75">
|
||||||
{options.map((option, index) => {
|
{options.map((option, index) => {
|
||||||
const title = tx(option.titleKey, option.title);
|
const title = tx(option.titleKey, option.title);
|
||||||
const Icon = option.kind === "priority" ? Zap : Globe2;
|
const Icon = option.kind === "priority" ? Zap : Globe2;
|
||||||
@@ -599,7 +599,7 @@ function ProviderAdvancedOptions({
|
|||||||
onChange={(event) => onChange({ extraHeaders: event.target.value })}
|
onChange={(event) => onChange({ extraHeaders: event.target.value })}
|
||||||
placeholder={'{"X-Header":"value"}'}
|
placeholder={'{"X-Header":"value"}'}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="min-h-[88px] resize-y rounded-[14px] bg-background font-mono text-[12px]"
|
className="min-h-[88px] resize-y bg-background font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -613,7 +613,7 @@ function ProviderAdvancedOptions({
|
|||||||
onChange={(event) => onChange({ extraQuery: event.target.value })}
|
onChange={(event) => onChange({ extraQuery: event.target.value })}
|
||||||
placeholder={'{"api-version":"2024-02-01"}'}
|
placeholder={'{"api-version":"2024-02-01"}'}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="min-h-[88px] resize-y rounded-[14px] bg-background font-mono text-[12px]"
|
className="min-h-[88px] resize-y bg-background font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -627,7 +627,7 @@ function ProviderAdvancedOptions({
|
|||||||
onChange={(event) => onChange({ extraBody: event.target.value })}
|
onChange={(event) => onChange({ extraBody: event.target.value })}
|
||||||
placeholder={'{"service_tier":"priority"}'}
|
placeholder={'{"service_tier":"priority"}'}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
className="min-h-[96px] resize-y rounded-[14px] bg-background font-mono text-[12px]"
|
className="min-h-[96px] resize-y bg-background font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -825,7 +825,7 @@ export function ProvidersSettings({
|
|||||||
) : null}
|
) : null}
|
||||||
{isOauthProvider ? (
|
{isOauthProvider ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-3 rounded-[18px] border border-border/45 bg-background/75 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-3 rounded-floating border border-border/45 bg-background/75 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-[13px] font-semibold text-foreground">
|
<p className="text-[13px] font-semibold text-foreground">
|
||||||
{tx("settings.oauth.authentication", "OAuth authentication")}
|
{tx("settings.oauth.authentication", "OAuth authentication")}
|
||||||
@@ -1240,7 +1240,7 @@ export function ProvidersSettings({
|
|||||||
className="group flex min-h-[70px] w-full items-center justify-between gap-4 px-4 py-3 text-left transition-colors hover:bg-muted/35 sm:px-5"
|
className="group flex min-h-[70px] w-full items-center justify-between gap-4 px-4 py-3 text-left transition-colors hover:bg-muted/35 sm:px-5"
|
||||||
>
|
>
|
||||||
<span className="flex min-w-0 items-center gap-3">
|
<span className="flex min-w-0 items-center gap-3">
|
||||||
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-[14px] bg-muted text-muted-foreground">
|
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-control bg-muted text-muted-foreground">
|
||||||
<Plus className="h-5 w-5" aria-hidden />
|
<Plus className="h-5 w-5" aria-hidden />
|
||||||
</span>
|
</span>
|
||||||
<span className="truncate text-[15px] font-semibold text-foreground">
|
<span className="truncate text-[15px] font-semibold text-foreground">
|
||||||
@@ -1334,7 +1334,7 @@ function ProviderIcon({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-testid={`provider-logo-${provider}`}
|
data-testid={`provider-logo-${provider}`}
|
||||||
className="grid h-10 w-10 shrink-0 place-items-center overflow-hidden rounded-[14px] border border-border/45 bg-background"
|
className="grid h-10 w-10 shrink-0 place-items-center overflow-hidden rounded-control border border-border/45 bg-background"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={logoUrl}
|
src={logoUrl}
|
||||||
@@ -1352,7 +1352,7 @@ function ProviderIcon({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-testid={`provider-logo-fallback-${provider}`}
|
data-testid={`provider-logo-fallback-${provider}`}
|
||||||
className="grid h-10 w-10 shrink-0 place-items-center rounded-[14px] text-[11px] font-semibold text-white"
|
className="grid h-10 w-10 shrink-0 place-items-center rounded-control text-[11px] font-semibold text-white"
|
||||||
style={{ backgroundColor: brand.color }}
|
style={{ backgroundColor: brand.color }}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export function OverviewSettings({
|
|||||||
: tx("settings.values.ready", "Ready");
|
: tx("settings.values.ready", "Ready");
|
||||||
return (
|
return (
|
||||||
<div className="space-y-7">
|
<div className="space-y-7">
|
||||||
<section className="rounded-[22px] bg-settings-surface px-4 py-4 sm:px-5">
|
<section className="rounded-panel bg-settings-surface px-4 py-4 sm:px-5">
|
||||||
<TokenUsageHeatmap usage={settings.usage} timeZone={settings.agent.timezone} />
|
<TokenUsageHeatmap usage={settings.usage} timeZone={settings.agent.timezone} />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ function OverviewRowIcon({
|
|||||||
icon: LucideIcon;
|
icon: LucideIcon;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-[12px] bg-muted text-foreground/82 transition-colors group-hover:bg-muted/80 dark:bg-muted/70">
|
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-control bg-muted text-foreground/82 transition-colors group-hover:bg-muted/80 dark:bg-muted/70">
|
||||||
<Icon className="h-4 w-4" aria-hidden />
|
<Icon className="h-4 w-4" aria-hidden />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ export function ModelIdPicker({
|
|||||||
key={model.id}
|
key={model.id}
|
||||||
{...navigation.getOptionProps(model.id)}
|
{...navigation.getOptionProps(model.id)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex cursor-default items-center justify-between gap-2 rounded-[12px] px-2 py-1.5 text-[12px]",
|
"flex cursor-default items-center justify-between gap-2 rounded-control px-2 py-1.5 text-[12px]",
|
||||||
options.selected && "text-foreground",
|
options.selected && "text-foreground",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -455,7 +455,7 @@ export function ModelIdPicker({
|
|||||||
) : null}
|
) : null}
|
||||||
<ComboboxOption
|
<ComboboxOption
|
||||||
{...navigation.getOptionProps(customCandidate)}
|
{...navigation.getOptionProps(customCandidate)}
|
||||||
className="flex cursor-default items-center gap-2 rounded-[12px] px-2 py-1.5 text-[12px]"
|
className="flex cursor-default items-center gap-2 rounded-control px-2 py-1.5 text-[12px]"
|
||||||
>
|
>
|
||||||
<span className="grid h-5 w-5 shrink-0 place-items-center rounded-md bg-muted/80 text-muted-foreground">
|
<span className="grid h-5 w-5 shrink-0 place-items-center rounded-md bg-muted/80 text-muted-foreground">
|
||||||
<Pencil className="h-3 w-3" aria-hidden />
|
<Pencil className="h-3 w-3" aria-hidden />
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function CapabilityInstallNotice({
|
|||||||
installing?: boolean;
|
installing?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-start gap-3 rounded-[14px] border border-border/55 bg-muted/22 px-3.5 py-3">
|
<div className="flex items-start gap-3 rounded-control border border-border/55 bg-muted/22 px-3.5 py-3">
|
||||||
{installing ? (
|
{installing ? (
|
||||||
<Loader2 className="mt-0.5 h-4 w-4 shrink-0 animate-spin text-muted-foreground" aria-hidden />
|
<Loader2 className="mt-0.5 h-4 w-4 shrink-0 animate-spin text-muted-foreground" aria-hidden />
|
||||||
) : (
|
) : (
|
||||||
@@ -78,13 +78,13 @@ export function NanobotFeatureInstallDialog({
|
|||||||
)}
|
)}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter className="mt-7 !grid grid-cols-1 gap-3 space-x-0 sm:grid-cols-2 sm:space-x-0">
|
<DialogFooter className="mt-7 !grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
disabled={installing}
|
disabled={installing}
|
||||||
className="h-11 w-full min-w-0 rounded-full bg-muted/70 px-5 text-[15px] font-semibold text-foreground shadow-none hover:bg-muted"
|
className="h-11 w-full min-w-0 bg-muted/70 px-5 text-[15px] font-semibold text-foreground shadow-none hover:bg-muted"
|
||||||
>
|
>
|
||||||
{tx("settings.automations.cancel", "Cancel")}
|
{tx("settings.automations.cancel", "Cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -92,7 +92,7 @@ export function NanobotFeatureInstallDialog({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => feature && void onConfirm(feature)}
|
onClick={() => feature && void onConfirm(feature)}
|
||||||
disabled={!feature || installing}
|
disabled={!feature || installing}
|
||||||
className="h-11 w-full min-w-0 !whitespace-normal rounded-full px-5 text-center text-[15px] font-semibold"
|
className="h-11 w-full min-w-0 !whitespace-normal px-5 text-center text-[15px] font-semibold"
|
||||||
>
|
>
|
||||||
{installing ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
{installing ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
||||||
{tx("settings.nanobotFeatures.installConfirmAction", "Install and enable")}
|
{tx("settings.nanobotFeatures.installConfirmAction", "Install and enable")}
|
||||||
@@ -117,7 +117,7 @@ export function DismissibleStatusMessage({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center justify-between gap-3 rounded-[12px] border py-2.5 pl-4 pr-2 text-[13px]",
|
"flex items-center justify-between gap-3 rounded-control border py-2.5 pl-4 pr-2 text-[13px]",
|
||||||
isError
|
isError
|
||||||
? "border-destructive/20 bg-destructive/5 text-destructive"
|
? "border-destructive/20 bg-destructive/5 text-destructive"
|
||||||
: "border-border/55 bg-muted/35 text-muted-foreground",
|
: "border-border/55 bg-muted/35 text-muted-foreground",
|
||||||
@@ -153,7 +153,7 @@ export function RestartRequiredNotice({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-3 rounded-[12px] border border-amber-500/20 bg-amber-500/8 px-4 py-3 text-[12.5px] text-amber-800 dark:text-amber-200 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-3 rounded-control border border-amber-500/20 bg-amber-500/8 px-4 py-3 text-[12.5px] text-amber-800 dark:text-amber-200 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<span>{message}</span>
|
<span>{message}</span>
|
||||||
{onRestart ? (
|
{onRestart ? (
|
||||||
<Button
|
<Button
|
||||||
@@ -186,7 +186,7 @@ export function SettingsSectionTitle({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
export function SettingsGroup({ children }: { children: ReactNode }) {
|
export function SettingsGroup({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden rounded-[22px] bg-settings-surface">
|
<div className="overflow-hidden rounded-panel bg-settings-surface">
|
||||||
<div className="divide-y divide-border/45">{children}</div>
|
<div className="divide-y divide-border/45">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ export function AppsCatalogSettings({
|
|||||||
onChange={(event) => onQueryChange(event.target.value)}
|
onChange={(event) => onQueryChange(event.target.value)}
|
||||||
placeholder={tx("settings.apps.searchPlaceholder", "Search Apps")}
|
placeholder={tx("settings.apps.searchPlaceholder", "Search Apps")}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-12 rounded-[14px] pl-11 text-[15px]",
|
"h-12 pl-11 text-[15px]",
|
||||||
SETTINGS_SEARCH_INPUT_CLASS,
|
SETTINGS_SEARCH_INPUT_CLASS,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -289,7 +289,7 @@ export function AppsCatalogSettings({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<section className="rounded-[22px] bg-settings-surface px-3 py-3 sm:px-4">
|
<section className="rounded-panel bg-settings-surface px-3 py-3 sm:px-4">
|
||||||
<div className="flex items-center justify-between border-b border-border/45 pb-3">
|
<div className="flex items-center justify-between border-b border-border/45 pb-3">
|
||||||
<SettingsSectionTitle>
|
<SettingsSectionTitle>
|
||||||
{filter === "mcp"
|
{filter === "mcp"
|
||||||
@@ -412,7 +412,7 @@ function CliAppsCatalogRow({
|
|||||||
const description = app.description || app.requires || app.entry_point || app.name;
|
const description = app.description || app.requires || app.entry_point || app.name;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="apps-catalog-row group flex min-w-0 items-center gap-3 rounded-[14px] px-3 py-3 transition-colors hover:bg-muted/45">
|
<article className="apps-catalog-row group flex min-w-0 items-center gap-3 rounded-control px-3 py-3 transition-colors hover:bg-muted/45">
|
||||||
<CliAppLogo app={app} showBrandLogos={showBrandLogos} />
|
<CliAppLogo app={app} showBrandLogos={showBrandLogos} />
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="flex min-w-0 items-baseline gap-2">
|
<div className="flex min-w-0 items-baseline gap-2">
|
||||||
@@ -583,7 +583,7 @@ function McpAppsCatalogRow({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="min-w-0 rounded-[14px] transition-colors hover:bg-muted/45">
|
<article className="min-w-0 rounded-control transition-colors hover:bg-muted/45">
|
||||||
<div className="group flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 px-3 py-3">
|
<div className="group flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 px-3 py-3">
|
||||||
<McpPresetLogo preset={preset} showBrandLogos={showBrandLogos} />
|
<McpPresetLogo preset={preset} showBrandLogos={showBrandLogos} />
|
||||||
<div className="min-w-[8rem] flex-[1_1_8rem]">
|
<div className="min-w-[8rem] flex-[1_1_8rem]">
|
||||||
@@ -747,7 +747,7 @@ function McpAppsCatalogRow({
|
|||||||
|
|
||||||
{manualCallback ? (
|
{manualCallback ? (
|
||||||
<form
|
<form
|
||||||
className="mx-3 mb-3 min-w-0 space-y-3 rounded-[14px] bg-background/55 p-3"
|
className="mx-3 mb-3 min-w-0 space-y-3 rounded-control bg-background/55 p-3"
|
||||||
onSubmit={(event) => {
|
onSubmit={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onOAuthComplete();
|
onOAuthComplete();
|
||||||
@@ -825,7 +825,7 @@ function McpAppsCatalogRow({
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
) : oauthFlow && oauthPopupBlocked && oauthFlow.authorization_url ? (
|
) : oauthFlow && oauthPopupBlocked && oauthFlow.authorization_url ? (
|
||||||
<div className="mx-3 mb-3 flex flex-col gap-2.5 rounded-[14px] bg-background/55 p-3">
|
<div className="mx-3 mb-3 flex flex-col gap-2.5 rounded-control bg-background/55 p-3">
|
||||||
<div className="flex min-w-0 items-center gap-2.5 text-[12.5px] text-muted-foreground">
|
<div className="flex min-w-0 items-center gap-2.5 text-[12.5px] text-muted-foreground">
|
||||||
<span>
|
<span>
|
||||||
{mcpOAuthStatusText(
|
{mcpOAuthStatusText(
|
||||||
@@ -1016,10 +1016,10 @@ function McpCustomServerPanel({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="overflow-hidden rounded-[16px] bg-settings-surface">
|
<section className="overflow-hidden rounded-floating bg-settings-surface">
|
||||||
<div className="flex flex-col gap-3 px-3 py-3 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-3 px-3 py-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div className="flex min-w-0 items-center gap-3">
|
<div className="flex min-w-0 items-center gap-3">
|
||||||
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-[11px] bg-muted text-muted-foreground">
|
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-control bg-muted text-muted-foreground">
|
||||||
<Server className="h-4 w-4" aria-hidden />
|
<Server className="h-4 w-4" aria-hidden />
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
@@ -1154,7 +1154,7 @@ function McpCustomServerPanel({
|
|||||||
value={form.headers}
|
value={form.headers}
|
||||||
onChange={(event) => update("headers", event.target.value)}
|
onChange={(event) => update("headers", event.target.value)}
|
||||||
placeholder={'{"Authorization":"Bearer ..."}'}
|
placeholder={'{"Authorization":"Bearer ..."}'}
|
||||||
className="min-h-[68px] resize-y rounded-[12px] bg-background/80 font-mono text-[12px]"
|
className="min-h-[68px] resize-y bg-background/80 font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
id={headersHelpId}
|
id={headersHelpId}
|
||||||
@@ -1202,7 +1202,7 @@ function McpCustomServerPanel({
|
|||||||
value={form.args}
|
value={form.args}
|
||||||
onChange={(event) => update("args", event.target.value)}
|
onChange={(event) => update("args", event.target.value)}
|
||||||
placeholder={'["-y", "docs-mcp"]'}
|
placeholder={'["-y", "docs-mcp"]'}
|
||||||
className="min-h-[68px] resize-y rounded-[12px] bg-background/80 font-mono text-[12px]"
|
className="min-h-[68px] resize-y bg-background/80 font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -1214,7 +1214,7 @@ function McpCustomServerPanel({
|
|||||||
value={form.env}
|
value={form.env}
|
||||||
onChange={(event) => update("env", event.target.value)}
|
onChange={(event) => update("env", event.target.value)}
|
||||||
placeholder={'{"API_KEY":"..."}'}
|
placeholder={'{"API_KEY":"..."}'}
|
||||||
className="min-h-[68px] resize-y rounded-[12px] bg-background/80 font-mono text-[12px]"
|
className="min-h-[68px] resize-y bg-background/80 font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="min-w-0">
|
<label className="min-w-0">
|
||||||
@@ -1257,7 +1257,7 @@ function McpCustomServerPanel({
|
|||||||
value={configImport}
|
value={configImport}
|
||||||
onChange={(event) => onConfigImportChange(event.target.value)}
|
onChange={(event) => onConfigImportChange(event.target.value)}
|
||||||
placeholder={'{"mcpServers":{"docs":{"command":"npx","args":["-y","docs-mcp"]}}}'}
|
placeholder={'{"mcpServers":{"docs":{"command":"npx","args":["-y","docs-mcp"]}}}'}
|
||||||
className="min-h-[84px] resize-y rounded-[12px] bg-background/80 font-mono text-[12px]"
|
className="min-h-[84px] resize-y bg-background/80 font-mono text-[12px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<Button
|
<Button
|
||||||
@@ -1352,7 +1352,7 @@ function McpPresetLogo({
|
|||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"grid shrink-0 place-items-center border border-border/45 bg-background",
|
"grid shrink-0 place-items-center border border-border/45 bg-background",
|
||||||
compact ? "h-10 w-10 rounded-[10px]" : "h-11 w-11 rounded-[8px]",
|
compact ? "h-10 w-10 rounded-control" : "h-11 w-11 rounded-compact",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -1372,8 +1372,8 @@ function McpPresetLogo({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"grid shrink-0 place-items-center font-semibold text-white",
|
"grid shrink-0 place-items-center font-semibold text-white",
|
||||||
compact
|
compact
|
||||||
? "h-10 w-10 rounded-[10px] text-[12px]"
|
? "h-10 w-10 rounded-control text-[12px]"
|
||||||
: "h-11 w-11 rounded-[8px] text-[13px]",
|
: "h-11 w-11 rounded-compact text-[13px]",
|
||||||
)}
|
)}
|
||||||
style={{ backgroundColor: bg }}
|
style={{ backgroundColor: bg }}
|
||||||
>
|
>
|
||||||
@@ -1406,7 +1406,7 @@ function CliAppReadyPanel({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[12px] bg-settings-surface px-4 py-3">
|
<section className="rounded-control bg-settings-surface px-4 py-3">
|
||||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||||
<CliAppLogo app={app} showBrandLogos={showBrandLogos} />
|
<CliAppLogo app={app} showBrandLogos={showBrandLogos} />
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
@@ -1472,7 +1472,7 @@ function CliAppLogo({ app, showBrandLogos }: { app: CliAppInfo; showBrandLogos:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="relative grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-[8px] border border-border/45 bg-muted text-[13px] font-semibold"
|
className="relative grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-compact border border-border/45 bg-muted text-[13px] font-semibold"
|
||||||
style={{ color: app.brand_color || "hsl(var(--muted-foreground))" }}
|
style={{ color: app.brand_color || "hsl(var(--muted-foreground))" }}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -129,14 +129,14 @@ export function AutomationsSettings({
|
|||||||
<section className="shrink-0">
|
<section className="shrink-0">
|
||||||
<div className="mx-auto flex w-full max-w-[56rem] flex-col gap-3">
|
<div className="mx-auto flex w-full max-w-[56rem] flex-col gap-3">
|
||||||
<div className="-mx-1 overflow-x-auto px-1 pb-0.5">
|
<div className="-mx-1 overflow-x-auto px-1 pb-0.5">
|
||||||
<div className="grid w-full min-w-[36rem] grid-cols-5 gap-1 rounded-[15px] bg-muted p-1">
|
<div className="grid w-full min-w-[36rem] grid-cols-5 gap-1 rounded-floating bg-muted p-1">
|
||||||
{summaryOptions.map((option) => (
|
{summaryOptions.map((option) => (
|
||||||
<button
|
<button
|
||||||
key={option.value}
|
key={option.value}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onFilterChange(option.value)}
|
onClick={() => onFilterChange(option.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-8 min-w-0 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-[11px] px-3 text-[12px] font-medium text-muted-foreground transition-colors",
|
"inline-flex h-8 min-w-0 shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-control px-3 text-[12px] font-medium text-muted-foreground transition-colors",
|
||||||
filter === option.value && "bg-background text-foreground",
|
filter === option.value && "bg-background text-foreground",
|
||||||
automationFilterToneClass(option.value, option.count, filter === option.value),
|
automationFilterToneClass(option.value, option.count, filter === option.value),
|
||||||
)}
|
)}
|
||||||
@@ -166,7 +166,7 @@ export function AutomationsSettings({
|
|||||||
"Search task, message, linked chat, or schedule",
|
"Search task, message, linked chat, or schedule",
|
||||||
)}
|
)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-9 w-full rounded-[13px] pl-9 text-[13px]",
|
"h-9 w-full rounded-control pl-9 text-[13px]",
|
||||||
SETTINGS_SEARCH_INPUT_CLASS,
|
SETTINGS_SEARCH_INPUT_CLASS,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -175,7 +175,7 @@ export function AutomationsSettings({
|
|||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex h-9 min-w-[8.5rem] items-center justify-center gap-1.5 whitespace-nowrap rounded-[13px] border border-border/45 bg-settings-surface px-3 text-[12px] font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground sm:w-auto"
|
className="inline-flex h-9 min-w-[8.5rem] items-center justify-center gap-1.5 whitespace-nowrap rounded-control border border-border/45 bg-settings-surface px-3 text-[12px] font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground sm:w-auto"
|
||||||
>
|
>
|
||||||
<ArrowUpDown className="h-3.5 w-3.5" aria-hidden />
|
<ArrowUpDown className="h-3.5 w-3.5" aria-hidden />
|
||||||
<span>{sortLabel[sort]}</span>
|
<span>{sortLabel[sort]}</span>
|
||||||
@@ -197,19 +197,19 @@ export function AutomationsSettings({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="flex items-center gap-2 rounded-[18px] border border-destructive/20 bg-destructive/5 px-4 py-3 text-[13px] text-destructive">
|
<div className="flex items-center gap-2 rounded-floating border border-destructive/20 bg-destructive/5 px-4 py-3 text-[13px] text-destructive">
|
||||||
<CircleAlert className="h-4 w-4 shrink-0" aria-hidden />
|
<CircleAlert className="h-4 w-4 shrink-0" aria-hidden />
|
||||||
<span>{error}</span>
|
<span>{error}</span>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{loading && !payload ? (
|
{loading && !payload ? (
|
||||||
<div className="flex h-44 items-center justify-center rounded-[22px] bg-settings-surface text-[13px] text-muted-foreground">
|
<div className="flex h-44 items-center justify-center rounded-panel bg-settings-surface text-[13px] text-muted-foreground">
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden />
|
||||||
{tx("settings.automations.loading", "Loading automations...")}
|
{tx("settings.automations.loading", "Loading automations...")}
|
||||||
</div>
|
</div>
|
||||||
) : filtered.length && selectedJob ? (
|
) : filtered.length && selectedJob ? (
|
||||||
<section className="grid min-h-0 overflow-hidden rounded-[22px] bg-settings-surface xl:grid-cols-[minmax(16rem,18rem)_minmax(0,1fr)] xl:items-stretch">
|
<section className="grid min-h-0 overflow-hidden rounded-panel bg-settings-surface xl:grid-cols-[minmax(16rem,18rem)_minmax(0,1fr)] xl:items-stretch">
|
||||||
<aside className="flex min-h-0 flex-col overflow-hidden border-b border-border/35 bg-settings-surface xl:border-b-0 xl:border-r">
|
<aside className="flex min-h-0 flex-col overflow-hidden border-b border-border/35 bg-settings-surface xl:border-b-0 xl:border-r">
|
||||||
<div className="flex shrink-0 items-center justify-between gap-3 px-4 py-3">
|
<div className="flex shrink-0 items-center justify-between gap-3 px-4 py-3">
|
||||||
<h2 className="text-[13px] font-semibold tracking-[-0.01em] text-foreground/85">
|
<h2 className="text-[13px] font-semibold tracking-[-0.01em] text-foreground/85">
|
||||||
@@ -245,7 +245,7 @@ export function AutomationsSettings({
|
|||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-[22px] bg-settings-surface px-5 py-12 text-center text-[13px] text-muted-foreground">
|
<div className="rounded-panel bg-settings-surface px-5 py-12 text-center text-[13px] text-muted-foreground">
|
||||||
<div>
|
<div>
|
||||||
{jobs.length
|
{jobs.length
|
||||||
? tx("settings.automations.noMatches", "No automations match this view.")
|
? tx("settings.automations.noMatches", "No automations match this view.")
|
||||||
@@ -313,7 +313,7 @@ function AutomationListItem({
|
|||||||
aria-pressed={selected}
|
aria-pressed={selected}
|
||||||
onClick={onSelect}
|
onClick={onSelect}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group grid w-full grid-cols-[minmax(0,1fr)_auto] gap-3 rounded-[18px] px-3 py-3.5 text-left transition-colors",
|
"group grid w-full grid-cols-[minmax(0,1fr)_auto] gap-3 rounded-floating px-3 py-3.5 text-left transition-colors",
|
||||||
selected
|
selected
|
||||||
? "bg-background/80 text-foreground"
|
? "bg-background/80 text-foreground"
|
||||||
: "text-muted-foreground hover:bg-background/55 hover:text-foreground",
|
: "text-muted-foreground hover:bg-background/55 hover:text-foreground",
|
||||||
@@ -433,7 +433,7 @@ function AutomationDetailPanel({
|
|||||||
|
|
||||||
<div className="grid min-h-0 min-w-0 flex-1 overflow-hidden lg:grid-cols-[minmax(0,1fr)_14.5rem]">
|
<div className="grid min-h-0 min-w-0 flex-1 overflow-hidden lg:grid-cols-[minmax(0,1fr)_14.5rem]">
|
||||||
<div className="min-h-0 min-w-0 space-y-3 overflow-y-auto overscroll-contain p-4 sm:p-5">
|
<div className="min-h-0 min-w-0 space-y-3 overflow-y-auto overscroll-contain p-4 sm:p-5">
|
||||||
<section className="rounded-[20px] bg-background/55 px-4 py-3.5">
|
<section className="rounded-floating bg-background/55 px-4 py-3.5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div className="text-[11px] font-medium leading-none text-muted-foreground/75">
|
<div className="text-[11px] font-medium leading-none text-muted-foreground/75">
|
||||||
{messageLabel}
|
{messageLabel}
|
||||||
@@ -506,7 +506,7 @@ function AutomationDetailPanel({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{job.state.last_error ? (
|
{job.state.last_error ? (
|
||||||
<div className="rounded-[16px] border border-destructive/20 bg-destructive/8 px-3 py-2 text-[12px] leading-5 text-destructive">
|
<div className="rounded-floating border border-destructive/20 bg-destructive/8 px-3 py-2 text-[12px] leading-5 text-destructive">
|
||||||
{job.state.last_error}
|
{job.state.last_error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -520,7 +520,7 @@ function AutomationDetailPanel({
|
|||||||
>
|
>
|
||||||
{schedule}
|
{schedule}
|
||||||
</AutomationDetail>
|
</AutomationDetail>
|
||||||
<div className="rounded-[18px] bg-background/55 p-3">
|
<div className="rounded-floating bg-background/55 p-3">
|
||||||
<div className="grid gap-3">
|
<div className="grid gap-3">
|
||||||
{created ? (
|
{created ? (
|
||||||
<div>
|
<div>
|
||||||
@@ -672,7 +672,7 @@ function AutomationDetail({
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="min-w-0 rounded-[17px] bg-background/55 px-3 py-3">
|
<div className="min-w-0 rounded-floating bg-background/55 px-3 py-3">
|
||||||
<div className="text-[11px] font-medium leading-none text-muted-foreground/75">
|
<div className="text-[11px] font-medium leading-none text-muted-foreground/75">
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
@@ -757,7 +757,7 @@ export function AutomationEditDialog({
|
|||||||
{job ? (
|
{job ? (
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-describedby={undefined}
|
aria-describedby={undefined}
|
||||||
className="w-[min(calc(100vw-2rem),34rem)] rounded-[26px]"
|
className="w-[min(calc(100vw-2rem),34rem)]"
|
||||||
>
|
>
|
||||||
<form className="space-y-5" onSubmit={submit}>
|
<form className="space-y-5" onSubmit={submit}>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
@@ -772,7 +772,6 @@ export function AutomationEditDialog({
|
|||||||
<Input
|
<Input
|
||||||
value={draft.name}
|
value={draft.name}
|
||||||
onChange={(event) => setDraft((prev) => ({ ...prev, name: event.target.value }))}
|
onChange={(event) => setDraft((prev) => ({ ...prev, name: event.target.value }))}
|
||||||
className="h-10 rounded-[12px]"
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -784,7 +783,7 @@ export function AutomationEditDialog({
|
|||||||
<Textarea
|
<Textarea
|
||||||
value={draft.message}
|
value={draft.message}
|
||||||
onChange={(event) => setDraft((prev) => ({ ...prev, message: event.target.value }))}
|
onChange={(event) => setDraft((prev) => ({ ...prev, message: event.target.value }))}
|
||||||
className="min-h-[160px] resize-none rounded-[12px] text-[13px] leading-5"
|
className="min-h-[160px] resize-none text-[13px] leading-5"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -821,7 +820,6 @@ export function AutomationEditDialog({
|
|||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setDraft((prev) => ({ ...prev, everyValue: event.target.value }))
|
setDraft((prev) => ({ ...prev, everyValue: event.target.value }))
|
||||||
}
|
}
|
||||||
className="h-10 rounded-[12px]"
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="block space-y-1.5">
|
<label className="block space-y-1.5">
|
||||||
@@ -837,7 +835,7 @@ export function AutomationEditDialog({
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-10 w-full rounded-[12px] border border-input bg-background px-3 text-[13px] text-foreground transition-colors",
|
"h-10 w-full rounded-control border border-input bg-background px-3 text-[13px] text-foreground transition-colors",
|
||||||
formControlFocusClassName,
|
formControlFocusClassName,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -861,7 +859,7 @@ export function AutomationEditDialog({
|
|||||||
value={draft.cronExpr}
|
value={draft.cronExpr}
|
||||||
onChange={(event) => setDraft((prev) => ({ ...prev, cronExpr: event.target.value }))}
|
onChange={(event) => setDraft((prev) => ({ ...prev, cronExpr: event.target.value }))}
|
||||||
placeholder="0 9 * * *"
|
placeholder="0 9 * * *"
|
||||||
className="h-10 rounded-[12px] font-mono text-[13px]"
|
className="font-mono text-[13px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="block space-y-1.5">
|
<label className="block space-y-1.5">
|
||||||
@@ -872,7 +870,7 @@ export function AutomationEditDialog({
|
|||||||
value={draft.tz}
|
value={draft.tz}
|
||||||
onChange={(event) => setDraft((prev) => ({ ...prev, tz: event.target.value }))}
|
onChange={(event) => setDraft((prev) => ({ ...prev, tz: event.target.value }))}
|
||||||
placeholder="Asia/Shanghai"
|
placeholder="Asia/Shanghai"
|
||||||
className="h-10 rounded-[12px] text-[13px]"
|
className="text-[13px]"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -887,13 +885,12 @@ export function AutomationEditDialog({
|
|||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
value={draft.atLocal}
|
value={draft.atLocal}
|
||||||
onChange={(event) => setDraft((prev) => ({ ...prev, atLocal: event.target.value }))}
|
onChange={(event) => setDraft((prev) => ({ ...prev, atLocal: event.target.value }))}
|
||||||
className="h-10 rounded-[12px]"
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{validation ? (
|
{validation ? (
|
||||||
<div className="rounded-[12px] bg-destructive/8 px-3 py-2 text-[12px] text-destructive">
|
<div className="rounded-control bg-destructive/8 px-3 py-2 text-[12px] text-destructive">
|
||||||
{validation}
|
{validation}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -905,11 +902,10 @@ export function AutomationEditDialog({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
className="rounded-full"
|
|
||||||
>
|
>
|
||||||
{tx("settings.automations.cancel", "Cancel")}
|
{tx("settings.automations.cancel", "Cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" disabled={Boolean(validation) || saving} className="rounded-full">
|
<Button type="submit" disabled={Boolean(validation) || saving}>
|
||||||
{saving ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
{saving ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
||||||
{tx("settings.automations.save", "Save")}
|
{tx("settings.automations.save", "Save")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -937,7 +933,7 @@ export function AutomationDeleteDialog({
|
|||||||
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
||||||
return (
|
return (
|
||||||
<Dialog open={Boolean(job)} onOpenChange={onOpenChange}>
|
<Dialog open={Boolean(job)} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="w-[min(calc(100vw-2rem),26rem)] rounded-[26px]">
|
<DialogContent className="w-[min(calc(100vw-2rem),26rem)]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{tx("settings.automations.deleteTitle", "Delete automation")}</DialogTitle>
|
<DialogTitle>{tx("settings.automations.deleteTitle", "Delete automation")}</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
@@ -954,7 +950,6 @@ export function AutomationDeleteDialog({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
disabled={deleting}
|
disabled={deleting}
|
||||||
className="rounded-full"
|
|
||||||
>
|
>
|
||||||
{tx("settings.automations.cancel", "Cancel")}
|
{tx("settings.automations.cancel", "Cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -963,7 +958,6 @@ export function AutomationDeleteDialog({
|
|||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={() => job && void onConfirm(job)}
|
onClick={() => job && void onConfirm(job)}
|
||||||
disabled={!job || deleting}
|
disabled={!job || deleting}
|
||||||
className="rounded-full"
|
|
||||||
>
|
>
|
||||||
{deleting ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
{deleting ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
||||||
{tx("settings.automations.delete", "Delete")}
|
{tx("settings.automations.delete", "Delete")}
|
||||||
|
|||||||
@@ -147,19 +147,19 @@ export function ChannelsSettings({
|
|||||||
onChange={(event) => onQueryChange(event.target.value)}
|
onChange={(event) => onQueryChange(event.target.value)}
|
||||||
placeholder={tx("settings.channels.searchPlaceholder", "Search channels")}
|
placeholder={tx("settings.channels.searchPlaceholder", "Search channels")}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-12 rounded-[14px] pl-11 text-[15px]",
|
"h-12 rounded-control pl-11 text-[15px]",
|
||||||
SETTINGS_SEARCH_INPUT_CLASS,
|
SETTINGS_SEARCH_INPUT_CLASS,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 flex-wrap gap-1.5 rounded-[14px] bg-muted/55 p-1">
|
<div className="flex shrink-0 flex-wrap gap-1.5 rounded-control bg-muted/55 p-1">
|
||||||
{filterOptions.map((option) => (
|
{filterOptions.map((option) => (
|
||||||
<button
|
<button
|
||||||
key={option.value}
|
key={option.value}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setFilter(option.value)}
|
onClick={() => setFilter(option.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-[11px] px-3 py-1.5 text-[12px] font-medium transition-colors",
|
"rounded-control px-3 py-1.5 text-[12px] font-medium transition-colors",
|
||||||
filter === option.value
|
filter === option.value
|
||||||
? "bg-background text-foreground"
|
? "bg-background text-foreground"
|
||||||
: "text-muted-foreground hover:text-foreground",
|
: "text-muted-foreground hover:text-foreground",
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ export function McpManagementDialog({
|
|||||||
showCloseButton={false}
|
showCloseButton={false}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-[min(34rem,calc(100dvh-2rem))] w-[calc(100vw-2rem)] max-w-[42rem] flex-col gap-0 overflow-hidden p-0",
|
"flex h-[min(34rem,calc(100dvh-2rem))] w-[calc(100vw-2rem)] max-w-[42rem] flex-col gap-0 overflow-hidden p-0",
|
||||||
"rounded-[22px]",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex shrink-0 items-center gap-3 border-b border-border/45 px-5 py-3.5 sm:px-6">
|
<div className="flex shrink-0 items-center gap-3 border-b border-border/45 px-5 py-3.5 sm:px-6">
|
||||||
@@ -282,7 +281,7 @@ function OverviewPanel({
|
|||||||
const previewTools = (preset.tool_names ?? []).slice(0, 4);
|
const previewTools = (preset.tool_names ?? []).slice(0, 4);
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<section className="rounded-[16px] border border-border/55 px-4 py-3.5">
|
<section className="rounded-floating border border-border/55 px-4 py-3.5">
|
||||||
<h3 className="text-[13px] font-semibold text-foreground">
|
<h3 className="text-[13px] font-semibold text-foreground">
|
||||||
{tx("settings.mcp.about", "About this MCP")}
|
{tx("settings.mcp.about", "About this MCP")}
|
||||||
</h3>
|
</h3>
|
||||||
@@ -314,7 +313,7 @@ function OverviewPanel({
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
{previewTools.length ? (
|
{previewTools.length ? (
|
||||||
<section className="rounded-[16px] bg-muted/45 p-4">
|
<section className="rounded-floating bg-muted/45 p-4">
|
||||||
<h3 className="text-[13px] font-semibold text-foreground">
|
<h3 className="text-[13px] font-semibold text-foreground">
|
||||||
{tx("settings.mcp.toolPreview", "Tools")}
|
{tx("settings.mcp.toolPreview", "Tools")}
|
||||||
</h3>
|
</h3>
|
||||||
@@ -375,7 +374,7 @@ function ToolsPanel({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col gap-3 rounded-[16px] border px-4 py-3.5 sm:flex-row sm:items-center sm:justify-between",
|
"flex flex-col gap-3 rounded-floating border px-4 py-3.5 sm:flex-row sm:items-center sm:justify-between",
|
||||||
preset.error ? "border-destructive/25 bg-destructive/5" : "border-border/55 bg-muted/25",
|
preset.error ? "border-destructive/25 bg-destructive/5" : "border-border/55 bg-muted/25",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -444,7 +443,7 @@ function ToolsPanel({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-hidden rounded-[16px] border border-border/55">
|
<div className="overflow-hidden rounded-floating border border-border/55">
|
||||||
{filteredTools.length ? filteredTools.map((toolName) => {
|
{filteredTools.length ? filteredTools.map((toolName) => {
|
||||||
const selected = selectedTools.has(toolName);
|
const selected = selectedTools.has(toolName);
|
||||||
return (
|
return (
|
||||||
@@ -463,7 +462,7 @@ function ToolsPanel({
|
|||||||
<span
|
<span
|
||||||
aria-hidden
|
aria-hidden
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none absolute inset-0 grid place-items-center rounded-[7px] border transition-colors",
|
"pointer-events-none absolute inset-0 grid place-items-center rounded-compact border transition-colors",
|
||||||
selected
|
selected
|
||||||
? "border-foreground bg-foreground text-background"
|
? "border-foreground bg-foreground text-background"
|
||||||
: "border-border bg-background text-transparent",
|
: "border-border bg-background text-transparent",
|
||||||
@@ -529,7 +528,7 @@ function ConnectionPanel({
|
|||||||
<h3 id={`mcp-connection-${preset.name}`} className="sr-only">
|
<h3 id={`mcp-connection-${preset.name}`} className="sr-only">
|
||||||
{tx("settings.mcp.connectionDetails", "Connection details")}
|
{tx("settings.mcp.connectionDetails", "Connection details")}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="rounded-[16px] bg-muted/40 px-4 py-3.5">
|
<div className="rounded-floating bg-muted/40 px-4 py-3.5">
|
||||||
{preset.connection_summary ? (
|
{preset.connection_summary ? (
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-[12.5px] font-medium text-muted-foreground">{connectionLabel}</p>
|
<p className="text-[12.5px] font-medium text-muted-foreground">{connectionLabel}</p>
|
||||||
@@ -580,7 +579,7 @@ function ConnectionPanel({
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{preset.error ? (
|
{preset.error ? (
|
||||||
<div role="alert" className="rounded-[14px] bg-destructive/10 px-3.5 py-3 text-[12.5px] leading-5 text-destructive">
|
<div role="alert" className="rounded-control bg-destructive/10 px-3.5 py-3 text-[12.5px] leading-5 text-destructive">
|
||||||
{preset.error}
|
{preset.error}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -661,7 +660,7 @@ function ConnectionPanel({
|
|||||||
|
|
||||||
function MetricCard({ label, value }: { label: string; value: string }) {
|
function MetricCard({ label, value }: { label: string; value: string }) {
|
||||||
return (
|
return (
|
||||||
<div className="min-w-0 rounded-[14px] bg-muted/45 px-3.5 py-3">
|
<div className="min-w-0 rounded-control bg-muted/45 px-3.5 py-3">
|
||||||
<dt className="text-[12px] font-medium text-muted-foreground">{label}</dt>
|
<dt className="text-[12px] font-medium text-muted-foreground">{label}</dt>
|
||||||
<dd className="mt-1 truncate text-[14px] font-semibold text-foreground">{value}</dd>
|
<dd className="mt-1 truncate text-[14px] font-semibold text-foreground">{value}</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1112,7 +1112,7 @@ function CliRunRow({ run, active, app }: { run: CliRunSummary; active: boolean;
|
|||||||
<span
|
<span
|
||||||
data-testid={`activity-cli-logo-${run.name.toLowerCase()}`}
|
data-testid={`activity-cli-logo-${run.name.toLowerCase()}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px] border text-[6.5px] font-semibold text-white",
|
"grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-mark border text-[6.5px] font-semibold text-white",
|
||||||
rowActive && "animate-pulse",
|
rowActive && "animate-pulse",
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
@@ -1190,7 +1190,7 @@ function McpRunRow({ run, active, preset }: { run: McpRunSummary; active: boolea
|
|||||||
<span
|
<span
|
||||||
data-testid={`activity-mcp-logo-${run.presetName.toLowerCase()}`}
|
data-testid={`activity-mcp-logo-${run.presetName.toLowerCase()}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px] border text-[6.5px] font-semibold text-white",
|
"grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-mark border text-[6.5px] font-semibold text-white",
|
||||||
rowActive && "animate-pulse",
|
rowActive && "animate-pulse",
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ export function PromptRail({
|
|||||||
aria-hidden
|
aria-hidden
|
||||||
data-testid={previewVisible ? "prompt-rail-preview" : undefined}
|
data-testid={previewVisible ? "prompt-rail-preview" : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none absolute left-10 z-30 w-[34rem] max-w-[calc(100vw-4rem)] -translate-y-1/2 rounded-[20px] px-4 py-3 text-left",
|
"pointer-events-none absolute left-10 z-30 w-[34rem] max-w-[calc(100vw-4rem)] -translate-y-1/2 rounded-panel px-4 py-3 text-left",
|
||||||
floatingSurfaceElevationClassName,
|
floatingSurfaceElevationClassName,
|
||||||
"transition-[opacity,transform] duration-150",
|
"transition-[opacity,transform] duration-150",
|
||||||
previewVisible
|
previewVisible
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ export function SessionInfoPopover({ sessionKey, token, title }: SessionInfoPopo
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { jobs, loading, loadFailed, now } = useSessionAutomationJobs(open, token, sessionKey);
|
const { jobs, loading, loadFailed, now } = useSessionAutomationJobs(open, token, sessionKey);
|
||||||
const automationContent = loading ? (
|
const automationContent = loading ? (
|
||||||
<div className="flex items-center gap-2 rounded-[16px] bg-muted/45 px-3 py-3 text-[12.5px] text-muted-foreground">
|
<div className="flex items-center gap-2 rounded-floating bg-muted/45 px-3 py-3 text-[12.5px] text-muted-foreground">
|
||||||
<RefreshCcw className="h-3.5 w-3.5 animate-spin" />
|
<RefreshCcw className="h-3.5 w-3.5 animate-spin" />
|
||||||
{t("thread.sessionInfo.loading")}
|
{t("thread.sessionInfo.loading")}
|
||||||
</div>
|
</div>
|
||||||
) : loadFailed ? (
|
) : loadFailed ? (
|
||||||
<div className="flex items-center gap-2 rounded-[16px] bg-destructive/10 px-3 py-3 text-[12.5px] text-destructive">
|
<div className="flex items-center gap-2 rounded-floating bg-destructive/10 px-3 py-3 text-[12.5px] text-destructive">
|
||||||
<CircleAlert className="h-3.5 w-3.5" />
|
<CircleAlert className="h-3.5 w-3.5" />
|
||||||
{t("thread.sessionInfo.loadFailed")}
|
{t("thread.sessionInfo.loadFailed")}
|
||||||
</div>
|
</div>
|
||||||
@@ -57,7 +57,7 @@ export function SessionInfoPopover({ sessionKey, token, title }: SessionInfoPopo
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-[16px] bg-muted/35 px-3 py-3 text-[12.5px] leading-relaxed text-muted-foreground">
|
<div className="rounded-floating bg-muted/35 px-3 py-3 text-[12.5px] leading-relaxed text-muted-foreground">
|
||||||
{t("thread.sessionInfo.empty")}
|
{t("thread.sessionInfo.empty")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -124,7 +124,7 @@ function AutomationRow({ job, now }: { job: SessionAutomationJob; now: number })
|
|||||||
: "bg-muted-foreground/35";
|
: "bg-muted-foreground/35";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-[16px] px-3 py-2.5 transition-colors hover:bg-muted/40">
|
<div className="rounded-floating px-3 py-2.5 transition-colors hover:bg-muted/40">
|
||||||
<div className="flex items-start gap-2.5">
|
<div className="flex items-start gap-2.5">
|
||||||
<span className={cn("mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full", statusClass)} />
|
<span className={cn("mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full", statusClass)} />
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
|
|||||||
@@ -2246,8 +2246,8 @@ export function ThreadComposer({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"thread-composer-surface group/composer relative mx-auto flex w-full flex-col overflow-visible transition-all duration-200",
|
"thread-composer-surface group/composer relative mx-auto flex w-full flex-col overflow-visible transition-all duration-200",
|
||||||
isHero
|
isHero
|
||||||
? "max-w-[58rem] rounded-[28px] bg-muted/30 focus-within:bg-muted/50 dark:bg-card dark:focus-within:bg-white/[0.06]"
|
? "max-w-[58rem] rounded-prominent bg-muted/30 focus-within:bg-muted/50 dark:bg-card dark:focus-within:bg-white/[0.06]"
|
||||||
: "max-w-[49.5rem] rounded-[22px] bg-muted/30 focus-within:bg-muted/50 dark:bg-card dark:focus-within:bg-white/[0.06]",
|
: "max-w-[49.5rem] rounded-panel bg-muted/30 focus-within:bg-muted/50 dark:bg-card dark:focus-within:bg-white/[0.06]",
|
||||||
interactionDisabled && "opacity-60",
|
interactionDisabled && "opacity-60",
|
||||||
sessionDragPreview && "ring-1 ring-primary/25",
|
sessionDragPreview && "ring-1 ring-primary/25",
|
||||||
isDragging && "ring-2 ring-primary/40 motion-reduce:ring-0 motion-reduce:border-primary",
|
isDragging && "ring-2 ring-primary/40 motion-reduce:ring-0 motion-reduce:border-primary",
|
||||||
@@ -2610,7 +2610,7 @@ function QueuedPromptStack({
|
|||||||
role="group"
|
role="group"
|
||||||
data-state="enter"
|
data-state="enter"
|
||||||
className={cn(
|
className={cn(
|
||||||
"composer-status-strip relative z-20 mx-3 mt-3 overflow-hidden rounded-[18px]",
|
"composer-status-strip relative z-20 mx-3 mt-3 overflow-hidden rounded-floating",
|
||||||
"border border-black/[0.05] bg-popover/90 p-1.5",
|
"border border-black/[0.05] bg-popover/90 p-1.5",
|
||||||
"shadow-[0_10px_28px_rgba(15,23,42,0.07)] backdrop-blur-md",
|
"shadow-[0_10px_28px_rgba(15,23,42,0.07)] backdrop-blur-md",
|
||||||
"dark:border-white/[0.08] dark:bg-popover/90 dark:shadow-[0_14px_34px_rgba(0,0,0,0.30)]",
|
"dark:border-white/[0.08] dark:bg-popover/90 dark:shadow-[0_14px_34px_rgba(0,0,0,0.30)]",
|
||||||
@@ -2688,7 +2688,7 @@ function QueuedPromptRow({
|
|||||||
}}
|
}}
|
||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
className={cn(
|
className={cn(
|
||||||
"queued-prompt-row group/queued flex min-h-8 items-center gap-1.5 rounded-[12px] px-2 py-0.5",
|
"queued-prompt-row group/queued flex min-h-8 items-center gap-1.5 rounded-control px-2 py-0.5",
|
||||||
"text-[13px] transition-colors hover:bg-muted/55 dark:hover:bg-white/[0.055]",
|
"text-[13px] transition-colors hover:bg-muted/55 dark:hover:bg-white/[0.055]",
|
||||||
isHero && "text-[13.5px]",
|
isHero && "text-[13.5px]",
|
||||||
)}
|
)}
|
||||||
@@ -2973,7 +2973,7 @@ function MentionCandidateLogo({
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded-[5px]",
|
"flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded-compact",
|
||||||
selected ? "bg-background/55" : "bg-transparent",
|
selected ? "bg-background/55" : "bg-transparent",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -2991,7 +2991,7 @@ function MentionCandidateLogo({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-[5px] text-[7.5px] font-semibold text-white"
|
className="flex h-5 w-5 shrink-0 items-center justify-center rounded-compact text-[7.5px] font-semibold text-white"
|
||||||
style={{ backgroundColor: color }}
|
style={{ backgroundColor: color }}
|
||||||
>
|
>
|
||||||
{candidate.initials}
|
{candidate.initials}
|
||||||
@@ -3135,7 +3135,7 @@ function AttachmentChip({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"group relative flex items-center gap-2 rounded-[12px] border px-2 py-1.5",
|
"group relative flex items-center gap-2 rounded-control border px-2 py-1.5",
|
||||||
"transition-colors motion-reduce:transition-none",
|
"transition-colors motion-reduce:transition-none",
|
||||||
tone,
|
tone,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ export function WorkspaceProjectPicker({
|
|||||||
"flex min-h-[48px] w-full cursor-default gap-3 px-3 py-2.5 focus:bg-muted/55",
|
"flex min-h-[48px] w-full cursor-default gap-3 px-3 py-2.5 focus:bg-muted/55",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="grid h-8 w-8 shrink-0 place-items-center rounded-[12px] bg-muted text-foreground/80">
|
<span className="grid h-8 w-8 shrink-0 place-items-center rounded-control bg-muted text-foreground/80">
|
||||||
<Folder className="h-4 w-4" />
|
<Folder className="h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
<span className="min-w-0 flex-1">
|
<span className="min-w-0 flex-1">
|
||||||
@@ -328,7 +328,7 @@ export function WorkspaceAccessMenu({
|
|||||||
aria-label={accessAriaLabel}
|
aria-label={accessAriaLabel}
|
||||||
title={accessLabel}
|
title={accessLabel}
|
||||||
className={cn(
|
className={cn(
|
||||||
"thread-composer-access touch-target min-w-0 max-w-[min(12.5rem,42vw)] whitespace-nowrap rounded-[10px] border border-transparent font-semibold shadow-none",
|
"thread-composer-access touch-target min-w-0 max-w-[min(12.5rem,42vw)] whitespace-nowrap rounded-control border border-transparent font-semibold shadow-none",
|
||||||
isHero ? "h-8 px-2.5 text-[12px]" : "h-9 px-3 text-[12.5px]",
|
isHero ? "h-8 px-2.5 text-[12px]" : "h-9 px-3 text-[12.5px]",
|
||||||
isFull
|
isFull
|
||||||
? "bg-transparent text-orange-600 hover:bg-orange-500/8 dark:text-orange-300 dark:hover:bg-orange-400/10"
|
? "bg-transparent text-orange-600 hover:bg-orange-500/8 dark:text-orange-300 dark:hover:bg-orange-400/10"
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ function WebFavicon({ host, active }: { host: string; active: boolean }) {
|
|||||||
<img
|
<img
|
||||||
src={logoUrl}
|
src={logoUrl}
|
||||||
alt=""
|
alt=""
|
||||||
className={`h-4 w-4 shrink-0 rounded-[3px] object-contain${active ? " animate-pulse" : ""}`}
|
className={`h-4 w-4 shrink-0 rounded-mark object-contain${active ? " animate-pulse" : ""}`}
|
||||||
decoding="async"
|
decoding="async"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer"
|
referrerPolicy="no-referrer"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const AlertDialogContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
modalSurfaceClassName,
|
modalSurfaceClassName,
|
||||||
"grid w-full max-w-lg origin-center gap-4 rounded-[22px] p-6 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
"grid w-full max-w-lg origin-center gap-4 rounded-modal p-6 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -64,7 +64,7 @@ const AlertDialogFooter = ({
|
|||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-control text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
@@ -21,8 +21,8 @@ const buttonVariants = cva(
|
|||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-4 py-2",
|
default: "h-10 px-4 py-2",
|
||||||
sm: "h-9 rounded-md px-3",
|
sm: "h-9 px-3",
|
||||||
lg: "h-11 rounded-md px-8",
|
lg: "h-11 px-8",
|
||||||
icon: "h-9 w-9",
|
icon: "h-9 w-9",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const DialogContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
modalSurfaceClassName,
|
modalSurfaceClassName,
|
||||||
"grid w-full max-w-lg origin-center gap-4 rounded-[22px] p-6 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
"grid w-full max-w-lg origin-center gap-4 rounded-modal p-6 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -84,7 +84,7 @@ const DialogFooter = ({
|
|||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export const floatingSurfaceElevationClassName =
|
|||||||
"bg-popover text-popover-foreground shadow-[0_8px_24px_rgba(15,23,42,0.10)] dark:shadow-[0_12px_28px_rgba(0,0,0,0.32)]";
|
"bg-popover text-popover-foreground shadow-[0_8px_24px_rgba(15,23,42,0.10)] dark:shadow-[0_12px_28px_rgba(0,0,0,0.32)]";
|
||||||
|
|
||||||
export const floatingSurfaceVisualClassName =
|
export const floatingSurfaceVisualClassName =
|
||||||
`rounded-[18px] p-1.5 ${floatingSurfaceElevationClassName}`;
|
`rounded-floating p-1.5 ${floatingSurfaceElevationClassName}`;
|
||||||
|
|
||||||
export const modalOverlayClassName =
|
export const modalOverlayClassName =
|
||||||
"fixed inset-0 z-50 bg-black/45 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
"fixed inset-0 z-50 bg-black/45 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
||||||
@@ -17,7 +17,7 @@ export const floatingSurfaceMotionClassName =
|
|||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0";
|
||||||
|
|
||||||
export const floatingItemClassName =
|
export const floatingItemClassName =
|
||||||
"relative flex min-h-8 select-none items-center gap-2 rounded-[12px] px-2.5 py-2 text-[13px] outline-none transition-colors [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0";
|
"relative flex min-h-8 select-none items-center gap-2 rounded-control px-2.5 py-2 text-[13px] outline-none transition-colors [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0";
|
||||||
|
|
||||||
export const floatingItemFocusClassName =
|
export const floatingItemFocusClassName =
|
||||||
"focus:bg-foreground/[0.055] focus:text-foreground dark:focus:bg-white/[0.08]";
|
"focus:bg-foreground/[0.055] focus:text-foreground dark:focus:bg-white/[0.08]";
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-10 w-full rounded-control border border-input bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
formControlFocusClassName,
|
formControlFocusClassName,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
"flex min-h-[60px] w-full rounded-control border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
formControlFocusClassName,
|
formControlFocusClassName,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const TooltipContent = React.forwardRef<
|
|||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
floatingSurfaceElevationClassName,
|
floatingSurfaceElevationClassName,
|
||||||
"z-50 overflow-hidden rounded-[10px] px-3 py-1.5 text-xs animate-in fade-in-0 zoom-in-95",
|
"z-50 overflow-hidden rounded-control px-3 py-1.5 text-xs animate-in fade-in-0 zoom-in-95",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
+11
-2
@@ -38,6 +38,15 @@
|
|||||||
--temporary-foreground: 17 88% 32%;
|
--temporary-foreground: 17 88% 32%;
|
||||||
--temporary-border: 17 88% 40%;
|
--temporary-border: 17 88% 40%;
|
||||||
--radius: 0.4375rem;
|
--radius: 0.4375rem;
|
||||||
|
/* Shared shape scale: marks, compact content, controls, and progressively larger surfaces. */
|
||||||
|
--radius-mark: 0.25rem;
|
||||||
|
--radius-compact: 0.5rem;
|
||||||
|
--radius-control: 0.75rem;
|
||||||
|
--radius-floating: 1.125rem;
|
||||||
|
--radius-panel: 1.375rem;
|
||||||
|
--radius-modal: 1.375rem;
|
||||||
|
--radius-prominent: 1.75rem;
|
||||||
|
--radius-pill: 9999px;
|
||||||
--sidebar: 40 8% 96.8%;
|
--sidebar: 40 8% 96.8%;
|
||||||
--sidebar-foreground: 0 0% 3.9%;
|
--sidebar-foreground: 0 0% 3.9%;
|
||||||
--sidebar-selected: 40 1% 89.4%;
|
--sidebar-selected: 40 1% 89.4%;
|
||||||
@@ -121,7 +130,7 @@
|
|||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: var(--scrollbar-thumb);
|
background-color: var(--scrollbar-thumb);
|
||||||
border-radius: 9999px;
|
border-radius: var(--radius-pill);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb:hover {
|
*::-webkit-scrollbar-thumb:hover {
|
||||||
@@ -567,7 +576,7 @@
|
|||||||
}
|
}
|
||||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
background-color: hsl(var(--muted-foreground) / 0.4);
|
background-color: hsl(var(--muted-foreground) / 0.4);
|
||||||
border-radius: 9999px;
|
border-radius: var(--radius-pill);
|
||||||
}
|
}
|
||||||
.scrollbar-track-transparent {
|
.scrollbar-track-transparent {
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ describe("ChatList", () => {
|
|||||||
expect(tabSurface).toContainElement(paneList);
|
expect(tabSurface).toContainElement(paneList);
|
||||||
const activePane = within(tabGroup).getByRole("button", { name: "Research pane" });
|
const activePane = within(tabGroup).getByRole("button", { name: "Research pane" });
|
||||||
expect(activePane).toHaveAttribute("aria-current", "true");
|
expect(activePane).toHaveAttribute("aria-current", "true");
|
||||||
expect(activePane.closest("[data-sidebar-pane]")).toHaveClass("rounded-[0.65rem]");
|
expect(activePane.closest("[data-sidebar-pane]")).toHaveClass("rounded-control");
|
||||||
expect(activePane.querySelector("[data-sidebar-selection-track]"))
|
expect(activePane.querySelector("[data-sidebar-selection-track]"))
|
||||||
.toHaveAttribute("data-active", "true");
|
.toHaveAttribute("data-active", "true");
|
||||||
expect(screen.getByRole("button", {
|
expect(screen.getByRole("button", {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ describe("CodeBlock", () => {
|
|||||||
expect(screen.getByTestId("plain-code-fallback")).toHaveClass("py-4", "pl-5", "pr-14");
|
expect(screen.getByTestId("plain-code-fallback")).toHaveClass("py-4", "pl-5", "pr-14");
|
||||||
|
|
||||||
const container = screen.getByTestId("plain-code-fallback").closest(".not-prose");
|
const container = screen.getByTestId("plain-code-fallback").closest(".not-prose");
|
||||||
expect(container).toHaveClass("relative", "rounded-[18px]", "bg-secondary/70");
|
expect(container).toHaveClass("relative", "rounded-floating", "bg-secondary/70");
|
||||||
expect(container).not.toHaveClass("border");
|
expect(container).not.toHaveClass("border");
|
||||||
expect(container).toHaveAttribute("data-language", "ts");
|
expect(container).toHaveAttribute("data-language", "ts");
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ describe("MessageBubble", () => {
|
|||||||
const pill = screen.getByText("hello");
|
const pill = screen.getByText("hello");
|
||||||
|
|
||||||
expect(row).toHaveClass("ml-auto", "flex");
|
expect(row).toHaveClass("ml-auto", "flex");
|
||||||
expect(pill).toHaveClass("ml-auto", "w-fit", "rounded-[18px]");
|
expect(pill).toHaveClass("ml-auto", "w-fit", "rounded-floating");
|
||||||
expect(screen.getByRole("button", { name: "Copy" })).toBeInTheDocument();
|
expect(screen.getByRole("button", { name: "Copy" })).toBeInTheDocument();
|
||||||
expect(screen.queryByRole("button", { name: "Fork" })).not.toBeInTheDocument();
|
expect(screen.queryByRole("button", { name: "Fork" })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -286,7 +286,7 @@ describe("MessageBubble", () => {
|
|||||||
expect(command.getAttribute("style")).toContain("var(--inline-token-highlight)");
|
expect(command.getAttribute("style")).toContain("var(--inline-token-highlight)");
|
||||||
expect(command.className).not.toMatch(/(?:^|\s)(?:bg-|border|ring|rounded)/);
|
expect(command.className).not.toMatch(/(?:^|\s)(?:bg-|border|ring|rounded)/);
|
||||||
expect(command.parentElement).toHaveTextContent("/model gpt-5");
|
expect(command.parentElement).toHaveTextContent("/model gpt-5");
|
||||||
expect(command.parentElement).toHaveClass("rounded-[18px]", "bg-secondary/70");
|
expect(command.parentElement).toHaveClass("rounded-floating", "bg-secondary/70");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps unknown and invalid slash commands as plain message text", () => {
|
it("keeps unknown and invalid slash commands as plain message text", () => {
|
||||||
@@ -934,7 +934,7 @@ describe("MessageBubble", () => {
|
|||||||
const { container } = render(<MessageBubble message={message} />);
|
const { container } = render(<MessageBubble message={message} />);
|
||||||
|
|
||||||
const imageButton = screen.getByRole("button", { name: /view image/i });
|
const imageButton = screen.getByRole("button", { name: /view image/i });
|
||||||
expect(imageButton).toHaveClass("w-[min(100%,34rem)]", "rounded-[20px]");
|
expect(imageButton).toHaveClass("w-[min(100%,34rem)]", "rounded-panel");
|
||||||
expect(imageButton).toHaveClass(
|
expect(imageButton).toHaveClass(
|
||||||
"border",
|
"border",
|
||||||
"border-border/60",
|
"border-border/60",
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ describe("Settings models", () => {
|
|||||||
expect(editor).toHaveClass(
|
expect(editor).toHaveClass(
|
||||||
"slide-in-from-top-1",
|
"slide-in-from-top-1",
|
||||||
"lg:max-w-6xl",
|
"lg:max-w-6xl",
|
||||||
"rounded-[18px]",
|
"rounded-floating",
|
||||||
);
|
);
|
||||||
expect(within(editor).getByDisplayValue("Primary")).toBeInTheDocument();
|
expect(within(editor).getByDisplayValue("Primary")).toBeInTheDocument();
|
||||||
const deleteButton = within(editor).getByRole("button", { name: "Delete" });
|
const deleteButton = within(editor).getByRole("button", { name: "Delete" });
|
||||||
|
|||||||
@@ -554,7 +554,7 @@ describe("ThreadComposer", () => {
|
|||||||
expect(input.className).toContain("min-h-[50px]");
|
expect(input.className).toContain("min-h-[50px]");
|
||||||
expect(input.className).toContain("text-[16px]");
|
expect(input.className).toContain("text-[16px]");
|
||||||
expect(input.parentElement?.parentElement?.className).toContain("max-w-[49.5rem]");
|
expect(input.parentElement?.parentElement?.className).toContain("max-w-[49.5rem]");
|
||||||
expect(input.parentElement?.parentElement?.className).toContain("rounded-[22px]");
|
expect(input.parentElement?.parentElement?.className).toContain("rounded-panel");
|
||||||
expect(input.parentElement?.parentElement?.className).not.toContain("shadow-");
|
expect(input.parentElement?.parentElement?.className).not.toContain("shadow-");
|
||||||
expect(screen.getByRole("button", { name: "Attach files" }).className).toContain("bg-card");
|
expect(screen.getByRole("button", { name: "Attach files" }).className).toContain("bg-card");
|
||||||
expect(screen.getByRole("button", { name: "Send message" }).className).toContain("bg-foreground");
|
expect(screen.getByRole("button", { name: "Send message" }).className).toContain("bg-foreground");
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from "@/components/ui/alert-dialog";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
|
||||||
|
describe("UI shape system", () => {
|
||||||
|
it("gives standard controls one shared radius", () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<Button>Continue</Button>
|
||||||
|
<Input aria-label="Name" />
|
||||||
|
<Textarea aria-label="Description" />
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByRole("button", { name: "Continue" })).toHaveClass("rounded-control");
|
||||||
|
expect(screen.getByRole("textbox", { name: "Name" })).toHaveClass("rounded-control");
|
||||||
|
expect(screen.getByRole("textbox", { name: "Description" })).toHaveClass(
|
||||||
|
"rounded-control",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gives dialogs and alert dialogs one shared modal radius", () => {
|
||||||
|
const dialog = render(
|
||||||
|
<Dialog open>
|
||||||
|
<DialogContent showCloseButton={false}>
|
||||||
|
<DialogTitle>Edit name</DialogTitle>
|
||||||
|
<DialogDescription>Choose a new name.</DialogDescription>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole("dialog", { name: "Edit name" })).toHaveClass("rounded-modal");
|
||||||
|
dialog.unmount();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<AlertDialog open>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogTitle>Delete item?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>This cannot be undone.</AlertDialogDescription>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole("alertdialog", { name: "Delete item?" })).toHaveClass(
|
||||||
|
"rounded-modal",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps floating surfaces and their items on the shared radius scale", () => {
|
||||||
|
render(
|
||||||
|
<DropdownMenu open>
|
||||||
|
<DropdownMenuTrigger>Open menu</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuItem>Rename</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByRole("menu")).toHaveClass("rounded-floating");
|
||||||
|
expect(screen.getByRole("menuitem", { name: "Rename" })).toHaveClass(
|
||||||
|
"rounded-control",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -51,6 +51,13 @@ export default {
|
|||||||
lg: "var(--radius)",
|
lg: "var(--radius)",
|
||||||
md: "calc(var(--radius) - 2px)",
|
md: "calc(var(--radius) - 2px)",
|
||||||
sm: "calc(var(--radius) - 4px)",
|
sm: "calc(var(--radius) - 4px)",
|
||||||
|
mark: "var(--radius-mark)",
|
||||||
|
compact: "var(--radius-compact)",
|
||||||
|
control: "var(--radius-control)",
|
||||||
|
floating: "var(--radius-floating)",
|
||||||
|
panel: "var(--radius-panel)",
|
||||||
|
modal: "var(--radius-modal)",
|
||||||
|
prominent: "var(--radius-prominent)",
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
background: "hsl(var(--background))",
|
background: "hsl(var(--background))",
|
||||||
|
|||||||
Reference in New Issue
Block a user