diff options
| author | Ronan Kearns <[email protected]> | 2026-01-21 05:44:17 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-21 04:44:17 -0600 |
| commit | 996eeb1f6848b393d887791557e0d8cbe56255ec (patch) | |
| tree | 8f061d2f333f2334b5cdabc3e9a98f2abbdd3fc1 /packages/ui | |
| parent | 2e5fe6d5c88907aefe3dc19c3e95f761ba0efdea (diff) | |
| download | opencode-996eeb1f6848b393d887791557e0d8cbe56255ec.tar.gz opencode-996eeb1f6848b393d887791557e0d8cbe56255ec.zip | |
feat(app): add manage models icon to selector (per Figma request) (#9722)
Diffstat (limited to 'packages/ui')
| -rw-r--r-- | packages/ui/src/components/list.css | 38 | ||||
| -rw-r--r-- | packages/ui/src/components/list.tsx | 47 |
2 files changed, 61 insertions, 24 deletions
diff --git a/packages/ui/src/components/list.css b/packages/ui/src/components/list.css index ee9be422c..95641bb20 100644 --- a/packages/ui/src/components/list.css +++ b/packages/ui/src/components/list.css @@ -23,14 +23,46 @@ overflow: hidden; padding: 0 12px; - [data-slot="list-search"] { + [data-slot="list-search-wrapper"] { display: flex; flex-shrink: 0; - padding: 8px; align-items: center; - gap: 12px; + gap: 8px; align-self: stretch; margin-bottom: 4px; + padding-right: 4px; + + > [data-component="icon-button"] { + width: 24px; + height: 24px; + flex-shrink: 0; + background-color: transparent; + opacity: 0.5; + transition: opacity 0.15s ease; + + &:hover:not(:disabled), + &:focus:not(:disabled), + &:active:not(:disabled) { + background-color: transparent; + opacity: 0.7; + } + + &:hover:not(:disabled) [data-slot="icon-svg"] { + color: var(--icon-hover); + } + + &:active:not(:disabled) [data-slot="icon-svg"] { + color: var(--icon-active); + } + } + } + + [data-slot="list-search"] { + display: flex; + flex: 1; + padding: 8px; + align-items: center; + gap: 12px; border-radius: var(--radius-md); background: var(--surface-base); diff --git a/packages/ui/src/components/list.tsx b/packages/ui/src/components/list.tsx index 066363502..fc9fa5405 100644 --- a/packages/ui/src/components/list.tsx +++ b/packages/ui/src/components/list.tsx @@ -11,6 +11,7 @@ export interface ListSearchProps { autofocus?: boolean hideIcon?: boolean class?: string + action?: JSX.Element } export interface ListProps<T> extends FilteredListProps<T> { @@ -60,6 +61,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void }) const { filter, grouped, flat, active, setActive, onKeyDown, onInput } = useFilteredList<T>(props) const searchProps = () => (typeof props.search === "object" ? props.search : {}) + const searchAction = () => searchProps().action const moved = (event: MouseEvent) => event.movementX !== 0 || event.movementY !== 0 @@ -198,29 +200,32 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void }) return ( <div data-component="list" classList={{ [props.class ?? ""]: !!props.class }}> <Show when={!!props.search}> - <div data-slot="list-search" classList={{ [searchProps().class ?? ""]: !!searchProps().class }}> - <div data-slot="list-search-container"> - <Show when={!searchProps().hideIcon}> - <Icon name="magnifying-glass" /> + <div data-slot="list-search-wrapper"> + <div data-slot="list-search" classList={{ [searchProps().class ?? ""]: !!searchProps().class }}> + <div data-slot="list-search-container"> + <Show when={!searchProps().hideIcon}> + <Icon name="magnifying-glass" /> + </Show> + <TextField + autofocus={searchProps().autofocus} + variant="ghost" + data-slot="list-search-input" + type="text" + value={internalFilter()} + onChange={setInternalFilter} + onKeyDown={handleKey} + placeholder={searchProps().placeholder} + spellcheck={false} + autocorrect="off" + autocomplete="off" + autocapitalize="off" + /> + </div> + <Show when={internalFilter()}> + <IconButton icon="circle-x" variant="ghost" onClick={() => setInternalFilter("")} /> </Show> - <TextField - autofocus={searchProps().autofocus} - variant="ghost" - data-slot="list-search-input" - type="text" - value={internalFilter()} - onChange={setInternalFilter} - onKeyDown={handleKey} - placeholder={searchProps().placeholder} - spellcheck={false} - autocorrect="off" - autocomplete="off" - autocapitalize="off" - /> </div> - <Show when={internalFilter()}> - <IconButton icon="circle-x" variant="ghost" onClick={() => setInternalFilter("")} /> - </Show> + {searchAction()} </div> </Show> <div ref={setScrollRef} data-slot="list-scroll"> |
