Skip to content

Commit 38d7c96

Browse files
committed
Implement Repo UI - Implement document alike markdown viewer with white background (#25)
Signed-off-by: Dae❤️ <74119677+daeisbae@users.noreply.github.com>
1 parent a98e8d2 commit 38d7c96

File tree

9 files changed

+209
-39
lines changed

9 files changed

+209
-39
lines changed

next.config.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/** @type {import('next').NextConfig} */
2-
const nextConfig = {};
2+
const nextConfig = {
3+
transpilePackages: ['next-mdx-remote'],
4+
}
35

4-
export default nextConfig;
6+
export default nextConfig

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"langchain": "^0.3.7",
2323
"lucide-react": "^0.469.0",
2424
"next": "15.1.0",
25+
"next-mdx-remote": "^5.0.0",
2526
"pg": "^8.13.1",
2627
"react": "^19.0.0",
2728
"react-dom": "^19.0.0",

src/agent/structured-output/schema-factory.ts

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,36 +49,10 @@ File Schema Example Output:
4949
summary: z
5050
.string()
5151
.describe(
52-
'Summary of the file, its main purpose, and its role in the project. Include Markdown links to important code blocks within this file using the format `[{Description of Code Block}]({Full github url of the file including the start line with optional ending line}#L{startLine}-L{endLine})` where applicable.'
53-
),
54-
relevantCodeBlocks: z
55-
.array(
56-
z.object({
57-
name: z
58-
.string()
59-
.describe(
60-
'Name or identifier of the code block (e.g., function name, class name, key variable).'
61-
),
62-
description: z
63-
.string()
64-
.describe(
65-
'Description of the code block and its significance within the file.'
66-
),
67-
startLine: z
68-
.number()
69-
.describe(
70-
'Starting line number of the code block.'
71-
),
72-
endLine: z
73-
.number()
74-
.describe(
75-
'Ending line number of the code block.'
76-
),
77-
})
78-
)
79-
.optional()
80-
.describe(
81-
'List of important code blocks (functions, classes, key sections) within the file, with line numbers.'
52+
'Summary of the file talking about its main purpose, and its role in the project.\n'
53+
+ 'Include Markdown links to important code blocks within this file using the format\n`'
54+
+ '[{Description of Code Block}]({Full github url of the file including the start line with optional ending line}#L{startLine}-L{endLine})` where applicable.\n'
55+
+ 'Also you should not return more than 2-3 paragraphs of summary.'
8256
),
8357
})
8458

src/app/[ownerSlug]/[repoSlug]/page.tsx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { JSX, Suspense } from 'react'
22
import { RepoCard } from '@/components/RepoCard'
33
import Loading from '@/app/[ownerSlug]/[repoSlug]/loading'
44
import { FetchRepoService, FullRepository } from '@/db/get-db'
5+
import { MarkdownContent } from '@/components/MarkdownContent'
56
import { notFound } from 'next/navigation'
67

78
interface PageProps {
@@ -11,24 +12,49 @@ interface PageProps {
1112
}
1213
}
1314

