Skip to content

Commit 1aea999

Browse files
authored
fix(app): consolidate add project action (anomalyco#34086)
1 parent 4a8fee3 commit 1aea999

1 file changed

Lines changed: 77 additions & 19 deletions

File tree

packages/app/src/components/prompt-project-selector.tsx

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ export function createPromptProjectController(input: {
6969
if (servers().length <= 1) {
7070
return [...projects().map(projectKey), actionKey(servers()[0]?.key)]
7171
}
72-
return servers().flatMap((server) => [
73-
...projects()
74-
.filter((project) => project.server?.key === server!.key)
75-
.map(projectKey),
76-
actionKey(server!.key),
77-
])
72+
return [
73+
...servers().flatMap((server) =>
74+
projects()
75+
.filter((project) => project.server?.key === server!.key)
76+
.map(projectKey),
77+
),
78+
actionKey(),
79+
]
7880
}
7981
const initialActive = () => {
8082
const selectedKey = selected() ? projectKey(selected()!) : undefined
@@ -130,7 +132,10 @@ export function createPromptProjectController(input: {
130132
const first = input
131133
.controls()
132134
.available.find((project) => !search || displayName(project).toLowerCase().includes(search))
133-
setStore({ search: value, active: first ? projectKey(first) : actionKey(servers()[0]?.key) })
135+
setStore({
136+
search: value,
137+
active: first ? projectKey(first) : actionKey(servers().length > 1 ? undefined : servers()[0]?.key),
138+
})
134139
},
135140
clearSearch() {
136141
setStore({ search: "", active: initialActive() })
@@ -156,6 +161,9 @@ export function createPromptProjectController(input: {
156161
? decodeURIComponent(store.active.slice(actionPrefix.length)) || undefined
157162
: undefined
158163
},
164+
activeAction() {
165+
return store.active.startsWith(actionPrefix)
166+
},
159167
setSearchRef(el: HTMLInputElement) {
160168
searchRef = el
161169
},
@@ -204,6 +212,12 @@ export function PromptProjectSelector(props: {
204212
selectProject(project)
205213
return
206214
}
215+
if (props.controller.activeAction() && props.controller.servers().length > 1) {
216+
const item = activeItem()
217+
item?.focus()
218+
item?.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true }))
219+
return
220+
}
207221
selectAction(props.controller.activeServer())
208222
}
209223
const moveActive = (delta: number) => {
@@ -320,7 +334,13 @@ export function PromptProjectSelector(props: {
320334
</DropdownMenu.RadioGroup>
321335
}
322336
>
323-
<For each={props.controller.servers()}>
337+
<For
338+
each={props.controller
339+
.servers()
340+
.filter((server) =>
341+
props.controller.projects().some((project) => project.server?.key === server!.key),
342+
)}
343+
>
324344
{(server) => (
325345
<div>
326346
<div class="flex h-7 select-none items-center pl-1.5 pr-3 text-[11px] font-[530] leading-none tracking-[0.05px] text-v2-text-text-faint">
@@ -333,22 +353,49 @@ export function PromptProjectSelector(props: {
333353
)}
334354
</For>
335355
</DropdownMenu.RadioGroup>
336-
<ProjectAction server={server!.key} controller={props.controller} onSelect={selectAction} />
337356
</div>
338357
)}
339358
</For>
340359
</Show>
341360
</div>
342-
<Show when={props.controller.servers().length <= 1}>
343-
<div class="h-px bg-v2-border-border-muted" />
344-
<div class="flex flex-col p-0.5">
345-
<ProjectAction
346-
server={props.controller.servers()[0]?.key}
347-
controller={props.controller}
348-
onSelect={selectAction}
349-
/>
350-
</div>
351-
</Show>
361+
<div class="h-px bg-v2-border-border-muted" />
362+
<div class="flex flex-col p-0.5">
363+
<Show
364+
when={props.controller.servers().length > 1}
365+
fallback={
366+
<ProjectAction
367+
server={props.controller.servers()[0]?.key}
368+
controller={props.controller}
369+
onSelect={selectAction}
370+
/>
371+
}
372+
>
373+
<DropdownMenu.Sub>
374+
<DropdownMenu.SubTrigger
375+
id={props.controller.actionKey()}
376+
data-option-key={props.controller.actionKey()}
377+
class={projectActionClass}
378+
classList={{
379+
"!bg-v2-overlay-simple-overlay-hover": props.controller.active() === props.controller.actionKey(),
380+
}}
381+
onMouseEnter={() => props.controller.setActive(props.controller.actionKey())}
382+
>
383+
<Icon name="plus" size="small" />
384+
<span data-slot="dropdown-menu-item-label" class="min-w-0 flex-1 truncate leading-5">
385+
{props.controller.labels.add()}
386+
</span>
387+
<Icon name="chevron-right" size="small" class="shrink-0 text-v2-icon-icon-muted" />
388+
</DropdownMenu.SubTrigger>
389+
<DropdownMenu.Portal>
390+
<DropdownMenu.SubContent class="min-w-[180px] overflow-hidden rounded-md border-0 bg-v2-background-bg-layer-01 p-0.5 shadow-[var(--v2-elevation-floating)] focus:outline-none">
391+
<For each={props.controller.servers()}>
392+
{(server) => <ServerAction server={server!} onSelect={selectAction} />}
393+
</For>
394+
</DropdownMenu.SubContent>
395+
</DropdownMenu.Portal>
396+
</DropdownMenu.Sub>
397+
</Show>
398+
</div>
352399
</DropdownMenu.Content>
353400
</DropdownMenu.Portal>
354401
</DropdownMenu>
@@ -457,6 +504,9 @@ function ProjectItem(props: {
457504
)
458505
}
459506

507+
const projectActionClass =
508+
"h-7 gap-2 rounded-sm px-3 text-[13px] font-[440] leading-5 tracking-[-0.04px] text-v2-text-text-base [font-family:var(--v2-font-family-sans)] data-[highlighted]:!bg-v2-overlay-simple-overlay-hover"
509+
460510
function ProjectAction(props: {
461511
server?: string
462512
controller: PromptProjectController
@@ -491,3 +541,11 @@ function ProjectAction(props: {
491541
</DropdownMenu.Item>
492542
)
493543
}
544+
545+
function ServerAction(props: { server: { key: string; name: string }; onSelect: (server: string) => void }) {
546+
return (
547+
<DropdownMenu.Item class={projectActionClass} onSelect={() => props.onSelect(props.server.key)}>
548+
<DropdownMenu.ItemLabel class="min-w-0 flex-1 truncate leading-5">{props.server.name}</DropdownMenu.ItemLabel>
549+
</DropdownMenu.Item>
550+
)
551+
}

0 commit comments

Comments
 (0)