fix: address code review feedback on custom close dialog

This commit is contained in:
makaradam
2026-05-02 13:08:52 +02:00
parent b3469c469b
commit 36076aaf2a
2 changed files with 36 additions and 34 deletions
+5 -2
View File
@@ -252,6 +252,7 @@ function updateTrayMenu(recording: boolean = false) {
let editorHasUnsavedChanges = false;
let isForceClosing = false;
let isCloseConfirmInFlight = false;
ipcMain.on("set-has-unsaved-changes", (_, hasChanges: boolean) => {
editorHasUnsavedChanges = hasChanges;
@@ -283,9 +284,10 @@ function createEditorWindowWrapper() {
editorHasUnsavedChanges = false;
mainWindow.on("close", (event) => {
if (isForceClosing || !editorHasUnsavedChanges) return;
if (isForceClosing || !editorHasUnsavedChanges || isCloseConfirmInFlight) return;
event.preventDefault();
isCloseConfirmInFlight = true;
const windowToClose = mainWindow;
if (!windowToClose || windowToClose.isDestroyed()) return;
@@ -294,6 +296,7 @@ function createEditorWindowWrapper() {
windowToClose.webContents.send("request-close-confirm");
ipcMain.once("close-confirm-response", (_, choice: "save" | "discard" | "cancel") => {
isCloseConfirmInFlight = false;
if (!windowToClose || windowToClose.isDestroyed()) return;
if (choice === "save") {
@@ -306,7 +309,7 @@ function createEditorWindowWrapper() {
} else if (choice === "discard") {
forceCloseEditorWindow(windowToClose);
}
// "cancel": do nothing, window stays open
// "cancel": flag reset, window stays open
});
});
}
@@ -1,4 +1,11 @@
import { Save, Trash2, X } from "lucide-react";
import { Save, Trash2 } from "lucide-react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { useScopedT } from "@/contexts/I18nContext";
interface UnsavedChangesDialogProps {
@@ -17,41 +24,33 @@ export function UnsavedChangesDialog({
const td = useScopedT("dialogs");
const tc = useScopedT("common");
if (!isOpen) return null;
return (
<>
<div
className="fixed inset-0 bg-black/80 backdrop-blur-md z-50 animate-in fade-in duration-200"
onClick={onCancel}
/>
<div className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-[60] bg-[#09090b] rounded-2xl shadow-2xl border border-white/10 p-6 w-[90vw] max-w-sm animate-in zoom-in-95 duration-200">
<div className="flex items-center gap-3 mb-5">
<img
src="/openscreen.png"
alt="OpenScreen"
className="w-9 h-9 rounded-xl flex-shrink-0"
/>
<h2 className="text-base font-semibold text-slate-200 leading-tight">
{td("unsavedChanges.title")}
</h2>
<button
type="button"
onClick={onCancel}
className="ml-auto rounded-full p-1 hover:bg-white/10 text-slate-500 hover:text-slate-300 transition-colors flex-shrink-0"
>
<X className="w-4 h-4" />
</button>
</div>
<Dialog open={isOpen} onOpenChange={(open) => !open && onCancel()}>
<DialogContent className="bg-[#09090b] border-white/10 rounded-2xl max-w-sm p-6 gap-0">
<DialogHeader className="mb-5">
<div className="flex items-center gap-3">
<img
src="/openscreen.png"
alt=""
aria-hidden="true"
className="w-9 h-9 rounded-xl flex-shrink-0"
/>
<DialogTitle className="text-base font-semibold text-slate-200 leading-tight">
{td("unsavedChanges.title")}
</DialogTitle>
</div>
</DialogHeader>
<p className="text-sm text-slate-300 mb-1">{td("unsavedChanges.message")}</p>
<p className="text-sm text-slate-500 mb-6">{td("unsavedChanges.detail")}</p>
<DialogDescription className="text-sm text-slate-500 mb-6">
{td("unsavedChanges.detail")}
</DialogDescription>
<div className="flex flex-col gap-2">
<button
type="button"
onClick={onSaveAndClose}
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg bg-[#34B27B] hover:bg-[#2d9e6c] active:bg-[#27885c] text-white font-medium text-sm transition-colors"
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg bg-[#34B27B] hover:bg-[#2d9e6c] active:bg-[#27885c] text-white font-medium text-sm transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[#34B27B] focus-visible:ring-offset-2 focus-visible:ring-offset-[#09090b]"
>
<Save className="w-4 h-4" />
{td("unsavedChanges.saveAndClose")}
@@ -59,7 +58,7 @@ export function UnsavedChangesDialog({
<button
type="button"
onClick={onDiscardAndClose}
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg bg-white/5 hover:bg-red-500/15 border border-white/10 hover:border-red-500/30 text-slate-300 hover:text-red-400 font-medium text-sm transition-colors"
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg bg-white/5 hover:bg-red-500/15 border border-white/10 hover:border-red-500/30 text-slate-300 hover:text-red-400 font-medium text-sm transition-colors outline-none focus-visible:ring-2 focus-visible:ring-white/30 focus-visible:ring-offset-2 focus-visible:ring-offset-[#09090b]"
>
<Trash2 className="w-4 h-4" />
{td("unsavedChanges.discardAndClose")}
@@ -67,12 +66,12 @@ export function UnsavedChangesDialog({
<button
type="button"
onClick={onCancel}
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg hover:bg-white/5 text-slate-500 hover:text-slate-300 font-medium text-sm transition-colors"
className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg hover:bg-white/5 text-slate-500 hover:text-slate-300 font-medium text-sm transition-colors outline-none focus-visible:ring-2 focus-visible:ring-white/20 focus-visible:ring-offset-2 focus-visible:ring-offset-[#09090b]"
>
{tc("actions.cancel")}
</button>
</div>
</div>
</>
</DialogContent>
</Dialog>
);
}