diff --git a/services/vault-service.js b/services/vault-service.js
index 974bfde..2fbfee6 100644
--- a/services/vault-service.js
+++ b/services/vault-service.js
@@ -78,16 +78,17 @@ export const vaultService = {
if (window.__vaultConfig) {
window.__vaultConfig.id = newName;
}
+
+ history.replaceState(null, "", "/?vault=" + encodeURIComponent(newName));
}
return this.listVaults();
},
async deleteVault(id) {
- await fetchJson(
- API_BASE + "/remove?vault=" + encodeURIComponent(id),
- { method: "DELETE" },
- );
+ await fetchJson(API_BASE + "/remove?vault=" + encodeURIComponent(id), {
+ method: "DELETE",
+ });
const wasCurrentVault = id === this.getCurrentVaultId();
diff --git a/shims/electron/remote/dialog.js b/shims/electron/remote/dialog.js
index bb9da0f..aae3013 100644
--- a/shims/electron/remote/dialog.js
+++ b/shims/electron/remote/dialog.js
@@ -1,3 +1,9 @@
+import {
+ showMessageDialog,
+ showConfirmDialog,
+ showPromptDialog,
+} from "../../../ui/bootstrap.js";
+
export const dialogShim = {
async showOpenDialog(browserWindow, options) {
// TODO: implement custom modal with server-side file listing
@@ -5,21 +11,28 @@ export const dialogShim = {
return { canceled: true, filePaths: [] };
},
- // TODO: replace prompt() with a styled modal (matching vault manager style)
async showSaveDialog(browserWindow, options) {
if (typeof browserWindow === "object" && !options) {
options = browserWindow;
}
+
const defaultName =
- options?.defaultPath?.split(/[/\\]/).pop() || "download";
- const name = prompt("Save as:", defaultName);
+ options?.defaultPath?.split(/[\/\\]/).pop() || "download";
+ const name = await showPromptDialog(
+ "Save File",
+ "Save as:",
+ "filename",
+ defaultName,
+ "Save",
+ );
+
if (!name) {
return { canceled: true, filePath: undefined };
}
+
return { canceled: false, filePath: "/downloads/" + name };
},
- // TODO: replace alert() with a styled modal (matching vault manager style)
async showMessageBox(browserWindow, options) {
if (typeof browserWindow === "object" && !options) {
options = browserWindow;
@@ -30,21 +43,20 @@ export const dialogShim = {
const message = options.message || "";
const detail = options.detail || "";
const buttons = options.buttons || ["OK"];
+ const fullMessage = message + (detail ? "\n\n" + detail : "");
if (buttons.length <= 1) {
- alert(message + (detail ? "\n\n" + detail : ""));
+ await showMessageDialog(options.title || "Message", fullMessage);
return { response: 0, checkboxChecked: false };
}
- const result = confirm(
- message +
- (detail ? "\n\n" + detail : "") +
- '\n\n[OK] = "' +
- buttons[0] +
- '", [Cancel] = "' +
- buttons[1] +
- '"',
+ const result = await showConfirmDialog(
+ options.title || "Confirm",
+ message,
+ detail,
+ buttons[0],
);
+
return {
response: result ? 0 : 1,
checkboxChecked: false,
@@ -53,6 +65,6 @@ export const dialogShim = {
showErrorBox(title, content) {
console.error("[shim:dialog] Error:", title, content);
- alert(title + "\n\n" + content);
+ showMessageDialog(title, content);
},
};
diff --git a/ui/bootstrap.js b/ui/bootstrap.js
index bb12d90..0028722 100644
--- a/ui/bootstrap.js
+++ b/ui/bootstrap.js
@@ -9,3 +9,66 @@ export function showVaultManager() {
props: { vaultService },
});
}
+
+export function showMessageDialog(title, message) {
+ return new Promise((resolve) => {
+ const dialog = new window.IgnisUI.MessageDialog({
+ target: document.body,
+ props: { title, message },
+ });
+
+ dialog.$on("confirm", () => {
+ dialog.$destroy();
+ resolve();
+ });
+ });
+}
+
+export function showConfirmDialog(
+ title,
+ message,
+ description,
+ confirmText = "OK",
+) {
+ return new Promise((resolve) => {
+ const dialog = new window.IgnisUI.ConfirmDialog({
+ target: document.body,
+ props: { title, message, description, confirmText },
+ });
+
+ dialog.$on("confirm", () => {
+ dialog.$destroy();
+ resolve(true);
+ });
+
+ dialog.$on("cancel", () => {
+ dialog.$destroy();
+ resolve(false);
+ });
+ });
+}
+
+export function showPromptDialog(
+ title,
+ label,
+ placeholder = "",
+ value = "",
+ confirmText = "OK",
+) {
+ return new Promise((resolve) => {
+ const dialog = new window.IgnisUI.PromptDialog({
+ target: document.body,
+ props: { title, label, placeholder, value, confirmText },
+ });
+
+ dialog.$on("confirm", (event) => {
+ dialog.$destroy();
+ resolve(event.detail);
+ });
+
+ dialog.$on("cancel", () => {
+ dialog.$destroy();
+ resolve(null);
+ });
+ });
+}
diff --git a/ui/components/layout/MessageDialog.svelte b/ui/components/layout/MessageDialog.svelte
new file mode 100644
index 0000000..0386dab
--- /dev/null
+++ b/ui/components/layout/MessageDialog.svelte
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/index.js b/ui/index.js
index 1a15fc5..11fd0d4 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -1 +1,4 @@
export { default as VaultManager } from "./views/VaultManager.svelte";
+export { default as MessageDialog } from "./components/layout/MessageDialog.svelte";
+export { default as ConfirmDialog } from "./components/layout/ConfirmDialog.svelte";
+export { default as PromptDialog } from "./components/layout/PromptDialog.svelte";
diff --git a/ui/views/VaultManager.svelte b/ui/views/VaultManager.svelte
index 1f7c85c..ffe8589 100644
--- a/ui/views/VaultManager.svelte
+++ b/ui/views/VaultManager.svelte
@@ -12,6 +12,7 @@
import Modal from "../components/layout/Modal.svelte";
import PromptDialog from "../components/layout/PromptDialog.svelte";
import ConfirmDialog from "../components/layout/ConfirmDialog.svelte";
+ import MessageDialog from "../components/layout/MessageDialog.svelte";
import SearchInput from "../components/input/SearchInput.svelte";
import Button from "../components/input/Button.svelte";
import ListItem from "../components/display/ListItem.svelte";
@@ -27,6 +28,8 @@
let activeDialog = null;
let targetVault = null;
let dialogValue = "";
+ let errorMessage = "";
+ let pendingReload = false;
const menuItems = [
{ id: "rename", label: "Rename" },
@@ -108,12 +111,11 @@
try {
vaults = await vaultService.createVault(name);
+ closeDialog();
} catch (err) {
- alert("Failed to create vault: " + err.message);
- return;
+ errorMessage = "Failed to create vault: " + err.message;
+ activeDialog = "error";
}
-
- closeDialog();
}
async function onRenameConfirm(e) {
@@ -128,15 +130,15 @@
try {
vaults = await vaultService.renameVault(targetVault.id, trimmed);
+ closeDialog();
+
+ if (wasCurrentVault) {
+ currentVaultId = vaultService.getCurrentVaultId();
+ pendingReload = true;
+ }
} catch (err) {
- alert("Failed to rename vault: " + err.message);
- return;
- }
-
- closeDialog();
-
- if (wasCurrentVault) {
- currentVaultId = vaultService.getCurrentVaultId();
+ errorMessage = "Failed to rename vault: " + err.message;
+ activeDialog = "error";
}
}
@@ -154,7 +156,14 @@
vaultService.openVault("");
}
} catch (err) {
- alert("Failed to delete vault: " + err.message);
+ errorMessage = "Failed to delete vault: " + err.message;
+ activeDialog = "error";
+ }
+ }
+
+ function onModalClose() {
+ if (pendingReload) {
+ window.location.reload();
}
}
@@ -176,6 +185,7 @@
width="600px"
bind:this={modalRef}
on:escape={onEscape}
+ on:close={onModalClose}
closeOnOverlayClick={false}
>
@@ -270,7 +280,7 @@
{/if}
+{#if activeDialog === "error"}
+ {
+ activeDialog = null;
+ errorMessage = "";
+ }}
+ />
+{/if}
+