diff --git a/dist/index.html b/dist/index.html
index 732195d..a1120d6 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -5810,11 +5810,20 @@ var SettingsStore = class {
set lockOnTabSwitch(value) {
set(this.#lockOnTabSwitch, value, true);
}
+ #dismissedLocalWarning = /* @__PURE__ */ state(false);
+ get dismissedLocalWarning() {
+ return get(this.#dismissedLocalWarning);
+ }
+ set dismissedLocalWarning(value) {
+ set(this.#dismissedLocalWarning, value, true);
+ }
async load() {
const minutes = await getSetting("autoLockMinutes");
const tabSwitch = await getSetting("lockOnTabSwitch");
+ const dismissedWarning = await getSetting("dismissedLocalWarning");
this.autoLockMinutes = minutes != null ? Number(minutes) : 5;
this.lockOnTabSwitch = tabSwitch != null ? Boolean(tabSwitch) : true;
+ this.dismissedLocalWarning = dismissedWarning != null ? Boolean(dismissedWarning) : false;
}
/**
* Persist current settings to IndexedDB.
@@ -5822,6 +5831,7 @@ var SettingsStore = class {
async save() {
await saveSetting("autoLockMinutes", this.autoLockMinutes);
await saveSetting("lockOnTabSwitch", this.lockOnTabSwitch);
+ await saveSetting("dismissedLocalWarning", this.dismissedLocalWarning);
}
};
var settings = new SettingsStore();
@@ -5927,7 +5937,7 @@ function autofocus(node, condition = true) {
}
//#endregion
//#region src/components/LockScreen.svelte
-var root_1$7 = /* @__PURE__ */ from_html(`
You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.
`);
+var root_1$7 = /* @__PURE__ */ from_html(`You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.
`);
var root_2$6 = /* @__PURE__ */ from_html(`
`);
var root_3$6 = /* @__PURE__ */ from_html(`
`);
var root$7 = /* @__PURE__ */ from_html(``);
@@ -5943,6 +5953,16 @@ function LockScreen($$anchor, $$props) {
set(isSetup, !await isVaultInitialized());
}
checkVault();
+ let showLocalWarning = /* @__PURE__ */ state(true);
+ async function dismissLocalWarning() {
+ settings.dismissedLocalWarning = true;
+ set(showLocalWarning, false);
+ try {
+ await settings.save();
+ } catch (e) {
+ console.warn("Failed to persist warning dismissal:", e);
+ }
+ }
async function handleSubmit() {
set(error, "");
set(loading, true);
@@ -6000,10 +6020,14 @@ function LockScreen($$anchor, $$props) {
reset(p);
var node = sibling(p, 2);
var consequent = ($$anchor) => {
- append($$anchor, root_1$7());
+ var div_2 = root_1$7();
+ var button = sibling(child(div_2), 2);
+ reset(div_2);
+ delegated("click", button, dismissLocalWarning);
+ append($$anchor, div_2);
};
if_block(node, ($$render) => {
- if (get(notLocal)) $$render(consequent);
+ if (get(notLocal) && get(showLocalWarning) && !settings.dismissedLocalWarning) $$render(consequent);
});
var node_1 = sibling(node, 2);
var consequent_1 = ($$anchor) => {
@@ -6036,9 +6060,9 @@ function LockScreen($$anchor, $$props) {
if_block(node_2, ($$render) => {
if (get(isSetup)) $$render(consequent_2);
});
- var button = sibling(node_2, 2);
- var text_2 = child(button, true);
- reset(button);
+ var button_1 = sibling(node_2, 2);
+ var text_2 = child(button_1, true);
+ reset(button_1);
reset(form);
var p_1 = sibling(form, 2);
var text_3 = child(p_1, true);
@@ -6048,7 +6072,7 @@ function LockScreen($$anchor, $$props) {
template_effect(() => {
set_text(text, get(isSetup) ? "Create your vault" : "Unlock your vault");
input.disabled = get(loading);
- button.disabled = get(loading);
+ button_1.disabled = get(loading);
set_text(text_2, get(loading) ? "Processing..." : get(isSetup) ? "Create Vault" : "Unlock");
set_text(text_3, get(isSetup) ? "Your master password encrypts all data locally. It cannot be recovered if lost." : "Your data is encrypted with AES-256-GCM. Key is stored only in memory.");
});
@@ -6059,6 +6083,7 @@ function LockScreen($$anchor, $$props) {
append($$anchor, div);
pop();
}
+delegate(["click"]);
//#endregion
//#region src/lib/stores/search.svelte.js
var DEBOUNCE_MS = 300;
@@ -8204,13 +8229,35 @@ label {
.warning-banner.svelte-7sq1ct {
width: 100%;
- padding: 10px 14px;
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ padding: 10px 10px 10px 14px;
background: rgba(255, 193, 7, 0.15);
border: 1px solid rgba(230, 168, 0, 0.5);
border-radius: var(--radius-md);
color: #b8860b;
font-size: 0.85rem;
- text-align: center;
+ }
+
+ .warning-text.svelte-7sq1ct {
+ flex: 1;
+ text-align: left;
+ }
+
+ .warning-dismiss.svelte-7sq1ct {
+ flex-shrink: 0;
+ border: none;
+ background: transparent;
+ color: inherit;
+ font-size: 0.9rem;
+ line-height: 1;
+ cursor: pointer;
+ padding: 0 2px;
+ opacity: 0.7;
+ }
+ .warning-dismiss.svelte-7sq1ct:hover {
+ opacity: 1;
}
.hint.svelte-7sq1ct {
diff --git a/src/components/LockScreen.svelte b/src/components/LockScreen.svelte
index 0e5f1e2..e2eb039 100644
--- a/src/components/LockScreen.svelte
+++ b/src/components/LockScreen.svelte
@@ -19,6 +19,16 @@
}
checkVault()
+ // Dismissed warning state loads from the settings store (which loads on
+ // unlock/setup). Track locally so the banner hides immediately on click.
+ let showLocalWarning = $state(true)
+
+ async function dismissLocalWarning() {
+ settings.dismissedLocalWarning = true
+ showLocalWarning = false
+ try { await settings.save() } catch (e) { console.warn('Failed to persist warning dismissal:', e) }
+ }
+
async function handleSubmit() {
error = ''
loading = true
@@ -88,8 +98,11 @@
Password Vault
{isSetup ? 'Create your vault' : 'Unlock your vault'}
- {#if notLocal}
- This HTML file is intended for offline use.
+ {#if notLocal && showLocalWarning && !settings.dismissedLocalWarning}
+
+ You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.
+
+
{/if}
{#if error}
@@ -196,13 +209,35 @@
.warning-banner {
width: 100%;
- padding: 10px 14px;
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ padding: 10px 10px 10px 14px;
background: rgba(255, 193, 7, 0.15);
border: 1px solid rgba(230, 168, 0, 0.5);
border-radius: var(--radius-md);
color: #b8860b;
font-size: 0.85rem;
- text-align: center;
+ }
+
+ .warning-text {
+ flex: 1;
+ text-align: left;
+ }
+
+ .warning-dismiss {
+ flex-shrink: 0;
+ border: none;
+ background: transparent;
+ color: inherit;
+ font-size: 0.9rem;
+ line-height: 1;
+ cursor: pointer;
+ padding: 0 2px;
+ opacity: 0.7;
+ }
+ .warning-dismiss:hover {
+ opacity: 1;
}
.hint {
diff --git a/src/lib/stores/settings.svelte.js b/src/lib/stores/settings.svelte.js
index 5ee613c..baef51a 100644
--- a/src/lib/stores/settings.svelte.js
+++ b/src/lib/stores/settings.svelte.js
@@ -10,6 +10,8 @@ import { getSetting, saveSetting } from '../storage/db.js'
export class SettingsStore {
autoLockMinutes = $state(5)
lockOnTabSwitch = $state(true)
+ // User dismissed the "running from a web server" warning banner on the lock screen.
+ dismissedLocalWarning = $state(false)
/**
* Load persisted settings from IndexedDB.
@@ -18,9 +20,11 @@ export class SettingsStore {
async load() {
const minutes = await getSetting('autoLockMinutes')
const tabSwitch = await getSetting('lockOnTabSwitch')
+ const dismissedWarning = await getSetting('dismissedLocalWarning')
this.autoLockMinutes = minutes != null ? Number(minutes) : 5
this.lockOnTabSwitch = tabSwitch != null ? Boolean(tabSwitch) : true
+ this.dismissedLocalWarning = dismissedWarning != null ? Boolean(dismissedWarning) : false
}
/**
@@ -29,6 +33,7 @@ export class SettingsStore {
async save() {
await saveSetting('autoLockMinutes', this.autoLockMinutes)
await saveSetting('lockOnTabSwitch', this.lockOnTabSwitch)
+ await saveSetting('dismissedLocalWarning', this.dismissedLocalWarning)
}
}