diff --git a/webui/src/components/form/form.module.css b/webui/src/components/form/form.module.css index 54638847..2da07111 100644 --- a/webui/src/components/form/form.module.css +++ b/webui/src/components/form/form.module.css @@ -363,11 +363,8 @@ color: #fff; cursor: pointer; font: inherit; - font-size: 13px; font-weight: 600; line-height: 1.2; - min-height: 36px; - padding: 8px 12px; transition: transform 0.18s ease, border-color 0.18s ease, @@ -376,6 +373,34 @@ color 0.18s ease; } +.buttonSizeSm { + min-height: 32px; + padding: 6px 10px; + font-size: 13px; +} + +.buttonSizeMd { + min-height: 36px; + padding: 8px 12px; + font-size: 13px; +} + +.buttonSizeLg { + min-height: 40px; + padding: 10px 20px; + font-size: 14px; +} + +.buttonIcon { + width: var(--button-icon-size, 36px); + height: var(--button-icon-size, 36px); + min-height: var(--button-icon-size, 36px); + min-width: var(--button-icon-size, 36px); + padding: 0; + font-size: var(--button-icon-font-size, 15px); + line-height: 1; +} + .button:hover:not(:disabled) { transform: translateY(-1px); border-color: rgba(255, 255, 255, 0.18); @@ -394,6 +419,51 @@ transform: none; } +.buttonPrimary { + border-color: rgba(var(--accent-light-rgb), 0.45); + background: rgb(var(--accent-light-rgb)); + color: #000; +} + +.buttonPrimary:hover:not(:disabled) { + border-color: rgba(var(--accent-light-rgb), 0.55); + background: rgba(var(--accent-light-rgb), 0.95); + color: #000; +} + +.buttonPrimary:focus-visible { + border-color: rgba(var(--accent-light-rgb), 0.8); + box-shadow: 0 0 0 3px rgba(var(--accent-light-rgb), 0.16); +} + +.buttonPrimary:disabled { + opacity: 0.62; + background: rgba(var(--accent-light-rgb), 0.45); + color: rgba(0, 0, 0, 0.55); +} + +.buttonGhost { + border-color: transparent; + background: transparent; + color: rgba(255, 255, 255, 0.55); +} + +.buttonGhost:hover:not(:disabled) { + transform: none; + border-color: rgba(255, 255, 255, 0.14); + background: rgba(255, 255, 255, 0.07); + color: #fff; +} + +.buttonGhost:focus-visible { + border-color: rgba(var(--accent-light-rgb), 0.42); + box-shadow: 0 0 0 3px rgba(var(--accent-light-rgb), 0.12); +} + +.buttonGhost:disabled { + opacity: 0.5; +} + .formError { color: #ff8d8d; font-size: 12px; diff --git a/webui/src/components/form/form.test.tsx b/webui/src/components/form/form.test.tsx index 2feb7a2e..21a2cfa3 100644 --- a/webui/src/components/form/form.test.tsx +++ b/webui/src/components/form/form.test.tsx @@ -112,7 +112,9 @@ function FormDemo() { - + ); @@ -154,6 +156,9 @@ describe('form primitives', () => { expect(highPriority).toHaveAttribute('aria-pressed', 'true'); expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'Save' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Save' })).toHaveAttribute( + 'data-variant', + 'primary', + ); }); }); diff --git a/webui/src/components/form/form.tsx b/webui/src/components/form/form.tsx index 1a26870e..6d6b04fa 100644 --- a/webui/src/components/form/form.tsx +++ b/webui/src/components/form/form.tsx @@ -247,13 +247,35 @@ type BaseButtonProps = ComponentPropsWithoutRef; export type ButtonProps = Omit & { className?: string; + size?: 'sm' | 'md' | 'lg' | 'icon'; + variant?: 'default' | 'primary' | 'ghost'; }; export const Button = forwardRef(function Button( - { className, type = 'button', ...props }, + { className, size = 'md', type = 'button', variant = 'default', ...props }, ref, ) { - return ; + return ( + + ); }); export function FormError({ className, message }: { className?: string; message?: ReactNode }) { diff --git a/webui/src/routes/import/-ui/album-import-tab.tsx b/webui/src/routes/import/-ui/album-import-tab.tsx index 82d3fed3..aae1089d 100644 --- a/webui/src/routes/import/-ui/album-import-tab.tsx +++ b/webui/src/routes/import/-ui/album-import-tab.tsx @@ -298,18 +298,19 @@ function AlbumImportPanelContent({ viewModel }: { viewModel: AlbumImportViewMode if (event.key === 'Enter') onRunSearch(); }} /> - +
@@ -568,7 +569,7 @@ function AlbumMatchPanel({ viewModel }: { viewModel: AlbumImportViewModel }) {