Nummer 3 im Redaktionsplan, erscheint Mi 19.08. Carousel, vier Slides, Theme modern, Variante hell. DER BEITRAG Ein Ablauf, die Bausteine, aus denen er entsteht, und der Hinweis, dass man nicht bei null anfaengt: 1 Automatisiere deinen Betrieb. ein Ablauf auf dem Canvas 2 Erst der Ausloeser. die Ausloeser-Auswahl 3 Dann die Aktionen. die Aktionen-Auswahl 4 Fang nicht bei null an. drei fertige Vorlagen Slide 2 und 3 teilen sich eine Funktion mit zwei Rubriken, weil es im Produkt eine Auswahl ist: "Ausloeser" und "Aktionen" stehen dort untereinander im selben Feld. Getrennt gezeichnet waeren es zwei Bilder, die zufaellig gleich aussehen. Vier Slides statt der fuenf bis sieben aus dem Redaktionsplan. Das ist eine Spanne und kein Soll: eine Slide, die nichts hinzufuegt, kostet einen Wisch und gibt nichts zurueck. WAS AUS DEM PRODUKT KOMMT UND WAS NICHT Der Knoten ist NodeItem aus ui/components/NodeWorkflowEngine des Pitch-Pakets: quadratisch 128 x 128, rounded-lg, 6 px Rand, Titel und Beschreibung unter dem Feld, beim Ausloeser die linke Flanke voll gerundet. Genau so rendert es auch assets/screens/workflow.png. Ein Zwischenstand zeichnete stattdessen breite Karten mit farbiger Kante links und einem Block "BESCHREIBUNG" -- abgemalt vom Pitch-Bild 02_Praesentation/03. Im Code des Projekts gibt es das nirgends: weder "BESCHREIBUNG" als Label noch eine linke Farbkante, beides null Treffer. Der Kommentar behauptete trotzdem, es sei ein Nachbau der Komponente. Das ist berichtigt. Die Farben sind die des Produkts, aufgeloest aus ui/theme.css ueber die ganze Token-Kette und nicht aus dem Bild geschaetzt. Sie tragen Bedeutung: gruen faengt an, rot aendert Daten, blau meldet, amber macht eine Aufgabe daraus, violett entscheidet. Ein Zwischenstand hatte sie durch Markenfarben ersetzt, weil rules.md 2 diese Toene nicht kennt -- zurueckgenommen, der Beitrag zeigt die Oberflaeche, und umgefaerbt waere es eine Nacherzaehlung. Alle Produkttexte stehen woertlich in der Quelle. Wo ein Name nicht in eine Zeile passte, steht er zweizeilig: aus "Daten vereinheitlichen" ein "Pruefen" zu machen ist keine Kuerzung, sondern ein anderer Name. DREI STELLEN, AN DENEN BEWUSST ABGEWICHEN WIRD - Slide 1 gabelt nach dem zweiten Knoten. Alle drei echten Ablaeufe verzweigen erst an Position 3 oder 4, und das fuellt ein hochkantes Format schlecht -- solange der Stamm laeuft, steht ueber und unter ihm nichts. Dafuer fehlt zwischen "Formular eingegangen" und "Passender Lead?" der Schritt "Daten vereinheitlichen". Ein Ablauf, den es genau so gibt, ist es damit nicht mehr; einer, den es geben koennte, schon. - Slide 4 nennt die Demo-Ablaeufe "Vorlagen". Dass es eine Vorlagen-Bibliothek gibt, steht als Merkmal auf der Website; dass sie diese drei enthaelt, steht nirgends. Im Werkzeug werden sie ueber workflowId geladen, nicht als Galerie gezeigt, und das Wort "Vorlage" kommt in der Komponente nicht vor. - Kein PDS im Beitrag. Von den sechs Vorlagen nennen drei das Branchenprogramm. Uebrig bleibt genau die Gruppe GENERAL_WORKFLOW_PRESETS, in der es kein einziges Mal vorkommt -- also keine Auswahl nach Geschmack, sondern die vollstaendige zweite Gruppe. Gekuerzt wurde nichts. Erfundene Vorgaenge sind raus. Ein Zwischenstand hatte eine Slide mit einem Aktivitaetenverlauf samt Uhrzeiten. Nichts davon war gemessen, und bei einem Produkt vor dem Start ist eine erfundene Uhrzeit kein Beispiel, sondern ein Beleg, den es nicht gibt. DER PUNKTGRUND Die Arbeitsflaeche des Workflow-Editors, Werte aus WorkflowEditor.tsx der Website. Zwei begruendete Abweichungen: die Teilung ist verdoppelt, weil ein 24er Raster im Feed auf 9 px zusammenfaellt und zu grauem Schleier wird, und der Grund bleibt weiss statt getoent, weil rules.md 1a das verbietet. EIN FEHLER, DER FAST DURCHGERUTSCHT WAERE Beim Entfernen der Karten-Regeln von Post 2 blieben rund neunzig Zeilen Deklarationen ohne Selektor stehen, dazu ein Kommentar ohne Ende: nur die Selektorzeilen waren weggeschnitten. CSS faengt sich davon nicht wieder, der Parser ueberspringt bis zur naechsten Marke -- und dabei verschwand die Regel [data-edit] darunter. Damit war das Verschieben von Elementen im Canvas tot, ohne dass die Seite einen Fehler zeigte. Sichtbar wurde es erst, als ein gespeicherter Versatz von 3 px nicht mehr ankam. Behoben, und an der Stelle steht jetzt eine Warnung: Regeln als ganzen Block entfernen und danach nachsehen, ob document.styleSheets sie noch alle kennt. NEBENBEI - Die Ueberschriften stehen auf denselben Werten wie post3.html, bis auf den Pixel nachgemessen: 76 px, -0,032em, nowrap und der Versatz dy 3, den auch post2, post2-alt und post3 auf jeder Slide tragen. - Die Projektliste steht sechsmal im Repo, einmal je Post-Seite plus uebersicht.html. Post 4 ist ueberall eingetragen. Wer einen siebten Beitrag anlegt, muss an alle sechs Stellen denken. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
233 lines
9.5 KiB
HTML
233 lines
9.5 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>
|
|
<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" },
|
|
];
|
|
|
|
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>
|