Files
breakpilot-lehrer/website/app/admin/content/page.tsx
Benjamin Admin 34da9f4cda [split-required] Split 700-870 LOC files across all services
backend-lehrer (11 files):
- llm_gateway/routes/schools.py (867 → 5), recording_api.py (848 → 6)
- messenger_api.py (840 → 5), print_generator.py (824 → 5)
- unit_analytics_api.py (751 → 5), classroom/routes/context.py (726 → 4)
- llm_gateway/routes/edu_search_seeds.py (710 → 4)

klausur-service (12 files):
- ocr_labeling_api.py (845 → 4), metrics_db.py (833 → 4)
- legal_corpus_api.py (790 → 4), page_crop.py (758 → 3)
- mail/ai_service.py (747 → 4), github_crawler.py (767 → 3)
- trocr_service.py (730 → 4), full_compliance_pipeline.py (723 → 4)
- dsfa_rag_api.py (715 → 4), ocr_pipeline_auto.py (705 → 4)

website (6 pages):
- audit-checklist (867 → 8), content (806 → 6)
- screen-flow (790 → 4), scraper (789 → 5)
- zeugnisse (776 → 5), modules (745 → 4)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 08:01:18 +02:00

127 lines
5.4 KiB
TypeScript

'use client'
/**
* Admin Panel fuer Website-Content
*
* Erlaubt das Bearbeiten aller Website-Texte:
* - Hero Section, Features, FAQ, Pricing, Trust Indicators, Testimonial
*
* NEU: Live-Preview der Website zeigt Kontext beim Bearbeiten
*/
import LanguageSelector from '@/components/LanguageSelector'
import AdminLayout from '@/components/admin/AdminLayout'
import { useContentEditor } from './_components/useContentEditor'
import ContentEditorTabs from './_components/ContentEditorTabs'
import LivePreviewPanel from './_components/LivePreviewPanel'
export default function AdminPage() {
const editor = useContentEditor()
if (editor.loading) {
return (
<AdminLayout title="Uebersetzungen" description="Website Content & Sprachen">
<div className="flex items-center justify-center py-12">
<div className="text-xl text-slate-600">{editor.t('admin_loading')}</div>
</div>
</AdminLayout>
)
}
if (!editor.content) {
return (
<AdminLayout title="Uebersetzungen" description="Website Content & Sprachen">
<div className="flex items-center justify-center py-12">
<div className="text-xl text-red-600">{editor.t('admin_error')}</div>
</div>
</AdminLayout>
)
}
return (
<AdminLayout title="Uebersetzungen" description="Website Content & Sprachen">
<div className={editor.isRTL ? 'rtl' : ''} dir={editor.isRTL ? 'rtl' : 'ltr'}>
{/* Toolbar */}
<div className={`bg-white rounded-xl border border-slate-200 p-4 mb-6 flex items-center justify-between ${editor.isRTL ? 'flex-row-reverse' : ''}`}>
<div className="flex items-center gap-4">
<LanguageSelector currentLanguage={editor.language} onLanguageChange={editor.setLanguage} />
<button
onClick={() => editor.setShowPreview(!editor.showPreview)}
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
editor.showPreview ? 'bg-blue-100 text-blue-700' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
title={editor.showPreview ? 'Preview ausblenden' : 'Preview einblenden'}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
Live-Preview
</button>
</div>
<div className={`flex items-center gap-4 ${editor.isRTL ? 'flex-row-reverse' : ''}`}>
{editor.message && (
<span className={`px-3 py-1 rounded text-sm ${
editor.message.type === 'success' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
}`}>
{editor.message.text}
</span>
)}
<button
onClick={editor.saveChanges}
disabled={editor.saving}
className="bg-primary-600 text-white px-6 py-2 rounded-lg font-medium hover:bg-primary-700 disabled:opacity-50 transition-colors"
>
{editor.saving ? editor.t('admin_saving') : editor.t('admin_save')}
</button>
</div>
</div>
{/* Tabs */}
<div className="mb-6">
<div className={`flex gap-1 bg-slate-100 p-1 rounded-lg w-fit ${editor.isRTL ? 'flex-row-reverse' : ''}`}>
{(['hero', 'features', 'faq', 'pricing', 'other'] as const).map((tab) => (
<button
key={tab}
onClick={() => editor.setActiveTab(tab)}
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
editor.activeTab === tab ? 'bg-white text-slate-900 shadow-sm' : 'text-slate-600 hover:text-slate-900'
}`}
>
{tab === 'hero' && editor.t('admin_tab_hero')}
{tab === 'features' && editor.t('admin_tab_features')}
{tab === 'faq' && editor.t('admin_tab_faq')}
{tab === 'pricing' && editor.t('admin_tab_pricing')}
{tab === 'other' && editor.t('admin_tab_other')}
</button>
))}
</div>
</div>
{/* Split Layout: Editor + Preview */}
<div className={`grid gap-6 ${editor.showPreview ? 'grid-cols-2' : 'grid-cols-1'}`}>
<div className="bg-white rounded-xl border border-slate-200 shadow-sm p-6 max-h-[calc(100vh-280px)] overflow-y-auto">
<ContentEditorTabs
activeTab={editor.activeTab}
content={editor.content}
isRTL={editor.isRTL}
t={editor.t}
updateHero={editor.updateHero}
updateFeature={editor.updateFeature}
updateFAQ={editor.updateFAQ}
addFAQ={editor.addFAQ}
removeFAQ={editor.removeFAQ}
updatePricing={editor.updatePricing}
updateTrust={editor.updateTrust}
updateTestimonial={editor.updateTestimonial}
/>
</div>
{editor.showPreview && (
<LivePreviewPanel activeTab={editor.activeTab} iframeRef={editor.iframeRef} />
)}
</div>
</div>
</AdminLayout>
)
}