// Pieces every artifact page shares: the type glyph and tile, the detail // frame and the back link to the library. Kept apart from the library and the // Site route so a file page does not load either. import { useNavigate, useSearch, useStringifySearch } from "../../lib/navigation"; import { FileIcon, FileTextIcon, Globe2Icon, ImageIcon, PresentationIcon, Table2Icon, type LucideIcon, } from "lucide-react"; import type { MouseEvent } from "react"; import type { DetailBackLink } from "../../../ui/detail-page"; import { LogoTile } from "../../../ui/logo-tile"; import { artifactKindLabel, type ArtifactKind } from "../../lib/artifact-catalog"; import { artifactLibraryFilters, artifactLibrarySearch, } from "../../lib/artifact-library-navigation"; import type { ArtifactReturnSearch } from "../../lib/routes"; // Resolved at render, not in a module-level table: these icons can live in a // chunk that loads after this one, and a table built while this module loads // would hold undefined (the Artifacts list then fails to render). function artifactTypeGlyph(kind: ArtifactKind): LucideIcon { switch (kind) { case "site": return Globe2Icon; case "image": return ImageIcon; case "document": return FileTextIcon; case "spreadsheet": return Table2Icon; case "presentation": return PresentationIcon; default: return FileIcon; } } export function ArtifactTypeIcon({ kind, className, }: { kind: ArtifactKind; className?: string | undefined; }) { const Icon = artifactTypeGlyph(kind); return ; } /** The artifact's leading tile on its own page: its type glyph on the neutral tile. */ export function ArtifactKindTile({ kind }: { kind: ArtifactKind }) { return } name={artifactKindLabel[kind]} />; } /** Detail pages fill the content column; `DetailPage` draws the 960px frame. */ export const ARTIFACT_DETAIL_FRAME = "max-w-none px-0 py-0 pb-0 sm:px-0 lg:px-0"; /** * Whether the artifact page shows the artifact itself, full screen. Links from * outside the Artifacts list (chats, notifications, copied or pasted URLs) * do; the list marks its links with `browse` to land on the detail page. * Switching replaces the history entry, so the browser's back button still * returns to wherever the person came from. */ export function useArtifactFullView(): [boolean, (fullView: boolean) => void] { const navigate = useNavigate(); const search: ArtifactReturnSearch = useSearch({ strict: false }); // A link to one of a Site's tabs (Settings, Versions…) lands on its page. const fullView = search.browse !== true && search.view === undefined && search.tab === undefined; const setFullView = (next: boolean) => void navigate({ to: ".", search: { ...search, browse: next ? undefined : true }, replace: true, }); return [fullView, setFullView]; } /** "← Artifacts", keeping the way back to the session it was opened from. */ export function useArtifactsBackLink(workspaceId: string, fromSession?: string): DetailBackLink { const navigate = useNavigate(); const search = artifactLibrarySearch( artifactLibraryFilters(useSearch({ strict: false })), fromSession, ); const query = useStringifySearch()(search); return { label: "Artifacts", href: `/workspaces/${encodeURIComponent(workspaceId)}/artifacts${query}`, // The link keeps a real href (new tab, copy); a plain click stays in the router. onClick: (event?: MouseEvent) => { if ( event && (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) ) return; event?.preventDefault(); void navigate({ to: "/workspaces/$workspaceId/artifacts", params: { workspaceId }, search, }); }, }; }