feat(ext): shared state host — decouple components from popup.ts

Introduce shared/state.ts as a service-locator so popup components
(item-detail, item-form, trash, devices, settings, etc.) work in both
the popup and vault tab bundles. Both entry points register themselves
as the host; components import from shared/state instead of popup.ts.
Vault.ts now delegates to the real popup components, removing ~300 lines
of placeholder renderers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-04-27 16:38:06 -04:00
parent 6c8ebb3548
commit ce59223fc0
38 changed files with 259 additions and 441 deletions

View File

@@ -2,7 +2,7 @@
/// type-iconed rows. Clicking a row fetches the full Item and navigates
/// to the detail view.
import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../popup';
import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../../shared/state';
import type { ItemId, ItemType, ManifestEntry, Item } from '../../shared/types';
/// Extract the display hostname from an icon_hint or fallback to the first tag.
@@ -148,8 +148,9 @@ async function openItem(id: ItemId): Promise<void> {
/// Compute the visible (filtered) entry list from current state.
function getFilteredEntries(): Array<[ItemId, ManifestEntry]> {
const state = getState();
const entries: Array<[ItemId, ManifestEntry]> = state.entries;
// Hide trashed items from the main list.
let filtered = state.entries.filter(([, e]) => e.trashed_at === undefined || e.trashed_at === null);
let filtered = entries.filter(([, e]) => e.trashed_at === undefined || e.trashed_at === null);
if (state.searchQuery) {
const q = state.searchQuery.toLowerCase();
filtered = filtered.filter(([, e]) => {