fix(ext/popup): auto-popout for attachment types, keep login/note in popup

- Login and secure_note types stay in popup without attachment UI
- All other types (identity, card, key, totp, document) auto-redirect
  to full tab when selected
- Attachments only shown for login/secure_note when opened in tab

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-27 01:42:35 -04:00
parent c59e6892d8
commit 446949c5ce
5 changed files with 62 additions and 45 deletions

5
.claude/settings.json Normal file
View File

@@ -0,0 +1,5 @@
{
"enabledPlugins": {
"superpowers@claude-plugins-official": true
}
}

View File

@@ -78,7 +78,11 @@ function renderTypeSelection(app: HTMLElement): void {
btn.addEventListener('click', () => {
const type = btn.dataset.type as ItemType;
setState({ newType: type });
if (type === 'login' || type === 'secure_note') {
renderItemForm(app, 'add');
} else {
popOutToTab();
}
});
});
}

View File

@@ -1,7 +1,7 @@
/// Login type detail + form. Reference implementation for the shared
/// field helpers introduced in Slice 2.
import { getState, setState, sendMessage, navigate, escapeHtml, popOutToTab } from '../../popup';
import { getState, setState, sendMessage, navigate, escapeHtml, popOutToTab, isInTab } from '../../popup';
import type { Item, ItemId, LoginCore, ManifestEntry, Section, TotpConfig, AttachmentRef } from '../../../shared/types';
import { DEFAULT_PASSWORD_REQUEST } from '../../../shared/types';
import { base32Decode, base32Encode } from '../../../shared/base32';
@@ -267,7 +267,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
<div class="form-group"><label class="label" for="f-notes">notes</label>
<textarea id="f-notes" placeholder="recovery codes, security questions...">${escapeHtml(notes)}</textarea></div>
${renderSectionsEditor(sectionsDraft, sectionsExpanded)}
${renderAttachmentsDisclosure({ itemId: existing?.id ?? '', attachments: attachmentsDraft, mode: 'edit' })}
${isInTab() ? renderAttachmentsDisclosure({ itemId: existing?.id ?? '', attachments: attachmentsDraft, mode: 'edit' }) : ''}
<div class="form-actions">
<button class="btn" id="cancel-btn">cancel</button>
<button class="btn btn-primary" id="save-btn">${state.loading ? '<span class="spinner"></span>' : 'save'}</button>
@@ -284,6 +284,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
};
wireSectionsEditor(app, sectionsDraft, rerender);
if (isInTab()) {
const wireDisclosure = (): void => {
wireAttachmentsDisclosure(app, {
itemId: existing?.id ?? '',
@@ -304,6 +305,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
});
};
wireDisclosure();
}
document.getElementById('gen-btn')?.addEventListener('click', (e) => {
const trigger = e.currentTarget as HTMLElement;

View File

@@ -1,7 +1,7 @@
/// SecureNote: a single multiline body field. Concealed by default in the
/// detail view; the form is just a big <textarea>.
import { getState, setState, sendMessage, navigate, escapeHtml, popOutToTab } from '../../popup';
import { getState, setState, sendMessage, navigate, escapeHtml, popOutToTab, isInTab } from '../../popup';
import type { Item, ItemId, ManifestEntry, Section, AttachmentRef } from '../../../shared/types';
import {
renderConcealedRow, renderSignatureBlock, wireFieldHandlers, renderSections,
@@ -122,7 +122,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
<div class="form-group"><label class="label" for="f-body">body</label>
<textarea id="f-body" rows="10" placeholder="paste secrets here">${escapeHtml(body)}</textarea></div>
${renderSectionsEditor(sectionsDraft, sectionsExpanded)}
${renderAttachmentsDisclosure({ itemId: existing?.id ?? '', attachments: attachmentsDraft, mode: 'edit' })}
${isInTab() ? renderAttachmentsDisclosure({ itemId: existing?.id ?? '', attachments: attachmentsDraft, mode: 'edit' }) : ''}
<div class="form-actions">
<button class="btn" id="cancel-btn">cancel</button>
<button class="btn btn-primary" id="save-btn">save</button>
@@ -139,6 +139,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
};
wireSectionsEditor(app, sectionsDraft, rerender);
if (isInTab()) {
const wireDisclosure = (): void => {
wireAttachmentsDisclosure(app, {
itemId: existing?.id ?? '',
@@ -159,6 +160,7 @@ export function renderForm(app: HTMLElement, mode: 'add' | 'edit', existing: Ite
});
};
wireDisclosure();
}
document.getElementById('cancel-btn')?.addEventListener('click', () => {
setState({ error: null });

View File

@@ -30,6 +30,10 @@ export function escapeHtml(str: string): string {
// --- Pop out to tab ---
export function isInTab(): boolean {
return window.location.search.length > 0;
}
export function popOutToTab(): void {
const state = getState();
const params = new URLSearchParams();