backend-lehrer (10 files): - game/database.py (785 → 5), correction_api.py (683 → 4) - classroom_engine/antizipation.py (676 → 5) - llm_gateway schools/edu_search already done in prior batch klausur-service (12 files): - orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4) - zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5) - eh_templates.py (658 → 5), mail/api.py (651 → 5) - qdrant_service.py (638 → 5), training_api.py (625 → 4) website (6 pages): - middleware (696 → 8), mail (733 → 6), consent (628 → 8) - compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7) studio-v2 (3 components): - B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2) - dashboard-experimental (739 → 2) admin-lehrer (4 files): - uebersetzungen (769 → 4), manager (670 → 2) - ChunkBrowserQA (675 → 6), dsfa/page (674 → 5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
143 lines
5.1 KiB
TypeScript
143 lines
5.1 KiB
TypeScript
'use client'
|
|
|
|
import React from 'react'
|
|
import { COLLECTIONS } from './ChunkBrowserConstants'
|
|
import { getRegName } from './ChunkBrowserHelpers'
|
|
|
|
interface ChunkBrowserToolbarProps {
|
|
collection: string
|
|
onCollectionChange: (col: string) => void
|
|
selectedRegulation: string | null
|
|
structInfo: { article?: string; section?: string; pages?: string }
|
|
docChunkIndex: number
|
|
docTotalChunks: number
|
|
docChunksLength: number
|
|
chunksPerPage: number
|
|
setChunksPerPage: (v: number) => void
|
|
splitViewActive: boolean
|
|
setSplitViewActive: (v: boolean) => void
|
|
fullscreen: boolean
|
|
setFullscreen: (v: boolean) => void
|
|
onPrev: () => void
|
|
onNext: () => void
|
|
onJumpTo: (idx: number) => void
|
|
}
|
|
|
|
export function ChunkBrowserToolbar({
|
|
collection,
|
|
onCollectionChange,
|
|
selectedRegulation,
|
|
structInfo,
|
|
docChunkIndex,
|
|
docTotalChunks,
|
|
docChunksLength,
|
|
chunksPerPage,
|
|
setChunksPerPage,
|
|
splitViewActive,
|
|
setSplitViewActive,
|
|
fullscreen,
|
|
setFullscreen,
|
|
onPrev,
|
|
onNext,
|
|
onJumpTo,
|
|
}: ChunkBrowserToolbarProps) {
|
|
return (
|
|
<div className="flex-shrink-0 bg-white rounded-xl border border-slate-200 p-3 mb-3">
|
|
<div className="flex flex-wrap items-center gap-4">
|
|
<div>
|
|
<label className="block text-xs font-medium text-slate-500 mb-1">Collection</label>
|
|
<select
|
|
value={collection}
|
|
onChange={(e) => onCollectionChange(e.target.value)}
|
|
className="px-3 py-1.5 border rounded-lg text-sm focus:ring-2 focus:ring-teal-500"
|
|
>
|
|
{COLLECTIONS.map(c => (
|
|
<option key={c} value={c}>{c}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
{selectedRegulation && (
|
|
<>
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-sm font-semibold text-slate-900">
|
|
{selectedRegulation} — {getRegName(selectedRegulation)}
|
|
</span>
|
|
{structInfo.article && (
|
|
<span className="px-2 py-0.5 bg-blue-100 text-blue-800 text-xs font-medium rounded">
|
|
{structInfo.article}
|
|
</span>
|
|
)}
|
|
{structInfo.pages && (
|
|
<span className="px-2 py-0.5 bg-slate-100 text-slate-600 text-xs rounded">
|
|
{structInfo.pages}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-2 ml-auto">
|
|
<button
|
|
onClick={onPrev}
|
|
disabled={docChunkIndex === 0}
|
|
className="px-3 py-1.5 text-sm font-medium border rounded-lg bg-white hover:bg-slate-50 disabled:opacity-30 disabled:cursor-not-allowed"
|
|
>
|
|
◀ Zurueck
|
|
</button>
|
|
<span className="text-sm font-mono text-slate-600 min-w-[80px] text-center">
|
|
{docChunkIndex + 1} / {docTotalChunks}
|
|
</span>
|
|
<button
|
|
onClick={onNext}
|
|
disabled={docChunkIndex >= docChunksLength - 1}
|
|
className="px-3 py-1.5 text-sm font-medium border rounded-lg bg-white hover:bg-slate-50 disabled:opacity-30 disabled:cursor-not-allowed"
|
|
>
|
|
Weiter ▶
|
|
</button>
|
|
<input
|
|
type="number"
|
|
min={1}
|
|
max={docTotalChunks}
|
|
value={docChunkIndex + 1}
|
|
onChange={(e) => {
|
|
const v = parseInt(e.target.value, 10)
|
|
if (!isNaN(v) && v >= 1 && v <= docTotalChunks) onJumpTo(v - 1)
|
|
}}
|
|
className="w-16 px-2 py-1 border rounded text-xs text-center"
|
|
title="Springe zu Chunk Nr."
|
|
/>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<label className="text-xs text-slate-500">Chunks/Seite:</label>
|
|
<select
|
|
value={chunksPerPage}
|
|
onChange={(e) => setChunksPerPage(Number(e.target.value))}
|
|
className="px-2 py-1 border rounded text-xs"
|
|
>
|
|
{[3, 4, 5, 6, 8, 10, 12, 15, 20].map(n => (
|
|
<option key={n} value={n}>{n}</option>
|
|
))}
|
|
</select>
|
|
<button
|
|
onClick={() => setSplitViewActive(!splitViewActive)}
|
|
className={`px-3 py-1 text-xs rounded-lg border ${
|
|
splitViewActive ? 'bg-teal-50 border-teal-300 text-teal-700' : 'bg-slate-50 border-slate-300 text-slate-600'
|
|
}`}
|
|
>
|
|
{splitViewActive ? 'Split-View an' : 'Split-View aus'}
|
|
</button>
|
|
<button
|
|
onClick={() => setFullscreen(!fullscreen)}
|
|
className={`px-3 py-1 text-xs rounded-lg border ${
|
|
fullscreen ? 'bg-indigo-50 border-indigo-300 text-indigo-700' : 'bg-slate-50 border-slate-300 text-slate-600'
|
|
}`}
|
|
title={fullscreen ? 'Vollbild beenden (Esc)' : 'Vollbild'}
|
|
>
|
|
{fullscreen ? '\u2715 Vollbild beenden' : '\u2716 Vollbild'}
|
|
</button>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|