feat: port TechLog discovery screens

This commit is contained in:
DongHyeonka
2026-08-15 22:29:57 +09:00
parent c9164c1a03
commit ef1d5cc548
12 changed files with 1130 additions and 15 deletions
+24 -15
View File
@@ -48,7 +48,10 @@ import {
ROUTE_RUNTIME,
} from "../../features/installed-feature-runtimes.tsx";
import type { ParsedRouteInput } from "./route-contract.ts";
import { RouteInputProvider } from "./route-input.tsx";
import {
RegisteredNotFoundProvider,
RouteInputProvider,
} from "./route-input.tsx";
function RouteLoadingSurface({ definition }: { definition: RouteDefinition }) {
const { message, resolve } = useLocale();
@@ -256,12 +259,14 @@ function RegisteredRoute<RouteIdValue extends string>({
definition,
runtime,
codecs,
NotFoundComponent,
}: {
routeId: RouteIdValue;
buildId: string;
definition: RouteDefinition;
runtime: GroupedRouteRuntimeDefinition;
codecs: RouteCodecRegistry;
NotFoundComponent?: ComponentType;
}) {
const params = useParams();
const [search] = useSearchParams();
@@ -280,20 +285,22 @@ function RegisteredRoute<RouteIdValue extends string>({
const content = (
<RouteInputProvider input={routeInput}>
<CanonicalRouteRedirect
input={routeInput}
definition={definition}
codecs={codecs}
/>
<RouteLifecycle definition={definition} buildId={buildId} />
<Suspense fallback={<RouteLoadingSurface definition={definition} />}>
<ChunkRecoveryBoundary
chunkId={definition.chunkId}
recover={recovery.recoverChunk}
>
<RuntimeComponent />
</ChunkRecoveryBoundary>
</Suspense>
<RegisteredNotFoundProvider Component={NotFoundComponent}>
<CanonicalRouteRedirect
input={routeInput}
definition={definition}
codecs={codecs}
/>
<RouteLifecycle definition={definition} buildId={buildId} />
<Suspense fallback={<RouteLoadingSurface definition={definition} />}>
<ChunkRecoveryBoundary
chunkId={definition.chunkId}
recover={recovery.recoverChunk}
>
<RuntimeComponent />
</ChunkRecoveryBoundary>
</Suspense>
</RegisteredNotFoundProvider>
</RouteInputProvider>
);
const protectedContent =
@@ -345,6 +352,7 @@ export function createGroupedRouteObjects(
PUBLIC: [],
STUDIO: [],
};
const NotFoundComponent = runtime.NOT_FOUND?.Component;
for (const definition of Object.values(registry)) {
const routeId = definition.routeId;
const routeRuntime = runtime[definition.routeId];
@@ -358,6 +366,7 @@ export function createGroupedRouteObjects(
definition={definition}
runtime={routeRuntime}
codecs={codecs}
NotFoundComponent={NotFoundComponent}
/>
);
if (definition.path === "/") {
+22
View File
@@ -1,4 +1,5 @@
import {
type ComponentType,
createContext,
type ReactNode,
useContext,
@@ -7,6 +8,7 @@ import {
import type { ParsedRouteInput, RouteId } from "./route-contract.ts";
const RouteInputContext = createContext<ParsedRouteInput<string> | null>(null);
const RegisteredNotFoundContext = createContext<ComponentType | null>(null);
export function RouteInputProvider<RouteIdValue extends string>({
input,
@@ -29,3 +31,23 @@ export function useRouteInput<
if (!input) throw new Error("Registered route input is required");
return input as ParsedRouteInput<RouteIdValue>;
}
export function RegisteredNotFoundProvider({
Component,
children,
}: Readonly<{
Component?: ComponentType;
children: ReactNode;
}>) {
return (
<RegisteredNotFoundContext.Provider value={Component ?? null}>
{children}
</RegisteredNotFoundContext.Provider>
);
}
export function RegisteredNotFoundRoute() {
const Component = useContext(RegisteredNotFoundContext);
if (!Component) throw new Error("Registered not-found runtime is required");
return <Component />;
}