509 lines
15 KiB
HTML
509 lines
15 KiB
HTML
<!--
|
|
Copyright 2025-2026 AIIrondev
|
|
|
|
Licensed under the Inventarsystem EULA (Endbenutzer-Lizenzvertrag).
|
|
See Legal/LICENSE for the full license text.
|
|
Unauthorized commercial use, SaaS hosting, or removal of branding is prohibited.
|
|
For commercial licensing inquiries: https://github.com/AIIrondev
|
|
-->
|
|
{% extends "base.html" %}
|
|
|
|
{% block title %}Tutorial - {{ APP_VERSION }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<style>
|
|
.tutorial-shell {
|
|
max-width: 1120px;
|
|
margin: 0 auto;
|
|
padding: 24px 0 14px;
|
|
}
|
|
|
|
.tutorial-shell,
|
|
.tutorial-shell p,
|
|
.tutorial-shell li,
|
|
.tutorial-shell button,
|
|
.tutorial-shell a {
|
|
font-size: 1.03rem;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.tutorial-hero {
|
|
background: linear-gradient(135deg, #16324f 0%, #27455f 55%, #3c5a73 100%);
|
|
color: #f8fafc;
|
|
border-radius: 18px;
|
|
padding: 30px;
|
|
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.18);
|
|
margin-bottom: 18px;
|
|
}
|
|
|
|
.tutorial-hero h1 {
|
|
margin: 0 0 8px;
|
|
font-size: clamp(1.8rem, 3vw, 2.35rem);
|
|
font-weight: 900;
|
|
}
|
|
|
|
.tutorial-hero p {
|
|
margin: 0;
|
|
opacity: 0.98;
|
|
font-size: 1.08rem;
|
|
}
|
|
|
|
.tutorial-meta {
|
|
display: flex;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
margin-top: 14px;
|
|
}
|
|
|
|
.tutorial-pill {
|
|
background: rgba(255, 255, 255, 0.12);
|
|
border: 1px solid rgba(255, 255, 255, 0.22);
|
|
border-radius: 999px;
|
|
padding: 6px 14px;
|
|
font-size: 0.88rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.tutorial-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
gap: 14px;
|
|
}
|
|
|
|
.tutorial-side {
|
|
grid-column: span 12;
|
|
background: var(--ui-surface);
|
|
border: 1px solid #cfdbe8;
|
|
border-radius: 16px;
|
|
padding: 16px;
|
|
position: sticky;
|
|
top: 14px;
|
|
height: fit-content;
|
|
}
|
|
|
|
.tutorial-side h2 {
|
|
margin: 0 0 8px;
|
|
font-size: 1.08rem;
|
|
color: #0f172a;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.tutorial-side p {
|
|
margin: 0 0 14px;
|
|
color: #334155;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.workflow-nav {
|
|
display: grid;
|
|
gap: 7px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.workflow-nav button {
|
|
border: 1px solid #dbe3ee;
|
|
background: var(--ui-surface-soft);
|
|
color: #0f172a;
|
|
border-radius: 12px;
|
|
padding: 11px 12px;
|
|
text-align: left;
|
|
font-weight: 700;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
transition: all 180ms ease;
|
|
}
|
|
|
|
.workflow-nav button:hover {
|
|
background: #eff6ff;
|
|
border-color: #bfdbfe;
|
|
transform: translateX(2px);
|
|
}
|
|
|
|
.workflow-nav button.active {
|
|
background: #dbeafe;
|
|
border-color: #93c5fd;
|
|
color: #1d4ed8;
|
|
}
|
|
|
|
.workflow-main {
|
|
grid-column: span 12;
|
|
display: grid;
|
|
gap: 12px;
|
|
}
|
|
|
|
.workflow-step {
|
|
grid-column: span 12;
|
|
background: var(--ui-surface);
|
|
border: 1px solid #cfdbe8;
|
|
border-radius: 16px;
|
|
padding: 18px;
|
|
opacity: 0;
|
|
transform: translateY(8px) scale(0.995);
|
|
pointer-events: none;
|
|
max-height: 0;
|
|
overflow: hidden;
|
|
transition: opacity 220ms ease, transform 220ms ease;
|
|
}
|
|
|
|
.workflow-step.active {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
pointer-events: auto;
|
|
max-height: 1300px;
|
|
}
|
|
|
|
.workflow-step h3 {
|
|
margin: 0 0 8px;
|
|
font-size: 1.35rem;
|
|
color: #0f172a;
|
|
}
|
|
|
|
.workflow-step p {
|
|
margin: 0 0 10px;
|
|
color: #334155;
|
|
font-size: 1.03rem;
|
|
}
|
|
|
|
.workflow-step ul {
|
|
margin: 0;
|
|
padding-left: 18px;
|
|
color: #334155;
|
|
font-size: 1.02rem;
|
|
}
|
|
|
|
.workflow-step li {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.tutorial-actions {
|
|
margin-top: 12px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.tutorial-actions .btn,
|
|
.workflow-controls .btn {
|
|
border-radius: 12px;
|
|
padding: 10px 14px;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.tutorial-tooltip-toggle {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin-top: 20px;
|
|
padding: 16px;
|
|
border-radius: 18px;
|
|
background: rgba(224, 242, 254, 0.9);
|
|
border: 1px solid #bae6fd;
|
|
}
|
|
|
|
.tutorial-tooltip-toggle label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
font-weight: 700;
|
|
color: #0f172a;
|
|
}
|
|
|
|
.tutorial-tooltip-toggle input[type="checkbox"] {
|
|
width: 20px;
|
|
height: 20px;
|
|
accent-color: #2563eb;
|
|
}
|
|
|
|
.tooltip-description {
|
|
margin: 0;
|
|
color: #475569;
|
|
font-size: 0.95rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.workflow-controls {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 14px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.workflow-controls .btn {
|
|
min-width: 120px;
|
|
}
|
|
|
|
.tutorial-note {
|
|
margin-top: 14px;
|
|
background: #ecfeff;
|
|
border: 1px solid #bae6fd;
|
|
color: #0c4a6e;
|
|
border-radius: 14px;
|
|
padding: 14px;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
@media (min-width: 960px) {
|
|
.tutorial-side {
|
|
grid-column: span 4;
|
|
}
|
|
|
|
.workflow-main {
|
|
grid-column: span 8;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="tutorial-shell">
|
|
<section class="tutorial-hero">
|
|
<h1>Kurzer Rundgang in 2-5 Minuten</h1>
|
|
<p>Die Seite ist bewusst einfach gehalten. Sie begleitet Sie Schritt für Schritt, ohne viel Lesen und ohne komplizierte Fachbegriffe.</p>
|
|
<div class="tutorial-meta">
|
|
<span class="tutorial-pill">Dauer: ca. 4 Minuten</span>
|
|
<span class="tutorial-pill">Format: Ruhig und geführt</span>
|
|
<span class="tutorial-pill">Benutzer: {{ username }}</span>
|
|
</div>
|
|
<div class="tutorial-tooltip-toggle">
|
|
<label for="toggleTutorialTooltips">
|
|
<input type="checkbox" id="toggleTutorialTooltips" />
|
|
Tutorial-Tooltips für das gesamte System aktivieren
|
|
</label>
|
|
<p class="tooltip-description">Wenn aktiviert, erscheinen auf allen Seiten erklärende Hinweise und Icons für die wichtigsten Navigationselemente.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="tutorial-grid">
|
|
<aside class="tutorial-side">
|
|
<h2>Schritte</h2>
|
|
<p>Folgen Sie einfach jedem Schritt. Sie können jederzeit vor- oder zurückgehen.</p>
|
|
|
|
<div class="workflow-nav" id="workflowNav">
|
|
<button type="button" data-target-step="0">1. Startseite</button>
|
|
<button type="button" data-target-step="1">2. {{ 'Artikel erfassen' if is_admin else 'Artikel finden' }}</button>
|
|
{% if library_module_enabled %}
|
|
<button type="button" data-target-step="2">3. Bibliotek</button>
|
|
{% endif %}
|
|
<button type="button" data-target-step="{{ '3' if library_module_enabled else '2' }}">4. Alltag</button>
|
|
</div>
|
|
|
|
<div class="workflow-controls">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="prevStepBtn">Zurück</button>
|
|
<button type="button" class="btn btn-primary btn-sm" id="nextStepBtn">Nächster Schritt</button>
|
|
</div>
|
|
</aside>
|
|
|
|
<section class="workflow-main" id="workflowMain">
|
|
|
|
<article class="workflow-step" data-step-index="0" data-step-key="dashboard">
|
|
<h3>Startbereich</h3>
|
|
<p>Hier starten Sie. Das ist der sichere Ausgangspunkt für alle weiteren Schritte.</p>
|
|
<ul>
|
|
<li>Sie sehen den Überblick.</li>
|
|
<li>Oben liegen die wichtigsten Wege.</li>
|
|
<li>Alles ist gross und einfach lesbar.</li>
|
|
</ul>
|
|
|
|
<div class="tutorial-actions">
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('home') }}">Startseite öffnen</a>
|
|
</div>
|
|
</article>
|
|
|
|
<article class="workflow-step" data-step-index="1" data-step-key="items">
|
|
{% if is_admin %}
|
|
<h3>Artikel anlegen</h3>
|
|
<p>Hier legen Sie einen neuen Artikel an. Es sind nur wenige Felder erforderlich.</p>
|
|
<ul>
|
|
<li><strong>Name:</strong> Wie heisst der Artikel?</li>
|
|
<li><strong>Ort:</strong> Wo soll er gelagert werden?</li>
|
|
<li><strong>Beschreibung:</strong> Was ist daran interessant?</li>
|
|
<li><strong>Code:</strong> Eine Nummer zum schnellen Finden.</li>
|
|
</ul>
|
|
|
|
<div class="tutorial-actions">
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('upload_admin') }}">Neuen Artikel anlegen</a>
|
|
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('home_admin') }}">Zurück</a>
|
|
</div>
|
|
{% else %}
|
|
<h3>Artikel finden und ausleihen</h3>
|
|
<p>Als Nutzerin/Nutzer arbeiten Sie hauptsaechlich mit vorhandenen Artikeln und Ausleihen.</p>
|
|
<ul>
|
|
<li>Nutzen Sie Filter und Suche, um Material schnell zu finden.</li>
|
|
<li>Öffnen Sie <strong>Details</strong>, um Ort, Beschreibung und Verfügbarkeit zu sehen.</li>
|
|
<li>Mit <strong>Ausleihen</strong> buchen Sie den Artikel direkt.</li>
|
|
<li>In <strong>Meine Ausleihen</strong> sehen Sie, was aktuell auf Ihren Namen laeuft.</li>
|
|
</ul>
|
|
|
|
<div class="tutorial-actions">
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('home') }}">Zur Startseite</a>
|
|
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('my_borrowed_items') }}">Meine Ausleihen</a>
|
|
</div>
|
|
{% endif %}
|
|
</article>
|
|
|
|
{% if library_module_enabled %}
|
|
<article class="workflow-step" data-step-index="2" data-step-key="library">
|
|
<h3>Bibliotek-Bereich</h3>
|
|
<p>Dieser Bereich ist speziell für Bücher und Medienausleihe.</p>
|
|
<ul>
|
|
{% if is_admin %}
|
|
<li><strong>Bücher hochladen:</strong> Neue Bücher in die Sammlung aufnehmen.</li>
|
|
<li><strong>Ausleihen ansehen:</strong> Wer hat welches Buch ausgeliehen?</li>
|
|
<li><strong>Defekte bearbeiten:</strong> Defekte Bücher markieren oder reparieren.</li>
|
|
<li><strong>Rechnungen:</strong> Kosten und Rechnungen verwalten.</li>
|
|
{% else %}
|
|
<li><strong>Medium suchen:</strong> Titel, Autor oder Barcode direkt finden.</li>
|
|
<li><strong>Verfuegbarkeit pruefen:</strong> Schnell sehen, was aktuell ausleihbar ist.</li>
|
|
<li><strong>Ausleihen:</strong> In der Bibliothek direkt auf Ihren Namen buchen.</li>
|
|
<li><strong>Rückgabe-Status:</strong> Über "Meine Ausleihen" Fristen im Blick behalten.</li>
|
|
{% endif %}
|
|
</ul>
|
|
|
|
<div class="tutorial-actions">
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('library_view') }}">Zur Bibliotek</a>
|
|
{% if is_admin %}
|
|
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('library_loans_admin') }}">Ausleihen ansehen</a>
|
|
{% endif %}
|
|
</div>
|
|
</article>
|
|
{% endif %}
|
|
|
|
<article class="workflow-step" data-step-index="{{ '3' if library_module_enabled else '2' }}" data-step-key="daily">
|
|
<h3>Tägliche Aufgaben</h3>
|
|
<p>Das ist der gewöhnliche Arbeitsablauf während eines Schultages.</p>
|
|
|
|
<div style="background: var(--ui-surface-soft); border: 1px solid #dbe3ee; border-radius: 12px; padding: 14px; margin: 14px 0;">
|
|
<p style="margin-bottom: 10px; font-weight: 700; color: #0f172a;">Morgens:</p>
|
|
<p style="margin: 0; color: #334155;">Öffnen Sie die Startseite und prüfen Sie offene Reservierungen oder Rückgabefristen.</p>
|
|
</div>
|
|
|
|
<div style="background: var(--ui-surface-soft); border: 1px solid #dbe3ee; border-radius: 12px; padding: 14px; margin: 14px 0;">
|
|
<p style="margin-bottom: 10px; font-weight: 700; color: #0f172a;">Mittags:</p>
|
|
<p style="margin: 0; color: #334155;">Neue Artikel oder Bücher hinzufügen oder Ausleihungen begründen.</p>
|
|
</div>
|
|
|
|
<div style="background: var(--ui-surface-soft); border: 1px solid #dbe3ee; border-radius: 12px; padding: 14px; margin: 14px 0;">
|
|
<p style="margin-bottom: 10px; font-weight: 700; color: #0f172a;">Nachmittags:</p>
|
|
<p style="margin: 0; color: #334155;">Rückgaben buchen und kurz prüfen, ob alles in Ordnung ist.</p>
|
|
</div>
|
|
|
|
<div class="tutorial-actions">
|
|
{% if is_admin %}
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('admin_borrowings') }}">Admin-Bereich</a>
|
|
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('logs') }}">Protokolle</a>
|
|
{% else %}
|
|
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('my_borrowed_items') }}">Meine Ausleihen</a>
|
|
{% endif %}
|
|
</div>
|
|
</article>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="tutorial-note">
|
|
Tipp: Sie können das Training jederzeit wieder öffnen und in Ruhe weiterklicken.
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const stepEls = Array.from(document.querySelectorAll('.workflow-step'));
|
|
const navBtns = Array.from(document.querySelectorAll('#workflowNav button[data-target-step]'));
|
|
const nextBtn = document.getElementById('nextStepBtn');
|
|
const prevBtn = document.getElementById('prevStepBtn');
|
|
const tutorialStateKey = 'inventarsystem_tutorial_state_v3_{{ username }}';
|
|
|
|
if (!stepEls.length) return;
|
|
|
|
let currentStep = 0;
|
|
let prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
function loadState() {
|
|
try {
|
|
const raw = localStorage.getItem(tutorialStateKey);
|
|
if (!raw) return;
|
|
const parsed = JSON.parse(raw);
|
|
currentStep = Number.isInteger(parsed.currentStep) ? parsed.currentStep : 0;
|
|
} catch (e) {
|
|
currentStep = 0;
|
|
}
|
|
}
|
|
|
|
function saveState() {
|
|
localStorage.setItem(tutorialStateKey, JSON.stringify({
|
|
currentStep: currentStep
|
|
}));
|
|
}
|
|
|
|
function clampStep() {
|
|
if (currentStep < 0) currentStep = 0;
|
|
if (currentStep >= stepEls.length) currentStep = stepEls.length - 1;
|
|
}
|
|
|
|
function renderStep() {
|
|
clampStep();
|
|
|
|
stepEls.forEach(function (stepEl, idx) {
|
|
stepEl.classList.toggle('active', idx === currentStep);
|
|
if (idx === currentStep && !prefersReducedMotion) {
|
|
stepEl.animate(
|
|
[{ opacity: 0, transform: 'translateY(10px)' }, { opacity: 1, transform: 'translateY(0)' }],
|
|
{ duration: 260, easing: 'ease-out' }
|
|
);
|
|
}
|
|
});
|
|
|
|
navBtns.forEach(function (btn) {
|
|
const target = Number(btn.dataset.targetStep);
|
|
btn.classList.toggle('active', target === currentStep);
|
|
});
|
|
|
|
prevBtn.disabled = currentStep <= 0;
|
|
nextBtn.textContent = currentStep >= stepEls.length - 1 ? 'Fertig' : 'Nächster Schritt';
|
|
saveState();
|
|
}
|
|
|
|
navBtns.forEach(function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
currentStep = Number(btn.dataset.targetStep) || 0;
|
|
renderStep();
|
|
});
|
|
});
|
|
|
|
prevBtn.addEventListener('click', function () {
|
|
currentStep -= 1;
|
|
renderStep();
|
|
});
|
|
|
|
nextBtn.addEventListener('click', function () {
|
|
currentStep += 1;
|
|
renderStep();
|
|
});
|
|
|
|
const tooltipToggle = document.getElementById('toggleTutorialTooltips');
|
|
const tooltipModeKey = 'inventarsystem_tutorial_tooltips_enabled_{{ username }}';
|
|
|
|
function setTooltipMode(enabled) {
|
|
localStorage.setItem(tooltipModeKey, enabled ? '1' : '0');
|
|
document.body.classList.toggle('tutorial-tooltips-active', enabled);
|
|
}
|
|
|
|
function loadTooltipMode() {
|
|
const saved = localStorage.getItem(tooltipModeKey);
|
|
const enabled = saved === '1';
|
|
if (tooltipToggle) {
|
|
tooltipToggle.checked = enabled;
|
|
}
|
|
setTooltipMode(enabled);
|
|
}
|
|
|
|
if (tooltipToggle) {
|
|
tooltipToggle.addEventListener('change', function () {
|
|
setTooltipMode(this.checked);
|
|
});
|
|
}
|
|
|
|
loadState();
|
|
renderStep();
|
|
loadTooltipMode();
|
|
})();
|
|
</script>
|
|
{% endblock %}
|