diff --git a/webui/src/components/form/form.module.css b/webui/src/components/form/form.module.css
index 8f340d35..31120695 100644
--- a/webui/src/components/form/form.module.css
+++ b/webui/src/components/form/form.module.css
@@ -73,6 +73,7 @@
.select {
width: auto;
min-width: 130px;
+ box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
background:
@@ -95,7 +96,6 @@
font: inherit;
font-size: 13px;
line-height: 1.5;
- padding: 8px 32px 8px 12px;
transition:
border-color 0.18s ease,
background 0.18s ease,
@@ -107,6 +107,24 @@
cursor: pointer;
}
+.selectSizeSm {
+ min-height: 32px;
+ padding: 6px 30px 6px 10px;
+ background-position:
+ 0 0,
+ 0 0,
+ right 10px center;
+}
+
+.selectSizeMd {
+ min-height: 36px;
+ padding: 8px 32px 8px 12px;
+ background-position:
+ 0 0,
+ 0 0,
+ right 12px center;
+}
+
.select:hover {
border-color: rgba(255, 255, 255, 0.16);
background:
diff --git a/webui/src/components/form/form.test.tsx b/webui/src/components/form/form.test.tsx
index 7a060555..9c4923cb 100644
--- a/webui/src/components/form/form.test.tsx
+++ b/webui/src/components/form/form.test.tsx
@@ -138,6 +138,7 @@ describe('form primitives', () => {
expect(screen.getByText('Short summary')).toBeInTheDocument();
expect(screen.getByRole('alert')).toHaveTextContent('Validation failed');
expect(screen.getByLabelText('Status')).toHaveValue('open');
+ expect(screen.getByLabelText('Status')).toHaveAttribute('data-size', 'md');
fireEvent.change(screen.getByLabelText('Status'), { target: { value: 'resolved' } });
expect(screen.getByLabelText('Status')).toHaveValue('resolved');
@@ -176,4 +177,15 @@ describe('form primitives', () => {
'primary',
);
});
+
+ it('supports compact select sizing', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByLabelText('Compact')).toHaveAttribute('data-size', 'sm');
+ });
});
diff --git a/webui/src/components/form/form.tsx b/webui/src/components/form/form.tsx
index 11e46227..02958daa 100644
--- a/webui/src/components/form/form.tsx
+++ b/webui/src/components/form/form.tsx
@@ -77,13 +77,32 @@ export const TextArea = forwardRef(function
return ;
});
-export type SelectProps = SelectHTMLAttributes;
+export type SelectSize = 'sm' | 'md';
+
+export type SelectProps = Omit, 'className' | 'size'> & {
+ className?: string;
+ size?: SelectSize;
+};
export const Select = forwardRef(function Select(
- { className, ...props },
+ { className, size = 'md', ...props },
ref,
) {
- return ;
+ return (
+
+ );
});
type BaseCheckboxProps = ComponentPropsWithoutRef;
diff --git a/webui/src/routes/import/-route.test.tsx b/webui/src/routes/import/-route.test.tsx
index e9e01466..f4871df7 100644
--- a/webui/src/routes/import/-route.test.tsx
+++ b/webui/src/routes/import/-route.test.tsx
@@ -303,6 +303,11 @@ describe('import route', () => {
expect(await screen.findByRole('button', { name: /^Needs Review\s*1$/ })).toBeInTheDocument();
expect(screen.getAllByText('Album A').length).toBeGreaterThan(0);
+ const intervalSelect = document.getElementById('auto-import-interval');
+ if (!(intervalSelect instanceof HTMLElement)) {
+ throw new Error('auto-import interval select missing');
+ }
+ expect(intervalSelect).toHaveAttribute('data-size', 'sm');
expect(getFetchUrls().some((url) => url.includes('/api/import/staging/groups'))).toBe(false);
expect(getFetchUrls().some((url) => url.includes('/api/import/staging/suggestions'))).toBe(
false,
diff --git a/webui/src/routes/import/-ui/auto-import-tab.tsx b/webui/src/routes/import/-ui/auto-import-tab.tsx
index 63ee5f57..c3f1d0ec 100644
--- a/webui/src/routes/import/-ui/auto-import-tab.tsx
+++ b/webui/src/routes/import/-ui/auto-import-tab.tsx
@@ -214,6 +214,7 @@ export function AutoImportPanel({
Interval: