diff --git a/.claude/rules/emcn-components.md b/.claude/rules/emcn-components.md index f02ff3946e5..fd57ee5c00c 100644 --- a/.claude/rules/emcn-components.md +++ b/.claude/rules/emcn-components.md @@ -56,3 +56,17 @@ Declare keyboard intent on the action-owning primitive; never add document-level - Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example. Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating. + + +## Ordinary Button action geometry + +`Button` retains its existing appearance variants. For square actions use `iconSize`: +`compact` (24px on the spacing scale), `compact-fixed` (24px), `regular` (28px), +`roomy` (32px), or `touch` (40px). These values follow the root spacing scale; +only `compact-fixed` stays fixed when root text is enlarged. +Use `{ base: 'touch', sm: 'regular' }` for mobile/desktop targets. These props own +geometry only; colour, radius and SVG stroke continue to come from the selected +`variant` and `size`. `iconPadding` explicitly overrides the zero-padding geometry. +Use `shape='round'` for circular actions, or omit it to retain the current radius. +`size='inline'` is a 20px-high action with caption typography and compact horizontal +padding. Prefer these supported props to size, padding and radius overrides. diff --git a/.cursor/rules/emcn-components.mdc b/.cursor/rules/emcn-components.mdc index 1ac5fc577f8..3f5cd1bf90e 100644 --- a/.cursor/rules/emcn-components.mdc +++ b/.cursor/rules/emcn-components.mdc @@ -57,3 +57,17 @@ Declare keyboard intent on the action-owning primitive; never add document-level - Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example. Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating. + + +## Ordinary Button action geometry + +`Button` retains its existing appearance variants. For square actions use `iconSize`: +`compact` (24px on the spacing scale), `compact-fixed` (24px), `regular` (28px), +`roomy` (32px), or `touch` (40px). These values follow the root spacing scale; +only `compact-fixed` stays fixed when root text is enlarged. +Use `{ base: 'touch', sm: 'regular' }` for mobile/desktop targets. These props own +geometry only; colour, radius and SVG stroke continue to come from the selected +`variant` and `size`. `iconPadding` explicitly overrides the zero-padding geometry. +Use `shape='round'` for circular actions, or omit it to retain the current radius. +`size='inline'` is a 20px-high action with caption typography and compact horizontal +padding. Prefer these supported props to size, padding and radius overrides. diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-downloads.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-downloads.tsx index ed3ae9e2eb1..a694dc21271 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-downloads.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-downloads.tsx @@ -3,7 +3,6 @@ import { useEffect, useMemo, useRef, useState } from 'react' import type { BrowserDownloadInfo } from '@sim/desktop-bridge' import { - Button, cn, DropdownMenu, DropdownMenuContent, @@ -18,6 +17,7 @@ import { showBrowserDownloadInFolder, showBrowserDownloadsMenu, } from '@/lib/browser-agent/transport' +import { BrowserToolbarButton } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-toolbar-button' /** Aggregate byte progress for the toolbar rail; unknown-size downloads are ignored. */ export function aggregateDownloadPercent(downloads: BrowserDownloadInfo[]): number | null { @@ -127,14 +127,11 @@ export function BrowserDownloads({ scopeId, open, requestOpen, onClose }: Browse }} > - + Downloads diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.tsx index f3aa734a126..a7c82cf5069 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.tsx @@ -16,7 +16,6 @@ import type { DesktopAppearanceTheme, } from '@sim/desktop-bridge' import { - Button, ChipConfirmModal, ChipInput, chipVariants, @@ -82,6 +81,7 @@ import { useBrowserPanelOcclusion, } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-panel-occlusion' import { BrowserThemeNotice } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-theme-notice' +import { BrowserToolbarButton } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-toolbar-button' import { buildOmniboxSuggestions, googleSearchUrl, @@ -1034,38 +1034,26 @@ export function BrowserSession({
- - - + {/* URL bar: Enter navigates the agent browser. */} - + {fillOptions.map((credential) => ( diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-toolbar-button.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-toolbar-button.tsx new file mode 100644 index 00000000000..28c18eb1b40 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-toolbar-button.tsx @@ -0,0 +1,27 @@ +import { type ComponentProps, forwardRef } from 'react' +import { Button, cn } from '@sim/emcn' + +interface BrowserToolbarButtonProps + extends Omit< + ComponentProps, + 'variant' | 'size' | 'iconSize' | 'iconPadding' | 'type' + > { + 'aria-label': string +} + +/** Browser navigation and utility action; forwards menu-anchor refs and native events. */ +export const BrowserToolbarButton = forwardRef( + ({ className, ...props }, ref) => ( + + ) + expect(markup).toContain('size-10') + expect(markup).toContain('sm:size-7') + expect(markup).not.toContain('size-[20px]') + expect(markup).toContain('p-1') + expect(markup).not.toContain('p-0') + expect(markup).toContain('rounded-full') + expect(markup).not.toContain('rounded-sm') + expect(markup).toContain('[stroke-width:1.25]') + expect(markup).toContain('text-[var(--text-icon-muted)]') + expect(markup).not.toMatch(/(?:iconSize|iconPadding|shape)=/) + }) + + it('retains an inline caption size and supports a base-only responsive value', () => { + const inline = renderToStaticMarkup() + expect(inline).toContain('h-[20px]') + expect(inline).toContain('text-caption') + expect(inline).toContain('px-1.5 py-0') + const baseOnly = renderToStaticMarkup( */ - iconSize?: VariantProps['iconSize'] + iconSize?: ButtonIconSize | { base: ButtonIconSize; sm?: ButtonIconSize } | null /** * Symmetric padding for icon actions whose content or layout determines their size. * Preserves the selected size's typography, corner radius and icon stroke. @@ -98,11 +118,23 @@ export interface ButtonProps } const Button = forwardRef( - ({ className, variant, size, iconSize, iconPadding, ...props }, ref) => { + ({ className, variant, size, iconSize, iconPadding, shape, ...props }, ref) => { + const baseIconSize = typeof iconSize === 'object' ? iconSize?.base : iconSize + const smIconSize = typeof iconSize === 'object' ? iconSize?.sm : undefined return (