Files
breakpilot-compliance/admin-compliance/app/(admin)/development/docs/page.tsx
Benjamin Boenisch c11270f8e0 Add CLAUDE.md, MkDocs docs, docs page in admin, .claude/rules
- CLAUDE.md: Comprehensive documentation for Compliance SDK platform
- docs-src: AI-Compliance-SDK docs (architecture, developer, auditor, SBOM)
- mkdocs.yml: Compliance-specific nav with purple theme
- docker-compose: Added docs service (port 8011, profile: docs)
- admin-compliance: New /development/docs page with iframe + quick links
- navigation.ts: Added development category with docs module
- .claude/rules: testing, docs, open-source, compliance-checklist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 00:49:28 +01:00

189 lines
7.1 KiB
TypeScript

'use client'
import { useState } from 'react'
import { ExternalLink, Maximize2, Minimize2, RefreshCw, Search, BookOpen, ArrowRight } from 'lucide-react'
// Quick links to compliance documentation sections
const quickLinks = [
{ name: 'AI Compliance SDK', path: 'services/ai-compliance-sdk/', icon: '🔒' },
{ name: 'Architektur', path: 'services/ai-compliance-sdk/ARCHITECTURE/', icon: '🏗️' },
{ name: 'Developer Guide', path: 'services/ai-compliance-sdk/DEVELOPER/', icon: '👩‍💻' },
{ name: 'Auditor Doku', path: 'services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/', icon: '📋' },
{ name: 'SBOM', path: 'services/ai-compliance-sdk/SBOM/', icon: '📦' },
{ name: 'CI/CD Pipeline', path: 'development/ci-cd-pipeline/', icon: '🚀' },
]
export default function DocsPage() {
const [isFullscreen, setIsFullscreen] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const [currentPath, setCurrentPath] = useState('')
const getDocsUrl = () => {
if (typeof window !== 'undefined') {
const protocol = window.location.protocol
const hostname = window.location.hostname
const port = window.location.port
return `${protocol}//${hostname}${port ? ':' + port : ''}/docs`
}
return '/docs'
}
const docsUrl = getDocsUrl()
const handleIframeLoad = () => {
setIsLoading(false)
}
const navigateTo = (path: string) => {
setCurrentPath(path)
setIsLoading(true)
}
const toggleFullscreen = () => {
setIsFullscreen(!isFullscreen)
}
const openInNewTab = () => {
window.open(`${docsUrl}/${currentPath}`, '_blank')
}
const refreshDocs = () => {
setIsLoading(true)
setCurrentPath(currentPath + '?refresh=' + Date.now())
setTimeout(() => setCurrentPath(currentPath), 100)
}
if (isFullscreen) {
return (
<div className="fixed inset-0 z-50 bg-white">
<div className="absolute top-0 left-0 right-0 h-12 bg-slate-900 flex items-center justify-between px-4 z-10">
<div className="flex items-center gap-2 text-white">
<BookOpen className="w-5 h-5" />
<span className="font-semibold">BreakPilot Compliance Dokumentation</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={openInNewTab}
className="p-2 text-slate-300 hover:text-white hover:bg-slate-700 rounded transition-colors"
title="In neuem Tab oeffnen"
>
<ExternalLink className="w-4 h-4" />
</button>
<button
onClick={toggleFullscreen}
className="p-2 text-slate-300 hover:text-white hover:bg-slate-700 rounded transition-colors"
title="Vollbild beenden"
>
<Minimize2 className="w-4 h-4" />
</button>
</div>
</div>
<iframe
src={`${docsUrl}/${currentPath}`}
className="w-full h-full pt-12"
title="BreakPilot Compliance Documentation"
onLoad={handleIframeLoad}
/>
</div>
)
}
return (
<div className="space-y-6">
{/* Quick Links */}
<div className="bg-white border border-slate-200 rounded-xl p-4">
<h3 className="text-sm font-semibold text-slate-700 mb-3 flex items-center gap-2">
<Search className="w-4 h-4" />
Schnellzugriff
</h3>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2">
{quickLinks.map((link) => (
<button
key={link.path}
onClick={() => navigateTo(link.path)}
className="flex items-center gap-2 px-3 py-2 text-sm bg-slate-50 hover:bg-slate-100 border border-slate-200 rounded-lg transition-colors text-left"
>
<span>{link.icon}</span>
<span className="truncate">{link.name}</span>
</button>
))}
</div>
</div>
{/* Toolbar */}
<div className="flex items-center justify-between bg-white border border-slate-200 rounded-xl p-3">
<div className="flex items-center gap-2">
<BookOpen className="w-5 h-5 text-slate-500" />
<span className="text-sm font-medium text-slate-700">
BreakPilot Compliance Dokumentation
</span>
<span className="text-xs text-slate-400">
(MkDocs Material)
</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={refreshDocs}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="Aktualisieren"
>
<RefreshCw className={`w-4 h-4 ${isLoading ? 'animate-spin' : ''}`} />
</button>
<button
onClick={openInNewTab}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="In neuem Tab oeffnen"
>
<ExternalLink className="w-4 h-4" />
</button>
<button
onClick={toggleFullscreen}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="Vollbild"
>
<Maximize2 className="w-4 h-4" />
</button>
</div>
</div>
{/* Documentation Iframe */}
<div className="relative bg-white border border-slate-200 rounded-xl overflow-hidden" style={{ height: 'calc(100vh - 350px)', minHeight: '500px' }}>
{isLoading && (
<div className="absolute inset-0 bg-white flex items-center justify-center z-10">
<div className="flex flex-col items-center gap-3">
<div className="w-8 h-8 border-2 border-slate-300 border-t-slate-600 rounded-full animate-spin" />
<span className="text-sm text-slate-500">Dokumentation wird geladen...</span>
</div>
</div>
)}
<iframe
key={currentPath}
src={`${docsUrl}/${currentPath}`}
className="w-full h-full"
title="BreakPilot Compliance Documentation"
onLoad={handleIframeLoad}
/>
</div>
{/* Info Box */}
<div className="bg-slate-50 border border-slate-200 rounded-xl p-4">
<div className="flex items-start gap-3">
<div className="p-2 bg-slate-200 rounded-lg">
<ArrowRight className="w-4 h-4 text-slate-600" />
</div>
<div>
<h4 className="font-medium text-slate-800">Dokumentation bearbeiten</h4>
<p className="text-sm text-slate-600 mt-1">
Die Dokumentation befindet sich im Repository unter <code className="text-xs bg-slate-200 px-1.5 py-0.5 rounded">docs-src/</code>.
Nach Aenderungen muss der Docs-Container neu gebaut werden:
</p>
<div className="mt-2 text-xs text-slate-500 font-mono bg-slate-100 p-2 rounded">
docker compose --profile docs build docs && docker compose --profile docs up -d docs
</div>
</div>
</div>
</div>
</div>
)
}