diff --git a/backend/src/controllers/classroomController.js b/backend/src/controllers/classroomController.js index edb5b3f..47445ec 100644 --- a/backend/src/controllers/classroomController.js +++ b/backend/src/controllers/classroomController.js @@ -949,6 +949,19 @@ function simMode(req, res) { res.json({ ok: true }); } +/* POST /api/classroom/:id/sim/annotate — teacher toggles draw-over-sim mode */ +function simAnnotate(req, res) { + const sessionId = Number(req.params.id); + const session = db.prepare(`SELECT * FROM classroom_sessions WHERE id=? AND status='active'`).get(sessionId); + if (!session) return res.status(404).json({ error: 'Сессия не активна' }); + if (session.teacher_id !== req.user.id && req.user.role !== 'admin') + return res.status(403).json({ error: 'Нет доступа' }); + + const { active } = req.body; + emitToSession(sessionId, { type: 'classroom_sim_annotate', sessionId, active: !!active }); + res.json({ ok: true }); +} + /* DELETE /api/classroom/:id/sim — teacher closes simulation */ function simClose(req, res) { const sessionId = Number(req.params.id); @@ -1522,6 +1535,7 @@ module.exports = { simClose, simState, simMode, + simAnnotate, clearPage, previewStroke, broadcastCursor, diff --git a/backend/src/routes/classroom.js b/backend/src/routes/classroom.js index b54f187..f678ed1 100644 --- a/backend/src/routes/classroom.js +++ b/backend/src/routes/classroom.js @@ -98,6 +98,7 @@ router.post('/:id/sim', ...teacher, c.simOpen); router.delete('/:id/sim', ...teacher, c.simClose); router.post('/:id/sim/state', ...teacher, c.simState); router.post('/:id/sim/mode', ...teacher, c.simMode); +router.post('/:id/sim/annotate', ...teacher, c.simAnnotate); // Cursor broadcast (all participants) router.post('/:id/cursor', ...auth, c.broadcastCursor); diff --git a/frontend/classroom.html b/frontend/classroom.html index 8be4c58..c6ace3e 100644 --- a/frontend/classroom.html +++ b/frontend/classroom.html @@ -2007,6 +2007,55 @@ background: #0D0D1A; } + /* ── Annotate-over-sim mode ───────────────────────────────────────────── */ + /* Board floats above the sim panel (sim visible behind transparent canvas) */ + .cr-board-area.annotate-active .cr-sim-panel { z-index: 1; } + .cr-board-area.annotate-active .cr-board-wrap { + z-index: 45; + background: transparent !important; + border-color: transparent !important; + box-shadow: none !important; + } + .cr-board-area.annotate-active .cr-board-wrap::before, + .cr-board-area.annotate-active .cr-board-wrap::after { display: none !important; } + /* Floating bar shown while annotating */ + .cr-annotate-bar { + display: none; + position: absolute; top: 0; left: 0; right: 0; z-index: 60; + height: 40px; flex-shrink: 0; + background: rgba(10,6,22,0.92); + border-bottom: 1.5px solid rgba(241,91,181,0.4); + backdrop-filter: blur(6px); + align-items: center; gap: 8px; padding: 0 12px; + } + .cr-board-area.annotate-active .cr-annotate-bar { display: flex; } + .cr-annotate-bar-label { + font-size: 0.75rem; font-weight: 700; color: #F15BB5; + display: flex; align-items: center; gap: 5px; flex: 1; + } + .cr-annotate-bar-label svg { width: 14px; height: 14px; stroke: #F15BB5; } + .cr-annotate-exit { + padding: 4px 12px; border-radius: 7px; border: 1px solid rgba(241,91,181,0.4); + background: rgba(241,91,181,0.1); color: #F15BB5; + font-family: 'Manrope',sans-serif; font-size: 0.72rem; font-weight: 700; + cursor: pointer; transition: all .15s; + } + .cr-annotate-exit:hover { background: rgba(241,91,181,0.22); } + /* "Draw" button in sim bar */ + .cr-sim-annotate-btn { + display: none; + padding: 3px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.12); + background: transparent; color: rgba(255,255,255,0.5); + font-family: 'Manrope',sans-serif; font-size: 0.7rem; font-weight: 700; + cursor: pointer; transition: all .15s; align-items: center; gap: 4px; + margin-right: 4px; + } + .cr-sim-annotate-btn svg { width: 12px; height: 12px; flex-shrink: 0; } + .cr-sim-annotate-btn:hover { color: rgba(255,255,255,0.8); border-color: rgba(241,91,181,0.4); } + .cr-sim-annotate-btn.active { background: rgba(241,91,181,0.18); border-color: rgba(241,91,181,0.5); color: #F15BB5; } + /* Show draw button only for teachers when sim is open */ + .cr-sim-panel.open .cr-sim-annotate-btn.teacher-ctrl { display: flex; } + /* ── Simulation picker modal ────────────────────────────────────────── */ .cr-sim-picker-overlay { position: fixed; inset: 0; z-index: 200; @@ -2202,6 +2251,11 @@ + +
+ +