139 lines
7.0 KiB
JavaScript
139 lines
7.0 KiB
JavaScript
// 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,
|
||
});
|