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>
This commit is contained in:
adlee-was-taken
2026-04-27 01:32:39 -04:00
parent 39db697ce5
commit c59e6892d8
10 changed files with 99 additions and 111 deletions

View File

@@ -28,6 +28,29 @@ export function escapeHtml(str: string): string {
.replace(/'/g, '&#39;');
}
// --- Pop out to tab ---
export function popOutToTab(): void {
const state = getState();
const params = new URLSearchParams();
params.set('view', state.view);
if (state.newType) params.set('type', state.newType);
if (state.selectedId) params.set('id', state.selectedId);
chrome.tabs.create({ url: `popup.html?${params.toString()}` });
window.close();
}
function parseUrlParams(): { view?: View; type?: string; id?: string } | null {
const params = new URLSearchParams(window.location.search);
const view = params.get('view');
if (!view) return null;
return {
view: view as View,
type: params.get('type') ?? undefined,
id: params.get('id') ?? undefined,
};
}
// --- State ---
export type View = 'locked' | 'list' | 'detail' | 'add' | 'edit' | 'settings' | 'settings-vault' | 'trash' | 'devices' | 'field-history';
@@ -214,6 +237,28 @@ async function init(): Promise<void> {
currentState.vaultSettings = vs;
currentState.generatorDefaults = vs.generator_defaults;
}
// Check URL params for deep linking (when opened in tab)
const urlParams = parseUrlParams();
if (urlParams) {
currentState.entries = listData.items;
if (urlParams.view === 'add' && urlParams.type) {
currentState.newType = urlParams.type as import('../shared/types').ItemType;
navigate('add');
return;
}
if ((urlParams.view === 'edit' || urlParams.view === 'detail') && urlParams.id) {
// Fetch the item
const itemResp = await sendMessage({ type: 'get_item', id: urlParams.id });
if (itemResp.ok) {
currentState.selectedId = urlParams.id;
currentState.selectedItem = (itemResp.data as { item: Item }).item;
navigate(urlParams.view);
return;
}
}
}
navigate('list', { entries: listData.items });
return;
}