feat(app): flatten manage models into v2 rows (#56029)

This commit is contained in:
usrnk1
2026-10-16 12:20:52 +02:00
committed by GitHub
Unverified
parent bd874f4da4
commit 2fbdff9f41
2 changed files with 136 additions and 14 deletions
@@ -0,0 +1,117 @@
/* Outranks the deeply nested base dialog header rule. */
[data-component="dialog-v2"]
[data-slot="dialog-container"]
.settings-manage-models-dialog[data-slot="dialog-content"]
[data-slot="dialog-header"] {
padding-bottom: 12px;
}
.manage-models-search {
flex-shrink: 0;
/* The 1px top keeps the field's outside focus outline from clipping against the body. */
padding: 1px 12px 8px;
}
.settings-manage-models-dialog .settings-panel.settings-models {
height: 100%;
gap: 0;
padding: 0 8px 8px;
}
.settings-manage-models-dialog .settings-models .settings-section {
gap: 4px;
padding-block: 8px;
}
.settings-manage-models-dialog .settings-models .settings-section[data-expanded] {
padding-bottom: 8px;
}
.settings-manage-models-dialog .settings-models .settings-section + .settings-section {
border-top: 0.5px solid var(--v2-border-border-base);
}
.settings-manage-models-dialog .provider-model-groups {
gap: 8px;
}
.settings-manage-models-dialog .provider-model-group-header {
padding: 4px;
border-radius: 0;
}
.settings-manage-models-dialog .provider-model-group-header:has(:focus-visible) {
background: transparent;
}
.settings-manage-models-dialog .provider-model-group-trigger {
min-height: 36px;
padding-block: 0;
padding-inline: 12px 40px;
border-radius: 6px;
}
.settings-manage-models-dialog .provider-model-group-header:has(:focus-visible) .provider-model-group-trigger {
background: var(--v2-overlay-simple-overlay-hover);
}
.settings-manage-models-dialog .provider-model-group-actions {
position: absolute;
top: 50%;
inset-inline-end: 16px;
padding: 0;
transform: translateY(-50%);
}
@media (hover: hover) {
.settings-manage-models-dialog .provider-model-group-header:hover {
background: transparent;
}
.settings-manage-models-dialog .provider-model-group-header:hover .provider-model-group-trigger:not(:disabled) {
background: var(--v2-overlay-simple-overlay-hover);
}
}
.settings-manage-models-dialog .provider-model-group-models {
padding: 0 8px 8px;
}
.settings-manage-models-dialog .provider-model-group-models > .manage-models-rows {
padding-top: 4px;
border-top: 0.5px solid var(--v2-border-border-base);
}
.manage-models-rows {
display: flex;
flex-direction: column;
gap: 1px;
}
.manage-models-rows .search-list-row {
position: relative;
height: 36px;
padding-inline: 8px;
border-radius: 6px;
}
.manage-models-rows .search-list-row:not(:last-child)::after {
content: "";
position: absolute;
inset-inline: 8px;
bottom: -0.75px;
height: 0.5px;
background: var(--v2-border-border-base);
pointer-events: none;
}
@media (hover: hover) {
.manage-models-rows .search-list-row:hover {
background: var(--v2-overlay-simple-overlay-hover);
}
.manage-models-rows .search-list-row:hover::after,
.manage-models-rows .search-list-row:has(+ .search-list-row:hover)::after {
opacity: 0;
}
}
+19 -14
View File
@@ -11,10 +11,10 @@ import { useLanguage } from "@/runtime/i18n/language"
import { useDialog } from "@opencode/ui/context/dialog"
import { DialogConnectProvider } from "@/providers/connect/dialog"
import { decode64 } from "@/runtime/persistence/base64"
import { SettingsList } from "@/settings/list"
import { SettingsRow } from "@/settings/row"
import { consoleModelGroup, ProviderModelSections } from "@/providers/models/provider-group"
import "@/settings/settings.css"
import "@/shell/search-list.css"
import "./manage.css"
type ModelItem = ReturnType<ReturnType<typeof useLocal>["model"]["list"]>[number]
@@ -71,24 +71,29 @@ export const DialogManageModels: Component = () => {
const expanded = (key: string) => searching() || !store.collapsed[key]
function ModelRows(props: { items: ModelItem[] }) {
const visible = (item: ModelItem) => local.model.visible({ modelID: item.id, providerID: item.provider.id })
return (
<SettingsList variant="catalog">
<div class="manage-models-rows">
<For each={props.items}>
{(item) => (
<SettingsRow title={item.name} description="">
<div>
<Switch
checked={local.model.visible({ modelID: item.id, providerID: item.provider.id })}
onChange={(checked) => setModelVisibility(item, checked)}
hideLabel
>
<div
class="search-list-row"
onMouseDown={(event) => event.preventDefault()}
onClick={() => setModelVisibility(item, !visible(item))}
>
<div class="search-list-row-text">
<span class="search-list-title">{item.name}</span>
</div>
<div class="search-list-trailing" onClick={(event) => event.stopPropagation()}>
<Switch checked={visible(item)} onChange={(checked) => setModelVisibility(item, checked)} hideLabel>
{item.name}
</Switch>
</div>
</SettingsRow>
</div>
)}
</For>
</SettingsList>
</div>
)
}
@@ -104,7 +109,7 @@ export const DialogManageModels: Component = () => {
</Button>
</DialogHeader>
<DialogBody class="flex min-h-0 flex-1 flex-col">
<div class="px-4 pt-px pb-3">
<div class="manage-models-search">
<TextInput
type="search"
appearance="base"
@@ -125,7 +130,7 @@ export const DialogManageModels: Component = () => {
/>
</div>
<div data-slot="manage-models-scroll" class="relative min-h-0 flex-1">
<div class="settings-panel settings-models h-full px-4 pt-1 pb-4">
<div class="settings-panel settings-models">
<Show
when={!list.grouped.loading}
fallback={