import { Button, Label, ListView, Popup, ScrollContainer, Theme } from '../ui'; import { dialogButtons } from './FormDialog'; /** One project as the list shows it. */ export interface ProjectChoice { id: string; name: string; } const LIST_WIDTH = 320; const LIST_HEIGHT = 220; /** * The project picker behind "Open project…" (#183): the list the top bar's Project dropdown used * to be, now a dialog, because it has two things to do with a project rather than one. * * Delete closes this dialog and hands the choice on; the caller asks for confirmation. Two modals * stacked over one another would leave the question standing over a list it is no longer about. */ export class OpenProjectDialog extends Popup { private readonly list = new ListView(); private readonly scroll = new ScrollContainer(); private readonly openButton: Button; private readonly deleteButton: Button; private picked: string | null; private readonly names: string[]; constructor( projects: readonly ProjectChoice[], currentId: string, actions: { onOpen(id: string): void; onDelete(id: string): void }, ) { super({ modal: true, padding: Theme.padding * 2, gap: Theme.gap }); this.picked = projects.some((p) => p.id === currentId) ? currentId : (projects[0]?.id ?? null); this.names = projects.map((p) => p.name); this.content.add(new Label('Open project', { style: 'bodyBold' })); this.list.minWidth = LIST_WIDTH; this.list.setItems( projects.map((p) => ({ id: p.id, label: p.name, hint: p.id === currentId ? 'open' : undefined, })), ); this.list.select(this.picked, true); this.list.onSelect = (id) => { this.picked = id; this.refresh(); }; // A double click is how an asset is opened everywhere else in the editor, so it is here too. this.list.onActivate = (id) => this.closeThen(() => actions.onOpen(id))(); this.scroll.minWidth = LIST_WIDTH; this.scroll.minHeight = LIST_HEIGHT; this.scroll.setContent(this.list); this.content.add(this.scroll); this.deleteButton = new Button('Delete', { variant: 'danger' }); this.deleteButton.onClick = () => this.withPicked(actions.onDelete); this.openButton = new Button('Open', { variant: 'primary' }); this.openButton.onClick = () => this.withPicked(actions.onOpen); this.content.add(dialogButtons(this.closeThen(), this.openButton, this.deleteButton)); this.refresh(); } /** What the list shows and which row is picked (test hook). */ info(): { names: string[]; picked: string | null } { return { names: [...this.names], picked: this.picked }; } private withPicked(action: (id: string) => void): void { const id = this.picked; if (id) this.closeThen(() => action(id))(); } private refresh(): void { this.openButton.setEnabled(this.picked !== null); this.deleteButton.setEnabled(this.picked !== null); } }