Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions CLAUDE.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

| | Feature | Beschreibung |
|---|---|---|
| 🗺️ | **Onboarding-Rundgang** | Elf Schritte durch alle Bausteine – der Rundgang wechselt selbst in die passende Ansicht und hebt hervor, worum es gerade geht. Wird **angeboten statt aufgedrängt** – kein Auto-Start, sondern zwei dauerhafte Einstiege (Hero und Seitenleiste); Schritte, die Daten brauchen, bieten den Beispielimport an, statt ihn heimlich auszuführen |
| 🗺️ | **Geführter Rundgang** | **Sieben Kapitel, 29 Schritte** durch alles, was das Werkzeug kann – von der Startseite über Kompass, Governance, Inventar, Risiko und Textbereinigung bis zu Wissen, Vorlagen und dem Sichern des Arbeitsstands. Der Rundgang wechselt selbst in die passende Ansicht und den passenden Tab, hebt hervor, worum es geht, und stellt seine Erklärung **direkt daneben** statt darüber. Kapitel lassen sich direkt anspringen. Wird **angeboten statt aufgedrängt** – kein Auto-Start, sondern zwei dauerhafte Einstiege (Hero und Seitenleiste); ohne eigene Daten bietet er das Beispiel an, statt es heimlich zu laden |
| 📈 | **Kompass-Verlauf** | Reifegrad-Stände auf Knopfdruck festhalten und die Entwicklung als Balken samt Trend sehen – belegbarer Fortschritt gegenüber Leitung oder Gremium. Bewusst **kein automatischer Mitschnitt**: festgehalten wird, was man festhalten will |
| 🧭 | **Daten-Kompass** | Open-Data-Reifegrad-Checkliste nach anerkannten Modellen (ODRA, EU Open Data Maturity, 5-Sterne-Open-Data, DCAT-AP.de, DSGVO/FAIR, Data Orchard Data Maturity): **8 Dimensionen mit 33 Prüfpunkten**, Score + Ampel, Vorbelegung aus dem aktuellen Stand, adaptive Empfehlungen der nächsten Bausteine und PDF-Export – der Haupteinstieg |
| ⚖️ | **Rechtspflicht der Organisation** | Eine einzige, **optionale** Angabe: Unterliegt Ihre Organisation einem Informationsfreiheits- oder Open-Data-Gesetz? Wer *nein* wählt (Verein, Stiftung, gGmbH), bekommt den Prüfpunkt zu den Rechtsgrundlagen als *nicht relevant* vorbelegt – er zählt dann nicht in den Reifegrad –, keine Vorschläge zu hochwertigen Datensätzen, weil die EU-Verordnung dazu öffentliche Stellen bindet, und einen Fehler bei der Lizenz „Amtliches Werk nach § 5 UrhG", deren Lizenzfreiheit an der amtlichen Herkunft hängt und nicht an einer Entscheidung des Herausgebers. Bewusst **nicht** die Frage „Behörde oder NGO": dazwischen liegen Stadtwerke, Hochschulen und Belehnte, die ein Zwei-Wege-Schalter falsch einsortiert. Alles Übrige gilt unverändert |
Expand Down Expand Up @@ -116,7 +116,7 @@ Die App selbst bleibt abhängigkeitsfrei; für die Tests wird einmalig Playwrigh
```bash
npm install # nur Dev: @playwright/test
npx playwright install chromium
npm test # 380 Tests, ~150 s
npm test # 386 Tests, ~180 s
npm run test:ui # interaktiver Modus
```

Expand Down Expand Up @@ -309,7 +309,7 @@ datenlotse/
│ ├── sample-landesbehoerde.csv # Beispiel: fiktive Landesebene (12 Datensätze)
│ ├── sample-verein.csv # Beispiel: fiktiver gemeinnütziger Träger (12 Datensätze)
│ └── template.csv # Leere Vorlage zum eigenen Befüllen
├── tests/ # Playwright-End-to-End-Tests (380 Tests in 14 Dateien)
├── tests/ # Playwright-End-to-End-Tests (386 Tests in 14 Dateien)
│ ├── helpers.js # openApp/loadSample/Download-Helfer
│ ├── smoke.spec.js # Views, Routing, Dashboard, HTML-Validität, Anrede
│ ├── import.spec.js # CSV-Parser, Ableitung, Formel-Injection
Expand All @@ -322,7 +322,7 @@ datenlotse/
│ ├── export.spec.js # DCAT-URIs, Downloads, Persistenz
│ ├── a11y.spec.js # Fokus, ARIA, Kontrast, Responsive
│ ├── hvd.spec.js # hochwertige Datensätze (DVO (EU) 2023/138)
│ ├── tour.spec.js # Onboarding-Rundgang, Schritt-Ziele
│ ├── tour.spec.js # Rundgang: Kapitel, Platzierung, Abdunkeln, Schritt-Ziele
│ ├── seo.spec.js # statische Wissensseiten, Metadaten, Sitemap
│ └── assets.spec.js # Icon-Zuschnitt, Ladegewicht der Startseite
├── playwright.config.js # Testkonfiguration (startet den Webserver selbst)
Expand Down
2 changes: 1 addition & 1 deletion assets/fonts/fa/icons.min.css

