Detail view renders a signature block with a large monospace rotating code and a thin SVG countdown ring that sweeps via CSS transition. The ticker polls get_totp every second and is stopped on teardown (back/edit/trash/Escape/e/d/t). Form has a two-button kind toggle (TOTP / Steam Guard) that re-renders in place while preserving entered values. TOTP uses digits=6 kind='totp'; Steam uses digits=5 kind='steam'. Both default to algorithm='sha1' period_seconds=30. Keyboard shortcuts on detail: Escape=back, e=edit, d=trash, t=copy-code. Guarded against stealing keystrokes from editable targets. Wires totp.renderDetail / totp.renderForm into both dispatchers and calls totp.teardown() alongside the other types so tickers can't leak across views. Closes T8 of the extension 1C-β1 plan (5/5 typed-item modules in place; only T9 picker and T10 acceptance remain).
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
/// Typed-item add/edit form dispatcher. Each type's renderForm lives in
|
||
/// its own module under ./types/. Document stays "coming soon" until γ.
|
||
|
||
import { navigate, getState } from '../popup';
|
||
import type { Item, ItemType } from '../../shared/types';
|
||
import * as login from './types/login';
|
||
import * as secureNote from './types/secure-note';
|
||
import * as identity from './types/identity';
|
||
import * as card from './types/card';
|
||
import * as key from './types/key';
|
||
import * as totp from './types/totp';
|
||
|
||
export function renderItemForm(app: HTMLElement, mode: 'add' | 'edit'): void {
|
||
login.teardown(); // detail-view's ticker/listener don't leak into form
|
||
secureNote.teardown();
|
||
identity.teardown();
|
||
card.teardown();
|
||
key.teardown();
|
||
totp.teardown();
|
||
const state = getState();
|
||
const existing = mode === 'edit' ? state.selectedItem : null;
|
||
const type: ItemType = existing?.type ?? state.newType ?? 'login';
|
||
|
||
switch (type) {
|
||
case 'login': return login.renderForm(app, mode, existing);
|
||
case 'secure_note': return secureNote.renderForm(app, mode, existing);
|
||
case 'identity': return identity.renderForm(app, mode, existing);
|
||
case 'card': return card.renderForm(app, mode, existing);
|
||
case 'key': return key.renderForm(app, mode, existing);
|
||
case 'totp': return totp.renderForm(app, mode, existing);
|
||
case 'document': return renderComingSoon(app, type);
|
||
}
|
||
}
|
||
|
||
function renderComingSoon(app: HTMLElement, type: ItemType): void {
|
||
app.innerHTML = `
|
||
<div class="pad">
|
||
<div class="detail-title" style="margin-bottom:16px;">${type.replace('_', ' ')}</div>
|
||
<p class="muted">Editing <strong>${type}</strong> items is not available yet.</p>
|
||
<div class="form-actions"><button class="btn" id="back-btn">back</button></div>
|
||
</div>
|
||
`;
|
||
document.getElementById('back-btn')?.addEventListener('click', () => navigate('list'));
|
||
}
|