Files
3d.lehrstun.de/templates/cockpit.html
Hans Puettmann 8a55e175a2 Style Guide v1.0.0: Indigo-Palette + lokale Web-Fonts
Komplette visuelle Umstellung nach dem generierten Style-Guide
(3d-lehrstun-de-v1.0.0). 3D-Druck-AG bekommt eine eigene Marke,
getrennt vom Teal der arduino.lehrstun.de-Schwester.

Farben: Teal #00979D -> Indigo #5B6EAE, warmes Off-White Surface
  #F0EEE9 statt Kuehlweiss, Lavendel-Akzent #9B8EC4.
Fonts: Raleway (Headings), Lato (Body), Inconsolata (Mono) — lokal
  gehostet in static/fonts/ (DSGVO-konform, kein Google-CDN),
  via @font-face + unicode-range (latin + latin-ext).
Form: Radius/Schatten/Spacing als Tokens (--radius-*, --shadow-*).

Technik:
  - base.html :root: neue --color-*/--font-*/--radius-* Tokens,
    alte Variablennamen (--primary etc.) als Aliase -> alle 33
    Templates ziehen sofort mit, kein Template-Rewrite noetig.
  - Semantische Banner-Tokens (--info/warn/success/error-bg+text+border)
    loesen ~130 Hardcoded-Pastelle ab (per sed gemappt).
  - Komponenten (Card, Button, Badge, Flash, Table, Code) auf Tokens.

Alle 13 Hauptseiten gegengeprueft (HTTP 200, keine Render-Fehler).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-04 12:52:14 +02:00

