refactor: Entwicklung-Kategorie aus Core Admin entfernt
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 29s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 28s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 29s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 28s
Screen Flow, Brandbook und Developer Docs waren veraltet und werden nicht mehr benoetigt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,318 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState } from 'react'
|
|
||||||
|
|
||||||
type Tab = 'colors' | 'typography' | 'components' | 'logos' | 'voice'
|
|
||||||
|
|
||||||
const tabs: { id: Tab; label: string }[] = [
|
|
||||||
{ id: 'colors', label: 'Farben' },
|
|
||||||
{ id: 'typography', label: 'Typografie' },
|
|
||||||
{ id: 'components', label: 'Komponenten' },
|
|
||||||
{ id: 'logos', label: 'Logos' },
|
|
||||||
{ id: 'voice', label: 'Voice & Tone' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const primaryColors = [
|
|
||||||
{ name: 'Primary 50', hex: '#f0f9ff', class: 'bg-primary-50' },
|
|
||||||
{ name: 'Primary 100', hex: '#e0f2fe', class: 'bg-primary-100' },
|
|
||||||
{ name: 'Primary 200', hex: '#bae6fd', class: 'bg-primary-200' },
|
|
||||||
{ name: 'Primary 300', hex: '#7dd3fc', class: 'bg-primary-300' },
|
|
||||||
{ name: 'Primary 400', hex: '#38bdf8', class: 'bg-primary-400' },
|
|
||||||
{ name: 'Primary 500', hex: '#0ea5e9', class: 'bg-primary-500' },
|
|
||||||
{ name: 'Primary 600', hex: '#0284c7', class: 'bg-primary-600' },
|
|
||||||
{ name: 'Primary 700', hex: '#0369a1', class: 'bg-primary-700' },
|
|
||||||
{ name: 'Primary 800', hex: '#075985', class: 'bg-primary-800' },
|
|
||||||
{ name: 'Primary 900', hex: '#0c4a6e', class: 'bg-primary-900' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const categoryColorSets = [
|
|
||||||
{
|
|
||||||
name: 'Kommunikation',
|
|
||||||
baseHex: '#22c55e',
|
|
||||||
swatches: [
|
|
||||||
{ name: '100', hex: '#dcfce7' },
|
|
||||||
{ name: '300', hex: '#86efac' },
|
|
||||||
{ name: '500', hex: '#22c55e' },
|
|
||||||
{ name: '700', hex: '#15803d' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Infrastruktur',
|
|
||||||
baseHex: '#f97316',
|
|
||||||
swatches: [
|
|
||||||
{ name: '100', hex: '#ffedd5' },
|
|
||||||
{ name: '300', hex: '#fdba74' },
|
|
||||||
{ name: '500', hex: '#f97316' },
|
|
||||||
{ name: '700', hex: '#c2410c' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Entwicklung',
|
|
||||||
baseHex: '#64748b',
|
|
||||||
swatches: [
|
|
||||||
{ name: '100', hex: '#f1f5f9' },
|
|
||||||
{ name: '300', hex: '#cbd5e1' },
|
|
||||||
{ name: '500', hex: '#64748b' },
|
|
||||||
{ name: '700', hex: '#334155' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function BrandbookPage() {
|
|
||||||
const [activeTab, setActiveTab] = useState<Tab>('colors')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* Tabs */}
|
|
||||||
<div className="flex gap-1 mb-6 bg-white rounded-xl border border-slate-200 p-1">
|
|
||||||
{tabs.map((tab) => (
|
|
||||||
<button
|
|
||||||
key={tab.id}
|
|
||||||
onClick={() => setActiveTab(tab.id)}
|
|
||||||
className={`flex-1 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
||||||
activeTab === tab.id
|
|
||||||
? 'bg-primary-600 text-white'
|
|
||||||
: 'text-slate-600 hover:bg-slate-100'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{tab.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Colors Tab */}
|
|
||||||
{activeTab === 'colors' && (
|
|
||||||
<div className="space-y-8">
|
|
||||||
{/* Primary */}
|
|
||||||
<div>
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Primary: Sky Blue</h2>
|
|
||||||
<div className="grid grid-cols-5 md:grid-cols-10 gap-2">
|
|
||||||
{primaryColors.map((color) => (
|
|
||||||
<div key={color.hex} className="text-center">
|
|
||||||
<div
|
|
||||||
className="w-full aspect-square rounded-lg border border-slate-200 mb-1"
|
|
||||||
style={{ backgroundColor: color.hex }}
|
|
||||||
/>
|
|
||||||
<div className="text-xs text-slate-500">{color.name.split(' ')[1]}</div>
|
|
||||||
<div className="text-xs text-slate-400 font-mono">{color.hex}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Category Colors */}
|
|
||||||
<div>
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Kategorie-Farben</h2>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
||||||
{categoryColorSets.map((set) => (
|
|
||||||
<div key={set.name} className="bg-white rounded-xl border border-slate-200 p-4">
|
|
||||||
<div className="flex items-center gap-2 mb-3">
|
|
||||||
<div
|
|
||||||
className="w-4 h-4 rounded-full"
|
|
||||||
style={{ backgroundColor: set.baseHex }}
|
|
||||||
/>
|
|
||||||
<h3 className="font-medium text-slate-900">{set.name}</h3>
|
|
||||||
<span className="text-xs text-slate-400 font-mono">{set.baseHex}</span>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-4 gap-2">
|
|
||||||
{set.swatches.map((swatch) => (
|
|
||||||
<div key={swatch.hex} className="text-center">
|
|
||||||
<div
|
|
||||||
className="w-full aspect-square rounded-lg border border-slate-200 mb-1"
|
|
||||||
style={{ backgroundColor: swatch.hex }}
|
|
||||||
/>
|
|
||||||
<div className="text-xs text-slate-400 font-mono">{swatch.name}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Semantic Colors */}
|
|
||||||
<div>
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Semantische Farben</h2>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
||||||
{[
|
|
||||||
{ name: 'Success', hex: '#22c55e', bg: '#dcfce7' },
|
|
||||||
{ name: 'Warning', hex: '#f59e0b', bg: '#fef3c7' },
|
|
||||||
{ name: 'Error', hex: '#ef4444', bg: '#fee2e2' },
|
|
||||||
{ name: 'Info', hex: '#3b82f6', bg: '#dbeafe' },
|
|
||||||
].map((color) => (
|
|
||||||
<div key={color.name} className="p-4 rounded-xl border border-slate-200" style={{ backgroundColor: color.bg }}>
|
|
||||||
<div className="w-8 h-8 rounded-lg mb-2" style={{ backgroundColor: color.hex }} />
|
|
||||||
<div className="font-medium" style={{ color: color.hex }}>{color.name}</div>
|
|
||||||
<div className="text-xs text-slate-500 font-mono">{color.hex}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Typography Tab */}
|
|
||||||
{activeTab === 'typography' && (
|
|
||||||
<div className="space-y-8">
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Schriftart: Inter</h2>
|
|
||||||
<p className="text-slate-500 mb-6">
|
|
||||||
Inter ist eine Open-Source-Schriftart (OFL), optimiert fuer Bildschirme.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="space-y-6">
|
|
||||||
{[
|
|
||||||
{ name: 'Heading 1', class: 'text-4xl font-bold', size: '36px / 2.25rem' },
|
|
||||||
{ name: 'Heading 2', class: 'text-2xl font-semibold', size: '24px / 1.5rem' },
|
|
||||||
{ name: 'Heading 3', class: 'text-xl font-semibold', size: '20px / 1.25rem' },
|
|
||||||
{ name: 'Body Large', class: 'text-lg', size: '18px / 1.125rem' },
|
|
||||||
{ name: 'Body', class: 'text-base', size: '16px / 1rem' },
|
|
||||||
{ name: 'Body Small', class: 'text-sm', size: '14px / 0.875rem' },
|
|
||||||
{ name: 'Caption', class: 'text-xs', size: '12px / 0.75rem' },
|
|
||||||
].map((item) => (
|
|
||||||
<div key={item.name} className="flex items-baseline gap-4 border-b border-slate-100 pb-4">
|
|
||||||
<div className="w-32 text-sm text-slate-500">{item.name}</div>
|
|
||||||
<div className={`flex-1 text-slate-900 ${item.class}`}>
|
|
||||||
BreakPilot Core Admin
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-slate-400 font-mono">{item.size}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Components Tab */}
|
|
||||||
{activeTab === 'components' && (
|
|
||||||
<div className="space-y-8">
|
|
||||||
{/* Buttons */}
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Buttons</h2>
|
|
||||||
<div className="flex flex-wrap gap-4">
|
|
||||||
<button className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700">Primary</button>
|
|
||||||
<button className="px-4 py-2 bg-white border border-slate-200 text-slate-700 rounded-lg hover:bg-slate-50">Secondary</button>
|
|
||||||
<button className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700">Danger</button>
|
|
||||||
<button className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">Success</button>
|
|
||||||
<button className="px-4 py-2 text-primary-600 hover:text-primary-700 hover:bg-primary-50 rounded-lg">Ghost</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Cards */}
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Cards</h2>
|
|
||||||
<div className="grid grid-cols-3 gap-4">
|
|
||||||
<div className="p-4 bg-white rounded-xl border border-slate-200 shadow-sm">
|
|
||||||
<h3 className="font-medium text-slate-900">Default Card</h3>
|
|
||||||
<p className="text-sm text-slate-500 mt-1">Standard-Karte mit Rand</p>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 bg-primary-50 rounded-xl border border-primary-200">
|
|
||||||
<h3 className="font-medium text-primary-900">Active Card</h3>
|
|
||||||
<p className="text-sm text-primary-600 mt-1">Hervorgehobene Karte</p>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 bg-white rounded-xl border border-slate-200 shadow-md hover:shadow-lg transition-shadow">
|
|
||||||
<h3 className="font-medium text-slate-900">Hover Card</h3>
|
|
||||||
<p className="text-sm text-slate-500 mt-1">Karte mit Hover-Effekt</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Badges */}
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Badges / Status</h2>
|
|
||||||
<div className="flex flex-wrap gap-3">
|
|
||||||
<span className="px-2 py-1 bg-green-100 text-green-700 rounded-full text-xs font-medium">Healthy</span>
|
|
||||||
<span className="px-2 py-1 bg-red-100 text-red-700 rounded-full text-xs font-medium">Error</span>
|
|
||||||
<span className="px-2 py-1 bg-yellow-100 text-yellow-700 rounded-full text-xs font-medium">Warning</span>
|
|
||||||
<span className="px-2 py-1 bg-blue-100 text-blue-700 rounded-full text-xs font-medium">Info</span>
|
|
||||||
<span className="px-2 py-1 bg-slate-100 text-slate-700 rounded-full text-xs font-medium">Default</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Logos Tab */}
|
|
||||||
{activeTab === 'logos' && (
|
|
||||||
<div className="space-y-8">
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Logo-Varianten</h2>
|
|
||||||
<div className="grid grid-cols-2 gap-6">
|
|
||||||
<div className="p-8 bg-white rounded-xl border border-slate-200 flex items-center justify-center">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-3xl font-bold text-primary-600 mb-1">BreakPilot</div>
|
|
||||||
<div className="text-sm text-slate-500">Core Admin</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-8 bg-slate-900 rounded-xl flex items-center justify-center">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-3xl font-bold text-white mb-1">BreakPilot</div>
|
|
||||||
<div className="text-sm text-slate-400">Core Admin</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Schutzzone</h2>
|
|
||||||
<p className="text-sm text-slate-500">
|
|
||||||
Um das Logo herum muss mindestens der Abstand der Buchstabenhoehe "B" als Freiraum gelassen werden.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Voice & Tone Tab */}
|
|
||||||
{activeTab === 'voice' && (
|
|
||||||
<div className="space-y-8">
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Sprachstil</h2>
|
|
||||||
<div className="grid grid-cols-2 gap-6">
|
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-green-600 mb-2">So schreiben wir</h3>
|
|
||||||
<ul className="space-y-2 text-sm text-slate-600">
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-green-500 mt-0.5">+</span>
|
|
||||||
<span>Klar und direkt</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-green-500 mt-0.5">+</span>
|
|
||||||
<span>Technisch praezise, aber verstaendlich</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-green-500 mt-0.5">+</span>
|
|
||||||
<span>Handlungsorientiert</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-green-500 mt-0.5">+</span>
|
|
||||||
<span>Deutsch als Hauptsprache</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-red-600 mb-2">Das vermeiden wir</h3>
|
|
||||||
<ul className="space-y-2 text-sm text-slate-600">
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-red-500 mt-0.5">-</span>
|
|
||||||
<span>Unnoetige Anglizismen</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-red-500 mt-0.5">-</span>
|
|
||||||
<span>Marketing-Sprache</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-red-500 mt-0.5">-</span>
|
|
||||||
<span>Passive Formulierungen</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-2">
|
|
||||||
<span className="text-red-500 mt-0.5">-</span>
|
|
||||||
<span>Abkuerzungen ohne Erklaerung</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState } from 'react'
|
|
||||||
|
|
||||||
const quickLinks = [
|
|
||||||
{ name: 'Backend Core API', url: 'https://macmini:8000/docs', description: 'FastAPI Swagger Docs' },
|
|
||||||
{ name: 'Gitea', url: 'http://macmini:3003', description: 'Git Server' },
|
|
||||||
{ name: 'Woodpecker CI', url: 'http://macmini:8090', description: 'CI/CD Pipelines' },
|
|
||||||
{ name: 'MkDocs', url: 'http://macmini:8009', description: 'Projekt-Dokumentation' },
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function DocsPage() {
|
|
||||||
const [iframeUrl, setIframeUrl] = useState('http://macmini:8009')
|
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* Quick Links */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
|
||||||
{quickLinks.map((link) => (
|
|
||||||
<button
|
|
||||||
key={link.name}
|
|
||||||
onClick={() => {
|
|
||||||
setIframeUrl(link.url)
|
|
||||||
setIsLoading(true)
|
|
||||||
}}
|
|
||||||
className={`p-4 rounded-xl border text-left transition-all hover:shadow-md ${
|
|
||||||
iframeUrl === link.url
|
|
||||||
? 'bg-primary-50 border-primary-300'
|
|
||||||
: 'bg-white border-slate-200 hover:border-primary-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<h3 className="font-medium text-slate-900">{link.name}</h3>
|
|
||||||
<p className="text-sm text-slate-500">{link.description}</p>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Iframe Viewer */}
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
|
|
||||||
<div className="flex items-center justify-between px-4 py-2 bg-slate-50 border-b border-slate-200">
|
|
||||||
<span className="text-sm text-slate-600 truncate">{iframeUrl}</span>
|
|
||||||
<a
|
|
||||||
href={iframeUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-sm text-primary-600 hover:text-primary-700"
|
|
||||||
>
|
|
||||||
In neuem Tab oeffnen
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="relative" style={{ height: '70vh' }}>
|
|
||||||
{isLoading && (
|
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-slate-50">
|
|
||||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<iframe
|
|
||||||
src={iframeUrl}
|
|
||||||
className="w-full h-full border-0"
|
|
||||||
onLoad={() => setIsLoading(false)}
|
|
||||||
title="Documentation Viewer"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info */}
|
|
||||||
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded-xl">
|
|
||||||
<h3 className="font-medium text-blue-900 mb-1">Dokumentation bearbeiten</h3>
|
|
||||||
<p className="text-sm text-blue-700">
|
|
||||||
Die MkDocs-Dokumentation liegt unter <code className="px-1 py-0.5 bg-blue-100 rounded">/docs-src/</code>.
|
|
||||||
Aenderungen werden automatisch beim naechsten Build sichtbar.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState, useCallback, useMemo } from 'react'
|
|
||||||
import ReactFlow, {
|
|
||||||
Node,
|
|
||||||
Edge,
|
|
||||||
Controls,
|
|
||||||
Background,
|
|
||||||
MiniMap,
|
|
||||||
useNodesState,
|
|
||||||
useEdgesState,
|
|
||||||
MarkerType,
|
|
||||||
} from 'reactflow'
|
|
||||||
import 'reactflow/dist/style.css'
|
|
||||||
|
|
||||||
type CategoryFilter = 'all' | 'infrastructure' | 'development' | 'meta'
|
|
||||||
|
|
||||||
const categoryColors: Record<string, string> = {
|
|
||||||
infrastructure: '#f97316',
|
|
||||||
development: '#64748b',
|
|
||||||
meta: '#0ea5e9',
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
|
||||||
// Meta
|
|
||||||
{ id: 'role-select', position: { x: 400, y: 0 }, data: { label: 'Rollenauswahl', category: 'meta' }, style: { background: '#e0f2fe', border: '2px solid #0ea5e9', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'dashboard', position: { x: 400, y: 100 }, data: { label: 'Dashboard', category: 'meta' }, style: { background: '#e0f2fe', border: '2px solid #0ea5e9', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
|
|
||||||
// Infrastructure (Orange)
|
|
||||||
{ id: 'gpu', position: { x: 300, y: 250 }, data: { label: 'GPU Infrastruktur', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'middleware', position: { x: 300, y: 350 }, data: { label: 'Middleware', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'security', position: { x: 300, y: 450 }, data: { label: 'Security Dashboard', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'sbom', position: { x: 300, y: 550 }, data: { label: 'SBOM', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'ci-cd', position: { x: 500, y: 250 }, data: { label: 'CI/CD Dashboard', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'tests', position: { x: 500, y: 350 }, data: { label: 'Test Dashboard', category: 'infrastructure' }, style: { background: '#ffedd5', border: '2px solid #f97316', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
|
|
||||||
// Development (Slate)
|
|
||||||
{ id: 'docs', position: { x: 700, y: 250 }, data: { label: 'Developer Docs', category: 'development' }, style: { background: '#f1f5f9', border: '2px solid #64748b', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'screen-flow', position: { x: 700, y: 350 }, data: { label: 'Screen Flow', category: 'development' }, style: { background: '#f1f5f9', border: '2px solid #64748b', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
{ id: 'brandbook', position: { x: 700, y: 450 }, data: { label: 'Brandbook', category: 'development' }, style: { background: '#f1f5f9', border: '2px solid #64748b', borderRadius: '12px', padding: '10px 16px' } },
|
|
||||||
]
|
|
||||||
|
|
||||||
const initialEdges: Edge[] = [
|
|
||||||
// Meta flow
|
|
||||||
{ id: 'e-role-dash', source: 'role-select', target: 'dashboard', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#0ea5e9' } },
|
|
||||||
|
|
||||||
// Dashboard to categories
|
|
||||||
{ id: 'e-dash-gpu', source: 'dashboard', target: 'gpu', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
{ id: 'e-dash-cicd', source: 'dashboard', target: 'ci-cd', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
{ id: 'e-dash-docs', source: 'dashboard', target: 'docs', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#64748b' } },
|
|
||||||
|
|
||||||
|
|
||||||
// Infrastructure internal
|
|
||||||
{ id: 'e-gpu-mw', source: 'gpu', target: 'middleware', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
{ id: 'e-mw-sec', source: 'middleware', target: 'security', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
{ id: 'e-sec-sbom', source: 'security', target: 'sbom', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
{ id: 'e-cicd-tests', source: 'ci-cd', target: 'tests', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#f97316' } },
|
|
||||||
|
|
||||||
// Cross-category
|
|
||||||
{ id: 'e-sec-cicd', source: 'security', target: 'ci-cd', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#94a3b8', strokeDasharray: '5,5' } },
|
|
||||||
{ id: 'e-tests-docs', source: 'tests', target: 'docs', markerEnd: { type: MarkerType.ArrowClosed }, style: { stroke: '#94a3b8', strokeDasharray: '5,5' } },
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function ScreenFlowPage() {
|
|
||||||
const [filter, setFilter] = useState<CategoryFilter>('all')
|
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
|
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
|
|
||||||
|
|
||||||
const filteredNodes = useMemo(() => {
|
|
||||||
if (filter === 'all') return nodes
|
|
||||||
return nodes.filter(n => n.data.category === filter || n.data.category === 'meta')
|
|
||||||
}, [nodes, filter])
|
|
||||||
|
|
||||||
const filteredEdges = useMemo(() => {
|
|
||||||
const nodeIds = new Set(filteredNodes.map(n => n.id))
|
|
||||||
return edges.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target))
|
|
||||||
}, [edges, filteredNodes])
|
|
||||||
|
|
||||||
const filters: { id: CategoryFilter; label: string; color: string }[] = [
|
|
||||||
{ id: 'all', label: 'Alle', color: '#0ea5e9' },
|
|
||||||
{ id: 'infrastructure', label: 'Infrastruktur', color: '#f97316' },
|
|
||||||
{ id: 'development', label: 'Entwicklung', color: '#64748b' },
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* Filter */}
|
|
||||||
<div className="flex items-center gap-2 mb-4">
|
|
||||||
{filters.map((f) => (
|
|
||||||
<button
|
|
||||||
key={f.id}
|
|
||||||
onClick={() => setFilter(f.id)}
|
|
||||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
||||||
filter === f.id
|
|
||||||
? 'text-white'
|
|
||||||
: 'bg-white border border-slate-200 text-slate-600 hover:border-slate-300'
|
|
||||||
}`}
|
|
||||||
style={filter === f.id ? { backgroundColor: f.color } : undefined}
|
|
||||||
>
|
|
||||||
{f.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Stats */}
|
|
||||||
<div className="grid grid-cols-4 gap-4 mb-4">
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-3 text-center">
|
|
||||||
<div className="text-2xl font-bold text-slate-900">{filteredNodes.length}</div>
|
|
||||||
<div className="text-xs text-slate-500">Screens</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-3 text-center">
|
|
||||||
<div className="text-2xl font-bold text-slate-900">{filteredEdges.length}</div>
|
|
||||||
<div className="text-xs text-slate-500">Verbindungen</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-3 text-center">
|
|
||||||
<div className="text-2xl font-bold text-slate-900">3</div>
|
|
||||||
<div className="text-xs text-slate-500">Kategorien</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 p-3 text-center">
|
|
||||||
<div className="text-2xl font-bold text-slate-900">13</div>
|
|
||||||
<div className="text-xs text-slate-500">Module</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Flow */}
|
|
||||||
<div className="bg-white rounded-xl border border-slate-200 shadow-sm" style={{ height: '65vh' }}>
|
|
||||||
<ReactFlow
|
|
||||||
nodes={filteredNodes}
|
|
||||||
edges={filteredEdges}
|
|
||||||
onNodesChange={onNodesChange}
|
|
||||||
onEdgesChange={onEdgesChange}
|
|
||||||
fitView
|
|
||||||
attributionPosition="bottom-left"
|
|
||||||
>
|
|
||||||
<Controls />
|
|
||||||
<Background />
|
|
||||||
<MiniMap
|
|
||||||
nodeColor={(node) => categoryColors[node.data?.category] || '#94a3b8'}
|
|
||||||
maskColor="rgba(0,0,0,0.1)"
|
|
||||||
/>
|
|
||||||
</ReactFlow>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Legend */}
|
|
||||||
<div className="mt-4 flex items-center gap-6 text-sm text-slate-500">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="w-4 h-4 rounded bg-orange-100 border-2 border-orange-500" />
|
|
||||||
<span>Infrastruktur (6)</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="w-4 h-4 rounded bg-slate-100 border-2 border-slate-500" />
|
|
||||||
<span>Entwicklung (3)</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="w-4 h-4 rounded bg-sky-100 border-2 border-sky-500" />
|
|
||||||
<span>Meta</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
* 3 Categories: Communication, Infrastructure, Development
|
* 3 Categories: Communication, Infrastructure, Development
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type CategoryId = 'infrastructure' | 'development'
|
export type CategoryId = 'infrastructure'
|
||||||
|
|
||||||
export interface NavModule {
|
export interface NavModule {
|
||||||
id: string
|
id: string
|
||||||
@@ -94,43 +94,6 @@ export const navigation: NavCategory[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// =========================================================================
|
|
||||||
// Entwicklung (Slate)
|
|
||||||
// =========================================================================
|
|
||||||
{
|
|
||||||
id: 'development',
|
|
||||||
name: 'Entwicklung',
|
|
||||||
icon: 'code',
|
|
||||||
color: '#64748b',
|
|
||||||
colorClass: 'development',
|
|
||||||
description: 'Docs, Screen Flow & Brandbook',
|
|
||||||
modules: [
|
|
||||||
{
|
|
||||||
id: 'docs',
|
|
||||||
name: 'Developer Docs',
|
|
||||||
href: '/development/docs',
|
|
||||||
description: 'MkDocs Dokumentation',
|
|
||||||
purpose: 'API-Dokumentation und Architektur-Diagramme durchsuchen.',
|
|
||||||
audience: ['Entwickler'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'screen-flow',
|
|
||||||
name: 'Screen Flow',
|
|
||||||
href: '/development/screen-flow',
|
|
||||||
description: 'UI Screen-Verbindungen',
|
|
||||||
purpose: 'Navigation und Screen-Verbindungen der Core-App visualisieren.',
|
|
||||||
audience: ['Designer', 'Entwickler'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'brandbook',
|
|
||||||
name: 'Brandbook',
|
|
||||||
href: '/development/brandbook',
|
|
||||||
description: 'Corporate Design',
|
|
||||||
purpose: 'Referenz fuer Logos, Farben, Typografie und Design-Richtlinien.',
|
|
||||||
audience: ['Designer', 'Marketing'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// Meta modules (always visible)
|
// Meta modules (always visible)
|
||||||
|
|||||||
Reference in New Issue
Block a user