mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-17 01:26:40 +03:00
refactor(webui): unify shared shape system
This commit is contained in:
@@ -59,7 +59,7 @@ export function FeishuAssistantsPanel({
|
||||
/>
|
||||
),
|
||||
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">
|
||||
{tx("custom.createAnother", "Create another assistant")}
|
||||
</div>
|
||||
@@ -144,7 +144,7 @@ function FeishuInstanceAction({
|
||||
</Button>
|
||||
</div>
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -197,7 +197,7 @@ export function WeixinPanel({
|
||||
});
|
||||
|
||||
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 min-w-0 items-start gap-3">
|
||||
<WeixinLogo showBrandLogos={showBrandLogos} />
|
||||
@@ -251,7 +251,7 @@ export function WeixinPanel({
|
||||
</div>
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
@@ -304,7 +304,7 @@ export function WeixinPanel({
|
||||
{saveError ? (
|
||||
<div
|
||||
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}
|
||||
</div>
|
||||
@@ -413,7 +413,7 @@ function WeixinLogo({ showBrandLogos }: { showBrandLogos: boolean }) {
|
||||
const { logoUrl, onLogoError, onLogoLoad } = useLogoFallback(logoUrls);
|
||||
if (showBrandLogos && logoUrl) {
|
||||
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
|
||||
src={logoUrl}
|
||||
alt=""
|
||||
@@ -428,7 +428,7 @@ function WeixinLogo({ showBrandLogos }: { showBrandLogos: boolean }) {
|
||||
}
|
||||
return (
|
||||
<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" }}
|
||||
aria-hidden
|
||||
>
|
||||
|
||||
+1
-1
@@ -563,7 +563,7 @@ function PairingCodePopup({
|
||||
aria-label={t("app.pairing.title", { defaultValue: "Pair a chat user" })}
|
||||
className={cn(
|
||||
"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,
|
||||
"p-4",
|
||||
"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}
|
||||
aria-label={label}
|
||||
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",
|
||||
"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]",
|
||||
@@ -109,7 +109,7 @@ export function AttachmentTile({ attachment, className, inline = false, variant
|
||||
return (
|
||||
<div
|
||||
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",
|
||||
variant === "compact" && "max-w-[14rem] rounded-xl px-2.5 py-1.5 text-[11.5px]",
|
||||
className,
|
||||
@@ -139,7 +139,7 @@ function AttachmentFrame({
|
||||
variant?: "default" | "compact";
|
||||
}) {
|
||||
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",
|
||||
attachment.kind === "image" && "bg-background/85",
|
||||
attachment.kind === "video" ? "w-[min(100%,32rem)]" : "",
|
||||
|
||||
@@ -807,7 +807,7 @@ export const ChatList = memo(function ChatList({
|
||||
actionMenus.openFromContextMenu(event, actionMenuId)
|
||||
)}
|
||||
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,
|
||||
compact ? "min-h-7" : "min-h-8",
|
||||
topicActive
|
||||
@@ -1081,7 +1081,7 @@ function WorkbenchTabHeader({
|
||||
data-workbench-tab
|
||||
onContextMenu={(event) => actionMenus.openFromContextMenu(event, actionMenuId)}
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -1281,7 +1281,7 @@ function ActivePaneRows({
|
||||
actionMenus.openFromContextMenu(event, actionMenuId)
|
||||
)}
|
||||
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,
|
||||
compact ? "min-h-7" : "min-h-8",
|
||||
active
|
||||
|
||||
@@ -203,7 +203,7 @@ export function CliAppMentionToken({
|
||||
<span
|
||||
data-testid={`${testIdPrefix}-cli-mention-logo-${app.name}`}
|
||||
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",
|
||||
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
||||
)}
|
||||
@@ -260,7 +260,7 @@ export function McpPresetMentionToken({
|
||||
<span
|
||||
data-testid={`${testIdPrefix}-mcp-mention-logo-${preset.name}`}
|
||||
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",
|
||||
isHero ? "h-[0.74em] w-[0.74em]" : "h-[0.72em] w-[0.72em]",
|
||||
)}
|
||||
|
||||
@@ -202,7 +202,7 @@ export function CodeBlock({
|
||||
<div
|
||||
className={cn(
|
||||
"not-prose relative overflow-hidden",
|
||||
hasChrome && "rounded-[18px] bg-secondary/70",
|
||||
hasChrome && "rounded-floating bg-secondary/70",
|
||||
className,
|
||||
)}
|
||||
data-language={language || t("code.fallbackLanguage")}
|
||||
|
||||
@@ -96,16 +96,16 @@ export function DeleteConfirm({
|
||||
</div>
|
||||
) : null}
|
||||
</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
|
||||
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")}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
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
|
||||
? t("deleteConfirm.confirmWithAutomations")
|
||||
|
||||
@@ -183,7 +183,7 @@ export function FilePreviewPanel({
|
||||
) : null}
|
||||
<span
|
||||
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
|
||||
? "font-medium text-foreground"
|
||||
: "max-w-[26vw] shrink text-muted-foreground/78",
|
||||
|
||||
@@ -78,7 +78,7 @@ export function FileReferenceChip({
|
||||
"text-sky-600 transition-colors hover:text-sky-700",
|
||||
"dark:text-sky-300 dark:hover:text-sky-200",
|
||||
interactive && [
|
||||
"cursor-pointer rounded-[5px]",
|
||||
"cursor-pointer rounded-compact",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-400/45",
|
||||
],
|
||||
)}
|
||||
@@ -110,7 +110,7 @@ export function FileReferenceChip({
|
||||
sideOffset={8}
|
||||
collisionPadding={12}
|
||||
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",
|
||||
"break-all font-mono text-[11px] leading-snug text-popover-foreground",
|
||||
)}
|
||||
|
||||
@@ -120,7 +120,7 @@ export function ImageLightbox({
|
||||
alt={current.name ?? ""}
|
||||
decoding="async"
|
||||
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>
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
|
||||
>
|
||||
<span
|
||||
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",
|
||||
)}
|
||||
aria-hidden
|
||||
@@ -459,7 +459,7 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
|
||||
<img
|
||||
src={favicon}
|
||||
alt=""
|
||||
className="h-3 w-3 rounded-[2px] object-contain"
|
||||
className="h-3 w-3 rounded-mark object-contain"
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
referrerPolicy="no-referrer"
|
||||
@@ -745,7 +745,7 @@ export default function MarkdownTextRenderer({
|
||||
},
|
||||
mark({ children: markdownChildren }) {
|
||||
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}
|
||||
</mark>
|
||||
);
|
||||
|
||||
@@ -331,7 +331,7 @@ export function MessageBubble({
|
||||
<p
|
||||
data-temporary-message={temporary ? "true" : undefined}
|
||||
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]",
|
||||
temporary
|
||||
? "border border-dashed border-muted-foreground/40 bg-transparent"
|
||||
@@ -499,7 +499,7 @@ function UserQuotedContext({ text, label }: { text: string; label: string }) {
|
||||
return (
|
||||
<blockquote
|
||||
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",
|
||||
)}
|
||||
aria-label={label}
|
||||
@@ -718,8 +718,8 @@ function UserImageCell({
|
||||
const tileClasses = cn(
|
||||
"relative overflow-hidden border border-border/60 bg-muted/40",
|
||||
size === "large"
|
||||
? "w-[min(100%,34rem)] rounded-[20px] bg-transparent"
|
||||
: "h-24 w-24 rounded-[14px]",
|
||||
? "w-[min(100%,34rem)] rounded-panel bg-transparent"
|
||||
: "h-24 w-24 rounded-control",
|
||||
"shadow-[0_6px_18px_-14px_rgba(0,0,0,0.45)]",
|
||||
);
|
||||
|
||||
|
||||
@@ -44,41 +44,38 @@ export function RenameChatDialog({
|
||||
<Dialog open={open} onOpenChange={(next) => {
|
||||
if (!next) onCancel();
|
||||
}}>
|
||||
<DialogContent className="max-w-sm rounded-[20px] p-5 sm:p-6">
|
||||
<DialogContent className="max-w-sm">
|
||||
<form
|
||||
className="grid gap-5"
|
||||
className="grid gap-4"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!trimmed) return;
|
||||
onConfirm(trimmed);
|
||||
}}
|
||||
>
|
||||
<DialogHeader className="space-y-1 text-left">
|
||||
<DialogTitle className="text-xl leading-tight">
|
||||
{dialogTitle ?? t("chat.renameTitle")}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="leading-relaxed">
|
||||
<DialogHeader className="text-left">
|
||||
<DialogTitle>{dialogTitle ?? t("chat.renameTitle")}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{description ?? t("chat.renameDescription")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
className="h-11 rounded-xl border-border/80 bg-muted/20 px-3.5 text-[15px]"
|
||||
value={value}
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
placeholder={placeholder ?? t("chat.renamePlaceholder")}
|
||||
autoFocus
|
||||
maxLength={160}
|
||||
/>
|
||||
<DialogFooter className="gap-2 pt-1 sm:space-x-0">
|
||||
<DialogFooter>
|
||||
<Button
|
||||
className="min-w-20 rounded-xl"
|
||||
className="min-w-20"
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("deleteConfirm.cancel")}
|
||||
</Button>
|
||||
<Button className="min-w-20 rounded-xl" type="submit" disabled={!trimmed}>
|
||||
<Button className="min-w-20" type="submit" disabled={!trimmed}>
|
||||
{t("chat.renameSave")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
@@ -120,7 +120,6 @@ export function SessionSearchDialog({
|
||||
showCloseButton={false}
|
||||
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",
|
||||
"rounded-[22px]",
|
||||
)}
|
||||
>
|
||||
<DialogTitle className="sr-only">{t("sidebar.searchAria")}</DialogTitle>
|
||||
@@ -183,7 +182,7 @@ export function SessionSearchDialog({
|
||||
onMouseEnter={() => setHighlightedIndex(index)}
|
||||
aria-current={active ? "page" : undefined}
|
||||
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
|
||||
? "bg-muted text-foreground"
|
||||
: "text-foreground hover:bg-muted",
|
||||
|
||||
@@ -621,7 +621,7 @@ export function SettingsPage({
|
||||
) : null}
|
||||
|
||||
{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" />
|
||||
{t("settings.status.loading")}
|
||||
</div>
|
||||
@@ -640,7 +640,7 @@ export function SettingsPage({
|
||||
)}
|
||||
>
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -102,7 +102,7 @@ export function SettingsSidebar({
|
||||
<button
|
||||
type="button"
|
||||
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 />
|
||||
<span className="min-w-0 flex-1 truncate">{activeLabel}</span>
|
||||
@@ -176,7 +176,7 @@ export function SettingsSidebar({
|
||||
type="button"
|
||||
variant="ghost"
|
||||
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 />
|
||||
{t("app.account.logout")}
|
||||
|
||||
@@ -98,7 +98,7 @@ export function SkillsCatalogSettings({ skills }: { skills: SkillSummary[] }) {
|
||||
/>
|
||||
|
||||
{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="relative w-full sm:max-w-[320px]">
|
||||
<Search
|
||||
@@ -114,7 +114,7 @@ export function SkillsCatalogSettings({ skills }: { skills: SkillSummary[] }) {
|
||||
aria-label={t("settings.skills.searchInstalled", {
|
||||
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>
|
||||
<SegmentedControl
|
||||
@@ -220,7 +220,7 @@ function SkillCatalogRow({
|
||||
})}
|
||||
onClick={() => onSelect(skill)}
|
||||
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",
|
||||
"hover:bg-muted/70",
|
||||
"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..." })}
|
||||
</div>
|
||||
) : 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." })}
|
||||
</div>
|
||||
) : (
|
||||
@@ -484,7 +484,7 @@ function SkillDetailSheet({
|
||||
</div>
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
@@ -533,7 +533,7 @@ function SkillDetailSheet({
|
||||
</Sheet>
|
||||
|
||||
<AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>
|
||||
<AlertDialogContent className="rounded-[20px]">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{t("settings.skills.deleteConfirmTitle", {
|
||||
@@ -574,7 +574,7 @@ function RawInstructionsBlock({ markdown }: { markdown: string }) {
|
||||
});
|
||||
|
||||
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">
|
||||
<span>
|
||||
{t("settings.skills.instructionsTitle", { defaultValue: "Skill instructions" })}
|
||||
@@ -583,7 +583,7 @@ function RawInstructionsBlock({ markdown }: { markdown: string }) {
|
||||
SKILL.md
|
||||
</code>
|
||||
</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
|
||||
className={cn(
|
||||
"max-h-[min(42vh,32rem)] overflow-auto overscroll-contain px-3.5 py-3 pr-4",
|
||||
@@ -625,7 +625,7 @@ function RequirementsSection({
|
||||
};
|
||||
|
||||
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">
|
||||
<CircleAlert
|
||||
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) => (
|
||||
<div
|
||||
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 />
|
||||
<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}
|
||||
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 ? (
|
||||
<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", {
|
||||
defaultValue: "Search skills",
|
||||
})}
|
||||
className="h-11 rounded-[14px] bg-settings-surface pl-9"
|
||||
className="h-11 rounded-control bg-settings-surface pl-9"
|
||||
/>
|
||||
{loading ? (
|
||||
<span
|
||||
@@ -226,13 +226,13 @@ export function SkillsMarketplace({
|
||||
</div>
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{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">
|
||||
<h2 className="text-[14px] font-semibold">
|
||||
{t("settings.skills.marketplaceTrendingTitle", {
|
||||
@@ -271,14 +271,14 @@ export function SkillsMarketplace({
|
||||
)}
|
||||
</section>
|
||||
) : !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", {
|
||||
query: query.trim(),
|
||||
defaultValue: "No skills found for “{{query}}”.",
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="overflow-hidden rounded-[22px] bg-settings-surface">
|
||||
<div className="overflow-hidden rounded-panel bg-settings-surface">
|
||||
<MarketplaceSkillGroups
|
||||
skills={visibleResults}
|
||||
installedNames={installedNames}
|
||||
@@ -296,9 +296,9 @@ export function SkillsMarketplace({
|
||||
if (!open) setSelected(null);
|
||||
}}
|
||||
>
|
||||
<AlertDialogContent className="rounded-[20px]">
|
||||
<AlertDialogContent>
|
||||
<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 />
|
||||
</div>
|
||||
<AlertDialogTitle>
|
||||
@@ -316,7 +316,7 @@ export function SkillsMarketplace({
|
||||
"This third-party skill comes from {{provider}} ({{source}}) and may include instructions or executable scripts.",
|
||||
})}
|
||||
</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}
|
||||
<code>{selected?.source}</code>
|
||||
{selected?.version ? <span>v{selected.version}</span> : null}
|
||||
|
||||
@@ -224,7 +224,7 @@ export function TokenUsageHeatmap({
|
||||
<span
|
||||
aria-label={ariaLabel}
|
||||
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),
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -136,7 +136,7 @@ export function ChannelLogo({
|
||||
if (showBrandLogos && logoUrl) {
|
||||
return (
|
||||
<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
|
||||
src={logoUrl}
|
||||
@@ -154,7 +154,7 @@ export function ChannelLogo({
|
||||
if (Icon) {
|
||||
return (
|
||||
<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 }}
|
||||
aria-hidden
|
||||
>
|
||||
@@ -165,7 +165,7 @@ export function ChannelLogo({
|
||||
|
||||
return (
|
||||
<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 }}
|
||||
aria-hidden
|
||||
>
|
||||
@@ -275,7 +275,7 @@ export function ChannelRuntimeError({
|
||||
}) {
|
||||
if (!message) return null;
|
||||
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}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -144,7 +144,7 @@ export function ChannelInstancesPanel({
|
||||
};
|
||||
|
||||
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 min-w-0 items-start gap-3">
|
||||
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
||||
@@ -177,7 +177,7 @@ export function ChannelInstancesPanel({
|
||||
<article
|
||||
key={instance.id}
|
||||
className={cn(
|
||||
"overflow-hidden rounded-[18px] transition-colors",
|
||||
"overflow-hidden rounded-floating transition-colors",
|
||||
expanded
|
||||
? "bg-background"
|
||||
: "bg-background/70 hover:bg-muted",
|
||||
@@ -313,7 +313,7 @@ export function ChannelInstancesPanel({
|
||||
{customization.footer}
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -251,8 +251,8 @@ export function ChannelQrConnectFlow({
|
||||
return (
|
||||
<div className="mt-3 space-y-3">
|
||||
{pending ? (
|
||||
<div className="grid gap-4 rounded-[14px] 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 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-control border border-border/60 bg-background">
|
||||
{qrDataUrl ? (
|
||||
<img
|
||||
src={qrDataUrl}
|
||||
@@ -293,20 +293,20 @@ export function ChannelQrConnectFlow({
|
||||
) : null}
|
||||
|
||||
{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 />
|
||||
{displayMessage ?? labels.connected}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -87,7 +87,7 @@ export function ChannelCatalogRow({
|
||||
aria-pressed={selected}
|
||||
onClick={onSelect}
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -187,7 +187,7 @@ export function ChannelSetupPanel({
|
||||
});
|
||||
|
||||
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 min-w-0 items-start gap-3">
|
||||
<ChannelLogo feature={feature} showBrandLogos={showBrandLogos} />
|
||||
@@ -482,7 +482,7 @@ function ChannelSetupSurface({
|
||||
) : null}
|
||||
</div>
|
||||
{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}
|
||||
</code>
|
||||
) : null}
|
||||
@@ -538,7 +538,7 @@ function ChannelSetupSurface({
|
||||
{notice ? (
|
||||
<div
|
||||
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}
|
||||
</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",
|
||||
compact
|
||||
? "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
|
||||
className={cn(
|
||||
"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 }}
|
||||
aria-hidden
|
||||
@@ -231,7 +231,7 @@ export function ChannelProviderPresets({
|
||||
<div
|
||||
role="radiogroup"
|
||||
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))` }}
|
||||
>
|
||||
{presets.map((preset) => (
|
||||
@@ -245,7 +245,7 @@ export function ChannelProviderPresets({
|
||||
onApply(preset);
|
||||
}}
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -370,7 +370,7 @@ export function ChannelSetupSteps({
|
||||
))}
|
||||
</ol>
|
||||
{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">
|
||||
{tx("settings.channels.tryIt", "Try it")}
|
||||
</span>
|
||||
|
||||
@@ -159,7 +159,7 @@ export function CredentialForm({
|
||||
<span
|
||||
role="radiogroup"
|
||||
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))` }}
|
||||
>
|
||||
{field.options.map((option) => (
|
||||
@@ -170,7 +170,7 @@ export function CredentialForm({
|
||||
aria-checked={selectedOption === option.value}
|
||||
onClick={() => onChange(field.key, option.value)}
|
||||
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
|
||||
&& "bg-background text-foreground ring-1 ring-inset ring-border/45",
|
||||
)}
|
||||
@@ -200,7 +200,7 @@ export function CredentialForm({
|
||||
value={values[field.key] ?? ""}
|
||||
onChange={(event) => onChange(field.key, event.target.value)}
|
||||
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",
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -117,7 +117,7 @@ export function ModelPresetDeleteDialog({
|
||||
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
||||
return (
|
||||
<Dialog open={preset !== null} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[440px] rounded-[24px]">
|
||||
<DialogContent className="max-w-[440px]">
|
||||
<DialogHeader className="text-left">
|
||||
<DialogTitle>
|
||||
{tx("settings.models.deletePresetTitle", "Delete model preset?")}
|
||||
@@ -130,11 +130,10 @@ export function ModelPresetDeleteDialog({
|
||||
)}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter className="gap-2 sm:space-x-0">
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
className="rounded-full"
|
||||
disabled={deleting}
|
||||
onClick={() => onOpenChange(false)}
|
||||
>
|
||||
@@ -143,7 +142,6 @@ export function ModelPresetDeleteDialog({
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
className="rounded-full"
|
||||
disabled={deleting}
|
||||
onClick={onConfirm}
|
||||
>
|
||||
@@ -343,7 +341,7 @@ export function ModelsSettings({
|
||||
<div
|
||||
id="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 ? (
|
||||
<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 ? (
|
||||
<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">
|
||||
<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 />
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
@@ -674,7 +672,7 @@ export function ModelsSettings({
|
||||
aria-controls={isSelected ? "model-preset-editor" : undefined}
|
||||
disabled={!preset}
|
||||
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 ? (
|
||||
<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);
|
||||
if (Number.isFinite(value)) onChange({ maxTokens: value });
|
||||
}}
|
||||
className="h-9 rounded-[12px] text-[13px]"
|
||||
className="h-9 text-[13px]"
|
||||
/>
|
||||
</label>
|
||||
<label className="block">
|
||||
@@ -858,7 +856,7 @@ function ModelAdvancedFields({
|
||||
const value = Number(event.target.value);
|
||||
if (Number.isFinite(value)) onChange({ temperature: value });
|
||||
}}
|
||||
className="h-9 rounded-[12px] text-[13px]"
|
||||
className="h-9 text-[13px]"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
@@ -887,7 +885,7 @@ function ModelAdvancedFields({
|
||||
placeholder={tx("settings.values.default", "Default")}
|
||||
autoCapitalize="none"
|
||||
spellCheck={false}
|
||||
className="h-9 rounded-[12px] text-[13px]"
|
||||
className="h-9 text-[13px]"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -276,7 +276,7 @@ export function ProviderOAuthLoginDialog({
|
||||
if (!open) onClose();
|
||||
}}
|
||||
>
|
||||
<DialogContent className="w-[min(calc(100vw-2rem),28rem)] rounded-[24px]">
|
||||
<DialogContent className="w-[min(calc(100vw-2rem),28rem)]">
|
||||
<form
|
||||
className="space-y-4"
|
||||
onSubmit={(event) => {
|
||||
@@ -296,7 +296,7 @@ export function ProviderOAuthLoginDialog({
|
||||
: t("settings.oauth.localCodeHelp")}
|
||||
</DialogDescription>
|
||||
</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 ? (
|
||||
<Clipboard className="h-3.5 w-3.5 shrink-0" aria-hidden />
|
||||
) : (
|
||||
@@ -341,12 +341,12 @@ export function ProviderOAuthLoginDialog({
|
||||
{error ? (
|
||||
<p
|
||||
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}
|
||||
</p>
|
||||
) : null}
|
||||
<DialogFooter className="gap-2 sm:space-x-0">
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="outline" onClick={onOpenAuthorization}>
|
||||
<ExternalLink className="mr-2 h-4 w-4" aria-hidden />
|
||||
{expectsCallbackUrl
|
||||
@@ -380,7 +380,7 @@ function ProviderRequestOptions({
|
||||
const tx = (key: string, fallback: string) => t(key, { defaultValue: fallback });
|
||||
|
||||
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) => {
|
||||
const title = tx(option.titleKey, option.title);
|
||||
const Icon = option.kind === "priority" ? Zap : Globe2;
|
||||
@@ -599,7 +599,7 @@ function ProviderAdvancedOptions({
|
||||
onChange={(event) => onChange({ extraHeaders: event.target.value })}
|
||||
placeholder={'{"X-Header":"value"}'}
|
||||
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>
|
||||
) : null}
|
||||
@@ -613,7 +613,7 @@ function ProviderAdvancedOptions({
|
||||
onChange={(event) => onChange({ extraQuery: event.target.value })}
|
||||
placeholder={'{"api-version":"2024-02-01"}'}
|
||||
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>
|
||||
) : null}
|
||||
@@ -627,7 +627,7 @@ function ProviderAdvancedOptions({
|
||||
onChange={(event) => onChange({ extraBody: event.target.value })}
|
||||
placeholder={'{"service_tier":"priority"}'}
|
||||
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>
|
||||
) : null}
|
||||
@@ -825,7 +825,7 @@ export function ProvidersSettings({
|
||||
) : null}
|
||||
{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">
|
||||
<p className="text-[13px] font-semibold text-foreground">
|
||||
{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"
|
||||
>
|
||||
<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 />
|
||||
</span>
|
||||
<span className="truncate text-[15px] font-semibold text-foreground">
|
||||
@@ -1334,7 +1334,7 @@ function ProviderIcon({
|
||||
return (
|
||||
<span
|
||||
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
|
||||
src={logoUrl}
|
||||
@@ -1352,7 +1352,7 @@ function ProviderIcon({
|
||||
return (
|
||||
<span
|
||||
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 }}
|
||||
aria-hidden
|
||||
>
|
||||
|
||||
@@ -129,7 +129,7 @@ export function OverviewSettings({
|
||||
: tx("settings.values.ready", "Ready");
|
||||
return (
|
||||
<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} />
|
||||
</section>
|
||||
|
||||
@@ -433,7 +433,7 @@ function OverviewRowIcon({
|
||||
icon: LucideIcon;
|
||||
}) {
|
||||
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 />
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -309,7 +309,7 @@ export function ModelIdPicker({
|
||||
key={model.id}
|
||||
{...navigation.getOptionProps(model.id)}
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -455,7 +455,7 @@ export function ModelIdPicker({
|
||||
) : null}
|
||||
<ComboboxOption
|
||||
{...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">
|
||||
<Pencil className="h-3 w-3" aria-hidden />
|
||||
|
||||
@@ -31,7 +31,7 @@ export function CapabilityInstallNotice({
|
||||
installing?: boolean;
|
||||
}) {
|
||||
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 ? (
|
||||
<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>
|
||||
</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
|
||||
type="button"
|
||||
variant="ghost"
|
||||
onClick={() => onOpenChange(false)}
|
||||
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")}
|
||||
</Button>
|
||||
@@ -92,7 +92,7 @@ export function NanobotFeatureInstallDialog({
|
||||
type="button"
|
||||
onClick={() => feature && void onConfirm(feature)}
|
||||
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}
|
||||
{tx("settings.nanobotFeatures.installConfirmAction", "Install and enable")}
|
||||
@@ -117,7 +117,7 @@ export function DismissibleStatusMessage({
|
||||
return (
|
||||
<div
|
||||
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
|
||||
? "border-destructive/20 bg-destructive/5 text-destructive"
|
||||
: "border-border/55 bg-muted/35 text-muted-foreground",
|
||||
@@ -153,7 +153,7 @@ export function RestartRequiredNotice({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
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>
|
||||
{onRestart ? (
|
||||
<Button
|
||||
@@ -186,7 +186,7 @@ export function SettingsSectionTitle({ children }: { children: ReactNode }) {
|
||||
|
||||
export function SettingsGroup({ children }: { children: ReactNode }) {
|
||||
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>
|
||||
);
|
||||
|
||||
@@ -256,7 +256,7 @@ export function AppsCatalogSettings({
|
||||
onChange={(event) => onQueryChange(event.target.value)}
|
||||
placeholder={tx("settings.apps.searchPlaceholder", "Search Apps")}
|
||||
className={cn(
|
||||
"h-12 rounded-[14px] pl-11 text-[15px]",
|
||||
"h-12 pl-11 text-[15px]",
|
||||
SETTINGS_SEARCH_INPUT_CLASS,
|
||||
)}
|
||||
/>
|
||||
@@ -289,7 +289,7 @@ export function AppsCatalogSettings({
|
||||
/>
|
||||
) : 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">
|
||||
<SettingsSectionTitle>
|
||||
{filter === "mcp"
|
||||
@@ -412,7 +412,7 @@ function CliAppsCatalogRow({
|
||||
const description = app.description || app.requires || app.entry_point || app.name;
|
||||
|
||||
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} />
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-baseline gap-2">
|
||||
@@ -583,7 +583,7 @@ function McpAppsCatalogRow({
|
||||
};
|
||||
|
||||
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">
|
||||
<McpPresetLogo preset={preset} showBrandLogos={showBrandLogos} />
|
||||
<div className="min-w-[8rem] flex-[1_1_8rem]">
|
||||
@@ -747,7 +747,7 @@ function McpAppsCatalogRow({
|
||||
|
||||
{manualCallback ? (
|
||||
<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) => {
|
||||
event.preventDefault();
|
||||
onOAuthComplete();
|
||||
@@ -825,7 +825,7 @@ function McpAppsCatalogRow({
|
||||
</div>
|
||||
</form>
|
||||
) : 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">
|
||||
<span>
|
||||
{mcpOAuthStatusText(
|
||||
@@ -1016,10 +1016,10 @@ function McpCustomServerPanel({
|
||||
];
|
||||
|
||||
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 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 />
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
@@ -1154,7 +1154,7 @@ function McpCustomServerPanel({
|
||||
value={form.headers}
|
||||
onChange={(event) => update("headers", event.target.value)}
|
||||
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
|
||||
id={headersHelpId}
|
||||
@@ -1202,7 +1202,7 @@ function McpCustomServerPanel({
|
||||
value={form.args}
|
||||
onChange={(event) => update("args", event.target.value)}
|
||||
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>
|
||||
) : null}
|
||||
@@ -1214,7 +1214,7 @@ function McpCustomServerPanel({
|
||||
value={form.env}
|
||||
onChange={(event) => update("env", event.target.value)}
|
||||
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 className="min-w-0">
|
||||
@@ -1257,7 +1257,7 @@ function McpCustomServerPanel({
|
||||
value={configImport}
|
||||
onChange={(event) => onConfigImportChange(event.target.value)}
|
||||
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>
|
||||
<Button
|
||||
@@ -1352,7 +1352,7 @@ function McpPresetLogo({
|
||||
<span
|
||||
className={cn(
|
||||
"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
|
||||
@@ -1372,8 +1372,8 @@ function McpPresetLogo({
|
||||
className={cn(
|
||||
"grid shrink-0 place-items-center font-semibold text-white",
|
||||
compact
|
||||
? "h-10 w-10 rounded-[10px] text-[12px]"
|
||||
: "h-11 w-11 rounded-[8px] text-[13px]",
|
||||
? "h-10 w-10 rounded-control text-[12px]"
|
||||
: "h-11 w-11 rounded-compact text-[13px]",
|
||||
)}
|
||||
style={{ backgroundColor: bg }}
|
||||
>
|
||||
@@ -1406,7 +1406,7 @@ function CliAppReadyPanel({
|
||||
};
|
||||
|
||||
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">
|
||||
<CliAppLogo app={app} showBrandLogos={showBrandLogos} />
|
||||
<div className="min-w-0 flex-1">
|
||||
@@ -1472,7 +1472,7 @@ function CliAppLogo({ app, showBrandLogos }: { app: CliAppInfo; showBrandLogos:
|
||||
|
||||
return (
|
||||
<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))" }}
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -129,14 +129,14 @@ export function AutomationsSettings({
|
||||
<section className="shrink-0">
|
||||
<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="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) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
onClick={() => onFilterChange(option.value)}
|
||||
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",
|
||||
automationFilterToneClass(option.value, option.count, filter === option.value),
|
||||
)}
|
||||
@@ -166,7 +166,7 @@ export function AutomationsSettings({
|
||||
"Search task, message, linked chat, or schedule",
|
||||
)}
|
||||
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,
|
||||
)}
|
||||
/>
|
||||
@@ -175,7 +175,7 @@ export function AutomationsSettings({
|
||||
<DropdownMenuTrigger asChild>
|
||||
<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 />
|
||||
<span>{sortLabel[sort]}</span>
|
||||
@@ -197,19 +197,19 @@ export function AutomationsSettings({
|
||||
) : null}
|
||||
|
||||
{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 />
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{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 />
|
||||
{tx("settings.automations.loading", "Loading automations...")}
|
||||
</div>
|
||||
) : 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">
|
||||
<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">
|
||||
@@ -245,7 +245,7 @@ export function AutomationsSettings({
|
||||
/>
|
||||
</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>
|
||||
{jobs.length
|
||||
? tx("settings.automations.noMatches", "No automations match this view.")
|
||||
@@ -313,7 +313,7 @@ function AutomationListItem({
|
||||
aria-pressed={selected}
|
||||
onClick={onSelect}
|
||||
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
|
||||
? "bg-background/80 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="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="text-[11px] font-medium leading-none text-muted-foreground/75">
|
||||
{messageLabel}
|
||||
@@ -506,7 +506,7 @@ function AutomationDetailPanel({
|
||||
</div>
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
@@ -520,7 +520,7 @@ function AutomationDetailPanel({
|
||||
>
|
||||
{schedule}
|
||||
</AutomationDetail>
|
||||
<div className="rounded-[18px] bg-background/55 p-3">
|
||||
<div className="rounded-floating bg-background/55 p-3">
|
||||
<div className="grid gap-3">
|
||||
{created ? (
|
||||
<div>
|
||||
@@ -672,7 +672,7 @@ function AutomationDetail({
|
||||
children: ReactNode;
|
||||
}) {
|
||||
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">
|
||||
{label}
|
||||
</div>
|
||||
@@ -757,7 +757,7 @@ export function AutomationEditDialog({
|
||||
{job ? (
|
||||
<DialogContent
|
||||
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}>
|
||||
<DialogHeader>
|
||||
@@ -772,7 +772,6 @@ export function AutomationEditDialog({
|
||||
<Input
|
||||
value={draft.name}
|
||||
onChange={(event) => setDraft((prev) => ({ ...prev, name: event.target.value }))}
|
||||
className="h-10 rounded-[12px]"
|
||||
/>
|
||||
</label>
|
||||
|
||||
@@ -784,7 +783,7 @@ export function AutomationEditDialog({
|
||||
<Textarea
|
||||
value={draft.message}
|
||||
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>
|
||||
) : null}
|
||||
@@ -821,7 +820,6 @@ export function AutomationEditDialog({
|
||||
onChange={(event) =>
|
||||
setDraft((prev) => ({ ...prev, everyValue: event.target.value }))
|
||||
}
|
||||
className="h-10 rounded-[12px]"
|
||||
/>
|
||||
</label>
|
||||
<label className="block space-y-1.5">
|
||||
@@ -837,7 +835,7 @@ export function AutomationEditDialog({
|
||||
}))
|
||||
}
|
||||
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,
|
||||
)}
|
||||
>
|
||||
@@ -861,7 +859,7 @@ export function AutomationEditDialog({
|
||||
value={draft.cronExpr}
|
||||
onChange={(event) => setDraft((prev) => ({ ...prev, cronExpr: event.target.value }))}
|
||||
placeholder="0 9 * * *"
|
||||
className="h-10 rounded-[12px] font-mono text-[13px]"
|
||||
className="font-mono text-[13px]"
|
||||
/>
|
||||
</label>
|
||||
<label className="block space-y-1.5">
|
||||
@@ -872,7 +870,7 @@ export function AutomationEditDialog({
|
||||
value={draft.tz}
|
||||
onChange={(event) => setDraft((prev) => ({ ...prev, tz: event.target.value }))}
|
||||
placeholder="Asia/Shanghai"
|
||||
className="h-10 rounded-[12px] text-[13px]"
|
||||
className="text-[13px]"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
@@ -887,13 +885,12 @@ export function AutomationEditDialog({
|
||||
type="datetime-local"
|
||||
value={draft.atLocal}
|
||||
onChange={(event) => setDraft((prev) => ({ ...prev, atLocal: event.target.value }))}
|
||||
className="h-10 rounded-[12px]"
|
||||
/>
|
||||
</label>
|
||||
) : null}
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
@@ -905,11 +902,10 @@ export function AutomationEditDialog({
|
||||
variant="ghost"
|
||||
onClick={() => onOpenChange(false)}
|
||||
disabled={saving}
|
||||
className="rounded-full"
|
||||
>
|
||||
{tx("settings.automations.cancel", "Cancel")}
|
||||
</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}
|
||||
{tx("settings.automations.save", "Save")}
|
||||
</Button>
|
||||
@@ -937,7 +933,7 @@ export function AutomationDeleteDialog({
|
||||
t(key, { defaultValue: fallback, ...(values ?? {}) });
|
||||
return (
|
||||
<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>
|
||||
<DialogTitle>{tx("settings.automations.deleteTitle", "Delete automation")}</DialogTitle>
|
||||
<DialogDescription>
|
||||
@@ -954,7 +950,6 @@ export function AutomationDeleteDialog({
|
||||
variant="ghost"
|
||||
onClick={() => onOpenChange(false)}
|
||||
disabled={deleting}
|
||||
className="rounded-full"
|
||||
>
|
||||
{tx("settings.automations.cancel", "Cancel")}
|
||||
</Button>
|
||||
@@ -963,7 +958,6 @@ export function AutomationDeleteDialog({
|
||||
variant="destructive"
|
||||
onClick={() => job && void onConfirm(job)}
|
||||
disabled={!job || deleting}
|
||||
className="rounded-full"
|
||||
>
|
||||
{deleting ? <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden /> : null}
|
||||
{tx("settings.automations.delete", "Delete")}
|
||||
|
||||
@@ -147,19 +147,19 @@ export function ChannelsSettings({
|
||||
onChange={(event) => onQueryChange(event.target.value)}
|
||||
placeholder={tx("settings.channels.searchPlaceholder", "Search channels")}
|
||||
className={cn(
|
||||
"h-12 rounded-[14px] pl-11 text-[15px]",
|
||||
"h-12 rounded-control pl-11 text-[15px]",
|
||||
SETTINGS_SEARCH_INPUT_CLASS,
|
||||
)}
|
||||
/>
|
||||
</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) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
onClick={() => setFilter(option.value)}
|
||||
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
|
||||
? "bg-background text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
||||
@@ -153,7 +153,6 @@ export function McpManagementDialog({
|
||||
showCloseButton={false}
|
||||
className={cn(
|
||||
"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">
|
||||
@@ -282,7 +281,7 @@ function OverviewPanel({
|
||||
const previewTools = (preset.tool_names ?? []).slice(0, 4);
|
||||
return (
|
||||
<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">
|
||||
{tx("settings.mcp.about", "About this MCP")}
|
||||
</h3>
|
||||
@@ -314,7 +313,7 @@ function OverviewPanel({
|
||||
</dl>
|
||||
|
||||
{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">
|
||||
{tx("settings.mcp.toolPreview", "Tools")}
|
||||
</h3>
|
||||
@@ -375,7 +374,7 @@ function ToolsPanel({
|
||||
return (
|
||||
<div
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -444,7 +443,7 @@ function ToolsPanel({
|
||||
</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) => {
|
||||
const selected = selectedTools.has(toolName);
|
||||
return (
|
||||
@@ -463,7 +462,7 @@ function ToolsPanel({
|
||||
<span
|
||||
aria-hidden
|
||||
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
|
||||
? "border-foreground bg-foreground text-background"
|
||||
: "border-border bg-background text-transparent",
|
||||
@@ -529,7 +528,7 @@ function ConnectionPanel({
|
||||
<h3 id={`mcp-connection-${preset.name}`} className="sr-only">
|
||||
{tx("settings.mcp.connectionDetails", "Connection details")}
|
||||
</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 ? (
|
||||
<div className="min-w-0">
|
||||
<p className="text-[12.5px] font-medium text-muted-foreground">{connectionLabel}</p>
|
||||
@@ -580,7 +579,7 @@ function ConnectionPanel({
|
||||
</section>
|
||||
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
@@ -661,7 +660,7 @@ function ConnectionPanel({
|
||||
|
||||
function MetricCard({ label, value }: { label: string; value: string }) {
|
||||
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>
|
||||
<dd className="mt-1 truncate text-[14px] font-semibold text-foreground">{value}</dd>
|
||||
</div>
|
||||
|
||||
@@ -1112,7 +1112,7 @@ function CliRunRow({ run, active, app }: { run: CliRunSummary; active: boolean;
|
||||
<span
|
||||
data-testid={`activity-cli-logo-${run.name.toLowerCase()}`}
|
||||
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",
|
||||
)}
|
||||
style={{
|
||||
@@ -1190,7 +1190,7 @@ function McpRunRow({ run, active, preset }: { run: McpRunSummary; active: boolea
|
||||
<span
|
||||
data-testid={`activity-mcp-logo-${run.presetName.toLowerCase()}`}
|
||||
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",
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -203,7 +203,7 @@ export function PromptRail({
|
||||
aria-hidden
|
||||
data-testid={previewVisible ? "prompt-rail-preview" : undefined}
|
||||
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,
|
||||
"transition-[opacity,transform] duration-150",
|
||||
previewVisible
|
||||
|
||||
@@ -41,12 +41,12 @@ export function SessionInfoPopover({ sessionKey, token, title }: SessionInfoPopo
|
||||
const [open, setOpen] = useState(false);
|
||||
const { jobs, loading, loadFailed, now } = useSessionAutomationJobs(open, token, sessionKey);
|
||||
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" />
|
||||
{t("thread.sessionInfo.loading")}
|
||||
</div>
|
||||
) : 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" />
|
||||
{t("thread.sessionInfo.loadFailed")}
|
||||
</div>
|
||||
@@ -57,7 +57,7 @@ export function SessionInfoPopover({ sessionKey, token, title }: SessionInfoPopo
|
||||
))}
|
||||
</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")}
|
||||
</div>
|
||||
);
|
||||
@@ -124,7 +124,7 @@ function AutomationRow({ job, now }: { job: SessionAutomationJob; now: number })
|
||||
: "bg-muted-foreground/35";
|
||||
|
||||
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">
|
||||
<span className={cn("mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full", statusClass)} />
|
||||
<div className="min-w-0 flex-1">
|
||||
|
||||
@@ -2246,8 +2246,8 @@ export function ThreadComposer({
|
||||
className={cn(
|
||||
"thread-composer-surface group/composer relative mx-auto flex w-full flex-col overflow-visible transition-all duration-200",
|
||||
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-[49.5rem] rounded-[22px] 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-panel bg-muted/30 focus-within:bg-muted/50 dark:bg-card dark:focus-within:bg-white/[0.06]",
|
||||
interactionDisabled && "opacity-60",
|
||||
sessionDragPreview && "ring-1 ring-primary/25",
|
||||
isDragging && "ring-2 ring-primary/40 motion-reduce:ring-0 motion-reduce:border-primary",
|
||||
@@ -2610,7 +2610,7 @@ function QueuedPromptStack({
|
||||
role="group"
|
||||
data-state="enter"
|
||||
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",
|
||||
"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)]",
|
||||
@@ -2688,7 +2688,7 @@ function QueuedPromptRow({
|
||||
}}
|
||||
onDragEnd={onDragEnd}
|
||||
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]",
|
||||
isHero && "text-[13.5px]",
|
||||
)}
|
||||
@@ -2973,7 +2973,7 @@ function MentionCandidateLogo({
|
||||
return (
|
||||
<span
|
||||
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",
|
||||
)}
|
||||
>
|
||||
@@ -2991,7 +2991,7 @@ function MentionCandidateLogo({
|
||||
}
|
||||
return (
|
||||
<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 }}
|
||||
>
|
||||
{candidate.initials}
|
||||
@@ -3135,7 +3135,7 @@ function AttachmentChip({
|
||||
return (
|
||||
<div
|
||||
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",
|
||||
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",
|
||||
)}
|
||||
>
|
||||
<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" />
|
||||
</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
@@ -328,7 +328,7 @@ export function WorkspaceAccessMenu({
|
||||
aria-label={accessAriaLabel}
|
||||
title={accessLabel}
|
||||
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]",
|
||||
isFull
|
||||
? "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
|
||||
src={logoUrl}
|
||||
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"
|
||||
loading="lazy"
|
||||
referrerPolicy="no-referrer"
|
||||
|
||||
@@ -37,7 +37,7 @@ const AlertDialogContent = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
@@ -64,7 +64,7 @@ const AlertDialogFooter = ({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
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: {
|
||||
variant: {
|
||||
@@ -21,8 +21,8 @@ const buttonVariants = cva(
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
sm: "h-9 px-3",
|
||||
lg: "h-11 px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@ const DialogContent = React.forwardRef<
|
||||
ref={ref}
|
||||
className={cn(
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
@@ -84,7 +84,7 @@ const DialogFooter = ({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
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,
|
||||
)}
|
||||
{...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)]";
|
||||
|
||||
export const floatingSurfaceVisualClassName =
|
||||
`rounded-[18px] p-1.5 ${floatingSurfaceElevationClassName}`;
|
||||
`rounded-floating p-1.5 ${floatingSurfaceElevationClassName}`;
|
||||
|
||||
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";
|
||||
@@ -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";
|
||||
|
||||
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 =
|
||||
"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
|
||||
type={type}
|
||||
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,
|
||||
className,
|
||||
)}
|
||||
|
||||
@@ -10,7 +10,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
return (
|
||||
<textarea
|
||||
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,
|
||||
className,
|
||||
)}
|
||||
|
||||
@@ -18,7 +18,7 @@ const TooltipContent = React.forwardRef<
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
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,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
+11
-2
@@ -38,6 +38,15 @@
|
||||
--temporary-foreground: 17 88% 32%;
|
||||
--temporary-border: 17 88% 40%;
|
||||
--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-foreground: 0 0% 3.9%;
|
||||
--sidebar-selected: 40 1% 89.4%;
|
||||
@@ -121,7 +130,7 @@
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar-thumb);
|
||||
border-radius: 9999px;
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
@@ -567,7 +576,7 @@
|
||||
}
|
||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||
background-color: hsl(var(--muted-foreground) / 0.4);
|
||||
border-radius: 9999px;
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
.scrollbar-track-transparent {
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
@@ -493,7 +493,7 @@ describe("ChatList", () => {
|
||||
expect(tabSurface).toContainElement(paneList);
|
||||
const activePane = within(tabGroup).getByRole("button", { name: "Research pane" });
|
||||
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]"))
|
||||
.toHaveAttribute("data-active", "true");
|
||||
expect(screen.getByRole("button", {
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("CodeBlock", () => {
|
||||
expect(screen.getByTestId("plain-code-fallback")).toHaveClass("py-4", "pl-5", "pr-14");
|
||||
|
||||
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).toHaveAttribute("data-language", "ts");
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ describe("MessageBubble", () => {
|
||||
const pill = screen.getByText("hello");
|
||||
|
||||
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.queryByRole("button", { name: "Fork" })).not.toBeInTheDocument();
|
||||
});
|
||||
@@ -286,7 +286,7 @@ describe("MessageBubble", () => {
|
||||
expect(command.getAttribute("style")).toContain("var(--inline-token-highlight)");
|
||||
expect(command.className).not.toMatch(/(?:^|\s)(?:bg-|border|ring|rounded)/);
|
||||
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", () => {
|
||||
@@ -934,7 +934,7 @@ describe("MessageBubble", () => {
|
||||
const { container } = render(<MessageBubble message={message} />);
|
||||
|
||||
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(
|
||||
"border",
|
||||
"border-border/60",
|
||||
|
||||
@@ -165,7 +165,7 @@ describe("Settings models", () => {
|
||||
expect(editor).toHaveClass(
|
||||
"slide-in-from-top-1",
|
||||
"lg:max-w-6xl",
|
||||
"rounded-[18px]",
|
||||
"rounded-floating",
|
||||
);
|
||||
expect(within(editor).getByDisplayValue("Primary")).toBeInTheDocument();
|
||||
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("text-[16px]");
|
||||
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(screen.getByRole("button", { name: "Attach files" }).className).toContain("bg-card");
|
||||
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)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
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: {
|
||||
background: "hsl(var(--background))",
|
||||
|
||||
Reference in New Issue
Block a user