14-
export default async function RepoPage({
15-
params,
16-
}: PageProps): Promise<JSX.Element> {
17-
const { ownerSlug, repoSlug } = await params
18-
console.log(ownerSlug, repoSlug)
15+
interface RepoPageProps {
16+
ownerSlug: string
17+
repoSlug: string
18+
}
19+
20+
const placeholder = `
21+
# parser.cpp\n\n
22+
23+
- Reference \`parser/parser.cpp\`\n
1924
25+
This file defines the \`Parser\` class, responsible for transforming a stream of tokens into an Abstract Syntax Tree (AST). The parser utilizes a queue of \`TokenPtr\` objects (\`tok_queue_\`) and provides methods for consuming tokens (\`Eat\`), peeking at the next token (\`Peek\`), and expecting specific token types (\`ExpectedTokenType\`). The core functionality resides in \`ProduceAST\` which drives the parsing process by repeatedly calling \`ParseStatement\` until an end-of-line token is encountered. Different parsing methods are present to handle various expressions such as \`ParsePrimaryExpression\`, \`ParseAdditionExpression\`, \`ParseMultiplicationExpression\`, and \`ParseComparisonExpression\`. It supports variable declarations and assignments, and also handles whitespace using \`ParseWhitespaceExpression\`. The parser uses recursive descent parsing strategy with helper functions for each type of expression. It throws \`UnexpectedTokenParsedException\` when unexpected tokens are encountered. The \`Parser\` class depends on the \`TokenPtr\` and the \`ast.hpp\` module for the AST node definitions. Key methods include: [\`Eat\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L11-L15) for consuming tokens, [\`Peek\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L17-L17) for peeking at tokens, [\`ExpectedTokenType\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L19-L39) for validating token types, [\`ProduceAST\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L41-L53) for generating the AST, [\`ParseStatement\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L55-L62) for parsing statements, and [\`ParseExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L64-L66) for parsing expressions. The file also handles different types of expressions using separate parsing methods like [\`ParsePrimaryExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L68-L145), [\`ParseAdditionExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L147-L165), [\`ParseMultiplicationExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L167-L185), [\`ParseWhitespaceExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L187-L192), [\`ParseIdentifierDeclarationExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L194-L217), [\`ParseIdentifierAssignmentExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L219-L243), and [\`ParseComparisonExpression\`](https://github.com/daeisbae/AParser/blob/9bbea84efa9f8eeed5576f53e4a65ca87a7f023c/parser/parser.cpp#L245-L263).
26+
`
27+
28+
async function RepoPage({
29+
ownerSlug,
30+
repoSlug,
31+
}: RepoPageProps): Promise<JSX.Element> {
2032
const fetchRepoService = new FetchRepoService()
2133
const repoDetails: FullRepository | null =
2234
await fetchRepoService.getFullRepositoryTree(ownerSlug, repoSlug)
2335

2436
if (!repoDetails) {
25-
console.log('Repo not found')
2637
notFound()
2738
}
2839

40+
return (
41+
<div className="flex gap-6 p-6">
42+
<div className="flex-1">
43+
<MarkdownContent content={placeholder} />
44+
</div>
45+
<div className="w-[300px]">
46+
<RepoCard repoInfo={repoDetails.repository} />
47+
</div>
48+
</div>
49+
)
50+
}
51+
52+
export default function DocumentationPage({ params }: PageProps) {
53+
const { ownerSlug, repoSlug } = params
54+
2955
return (
3056
<Suspense fallback={<Loading />}>
31-
<RepoCard repoInfo={repoDetails.repository} />
57+
<RepoPage ownerSlug={ownerSlug} repoSlug={repoSlug} />
3258
</Suspense>
3359
)
3460
}

src/app/layout.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import './globals.css'
2+
import Navbar from '@/components/NavBar'
3+
4+
export const metadata = {
5+
title: 'OpenRepoWiki',
6+
description: 'A Wikipedia of Github Repositories of how it is made.',
7+
}
8+
9+
interface RootLayoutProps {
10+
children: React.ReactNode
11+
}
12+
13+
export default function RootLayout({ children } : RootLayoutProps) {
14+
return (
15+
<html lang="en">
16+
<body className="bg-white">
17+
<Navbar />
18+
<main className="max-w-7xl mx-auto p-6">{children}</main>
19+
</body>
20+
</html>
21+
)
22+
}

src/components/MarkdownContent.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use client'
2+
3+
import { MDXRemote } from 'next-mdx-remote'
4+
import { serialize } from 'next-mdx-remote/serialize'
5+
import { useState, useEffect } from 'react'
6+
import React from 'react'
7+
import { Skeleton } from '@/components/ui/skeleton'
8+
9+
interface MarkdownContentProps {
10+
content: string
11+
}
12+
13+
export function MarkdownContent({ content }: MarkdownContentProps) {
14+
const [serializedContent, setSerializedContent] = useState<any>(null)
15+
16+
useEffect(() => {
17+
const serializeMarkdown = async () => {
18+
const serialized = await serialize(content)
19+
setSerializedContent(serialized)
20+
}
21+
serializeMarkdown()
22+
}, [content])
23+
24+
if (!serializedContent) {
25+
return <Skeleton className="h-[200px] w-full" />
26+
}
27+
28+
return (
29+
<div className="prose dark:prose-invert max-w-none">
30+
<MDXRemote {...serializedContent} />
31+
</div>
32+
)
33+
}

src/components/ui/badge.jsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from "react"
2+
import { cva } from "class-variance-authority";
3+
4+
import { cn } from "@/lib/utils"
5+
6+
const badgeVariants = cva(
7+
"inline-flex items-center rounded-md border border-neutral-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 dark:border-neutral-800 dark:focus:ring-neutral-300",
8+
{
9+
variants: {
10+
variant: {
11+
default:
12+
"border-transparent bg-neutral-900 text-neutral-50 shadow hover:bg-neutral-900/80 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/80",
13+
secondary:
14+
"border-transparent bg-neutral-100 text-neutral-900 hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80",
15+
destructive:
16+
"border-transparent bg-red-500 text-neutral-50 shadow hover:bg-red-500/80 dark:bg-red-900 dark:text-neutral-50 dark:hover:bg-red-900/80",
17+
outline: "text-neutral-950 dark:text-neutral-50",
18+
},
19+
},
20+
defaultVariants: {
21+
variant: "default",
22+
},
23+
}
24+
)
25+
26+
function Badge({
27+
className,
28+
variant,
29+
...props
30+
}) {
31+
return (<div className={cn(badgeVariants({ variant }), className)} {...props} />);
32+
}
33+
34+
export { Badge, badgeVariants }

src/components/ui/card.jsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as React from "react"
2+
3+
import { cn } from "@/lib/utils"
4+
5+
const Card = React.forwardRef(({ className, ...props }, ref) => (
6+
<div
7+
ref={ref}
8+
className={cn(
9+
"rounded-xl border border-neutral-200 bg-white text-neutral-950 shadow dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
10+
className
11+
)}
12+
{...props} />
13+
))
14+
Card.displayName = "Card"
15+
16+
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
17+
<div
18+
ref={ref}
19+
className={cn("flex flex-col space-y-1.5 p-6", className)}
20+
{...props} />
21+
))
22+
CardHeader.displayName = "CardHeader"
23+
24+
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
25+
<div
26+
ref={ref}
27+
className={cn("font-semibold leading-none tracking-tight", className)}
28+
{...props} />
29+
))
30+
CardTitle.displayName = "CardTitle"
31+
32+
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
33+
<div
34+
ref={ref}
35+
className={cn("text-sm text-neutral-500 dark:text-neutral-400", className)}
36+
{...props} />
37+
))
38+
CardDescription.displayName = "CardDescription"
39+
40+
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
41+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
42+
))
43+
CardContent.displayName = "CardContent"
44+
45+
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
46+
<div
47+
ref={ref}
48+
className={cn("flex items-center p-6 pt-0", className)}
49+
{...props} />
50+
))
51+
CardFooter.displayName = "CardFooter"
52+
53+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

src/components/ui/separator.jsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as SeparatorPrimitive from "@radix-ui/react-separator"
5+
6+
import { cn } from "@/lib/utils"
7+
8+
const Separator = React.forwardRef((
9+
{ className, orientation = "horizontal", decorative = true, ...props },
10+
ref
11+
) => (
12+
<SeparatorPrimitive.Root
13+
ref={ref}
14+
decorative={decorative}
15+
orientation={orientation}
16+
className={cn(
17+
"shrink-0 bg-neutral-200 dark:bg-neutral-800",
18+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
19+
className
20+
)}
21+
{...props} />
22+
))
23+
Separator.displayName = SeparatorPrimitive.Root.displayName
24+
25+
export { Separator }

0 commit comments

Comments
 (0)