Files
tutortool/docs/design_handoff/shared.jsx
2026-04-29 04:38:26 +02:00

139 lines
7.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// shared.jsx — fake data + tiny UI helpers used everywhere
const COURSE = {
name: "Funktionale Programmierung",
semester: "SS 2026",
tutorin: "Lina Puchstein",
weekday: "Donnerstag",
};
const STUDENTS = [
{ id: 1, name: "Aaron Becker", initials: "AB" },
{ id: 2, name: "Anna Lehmann", initials: "AL" },
{ id: 3, name: "Ben Hartmann", initials: "BH" },
{ id: 4, name: "Carla Vogt", initials: "CV" },
{ id: 5, name: "David Köhler", initials: "DK" },
{ id: 6, name: "Elif Yıldız", initials: "EY" },
{ id: 7, name: "Felix Braun", initials: "FB" },
{ id: 8, name: "Greta Sommer", initials: "GS" },
{ id: 9, name: "Henrik Roth", initials: "HR" },
{ id: 10, name: "Ida Neumann", initials: "IN" },
{ id: 11, name: "Jakob Frank", initials: "JF" },
{ id: 12, name: "Klara Wagner", initials: "KW" },
{ id: 13, name: "Leonie Krause", initials: "LK" },
{ id: 14, name: "Marek Schulz", initials: "MS" },
{ id: 15, name: "Nina Albrecht", initials: "NA" },
{ id: 16, name: "Otto Brandt", initials: "OB" },
{ id: 17, name: "Paula Engel", initials: "PE" },
{ id: 18, name: "Rafael Diaz", initials: "RD" },
{ id: 19, name: "Sophia Weiß", initials: "SW" },
];
// Room layout: tables with chairs around them — top-down floor plan.
// Tables are rectangles; seats are positioned along the long edges.
// coords are in % of room canvas (we render onto an absolutely positioned div).
const ROOM = {
name: "BC2 1.103",
width: 760, // px design space
height: 460,
// structural elements
walls: { x: 12, y: 12, w: 736, h: 436 },
door: { x: 60, y: 448, w: 70, h: 6, label: "Tür" },
window:{ x: 12, y: 120, w: 6, h: 220, label: "Fenster" },
beamer:{ x: 372, y: 24, w: 110, h: 8, label: "Beamer" },
podium:{ x: 332, y: 60, w: 190, h: 38, label: "Pult" },
// 4 group tables, each with 5 seats around it (2 top, 2 bottom, 1 short edge)
tables: [
{ id: "T1", x: 90, y: 150, w: 200, h: 70, label: "T1" },
{ id: "T2", x: 470, y: 150, w: 200, h: 70, label: "T2" },
{ id: "T3", x: 90, y: 320, w: 200, h: 70, label: "T3" },
{ id: "T4", x: 470, y: 320, w: 200, h: 70, label: "T4" },
],
};
// Generate seats around each table. Seat coords reference the seat circle's CENTER.
function makeSeats() {
const seats = [];
ROOM.tables.forEach((t) => {
// top edge: 2 seats
seats.push({ id: `${t.id}-1`, x: t.x + t.w * 0.28, y: t.y - 22, table: t.id });
seats.push({ id: `${t.id}-2`, x: t.x + t.w * 0.72, y: t.y - 22, table: t.id });
// bottom edge: 2 seats
seats.push({ id: `${t.id}-3`, x: t.x + t.w * 0.28, y: t.y + t.h + 22, table: t.id });
seats.push({ id: `${t.id}-4`, x: t.x + t.w * 0.72, y: t.y + t.h + 22, table: t.id });
// short edge (head): 1 seat
seats.push({ id: `${t.id}-5`, x: t.x + t.w + 26, y: t.y + t.h / 2, table: t.id });
});
return seats;
}
const SEATS = makeSeats();
// Pre-assign 14 students to seats for the live view
const SEAT_ASSIGN = {
"T1-1": 1, "T1-2": 2, "T1-3": 3, "T1-4": 4, "T1-5": 5,
"T2-1": 6, "T2-2": 7, "T2-3": 8, "T2-5": 10,
"T3-1": 11, "T3-2": 12, "T3-4": 14,
"T4-1": 15, "T4-3": 17,
};
const CHECKED_IN_AT = {
1: "14:02", 2: "14:01", 3: "14:00", 4: "14:03", 5: "14:01",
6: "14:04", 7: "14:02", 8: "14:05", 10: "14:08",
11: "14:11", 12: "14:06", 14: "14:09",
15: "14:12", 17: "14:18",
};
// Notes pre-filled for the live view
const NOTES = {
3: "Sehr aktiv heute — hat die Lösung zu Aufgabe 3 erklärt. Funktoren sitzen.",
5: "Hängt bei Currying noch. Mit Marek gepaart, läuft besser.",
10: "Kommt zu spät rein, sehr ruhig. Kurz nachfragen ob alles ok.",
14: "Hat eine elegante Foldr-Lösung gefunden — bei nächstem Mal als Beispiel zeigen.",
};
// Rendering helpers ---------------------------------------------------------
const StatusPill = ({ status }) => {
const map = {
open: { label: "OFFEN", cls: "open" },
closed: { label: "GESCHL.", cls: "closed" },
locked: { label: "GESPERRT", cls: "locked" },
present: { label: "ANWESEND", cls: "present" },
absent: { label: "FEHLT", cls: "absent" },
};
const m = map[status] || map.closed;
return (
<span className={`pill ${m.cls}`}>
<span className="dot"></span>
{m.label}
</span>
);
};
// Hand-drawn underline stroke
const UnderlineStroke = ({ width = 110, color = "var(--accent)" }) => (
<svg className="underline-stroke" width={width} height="8" viewBox={`0 0 ${width} 8`} fill="none">
<path d={`M 2 5 Q ${width*0.25} 1 ${width*0.5} 4 T ${width-2} 3`}
stroke={color} strokeWidth="1.6" strokeLinecap="round" fill="none" />
</svg>
);
// Tiny check / x icons
const Icon = {
check: (p={}) => <svg width="14" height="14" viewBox="0 0 14 14" {...p}><path d="M2.5 7.5 L5.5 10.5 L11.5 3.5" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>,
x: (p={}) => <svg width="12" height="12" viewBox="0 0 12 12" {...p}><path d="M3 3 L9 9 M9 3 L3 9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>,
lock: (p={}) => <svg width="13" height="13" viewBox="0 0 13 13" {...p}><rect x="2.5" y="6" width="8" height="5.5" rx="1" stroke="currentColor" strokeWidth="1.3" fill="none"/><path d="M4.5 6 V4.5 a2 2 0 0 1 4 0 V6" stroke="currentColor" strokeWidth="1.3" fill="none"/></svg>,
open: (p={}) => <svg width="13" height="13" viewBox="0 0 13 13" {...p}><rect x="2.5" y="6" width="8" height="5.5" rx="1" stroke="currentColor" strokeWidth="1.3" fill="none"/><path d="M4.5 6 V4.5 a2 2 0 0 1 4 0" stroke="currentColor" strokeWidth="1.3" fill="none"/></svg>,
copy: (p={}) => <svg width="13" height="13" viewBox="0 0 13 13" {...p}><rect x="2" y="2" width="7" height="7" rx="1" stroke="currentColor" strokeWidth="1.2" fill="none"/><rect x="4.5" y="4.5" width="7" height="7" rx="1" stroke="currentColor" strokeWidth="1.2" fill="none"/></svg>,
edit: (p={}) => <svg width="13" height="13" viewBox="0 0 13 13" {...p}><path d="M2 11 L2 9 L9 2 L11 4 L4 11 Z" stroke="currentColor" strokeWidth="1.2" fill="none" strokeLinejoin="round"/></svg>,
download: (p={}) => <svg width="14" height="14" viewBox="0 0 14 14" {...p}><path d="M7 2 V9 M3.5 6 L7 9 L10.5 6 M2.5 11.5 H11.5" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>,
arrow: (p={}) => <svg width="12" height="12" viewBox="0 0 12 12" {...p}><path d="M3 6 H9 M6.5 3 L9 6 L6.5 9" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>,
search:(p={}) => <svg width="13" height="13" viewBox="0 0 13 13" {...p}><circle cx="5.5" cy="5.5" r="3.5" stroke="currentColor" strokeWidth="1.3" fill="none"/><path d="M8 8 L11 11" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/></svg>,
plus: (p={}) => <svg width="12" height="12" viewBox="0 0 12 12" {...p}><path d="M6 2 V10 M2 6 H10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>,
};
Object.assign(window, {
COURSE, STUDENTS, ROOM, SEATS, SEAT_ASSIGN, CHECKED_IN_AT, NOTES,
StatusPill, UnderlineStroke, Icon,
});