website (17 pages + 3 components): - multiplayer/wizard, middleware/wizard+test-wizard, communication - builds/wizard, staff-search, voice, sbom/wizard - foerderantrag, mail/tasks, tools/communication, sbom - compliance/evidence, uni-crawler, brandbook (already done) - CollectionsTab, IngestionTab, RiskHeatmap backend-lehrer (5 files): - letters_api (641 → 2), certificates_api (636 → 2) - alerts_agent/db/models (636 → 3) - llm_gateway/communication_service (614 → 2) - game/database already done in prior batch klausur-service (2 files): - hybrid_vocab_extractor (664 → 2) - klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2) voice-service (3 files): - bqas/rag_judge (618 → 3), runner (529 → 2) - enhanced_task_orchestrator (519 → 2) studio-v2 (6 files): - korrektur/[klausurId] (578 → 4), fairness (569 → 2) - AlertsWizard (552 → 2), OnboardingWizard (513 → 2) - korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
94 lines
3.7 KiB
TypeScript
94 lines
3.7 KiB
TypeScript
interface AssistantSidebarProps {
|
|
isRTL: boolean
|
|
t: (key: string) => string
|
|
assistantHistory: { role: string; content: string }[]
|
|
assistantMessage: string
|
|
setAssistantMessage: (msg: string) => void
|
|
onAskAssistant: () => void
|
|
onClose: () => void
|
|
}
|
|
|
|
export function AssistantSidebar({
|
|
isRTL,
|
|
t,
|
|
assistantHistory,
|
|
assistantMessage,
|
|
setAssistantMessage,
|
|
onAskAssistant,
|
|
onClose,
|
|
}: AssistantSidebarProps) {
|
|
return (
|
|
<div className={`fixed ${isRTL ? 'left-0' : 'right-0'} top-0 h-full w-96 bg-white border-${isRTL ? 'r' : 'l'} border-slate-200 shadow-xl z-30 flex flex-col`}>
|
|
<div className={`p-4 border-b border-slate-200 flex items-center justify-between ${isRTL ? 'flex-row-reverse' : ''}`}>
|
|
<div className={`flex items-center gap-2 ${isRTL ? 'flex-row-reverse' : ''}`}>
|
|
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center">
|
|
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold text-slate-900">{t('fa_assistant_title')}</h3>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={onClose}
|
|
className="p-2 rounded-lg hover:bg-slate-100 transition-colors"
|
|
>
|
|
<svg className="w-4 h-4 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Chat History */}
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
|
{assistantHistory.length === 0 && (
|
|
<div className="text-center py-8">
|
|
<p className="text-slate-500 text-sm">
|
|
{t('fa_assistant_placeholder')}
|
|
</p>
|
|
</div>
|
|
)}
|
|
{assistantHistory.map((msg, idx) => (
|
|
<div
|
|
key={idx}
|
|
className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
|
|
>
|
|
<div
|
|
className={`max-w-[85%] p-3 rounded-xl text-sm ${
|
|
msg.role === 'user'
|
|
? 'bg-blue-600 text-white'
|
|
: 'bg-slate-100 text-slate-700'
|
|
}`}
|
|
>
|
|
{msg.content}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Input */}
|
|
<div className="p-4 border-t border-slate-200">
|
|
<div className={`flex gap-2 ${isRTL ? 'flex-row-reverse' : ''}`}>
|
|
<input
|
|
type="text"
|
|
value={assistantMessage}
|
|
onChange={(e) => setAssistantMessage(e.target.value)}
|
|
onKeyDown={(e) => e.key === 'Enter' && onAskAssistant()}
|
|
placeholder={t('fa_assistant_placeholder')}
|
|
className="flex-1 px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
/>
|
|
<button
|
|
onClick={onAskAssistant}
|
|
className="p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|