Large diffs are not rendered by default.

Binary file modified assets/fonts/webfonts/fa-regular-400.subset.woff2
Binary file not shown.
Binary file modified assets/fonts/webfonts/fa-solid-900.subset.woff2
Binary file not shown.
97 changes: 71 additions & 26 deletions css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1514,53 +1514,98 @@ body.tour-on::before {
inset: 0;
/* über der hervorgehobenen Stelle: sonst zeichnet das Zielelement in die Karte */
z-index: 1202;
display: flex;
align-items: flex-end;
justify-content: center;
padding: 20px;
/* Der Layer blockiert die hervorgehobene Stelle nicht – nur die Karte fängt Klicks */
pointer-events: none;
}
/* Die Karte steht seit v70 NEBEN dem Ziel (`placeTourCard()` setzt top/left).
`mitte` für Schritte ohne Ziel, `dock` für schmale Bildschirme und für Ziele,
neben die sie nicht passt – dort unten angedockt wie bisher. */
.tour-card {
position: absolute;
pointer-events: auto;
width: min(560px, 100%);
width: 440px;
max-width: calc(100vw - 24px);
background: #fff;
border-radius: var(--radius);
box-shadow: var(--shadow-lg);
padding: 20px 22px;
border: 1px solid rgba(66, 0, 147, 0.14);
padding: 18px 20px 16px;
min-width: 0;
}
.tour-card[data-place="mitte"] {
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: min(540px, calc(100vw - 32px));
}
.tour-card[data-place="dock"] {
left: 50%; bottom: 16px;
transform: translateX(-50%);
width: min(560px, calc(100vw - 24px));
max-height: 62vh;
overflow-y: auto;
}
.tour-card[data-place="dock-oben"] {
left: 50%; top: 16px;
transform: translateX(-50%);
width: min(560px, calc(100vw - 24px));
max-height: 55vh;
overflow-y: auto;
}
.tour-card:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }
.tour-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tour-count { font-size: 11.5px; font-weight: 700; letter-spacing: 0.03em; color: var(--c-muted); text-transform: uppercase; }
.tour-title { margin: 8px 0 6px; font-size: 20px; color: var(--c-accent); }
.tour-head { display: flex; align-items: center; gap: 10px; }
.tour-kapitel {
font-size: 11.5px; font-weight: 700; letter-spacing: 0.03em;
color: var(--c-muted); text-transform: uppercase; min-width: 0; flex: 1;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tour-kapitel i { color: var(--c-accent); margin-right: 4px; }
.tour-progress { height: 4px; border-radius: 2px; background: rgba(66, 0, 147, 0.10); margin: 10px 0 2px; overflow: hidden; }
.tour-progress > span { display: block; height: 100%; background: var(--c-accent); border-radius: 2px; transition: width 0.2s var(--ease-fluid); }
.tour-title { margin: 10px 0 6px; font-size: 18px; line-height: 1.3; color: var(--c-accent); }
.tour-text { margin: 0; font-size: 14px; line-height: 1.6; color: var(--c-text); }
.tour-note {
margin: 12px 0 8px;
font-size: 12.5px;
line-height: 1.55;
color: var(--c-muted);
display: flex;
gap: 8px;
.tour-sample { margin-top: 12px; }
.tour-chapters {
list-style: none; margin: 14px 0 0; padding: 0;
display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr)); gap: 6px;
}
.tour-chapter {
width: 100%; text-align: left; font: inherit; font-size: 13px; font-weight: 600;
color: var(--c-text); background: #fff; cursor: pointer;
border: 1px solid rgba(66, 0, 147, 0.14); border-radius: 8px; padding: 7px 10px;
display: flex; align-items: center; gap: 8px;
}
.tour-sample { margin-bottom: 4px; }
.tour-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 16px; }
.tour-actions .btn:first-child { margin-right: auto; }
.tour-chapter i { color: var(--c-accent); width: 16px; text-align: center; }
.tour-chapter:hover { border-color: rgba(66, 0, 147, 0.4); background: rgba(66, 0, 147, 0.04); }
.tour-finale { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.tour-dots { display: flex; justify-content: center; align-items: center; gap: 6px; margin-right: auto; }
.tour-dot {
width: 10px; height: 10px; padding: 0; border-radius: 50%; cursor: pointer;
border: 1.5px solid var(--c-accent); background: #fff;
}
.tour-dot.is-active { background: var(--c-accent); }
.tour-dot:hover { background: rgba(66, 0, 147, 0.35); }
.tour-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.tour-count { font-size: 11.5px; color: var(--c-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Die hervorgehobene Stelle wird über den abdunkelnden Layer geholt. */
/* Die hervorgehobene Stelle wird über das Abdunkeln geholt. `position`
setzt `tour-pos` nur, wenn das Ziel statisch ist – ein sticky oder fixiertes
Ziel (Topbar) darf seine Positionierung nicht verlieren. */
.tour-highlight {
position: relative;
z-index: 1201;
z-index: 1201 !important;
outline: 3px solid var(--c-accent);
outline-offset: 4px;
border-radius: var(--radius);
box-shadow: 0 0 0 9999px rgba(30, 27, 46, 0.05);
}
.tour-pos { position: relative; }
.topbar.tour-highlight { outline-offset: -4px; }
/* Der äußerste Vorfahr mit eigenem Stapelkontext (Topbar, Seitenleiste) –
sonst bliebe das Ziel darin unter dem Abdunkeln. */
.tour-lift { z-index: 1201 !important; }
.tour-lift-pos { position: relative !important; }
@media (max-width: 600px) {
.tour-layer { padding: 12px; }
.tour-actions { justify-content: stretch; }
.tour-actions .btn { flex: 1 1 auto; }
.tour-actions .btn:first-child { margin-right: 0; }
.tour-actions .btn { flex: 1 1 auto; justify-content: center; }
.tour-dots { width: 100%; order: -1; margin: 0 0 4px; }
}
@media (prefers-reduced-motion: reduce) {
.tour-highlight { transition: none; }
Expand Down
2 changes: 1 addition & 1 deletion datenschutz/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
}
</script>
<link rel="stylesheet" href="/assets/fonts/inter/inter.css">
<link rel="stylesheet" href="/assets/fonts/fa/icons.min.css?v=69">
<link rel="stylesheet" href="/assets/fonts/fa/icons.min.css?v=70">
<link rel="stylesheet" href="/css/tokens.css">
<link rel="stylesheet" href="/css/styles.css">
</head>
Expand Down
12 changes: 6 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@
<link rel="stylesheet" href="assets/fonts/inter/inter.css">
<!-- Zugeschnitten auf die verwendeten Icons (tools/build-icons.py) – das
vollstaendige all.min.css bleibt als Quelle im Repo, wird aber nicht geladen. -->
<link rel="stylesheet" href="assets/fonts/fa/icons.min.css?v=69">
<link rel="stylesheet" href="assets/fonts/fa/icons.min.css?v=70">

<link rel="stylesheet" href="css/tokens.css?v=69">
<link rel="stylesheet" href="css/styles.css?v=69">
<link rel="stylesheet" href="css/tokens.css?v=70">
<link rel="stylesheet" href="css/styles.css?v=70">
</head>
<body>

Expand Down Expand Up @@ -325,7 +325,7 @@ <h2 class="module-title">Risiko &amp; Pseudonymisierung</h2>
der Stelle, an der sie die Module ohnehin überflogen haben. -->
<section class="graf-bridge home-only" id="graf-bridge" aria-labelledby="graf-bridge-title">
<div class="graf-bridge-panel">
<img src="datengraf-logo.svg" alt="DatenGraf" class="graf-bridge-icon" width="56" height="56" loading="lazy" decoding="async">
<img data-src="datengraf-logo.svg" alt="DatenGraf" class="graf-bridge-icon" width="56" height="56" decoding="async">
<div class="graf-bridge-body">
<h2 class="graf-bridge-title" id="graf-bridge-title">Schon mit DatenGraf kartiert?</h2>
<p class="graf-bridge-text">Dann brauchen Sie hier nicht von vorn anzufangen. DatenLotse liest <strong>genau das CSV-Schema</strong>, das DatenGraf exportiert: Aus jeder Kombination aus Quelle und Datentyp wird ein Datensatz-Kandidat nach DCAT-AP.de &ndash; samt Vorbelegung von Zugriffsrechten und Aktualisierungszyklus aus Ihrer Kartierung. Sie erg&auml;nzen nur noch, was DatenGraf nicht kennt: Lizenz, Schlagw&ouml;rter und die Adresse, unter der die Daten liegen.</p>
Expand Down Expand Up @@ -915,7 +915,7 @@ <h2 class="consult-card-headline">Umsetzung besprechen</h2>
Brands-Familie und h&auml;tte daf&uuml;r 116 KB Schrift nachgeladen. -->
<a href="https://github.com/daimpad/datenlotse" target="_blank" rel="noopener" title="GitHub Repository" aria-label="DatenLotse auf GitHub"><svg class="footer-github" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"/></svg></a>
</nav>
<span class="footer-version">v69</span>
<span class="footer-version">v70</span>
</footer>

<!-- ── FAQ-Modal ─────────────────────────────────────────────── -->
Expand Down Expand Up @@ -1131,7 +1131,7 @@ <h2 id="license-title"><i class="fas fa-id-card"></i> Lizenz-Wegweiser</h2>
</div>
</div>

<script src="js/app.js?v=69"></script>
<script src="js/app.js?v=70"></script>

<!-- Anonyme Seitenzählung (GoatCounter). Der EINZIGE externe Aufruf der
Seite: keine Cookies, kein LocalStorage, keine Kennung, kein
Expand Down
Loading
Loading