fix(ui): improve responsive layouts and refine API access page

- Fix overflow, clipped controls, and toolbar overlap in narrow windows
- Improve responsive layouts across usage, OAuth, agents, settings, and dialogs
- Unify API category navigation and compact provider rows and actions
- Preserve inherited provider priorities instead of displaying zero
- Add responsive layout regression tests and dense provider fixtures
- Bump proxy core version from 8.0.6 to 8.0.10
This commit is contained in:
lzt404 committed 2026-10-04 17:31:52 +08:00
1 parent c7d58128b9
commit 5a5eab96e2
17 files changed
+1798 -153

No files matched your search

+1 -1
View File
@@ -2058,7 +2058,7 @@ export function AgentsPage({ embedded = false, onConfigurationApplied }: AgentsP
disabled={busy}
>
<span className="agent-client-icon"><AgentMark definition={agent} /></span>
<span><strong>{agent.name}</strong><small>{listStatusText(status)}</small></span>
<span><strong title={agent.name}>{agent.name}</strong><small title={listStatusText(status)}>{listStatusText(status)}</small></span>
{status?.installed ? (
<i className="agent-installed-indicator" title={t('agents.clientDetected')} aria-hidden="true" />
) : null}
+16 -17
View File
@@ -336,7 +336,7 @@ const rowFromRecord = (
disabled: grouped ? providerGroupStatus(record) === 'disabled' : definitionFor(section).openAi
? readBoolean(record, 'disabled')
: excludedModels.some((model) => model.trim() === '*'),
priority: readNumber(record, 'priority'),
priority: record.priority == null ? null : readNumber(record, 'priority'),
authIndex: entry
? readString(entry, 'auth-index', 'authIndex')
: readString(record, 'auth-index', 'authIndex'),
@@ -1477,6 +1477,7 @@ export function ApiAccessPage() {
type="button"
key={definition.id}
className={definition.id === activeCategory ? 'active' : ''}
aria-pressed={definition.id === activeCategory}
onClick={() => {
setActiveCategory(definition.id);
feedback.clearNotice();
@@ -1496,6 +1497,10 @@ export function ApiAccessPage() {
<h2 title={t(activeDefinition.labelKey)}>{t(activeDefinition.labelKey)}</h2>
<span>{t('apiAccess.groups.summary', { count: rows.length })}</span>
</div>
<div className="management-toolbar compact-toolbar api-access-search">
<Search size={16} aria-hidden="true" />
<input value={filter} onChange={(event) => setFilter(event.currentTarget.value)} placeholder={t('apiAccess.search')} aria-label={t('apiAccess.search')} />
</div>
<div className="api-access-heading-tools">
<button type="button" className="secondary-button compact-button" onClick={() => void loadProviders()} disabled={loading || busy}>
<RefreshCw size={16} aria-hidden="true" />
@@ -1505,10 +1510,6 @@ export function ApiAccessPage() {
<Plus size={16} aria-hidden="true" />
{t('apiAccess.groups.add')}
</button>
<div className="management-toolbar compact-toolbar">
<Search size={16} aria-hidden="true" />
<input value={filter} onChange={(event) => setFilter(event.currentTarget.value)} placeholder={t('apiAccess.search')} />
</div>
</div>
</div>
@@ -1545,21 +1546,20 @@ export function ApiAccessPage() {
<div className="provider-row-main">
<div className="provider-row-title">
<strong title={row.name}>{row.name}</strong>
{row.remark ? <span>{row.remark}</span> : null}
{providerGroupStatus(row.record) === 'partial' ? <span className="state-pill">{t('apiAccess.groups.partial')}</span> : null}
{row.remark ? <span title={row.remark}>{row.remark}</span> : null}
</div>
<code title={t('apiAccess.keys.count', { count: row.apiKeys.length })}>
{row.apiKeys.length > 1
? t('apiAccess.keys.summary', { key: maskSecret(row.apiKey), count: row.apiKeys.length })
: maskSecret(row.apiKey)}
</code>
<span className="provider-row-url" title={row.baseUrl || undefined}>{row.baseUrl || t('apiAccess.defaultUrl')}</span>
{row.models.length > 0 ? <span className="provider-row-models">{t('apiAccess.models.summary', { count: row.models.length })}</span> : null}
</div>
{row.priority === null ? null : (
<div className="provider-row-meta">
<span>{t('apiAccess.priorityValue', { priority: row.priority })}</span>
<code title={t('apiAccess.keys.count', { count: row.apiKeys.length })}>
{row.apiKeys.length > 1
? t('apiAccess.keys.summary', { key: maskSecret(row.apiKey), count: row.apiKeys.length })
: maskSecret(row.apiKey)}
</code>
{row.models.length > 0 ? <span className="provider-row-models">{t('apiAccess.models.summary', { count: row.models.length })}</span> : null}
{row.priority === null ? null : <span>{t('apiAccess.priorityValue', { priority: row.priority })}</span>}
</div>
)}
</div>
<div className="provider-row-actions">
<button
type="button"
@@ -1582,7 +1582,6 @@ export function ApiAccessPage() {
<span className="switch-track" />
</span>
</label>
{providerGroupStatus(row.record) === 'partial' ? <span className="state-pill">{t('apiAccess.groups.partial')}</span> : null}
<button type="button" className="icon-button quiet" onClick={() => openEdit(row)} disabled={busy} title={t('common.edit')} aria-label={t('common.edit')}>
<Edit3 size={16} aria-hidden="true" />
</button>
+22 -18
View File
@@ -2616,22 +2616,26 @@ function PricingView({
</span>
</div>
<div className="usage-pricing-actions">
<input
value={search}
onChange={(event) => setSearch(event.currentTarget.value)}
placeholder={t('usage.pricing.search')}
aria-label={t('usage.pricing.search')}
/>
<button type="button" className="secondary-button" onClick={() => setDraft(emptyPriceDraft())}>
{t('usage.pricing.add')}
</button>
<select value={syncSource} onChange={(event) => changeSyncSource(event.currentTarget.value as 'models-dev' | 'litellm')} aria-label={t('usage.pricing.syncSource')}>
<option value="models-dev">Models.dev</option>
<option value="litellm">LiteLLM</option>
</select>
<button type="button" className="primary-button" disabled={syncing} onClick={() => void previewPrices()}>
{syncing ? t('usage.pricing.syncing') : t('usage.pricing.sync')}
</button>
<div className="usage-pricing-action-group">
<input
value={search}
onChange={(event) => setSearch(event.currentTarget.value)}
placeholder={t('usage.pricing.search')}
aria-label={t('usage.pricing.search')}
/>
<button type="button" className="secondary-button" onClick={() => setDraft(emptyPriceDraft())}>
{t('usage.pricing.add')}
</button>
</div>
<div className="usage-pricing-action-group">
<select value={syncSource} onChange={(event) => changeSyncSource(event.currentTarget.value as 'models-dev' | 'litellm')} aria-label={t('usage.pricing.syncSource')}>
<option value="models-dev">Models.dev</option>
<option value="litellm">LiteLLM</option>
</select>
<button type="button" className="primary-button" disabled={syncing} onClick={() => void previewPrices()}>
{syncing ? t('usage.pricing.syncing') : t('usage.pricing.sync')}
</button>
</div>
</div>
</div>
@@ -2749,7 +2753,7 @@ function PricingView({
) : null}
{visibleRows.length ? (
<div className="usage-table-wrap usage-pricing-table-wrap">
<div className="usage-table-wrap usage-pricing-table-wrap" tabIndex={0} role="region" aria-label={t('usage.tab.pricing')}>
<table className="usage-pricing-table">
<thead>
<tr>
@@ -2768,7 +2772,7 @@ function PricingView({
{visibleRows.map((row) => (
<tr key={row.model}>
<td>
<strong>{row.model}</strong>
<strong title={row.model}>{row.model}</strong>
</td>
<td>{compactNumber(row.requests)}</td>
<td>{compactNumber(row.totalTokens)}</td>
+58 -29
View File
@@ -9787,16 +9787,13 @@ body.table-col-resizing * {
overflow: auto;
}
.usage-pricing-panel {
min-height: 0;
overflow: auto;
}
/* Pricing Tab */
.usage-pricing-panel {
display: grid;
display: flex;
min-width: 0;
align-content: start;
min-height: 0;
flex-direction: column;
overflow: hidden;
gap: 14px;
padding: 16px;
border: 1px solid var(--theme-e3e1db);
@@ -9936,6 +9933,7 @@ body.table-col-resizing * {
.usage-pricing-toolbar {
display: flex;
flex: none;
align-items: center;
justify-content: space-between;
gap: 14px;
@@ -9944,6 +9942,7 @@ body.table-col-resizing * {
.usage-pricing-summary {
display: grid;
flex: 1 1 240px;
gap: 2px;
}
@@ -9961,13 +9960,26 @@ body.table-col-resizing * {
.usage-pricing-actions {
display: flex;
min-width: 0;
flex: 1 1 560px;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.usage-pricing-action-group {
display: flex;
min-width: 0;
flex: 1 1 250px;
align-items: center;
gap: 8px;
}
.usage-pricing-actions input,
.usage-pricing-actions select {
min-width: 180px;
width: 100%;
min-width: 0;
flex: 1 1 0;
height: 34px;
padding: 0 10px;
border: 1px solid var(--theme-d5d2cb);
@@ -9979,7 +9991,10 @@ body.table-col-resizing * {
.usage-pricing-actions button,
.usage-price-editor-actions button {
flex: none;
min-height: 34px;
height: 34px;
white-space: nowrap;
}
.usage-price-sync-dialog {
@@ -10035,6 +10050,10 @@ body.table-col-resizing * {
.usage-price-editor {
display: grid;
min-height: 0;
flex: 0 1 auto;
max-height: 50%;
overflow: auto;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 10px;
padding: 14px;
@@ -10073,13 +10092,26 @@ body.table-col-resizing * {
}
.usage-pricing-table-wrap {
min-height: 380px;
min-height: 120px;
}
.usage-pricing-table-wrap::-webkit-scrollbar,
.usage-pricing-table-wrap::-webkit-scrollbar:horizontal {
display: block;
width: 8px;
height: 8px;
}
.usage-pricing-table-wrap::-webkit-scrollbar-thumb {
border-radius: 4px;
background: var(--border-primary);
}
.usage-pricing-table {
width: 100%;
min-width: 980px;
border-collapse: collapse;
border-collapse: separate;
border-spacing: 0;
font-size: var(--font-size-meta);
}
@@ -10105,7 +10137,22 @@ body.table-col-resizing * {
.usage-pricing-table th:first-child,
.usage-pricing-table td:first-child {
text-align: center;
position: sticky;
left: 0;
min-width: 180px;
max-width: 240px;
overflow: hidden;
text-overflow: ellipsis;
box-shadow: 1px 0 0 var(--border-color);
}
.usage-pricing-table td:first-child {
z-index: 1;
background: var(--bg-primary);
}
.usage-pricing-table th:first-child {
z-index: 2;
}
.usage-price-row-actions {
@@ -11271,24 +11318,6 @@ body.table-col-resizing * {
grid-template-columns: 1fr;
}
.usage-pricing-toolbar {
align-items: stretch;
flex-direction: column;
}
.usage-pricing-actions {
display: grid;
grid-template-columns: 1fr;
}
.usage-pricing-actions input {
width: 100%;
}
.usage-price-editor {
grid-template-columns: 1fr;
}
.thinking-alias-workbench {
grid-template-columns: 1fr;
}
-31
View File
@@ -2976,11 +2976,6 @@
grid-template-columns: 1fr;
}
.usage-topbar {
align-items: stretch;
flex-direction: column;
}
.usage-tabs {
display: flex;
width: 100%;
@@ -2996,42 +2991,16 @@
padding-inline: 12px;
}
.usage-topbar-actions {
width: 100%;
}
.usage-events-summary-left,
.usage-events-summary-right {
width: 100%;
justify-content: space-between;
}
.usage-collector-state {
flex: 1;
}
.usage-analysis-grid {
grid-template-columns: 1fr;
}
.usage-pricing-toolbar {
align-items: stretch;
flex-direction: column;
}
.usage-pricing-actions {
display: grid;
grid-template-columns: 1fr;
}
.usage-pricing-actions input {
width: 100%;
}
.usage-price-editor {
grid-template-columns: 1fr;
}
.auth-files-toolbar {
grid-template-columns: 18px minmax(0, 1fr);
}
+4
View File
@@ -1,3 +1,7 @@
@import '../styles.css';
@import './feature-pages.css';
@import './ui-refinements.css';
@import './responsive-shell-usage.css';
@import './responsive-providers.css';
@import './responsive-agents.css';
@import './responsive-settings.css';
+244
View File
@@ -0,0 +1,244 @@
/* Use the space left for the workbench, including the app sidebar and padding. */
.agents-page:not(.agents-page-embedded) {
container: agent-workspace / inline-size;
}
@container agent-workspace (max-width: 760px) {
.app-shell:has(.agents-page:not(.agents-page-embedded)) .agent-workbench {
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr);
gap: 12px;
}
.app-shell:has(.agents-page:not(.agents-page-embedded)) .agent-client-list {
height: auto;
max-height: none;
gap: 6px;
padding: 10px 12px;
}
.agents-page:not(.agents-page-embedded) .agent-list-items {
display: grid;
flex: none;
grid-auto-flow: column;
grid-auto-columns: 192px;
grid-template-columns: none;
grid-template-rows: auto;
overflow-x: auto;
overflow-y: hidden;
padding: 0 0 4px;
scrollbar-gutter: auto;
scroll-snap-type: x proximity;
}
.agents-page:not(.agents-page-embedded) .agent-list-items button {
min-height: 58px;
scroll-snap-align: start;
}
.agents-page:not(.agents-page-embedded) .agent-list-items strong,
.agents-page:not(.agents-page-embedded) .agent-list-items small {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.agent-save-bar,
.agent-codex-save-actions,
.agent-signin-label,
.agent-section-heading-actions {
flex-wrap: wrap;
}
.agent-save-bar .agent-save-feedback {
flex-basis: 180px;
}
.agent-save-actions button,
.agent-management-actions button {
max-width: 100%;
}
.agent-section-heading > div:first-child,
.agent-claude-code-disable-compact > span:first-child {
overflow-wrap: anywhere;
}
@container agent-panel (max-width: 640px) {
.agent-desktop-models > .agent-section-heading {
align-items: flex-start;
flex-direction: column;
}
.agent-desktop-models > .agent-section-heading > .agent-section-heading-actions {
width: 100%;
justify-content: flex-start;
}
.agent-desktop-model-fields {
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
}
.agent-desktop-model-field:first-child {
grid-column: 1 / -1;
}
.agent-desktop-model-actions {
height: 44px;
justify-self: end;
}
.agent-status-grid,
.agent-status-grid.dual-install-status-grid,
.agent-status-grid.pi-status-grid {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr));
}
.codex-session-overview-head,
.codex-session-list-head {
flex-wrap: wrap;
align-items: flex-start;
}
.codex-session-selection-actions {
justify-content: flex-start;
}
.codex-session-pagination {
flex-wrap: wrap;
}
}
@container agent-panel (max-width: 420px) {
.agent-subpage-tabs {
width: fit-content;
overflow-x: auto;
}
.agent-subpage-tabs button {
flex: none;
width: auto;
padding-inline: 10px;
}
.agent-signin-explanation dl > div {
grid-template-columns: minmax(0, 1fr);
gap: 4px;
}
.codex-session-meta,
.codex-session-row:has(.codex-session-checkbox) .codex-session-meta {
grid-template-columns: auto minmax(0, 1fr);
gap: 6px;
}
.codex-session-meta time {
grid-column: 1 / -1;
justify-self: start;
}
}
/* Catalog forms must respond to the editor width, not the whole dialog. */
.codex-catalog-editor {
container: catalog-editor / inline-size;
}
.codex-catalog-sidebar,
.codex-catalog-form > label,
.codex-catalog-models > button {
min-width: 0;
}
.codex-catalog-model-heading,
.codex-catalog-footer,
.codex-catalog-footer > div:last-child,
.codex-catalog-confirm > div > div {
flex-wrap: wrap;
}
.codex-catalog-model-heading > button {
flex: none;
max-width: 100%;
}
.codex-catalog-footer > div:last-child {
margin-left: auto;
}
.codex-catalog-hint,
.codex-catalog-heading p {
overflow-wrap: anywhere;
}
@container catalog-editor (max-width: 500px) {
.codex-catalog-form,
.harness-reasoning-levels {
grid-template-columns: minmax(0, 1fr);
}
}
/* Keep the model list beside the editor on small desktop windows so it does
not consume most of the dialog's available height. */
@media (min-width: 600px) and (max-width: 900px) {
.codex-catalog-body,
.harness-catalog-dialog .codex-catalog-body {
grid-template-columns: 180px minmax(0, 1fr);
grid-template-rows: minmax(0, 1fr);
}
.codex-catalog-sidebar {
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr) auto;
gap: 8px;
padding: 10px;
border-right: 1px solid var(--theme-d5d2cb);
border-bottom: 0;
}
.harness-catalog-dialog .codex-catalog-sidebar {
grid-template-rows: auto auto minmax(0, 1fr) auto;
}
.codex-catalog-sidebar > *,
.harness-catalog-dialog .codex-catalog-sidebar > * {
grid-column: 1;
grid-row: auto;
}
.codex-catalog-footer {
flex-direction: row;
gap: 8px;
}
.codex-catalog-footer > div:last-child {
display: flex;
}
}
.agent-backup-modal {
container: agent-backup / inline-size;
}
.agent-backup-modal footer {
flex-wrap: wrap;
}
.agent-backup-columns nav {
min-width: 0;
}
.agent-backup-columns nav button {
overflow-wrap: anywhere;
}
@container agent-backup (max-width: 680px) {
.agent-backup-columns {
grid-template-columns: minmax(0, 1fr);
}
.agent-backup-columns nav {
max-height: 160px;
}
}
+435
View File
@@ -0,0 +1,435 @@
/* Keep API navigation above the list at every width. */
.api-access-page .real-provider-workbench {
grid-template-columns: minmax(0, 1fr);
gap: 16px;
}
.api-access-page .provider-category-panel {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 4px;
height: auto;
padding: 8px;
}
.api-access-page .provider-category-panel button {
grid-template-columns: 24px minmax(0, auto) auto;
justify-content: center;
gap: 8px;
height: 50px;
min-height: 50px;
padding: 8px;
border-radius: 8px;
}
.api-access-page .provider-category-panel button.active {
background: var(--ui-accent-soft);
border-color: color-mix(in srgb, var(--ui-accent) 20%, transparent);
color: var(--ui-accent);
}
.api-access-page .provider-category-panel .provider-logo {
width: 24px;
height: 24px;
}
.api-access-page .provider-category-panel span {
white-space: normal;
overflow-wrap: normal;
overflow: hidden;
text-overflow: clip;
}
.api-access-page .provider-category-panel strong {
justify-self: center;
min-width: 22px;
padding: 2px 5px;
border-radius: 6px;
background: var(--bg-secondary);
color: var(--text-quaternary);
font-size: 12px;
line-height: 18px;
text-align: center;
}
.api-access-page .provider-category-panel .active strong {
background: color-mix(in srgb, var(--ui-accent) 10%, var(--bg-primary));
color: var(--ui-accent);
}
.api-access-page .provider-resource-panel {
container: provider-resources / inline-size;
min-width: 0;
min-height: 0;
}
.api-access-page .management-panel-heading {
display: grid;
grid-template-columns: auto minmax(180px, 1fr) auto;
grid-template-areas: 'title search actions';
gap: 14px 24px;
align-items: center;
}
.api-access-page .management-panel-heading > div:first-child {
grid-area: title;
text-align: left;
}
.api-access-page .api-access-search {
grid-area: search;
width: 100%;
max-width: 440px;
justify-self: end;
}
.api-access-page .api-access-heading-tools {
grid-area: actions;
display: flex;
width: auto;
flex: none;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.api-access-page .api-access-heading-tools > button {
flex: 0 0 auto;
width: auto;
}
.api-access-page .real-provider-list {
margin-top: 18px;
}
.api-access-page .real-provider-row {
grid-template-columns: 24px minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
min-height: 104px;
padding: 16px 0;
}
.api-access-page .real-provider-row:last-child {
border-bottom: 0;
padding-bottom: 0;
}
.api-access-page .provider-drag-handle {
grid-column: 1;
grid-row: 1;
width: 24px;
min-width: 24px;
height: 32px;
padding: 0;
margin: 0;
align-self: start;
border-color: transparent;
background: transparent;
box-shadow: none;
}
.api-access-page .provider-row-main {
grid-column: 2;
grid-row: 1;
gap: 7px;
}
.api-access-page .provider-row-title {
align-items: baseline;
flex-wrap: wrap;
gap: 2px 10px;
}
.api-access-page .provider-row-title strong {
max-width: 100%;
font-size: 15px;
line-height: 22px;
text-overflow: ellipsis;
white-space: nowrap;
}
.api-access-page .provider-row-title > span:not(.state-pill) {
min-width: 0;
max-width: 100%;
overflow: hidden;
color: var(--text-quaternary);
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.api-access-page .provider-row-title .state-pill {
min-height: 22px;
padding: 1px 7px;
font-size: 11px;
line-height: 18px;
}
.api-access-page .provider-row-main > .provider-row-url {
overflow: hidden;
font-size: 13px;
line-height: 20px;
text-overflow: ellipsis;
white-space: nowrap;
}
.api-access-page .provider-row-meta {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
gap: 6px 12px;
padding: 0;
line-height: 20px;
}
.api-access-page .provider-row-meta code {
min-width: 0;
max-width: 100%;
overflow-wrap: anywhere;
color: var(--text-quaternary);
font-size: 12px;
}
.api-access-page .provider-row-meta span {
flex: none;
color: var(--text-quaternary);
font-size: 12px;
}
.api-access-page .provider-row-actions {
grid-column: 3;
grid-row: 1;
flex-wrap: wrap;
justify-content: flex-end;
gap: 8px;
max-width: 340px;
}
.api-access-page .provider-enabled-control {
min-width: 0;
}
.api-access-page .provider-row-actions .icon-button {
width: 32px;
height: 32px;
min-width: 32px;
}
/* Compact tabs keep every category visible instead of wrapping a lone tab. */
@container workspace (max-width: 820px) {
.api-access-page .provider-category-panel button {
grid-template-columns: 24px auto;
grid-template-rows: 24px auto;
gap: 4px 8px;
height: auto;
min-height: 68px;
}
.api-access-page .provider-category-panel span {
grid-column: 1 / -1;
grid-row: 2;
font-size: 12px;
text-align: center;
white-space: normal;
overflow-wrap: normal;
}
.api-access-page .provider-category-panel strong {
grid-column: 2;
grid-row: 1;
}
}
@container provider-resources (max-width: 720px) {
.api-access-page .management-panel-heading {
grid-template-columns: minmax(0, 1fr) auto;
grid-template-areas: 'title actions' 'search search';
column-gap: 12px;
}
.api-access-page .api-access-search {
max-width: none;
}
}
@container provider-resources (max-width: 580px) {
.api-access-page .real-provider-row {
grid-template-columns: 24px minmax(0, 1fr);
gap: 10px;
}
.api-access-page .provider-row-actions {
grid-column: 2;
grid-row: 2;
max-width: none;
justify-content: flex-start;
}
}
/* Keep controls compact while allowing complete groups to move to the next line. */
.auth-files-page .management-heading-actions {
min-width: 0;
max-width: 100%;
flex-wrap: wrap;
}
.auth-files-page .management-heading-actions button {
flex: 0 0 auto;
width: auto;
}
.auth-files-page .real-auth-files-panel {
container: credential-files / inline-size;
min-width: 0;
}
.auth-files-page .auth-files-toolbar select {
min-width: 0;
}
@container credential-files (max-width: 680px) {
.auth-files-page .auth-files-toolbar {
grid-template-columns: 18px minmax(0, 1fr) minmax(0, 1fr);
gap: 0 9px;
}
.auth-files-page .auth-files-toolbar input {
grid-column: 2 / -1;
}
.auth-files-page .auth-files-toolbar select:first-of-type {
grid-column: 1 / 3;
}
.auth-files-page .auth-files-toolbar select:last-of-type {
grid-column: 3;
}
.auth-files-page .auth-files-toolbar select {
border-top: 1px solid var(--theme-e3e1db);
border-left: 0;
}
}
.oauth-login-page > .oauth-grid {
grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr));
}
.oauth-browser-picker {
min-width: 0;
max-width: 100%;
flex-wrap: wrap;
}
.oauth-browser-picker select {
min-width: 0;
max-width: 100%;
flex: 0 1 240px;
}
.oauth-card .oauth-auth-url-actions,
.oauth-card .management-card-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.oauth-card .management-card-actions > button {
flex: 1 1 auto;
}
.oauth-card .oauth-callback-row {
grid-template-columns: minmax(0, 1fr) auto;
}
.oauth-card .oauth-callback-row > button {
width: auto;
white-space: nowrap;
}
.quota-group-heading {
flex-wrap: wrap;
}
.quota-group-heading .quota-group-actions {
flex: 1 1 280px;
}
.quota-group-actions .muted-summary {
width: auto;
}
.real-quota-row > div:first-child {
flex-wrap: wrap;
}
.real-quota-row small,
.quota-reset-credit-summary span {
min-width: 0;
white-space: normal;
overflow-wrap: anywhere;
}
/* Optional key selectors must not shift fixed dialog grid tracks onto the model list. */
.model-discovery-dialog.provider-health-dialog {
display: flex;
flex-direction: column;
height: min(660px, calc(100dvh - 48px));
min-height: 0;
overflow: auto;
}
.provider-health-dialog > :not(.provider-health-model-list) {
flex-shrink: 0;
}
.provider-health-dialog .provider-health-model-list {
flex: 1 1 180px;
min-height: 100px;
height: auto;
}
.provider-health-dialog .model-discovery-header > div {
flex-wrap: wrap;
}
.provider-health-dialog .model-discovery-header span {
white-space: normal;
overflow-wrap: anywhere;
}
.provider-health-dialog .provider-health-key-selector {
min-width: 0;
padding: 0;
}
.model-discovery-dialog .model-discovery-toolbar,
.model-discovery-dialog .model-discovery-actions,
.model-discovery-dialog .model-transfer-summary {
flex-wrap: wrap;
}
.model-discovery-dialog .model-discovery-toolbar > span {
white-space: normal;
}
.api-provider-dialog .provider-group-heading,
.api-provider-dialog .model-config-heading,
.api-provider-dialog .thinking-level-heading {
flex-wrap: wrap;
}
@container workspace (max-width: 760px) {
.oauth-browser-picker {
justify-content: flex-start;
}
.auth-files-page .management-heading-actions,
.quota-group-heading .quota-group-actions {
justify-content: flex-start;
}
}
+342
View File
@@ -0,0 +1,342 @@
/* Keep each section responsive to its available content width, including the
sidebar and the narrower cards in the two-column home layout. */
.home-quick-actions {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
@container workspace (max-width: 1080px) {
.home-quick-actions {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@container workspace (max-width: 480px) {
.home-quick-actions {
grid-template-columns: minmax(0, 1fr);
}
}
.client-api-panel {
container: home-api / inline-size;
}
.client-api-panel .client-api-heading {
flex-wrap: wrap;
gap: 10px;
}
.client-api-panel .client-api-heading > div {
flex: 1 1 260px;
}
.client-api-panel .client-api-key-actions {
max-width: 100%;
flex-shrink: 1;
}
.client-api-key-code {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
@container home-api (max-width: 480px) {
.client-api-card {
height: auto;
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.client-api-card-heading {
flex: none;
width: auto;
min-width: 0;
}
}
/* The download source is one control group: move the group together, then let
the select shrink while the action retains a readable label. */
.version-management-page > .version-list {
padding: 0;
}
.version-source-row {
display: flex;
flex-wrap: wrap;
gap: 16px 24px;
}
.version-source-copy {
flex: 1 1 240px;
}
.version-source-control {
grid-template-columns: minmax(0, 1fr) auto;
width: min(360px, 100%);
min-width: 0;
}
.version-source-control label,
.version-source-control select {
min-width: 0;
width: 100%;
}
.version-source-add-button {
grid-column: auto;
white-space: nowrap;
}
@container workspace (max-width: 620px) {
.app-release-notes-heading {
flex-wrap: wrap;
padding: 16px;
}
.app-release-notes-body {
padding: 0 16px 16px;
}
.app-release-notes-markdown {
gap: 14px 12px;
}
.app-release-notes-markdown > .release-notes-category {
max-width: 80px;
}
}
/* Settings have variable-length descriptions; fixed row heights and controls
sized from the window instead of the workspace can make adjacent cards overlap. */
.config-page .config-panel-heading,
.config-page .config-heading-actions,
.config-page .config-network-section-heading,
.config-page .config-proxy-heading {
flex-wrap: wrap;
}
.config-page .config-panel-heading {
gap: 10px 14px;
}
.config-page .config-heading-actions {
margin-left: auto;
}
.config-keys-panel {
grid-template-rows: auto minmax(0, 1fr);
}
.config-network-grid {
grid-auto-rows: minmax(154px, auto);
}
.config-network-field small,
.config-diagnostics-setting-copy,
.config-software-setting-copy {
overflow-wrap: anywhere;
}
.config-diagnostics-actions,
.config-management-actions {
flex-wrap: wrap;
}
@container workspace (max-width: 900px) {
.config-network-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.config-diagnostics-toggle-grid {
grid-template-columns: minmax(0, 1fr);
}
}
@container workspace (max-width: 700px) {
.config-diagnostics-fields {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.config-software-setting-row {
gap: 16px;
padding: 15px 16px;
}
.config-software-close-row {
align-items: stretch;
flex-direction: column;
}
.config-software-select {
width: 100%;
min-width: 0;
padding-left: 54px;
}
.config-diagnostics-footer,
.config-management-form-footer {
grid-template-columns: minmax(0, 1fr);
gap: 8px;
}
.config-diagnostics-actions {
justify-content: flex-end;
}
}
@container workspace (max-width: 560px) {
.config-network-grid,
.config-diagnostics-fields {
grid-template-columns: minmax(0, 1fr);
}
.config-network-grid {
grid-auto-rows: auto;
}
.config-software-select {
padding-left: 0;
}
.config-heading-title h2 {
white-space: normal;
}
}
/* Alias routes should keep their names readable before metadata and actions
wrap onto a second line. The editor uses its own width inside a modal. */
.thinking-alias-list-panel {
container: alias-list / inline-size;
}
.thinking-alias-dialog {
container: alias-editor / inline-size;
}
.thinking-alias-field {
min-width: 0;
}
@container alias-list (max-width: 560px) {
.thinking-alias-row {
grid-template-columns: minmax(0, 1fr) 34px;
}
.thinking-alias-route {
grid-column: 1 / -1;
}
.thinking-alias-badges {
flex-wrap: wrap;
justify-content: flex-start;
}
}
@container alias-editor (max-width: 580px) {
.thinking-effort-options {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
/* Keep novice-mode actions compact at intermediate widths. Existing phone
rules made every action full-width even when two controls easily fit. */
.simple-mode-topbar,
.simple-mode-topbar-right,
.simple-mode-brand-title,
.simple-mode-choice-title,
.simple-mode-api-model-heading,
.simple-mode-api-model-selection-heading {
flex-wrap: wrap;
}
.simple-mode-topbar-left,
.simple-mode-topbar-right,
.simple-mode-brand,
.simple-mode-brand-text {
min-width: 0;
}
.simple-mode-topbar-left {
flex: 1 1 340px;
}
.simple-mode-topbar-right {
flex: 0 1 auto;
justify-content: flex-end;
margin-left: auto;
}
.simple-mode-topbar-right > *,
.simple-mode-guide-toggle {
flex-shrink: 0;
}
.simple-mode-choice-title strong,
.simple-mode-brand-title strong {
white-space: normal;
overflow-wrap: anywhere;
}
.simple-mode-provider-card-foot {
flex-wrap: wrap;
}
.simple-mode-field .text-input,
.simple-mode-field .select-input {
min-width: 0;
}
@container workspace (max-width: 720px) {
.simple-mode-topbar-left,
.simple-mode-topbar-right {
width: 100%;
}
.simple-mode-topbar-right {
justify-content: flex-start;
}
.simple-mode-choice-grid,
.simple-mode-api-fields {
grid-template-columns: minmax(0, 1fr);
}
.simple-mode-api-actions,
.simple-mode-task-footer {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.simple-mode-api-actions button,
.simple-mode-task-footer > .primary-button,
.simple-mode-task-footer > .secondary-button {
width: auto;
}
.simple-mode-task-footer > .primary-button {
margin-left: auto;
}
}
@container workspace (max-width: 520px) {
.simple-mode-api-model-options {
grid-template-columns: minmax(0, 1fr);
}
.simple-mode-step-status-track {
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.simple-mode-step-status-connector {
display: none;
}
.simple-mode-step-status-copy strong,
.simple-mode-step-status-copy small {
white-space: normal;
overflow-wrap: anywhere;
}
}
+174
View File
@@ -0,0 +1,174 @@
/* Keep footer controls reachable when desktop navigation exceeds the height. */
@media (min-width: 901px) {
.sidebar-brand,
.sidebar-bottom {
flex-shrink: 0;
}
.sidebar > .nav-section {
min-height: 0;
margin-bottom: 18px;
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: thin;
}
}
/* Let toolbar rows keep their height instead of overlapping the table. */
.usage-events-summary {
flex: none;
flex-wrap: wrap;
}
.usage-events-summary-left,
.usage-events-summary-right {
width: auto;
max-width: 100%;
justify-content: flex-start;
}
.usage-events-summary-right {
margin-left: auto;
}
.usage-pagination-controls {
min-width: 0;
max-width: 100%;
flex-wrap: wrap;
}
.usage-topbar,
.usage-filter-panel {
flex-shrink: 0;
}
.usage-page-navigation,
.usage-topbar-actions {
max-width: 100%;
}
.usage-tabs,
.config-subpage-tabs,
.oauth-subpage-tabs {
min-width: 0;
max-width: 100%;
overflow-x: auto;
}
.usage-tabs button,
.config-subpage-tabs button,
.oauth-subpage-tabs button {
flex-shrink: 0;
white-space: nowrap;
}
.usage-topbar-actions {
min-width: 0;
flex-wrap: wrap;
}
.usage-collector-state {
max-width: 100%;
}
.usage-collector-state > span:last-child {
overflow: hidden;
text-overflow: ellipsis;
}
.usage-section-heading {
gap: 10px;
flex-wrap: wrap;
}
.usage-section-heading > div {
min-width: 0;
}
.usage-section-heading strong {
white-space: normal;
overflow-wrap: anywhere;
}
.usage-custom-range input {
min-width: 0;
max-width: 100%;
}
.usage-pricing-table-wrap:focus-visible {
outline: 2px solid var(--ui-accent);
outline-offset: -2px;
}
.usage-pricing-panel {
overflow: auto;
}
.usage-price-editor {
min-height: 160px;
max-height: min(320px, 40vh);
flex-shrink: 0;
}
.usage-storage-limit-editor {
min-width: 0;
max-width: 100%;
}
.usage-storage-limit-editor label {
min-width: 0;
flex: 1;
}
.usage-storage-limit-editor input {
min-width: 0;
width: 100%;
max-width: 168px;
}
.usage-storage-limit-editor button {
flex: none;
white-space: nowrap;
}
@container workspace (max-width: 760px) {
.usage-overview-layout {
grid-template-columns: minmax(0, 1fr);
grid-template-rows: max-content minmax(280px, 1fr) auto;
}
.usage-health-panel {
height: auto;
}
.usage-data-management-action {
flex-wrap: wrap;
gap: 12px;
}
.usage-data-management-action > div:first-child {
min-width: 0;
flex: 1 1 260px;
}
}
@container workspace (max-width: 540px) {
.usage-events-summary-right {
margin-left: 0;
}
.usage-storage-limit-editor {
flex-direction: row;
}
.usage-storage-limit-editor .primary-button {
width: auto;
}
}
@media (min-width: 761px) {
.usage-events-panel > .usage-table-wrap,
.usage-events-panel > .usage-empty {
min-height: 0;
}
}
+19 -36
View File
@@ -387,40 +387,6 @@ body, html, #root {
font-weight: var(--font-weight-semibold);
}
/* API access toolbar */
.api-access-page .management-panel-heading {
align-items: center;
flex-wrap: wrap;
}
.api-access-heading-tools {
display: flex;
min-width: 0;
flex: 1 1 420px;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.api-access-heading-tools .compact-toolbar {
width: min(280px, 100%);
flex: 1 1 180px;
}
@container workspace (max-width: 760px) {
.api-access-heading-tools {
width: 100%;
flex-basis: 100%;
flex-wrap: wrap;
justify-content: flex-start;
}
.api-access-heading-tools .compact-toolbar {
flex-basis: 100%;
}
}
/* 7. OAuth Management Page Polish */
.oauth-management-page .management-header h1 {
display: none;
@@ -618,13 +584,18 @@ body, html, #root {
gap: 8px;
}
.usage-records-page .usage-filter-group {
display: grid;
min-width: 0;
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.usage-records-page .usage-filter-item {
flex: 1 1 150px;
flex-direction: row;
align-items: center;
gap: 0;
min-width: 132px;
max-width: 210px;
min-width: 0;
height: 36px;
padding: 0 8px;
border: 1px solid var(--border-color);
@@ -688,6 +659,18 @@ body, html, #root {
color: var(--text-primary);
}
@container workspace (max-width: 880px) {
.usage-records-page .usage-filter-group {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@container workspace (max-width: 520px) {
.usage-records-page .usage-filter-group {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.usage-records-page .usage-section-heading strong {
color: #1d1d1f;
font-weight: 650;