Animate InspectorView screen transitions and refactor App.tsx

- InspectorView: wrap each screen in a Mantine `Transition` (`fade-up`,
  350ms). Outgoing screens fade out and slide down 30px; incoming screens
  fade in and slide up to meet the ViewHeader. A `pos: "relative"` Stack
  container holds the screens so the absolute-positioned `Transition`
  wrappers stack in the same area without pushing layout.
- InspectorView: reorder ALL_TABS so Logs sits beside History at the end:
  Servers · Tools · Prompts · Resources · Tasks · Logs · History.
- App.tsx: refactor to AGENTS.md guidelines — extract `PageContainer`,
  `PageStack`, `ThemeToggle`, `SubtitleText` as `.withProps()`
  subcomponents; replace inline unicode glyphs with `MdLightMode` /
  `MdDarkMode` icons (matches the ViewHeader pattern); convert the click
  handler to a `function` declaration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-04-25 19:33:57 -04:00
commit d3c2645e38

View file

@ -1,5 +1,5 @@
import { useMemo, useState } from "react";
import { AppShell } from "@mantine/core";
import { useMemo, useState, type ReactNode } from "react";
import { AppShell, Box, Stack, Transition } from "@mantine/core";
import type {
InitializeResult,
LoggingLevel,
@ -35,11 +35,45 @@ const ALL_TABS: string[] = [
"Tools",
"Prompts",
"Resources",
"Logs",
"Tasks",
"Logs",
"History",
];
const SCREEN_TRANSITION_MS = 350;
const ScreenStageContainer = Stack.withProps({
pos: "relative",
gap: 0,
flex: 1,
mih: "100%",
});
function ScreenStage({
active,
children,
}: {
active: boolean;
children: ReactNode;
}) {
return (
<Transition
mounted={active}
transition="fade-up"
duration={SCREEN_TRANSITION_MS}
timingFunction="ease"
>
{(styles) => (
// `style={styles}` is the runtime transition state from Mantine's
// Transition API — these are interpolated values, not static styling.
<Box style={styles} pos="absolute" top={0} left={0} right={0}>
{children}
</Box>
)}
</Transition>
);
}
// Demo stub: every screen-action callback below resolves to noop. Phase 3
// wiring will replace each with its real `useManaged*` / `useConnection`
// hook call. Anything still pointing here in Phase 3 is unfinished.
@ -204,84 +238,86 @@ export function InspectorView({
)}
</AppShell.Header>
<AppShell.Main>
{activeTab === SERVERS_TAB && (
<ServerListScreen
servers={servers}
activeServer={activeServer}
onAddManually={noop}
onImportConfig={noop}
onImportServerJson={noop}
onToggleConnection={handleToggleConnection}
onServerInfo={noop}
onSettings={noop}
onEdit={noop}
onClone={noop}
onRemove={noop}
/>
)}
{activeTab === "Tools" && (
<ToolsScreen
tools={tools}
listChanged={false}
onRefreshList={noop}
onSelectTool={noop}
onCallTool={noop}
/>
)}
{activeTab === "Prompts" && (
<PromptsScreen
prompts={prompts}
listChanged={false}
onRefreshList={noop}
onSelectPrompt={noop}
onGetPrompt={noop}
/>
)}
{activeTab === "Resources" && (
<ResourcesScreen
resources={resources}
templates={resourceTemplates}
subscriptions={subscriptions}
listChanged={false}
onRefreshList={noop}
onSelectUri={noop}
onSelectTemplate={noop}
onReadResource={noop}
onSubscribeResource={noop}
onUnsubscribeResource={noop}
/>
)}
{activeTab === "Logs" && (
<LoggingScreen
entries={logs}
currentLevel={logLevel}
onSetLevel={setLogLevel}
onClear={noop}
onExport={noop}
autoScroll={autoScroll}
onToggleAutoScroll={() => setAutoScroll((prev) => !prev)}
onCopyAll={noop}
/>
)}
{activeTab === "Tasks" && (
<TasksScreen
tasks={tasks}
progressByTaskId={progressByTaskId}
onRefresh={noop}
onClearCompleted={noop}
onCancel={noop}
/>
)}
{activeTab === "History" && (
<HistoryScreen
entries={history}
pinnedIds={new Set()}
onClearAll={noop}
onExport={noop}
onReplay={noop}
onTogglePin={noop}
/>
)}
<ScreenStageContainer>
<ScreenStage active={activeTab === SERVERS_TAB}>
<ServerListScreen
servers={servers}
activeServer={activeServer}
onAddManually={noop}
onImportConfig={noop}
onImportServerJson={noop}
onToggleConnection={handleToggleConnection}
onServerInfo={noop}
onSettings={noop}
onEdit={noop}
onClone={noop}
onRemove={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "Tools"}>
<ToolsScreen
tools={tools}
listChanged={false}
onRefreshList={noop}
onSelectTool={noop}
onCallTool={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "Prompts"}>
<PromptsScreen
prompts={prompts}
listChanged={false}
onRefreshList={noop}
onSelectPrompt={noop}
onGetPrompt={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "Resources"}>
<ResourcesScreen
resources={resources}
templates={resourceTemplates}
subscriptions={subscriptions}
listChanged={false}
onRefreshList={noop}
onSelectUri={noop}
onSelectTemplate={noop}
onReadResource={noop}
onSubscribeResource={noop}
onUnsubscribeResource={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "Tasks"}>
<TasksScreen
tasks={tasks}
progressByTaskId={progressByTaskId}
onRefresh={noop}
onClearCompleted={noop}
onCancel={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "Logs"}>
<LoggingScreen
entries={logs}
currentLevel={logLevel}
onSetLevel={setLogLevel}
onClear={noop}
onExport={noop}
autoScroll={autoScroll}
onToggleAutoScroll={() => setAutoScroll((prev) => !prev)}
onCopyAll={noop}
/>
</ScreenStage>
<ScreenStage active={activeTab === "History"}>
<HistoryScreen
entries={history}
pinnedIds={new Set()}
onClearAll={noop}
onExport={noop}
onReplay={noop}
onTogglePin={noop}
/>
</ScreenStage>
</ScreenStageContainer>
</AppShell.Main>
</AppShell>
);