refactor(console-web): centralize page lifecycle and UI composition

Declare navigation, page metadata, lazy loaders, and keep-alive policy in one registry. Retain primary iframe pages until a continuous inactive TTL expires and expose typed show, hide, and unload events through the Page SDK.

Move business-aware components out of the UI primitive directory, migrate views and Host dialogs to variant primitives and local Tailwind classes, and remove the global component style layer. Keep native dialogs inside the overlay flex context so they remain centered.

Cover iframe expiration, lifecycle dispatch, UI dependency direction, and global style ownership with focused tests.
This commit is contained in:
Maofeng
2026-07-30 15:16:02 +08:00
parent 23fa6137ff
commit 9ff3223c44
30 changed files with 1136 additions and 872 deletions
@@ -1,7 +1,10 @@
import { History, RefreshCw } from "lucide-solid";
import { createMemo, For, Show } from "solid-js";
import { EmptyState } from "../../components/ui/empty-state";
import { PageHeading } from "../../components/ui/page-heading";
import { createMemo, For, onCleanup, Show } from "solid-js";
import { EmptyState } from "../../components/feedback/empty-state";
import { Page } from "../../components/layout/page";
import { PageHeading } from "../../components/layout/page-heading";
import { IconButton } from "../../components/ui/button";
import { Card } from "../../components/ui/card";
import { eventsFrom } from "../../lib/view-state";
import type { PageProps } from "../types";
@@ -13,6 +16,11 @@ const toneClass = {
};
export default function ActivityPage(props: PageProps) {
// A retained Activity iframe may have been hidden for a while. Request a
// fresh snapshot whenever it becomes visible instead of waiting for the
// Host's next background poll.
onCleanup(props.lifecycle.onShow(() => props.command({ type: "refresh" })));
const events = createMemo(() => {
const query = props.state()?.query.trim().toLowerCase() ?? "";
return eventsFrom(props.state()).filter(
@@ -24,18 +32,22 @@ export default function ActivityPage(props: PageProps) {
});
return (
<main class="page">
<Page>
<PageHeading
eyebrow="EVENTS"
title="调用记录"
description="最近 256 条持久化生命周期与调用事件。"
actions={
<button class="icon-btn" title="刷新" onClick={() => props.command({ type: "refresh" })}>
<IconButton
aria-label="刷新"
title="刷新"
onClick={() => props.command({ type: "refresh" })}
>
<RefreshCw size={16} />
</button>
</IconButton>
}
/>
<section class="panel">
<Card as="section">
<Show
when={events().length > 0}
fallback={
@@ -55,7 +67,7 @@ export default function ActivityPage(props: PageProps) {
</For>
</div>
</Show>
</section>
</main>
</Card>
</Page>
);
}