Card central

This commit is contained in:
2026-05-01 21:18:48 +02:00
parent 2b65876525
commit 94a2ef340e
4 changed files with 57 additions and 110 deletions

View File

@@ -213,7 +213,6 @@ function TutorApp({ currentUser, onLogout }) {
const [studentProgram, setStudentProgram] = useState(null)
const [activeAssetIndex, setActiveAssetIndex] = useState(0)
const [activeSectionIndex, setActiveSectionIndex] = useState(0)
const [assetFullscreenOpen, setAssetFullscreenOpen] = useState(false)
const [progressPanelOpen, setProgressPanelOpen] = useState(false)
const [settingsPanelOpen, setSettingsPanelOpen] = useState(false)
const mediaRecorderRef = useRef(null)
@@ -512,7 +511,6 @@ function TutorApp({ currentUser, onLogout }) {
stopSpeechPlayback()
deactivateAutoListening(false)
setSessionActive(false)
setAssetFullscreenOpen(false)
setProgressPanelOpen(false)
setSettingsPanelOpen(false)
setCurrentInstruction('')
@@ -614,6 +612,22 @@ function TutorApp({ currentUser, onLogout }) {
}
}
function getLessonContextPayload() {
return {
lesson_title: activeLessonTitle,
asset_title: activeAsset?.title || null,
section_title: activeSection?.title || activeAsset?.title || null,
step_percent: lessonStepPercent,
}
}
function compactInstruction(text) {
const cleanText = text.trim()
if (!cleanText) return ''
const sentences = cleanText.match(/[^.!?]+[.!?]+|[^.!?]+$/g) || [cleanText]
return sentences.slice(0, 2).join(' ').trim()
}
async function finishSpeechPlayback(debugMessage) {
setSpeaking(false)
if (audioPlaybackUrlRef.current) {
@@ -718,7 +732,11 @@ function TutorApp({ currentUser, onLogout }) {
const data = await apiFetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ student_id: Number(selectedStudentId), message: text }),
body: JSON.stringify({
student_id: Number(selectedStudentId),
message: text,
...getLessonContextPayload(),
}),
})
appendMessage('assistant', data.reply)
setCurrentInstruction(data.reply)
@@ -1079,7 +1097,7 @@ function TutorApp({ currentUser, onLogout }) {
)}
</div>
{currentInstruction ? (
<p className="teacher-transcript">{currentInstruction}</p>
<p className="teacher-transcript">{compactInstruction(currentInstruction)}</p>
) : (
<p className="muted teacher-transcript">Professeur TOP prépare la suite de la leçon.</p>
)}
@@ -1106,18 +1124,12 @@ function TutorApp({ currentUser, onLogout }) {
</button>
</div>
</div>
<button
type="button"
className="lesson-asset-open"
onClick={() => setAssetFullscreenOpen(true)}
aria-label="Agrandir la fiche"
>
<div className="lesson-asset-open">
<img
src={activeSection?.url || activeAsset.url}
alt={activeSection?.title || activeAsset.title}
/>
<span>Agrandir la fiche</span>
</button>
</div>
</div>
)}
</section>
@@ -1195,42 +1207,6 @@ function TutorApp({ currentUser, onLogout }) {
</div>
)}
{assetFullscreenOpen && activeAsset && (
<div className="asset-fullscreen" role="dialog" aria-label="Fiche agrandie">
<div className="asset-fullscreen-bar">
<strong>
Étape {activeLessonStep}/{totalLessonSteps} · {activeSection?.title || activeAsset.title}
</strong>
<button type="button" className="secondary-button" onClick={() => setAssetFullscreenOpen(false)}>
Fermer
</button>
</div>
<div className="asset-fullscreen-stage">
<img
src={activeSection?.url || activeAsset.url}
alt={activeSection?.title || activeAsset.title}
/>
</div>
<div className="asset-fullscreen-controls">
<button
type="button"
className="secondary-button"
onClick={goToPreviousLessonStep}
disabled={activeLessonStep <= 1}
>
Précédente
</button>
<button
type="button"
className="secondary-button"
onClick={goToNextLessonStep}
disabled={activeLessonStep >= totalLessonSteps}
>
Suivante
</button>
</div>
</div>
)}
</main>
)}
</div>

View File

@@ -477,7 +477,7 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
font-weight: 700;
}
.teacher-transcript {
max-height: 4.8rem;
max-height: 3.2rem;
overflow: auto;
color: #14213d;
font-size: clamp(0.95rem, 1.5vw, 1.08rem);
@@ -523,43 +523,6 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
border-radius: 14px;
background: white;
}
.lesson-asset-open span {
display: none;
color: #2563eb;
font-size: 0.9rem;
font-weight: 700;
}
.asset-fullscreen {
position: fixed;
inset: 0;
z-index: 20;
display: grid;
grid-template-rows: auto minmax(0, 1fr) auto;
gap: 0.75rem;
padding: 0.75rem;
background: #f5f7fb;
}
.asset-fullscreen-bar,
.asset-fullscreen-controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.asset-fullscreen-stage {
min-height: 0;
overflow: auto;
border: 1px solid #dbeafe;
border-radius: 16px;
background: white;
}
.asset-fullscreen-stage img {
display: block;
width: max(100%, 980px);
height: auto;
min-height: 100%;
object-fit: contain;
}
.lesson-bubble {
min-height: 68px;
}
@@ -794,8 +757,8 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
}
.teacher-transcript {
max-height: 2.7rem;
font-size: 0.95rem;
max-height: 2.35rem;
font-size: 0.9rem;
}
.lesson-display-head,
@@ -819,26 +782,8 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
font-size: 0.95rem;
}
.lesson-asset-open span {
display: block;
}
.lesson-asset-open img {
max-height: 31dvh;
}
.asset-fullscreen {
padding: 0.5rem;
}
.asset-fullscreen-stage img {
width: 100%;
min-height: 100%;
}
.asset-fullscreen-controls {
display: grid;
grid-template-columns: 1fr 1fr;
max-height: none;
}
.lesson-composer {