Skip to content

Commit 6b96901

Browse files
committed
feat: Improved API docs with VEXGen endpoints, and readability dividing the file in individual components
1 parent 818519d commit 6b96901

File tree

23 files changed

+1256
-749
lines changed

23 files changed

+1256
-749
lines changed

app/[locale]/docs/page.tsx

Lines changed: 43 additions & 742 deletions
Large diffs are not rendered by default.

components/feature/depex/PackagesTab.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ export default function PackagesTab({ translations, packageOperations }: Package
3939
<div className="grid gap-4">
4040
<div className="grid gap-2">
4141
<Label htmlFor="nodeType" className="text-sm font-medium">
42-
Package Type
42+
{translations.packageTypeLabel}
4343
</Label>
4444
<Select value={nodeType} onValueChange={(value: any) => setNodeType(value)}>
4545
<SelectTrigger className="w-full">
46-
<SelectValue placeholder="Select package type" />
46+
<SelectValue placeholder={translations.selectPackageTypePlaceholder} />
4747
</SelectTrigger>
4848
<SelectContent>
4949
<SelectItem value="PyPIPackage">PyPI</SelectItem>

components/feature/docs/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Tabs
2+
export { AuthTab } from './tabs/AuthTab'
3+
export { VexgenTab } from './tabs/VexgenTab'
4+
export { GraphTab } from './tabs/GraphTab'
5+
export { FileOpsTab } from './tabs/FileOpsTab'
6+
export { ConfigOpsTab } from './tabs/ConfigOpsTab'
7+
8+
// Shared components
9+
export { EndpointCard } from './shared/EndpointCard'
10+
export { OverviewSection } from './shared/OverviewSection'
11+
export { EcosystemsSection } from './shared/EcosystemsSection'
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use client'
2+
3+
import { useEffect, useState } from 'react'
4+
import { useRouter } from 'next/navigation'
5+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui'
6+
7+
interface DocsTabsProps {
8+
children: React.ReactNode
9+
t: any
10+
}
11+
12+
export function DocsTabs({ children, t }: DocsTabsProps) {
13+
const [activeTab, setActiveTab] = useState('overview')
14+
const router = useRouter()
15+
16+
// Read the hash from URL on mount
17+
useEffect(() => {
18+
const hash = window.location.hash.replace('#', '')
19+
if (hash && ['overview', 'auth', 'vexgen', 'graph', 'file-ops', 'config-ops', 'schemas'].includes(hash)) {
20+
setActiveTab(hash)
21+
}
22+
}, [])
23+
24+
// Update URL hash when tab changes
25+
const handleTabChange = (value: string) => {
26+
setActiveTab(value)
27+
// Update URL hash without triggering navigation
28+
const newUrl = `${window.location.pathname}${window.location.search}#${value}`
29+
window.history.replaceState({}, '', newUrl)
30+
}
31+
32+
return (
33+
<Tabs value={activeTab} onValueChange={handleTabChange} className="w-full">
34+
<TabsList className="grid w-full grid-cols-3 lg:grid-cols-7 h-auto">
35+
<TabsTrigger value="overview" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
36+
<span className="lg:hidden">{t.docs.overview}</span>
37+
<span className="hidden lg:inline">{t.docs.overview}</span>
38+
</TabsTrigger>
39+
<TabsTrigger value="auth" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
40+
<span className="lg:hidden">{t.docs.auth}</span>
41+
<span className="hidden lg:inline">{t.docs.auth}</span>
42+
</TabsTrigger>
43+
<TabsTrigger value="vexgen" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
44+
<span className="lg:hidden">VEX/TIX</span>
45+
<span className="hidden lg:inline">
46+
{(t as any).vexgen?.tabTitle || 'VEX & TIX'}
47+
</span>
48+
</TabsTrigger>
49+
<TabsTrigger value="graph" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
50+
<span className="lg:hidden">{t.docs.graph}</span>
51+
<span className="hidden lg:inline">{t.docs.graph}</span>
52+
</TabsTrigger>
53+
<TabsTrigger value="file-ops" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
54+
<span className="lg:hidden">{t.docs.fileOps}</span>
55+
<span className="hidden lg:inline">{t.docs.fileOps}</span>
56+
</TabsTrigger>
57+
<TabsTrigger value="config-ops" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
58+
<span className="lg:hidden">{t.docs.configOps}</span>
59+
<span className="hidden lg:inline">{t.docs.configOps}</span>
60+
</TabsTrigger>
61+
<TabsTrigger value="schemas" className="text-xs sm:text-sm py-2 px-1 sm:px-3">
62+
<span className="lg:hidden">{t.docs.schemas}</span>
63+
<span className="hidden lg:inline">{t.docs.schemas}</span>
64+
</TabsTrigger>
65+
</TabsList>
66+
67+
{children}
68+
</Tabs>
69+
)
70+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Badge } from '@/components/ui'
2+
import { Lock } from 'lucide-react'
3+
4+
interface EndpointCardProps {
5+
endpoint: {
6+
method: string
7+
path: string
8+
summary: string
9+
description: string
10+
auth?: boolean
11+
}
12+
index: number
13+
t: any
14+
}
15+
16+
export const EndpointCard: React.FC<EndpointCardProps> = ({ endpoint, index, t }) => {
17+
const getMethodColorClasses = (method: string): string => {
18+
switch (method.toUpperCase()) {
19+
case 'GET':
20+
return 'bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900 dark:text-blue-300 dark:border-blue-700'
21+
case 'POST':
22+
return 'bg-green-100 text-green-800 border-green-200 dark:bg-green-900 dark:text-green-300 dark:border-green-700'
23+
case 'PUT':
24+
return 'bg-orange-100 text-orange-800 border-orange-200 dark:bg-orange-900 dark:text-orange-300 dark:border-orange-700'
25+
case 'PATCH':
26+
return 'bg-yellow-100 text-yellow-800 border-yellow-200 dark:bg-yellow-900 dark:text-yellow-300 dark:border-yellow-700'
27+
case 'DELETE':
28+
return 'bg-red-100 text-red-800 border-red-200 dark:bg-red-900 dark:text-red-300 dark:border-red-700'
29+
default:
30+
return 'bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-900 dark:text-gray-300 dark:border-gray-700'
31+
}
32+
}
33+
34+
const methodColorClasses = getMethodColorClasses(endpoint.method)
35+
36+
return (
37+
<div key={index} className="border rounded-lg p-3 sm:p-4">
38+
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-2">
39+
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
40+
<span className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold border ${methodColorClasses}`}>
41+
{endpoint.method}
42+
</span>
43+
<code className="text-xs sm:text-sm font-mono break-all">{endpoint.path}</code>
44+
</div>
45+
{endpoint.auth && (
46+
<Badge variant="outline" className="gap-1 text-xs w-fit">
47+
<Lock className="h-3 w-3" />
48+
<span className="hidden sm:inline">{t.docs.authRequired}</span>
49+
<span className="sm:hidden">{t.docs.auth}</span>
50+
</Badge>
51+
)}
52+
</div>
53+
<h4 className="font-semibold mb-1 text-sm sm:text-base">{endpoint.summary}</h4>
54+
<p className="text-xs sm:text-sm text-muted-foreground leading-relaxed">
55+
{endpoint.description}
56+
</p>
57+
</div>
58+
)
59+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Badge, Button } from '@/components/ui'
2+
import { BookOpen, ExternalLink } from 'lucide-react'
3+
4+
interface HeroSectionProps {
5+
t: any
6+
locale: string
7+
}
8+
9+
export const HeroSection: React.FC<HeroSectionProps> = ({ t, locale }) => {
10+
return (
11+
<section className="py-8 sm:py-12 lg:py-16 px-4 bg-gradient-to-br from-primary/10 via-background to-secondary/10">
12+
<div className="container mx-auto text-center">
13+
<Badge variant="outline" className="mb-4 text-xs sm:text-sm">
14+
<BookOpen className="h-3 w-3 sm:h-4 sm:w-4 mr-2" />
15+
{t.docs.apiDocumentationBadge}
16+
</Badge>
17+
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6 bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent leading-tight pb-2">
18+
{t.docs.title}
19+
</h1>
20+
<p className="text-base sm:text-lg lg:text-xl text-muted-foreground mb-6 sm:mb-8 max-w-3xl mx-auto leading-relaxed px-4">
21+
{t.docs.subtitle}
22+
</p>
23+
<div className="flex flex-col sm:flex-row gap-4 justify-center">
24+
<Button size="lg" variant="outline" asChild className="w-full sm:w-auto">
25+
<a href="https://github.com/securechaindev" target="_blank" rel="noopener noreferrer">
26+
<ExternalLink className="h-4 w-4 mr-2" />
27+
{t.docs.viewOnGitHub}
28+
</a>
29+
</Button>
30+
</div>
31+
</div>
32+
</section>
33+
)
34+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ThemeToggle, LanguageToggle } from '@/components/layout'
2+
import Image from 'next/image'
3+
import Link from 'next/link'
4+
import { type Locale } from '@/lib/i18n'
5+
6+
interface NavigationProps {
7+
t: any
8+
locale: Locale
9+
}
10+
11+
export const Navigation: React.FC<NavigationProps> = ({ t, locale }) => {
12+
return (
13+
<nav className="sticky top-0 z-50 bg-background/90 backdrop-blur-sm border-b">
14+
<div className="container mx-auto px-4 py-3 sm:py-4">
15+
<div className="flex items-center justify-between">
16+
<div className="flex items-center gap-2 sm:gap-4 min-w-0">
17+
<Link
18+
href={`/${locale}`}
19+
className="text-muted-foreground hover:text-foreground transition-colors text-sm sm:text-base"
20+
>
21+
<span className="hidden sm:inline">{t.docs.backToHome}</span>
22+
<span className="sm:hidden">{t.docs.back}</span>
23+
</Link>
24+
<div className="flex items-center gap-2 min-w-0">
25+
<Image
26+
src="/images/securechain-logo.ico"
27+
alt="Secure Chain Logo"
28+
width={32}
29+
height={32}
30+
className="h-6 w-6 sm:h-8 sm:w-8 flex-shrink-0"
31+
/>
32+
<span className="font-bold text-sm sm:text-base truncate">
33+
<span className="hidden md:inline">{t.appName}</span>
34+
<span className="md:hidden">{t.appNameShort}</span>
35+
</span>
36+
</div>
37+
</div>
38+
39+
<div className="flex items-center gap-1 sm:gap-2">
40+
<ThemeToggle />
41+
<LanguageToggle currentLang={locale} />
42+
</div>
43+
</div>
44+
</div>
45+
</nav>
46+
)
47+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { Card, CardContent, CardHeader, CardTitle, Badge } from '@/components/ui'
2+
import { Shield, Database, Code, FileText, Globe, Settings } from 'lucide-react'
3+
4+
interface OverviewSectionProps {
5+
t: any
6+
nodeTypes: string[]
7+
}
8+
9+
export const OverviewSection: React.FC<OverviewSectionProps> = ({ t, nodeTypes }) => {
10+
return (
11+
<div className="space-y-4 sm:space-y-6">
12+
<Card>
13+
<CardHeader className="pb-4">
14+
<CardTitle className="flex items-center gap-2 text-lg sm:text-xl">
15+
<Globe className="h-4 w-4 sm:h-5 sm:w-5" />
16+
{t.docs.apiInformation}
17+
</CardTitle>
18+
</CardHeader>
19+
<CardContent className="space-y-4">
20+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
21+
<div>
22+
<h4 className="font-semibold mb-2 text-sm sm:text-base">{t.docs.version}</h4>
23+
<p className="text-muted-foreground text-sm">1.0.0</p>
24+
</div>
25+
<div>
26+
<h4 className="font-semibold mb-2 text-sm sm:text-base">{t.docs.openapi}</h4>
27+
<p className="text-muted-foreground text-sm">3.1.0</p>
28+
</div>
29+
<div className="sm:col-span-2 lg:col-span-1">
30+
<h4 className="font-semibold mb-2 text-sm sm:text-base">{t.docs.baseUrl}</h4>
31+
<p className="text-muted-foreground font-mono text-xs sm:text-sm break-all">
32+
https://securechain.dev/api/
33+
</p>
34+
</div>
35+
<div className="sm:col-span-2 lg:col-span-1">
36+
<h4 className="font-semibold mb-2 text-sm sm:text-base">{t.docs.authentication}</h4>
37+
<p className="text-muted-foreground text-sm">{t.docs.jwtBearerToken}</p>
38+
</div>
39+
</div>
40+
</CardContent>
41+
</Card>
42+
43+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-5 gap-4 sm:gap-6">
44+
<Card className="md:col-span-2 xl:col-span-1">
45+
<CardHeader className="pb-4">
46+
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-blue-500/10 rounded-lg flex items-center justify-center mb-2">
47+
<Shield className="h-5 w-5 sm:h-6 sm:w-6 text-blue-500" />
48+
</div>
49+
<CardTitle className="text-base sm:text-lg">{t.docs.authenticationTitle}</CardTitle>
50+
</CardHeader>
51+
<CardContent>
52+
<p className="text-muted-foreground mb-4 text-sm leading-relaxed">
53+
{t.docs.authenticationDescription}
54+
</p>
55+
<Badge variant="secondary" className="text-xs">
56+
7 {t.docs.endpoints}
57+
</Badge>
58+
</CardContent>
59+
</Card>
60+
61+
<Card className="md:col-span-2 xl:col-span-1">
62+
<CardHeader className="pb-4">
63+
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-green-500/10 rounded-lg flex items-center justify-center mb-2">
64+
<Database className="h-5 w-5 sm:h-6 sm:w-6 text-green-500" />
65+
</div>
66+
<CardTitle className="text-base sm:text-lg">{t.docs.dependencyGraphTitle}</CardTitle>
67+
</CardHeader>
68+
<CardContent>
69+
<p className="text-muted-foreground mb-4 text-sm leading-relaxed">
70+
{t.docs.dependencyGraphDescription}
71+
</p>
72+
<Badge variant="secondary" className="text-xs">
73+
6 {t.docs.endpoints}
74+
</Badge>
75+
</CardContent>
76+
</Card>
77+
78+
<Card className="md:col-span-2 xl:col-span-1">
79+
<CardHeader className="pb-4">
80+
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-orange-500/10 rounded-lg flex items-center justify-center mb-2">
81+
<FileText className="h-5 w-5 sm:h-6 sm:w-6 text-orange-500" />
82+
</div>
83+
<CardTitle className="text-base sm:text-lg">{t.docs.vexgen.title}</CardTitle>
84+
</CardHeader>
85+
<CardContent>
86+
<p className="text-muted-foreground mb-4 text-sm leading-relaxed">
87+
{t.docs.vexgen.description}
88+
</p>
89+
<Badge variant="secondary" className="text-xs">
90+
7 {t.docs.endpoints}
91+
</Badge>
92+
</CardContent>
93+
</Card>
94+
95+
<Card className="md:col-span-2 xl:col-span-1">
96+
<CardHeader className="pb-4">
97+
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-purple-500/10 rounded-lg flex items-center justify-center mb-2">
98+
<Code className="h-5 w-5 sm:h-6 sm:w-6 text-purple-500" />
99+
</div>
100+
<CardTitle className="text-base sm:text-lg">{t.docs.fileOperationsTitle}</CardTitle>
101+
</CardHeader>
102+
<CardContent>
103+
<p className="text-muted-foreground mb-4 text-sm leading-relaxed">
104+
{t.docs.fileOperationsDescription}
105+
</p>
106+
<Badge variant="secondary" className="text-xs">
107+
5 {t.docs.endpoints}
108+
</Badge>
109+
</CardContent>
110+
</Card>
111+
112+
<Card className="md:col-span-2 xl:col-span-1">
113+
<CardHeader className="pb-4">
114+
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-indigo-500/10 rounded-lg flex items-center justify-center mb-2">
115+
<Settings className="h-5 w-5 sm:h-6 sm:w-6 text-indigo-500" />
116+
</div>
117+
<CardTitle className="text-base sm:text-lg">{t.docs.configOperationsTitle}</CardTitle>
118+
</CardHeader>
119+
<CardContent>
120+
<p className="text-muted-foreground mb-4 text-sm leading-relaxed">
121+
{t.docs.configOperationsDescription}
122+
</p>
123+
<Badge variant="secondary" className="text-xs">
124+
3 {t.docs.endpoints}
125+
</Badge>
126+
</CardContent>
127+
</Card>
128+
</div>
129+
130+
<Card>
131+
<CardHeader className="pb-4">
132+
<CardTitle className="flex items-center gap-2 text-lg sm:text-xl">
133+
<FileText className="h-4 w-4 sm:h-5 sm:w-5" />
134+
{t.docs.supportedEcosystems}
135+
</CardTitle>
136+
</CardHeader>
137+
<CardContent>
138+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
139+
{nodeTypes.map(nodeType => (
140+
<div key={nodeType} className="flex items-center gap-2 p-3 border rounded-lg">
141+
<div className="w-2 h-2 bg-primary rounded-full flex-shrink-0"></div>
142+
<span className="font-mono text-xs sm:text-sm truncate">{nodeType}</span>
143+
</div>
144+
))}
145+
</div>
146+
</CardContent>
147+
</Card>
148+
</div>
149+
)
150+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { OverviewSection } from './OverviewSection'
2+
export { HeroSection } from './HeroSection'
3+
export { Navigation } from './Navigation'
4+
export { DocsTabs } from './DocsTabs'

0 commit comments

Comments
 (0)