Skip to content

Commit 0d99023

Browse files
committed
feat(dialogs): add option to cancel replacing the queue
1 parent ba230a7 commit 0d99023

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

src/dialogs.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ type ConfirmDialogOptions = {
66
confirmLabel?: string;
77
cancelLabel?: string;
88
tone?: ButtonTone;
9+
extraLabel?: string;
10+
extraTone?: ButtonTone;
911
};
1012

1113
type PromptDialogOptions = {
@@ -38,10 +40,12 @@ function createDialogContainer(backdrop: HTMLDivElement): HTMLDivElement {
3840
return dialog;
3941
}
4042

41-
export function showConfirmDialog(options: ConfirmDialogOptions): Promise<boolean> {
42-
if (dialogOpen) return Promise.resolve(false);
43+
type ConfirmDialogResult = "confirm" | "cancel" | "extra";
44+
45+
export function showConfirmDialog(options: ConfirmDialogOptions): Promise<ConfirmDialogResult> {
46+
if (dialogOpen) return Promise.resolve("cancel");
4347
dialogOpen = true;
44-
const { title, message, confirmLabel = "Confirm", cancelLabel = "Cancel", tone } = options;
48+
const { title, message, confirmLabel = "Confirm", cancelLabel = "Cancel", tone, extraLabel, extraTone } = options;
4549

4650
return new Promise(resolve => {
4751
const backdrop = createBackdrop();
@@ -76,13 +80,29 @@ export function showConfirmDialog(options: ConfirmDialogOptions): Promise<boolea
7680
confirmBtn.className = confirmClasses.join(" ");
7781
confirmBtn.textContent = confirmLabel;
7882

79-
actionsEl.append(cancelBtn, confirmBtn);
83+
let extraBtn: HTMLButtonElement | null = null;
84+
if (extraLabel) {
85+
extraBtn = document.createElement("button");
86+
extraBtn.type = "button";
87+
const extraToneClass = getToneClass(extraTone);
88+
const extraClasses = ["qs-btn"];
89+
if (extraToneClass === "default") extraClasses.push("subtle");
90+
else extraClasses.push(extraToneClass);
91+
extraBtn.className = extraClasses.join(" ");
92+
extraBtn.textContent = extraLabel;
93+
}
94+
95+
if (extraBtn) {
96+
actionsEl.append(cancelBtn, extraBtn, confirmBtn);
97+
} else {
98+
actionsEl.append(cancelBtn, confirmBtn);
99+
}
80100
dialog.appendChild(actionsEl);
81101

82102
const prevFocused = document.activeElement as HTMLElement | null;
83103
let resolved = false;
84104

85-
function cleanup(result: boolean) {
105+
function cleanup(result: ConfirmDialogResult) {
86106
if (resolved) return;
87107
resolved = true;
88108
backdrop.remove();
@@ -95,17 +115,20 @@ export function showConfirmDialog(options: ConfirmDialogOptions): Promise<boolea
95115
function onKeyDown(ev: KeyboardEvent) {
96116
if (ev.key === "Escape") {
97117
ev.preventDefault();
98-
cleanup(false);
118+
cleanup("cancel");
99119
} else if (ev.key === "Enter" && document.activeElement === confirmBtn) {
100120
ev.preventDefault();
101-
cleanup(true);
121+
cleanup("confirm");
102122
}
103123
}
104124

105-
cancelBtn.addEventListener("click", () => cleanup(false));
106-
confirmBtn.addEventListener("click", () => cleanup(true));
125+
cancelBtn.addEventListener("click", () => cleanup("cancel"));
126+
confirmBtn.addEventListener("click", () => cleanup("confirm"));
127+
if (extraBtn) {
128+
extraBtn.addEventListener("click", () => cleanup("extra"));
129+
}
107130
backdrop.addEventListener("click", ev => {
108-
if (ev.target === backdrop) cleanup(false);
131+
if (ev.target === backdrop) cleanup("cancel");
109132
});
110133
document.addEventListener("keydown", onKeyDown, true);
111134

@@ -219,5 +242,5 @@ export function showPromptDialog(options: PromptDialogOptions): Promise<string |
219242
});
220243
}
221244

222-
export type { ConfirmDialogOptions, PromptDialogOptions };
245+
export type { ConfirmDialogOptions, ConfirmDialogResult, PromptDialogOptions };
223246

src/ui.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createManualSnapshot, exportSnapshotToPlaylist } from "./exporter";
99
import { replaceQueueWithSnapshot } from "./exporter";
1010
import { APP_CHANNEL, APP_NAME, APP_VERSION } from "./appInfo";
1111
import { getSortedSnapshots } from "./storage";
12-
import { showConfirmDialog } from "./dialogs";
12+
import { showConfirmDialog, ConfirmDialogResult } from "./dialogs";
1313

1414
export type UIHandlers = {
1515
getSettings: () => Settings;
@@ -19,7 +19,6 @@ export type UIHandlers = {
1919
let boundClickHandler: ((e: MouseEvent) => void) | null = null;
2020
let boundChangeHandler: ((e: Event) => void) | null = null;
2121
const exportingIds = new Set<string>();
22-
let notificationWatcher: number | null = null;
2322

2423
type InlineEditState = {
2524
input: HTMLInputElement;
@@ -504,9 +503,14 @@ export function openManagerModal(ui: UIHandlers): void {
504503
message: "Create a manual snapshot of the current queue before replacing it?",
505504
confirmLabel: "Save snapshot",
506505
cancelLabel: "Skip",
506+
extraLabel: "Cancel",
507+
extraTone: "subtle",
507508
tone: "primary",
508509
});
509-
if (shouldSave) {
510+
if (shouldSave === "extra") {
511+
return;
512+
}
513+
if (shouldSave === "confirm") {
510514
await createManualSnapshot();
511515
renderList();
512516
}
@@ -518,16 +522,13 @@ export function openManagerModal(ui: UIHandlers): void {
518522
return;
519523
}
520524
if (action === "delete") {
521-
const confirmDelete = await showConfirmDialog({
525+
const confirmDelete: ConfirmDialogResult = await showConfirmDialog({
522526
title: "Delete snapshot",
523527
message: "Delete this snapshot? This cannot be undone.",
524528
confirmLabel: "Delete",
525529
tone: "danger",
526530
});
527-
if (!confirmDelete) {
528-
exportingIds.delete(id);
529-
return;
530-
}
531+
if (confirmDelete !== "confirm") return;
531532
const snapshotName = getSnapshotDisplayName(snap);
532533
const remaining = snapshots.filter(s => s.id !== id);
533534
saveSnapshots(remaining);

0 commit comments

Comments
 (0)