app/routes/frame.tsx
47 lines and 4 functions in DrDustinEdwards/carrel, at commit d5d5e82 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| loader | 14 to 22 | 2 | 0% | WatchCRAP 6 | No data: mutation testing has not run on this repo yet |
| <anonymous:20> | 20 to 20 | 1 | 0% | OkCRAP 2 | No data: mutation testing has not run on this repo yet |
| Layout | 24 to 30 | 1 | 0% | OkCRAP 2 | No data: mutation testing has not run on this repo yet |
| ErrorBoundary | 33 to 53 | 8 | 0% | CriticalCRAP 72 | No data: mutation testing has not run on this repo yet |
Imports
It imports app/components/frame.tsx, app/lib/context.ts, app/lib/people.server.ts. No module of this repo imports it.
Source
// The layout every page sits in: Capsomer's shell with Carrel's name, its projects and the views the
// viewer may open. It reads who is signed in from the gate's context, so a person with no projects
// still gets Home, and only the Owner is offered the Owner's views.
import { isRouteErrorResponse, Outlet, useRouteError, useRouteLoaderData } from "react-router";
import { Empty } from "capsomer/react/empty";
import { Frame, type FrameData } from "~/components/frame";
import { getEnv, getViewer } from "~/lib/context";
import { visibleProjects } from "~/lib/people.server";
import type { Route } from "./+types/frame";
export async function loader({ context }: Route.LoaderArgs): Promise<FrameData> {
const viewer = getViewer(context);
const projects = await visibleProjects(getEnv(context).DB, viewer);
return {
name: viewer.name || viewer.email,
isOwner: viewer.isOwner,
projects: projects.map((p) => ({ slug: p.slug, name: p.name, kind: p.kind })),
};
}
export default function Layout({ loaderData }: Route.ComponentProps) {
return (
<Frame data={loaderData}>
<Outlet />
</Frame>
);
}
// A page that fails keeps the frame, so the way back is still in reach.
export function ErrorBoundary() {
const error = useRouteError();
const data = useRouteLoaderData<typeof loader>("routes/frame") ?? null;
const status = isRouteErrorResponse(error) ? error.status : null;
const title = status === 404 ? "Not found" : status === 403 ? "You may not open this" : "Something went wrong";
const detail =
status === 404
? "There is nothing at this address, or it is not shared with you."
: status === 403
? "Your role on this project does not allow it."
: "Nothing you wrote is lost. Try again, or go back to Home.";
return (
<Frame data={data}>
<div className="app-page">
<Empty kind="failed" title={status ? `${status}: ${title}` : title} action={<a className="cap-btn" href="/">Go to Home</a>}>
{detail}
</Empty>
</div>
</Frame>
);
}