Clears the final four transitional @ts-nocheck shields: - popup.ts (already mostly updated in Slice 6 prior tasks; nocheck just removed and the init fallback switched to list_items / ItemId typing) - unlock.ts (list_entries → list_items; ManifestEntry typing) - settings.ts (RelicarioSettings → DeviceSettings; pure type rename, UX unchanged) Also drops the stale `idfoto-extension` name in bun.lock (workspace was renamed; lock file still carried the old name). Verification: git grep -n '@ts-nocheck' extension/src/ → 0 hits bun run build + build:firefox → both green bun run test → 52/52 passing cargo test --workspace → green Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
/// Unlock view — passphrase input with ENTER to submit.
|
|
|
|
import { getState, setState, sendMessage, navigate, escapeHtml } from '../popup';
|
|
import type { ItemId, ManifestEntry } from '../../shared/types';
|
|
|
|
export function renderUnlock(app: HTMLElement): void {
|
|
const state = getState();
|
|
|
|
app.innerHTML = `
|
|
<div class="pad" style="text-align:center; padding-top:40px;">
|
|
<img class="brand-logo" src="icons/relicario-logo.svg" alt="">
|
|
<div class="brand">relicario</div>
|
|
<p class="muted" style="margin:8px 0 24px;">two-factor vault</p>
|
|
<div class="form-group">
|
|
<input
|
|
type="password"
|
|
id="passphrase-input"
|
|
placeholder="passphrase"
|
|
autocomplete="off"
|
|
${state.loading ? 'disabled' : ''}
|
|
>
|
|
</div>
|
|
${state.loading ? '<div style="margin:12px 0;"><span class="spinner"></span></div>' : ''}
|
|
${state.error ? `<div class="error">${escapeHtml(state.error)}</div>` : ''}
|
|
<div style="margin-top:24px;">
|
|
<button class="btn" id="settings-btn" style="font-size:11px;">settings</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const input = document.getElementById('passphrase-input') as HTMLInputElement;
|
|
if (input && !state.loading) {
|
|
input.focus();
|
|
input.addEventListener('keydown', async (e) => {
|
|
if (e.key === 'Enter') {
|
|
const passphrase = input.value;
|
|
if (!passphrase) return;
|
|
setState({ loading: true, error: null });
|
|
const resp = await sendMessage({ type: 'unlock', passphrase });
|
|
if (resp.ok) {
|
|
const listResp = await sendMessage({ type: 'list_items' });
|
|
if (listResp.ok) {
|
|
const data = listResp.data as { items: Array<[ItemId, ManifestEntry]> };
|
|
navigate('list', { entries: data.items });
|
|
} else {
|
|
setState({ loading: false, error: listResp.error });
|
|
}
|
|
} else {
|
|
setState({ loading: false, error: resp.error });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
const settingsBtn = document.getElementById('settings-btn');
|
|
settingsBtn?.addEventListener('click', () => navigate('settings'));
|
|
}
|