feat(ext/popup): typed-item list view

Rewrites item-list.ts to render the typed-item ManifestEntry v2
surface: title + type-icon emoji (🔑/📝/🪪/💳/🗝/📄/⏱) + icon_hint
as the meta line. Toolbar now has +new, sync, settings, lock. Keyboard
nav unchanged (/, +, arrows, Enter).

Clicking a row fires list_items → get_item (the new typed-item
messages) and stores the full Item in state.selectedItem before
navigating to 'detail'.

Also updates popup.ts PopupState:
- entries now typed Array<[ItemId, ManifestEntry]>
- selectedEntry → selectedItem (Item)
- init() uses list_items not list_entries

Trashed items (trashed_at set) are filtered out of the visible list.
@ts-nocheck removed from item-list.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-20 21:09:28 -04:00
parent d090fc421e
commit dc8097589e
2 changed files with 86 additions and 71 deletions

View File

@@ -5,7 +5,7 @@
/// Navigation works by updating `currentState` and calling `render()`.
import type { Request, Response } from '../shared/messages';
import type { ManifestEntry, Entry } from '../shared/types';
import type { ItemId, ManifestEntry, Item } from '../shared/types';
import { renderUnlock } from './components/unlock';
import { renderItemList } from './components/item-list';
import { renderItemDetail } from './components/item-detail';
@@ -25,9 +25,9 @@ export type View = 'locked' | 'list' | 'detail' | 'add' | 'edit' | 'settings';
export interface PopupState {
view: View;
entries: Array<[string, ManifestEntry]>;
selectedId: string | null;
selectedEntry: Entry | null;
entries: Array<[ItemId, ManifestEntry]>;
selectedId: ItemId | null;
selectedItem: Item | null;
selectedIndex: number;
searchQuery: string;
activeGroup: string | null;
@@ -45,7 +45,7 @@ let currentState: PopupState = {
view: 'locked',
entries: [],
selectedId: null,
selectedEntry: null,
selectedItem: null,
selectedIndex: 0,
searchQuery: '',
activeGroup: null,
@@ -135,10 +135,10 @@ async function init(): Promise<void> {
const data = unlockResp.data as { unlocked: boolean };
if (data.unlocked) {
// Load entries and go to list.
const listResp = await sendMessage({ type: 'list_entries' });
const listResp = await sendMessage({ type: 'list_items' });
if (listResp.ok) {
const listData = listResp.data as { entries: Array<[string, ManifestEntry]> };
navigate('list', { entries: listData.entries });
const listData = listResp.data as { items: Array<[ItemId, ManifestEntry]> };
navigate('list', { entries: listData.items });
return;
}
}