Skip to content

Commit 905b2cd

Browse files
authored
Merge pull request #28 from daeisbae/25-implement-ui-for-repo
Implement Repo UI - Same URI format like Github (https://<url>/<ownerSlug>/<repoSlug>). (#25)
2 parents 839b8a4 + 6f18ecf commit 905b2cd

File tree

18 files changed

+640
-34
lines changed

18 files changed

+640
-34
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: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@
1616
"@google/generative-ai": "^0.21.0",
1717
"@langchain/core": "^0.3.26",
1818
"axios": "^1.7.9",
19+
"class-variance-authority": "^0.7.1",
20+
"clsx": "^2.1.1",
1921
"dotenv": "^16.4.7",
2022
"langchain": "^0.3.7",
23+
"lucide-react": "^0.469.0",
2124
"next": "15.1.0",
25+
"next-mdx-remote": "^5.0.0",
2226
"pg": "^8.13.1",
2327
"react": "^19.0.0",
24-
"react-dom": "^19.0.0"
28+
"react-dom": "^19.0.0",
29+
"tailwind-merge": "^2.6.0"
2530
},
2631
"devDependencies": {
2732
"@babel/cli": "^7.26.4",

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Skeleton } from '@/components/ui/skeleton'
2+
3+
export default function Loading() {
4+
return (
5+
<div className="space-y-4">
6+
<Skeleton className="h-8 w-[250px]" />
7+
<Skeleton className="h-4 w-[200px]" />
8+
<Skeleton className="h-4 w-[150px]" />
9+
<div className="space-y-2">
10+
<Skeleton className="h-4 w-full" />
11+
<Skeleton className="h-4 w-full" />
12+
<Skeleton className="h-4 w-2/3" />
13+
</div>
14+
</div>
15+
)
16+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { JSX, Suspense } from 'react'
2+
import { RepoCard } from '@/components/RepoCard'
3+
import Loading from '@/app/[ownerSlug]/[repoSlug]/loading'
4+
import { FetchRepoService, FullRepository } from '@/db/get-db'
5+
import { MarkdownContent } from '@/components/MarkdownContent'
6+
import { notFound } from 'next/navigation'
7+
8+
interface PageProps {
9+
params: {
10+
ownerSlug: string
11+
repoSlug: string
12+
}
13+
}
14+
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
24+
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> {
32+
const fetchRepoService = new FetchRepoService()
33+
const repoDetails: FullRepository | null =
34+
await fetchRepoService.getFullRepositoryTree(ownerSlug, repoSlug)
35+
36+
if (!repoDetails) {
37+
notFound()
38+
}
39+
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+
55+
return (
56+
<Suspense fallback={<Loading />}>
57+
<RepoPage ownerSlug={ownerSlug} repoSlug={repoSlug} />
58+
</Suspense>
59+
)
60+
}

src/app/globals.css

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
body {
6+
font-family: Arial, Helvetica, sans-serif;
7+
}
8+
9+
@layer base {
10+
:root {
11+
--radius: 0.5rem;
12+
}
13+
}
14+
15+
h1 {
16+
font-size: 48px;
17+
font-weight: bold;
18+
}
19+
20+
h2 {
21+
font-size: 40px;
22+
font-weight: bold;
23+
}
24+
25+
h3 {
26+
font-size: 32px;
27+
font-weight: bold;
28+
}
29+
30+
h4 {
31+
font-size: 24px;
32+
font-weight: bold;
33+
}
34+
35+
h5 {
36+
font-size: 20px;
37+
font-weight: bold;
38+
}
39+
40+
ul > li {
41+
padding: 20px 0px;
42+
}
43+
44+
a > code {
45+
background-color: lightblue;
46+
color:blue;
47+
padding: 2px 4px;
48+
border-radius: 4px;
49+
}

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/NavBar.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import * as React from 'react'
2+
import Link from 'next/link'
3+
4+
import { cn } from '@/lib/utils'
5+
6+
import {
7+
NavigationMenu,
8+
NavigationMenuItem,
9+
NavigationMenuLink,
10+
NavigationMenuList,
11+
navigationMenuTriggerStyle,
12+
} from '@/components/ui/navigation-menu'
13+
14+
export default function Navbar() {
15+
return (
16+
<div className="border-b">
17+
<div className="flex h-16 items-center px-4">
18+
<Link href="/" className="mr-6 flex items-center space-x-2">
19+
<span className="text-xl font-bold">OpenRepoWiki</span>
20+
</Link>
21+
<NavigationMenu className="hidden md:flex">
22+
<NavigationMenuList>
23+
<NavigationMenuItem>
24+
<Link href="/repositories" legacyBehavior passHref>
25+
<NavigationMenuLink
26+
className={cn(
27+
navigationMenuTriggerStyle(),
28+
'w-28'
29+
)}
30+
>
31+
Repo
32+
</NavigationMenuLink>
33+
</Link>
34+
</NavigationMenuItem>
35+
<NavigationMenuItem>
36+
<Link href="/blogs" legacyBehavior passHref>
37+
<NavigationMenuLink
38+
className={cn(
39+
navigationMenuTriggerStyle(),
40+
'w-28'
41+
)}
42+
>
43+
Blogs
44+
</NavigationMenuLink>
45+
</Link>
46+
</NavigationMenuItem>
47+
<NavigationMenuItem>
48+
<Link href="/about" legacyBehavior passHref>
49+
<NavigationMenuLink
50+
className={cn(
51+
navigationMenuTriggerStyle(),
52+
'w-28 h-auto'
53+
)}
54+
>
55+
About
56+
</NavigationMenuLink>
57+
</Link>
58+
</NavigationMenuItem>
59+
</NavigationMenuList>
60+
</NavigationMenu>
61+
</div>
62+
</div>
63+
)
64+
}

src/components/RepoCard.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Card, CardHeader, CardContent, CardTitle } from '@/components/ui/card'
2+
import { Badge } from '@/components/ui/badge'
3+
import { Separator } from '@/components/ui/separator'
4+
import { Star, GitFork } from 'lucide-react'
5+
import React from 'react'
6+
7+
export interface RepoDetails {
8+
owner: string
9+
repo: string
10+
descriptions: string
11+
stars: number
12+
forks: number
13+
url: string
14+
default_branch: string
15+
topics: string[]
16+
}
17+
18+
export interface RepoCardProps {
19+
repoInfo: RepoDetails
20+
}
21+
22+
export function RepoCard({ repoInfo }: RepoCardProps) {
23+
return (
24+
<Card>
25+
<CardHeader>
26+
<CardTitle>
27+
{repoInfo.owner}/{repoInfo.repo}
28+
</CardTitle>
29+
</CardHeader>
30+
<CardContent>
31+
<p className="text-sm text-muted-foreground mb-4">
32+
{repoInfo.descriptions}
33+
</p>
34+
<div className="flex items-center gap-4 mb-4">
35+
<div className="flex items-center">
36+
<Star className="w-4 h-4 mr-1" />
37+
<span>{repoInfo.stars}</span>
38+
</div>
39+
<div className="flex items-center">
40+
<GitFork className="w-4 h-4 mr-1" />
41+
<span>{repoInfo.forks}</span>
42+
</div>
43+
</div>
44+
<a
45+
href={repoInfo.url}
46+
target="_blank"
47+
rel="noopener noreferrer"
48+
className="text-primary hover:underline"
49+
>
50+
View on GitHub
51+
</a>
52+
<Separator className="my-4" />
53+
<div>
54+
<h4 className="font-semibold mb-2">Topics</h4>
55+
<div className="flex flex-wrap gap-2">
56+
{repoInfo.topics.map((topic, index) => (
57+
<Badge key={index} variant="secondary">
58+
{topic}
59+
</Badge>
60+
))}
61+
</div>
62+
</div>
63+
</CardContent>
64+
</Card>
65+
)
66+
}

0 commit comments

Comments
 (0)