diff --git a/web/src/app/routes/root.tsx b/web/src/app/routes/root.tsx index 3d6f6efb46..5125eae97d 100644 --- a/web/src/app/routes/root.tsx +++ b/web/src/app/routes/root.tsx @@ -1,5 +1,4 @@ -import { Link, Outlet, createRootRoute } from "@tanstack/react-router"; -import { ThemeToggle } from "@/shared/theme/ThemeToggle"; +import { Outlet, createRootRoute } from "@tanstack/react-router"; export const Route = createRootRoute({ component: RootLayout, @@ -8,15 +7,6 @@ export const Route = createRootRoute({ function RootLayout() { return (
{host}
-- Buzz is a messaging platform for human–agent collaboration. Accept this - invite in the desktop app to join the workspace on this relay. -
+{host}
-- Already have Buzz installed? “Open in Buzz” will launch it - and accept the invite. Otherwise download the app first, then come back - and use this link again. -
`. return ( -+{content}); @@ -125,7 +132,7 @@ function ImageView({ const url = useObjectUrl(bytes, contentType); if (!url) return null; return ( -+); } @@ -174,7 +181,7 @@ function ViewerBody({ return
; case "markdown": return ( - +); @@ -196,14 +203,14 @@ function ViewerBody({ ); case "binary": return ( -{view.content} +Binary file — {formatBytes(view.sizeBytes)}. Use the Download button above to save it.); case "too-large": return ( -+File is {formatBytes(view.sizeBytes)}, over the{" "} {formatBytes(view.limitBytes)} preview limit. Use the Download button above to save it. @@ -215,19 +222,29 @@ function ViewerBody({ export function RepoBlobPage() { const { repoId, _splat } = useParams({ from: "/repos/$repoId/blob/$" }); const filepath = _splat ?? ""; + const preview = + import.meta.env.DEV && + new URLSearchParams(window.location.search).get("preview") === + "repositories"; + const mockView = preview ? getMockBlob(repoId, filepath) : undefined; + const showMockBlob = Boolean(mockView); const { owner, repoName, defaultRef, isLoading: ctxLoading, error: ctxError, - } = useRepoContext(repoId); + } = useRepoContext(repoId, { preview: showMockBlob }); + + const browseOwner = showMockBlob ? "" : owner; const { - data: view, - isLoading, + data: fetchedView, + isLoading: isViewLoading, error, - } = useGitBlob(owner, repoName, defaultRef, filepath); + } = useGitBlob(browseOwner, repoName, defaultRef, filepath); + const view = mockView ?? fetchedView; + const isLoading = showMockBlob ? false : isViewLoading; const [running, setRunning] = useState(false); const isHtml = view?.kind === "html"; @@ -244,8 +261,8 @@ export function RepoBlobPage() { if (ctxError) { return ( --+ +Failed to load repository: {ctxError.message}
@@ -254,11 +271,11 @@ export function RepoBlobPage() { } return ( --+ + -+ {filepath}
{view && @@ -271,6 +288,7 @@ export function RepoBlobPage() {setRunning((r) => !r)} > @@ -296,7 +314,7 @@ export function RepoBlobPage() { {ctxLoading || isLoading ? ( - + ) : error ? (Failed to load file: {(error as Error).message} @@ -313,12 +331,13 @@ export function RepoBlobPage() { ); } -function BackLink({ repoId }: { repoId: string }) { +function BackLink({ repoId, preview }: { repoId: string; preview: boolean }) { return (
Back to repository diff --git a/web/src/features/repos/ui/RepoCommitsSection.tsx b/web/src/features/repos/ui/RepoCommitsSection.tsx index 737f4a9755..13c826df3e 100644 --- a/web/src/features/repos/ui/RepoCommitsSection.tsx +++ b/web/src/features/repos/ui/RepoCommitsSection.tsx @@ -5,15 +5,15 @@ import type { CommitInfo } from "../git-client"; function CommitRow({ commit }: { commit: CommitInfo }) { const firstLine = commit.message.split("\n")[0]; return ( - -+ +@@ -30,20 +30,20 @@ export function RepoCommitsSection({ if (isLoading) { return ( -{firstLine}
-+
{commit.author.name} committed {relativeTime(commit.author.timestamp)}
+{commit.oid.slice(0, 7)}-+
-
Recent commits +{["sk-1", "sk-2", "sk-3"].map((key) => (- +))} @@ -56,11 +56,11 @@ export function RepoCommitsSection({ return (- - + +-+
-
Recent commits +{commits.map((commit) => ())} diff --git a/web/src/features/repos/ui/RepoDetailPage.tsx b/web/src/features/repos/ui/RepoDetailPage.tsx index 07e683139f..baedb3aadf 100644 --- a/web/src/features/repos/ui/RepoDetailPage.tsx +++ b/web/src/features/repos/ui/RepoDetailPage.tsx @@ -16,6 +16,12 @@ import { Button } from "@/shared/ui/button"; import { relativeTime } from "@/shared/lib/relative-time"; import { useRepoRefs } from "../use-repo-refs"; import { useRepo } from "../use-repos"; +import { + getMockRepo, + mockRepoCommits, + mockRepoReadme, + mockRepoTree, +} from "../mock-repos"; import type { CommitInfo, ReadmeResult, TreeEntry } from "../git-client"; import { useGitTree, useGitLog, useGitReadme } from "../use-git-browse"; import { ConnectButton } from "./ConnectButton"; @@ -40,12 +46,14 @@ function CopyableUrl({ url }: { url: string }) { } return ( - -{url}+++ {url} +{copied ? ( @@ -60,14 +68,14 @@ function CopyableUrl({ url }: { url: string }) { function DetailSkeleton() { return ( - +- - - + + +@@ -75,6 +83,31 @@ function DetailSkeleton() { ); } +function BackToRepositories({ + mockPreview = false, +}: { + mockPreview?: boolean; +}) { + const className = + "inline-flex items-center gap-1 text-sm text-black/60 hover:text-black dark:text-white/60 dark:hover:text-white"; + const content = ( + <> +- - + ++ Back to repositories + > + ); + + return mockPreview ? ( + + {content} + + ) : ( + + {content} + + ); +} + type Tab = "code" | "commits"; function RepoTabs({ @@ -85,6 +118,7 @@ function RepoTabs({ commitsLoading, readme, readmeLoading, + preview, }: { repoId: string; treeEntries: TreeEntry[] | undefined; @@ -93,20 +127,21 @@ function RepoTabs({ commitsLoading: boolean; readme: ReadmeResult | null | undefined; readmeLoading: boolean; + preview: boolean; }) { const [tab, setTab] = useState ("code"); return ( {/* Tab bar */} -+setTab("code")} className={`px-4 py-2 text-sm font-medium transition-colors ${ tab === "code" - ? "border-b-2 border-foreground text-foreground" - : "text-muted-foreground hover:text-foreground" + ? "border-b-2 border-black text-black dark:border-white dark:text-white" + : "text-black/50 hover:text-black dark:text-white/50 dark:hover:text-white" }`} > Code @@ -116,8 +151,8 @@ function RepoTabs({ onClick={() => setTab("commits")} className={`px-4 py-2 text-sm font-medium transition-colors ${ tab === "commits" - ? "border-b-2 border-foreground text-foreground" - : "text-muted-foreground hover:text-foreground" + ? "border-b-2 border-black text-black dark:border-white dark:text-white" + : "text-black/50 hover:text-black dark:text-white/50 dark:hover:text-white" }`} > Commits @@ -131,6 +166,7 @@ function RepoTabs({ entries={treeEntries} isLoading={treeLoading} repoId={repoId} + preview={preview} /> > @@ -144,28 +180,49 @@ function RepoTabs({ export function RepoDetailPage() { const { repoId } = useParams({ from: "/repos/$repoId" }); - const { data: repo, isLoading, error } = useRepo(repoId); - const { data: refs, isLoading: refsLoading } = useRepoRefs(repoId); + const preview = + import.meta.env.DEV && + new URLSearchParams(window.location.search).get("preview") === + "repositories"; + const mockRepo = preview ? getMockRepo(repoId) : undefined; + const showMockRepo = Boolean(mockRepo); + const { + data: repo, + isLoading, + error, + } = useRepo(repoId, { + preview: showMockRepo, + }); + const { data: refs, isLoading: refsLoading } = useRepoRefs(repoId, { + preview: showMockRepo, + }); const defaultRef = refs?.head?.ref ?? "main"; const owner = repo?.owner ?? ""; const repoName = repo?.id ?? ""; + const browseOwner = showMockRepo ? "" : owner; const { - data: treeEntries, - isLoading: treeLoading, + data: fetchedTreeEntries, + isLoading: isTreeLoading, error: treeError, - } = useGitTree(owner, repoName, defaultRef); + } = useGitTree(browseOwner, repoName, defaultRef); const { - data: commits, - isLoading: commitsLoading, + data: fetchedCommits, + isLoading: areCommitsLoading, error: commitsError, - } = useGitLog(owner, repoName, defaultRef); - const { data: readme, isLoading: readmeLoading } = useGitReadme( - owner, + } = useGitLog(browseOwner, repoName, defaultRef); + const { data: fetchedReadme, isLoading: isReadmeLoading } = useGitReadme( + browseOwner, repoName, defaultRef, ); + const treeEntries = showMockRepo ? mockRepoTree : fetchedTreeEntries; + const commits = showMockRepo ? mockRepoCommits : fetchedCommits; + const readme = showMockRepo ? mockRepoReadme : fetchedReadme; + const treeLoading = showMockRepo ? false : isTreeLoading; + const commitsLoading = showMockRepo ? false : areCommitsLoading; + const readmeLoading = showMockRepo ? false : isReadmeLoading; // Surface clone/browse errors — these are otherwise silent const browseError = treeError || commitsError; @@ -187,19 +244,15 @@ export function RepoDetailPage() { if (!repo) { return ( - +- -- Back to repositories - + -- Repository not found
-+
+ + Repository not found +
+This repository may have been removed or doesn't exist on this relay.
@@ -211,17 +264,11 @@ export function RepoDetailPage() { } return ( -+{/* Main content */}{/* Back link */} - -- Back to repositories - + {/* Mobile-only connect button */} @@ -231,18 +278,23 @@ export function RepoDetailPage() { {/* Header */}@@ -269,12 +321,15 @@ export function RepoDetailPage() { commitsLoading={commitsLoading} readme={readme} readmeLoading={readmeLoading} + preview={showMockRepo} /> {/* Clone URLs */} {repo.cloneUrls.length > 0 && (-{repo.description && ( -- +
+ {repo.name}
-Public ++ Public + +
{repo.description}
)} -+
Updated {relativeTime(repo.createdAt)}
-Clone
++ Clone +
{repo.cloneUrls.map((url) => (@@ -297,7 +352,11 @@ export function RepoDetailPage() { if (!safe) return null; return (