Files
posts/uebersicht.html
T
dejanandClaude Opus 5 4d227a01c9 Post 7: Form Builder, mit dem Bewegtbild als Titelelement
Anders als die Beitraege davor: das Bewegtbild ist das ERSTE Element im
Carousel und kein Anhang am Ende. Ein Form Builder ist ein Werkzeug, das
man bedient -- was er kann, sieht man am Bauen und nicht an einem
Standbild davon. Die drei Slides erklaeren danach, was das Gebaute
leistet, und tragen deshalb alle Ueberschrift und Fliesstext.

  animForm   Das Formular baust du selbst.       6 s, der Editor beim Bauen
  1          Frag genau das, was du wissen musst. die fuenf Fragen mit ihren Typen
  2          Fragen, die nur kommen, wenn sie
             noetig sind.                         das bedingte Feld
  3          Aus der Antwort wird ein Lead.       das Hinweisfeld mit Pipeline

Zwei Folgen davon, die man wissen muss: die Kachel im Profilraster ist
jetzt das erste Bild der Animation und nicht mehr eine eigens dafuer
gebaute Slide -- Bild 0 zeigt deshalb schon ein Formular mit zwei Fragen
und keine leere Flaeche. Und die Ueberschrift des Bewegtbilds ist die
Ueberschrift des Beitrags.