343 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
{% extends "base.html" %}
{% block title %}Cockpit &mdash; {{ vorname }}{% endblock %}
{% block content %}
{# ====== Header ====== #}
<div class="section-header">
<h1 style="display:flex; align-items:center; gap:0.5rem;">
<span style="font-size: 2.2rem;">{{ tier_emoji(tier) }}</span>
Hallo, {{ vorname }}!
</h1>
<a href="{{ url_for('profil.logout') }}" class="btn btn-secondary">Abmelden</a>
</div>
{# ====== BANNER: Lehrer-Notizen (V5-Quick-Action) ====== #}
{% for n in status.notizen %}
<div class="card" style="background: var(--warn-bg); border-left: 5px solid var(--warning); margin-bottom: 0.5rem;">
<p style="margin: 0; color: var(--warn-text);">
<strong>📌 Lehrer-Notiz:</strong> {{ n.text }}
</p>
<form method="post" action="{{ url_for('profil.notiz_gelesen', notiz_id=n.id) }}" style="margin-top: 0.5rem;">
<button class="btn btn-secondary" style="padding: 0.2rem 0.6rem; font-size: 0.85rem;">verstanden</button>
</form>
</div>
{% endfor %}
{# ====== BANNER: Offene Rueckfragen zu eigenen Projekten (V6) ====== #}
{% for r in status.rueckfragen %}
<div class="card" style="background: var(--warn-bg); border-left: 5px solid var(--warning); margin-bottom: 0.5rem;">
<p style="margin: 0; color: var(--warn-text);">
<strong>❓ Rueckfrage zu „{{ r.projekt_titel }}":</strong> {{ r.text }}
</p>
<p style="margin-top: 0.5rem; font-size: 0.85rem; color: var(--text-light);">
Bessere das Projekt nach, dann melde es erneut zur Freigabe.
</p>
</div>
{% endfor %}
{# ====== BANNER: Eingegangene Paarungs-Anfragen ====== #}
{% for a in status.offene_anfragen %}
<div class="card" style="background: var(--info-bg); border-left: 5px solid var(--primary); margin-bottom: 0.5rem;">
<p style="margin: 0;">
<strong>{{ tier_emoji(a.von_tier) }} {{ a.von_vorname }}</strong> moechte mit dir
zusammenarbeiten. Magst du?
</p>
<div style="margin-top: 0.5rem; display: flex; gap: 0.5rem;">
<form method="post" action="{{ url_for('profil.paarung_anfrage_beantworten', anfrage_id=a.id, aktion='annehmen') }}">
<button class="btn btn-primary" style="padding: 0.3rem 0.8rem;">Ja, gerne</button>
</form>
<form method="post" action="{{ url_for('profil.paarung_anfrage_beantworten', anfrage_id=a.id, aktion='ablehnen') }}">
<button class="btn btn-secondary" style="padding: 0.3rem 0.8rem;">Nein, lieber nicht</button>
</form>
</div>
</div>
{% endfor %}
{# ====== POWER-WERKZEUGE (nur fuer Power-User) ====== #}
{% if session.rolle == 'power' %}
<div class="card" style="border-left: 4px solid var(--primary);">
<h2>🔧 Power-Werkzeuge</h2>
<p style="color: var(--text-light); font-size: 0.9rem; margin-bottom: 0.8rem;">
Du bist Power-User — hier deine Verwaltungs-Bereiche. SuS-Profile und Projekt-Freigaben
bleiben dem Lehrer-Admin vorbehalten.
</p>
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
<a href="{{ url_for('admin.admin_drucker') }}" class="btn btn-secondary">🖨️ Drucker verwalten</a>
<a href="{{ url_for('admin.software_liste') }}" class="btn btn-secondary">🖥️ Software-Katalog</a>
<a href="{{ url_for('admin.slot_neu_lehrer') }}" class="btn btn-secondary">🔖 Slot fuer SuS</a>
<a href="{{ url_for('profil.projekt_neu') }}" class="btn btn-primary">+ Projekt anlegen</a>
</div>
</div>
{% endif %}
{# ====== Check-In-Modal — wenn heute noch nichts gewaehlt wurde (nicht fuer Power) ====== #}
{% if session.rolle != 'power' %}
{% if not status.check_in_heute %}
<div class="card" style="border-top: 4px solid var(--primary);">
<h2>Was machst du heute? 🎯</h2>
<p style="color: var(--text-light); font-size: 0.9rem;">
Damit Herb und Herr Rechmann auf einen Blick sehen, woran du arbeitest.
Ein Klick reicht — Freitext nur, wenn du willst.
</p>
<form method="post" action="{{ url_for('profil.check_in') }}" style="margin-top: 1rem;">
<div class="check-in-optionen">
{% set hat_projekte = status.aktive_projekte | length > 0 %}
{% if hat_projekte %}
<label class="ci-option">
<input type="radio" name="modus" value="weiter_wie_bisher" checked>
<span>Ich arbeite an „{{ status.aktive_projekte[0].titel }}" weiter</span>
</label>
{% endif %}
<label class="ci-option">
<input type="radio" name="modus" value="neues_projekt" {% if not hat_projekte %}checked{% endif %}>
<span>Neues Projekt anfangen</span>
</label>
{% if status.ist_neu %}
<label class="ci-option">
<input type="radio" name="modus" value="onboarding">
<span>Onboarding-Lektion machen</span>
</label>
{% endif %}
<label class="ci-option">
<input type="radio" name="modus" value="drucken">
<span>Drucken / auf Drucker warten</span>
</label>
<label class="ci-option">
<input type="radio" name="modus" value="helfen">
<span>Jemandem helfen</span>
</label>
<label class="ci-option">
<input type="radio" name="modus" value="sonstiges">
<span>Sonstiges</span>
</label>
</div>
<input type="text" name="freitext" placeholder="(optional) was genau …"
style="width: 100%; padding: 0.5rem; margin-top: 0.6rem; border: 1px solid var(--border); border-radius: 4px;">
<button class="btn btn-primary" style="margin-top: 0.6rem;">Los geht's</button>
</form>
</div>
{% else %}
<div class="card" style="background: var(--success-bg); border-left: 4px solid var(--success); display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap;">
<p style="margin: 0; font-size: 0.9rem;">
<strong>Heute eingecheckt:</strong>
{% if status.check_in_heute.modus == 'weiter_wie_bisher' %}Arbeite weiter
{% elif status.check_in_heute.modus == 'neues_projekt' %}Neues Projekt
{% elif status.check_in_heute.modus == 'onboarding' %}Onboarding
{% elif status.check_in_heute.modus == 'drucken' %}Drucken
{% elif status.check_in_heute.modus == 'helfen' %}Hilft anderen
{% else %}{{ status.check_in_heute.modus }}{% endif %}
{% if status.check_in_heute.freitext %} &mdash; „{{ status.check_in_heute.freitext }}"{% endif %}
</p>
<form method="post" action="{{ url_for('profil.check_in_zuruecksetzen') }}" style="margin: 0;">
<button class="btn btn-secondary" style="padding: 0.3rem 0.7rem; font-size: 0.8rem;">
Modus aendern
</button>
</form>
</div>
{% endif %}
{% endif %}{# Ende: Check-In nur fuer Nicht-Power #}
{# ====== PROJEKT-KARTE — ganz oben, damit "Hier weitermachen" sofort sichtbar ist ====== #}
{% if status.hat_projekte or not status.ist_neu or status.projekt.letztes %}
<div class="card" style="margin-top: 1rem;
{% if status.projekt.aktiv %}border-left: 4px solid var(--success);{% endif %}">
<h2>{% if status.paarung %}Euer Projekt{% else %}Dein Projekt{% endif %}</h2>
{% if status.projekt.aktiv %}
{# === Aktives Projekt: Weitermachen-Karte === #}
<div style="display: flex; gap: 1rem; align-items: center; margin-top: 0.5rem; flex-wrap: wrap;">
<div style="flex: 0 0 120px;">
{% if status.projekt.aktiv.hat_cover %}
<img src="{{ url_for('api.projekt_cover', projekt_id=status.projekt.aktiv.id) }}" alt=""
style="width: 120px; height: 120px; object-fit: cover; border-radius: 8px;">
{% else %}
<div style="width: 120px; height: 120px; background: linear-gradient(135deg, var(--surface-muted), var(--surface-hover));
border-radius: 8px; display: flex; align-items: center; justify-content: center;
font-size: 2.5rem; color: var(--text-light);">🎯</div>
{% endif %}
</div>
<div style="flex: 1; min-width: 250px;">
<h3 style="margin: 0 0 0.4rem 0;">{{ status.projekt.aktiv.titel }}</h3>
{% if status.projekt.aktiv.beschreibung_md %}
<div style="font-size: 0.9rem; color: var(--text); max-height: 4.5em; overflow: hidden;">
{{ status.projekt.aktiv.beschreibung_md|markdown }}
</div>
{% endif %}
<div style="margin-top: 0.8rem; display: flex; gap: 0.5rem; flex-wrap: wrap;">
<a href="{{ url_for('profil.projekt_detail', projekt_id=status.projekt.aktiv.id) }}"
class="btn btn-primary">Hier weitermachen →</a>
<a href="{{ url_for('profil.projekt_abschluss', projekt_id=status.projekt.aktiv.id) }}"
class="btn btn-secondary" style="font-size: 0.85rem;">Abschliessen</a>
</div>
</div>
</div>
{% elif status.projekt.letztes and status.projekt.letztes.freigabe_status == 'wartet_auf_freigabe' %}
<div style="background: var(--warn-bg); padding: 0.8rem; border-radius: 6px; border-left: 4px solid var(--warning);">
<strong>⏳ Wartet auf Freigabe:</strong>
<a href="{{ url_for('profil.projekt_detail', projekt_id=status.projekt.letztes.id) }}">{{ status.projekt.letztes.titel }}</a>
<div style="font-size: 0.85rem; margin-top: 0.3rem; color: var(--text-light);">
Der Lehrer schaut drueber. Sobald freigegeben, kannst du ein neues Projekt anfangen.
</div>
</div>
{% elif status.projekt.letztes and status.projekt.letztes.freigabe_status == 'rueckfrage' %}
<div style="background: var(--error-bg); padding: 0.8rem; border-radius: 6px; border-left: 4px solid var(--danger);">
<strong>❓ Rueckfrage offen zu:</strong>
<a href="{{ url_for('profil.projekt_detail', projekt_id=status.projekt.letztes.id) }}">{{ status.projekt.letztes.titel }}</a>
<div style="font-size: 0.85rem; margin-top: 0.3rem;">
Siehe Rueckfrage-Banner oben, beantworte sie — dann kann der Lehrer freigeben.
</div>
</div>
{% else %}
<p style="color: var(--text-light); margin-bottom: 0.8rem;">
Du hast gerade kein laufendes Projekt. Bereit fuer was Neues?
</p>
{% if status.projekt.darf_neues %}
<a href="{{ url_for('profil.projekt_neu') }}" class="btn btn-primary">+ Neues Projekt anfangen</a>
{% else %}
<div style="background: var(--warn-bg); padding: 0.6rem 0.8rem; border-radius: 6px; font-size: 0.9rem;">
{{ status.projekt.sperr_grund }}
</div>
{% endif %}
{% endif %}
{% if status.projekt.aktiv or status.projekt.letztes %}
<div style="margin-top: 0.8rem; font-size: 0.85rem;">
<a href="{{ url_for('profil.projekte_liste') }}" style="color: var(--text-light);">Alle meine Projekte ansehen →</a>
</div>
{% endif %}
</div>
{% endif %}
<div class="grid" style="grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 1rem;">
{# ====== ONBOARDING-KARTE (V1: nur wenn nicht fertig) ====== #}
{% if status.ist_neu %}
<div class="card" style="grid-column: span 2; border-top: 4px solid var(--success);">
<h2>Dein Onboarding-Pfad 🚀</h2>
<p style="color: var(--text-light); margin-bottom: 1rem;">
Drei Lektionen, damit du allein klarkommst. Du klickst selbst „fertig", wenn du soweit bist.
</p>
<div class="onboarding-liste">
{% for l in status.onboarding.lektionen %}
<div class="onb-zeile onb-{{ l.status }}{% if l.aktuell %} onb-aktuell{% endif %}">
<span class="onb-icon">
{% if l.status == 'fertig' %}✅
{% elif l.status == 'laeuft' %}🟡
{% else %}⚪{% endif %}
</span>
<span class="onb-titel">
<strong>L{{ l.nummer }}</strong> &mdash; {{ l.titel }}
</span>
<span class="onb-aktion">
{% if l.status != 'fertig' %}
<a href="{{ url_for('oeffentlich.lektion_detail', nummer=l.nummer) }}"
class="btn btn-secondary" style="padding: 0.2rem 0.6rem; font-size: 0.8rem;">
ansehen
</a>
<form method="post" action="{{ url_for('profil.lektion_status_setzen', nummer=l.nummer) }}" style="display:inline;">
{% if l.status == 'offen' %}
<button name="status" value="laeuft" class="btn btn-secondary" style="padding: 0.2rem 0.6rem; font-size: 0.8rem;">starte</button>
{% else %}
<button name="status" value="fertig" class="btn btn-primary" style="padding: 0.2rem 0.6rem; font-size: 0.8rem;">fertig ✓</button>
{% endif %}
</form>
{% else %}
<form method="post" action="{{ url_for('profil.lektion_status_setzen', nummer=l.nummer) }}" style="display:inline;">
<button name="status" value="laeuft" class="btn btn-secondary" style="padding: 0.2rem 0.6rem; font-size: 0.75rem; opacity: 0.6;">nochmal</button>
</form>
{% endif %}
</span>
</div>
{% endfor %}
</div>
{% if not status.darf_slots_buchen %}
<p style="margin-top: 1rem; font-size: 0.85rem; color: var(--text-light);">
Drucker reservieren kannst du, sobald <strong>L1 (Sicherheit)</strong> erledigt ist.
</p>
{% endif %}
</div>
{% endif %}
{# ====== PAARUNG / TEAM-KARTE — immer wenn Paarung aktiv, sonst nur fuer Erfahrene ====== #}
{% if status.paarung or not status.ist_neu %}
<div class="card">
<h2>{% if status.paarung %}Dein Team{% else %}Allein arbeiten?{% endif %}</h2>
{% if status.paarung %}
<p style="font-size: 1.1rem;">
Du arbeitest mit
<strong>{{ tier_emoji(status.paarung.partner.tier) }} {{ status.paarung.partner.vorname }}</strong>
zusammen seit {{ status.paarung.gebildet_am[:10] }}.
</p>
<form method="post" action="{{ url_for('profil.paarung_aufloesen') }}"
onsubmit="return confirm('Paarung wirklich aufloesen?')"
style="margin-top: 0.8rem;">
<button class="btn btn-secondary" style="font-size: 0.85rem;">Paarung aufloesen</button>
</form>
{% else %}
<p style="color: var(--text-light); margin-bottom: 0.5rem;">
Du kannst dich mit jemandem zusammenschliessen — frag im Cockpit-Untermenue.
</p>
{% if andere_profile %}
<details>
<summary style="cursor:pointer; color: var(--primary);">Anfrage stellen</summary>
<div id="paarung-suche" style="margin-top: 0.5rem;">
{% for andere in andere_profile %}
<form method="post" action="{{ url_for('profil.paarung_anfragen', andere_profil_id=andere.id) }}"
style="display: inline-block; margin: 0.2rem;">
<button class="btn btn-secondary" style="padding: 0.3rem 0.6rem; font-size: 0.85rem;">
{{ tier_emoji(andere.tier) }} {{ andere.vorname }}
</button>
</form>
{% endfor %}
</div>
</details>
{% else %}
<p style="font-size: 0.85rem; color: var(--text-light); margin-top: 0.5rem;">
<em>Noch niemand sonst in der AG.</em>
</p>
{% endif %}
{% endif %}
</div>
{% endif %}
{# ====== DRUCKER-/SLOT-KARTE (V1: nur wenn L1 fertig) ====== #}
{% if status.darf_slots_buchen %}
<div class="card" style="grid-column: span 2; opacity: 0.7;">
<h2>🖨️ Drucker reservieren</h2>
<p style="color: var(--text-light);">
Slot-System kommt mit <em>Etappe 7</em>. Bis dahin: sprich dich vor Ort ab.
</p>
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<style>
.check-in-optionen { display: flex; flex-direction: column; gap: 0.4rem; }
.ci-option {
display: flex; gap: 0.6rem; align-items: center;
padding: 0.5rem 0.7rem; border-radius: 6px; cursor: pointer;
transition: background 0.15s;
}
.ci-option:hover { background: var(--surface-muted); }
.ci-option input[type=radio] { margin: 0; }
.onboarding-liste { display: flex; flex-direction: column; gap: 0.5rem; }
.onb-zeile {
display: flex; gap: 0.7rem; align-items: center;
padding: 0.5rem 0.7rem; border-radius: 6px;
background: var(--surface-muted);
}
.onb-zeile.onb-fertig { background: var(--success-bg); opacity: 0.8; }
.onb-zeile.onb-aktuell { background: var(--info-bg); border-left: 4px solid var(--primary); }
.onb-icon { font-size: 1.2rem; }
.onb-titel { flex: 1; }
.onb-aktion { display: flex; gap: 0.3rem; }
</style>
{% endblock %}