Major UI refresh: sidebar redesign, theme expansion, and chat performance optimizations (#706)

## Summary
Complete sidebar redesign and comprehensive UI polish pass with performance optimizations, theme system refinements, and desktop integration improvements.

## Key Changes

**Sidebar & Navigation Redesign**
- Redesigned sessions sidebar layout with unified button primitives
- Added activity sections with project grouping and improved session organization
- Refined sidebar corners, spacing, and visual hierarchy
- Removed NavRail component in favor of streamlined sidebar
- Stabilized sessions bar toggle position in fullscreen mode

**Performance Optimizations**
- Reduced chat streaming CPU usage and storage churn
- Optimized task tool polling and live timers with debouncing
- Prevented chat state races and reduced background request load
- Debounced draft writes and coalesced session reloads
- Optimized message store updates and turn tracking

**Theme & Visual System**
- Added theme-aware window corners (desktop) and border radius tokens
- Introduced glassmorphism effects on desktop sidebar
- Added backdrop blur to UI elements

**Chat Experience**
- Added session-based permission auto-accept toggle in chat input
- Polished permission shield UX with improved icon sizing and spacing
- Fixed chat scroll-to-bottom behavior and timeline tracking
- Enhanced tool output display with better path label detection
- Removed duplicate draft context details in chat header
- Added text selection menu to chat messages

**Git Improvements**
- Refreshed git history visual design with cleaner dividers
- Added remote removal action in sync selector
- Stabilized git polling to prevent excessive requests
- Improved tool output rendering for git operations

**Settings & Panels**
- Fixed mobile scrolling on settings pages
- Made outside-click settings close instantly
- Reduced settings load churn and CPU spikes
- Improved services dropdown layout and spacing
- Softened panel resize handles

**Desktop Integration**
- Synced macOS window theme with app theme
- Restored window dragging in sidebar header zones
- Fixed system window corners on macOS
- Improved header session metadata and action controls

**Button & Component Standardization**
- Unified button primitives across all components
- Standardized destructive action patterns
- Removed unused button variants (button-large, button-small)
- Aligned context tab close hit areas

---------

Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
This commit is contained in:
Bohdan Triapitsyn
2026-03-20 01:01:03 +02:00
committed by GitHub
co-authored by Iuliia Ivashko
parent 359879153a
commit 321cc7252a
222 changed files with 8575 additions and 5456 deletions
@@ -1,5 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { NumberInput } from '@/components/ui/number-input';
import { Textarea } from '@/components/ui/textarea';
@@ -685,7 +685,7 @@ export const AgentsPage: React.FC = () => {
</Tooltip>
</div>
<div className="flex flex-wrap items-center gap-1">
<ButtonSmall
<Button
variant="outline"
size="xs"
onClick={() => setMode('primary')}
@@ -697,8 +697,8 @@ export const AgentsPage: React.FC = () => {
)}
>
Primary
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="outline"
size="xs"
onClick={() => setMode('subagent')}
@@ -710,8 +710,8 @@ export const AgentsPage: React.FC = () => {
)}
>
Subagent
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="outline"
size="xs"
onClick={() => setMode('all')}
@@ -723,7 +723,7 @@ export const AgentsPage: React.FC = () => {
)}
>
All
</ButtonSmall>
</Button>
</div>
</div>
</div>
@@ -790,7 +790,7 @@ export const AgentsPage: React.FC = () => {
className="w-16"
/>
{temperature !== undefined && (
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setTemperature(undefined)}
@@ -799,7 +799,7 @@ export const AgentsPage: React.FC = () => {
title="Clear"
>
<RiCloseLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -834,7 +834,7 @@ export const AgentsPage: React.FC = () => {
className="w-16"
/>
{topP !== undefined && (
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setTopP(undefined)}
@@ -843,7 +843,7 @@ export const AgentsPage: React.FC = () => {
title="Clear"
>
<RiCloseLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -876,14 +876,14 @@ export const AgentsPage: React.FC = () => {
<h3 className="typography-ui-header font-medium text-foreground">
Tool Permissions
</h3>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
onClick={() => setShowPermissionEditor((prev) => !prev)}
>
{showPermissionEditor ? 'Hide Editor' : 'Advanced Editor'}
</ButtonSmall>
</Button>
</div>
{!showPermissionEditor ? (
@@ -961,13 +961,13 @@ export const AgentsPage: React.FC = () => {
<span className="typography-micro text-muted-foreground">Pattern</span>
<span className="typography-micro font-mono text-foreground bg-[var(--surface-muted)] px-1 rounded">*</span>
{wildcardOverride && (
<ButtonSmall
<Button size="sm"
variant="ghost"
onClick={() => revertRule(permissionName, '*')}
className="px-1.5 py-0 h-5"
>
<RiSubtractLine className="h-3.5 w-3.5 text-muted-foreground hover:text-foreground" />
</ButtonSmall>
</Button>
)}
</div>
<Select
@@ -1008,13 +1008,13 @@ export const AgentsPage: React.FC = () => {
{isAdded && <span className="typography-micro text-[var(--status-success)]">New</span>}
{isModified && <span className="typography-micro text-[var(--status-warning)]">Modified</span>}
{(isAdded || isModified) && (
<ButtonSmall
<Button size="sm"
variant="ghost"
onClick={() => isAdded ? removeRule(rule.permission, rule.pattern) : revertRule(rule.permission, rule.pattern)}
className="px-1.5 py-0 h-5"
>
<RiSubtractLine className="h-3.5 w-3.5 text-muted-foreground hover:text-foreground" />
</ButtonSmall>
</Button>
)}
</div>
<Select
@@ -1069,9 +1069,9 @@ export const AgentsPage: React.FC = () => {
/>
<div className="flex gap-1">
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('allow')}>Allow</ButtonSmall>
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('ask')}>Ask</ButtonSmall>
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('deny')}>Deny</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('allow')}>Allow</Button>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('ask')}>Ask</Button>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => applyPendingRule('deny')}>Deny</Button>
</div>
</div>
</div>
@@ -1081,14 +1081,14 @@ export const AgentsPage: React.FC = () => {
{/* Save action */}
<div className="px-2 py-1">
<ButtonSmall
<Button
onClick={handleSave}
disabled={isSaving || !isDirty}
size="xs"
className="!font-normal"
>
{isSaving ? 'Saving...' : 'Save Changes'}
</ButtonSmall>
</Button>
</div>
</div>
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { toast } from '@/components/ui';
import { isMobileDeviceViaCSS } from '@/lib/device';
@@ -324,13 +323,13 @@ export const AgentsSidebar: React.FC<AgentsSidebarProps> = ({ onItemSelect }) =>
<SettingsProjectSelector className="mb-3" />
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">Total {visibleAgents.length}</span>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 -my-1 text-muted-foreground"
onClick={handleCreateNew}
>
<RiAddLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -446,16 +445,17 @@ export const AgentsSidebar: React.FC<AgentsSidebarProps> = ({ onItemSelect }) =>
</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={closeConfirmActionDialog}
disabled={isConfirmActionPending}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleConfirmAction} disabled={isConfirmActionPending}>
</Button>
<Button size="sm" onClick={handleConfirmAction} disabled={isConfirmActionPending}>
{confirmActionType === 'delete' ? 'Delete' : 'Reset'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -481,15 +481,16 @@ export const AgentsSidebar: React.FC<AgentsSidebarProps> = ({ onItemSelect }) =>
}}
/>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => setRenameDialogAgent(null)}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleRenameAgent}>
</Button>
<Button size="sm" onClick={handleRenameAgent}>
Rename
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -563,12 +564,12 @@ const AgentListItem: React.FC<AgentListItemProps> = ({
<DropdownMenu open={isMenuOpen} onOpenChange={onMenuOpenChange}>
<DropdownMenuTrigger asChild>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-6 w-6 px-0 flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
>
<RiMore2Line className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-fit min-w-20">
{onRename && (
@@ -630,8 +630,8 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
{/* Favorites Section */}
{filteredFavorites.length > 0 && (
<>
<DropdownMenuLabel style={{ backgroundColor: 'var(--surface-elevated)' }} className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30">
<div>
<DropdownMenuLabel className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30">
<RiStarFill className="h-4 w-4 text-primary" />
Favorites
</DropdownMenuLabel>
@@ -639,14 +639,14 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
const idx = currentFlatIndex++;
return renderModelRow(model, providerID, modelID, 'fav', idx, selectedIndex === idx);
})}
</>
</div>
)}
{/* Recents Section */}
{filteredRecents.length > 0 && (
<>
<div>
{filteredFavorites.length > 0 && <DropdownMenuSeparator />}
<DropdownMenuLabel style={{ backgroundColor: 'var(--surface-elevated)' }} className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30">
<DropdownMenuLabel className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30">
<RiTimeLine className="h-4 w-4" />
Recent
</DropdownMenuLabel>
@@ -654,7 +654,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
const idx = currentFlatIndex++;
return renderModelRow(model, providerID, modelID, 'recent', idx, selectedIndex === idx);
})}
</>
</div>
)}
{/* Separator before providers */}
@@ -664,9 +664,9 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
{/* All Providers - Flat List */}
{filteredProviders.map((provider, index) => (
<React.Fragment key={provider.id}>
<div key={provider.id}>
{index > 0 && <DropdownMenuSeparator />}
<DropdownMenuLabel style={{ backgroundColor: 'var(--surface-elevated)' }} className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30">
<DropdownMenuLabel className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30">
<ProviderLogo
providerId={provider.id}
className="h-4 w-4 flex-shrink-0"
@@ -677,7 +677,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
const idx = currentFlatIndex++;
return renderModelRow(model, provider.id as string, model.id as string, 'provider', idx, selectedIndex === idx);
})}
</React.Fragment>
</div>
))}
</div>
</ScrollableOverlay>
@@ -1,5 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { toast } from '@/components/ui';
@@ -321,14 +321,14 @@ export const CommandsPage: React.FC = () => {
{/* Save action */}
<div className="px-2 py-1">
<ButtonSmall
<Button
onClick={handleSave}
disabled={isSaving || !isDirty}
size="xs"
className="!font-normal"
>
{isSaving ? 'Saving...' : 'Save Changes'}
</ButtonSmall>
</Button>
</div>
</div>
@@ -1,6 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { toast } from '@/components/ui';
import { isMobileDeviceViaCSS } from '@/lib/device';
@@ -221,13 +220,13 @@ export const CommandsSidebar: React.FC<CommandsSidebarProps> = ({ onItemSelect }
<SettingsProjectSelector className="mb-3" />
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">Total {commandOnlyItems.length}</span>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 -my-1 text-muted-foreground"
onClick={handleCreateNew}
>
<RiAddLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -310,16 +309,17 @@ export const CommandsSidebar: React.FC<CommandsSidebarProps> = ({ onItemSelect }
</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={closeConfirmActionDialog}
disabled={isConfirmActionPending}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleConfirmAction} disabled={isConfirmActionPending}>
</Button>
<Button size="sm" onClick={handleConfirmAction} disabled={isConfirmActionPending}>
{confirmActionType === 'delete' ? 'Delete' : 'Reset'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -345,15 +345,16 @@ export const CommandsSidebar: React.FC<CommandsSidebarProps> = ({ onItemSelect }
}}
/>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => setRenameDialogCommand(null)}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleRenameCommand}>
</Button>
<Button size="sm" onClick={handleRenameCommand}>
Rename
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -422,12 +423,12 @@ const CommandListItem: React.FC<CommandListItemProps> = ({
<DropdownMenu open={isMenuOpen} onOpenChange={onMenuOpenChange}>
<DropdownMenuTrigger asChild>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-6 w-6 px-0 flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
>
<RiMore2Line className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-fit min-w-20">
{onRename && (
@@ -1,6 +1,5 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { ButtonSmall } from '@/components/ui/button-small';
import { Input } from '@/components/ui/input';
import { toast } from '@/components/ui';
import {
@@ -351,7 +350,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<div className="flex items-center justify-between gap-4">
<span className="typography-ui-label text-foreground">Auth Method</span>
<div className="flex items-center gap-1">
<ButtonSmall
<Button size="sm"
type="button"
variant="outline"
onClick={() => setAuthType('ssh')}
@@ -362,8 +361,8 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
)}
>
<RiLock2Line className="w-3.5 h-3.5 mr-1" /> SSH
</ButtonSmall>
<ButtonSmall
</Button>
<Button size="sm"
type="button"
variant="outline"
onClick={() => setAuthType('token')}
@@ -374,7 +373,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
)}
>
<RiKeyLine className="w-3.5 h-3.5 mr-1" /> Token
</ButtonSmall>
</Button>
</div>
</div>
@@ -467,7 +466,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<Button variant="ghost" onClick={() => setIsDeleteDialogOpen(false)} disabled={isDeleting}>
Cancel
</Button>
<Button size="sm" onClick={() => void handleConfirmDelete()} disabled={isDeleting} className="bg-[var(--status-error)] hover:bg-[var(--status-error)]/90 text-white border-0">
<Button size="sm" variant="destructive" onClick={() => void handleConfirmDelete()} disabled={isDeleting}>
Delete
</Button>
</DialogFooter>
@@ -1,5 +1,4 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { toast } from '@/components/ui';
import {
Dialog,
@@ -10,7 +9,6 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { ButtonLarge } from '@/components/ui/button-large';
import {
DropdownMenu,
DropdownMenuContent,
@@ -124,9 +122,9 @@ export const GitPage: React.FC = () => {
<div className="flex items-center gap-2">
<h3 className="typography-ui-header font-semibold text-foreground">Identities</h3>
</div>
<ButtonSmall variant="outline" onClick={() => openEditor('new')}>
<Button size="sm" variant="outline" onClick={() => openEditor('new')}>
<RiAddLine className="w-3.5 h-3.5 mr-1" /> New
</ButtonSmall>
</Button>
</div>
<div className="rounded-lg bg-[var(--surface-elevated)]/70 overflow-hidden flex flex-col">
@@ -213,9 +211,9 @@ export const GitPage: React.FC = () => {
<Button variant="ghost" onClick={() => setDeleteDialogProfile(null)} disabled={isDeletePending}>
Cancel
</Button>
<ButtonLarge onClick={() => void handleConfirmDelete()} disabled={isDeletePending} className="bg-[var(--status-error)] hover:bg-[var(--status-error)]/90 text-white border-0">
<Button size="sm" variant="destructive" onClick={() => void handleConfirmDelete()} disabled={isDeletePending}>
Delete
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -340,10 +338,10 @@ const DiscoveredRow: React.FC<DiscoveredRowProps> = ({ credential, onImport, has
{isRepoSpecific ? credential.host : credential.username}
</span>
</div>
<ButtonSmall variant="ghost" onClick={onImport} className="gap-1 shrink-0">
<Button size="sm" variant="ghost" onClick={onImport} className="gap-1 shrink-0">
<RiDownloadLine className="h-3 w-3" />
Import
</ButtonSmall>
</Button>
</div>
);
};
@@ -1,7 +1,5 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { ButtonLarge } from '@/components/ui/button-large';
import { ButtonSmall } from '@/components/ui/button-small';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
@@ -110,7 +108,7 @@ const CommandTextarea: React.FC<CommandTextareaProps> = ({ value, onChange }) =>
return (
<div className="space-y-2">
<div className="flex items-center justify-end gap-2">
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal gap-1 text-muted-foreground"
@@ -120,7 +118,7 @@ const CommandTextarea: React.FC<CommandTextareaProps> = ({ value, onChange }) =>
>
<RiClipboardLine className="h-3 w-3" />
Paste command
</ButtonSmall>
</Button>
</div>
<Textarea
@@ -252,7 +250,7 @@ const EnvEditor: React.FC<EnvEditorProps> = ({ value, onChange }) => {
<span className="typography-micro text-muted-foreground w-32 shrink-0">Key</span>
<span className="typography-micro text-muted-foreground">Value</span>
</div>
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal gap-1 text-muted-foreground"
@@ -262,7 +260,7 @@ const EnvEditor: React.FC<EnvEditorProps> = ({ value, onChange }) => {
>
<RiClipboardLine className="h-3 w-3" />
Paste .env
</ButtonSmall>
</Button>
</div>
{/* Rows */}
@@ -299,18 +297,18 @@ const EnvEditor: React.FC<EnvEditorProps> = ({ value, onChange }) => {
</button>
</div>
{/* Remove */}
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 shrink-0 text-muted-foreground hover:text-[var(--status-error)]"
onClick={() => removeRow(idx)}
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
))}
</div>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal gap-1.5"
@@ -319,7 +317,7 @@ const EnvEditor: React.FC<EnvEditorProps> = ({ value, onChange }) => {
>
<RiAddLine className="h-3.5 w-3.5" />
Add variable
</ButtonSmall>
</Button>
{hasSensitiveValues && (
<p className="typography-micro text-muted-foreground/60">
@@ -535,7 +533,7 @@ export const McpPage: React.FC = () => {
{isNewServer ? 'Configure a new MCP server' : `${mcpType === 'local' ? 'Local · stdio' : 'Remote · SSE'} transport`}
</p>
{!isNewServer && (
<ButtonSmall
<Button
variant={isConnected ? 'outline' : 'default'}
size="xs"
className="!font-normal"
@@ -543,7 +541,7 @@ export const McpPage: React.FC = () => {
disabled={isConnecting || !enabled}
>
{isConnecting ? 'Working...' : isConnected ? 'Disconnect' : 'Connect'}
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -618,7 +616,7 @@ export const McpPage: React.FC = () => {
<div className="flex min-w-0 flex-col gap-1.5">
<span className="typography-ui-label text-foreground">Transport Mode</span>
<div className="flex flex-wrap items-center gap-1">
<ButtonSmall
<Button
variant="outline"
size="xs"
onClick={() => setMcpType('local')}
@@ -630,8 +628,8 @@ export const McpPage: React.FC = () => {
)}
>
Local · stdio
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="outline"
size="xs"
onClick={() => setMcpType('remote')}
@@ -643,7 +641,7 @@ export const McpPage: React.FC = () => {
)}
>
Remote · SSE
</ButtonSmall>
</Button>
</div>
</div>
</div>
@@ -693,23 +691,23 @@ export const McpPage: React.FC = () => {
{/* Actions */}
<div className="flex items-center gap-2 px-2 py-1">
<ButtonSmall
<Button
onClick={handleSave}
disabled={isSaving || (!isDirty && !isNewServer)}
size="xs"
className="!font-normal"
>
{isSaving ? 'Saving...' : isNewServer ? 'Create' : 'Save Changes'}
</ButtonSmall>
</Button>
{!isNewServer && (
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal text-[var(--status-error)] hover:text-[var(--status-error)]"
onClick={() => setShowDeleteConfirm(true)}
>
Delete
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -736,9 +734,9 @@ export const McpPage: React.FC = () => {
>
Cancel
</Button>
<ButtonLarge onClick={handleDelete} disabled={isDeleting}>
<Button size="sm" onClick={handleDelete} disabled={isDeleting}>
{isDeleting ? 'Deleting…' : 'Delete'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,6 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
@@ -130,14 +129,14 @@ export const McpSidebar: React.FC<McpSidebarProps> = ({ onItemSelect }) => {
<span className="typography-meta text-muted-foreground">
Total {mcpServers.length}
</span>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 -my-1 text-muted-foreground"
onClick={handleCreateNew}
title="Add MCP server"
>
<RiAddLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -198,9 +197,9 @@ export const McpSidebar: React.FC<McpSidebarProps> = ({ onItemSelect }) => {
<DropdownMenu open={openMenuMcp === server.name} onOpenChange={(open) => setOpenMenuMcp(open ? server.name : null)}>
<DropdownMenuTrigger asChild>
<ButtonSmall variant="ghost" className="h-6 w-6 px-0 flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<Button size="xs" variant="ghost" className="flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<RiMore2Line className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-fit min-w-20">
<DropdownMenuItem
@@ -268,9 +267,9 @@ export const McpSidebar: React.FC<McpSidebarProps> = ({ onItemSelect }) => {
<DropdownMenu open={openMenuMcp === server.name} onOpenChange={(open) => setOpenMenuMcp(open ? server.name : null)}>
<DropdownMenuTrigger asChild>
<ButtonSmall variant="ghost" className="h-6 w-6 px-0 flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<Button size="xs" variant="ghost" className="flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<RiMore2Line className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-fit min-w-20">
<DropdownMenuItem
@@ -308,16 +307,17 @@ export const McpSidebar: React.FC<McpSidebarProps> = ({ onItemSelect }) => {
</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => setDeleteTarget(null)}
disabled={isDeleting}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleDelete} disabled={isDeleting}>
</Button>
<Button size="sm" onClick={handleDelete} disabled={isDeleting}>
{isDeleting ? 'Deleting…' : 'Delete'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -5,7 +5,7 @@ import { UpdateDialog } from '@/components/ui/UpdateDialog';
import { useDeviceInfo } from '@/lib/device';
import { toast } from '@/components/ui';
import { cn } from '@/lib/utils';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
const GITHUB_URL = 'https://github.com/btriapitsyn/openchamber';
@@ -155,26 +155,26 @@ export const AboutSettings: React.FC = () => {
)}
{!updateStore.checking && updateStore.available && (
<ButtonSmall
<Button size="sm"
variant="default"
onClick={() => setUpdateDialogOpen(true)}
>
<RiDownloadLine className="h-4 w-4 mr-1" />
Update to {updateStore.info?.version}
</ButtonSmall>
</Button>
)}
{!updateStore.checking && !updateStore.available && !updateStore.error && (
<span className="typography-meta text-muted-foreground">Up to date</span>
)}
<ButtonSmall
<Button size="sm"
variant="outline"
onClick={() => updateStore.checkForUpdates()}
disabled={updateStore.checking}
>
Check for updates
</ButtonSmall>
</Button>
</div>
</div>
@@ -1,6 +1,5 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { ButtonSmall } from '@/components/ui/button-small';
import { toast } from '@/components/ui';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
import { useGitHubAuthStore } from '@/stores/useGitHubAuthStore';
@@ -304,18 +303,18 @@ export const GitHubSettings: React.FC = () => {
</div>
</div>
<ButtonSmall variant="outline" onClick={disconnect} disabled={isBusy} className={cn("text-[var(--status-error)] hover:text-[var(--status-error)]", isMobile ? "w-full" : undefined)}>
<Button size="sm" variant="outline" onClick={disconnect} disabled={isBusy} className={cn("text-[var(--status-error)] hover:text-[var(--status-error)]", isMobile ? "w-full" : undefined)}>
Disconnect
</ButtonSmall>
</Button>
</div>
) : (
<div className="flex items-center justify-between gap-4 px-4 py-4">
<div className="flex min-w-0 flex-col">
<span className="typography-ui-label text-foreground">Not Connected</span>
</div>
<ButtonSmall variant="default" onClick={startConnect} disabled={isBusy}>
<Button size="sm" variant="default" onClick={startConnect} disabled={isBusy}>
Connect GitHub
</ButtonSmall>
</Button>
</div>
)}
@@ -359,13 +358,13 @@ export const GitHubSettings: React.FC = () => {
{isCurrent ? (
<span className="typography-micro text-[var(--primary-base)] bg-[var(--primary-base)]/10 px-1.5 py-0.5 rounded">Active</span>
) : (
<ButtonSmall
<Button size="sm"
variant="ghost"
onClick={() => activateAccount(account.id)}
disabled={isBusy}
>
Switch to
</ButtonSmall>
</Button>
)}
</div>
);
@@ -378,14 +377,14 @@ export const GitHubSettings: React.FC = () => {
{connected && (
<div className="mt-2 px-2 pb-2">
<ButtonSmall
<Button size="sm"
variant="outline"
onClick={startConnect}
disabled={isBusy}
className={cn(isMobile ? 'w-full' : undefined)}
>
Add Account
</ButtonSmall>
</Button>
</div>
)}
@@ -413,12 +412,12 @@ export const GitHubSettings: React.FC = () => {
<span className="typography-micro text-muted-foreground animate-pulse">
Waiting for approval (auto-refresh)
</span>
<ButtonSmall variant="ghost" disabled={isBusy} onClick={() => {
<Button size="sm" variant="ghost" disabled={isBusy} onClick={() => {
stopPolling();
setFlow(null);
}}>
Cancel
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -1,5 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { RiInformationLine } from '@remixicon/react';
@@ -132,7 +132,7 @@ export const KeyboardShortcutsSettings: React.FC = () => {
<div className="mb-1 px-1">
<div className="flex items-center gap-2">
<h3 className="typography-ui-header font-medium text-foreground">Keyboard Shortcuts</h3>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -146,7 +146,7 @@ export const KeyboardShortcutsSettings: React.FC = () => {
}}
>
Reset All
</ButtonSmall>
</Button>
<Tooltip delayDuration={1000}>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
@@ -166,8 +166,8 @@ export const KeyboardShortcutsSettings: React.FC = () => {
This combo is already used by another shortcut. Overwrite and clear that other mapping?
</span>
<div className="flex gap-2 shrink-0">
<ButtonSmall type="button" size="xs" className="!font-normal" onClick={confirmOverwrite}>Overwrite</ButtonSmall>
<ButtonSmall type="button" size="xs" className="!font-normal" variant="ghost" onClick={() => setPendingOverwrite(null)}>Cancel</ButtonSmall>
<Button type="button" size="xs" className="!font-normal" onClick={confirmOverwrite}>Overwrite</Button>
<Button type="button" size="xs" className="!font-normal" variant="ghost" onClick={() => setPendingOverwrite(null)}>Cancel</Button>
</div>
</div>
)}
@@ -233,7 +233,7 @@ export const KeyboardShortcutsSettings: React.FC = () => {
}}
className="h-7 w-40 min-w-0 typography-ui-label text-center"
/>
<ButtonSmall
<Button
type="button"
variant="secondary"
size="xs"
@@ -249,10 +249,10 @@ export const KeyboardShortcutsSettings: React.FC = () => {
disabled={!hasDraft}
>
Save
</ButtonSmall>
<ButtonSmall type="button" size="xs" className="!font-normal" variant="ghost" onClick={() => resetOne(action.id)}>
</Button>
<Button type="button" size="xs" className="!font-normal" variant="ghost" onClick={() => resetOne(action.id)}>
Reset
</ButtonSmall>
</Button>
</div>
</div>
);
@@ -11,7 +11,7 @@ import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';
import { GridLoader } from '@/components/ui/grid-loader';
import { Input } from '@/components/ui/input';
import { NumberInput } from '@/components/ui/number-input';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
@@ -800,7 +800,7 @@ export const NotificationSettings: React.FC = () => {
step={50}
className="w-20 tabular-nums"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setSummaryThreshold(DEFAULT_SUMMARY_THRESHOLD)}
@@ -810,7 +810,7 @@ export const NotificationSettings: React.FC = () => {
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
<div className="flex items-center gap-8 py-1.5">
@@ -827,7 +827,7 @@ export const NotificationSettings: React.FC = () => {
step={10}
className="w-20 tabular-nums"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setSummaryLength(DEFAULT_SUMMARY_LENGTH)}
@@ -837,7 +837,7 @@ export const NotificationSettings: React.FC = () => {
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
</>
@@ -856,7 +856,7 @@ export const NotificationSettings: React.FC = () => {
step={10}
className="w-20 tabular-nums"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setMaxLastMessageLength(DEFAULT_MAX_LAST_MESSAGE_LENGTH)}
@@ -866,7 +866,7 @@ export const NotificationSettings: React.FC = () => {
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -99,7 +99,7 @@ const ShortcutsSectionContent: React.FC = () => {
return <KeyboardShortcutsSettings />;
};
// Visual section: Theme Mode, Font Size, Spacing, Corner Radius, Input Bar Offset (mobile), Nav Rail
// Visual section: Theme Mode, Font Size, Spacing, Input Bar Offset (mobile), Nav Rail
const VisualSectionContent: React.FC = () => {
const isVSCode = isVSCodeRuntime();
return <OpenChamberVisualSettings visibleSettings={[
@@ -108,9 +108,8 @@ const VisualSectionContent: React.FC = () => {
'fontSize',
'terminalFontSize',
'spacing',
'cornerRadius',
'inputBarOffset',
...(!isVSCode ? ['terminalQuickKeys' as const, 'navRail' as const] : []),
...(!isVSCode ? ['terminalQuickKeys' as const] : []),
]} />;
};
@@ -7,7 +7,7 @@ import type { ThemeMode } from '@/types/theme';
import { useUIStore } from '@/stores/useUIStore';
import { useMessageQueueStore } from '@/stores/messageQueueStore';
import { cn, getModifierLabel } from '@/lib/utils';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { NumberInput } from '@/components/ui/number-input';
import { Radio } from '@/components/ui/radio';
@@ -143,7 +143,7 @@ const normalizeUserMessageRenderingMode = (mode: unknown): 'markdown' | 'plain'
return mode === 'markdown' ? 'markdown' : 'plain';
};
export type VisibleSetting = 'theme' | 'pwaInstallName' | 'fontSize' | 'terminalFontSize' | 'spacing' | 'cornerRadius' | 'inputBarOffset' | 'navRail' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'activityRenderMode' | 'stickyUserHeader' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'reasoning' | 'showToolFileIcons' | 'expandedTools' | 'queueMode' | 'terminalQuickKeys' | 'persistDraft' | 'inputSpellcheck';
export type VisibleSetting = 'theme' | 'pwaInstallName' | 'fontSize' | 'terminalFontSize' | 'spacing' | 'inputBarOffset' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'activityRenderMode' | 'stickyUserHeader' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'reasoning' | 'showToolFileIcons' | 'expandedTools' | 'queueMode' | 'terminalQuickKeys' | 'persistDraft' | 'inputSpellcheck';
interface OpenChamberVisualSettingsProps {
/** Which settings to show. If undefined, shows all. */
@@ -173,8 +173,6 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
const setTerminalFontSize = useUIStore(state => state.setTerminalFontSize);
const padding = useUIStore(state => state.padding);
const setPadding = useUIStore(state => state.setPadding);
const cornerRadius = useUIStore(state => state.cornerRadius);
const setCornerRadius = useUIStore(state => state.setCornerRadius);
const inputBarOffset = useUIStore(state => state.inputBarOffset);
const setInputBarOffset = useUIStore(state => state.setInputBarOffset);
const diffLayoutPreference = useUIStore(state => state.diffLayoutPreference);
@@ -195,10 +193,9 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
const setShowExpandedBashTools = useUIStore(state => state.setShowExpandedBashTools);
const showExpandedEditTools = useUIStore(state => state.showExpandedEditTools);
const setShowExpandedEditTools = useUIStore(state => state.setShowExpandedEditTools);
const isNavRailExpanded = useUIStore(state => state.isNavRailExpanded);
const setNavRailExpanded = useUIStore(state => state.setNavRailExpanded);
const showMobileSessionStatusBar = useUIStore(state => state.showMobileSessionStatusBar);
const setShowMobileSessionStatusBar = useUIStore(state => state.setShowMobileSessionStatusBar);
const isSettingsDialogOpen = useUIStore(state => state.isSettingsDialogOpen);
const {
themeMode,
setThemeMode,
@@ -214,7 +211,14 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
const [themesReloading, setThemesReloading] = React.useState(false);
const [chatRenderPreviewTick, setChatRenderPreviewTick] = React.useState(0);
const shouldAnimateChatPreview = isSettingsDialogOpen
&& (visibleSettings ? visibleSettings.includes('chatRenderMode') : true);
React.useEffect(() => {
if (!shouldAnimateChatPreview) {
return;
}
const intervalId = setInterval(() => {
setChatRenderPreviewTick((prev) => (prev + 1) % 24);
}, 420);
@@ -222,7 +226,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
return () => {
clearInterval(intervalId);
};
}, []);
}, [shouldAnimateChatPreview]);
const handleUserMessageRenderingModeChange = React.useCallback((mode: 'markdown' | 'plain') => {
setUserMessageRenderingMode(mode);
@@ -305,8 +309,8 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
const isVSCode = isVSCodeRuntime();
const hasAppearanceSettings = (shouldShow('theme') || shouldShow('pwaInstallName')) && !isVSCode;
const hasLayoutSettings = shouldShow('fontSize') || shouldShow('terminalFontSize') || shouldShow('spacing') || shouldShow('cornerRadius') || shouldShow('inputBarOffset');
const hasNavigationSettings = (!isMobile && shouldShow('navRail')) || (shouldShow('terminalQuickKeys') && !isMobile);
const hasLayoutSettings = shouldShow('fontSize') || shouldShow('terminalFontSize') || shouldShow('spacing') || shouldShow('inputBarOffset');
const hasNavigationSettings = shouldShow('terminalQuickKeys') && !isMobile;
const hasBehaviorSettings = shouldShow('mermaidRendering')
|| shouldShow('userMessageRendering')
|| shouldShow('chatRenderMode')
@@ -402,7 +406,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
<span className="typography-ui-header font-medium text-foreground">Color Mode</span>
<div className="flex flex-wrap items-center gap-1">
{THEME_MODE_OPTIONS.map((option) => (
<ButtonSmall
<Button
key={option.value}
variant="outline"
size="xs"
@@ -415,7 +419,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
onClick={() => setThemeMode(option.value)}
>
{option.label}
</ButtonSmall>
</Button>
))}
</div>
</div>
@@ -516,7 +520,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
maxLength={64}
aria-label="PWA install app name"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => {
@@ -528,7 +532,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -558,7 +562,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
aria-label="Font size percentage"
className="w-16"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setFontSize(100)}
@@ -568,7 +572,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -587,7 +591,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
step={1}
className="w-16"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setTerminalFontSize(13)}
@@ -597,7 +601,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -616,7 +620,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
step={5}
className="w-16"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setPadding(100)}
@@ -626,36 +630,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</div>
</div>
)}
{shouldShow('cornerRadius') && (
<div className={cn("py-1", isMobile ? "flex flex-col gap-3" : "flex items-center gap-8")}>
<div className={cn("flex min-w-0 flex-col", isMobile ? "w-full" : "w-56 shrink-0")}>
<span className="typography-ui-label text-foreground">Corner Radius</span>
</div>
<div className={cn("flex items-center gap-2", isMobile ? "w-full" : "w-fit")}>
<NumberInput
value={cornerRadius}
onValueChange={setCornerRadius}
min={0}
max={32}
step={1}
className="w-16"
/>
<ButtonSmall
type="button"
variant="ghost"
onClick={() => setCornerRadius(12)}
disabled={cornerRadius === 12}
className="h-7 w-7 px-0 text-muted-foreground hover:text-foreground"
aria-label="Reset corner radius"
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -684,7 +659,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
step={5}
className="w-16"
/>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setInputBarOffset(0)}
@@ -694,7 +669,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -710,38 +685,6 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
<div className="space-y-3">
<section className="px-2 pb-2 pt-0">
<h4 className="typography-ui-header font-medium text-foreground">Navigation</h4>
{shouldShow('navRail') && !isMobile && (
<div
className="group mt-1.5 flex cursor-pointer items-center gap-2 py-1.5"
role="button"
tabIndex={0}
onClick={() => setNavRailExpanded(!isNavRailExpanded)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
setNavRailExpanded(!isNavRailExpanded);
}
}}
>
<Checkbox
checked={isNavRailExpanded}
onChange={setNavRailExpanded}
ariaLabel="Expand project rail by default"
/>
<div className="flex min-w-0 items-center gap-1.5">
<span className="typography-ui-label text-foreground">Expand project rail</span>
<Tooltip delayDuration={1000}>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
<TooltipContent sideOffset={8} className="max-w-xs">
Show project names in the left rail when multiple projects are open. Auto-collapses with a single project.
</TooltipContent>
</Tooltip>
</div>
</div>
)}
{shouldShow('terminalQuickKeys') && !isMobile && (
<div
className="group flex cursor-pointer items-center gap-2 py-1.5"
@@ -1,5 +1,5 @@
import * as React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { RiFolderLine, RiInformationLine } from '@remixicon/react';
@@ -111,7 +111,7 @@ export const OpenCodeCliSettings: React.FC = () => {
disabled={isLoading || isSaving}
className="h-7 min-w-0 flex-1 font-mono text-xs"
/>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -122,7 +122,7 @@ export const OpenCodeCliSettings: React.FC = () => {
title="Browse"
>
<RiFolderLine className="h-4 w-4" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -133,7 +133,7 @@ export const OpenCodeCliSettings: React.FC = () => {
</div>
<div className="flex justify-start py-1.5">
<ButtonSmall
<Button
type="button"
size="xs"
onClick={handleSaveAndReload}
@@ -141,7 +141,7 @@ export const OpenCodeCliSettings: React.FC = () => {
className="shrink-0 !font-normal"
>
{isSaving ? 'Saving…' : 'Save + Reload'}
</ButtonSmall>
</Button>
</div>
</section>
</div>
@@ -3,7 +3,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
import { RiInformationLine, RiRestartLine } from '@remixicon/react';
import { toast } from '@/components/ui';
import { NumberInput } from '@/components/ui/number-input';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { useUIStore } from '@/stores/useUIStore';
import { useSessionAutoCleanup } from '@/hooks/useSessionAutoCleanup';
@@ -90,7 +90,7 @@ export const SessionRetentionSettings: React.FC = () => {
className="w-20 tabular-nums"
/>
<span className="typography-ui-label text-muted-foreground">days</span>
<ButtonSmall
<Button size="sm"
type="button"
variant="ghost"
onClick={() => setAutoDeleteAfterDays(DEFAULT_RETENTION_DAYS)}
@@ -100,7 +100,7 @@ export const SessionRetentionSettings: React.FC = () => {
title="Reset"
>
<RiRestartLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
</section>
@@ -111,7 +111,7 @@ export const SessionRetentionSettings: React.FC = () => {
<p className="typography-meta text-foreground font-medium">Manual Cleanup</p>
</div>
<div className="flex items-center gap-2 sm:w-fit">
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -120,7 +120,7 @@ export const SessionRetentionSettings: React.FC = () => {
className="!font-normal"
>
{isRunning ? 'Cleaning up...' : 'Run cleanup now'}
</ButtonSmall>
</Button>
</div>
</div>
<p className="typography-meta text-muted-foreground">
@@ -18,7 +18,7 @@ import {
RiRestartLine,
} from '@remixicon/react';
import { toast } from '@/components/ui';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { GridLoader } from '@/components/ui/grid-loader';
import { Input } from '@/components/ui/input';
@@ -1121,7 +1121,7 @@ export const TunnelSettings: React.FC = () => {
{TUNNEL_MODE_OPTIONS.map((option) => (
<Tooltip key={option.value} delayDuration={700}>
<TooltipTrigger asChild>
<ButtonSmall
<Button
variant="outline"
size="xs"
className={cn(
@@ -1136,7 +1136,7 @@ export const TunnelSettings: React.FC = () => {
disabled={isSavingMode || state === 'starting' || state === 'stopping'}
>
{option.label}
</ButtonSmall>
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="max-w-xs">
{option.tooltip}
@@ -1217,7 +1217,7 @@ export const TunnelSettings: React.FC = () => {
<div className="mb-1 flex items-center justify-between gap-3">
<p className="typography-ui-label text-foreground">Saved managed remote tunnels</p>
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal"
@@ -1226,7 +1226,7 @@ export const TunnelSettings: React.FC = () => {
>
<RiAddLine className="h-3.5 w-3.5" />
Add
</ButtonSmall>
</Button>
</div>
{managedRemoteTunnelPresets.length > 0 ? (
@@ -1263,7 +1263,7 @@ export const TunnelSettings: React.FC = () => {
<span className="typography-ui-label min-w-0 flex-1 truncate text-foreground">{preset.name}</span>
</CollapsibleTrigger>
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="h-7 w-7 p-0 text-muted-foreground hover:text-[var(--status-error)]"
@@ -1274,7 +1274,7 @@ export const TunnelSettings: React.FC = () => {
disabled={state === 'starting' || state === 'stopping' || isSavingMode}
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
<CollapsibleContent className="pt-1.5">
@@ -1305,7 +1305,7 @@ export const TunnelSettings: React.FC = () => {
disabled={state === 'starting' || state === 'stopping'}
/>
<div className="flex items-center justify-end">
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal"
@@ -1320,7 +1320,7 @@ export const TunnelSettings: React.FC = () => {
}}
>
Save token
</ButtonSmall>
</Button>
</div>
</div>
</CollapsibleContent>
@@ -1363,7 +1363,7 @@ export const TunnelSettings: React.FC = () => {
</p>
)}
<div className="flex items-center gap-2">
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal"
@@ -1373,8 +1373,8 @@ export const TunnelSettings: React.FC = () => {
disabled={isSavingMode || state === 'starting' || state === 'stopping'}
>
Save
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="ghost"
size="xs"
className="!font-normal"
@@ -1387,7 +1387,7 @@ export const TunnelSettings: React.FC = () => {
disabled={isSavingMode || state === 'starting' || state === 'stopping'}
>
Cancel
</ButtonSmall>
</Button>
</div>
</div>
)}
@@ -1442,7 +1442,7 @@ export const TunnelSettings: React.FC = () => {
className="h-7"
disabled={state === 'starting' || state === 'stopping' || isSavingMode}
/>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="h-7 w-7 p-0"
@@ -1453,9 +1453,9 @@ export const TunnelSettings: React.FC = () => {
disabled={state === 'starting' || state === 'stopping' || isSavingMode}
>
<RiFolderLine className="size-3.5" />
</ButtonSmall>
</Button>
{managedLocalConfigPath && (
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="h-7 w-7 p-0"
@@ -1466,7 +1466,7 @@ export const TunnelSettings: React.FC = () => {
disabled={state === 'starting' || state === 'stopping' || isSavingMode}
>
<RiCloseLine className="size-3.5" />
</ButtonSmall>
</Button>
)}
</div>
<p className="typography-meta text-muted-foreground/70">
@@ -1566,7 +1566,7 @@ export const TunnelSettings: React.FC = () => {
</div>
)}
<ButtonSmall
<Button size="sm"
variant="outline"
onClick={handleStart}
disabled={
@@ -1580,7 +1580,7 @@ export const TunnelSettings: React.FC = () => {
{state === 'starting'
? <><RiLoader4Line className="size-3.5 animate-spin" /> Starting tunnel...</>
: 'Start Tunnel'}
</ButtonSmall>
</Button>
</div>
)}
@@ -1610,12 +1610,12 @@ export const TunnelSettings: React.FC = () => {
<code className="typography-code flex-1 truncate rounded bg-muted/50 px-2 py-1 text-xs text-foreground">
{tunnelInfo.connectUrl}
</code>
<ButtonSmall variant="ghost" onClick={handleCopyUrl} className="shrink-0 gap-1.5">
<Button size="sm" variant="ghost" onClick={handleCopyUrl} className="shrink-0 gap-1.5">
{copied
? <RiCheckLine className="size-3.5 text-[var(--status-success)]" />
: <RiFileCopyLine className="size-3.5" />}
{copied ? 'Copied' : 'Copy'}
</ButtonSmall>
</Button>
</div>
<p className="typography-meta mt-1 text-muted-foreground/70">
Expires: {tunnelInfo.bootstrapExpiresAt ? remainingText : 'Never'}
@@ -1634,7 +1634,7 @@ export const TunnelSettings: React.FC = () => {
<div className="pt-1">
<div className="flex flex-wrap items-center gap-2">
<ButtonSmall
<Button size="sm"
variant="outline"
onClick={handleStart}
disabled={state === 'stopping' || isSavingMode || (tunnelMode === 'managed-local' && isManagedLocalConfigPathInvalid)}
@@ -1642,9 +1642,9 @@ export const TunnelSettings: React.FC = () => {
>
<RiRestartLine className="size-3.5" />
New connect link
</ButtonSmall>
</Button>
<ButtonSmall
<Button size="sm"
variant="ghost"
onClick={handleStop}
disabled={state === 'stopping' || isSavingMode}
@@ -1653,7 +1653,7 @@ export const TunnelSettings: React.FC = () => {
{state === 'stopping'
? <><RiLoader4Line className="size-3.5 animate-spin" /> Stopping...</>
: 'Stop Tunnel'}
</ButtonSmall>
</Button>
</div>
</div>
</section>
@@ -1662,7 +1662,7 @@ export const TunnelSettings: React.FC = () => {
{state === 'error' && errorMessage && (
<section className="space-y-3 px-2 pb-2 pt-0">
<p className="typography-meta text-[var(--status-error)]">{errorMessage}</p>
<ButtonSmall variant="ghost" onClick={handleStart}>Retry</ButtonSmall>
<Button size="sm" variant="ghost" onClick={handleStart}>Retry</Button>
</section>
)}
</div>
@@ -11,7 +11,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { NumberInput } from '@/components/ui/number-input';
import { RiPlayLine, RiStopLine, RiCloseLine, RiAppleLine, RiInformationLine } from '@remixicon/react';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
@@ -363,7 +363,7 @@ export const VoiceSettings: React.FC = () => {
</Tooltip>
</div>
<div className="flex flex-wrap items-center gap-1">
<ButtonSmall
<Button
variant="outline"
size="xs"
onClick={() => setVoiceProvider('browser')}
@@ -375,8 +375,8 @@ export const VoiceSettings: React.FC = () => {
)}
>
Browser
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="outline"
size="xs"
onClick={() => setVoiceProvider('openai')}
@@ -388,9 +388,9 @@ export const VoiceSettings: React.FC = () => {
)}
>
OpenAI
</ButtonSmall>
</Button>
{isSayAvailable && (
<ButtonSmall
<Button
variant="outline"
size="xs"
onClick={() => setVoiceProvider('say')}
@@ -403,7 +403,7 @@ export const VoiceSettings: React.FC = () => {
>
<RiAppleLine className="w-3.5 h-3.5 mr-0.5" />
Say
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -455,9 +455,9 @@ export const VoiceSettings: React.FC = () => {
))}
</SelectContent>
</Select>
<ButtonSmall variant="ghost" className="h-7 w-7 px-0" onClick={previewOpenAIVoice} title="Preview">
<Button size="xs" variant="ghost" onClick={previewOpenAIVoice} title="Preview">
{isOpenAIPreviewPlaying ? <RiStopLine className="w-3.5 h-3.5" /> : <RiPlayLine className="w-3.5 h-3.5" />}
</ButtonSmall>
</Button>
</>
)}
@@ -473,9 +473,9 @@ export const VoiceSettings: React.FC = () => {
))}
</SelectContent>
</Select>
<ButtonSmall variant="ghost" className="h-7 w-7 px-0" onClick={previewVoice} title="Preview">
<Button size="xs" variant="ghost" onClick={previewVoice} title="Preview">
{isPreviewPlaying ? <RiStopLine className="w-3.5 h-3.5" /> : <RiPlayLine className="w-3.5 h-3.5" />}
</ButtonSmall>
</Button>
</>
)}
@@ -492,9 +492,9 @@ export const VoiceSettings: React.FC = () => {
))}
</SelectContent>
</Select>
<ButtonSmall variant="ghost" className="h-7 w-7 px-0" onClick={previewBrowserVoice} title="Preview">
<Button size="xs" variant="ghost" onClick={previewBrowserVoice} title="Preview">
{isBrowserPreviewPlaying ? <RiStopLine className="w-3.5 h-3.5" /> : <RiPlayLine className="w-3.5 h-3.5" />}
</ButtonSmall>
</Button>
</>
)}
</div>
@@ -1,6 +1,6 @@
import React from 'react';
import { RiAddLine, RiCloseLine, RiDeleteBinLine, RiInformationLine } from '@remixicon/react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useProjectsStore } from '@/stores/useProjectsStore';
@@ -306,7 +306,7 @@ export const WorktreeSectionContent: React.FC<WorktreeSectionContentProps> = ({
</button>
</div>
))}
<ButtonSmall
<Button
type="button"
variant="ghost"
size="xs"
@@ -315,7 +315,7 @@ export const WorktreeSectionContent: React.FC<WorktreeSectionContentProps> = ({
>
<RiAddLine className="h-3.5 w-3.5" />
Add command
</ButtonSmall>
</Button>
</div>
)}
</div>
@@ -7,7 +7,7 @@ import {
RiInformationLine,
RiPlayLine,
} from '@remixicon/react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
Collapsible,
@@ -198,10 +198,10 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
<h3 className="typography-ui-header font-medium text-foreground">Actions</h3>
<p className="typography-meta text-muted-foreground">Per-project commands shown in header next to project name.</p>
</div>
<ButtonSmall type="button" variant="outline" size="xs" className="!font-normal" onClick={handleAddAction}>
<Button type="button" variant="outline" size="xs" className="!font-normal" onClick={handleAddAction}>
<RiAddLine className="h-3.5 w-3.5" />
Add action
</ButtonSmall>
</Button>
</div>
<section className="pb-2 pt-0 space-y-2">
@@ -248,7 +248,7 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
</div>
</CollapsibleTrigger>
<ButtonSmall
<Button
type="button"
variant="ghost"
size="xs"
@@ -256,7 +256,7 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
onClick={() => handleRemoveAction(action.id)}
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
<CollapsibleContent className="pt-1.5">
@@ -418,7 +418,7 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
{validationError ? (
<p className="typography-meta mb-2 text-[var(--status-warning)]">{validationError}</p>
) : null}
<ButtonSmall
<Button
type="button"
size="xs"
className="!font-normal"
@@ -426,7 +426,7 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
disabled={!canSave}
>
{isSaving ? 'Saving...' : 'Save Actions'}
</ButtonSmall>
</Button>
</div>
</section>
</div>
@@ -1,6 +1,6 @@
import React from 'react';
import { Input } from '@/components/ui/input';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { toast } from '@/components/ui';
import { cn } from '@/lib/utils';
@@ -399,7 +399,7 @@ export const ProjectsPage: React.FC = () => {
placeholder="#000000"
className="h-7 w-[8rem]"
/>
<ButtonSmall
<Button
type="button"
size="xs"
variant="outline"
@@ -410,21 +410,21 @@ export const ProjectsPage: React.FC = () => {
disabled={!iconBackground}
>
<RiCloseLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
)}
<div className="mt-2 flex flex-wrap items-center gap-2">
{!hasCustomIcon && (
<>
<ButtonSmall
<Button
size="xs"
className="h-6 !font-normal"
onClick={() => fileInputRef.current?.click()}
disabled={isUploadingIcon}
>
{isUploadingIcon ? 'Uploading...' : 'Upload Icon'}
</ButtonSmall>
<ButtonSmall
</Button>
<Button
size="xs"
className="h-6 !font-normal"
variant="outline"
@@ -432,11 +432,11 @@ export const ProjectsPage: React.FC = () => {
disabled={isDiscoveringIcon}
>
{isDiscoveringIcon ? 'Discovering...' : 'Discover Favicon'}
</ButtonSmall>
</Button>
</>
)}
{hasRemovableImageIcon && (
<ButtonSmall
<Button
size="xs"
className="!font-normal"
variant="outline"
@@ -444,10 +444,10 @@ export const ProjectsPage: React.FC = () => {
disabled={isRemovingCustomIcon}
>
{isRemovingCustomIcon ? 'Removing...' : 'Remove Project Icon'}
</ButtonSmall>
</Button>
)}
{pendingRemoveImageIcon && (
<ButtonSmall
<Button
size="xs"
className="!font-normal"
variant="outline"
@@ -455,7 +455,7 @@ export const ProjectsPage: React.FC = () => {
disabled={isRemovingCustomIcon}
>
Undo Remove
</ButtonSmall>
</Button>
)}
</div>
</div>
@@ -463,14 +463,14 @@ export const ProjectsPage: React.FC = () => {
</section>
<div className="mt-0.5 px-2 py-1">
<ButtonSmall
<Button
onClick={handleSave}
disabled={!hasChanges || name.trim().length === 0 || isUploadingIcon || isRemovingCustomIcon}
size="xs"
className="!font-normal"
>
Save Changes
</ButtonSmall>
</Button>
</div>
</div>
@@ -3,7 +3,7 @@ import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { ProviderLogo } from '@/components/ui/ProviderLogo';
import { useConfigStore } from '@/stores/useConfigStore';
import { useUIStore } from '@/stores/useUIStore';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
DropdownMenu,
@@ -653,14 +653,14 @@ export const ProvidersPage: React.FC = () => {
placeholder="sk-..."
className="flex-1 font-mono text-xs"
/>
<ButtonSmall
<Button
size="xs"
className="!font-normal shrink-0"
onClick={() => handleSaveApiKey(candidateProviderId)}
disabled={authBusyKey === `api:${candidateProviderId}`}
>
{authBusyKey === `api:${candidateProviderId}` ? 'Saving...' : 'Save Key'}
</ButtonSmall>
</Button>
</div>
</div>
@@ -693,7 +693,7 @@ export const ProvidersPage: React.FC = () => {
</div>
)}
</div>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
@@ -701,7 +701,7 @@ export const ProvidersPage: React.FC = () => {
disabled={authBusyKey === `oauth:${candidateProviderId}:${index}`}
>
Connect
</ButtonSmall>
</Button>
</div>
{oauthDetails[codeKey]?.instructions && (
@@ -713,7 +713,7 @@ export const ProvidersPage: React.FC = () => {
{oauthDetails[codeKey]?.userCode && (
<div className="flex items-center gap-2 mt-2">
<Input value={oauthDetails[codeKey]?.userCode} readOnly className="font-mono text-center tracking-widest" />
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthCode(oauthDetails[codeKey]?.userCode ?? '')}>Copy Code</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthCode(oauthDetails[codeKey]?.userCode ?? '')}>Copy Code</Button>
</div>
)}
@@ -721,8 +721,8 @@ export const ProvidersPage: React.FC = () => {
<div className="flex items-center gap-2 mt-2">
<Input value={oauthDetails[codeKey]?.url} readOnly className="text-xs text-muted-foreground" />
<div className="flex gap-1 shrink-0">
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => window.open(oauthDetails[codeKey]?.url, '_blank', 'noopener,noreferrer')}>Open</ButtonSmall>
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthLink(oauthDetails[codeKey]?.url ?? '')}>Copy</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => window.open(oauthDetails[codeKey]?.url, '_blank', 'noopener,noreferrer')}>Open</Button>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthLink(oauthDetails[codeKey]?.url ?? '')}>Copy</Button>
</div>
</div>
)}
@@ -740,14 +740,14 @@ export const ProvidersPage: React.FC = () => {
placeholder="Paste authorization code"
className="font-mono text-xs"
/>
<ButtonSmall
<Button
size="xs"
className="!font-normal"
onClick={() => handleOAuthComplete(candidateProviderId, index)}
disabled={authBusyKey === `oauth-complete:${candidateProviderId}:${index}`}
>
{authBusyKey === `oauth-complete:${candidateProviderId}:${index}` ? 'Saving...' : 'Complete'}
</ButtonSmall>
</Button>
</div>
)}
</div>
@@ -810,14 +810,14 @@ export const ProvidersPage: React.FC = () => {
<div className="mb-8">
<div className="mb-1 px-1 flex items-center justify-between gap-2">
<h3 className="typography-ui-header font-medium text-foreground">Authentication</h3>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
onClick={() => setShowAuthPanel((prev) => !prev)}
>
{showAuthPanel ? 'Hide' : 'Reconnect'}
</ButtonSmall>
</Button>
</div>
<section className="px-2 pb-2 pt-0">
@@ -856,14 +856,14 @@ export const ProvidersPage: React.FC = () => {
placeholder="sk-..."
className="flex-1 font-mono text-xs"
/>
<ButtonSmall
<Button
size="xs"
className="!font-normal shrink-0"
onClick={() => handleSaveApiKey(selectedProvider.id)}
disabled={authBusyKey === `api:${selectedProvider.id}`}
>
{authBusyKey === `api:${selectedProvider.id}` ? 'Saving...' : 'Save Key'}
</ButtonSmall>
</Button>
</div>
</div>
@@ -886,7 +886,7 @@ export const ProvidersPage: React.FC = () => {
</div>
)}
</div>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
@@ -894,7 +894,7 @@ export const ProvidersPage: React.FC = () => {
disabled={authBusyKey === `oauth:${selectedProvider.id}:${index}`}
>
Connect
</ButtonSmall>
</Button>
</div>
{oauthDetails[codeKey]?.instructions && (
@@ -906,7 +906,7 @@ export const ProvidersPage: React.FC = () => {
{oauthDetails[codeKey]?.userCode && (
<div className="flex items-center gap-2 mt-2">
<Input value={oauthDetails[codeKey]?.userCode} readOnly className="font-mono text-center tracking-widest" />
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthCode(oauthDetails[codeKey]?.userCode ?? '')}>Copy Code</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthCode(oauthDetails[codeKey]?.userCode ?? '')}>Copy Code</Button>
</div>
)}
@@ -914,8 +914,8 @@ export const ProvidersPage: React.FC = () => {
<div className="flex items-center gap-2 mt-2">
<Input value={oauthDetails[codeKey]?.url} readOnly className="text-xs text-muted-foreground" />
<div className="flex gap-1 shrink-0">
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => window.open(oauthDetails[codeKey]?.url, '_blank', 'noopener,noreferrer')}>Open</ButtonSmall>
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthLink(oauthDetails[codeKey]?.url ?? '')}>Copy</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => window.open(oauthDetails[codeKey]?.url, '_blank', 'noopener,noreferrer')}>Open</Button>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => handleCopyOAuthLink(oauthDetails[codeKey]?.url ?? '')}>Copy</Button>
</div>
</div>
)}
@@ -933,14 +933,14 @@ export const ProvidersPage: React.FC = () => {
placeholder="Paste authorization code"
className="font-mono text-xs"
/>
<ButtonSmall
<Button
size="xs"
className="!font-normal"
onClick={() => handleOAuthComplete(selectedProvider.id, index)}
disabled={authBusyKey === `oauth-complete:${selectedProvider.id}:${index}`}
>
{authBusyKey === `oauth-complete:${selectedProvider.id}:${index}` ? 'Saving...' : 'Complete'}
</ButtonSmall>
</Button>
</div>
)}
</div>
@@ -976,7 +976,7 @@ export const ProvidersPage: React.FC = () => {
)}
</div>
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal text-[var(--status-error)] hover:text-[var(--status-error)]"
@@ -984,7 +984,7 @@ export const ProvidersPage: React.FC = () => {
disabled={authBusyKey === `disconnect:${selectedProvider.id}`}
>
{authBusyKey === `disconnect:${selectedProvider.id}` ? 'Disconnecting...' : 'Disconnect'}
</ButtonSmall>
</Button>
</div>
</section>
</div>
@@ -1001,7 +1001,7 @@ export const ProvidersPage: React.FC = () => {
)}
</h3>
<div className="flex items-center gap-1">
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
@@ -1013,15 +1013,15 @@ export const ProvidersPage: React.FC = () => {
}}
>
Hide all
</ButtonSmall>
<ButtonSmall
</Button>
<Button
variant="outline"
size="xs"
className="!font-normal"
onClick={() => showAllModels(selectedProvider.id)}
>
Show all
</ButtonSmall>
</Button>
</div>
</div>
@@ -1,7 +1,7 @@
import React from 'react';
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { ProviderLogo } from '@/components/ui/ProviderLogo';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { useConfigStore } from '@/stores/useConfigStore';
import { useProjectsStore } from '@/stores/useProjectsStore';
import { RiAddLine, RiStackLine } from '@remixicon/react';
@@ -110,7 +110,7 @@ export const ProvidersSidebar: React.FC<ProvidersSidebarProps> = ({ onItemSelect
<SettingsProjectSelector className="mb-3" />
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">Total {providers.length}</span>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 -my-1 text-muted-foreground"
onClick={() => {
@@ -121,7 +121,7 @@ export const ProvidersSidebar: React.FC<ProvidersSidebarProps> = ({ onItemSelect
title="Connect provider"
>
<RiAddLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -1,5 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { NumberInput } from '@/components/ui/number-input';
import { Switch } from '@/components/ui/switch';
@@ -701,7 +701,7 @@ export const RemoteInstancesPage: React.FC = () => {
</div>
<div className="typography-micro text-muted-foreground">{candidate.source} config</div>
</div>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -709,7 +709,7 @@ export const RemoteInstancesPage: React.FC = () => {
onClick={() => void handleImportCandidate(candidate.host, candidate.pattern)}
>
Create
</ButtonSmall>
</Button>
</div>
))}
</div>
@@ -746,12 +746,12 @@ export const RemoteInstancesPage: React.FC = () => {
autoFocus
/>
<div className="flex items-center justify-end gap-2">
<ButtonSmall type="button" variant="outline" size="xs" className="!font-normal" onClick={closePatternDialog} disabled={patternCreating}>
<Button type="button" variant="outline" size="xs" className="!font-normal" onClick={closePatternDialog} disabled={patternCreating}>
Cancel
</ButtonSmall>
<ButtonSmall type="submit" size="xs" className="!font-normal" disabled={patternCreating}>
</Button>
<Button type="submit" size="xs" className="!font-normal" disabled={patternCreating}>
Create
</ButtonSmall>
</Button>
</div>
</form>
</DialogContent>
@@ -782,7 +782,7 @@ export const RemoteInstancesPage: React.FC = () => {
</div>
<section className="px-2 pb-2 pt-0 space-y-3">
<div className="flex flex-wrap items-center gap-2">
<ButtonSmall
<Button
type="button"
variant={canDisconnect ? 'outline' : 'default'}
size="xs"
@@ -792,8 +792,8 @@ export const RemoteInstancesPage: React.FC = () => {
>
{canDisconnect ? <RiStopLine className="h-3.5 w-3.5" /> : <RiPlug2Line className="h-3.5 w-3.5" />}
{primaryButtonLabel}
</ButtonSmall>
<ButtonSmall
</Button>
<Button
type="button"
variant="outline"
size="xs"
@@ -803,8 +803,8 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiRefreshLine className={`h-3.5 w-3.5 ${isConnecting || (isReconnecting && !reconnectAppearsStuck) ? 'animate-spin' : ''}`} />
{retryButtonLabel}
</ButtonSmall>
<ButtonSmall
</Button>
<Button
type="button"
variant="outline"
size="xs"
@@ -815,8 +815,8 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiTerminalWindowLine className="h-3.5 w-3.5" />
Logs
</ButtonSmall>
<ButtonSmall
</Button>
<Button
type="button"
variant="outline"
size="xs"
@@ -838,7 +838,7 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
Remove
</ButtonSmall>
</Button>
</div>
{status?.localUrl ? (
<div className="flex flex-wrap items-center gap-2 typography-meta text-muted-foreground">
@@ -1114,7 +1114,7 @@ export const RemoteInstancesPage: React.FC = () => {
}}
emptyLabel="Auto"
/>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -1131,7 +1131,7 @@ export const RemoteInstancesPage: React.FC = () => {
}
>
<RiShuffleLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
</section>
@@ -1254,7 +1254,7 @@ export const RemoteInstancesPage: React.FC = () => {
</div>
<div className="flex items-center gap-2">
<Switch checked={forward.enabled} onCheckedChange={(checked) => updateForward((item) => ({ ...item, enabled: checked }))} aria-label="Enable forward" />
<ButtonSmall
<Button
type="button"
variant="ghost"
size="xs"
@@ -1267,7 +1267,7 @@ export const RemoteInstancesPage: React.FC = () => {
}
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
<CollapsibleContent className="pt-2">
@@ -1416,7 +1416,7 @@ export const RemoteInstancesPage: React.FC = () => {
</div>
{canOpenLocalEndpoint ? (
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -1431,7 +1431,7 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiExternalLinkLine className="h-3.5 w-3.5" />
Open local
</ButtonSmall>
</Button>
) : null}
</div>
</div>
@@ -1440,7 +1440,7 @@ export const RemoteInstancesPage: React.FC = () => {
);
})}
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -1459,7 +1459,7 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiAddLine className="h-3.5 w-3.5" />
Add forward
</ButtonSmall>
</Button>
</section>
</div>
@@ -1486,7 +1486,7 @@ export const RemoteInstancesPage: React.FC = () => {
</div>
<div className="typography-micro text-muted-foreground truncate">{candidate.sshCommand}</div>
</div>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -1494,7 +1494,7 @@ export const RemoteInstancesPage: React.FC = () => {
onClick={() => void handleImportCandidate(candidate.host, candidate.pattern)}
>
Import
</ButtonSmall>
</Button>
</div>
))}
</div>
@@ -1504,12 +1504,12 @@ export const RemoteInstancesPage: React.FC = () => {
<div className="sticky bottom-0 z-10 -mx-3 sm:-mx-6 bg-[var(--surface-background)] border-t border-[var(--interactive-border)] px-3 sm:px-6 py-3">
<div className="flex items-center gap-2">
<ButtonSmall type="button" size="xs" className="!font-normal" onClick={() => void handleSave()} disabled={!hasChanges || isSaving}>
<Button type="button" size="xs" className="!font-normal" onClick={() => void handleSave()} disabled={!hasChanges || isSaving}>
Save changes
</ButtonSmall>
</Button>
{status?.localUrl ? (
<>
<ButtonSmall
<Button
type="button"
variant="outline"
size="xs"
@@ -1524,8 +1524,8 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiFileCopyLine className="h-3.5 w-3.5" />
Copy local URL
</ButtonSmall>
<ButtonSmall
</Button>
<Button
type="button"
variant="outline"
size="xs"
@@ -1536,7 +1536,7 @@ export const RemoteInstancesPage: React.FC = () => {
>
<RiExternalLinkLine className="h-3.5 w-3.5" />
Open
</ButtonSmall>
</Button>
</>
) : null}
{error ? <div className="ml-auto typography-meta text-[var(--status-error)]">{error}</div> : null}
@@ -1552,14 +1552,14 @@ export const RemoteInstancesPage: React.FC = () => {
</DialogDescription>
</DialogHeader>
<div className="flex items-center justify-end gap-2">
<ButtonSmall type="button" variant="outline" size="xs" className="!font-normal" onClick={handleCopyAllLogs} disabled={logDialogLoading || !logLinesText.trim()}>
<Button type="button" variant="outline" size="xs" className="!font-normal" onClick={handleCopyAllLogs} disabled={logDialogLoading || !logLinesText.trim()}>
<RiFileCopyLine className="h-3.5 w-3.5" />
Copy all
</ButtonSmall>
<ButtonSmall type="button" variant="outline" size="xs" className="!font-normal" onClick={() => void handleClearLogs()} disabled={logDialogLoading}>
</Button>
<Button type="button" variant="outline" size="xs" className="!font-normal" onClick={() => void handleClearLogs()} disabled={logDialogLoading}>
<RiDeleteBinLine className="h-3.5 w-3.5" />
Clear
</ButtonSmall>
</Button>
</div>
{logDialogLoading ? (
<div className="typography-meta text-muted-foreground">Loading logs...</div>
@@ -1602,12 +1602,12 @@ export const RemoteInstancesPage: React.FC = () => {
autoFocus
/>
<div className="flex items-center justify-end gap-2">
<ButtonSmall type="button" variant="outline" size="xs" className="!font-normal" onClick={closePatternDialog} disabled={patternCreating}>
<Button type="button" variant="outline" size="xs" className="!font-normal" onClick={closePatternDialog} disabled={patternCreating}>
Cancel
</ButtonSmall>
<ButtonSmall type="submit" size="xs" className="!font-normal" disabled={patternCreating}>
</Button>
<Button type="submit" size="xs" className="!font-normal" disabled={patternCreating}>
Create
</ButtonSmall>
</Button>
</div>
</form>
</DialogContent>
@@ -1,5 +1,5 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { toast } from '@/components/ui';
@@ -20,7 +20,6 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ButtonLarge } from '@/components/ui/button-large';
import { SkillsCatalogPage } from './catalog/SkillsCatalogPage';
import {
SKILL_LOCATION_OPTIONS,
@@ -459,9 +458,9 @@ const SkillsInstalledPage: React.FC = () => {
<h3 className="typography-ui-header font-medium text-foreground">
Supporting Files
</h3>
<ButtonSmall variant="outline" size="xs" className="!font-normal gap-1" onClick={handleAddFile}>
<Button variant="outline" size="xs" className="!font-normal gap-1" onClick={handleAddFile}>
<RiAddLine className="h-3.5 w-3.5" /> Add File
</ButtonSmall>
</Button>
</div>
<section className="px-2 pb-2 pt-0">
@@ -491,7 +490,7 @@ const SkillsInstalledPage: React.FC = () => {
pending
</span>
)}
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-5 w-5 px-0 flex-shrink-0 text-muted-foreground hover:text-[var(--status-error)] opacity-0 group-hover:opacity-100 transition-opacity"
onClick={(e) => {
@@ -500,7 +499,7 @@ const SkillsInstalledPage: React.FC = () => {
}}
>
<RiDeleteBinLine className="h-3 w-3" />
</ButtonSmall>
</Button>
</div>
))}
</div>
@@ -511,14 +510,14 @@ const SkillsInstalledPage: React.FC = () => {
{/* Save action */}
<div className="px-2 py-1">
<ButtonSmall
<Button
onClick={handleSave}
disabled={isSaving || !hasSkillChanges}
size="xs"
className="!font-normal"
>
{isSaving ? 'Saving...' : isNewSkill ? 'Create Skill' : 'Save Changes'}
</ButtonSmall>
</Button>
</div>
</div>
@@ -540,16 +539,17 @@ const SkillsInstalledPage: React.FC = () => {
</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => setDeleteFilePath(null)}
disabled={isDeletingFile}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleConfirmDeleteFile} disabled={isDeletingFile} className="bg-[var(--status-error)] hover:bg-[var(--status-error)]/90 text-white border-0">
</Button>
<Button size="sm" variant="destructive" onClick={handleConfirmDeleteFile} disabled={isDeletingFile}>
Delete
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -603,7 +603,8 @@ const SkillsInstalledPage: React.FC = () => {
</div>
)}
<DialogFooter className="mt-4">
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => {
setIsFileDialogOpen(false);
@@ -611,10 +612,10 @@ const SkillsInstalledPage: React.FC = () => {
}}
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleSaveFile} disabled={isLoadingFile || !hasFileChanges}>
</Button>
<Button size="sm" onClick={handleSaveFile} disabled={isLoadingFile || !hasFileChanges}>
{editingFilePath ? 'Save Changes' : 'Create File'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { toast } from '@/components/ui';
import { isMobileDeviceViaCSS } from '@/lib/device';
@@ -207,13 +206,13 @@ export const SkillsSidebar: React.FC<SkillsSidebarProps> = ({ onItemSelect }) =>
<SettingsProjectSelector className="mb-3" />
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">Total {skills.length}</span>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 -my-1 text-muted-foreground"
onClick={handleCreateNew}
>
<RiAddLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</div>
</div>
@@ -347,17 +346,18 @@ export const SkillsSidebar: React.FC<SkillsSidebarProps> = ({ onItemSelect }) =>
</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
className="text-foreground hover:bg-interactive-hover hover:text-foreground"
variant="ghost"
onClick={() => setDeleteDialogSkill(null)}
disabled={isDeletePending}
className="text-foreground hover:bg-interactive-hover hover:text-foreground"
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleConfirmDeleteSkill} disabled={isDeletePending}>
</Button>
<Button size="sm" onClick={handleConfirmDeleteSkill} disabled={isDeletePending}>
Delete
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -383,16 +383,17 @@ export const SkillsSidebar: React.FC<SkillsSidebarProps> = ({ onItemSelect }) =>
}}
/>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
className="text-foreground hover:bg-interactive-hover hover:text-foreground"
variant="ghost"
onClick={() => setRenameDialogSkill(null)}
className="text-foreground hover:bg-interactive-hover hover:text-foreground"
>
Cancel
</ButtonLarge>
<ButtonLarge onClick={handleRenameSkill}>
</Button>
<Button size="sm" onClick={handleRenameSkill}>
Rename
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -461,12 +462,12 @@ const SkillListItem: React.FC<SkillListItemProps> = ({
<DropdownMenu open={isMenuOpen} onOpenChange={onMenuOpenChange}>
<DropdownMenuTrigger asChild>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-6 w-6 px-0 flex-shrink-0 -mr-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100"
>
<RiMore2Line className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-fit min-w-20">
<DropdownMenuItem
@@ -9,7 +9,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
Select,
@@ -311,24 +311,26 @@ export const AddCatalogDialog: React.FC<AddCatalogDialogProps> = ({ open, onOpen
</div>
<DialogFooter>
<ButtonLarge variant="ghost" onClick={() => onOpenChange(false)}>
<Button size="sm" variant="ghost" onClick={() => onOpenChange(false)}>
Cancel
</ButtonLarge>
<ButtonLarge
</Button>
<Button
size="sm"
className="gap-2"
variant="ghost"
onClick={() => void handleScan()}
disabled={isScanning || !source.trim()}
className="gap-2"
>
<RiGitRepositoryLine className="h-4 w-4" />
{isScanning ? 'Scanning...' : 'Scan'}
</ButtonLarge>
<ButtonLarge
</Button>
<Button
size="sm"
onClick={() => void handleAdd()}
disabled={!scanOk || isDuplicate || !label.trim() || !source.trim()}
>
Add catalog
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -8,8 +8,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ButtonLarge } from '@/components/ui/button-large';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
@@ -73,8 +72,8 @@ export const InstallConflictsDialog: React.FC<InstallConflictsDialogProps> = ({
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">{conflicts.length} conflict(s)</span>
<div className="flex items-center gap-2">
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => setAll('skip')}>Skip all</ButtonSmall>
<ButtonSmall variant="outline" size="xs" className="!font-normal" onClick={() => setAll('overwrite')}>Overwrite all</ButtonSmall>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => setAll('skip')}>Skip all</Button>
<Button variant="outline" size="xs" className="!font-normal" onClick={() => setAll('overwrite')}>Overwrite all</Button>
</div>
</div>
@@ -113,15 +112,16 @@ export const InstallConflictsDialog: React.FC<InstallConflictsDialogProps> = ({
</div>
<DialogFooter>
<ButtonLarge variant="ghost" onClick={() => onOpenChange(false)}>
<Button size="sm" variant="ghost" onClick={() => onOpenChange(false)}>
Cancel
</ButtonLarge>
<ButtonLarge
</Button>
<Button
size="sm"
onClick={() => onConfirm(decisions)}
disabled={!canConfirm}
>
Continue
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -10,7 +10,6 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { ButtonLarge } from '@/components/ui/button-large';
import { Input } from '@/components/ui/input';
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { Checkbox } from '@/components/ui/checkbox';
@@ -487,15 +486,16 @@ export const InstallFromRepoDialog: React.FC<InstallFromRepoDialogProps> = ({ op
</div>
<DialogFooter className="flex-shrink-0">
<ButtonLarge variant="ghost" onClick={() => onOpenChange(false)}>
<Button size="sm" variant="ghost" onClick={() => onOpenChange(false)}>
Cancel
</ButtonLarge>
<ButtonLarge
</Button>
<Button
size="sm"
disabled={isInstalling || selectedDirs.length === 0 || !source.trim() || (scope === 'project' && !directoryOverride)}
onClick={() => void doInstall({})}
>
{isInstalling ? 'Installing…' : 'Install selected'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -9,7 +9,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ButtonLarge } from '@/components/ui/button-large';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
@@ -231,13 +231,15 @@ export const InstallSkillDialog: React.FC<InstallSkillDialogProps> = ({ open, on
</div>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => onOpenChange(false)}
>
Cancel
</ButtonLarge>
<ButtonLarge
</Button>
<Button
size="sm"
disabled={isInstalling || !item.installable || (scope === 'project' && !directoryOverride)}
onClick={() =>
void doInstall({
@@ -251,7 +253,7 @@ export const InstallSkillDialog: React.FC<InstallSkillDialogProps> = ({ open, on
}
>
{isInstalling ? 'Installing...' : 'Install'}
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,6 +1,6 @@
import React from 'react';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { SortableTabsStrip } from '@/components/ui/sortable-tabs-strip';
@@ -12,7 +12,6 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { ButtonLarge } from '@/components/ui/button-large';
import {
Select,
SelectContent,
@@ -195,7 +194,7 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
</SelectContent>
</Select>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal h-6 w-6 px-0"
@@ -210,10 +209,10 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
title="Refresh"
>
<RiRefreshLine className={cn("h-3.5 w-3.5", (isLoadingCatalog || isLoadingSource) && "animate-spin")} />
</ButtonSmall>
</Button>
{isCustomSource && (
<ButtonSmall
<Button
variant="ghost"
size="xs"
className="!font-normal h-6 w-6 px-0 text-[var(--status-error)] hover:text-[var(--status-error)]"
@@ -222,16 +221,16 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
title="Remove Catalog"
>
<RiDeleteBinLine className="h-3.5 w-3.5" />
</ButtonSmall>
</Button>
)}
<ButtonSmall
<Button
size="xs"
className="!font-normal gap-1"
onClick={() => setAddCatalogOpen(true)}
>
<RiAddLine className="h-3.5 w-3.5" /> Add Catalog
</ButtonSmall>
</Button>
</div>
<div className="py-1.5">
@@ -328,7 +327,7 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
) : null}
</div>
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal shrink-0"
@@ -339,7 +338,7 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
}}
>
Install
</ButtonSmall>
</Button>
</div>
</div>
);
@@ -350,7 +349,7 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
{isClawdHubSource && hasMoreClawdHub && !isLoadingSource && filtered.length > 0 && (
<div className="flex justify-center mt-2 px-2">
<ButtonSmall
<Button
variant="outline"
size="xs"
className="!font-normal"
@@ -358,7 +357,7 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
disabled={isLoadingMore}
>
{isLoadingMore ? 'Loading...' : 'Load More Skills'}
</ButtonSmall>
</Button>
</div>
)}
</div>
@@ -381,16 +380,17 @@ export const SkillsCatalogPage: React.FC<SkillsCatalogPageProps> = ({ mode, onMo
<DialogDescription>Are you sure you want to remove this catalog?</DialogDescription>
</DialogHeader>
<DialogFooter>
<ButtonLarge
<Button
size="sm"
variant="ghost"
onClick={() => setIsRemoveCatalogDialogOpen(false)}
disabled={isRemovingCatalog}
>
Cancel
</ButtonLarge>
<ButtonLarge className="bg-[var(--status-error)] hover:bg-[var(--status-error)]/90 text-white" onClick={() => void removeSelectedCatalog()} disabled={isRemovingCatalog}>
</Button>
<Button size="sm" variant="destructive" onClick={() => void removeSelectedCatalog()} disabled={isRemovingCatalog}>
Remove Catalog
</ButtonLarge>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,7 +1,7 @@
import React from 'react';
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
import { ProviderLogo } from '@/components/ui/ProviderLogo';
import { ButtonSmall } from '@/components/ui/button-small';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
@@ -111,7 +111,7 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
<SelectItem value="300000">5m</SelectItem>
</SelectContent>
</Select>
<ButtonSmall
<Button size="sm"
variant="ghost"
className="h-7 w-7 px-0 text-muted-foreground"
onClick={() => fetchAllQuotas()}
@@ -120,7 +120,7 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
disabled={isLoading}
>
<RiRefreshLine className={cn('h-3.5 w-3.5', isLoading && 'animate-spin')} />
</ButtonSmall>
</Button>
</div>
</div>
<div className="mt-2 flex items-center justify-between gap-2">