diff --git a/src/components/SelectMenu.css b/src/components/SelectMenu.css index 7d82f43..764d1fe 100644 --- a/src/components/SelectMenu.css +++ b/src/components/SelectMenu.css @@ -53,8 +53,11 @@ position: fixed; z-index: 45; display: grid; - min-width: 180px; - padding: 6px; + box-sizing: border-box; + width: max-content; + min-width: 0; + max-width: min(320px, calc(100vw - 24px)); + padding: 4px; border: 1px solid var(--border-color); border-radius: 10px; background: var(--bg-card); @@ -69,12 +72,12 @@ .select-menu-option { display: grid; - grid-template-columns: minmax(0, 1fr) 16px; + grid-template-columns: minmax(0, max-content) 16px; align-items: center; gap: 8px; width: 100%; - min-height: 36px; - padding: 6px 10px; + min-height: 32px; + padding: 4px 8px; border: 0; border-radius: 6px; background: transparent; diff --git a/src/components/SelectMenu.tsx b/src/components/SelectMenu.tsx index 5ff1b1d..06cb131 100644 --- a/src/components/SelectMenu.tsx +++ b/src/components/SelectMenu.tsx @@ -21,6 +21,31 @@ type MenuLayout = { height: number; }; +const measureMenu = (menu: HTMLDivElement) => { + const menuStyle = menu.getAttribute('style'); + const optionButtons = [...menu.querySelectorAll('.select-menu-option')]; + const optionStyles = optionButtons.map((option) => option.getAttribute('style')); + menu.style.width = 'max-content'; + menu.style.maxWidth = 'none'; + menu.style.height = 'auto'; + menu.style.maxHeight = 'none'; + menu.style.visibility = 'hidden'; + optionButtons.forEach((option) => { + option.style.width = 'max-content'; + option.style.maxWidth = 'none'; + option.style.gridTemplateColumns = 'max-content 16px'; + }); + const rect = menu.getBoundingClientRect(); + if (menuStyle === null) menu.removeAttribute('style'); + else menu.setAttribute('style', menuStyle); + optionButtons.forEach((option, index) => { + const style = optionStyles[index]; + if (style === null) option.removeAttribute('style'); + else option.setAttribute('style', style); + }); + return { width: Math.ceil(rect.width), height: Math.ceil(rect.height) }; +}; + export function SelectMenu({ value, options, @@ -44,18 +69,23 @@ export function SelectMenu({ const updateLayout = useCallback(() => { const root = rootRef.current; + const menu = menuRef.current; if (!root) return; const rect = root.getBoundingClientRect(); const edgeGap = 12; const triggerGap = 6; - const preferredHeight = Math.min(282, Math.max(options.length, 1) * 42 + 18); - const minimumHeight = 88; + const measured = menu ? measureMenu(menu) : null; + const contentWidth = measured && measured.width > 0 ? measured.width : rect.width; + const contentHeight = measured && measured.height > 0 + ? measured.height + : Math.max(options.length, 1) * 36 + 12; const spaceBelow = Math.max(0, window.innerHeight - edgeGap - rect.bottom - triggerGap); const spaceAbove = Math.max(0, rect.top - triggerGap - edgeGap); - const placeAbove = spaceBelow < minimumHeight && spaceAbove > spaceBelow; + const placeAbove = spaceBelow < contentHeight && spaceAbove > spaceBelow; const available = placeAbove ? spaceAbove : spaceBelow; - const height = Math.min(preferredHeight, Math.max(Math.min(minimumHeight, available), available)); - const width = Math.min(320, Math.max(rect.width, 180)); + const maxWidth = Math.max(edgeGap, window.innerWidth - edgeGap * 2); + const width = Math.min(320, maxWidth, contentWidth); + const height = Math.min(contentHeight, Math.max(available, Math.min(contentHeight, 36))); const maxLeft = Math.max(edgeGap, window.innerWidth - edgeGap - width); const left = Math.min(Math.max(edgeGap, rect.left), maxLeft); const desiredTop = placeAbove ? rect.top - triggerGap - height : rect.bottom + triggerGap; diff --git a/src/pages/UsageAnalysisView.css b/src/pages/UsageAnalysisView.css index 8cc9781..9e7cc41 100644 --- a/src/pages/UsageAnalysisView.css +++ b/src/pages/UsageAnalysisView.css @@ -57,26 +57,36 @@ .usage-analysis-metric { display: flex; flex: none; - gap: 2px; - padding: 3px; - border-radius: 8px; - background: var(--bg-secondary); + gap: 8px; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; } .usage-analysis-metric button { padding: 5px 9px; - border: 0; - border-radius: 5px; + border: 1px solid transparent; + border-radius: 8px; background: transparent; - color: var(--text-secondary); + color: var(--text-tertiary); font-size: 12px; + font-weight: 500; white-space: nowrap; } -.usage-analysis-metric button[aria-pressed='true'] { - background: var(--bg-primary); - color: var(--text-primary); - box-shadow: 0 1px 3px rgb(0 0 0 / 9%); +.usage-analysis-metric button:hover { + color: var(--ui-accent); + background: color-mix(in srgb, var(--ui-accent) 5%, var(--bg-card)); +} + +.usage-analysis-metric button[aria-pressed='true'], +.usage-analysis-metric button[aria-pressed='true']:hover { + border-color: transparent; + background: color-mix(in srgb, var(--ui-accent) 10%, var(--bg-card)); + color: var(--ui-accent); + font-weight: 600; + box-shadow: none; } .usage-model-comparison { diff --git a/src/styles/workspace-white.css b/src/styles/workspace-white.css index b2fb8ac..a24a4c9 100644 --- a/src/styles/workspace-white.css +++ b/src/styles/workspace-white.css @@ -43,7 +43,7 @@ :root:not([data-theme='dark']) .workspace :is( .agent-model-section, .agent-auth-segmented, .routing-segmented, - .plugin-tabs, .usage-analysis-metric, + .plugin-tabs, .credential-quota, .usage-collector-state ) { background: #fff; @@ -73,8 +73,7 @@ :root:not([data-theme='dark']) .workspace :is( .agent-list-items button.active, - .routing-segmented button.active, .plugin-tabs button.active, - .usage-analysis-metric button[aria-pressed='true'] + .routing-segmented button.active, .plugin-tabs button.active ) { background: #fff; border: 1px solid var(--ui-accent); @@ -111,6 +110,14 @@ box-shadow: none; } +:root:not([data-theme='dark']) .workspace .usage-analysis-metric button[aria-pressed='true'], +:root:not([data-theme='dark']) .workspace .usage-analysis-metric button[aria-pressed='true']:hover { + background: color-mix(in srgb, var(--ui-accent) 10%, var(--bg-card)); + border-color: transparent; + color: var(--ui-accent); + box-shadow: none; +} + /* Do not let local subpage palettes bring the neutral fills back. */ :root:not([data-theme='dark']) .workspace .usage-tab-panel { --usage-page-soft: #fff;