QUELLE
S02EinfacherFragenEditor.tsx aus dem Pitch-Paket, derselbe Bildschirm wie
assets/screens/form-builder.png. Die fuenf Fragen, ihre Feldtypen, die
Marke "Bedingt sichtbar" und der Satz im Hinweisfeld stehen woertlich
dort. Die Farben des Hinweisfelds sind ueber die Token-Kette aufgeloest
(surface-feedback-subtle-information -> feedback-information-100 ->
ocean-100 = #E1F4FD), nicht aus dem Bild geschaetzt. Elf zusaetzliche
Zeichen aus demselben Phosphor-bold-Satz.

ABWEICHUNGEN, ALLE DOKUMENTIERT
Die Quelle schreibt {general ? "Website-Anfragen" : "Vertrieb SHK"} --
hier steht Vertrieb SHK, weil der Beitrag durchgehend das Gewerk zeigt.
"Sanitaer" und "Klima / Lueftung" stehen mit Umlaut. "Deaktivieren" ist
weg, weil ein Ausschalter nichts zur Aussage beitraegt und dem
Pipeline-Satz den Platz nahm.

DREI SACHEN, DIE ERST AM GERENDERTEN BLATT AUFFIELEN
Die Karte wuchs und schrumpfte zugleich: der Kasten wurde mit dem Inhalt
hoeher, und bei fester Breite skaliert die Zeichnung dabei kleiner. Die
Animation hat jetzt eine feste Kastenhoehe.

Der Pipeline-Satz lief unter den Knopf und endete bei "Vertrieb S".
Jetzt zweizeilig statt gekuerzt -- der Pipelinename ist die halbe
Aussage des Felds.

Eine Ueberschrift mass 936 px und lief 45 px ueber die Schutzzone. Am
gerenderten Bild nachgemessen, nicht geschaetzt; die kuerzere Fassung
liegt bei 846.

Erreichbar ueber die Toolbar in allen Projekten und in uebersicht.html.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U7RZ6ZpLD8Dp84Rtt4KHfv
2026-09-01 19:46:34 +02:00

239 lines
10 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PostGrid · Alle Projekte</title>
<link rel="stylesheet" href="./assets/fonts/manrope.css">
<style>
/* ─── Projektübersicht ────────────────────────────────────────────────────
Alle Streifen untereinander auf einer Fläche. Die Seite baut die Slides
nicht selbst: jedes Projekt kommt als iframe im Modus ?nur=streifen, in
dem die Post-Seite ihre Bedienoberfläche ausblendet und nur den Streifen
in natürlicher Größe zeigt. Skaliert wird hier außen.
Warum nicht nachbauen: die Streifen müssen genau das zeigen, was der
Generator zeigt — bis auf den letzten gespeicherten Versatz. Jede zweite
Implementierung würde irgendwann abweichen, und dann wäre die Übersicht
schlimmer als keine. */
* { box-sizing: border-box; }
:root { color-scheme: dark; }
html, body { height: 100%; }
body {
margin: 0; font-family: Manrope, system-ui, sans-serif;
background: #101116; color: #C7CCD6; overflow: hidden;
}
.menubar {
position: relative; z-index: 10; display: flex; align-items: center; gap: 2px;
height: 34px; padding: 0 10px; background: #16181F;
border-bottom: 1px solid #23262F;
font-size: 13px; user-select: none;
}
.menubar .marke { font-weight: 800; color: #FFFFFF; margin-right: 14px; letter-spacing: -.01em; }
.menu { position: relative; }
.menu > button {
font: inherit; color: #C7CCD6; background: none; border: 0;
padding: 5px 10px; border-radius: 6px; cursor: pointer;
}
.menu > button:hover, .menu[data-auf] > button { background: #23262F; color: #FFFFFF; }
.menu .liste {
display: none; position: absolute; left: 0; top: 100%; min-width: 250px;
padding: 5px; background: #1B1E26; border: 1px solid #2E313B;
border-radius: 9px; flex-direction: column;
}
.menu[data-auf] .liste { display: flex; }
.menu .liste button {
font: inherit; text-align: left; color: #C7CCD6; background: none;
border: 0; padding: 7px 10px; border-radius: 6px; cursor: pointer;
}
.menu .liste button:hover { background: #262A34; color: #FFFFFF; }
.menu .liste hr { border: 0; border-top: 1px solid #2E313B; margin: 5px 2px; }
/* Derselbe gepunktete Grund wie im Generator, aber ohne dessen Canvas:
hier wird nur gescrollt. */
.stage { position: absolute; inset: 34px 0 0; overflow: hidden;
background-color: #101116;
background-image: radial-gradient(circle, #282B35 1.6px, transparent 1.6px);
background-size: 26px 26px;
}
/* Nur hoch und runter. Die Streifen sind auf die Breite eingepasst,
also gibt es waagerecht nichts zu holen. */
.scroller { position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden;
overscroll-behavior: contain; }
.flaeche {
width: max-content; min-width: 100%; height: max-content; min-height: 100%;
padding: 54px; display: flex; flex-direction: column; gap: 46px;
align-items: flex-start;
}
.reihe { display: flex; flex-direction: column; gap: 10px; }
.reihe h2 {
margin: 0; font-size: 12px; font-weight: 800; letter-spacing: .14em;
text-transform: uppercase; color: #6E7480;
}
.reihe h2 b { color: #C7CCD6; font-weight: 800; }
/* Der Rahmen bekommt die Größe des skalierten Streifens, das iframe darin
bleibt in Originalgröße und wird nur transformiert. Ohne den Rahmen
würde das ungeskalierte iframe die Fläche aufblähen. */
.rahmen { overflow: hidden; background: #FFFFFF; border: 1px solid #2E313B; }
/* pointer-events: none -- sonst zoomt das Mausrad im Streifen die
Post-Seite darin, die ja ihren eigenen Canvas mitbringt. Die Uebersicht
ist zum Ansehen da, bedient wird im Projekt selbst. */
.rahmen iframe {
display: block; border: 0; transform-origin: 0 0; background: #FFFFFF;
pointer-events: none;
}
.reihe.fehlt .rahmen { display: grid; place-items: center; width: 420px; height: 90px;
background: #16181F; color: #6E7480; font-size: 13px; }
.hud {
position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
display: flex; align-items: center; gap: 12px;
padding: 8px 12px; background: rgba(16,17,22,.92);
border-top: 1px solid #23262F;
}
.hud p { margin: 0; font-size: 12px; color: #6E7480; letter-spacing: .04em; }
</style>
</head>
<body>
<div class="menubar">
<span class="marke">PostGrid</span>
<div class="menu" data-menu="projekt">
<button type="button">Projekt</button>
<div class="liste">
<button type="button" data-gehe="./post1.html">Post 1 · Lösung</button>
<button type="button" data-gehe="./post2.html">Post 2 · Die Geschichte</button>
<button type="button" data-gehe="./post2-alt.html">Post 2 · Alternative</button>
<button type="button" data-gehe="./post3.html">Post 3 · Verbinden statt ersetzen</button>
<button type="button" data-gehe="./post4.html">Post 4 · Workflow-Engine</button>
<button type="button" data-gehe="./post5.html">Post 5 · Projektmanagement</button>
<button type="button" data-gehe="./post6.html">Post 6 · Team-Chat</button>
<button type="button" data-gehe="./post7.html">Post 7 · Form Builder</button>
<hr>
<button type="button" data-klick="neu">Streifen neu laden</button>
</div>
</div>
</div>
<main class="stage">
<div class="scroller" id="scroller">
<div class="flaeche" id="flaeche"></div>
</div>
<div class="hud">
<p id="meta">Lade Streifen ...</p>
</div>
</main>
<script>
(() => {
"use strict";
const PROJEKTE = [
{ datei: "./post1.html", name: "Post 1 · Lösung" },
{ datei: "./post2.html", name: "Post 2 · Die Geschichte", theme: "notebook" },
{ datei: "./post2-alt.html", name: "Post 2 · Alternative", theme: "modern" },
{ datei: "./post3.html", name: "Post 3 · Verbinden statt ersetzen", theme: "modern" },
{ datei: "./post4.html", name: "Post 4 · Workflow-Engine", theme: "modern" },
{ datei: "./post5.html", name: "Post 5 · Projektmanagement", theme: "modern" },
{ datei: "./post6.html", name: "Post 6 · Team-Chat", theme: "modern" },
{ datei: "./post7.html", name: "Post 7 · Form Builder", theme: "modern" },
];
const flaeche = document.getElementById("flaeche");
const scroller = document.getElementById("scroller");
const meta = document.getElementById("meta");
/* Kein Zoom. Ein Streifen ist bis zu 6480 px breit und wird immer auf die
Fensterbreite eingepasst; gescrollt wird nur hoch und runter. Ein
Zwischenstand hatte Rad-Zoom und Zoomknöpfe -- das war doppelt gemoppelt,
weil die Post-Seite im iframe ihren eigenen Canvas mitbringt, und die
Beschriftungen skalierten nicht mit, standen beim Herauszoomen also
riesig über winzigen Streifen. */
const reihen = [];
function bauen() {
flaeche.innerHTML = "";
reihen.length = 0;
PROJEKTE.forEach(pr => {
const reihe = document.createElement("div");
reihe.className = "reihe";
const h2 = document.createElement("h2");
h2.innerHTML = "<b>" + pr.name + "</b>" + (pr.theme ? " · Theme " + pr.theme : "");
const rahmen = document.createElement("div");
rahmen.className = "rahmen";
const ram = document.createElement("iframe");
ram.src = pr.datei + "?nur=streifen";
ram.loading = "eager";
rahmen.appendChild(ram);
reihe.appendChild(h2); reihe.appendChild(rahmen);
flaeche.appendChild(reihe);
reihen.push({ pr, reihe, rahmen, ram, w: 6480, h: 1350, da: false });
});
}
/* Jede Post-Seite meldet ihre Streifenbreite, sobald sie steht. Die Zahl
der Slides ist je Projekt anders und kann sich ändern, deshalb wird sie
nicht hier gepflegt. */
window.addEventListener("message", e => {
const d = e.data;
if (!d || d.hg !== "streifen") return;
const r = reihen.find(x => x.ram.contentWindow === e.source);
if (!r) return;
r.w = d.w; r.h = d.h; r.da = true;
legen();
});
// Eingepasst wird nur in die Breite, die Höhe ergibt sich und wird gescrollt.
const POLSTER = 54 * 2;
function passend() {
const breit = Math.max(...reihen.map(r => r.w), 1080);
return Math.min((scroller.clientWidth - POLSTER) / breit, 0.5);
}
function legen() {
const k = passend();
reihen.forEach(r => {
r.ram.style.width = r.w + "px";
r.ram.style.height = r.h + "px";
r.ram.style.transform = "scale(" + k + ")";
r.rahmen.style.width = Math.round(r.w * k) + "px";
r.rahmen.style.height = Math.round(r.h * k) + "px";
});
const offen = reihen.filter(r => r.da).length;
meta.textContent = offen < reihen.length
? "Lade Streifen ... " + offen + " von " + reihen.length
// Seit Post 3 gibt es Einzelbilder: "1 Slides" stand vorher da.
: reihen.length + " Projekte · " + reihen.map(r => {
const n = Math.round(r.w / 1080);
return n + (n === 1 ? " Slide" : " Slides");
}).join(" · ");
}
// Kein Ziehen, kein Rad-Zoom: die Seite scrollt wie eine gewoehnliche Seite.
window.addEventListener("resize", legen);
// ─── Menü ────────────────────────────────────────────────────────────────
document.querySelectorAll(".menu").forEach(m => {
m.querySelector("button").addEventListener("click", e => {
e.stopPropagation();
const auf = m.hasAttribute("data-auf");
document.querySelectorAll(".menu").forEach(x => x.removeAttribute("data-auf"));
if (!auf) m.setAttribute("data-auf", "");
});
});
document.addEventListener("click", e => {
const b = e.target.closest("button[data-gehe], button[data-klick]");
document.querySelectorAll(".menu").forEach(x => x.removeAttribute("data-auf"));
if (!b) return;
if (b.dataset.gehe) { location.href = b.dataset.gehe; return; }
if (b.dataset.klick === "neu") { bauen(); legen(); }
});
bauen();
legen();
})();
</script>
</body>
</html>