Files
relicario/extension/src/popup/components/item-form.ts
adlee-was-taken c59e6892d8 feat(ext/popup): add pop-out to tab for forms
Forms can now be opened in a full browser tab via the ⤴ button,
solving Chrome's popup closure on file picker interaction. Deep
linking via URL params preserves view, item type, and item ID.

Also removes the unused dropdown picker code from item-list.ts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-27 01:32:39 -04:00

96 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 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, setState, escapeHtml, popOutToTab } from '../popup';
import type { Item, ItemType } from '../../shared/types';
const TYPE_OPTIONS: Array<{ type: ItemType; icon: string; label: string }> = [
{ type: 'login', icon: '🔑', label: 'login' },
{ type: 'secure_note', icon: '📝', label: 'secure note' },
{ type: 'identity', icon: '👤', label: 'identity' },
{ type: 'card', icon: '💳', label: 'card' },
{ type: 'key', icon: '🔐', label: 'key' },
{ type: 'document', icon: '📄', label: 'document' },
{ type: 'totp', icon: '⏱️', label: 'totp' },
];
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';
import * as documentType from './types/document';
export function renderItemForm(app: HTMLElement, mode: 'add' | 'edit'): void {
login.teardown();
secureNote.teardown();
identity.teardown();
card.teardown();
key.teardown();
totp.teardown();
documentType.teardown();
const state = getState();
const existing = mode === 'edit' ? state.selectedItem : null;
// Show type selection for new items when no type is pre-selected
if (mode === 'add' && !state.newType) {
renderTypeSelection(app);
return;
}
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 documentType.renderForm(app, mode, existing);
}
}
function renderTypeSelection(app: HTMLElement): void {
app.innerHTML = `
<div class="pad">
<div style="display:flex; align-items:center; gap:12px; margin-bottom:16px;">
<button class="btn" id="back-btn">← back</button>
<h3 style="margin:0;">new item</h3>
<span style="flex:1;"></span>
<button class="btn" id="popout-btn" title="Open in tab">⤴</button>
</div>
<div class="type-select-list">
${TYPE_OPTIONS.map((opt) => `
<button class="type-select-row" data-type="${opt.type}">
<span class="type-select-icon">${opt.icon}</span>
<span>${escapeHtml(opt.label)}</span>
</button>
`).join('')}
</div>
</div>
`;
document.getElementById('back-btn')?.addEventListener('click', () => navigate('list'));
document.getElementById('popout-btn')?.addEventListener('click', popOutToTab);
document.querySelectorAll<HTMLButtonElement>('[data-type]').forEach((btn) => {
btn.addEventListener('click', () => {
const type = btn.dataset.type as ItemType;
setState({ newType: type });
renderItemForm(app, 'add');
});
});
}
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'));
}