81 lines
2.9 KiB
TypeScript
81 lines
2.9 KiB
TypeScript
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);
|
|
}
|
|
}
|