From 57d1f4c540396e080185929a36b2d2a9bced7b48 Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Fri, 7 Aug 2026 19:50:35 +0200 Subject: [PATCH] Nur noch das Raster als Grund, Menueleiste, Post 2 Der Grund ist fest das Raster. Raus sind die vier Formen-Bausteine, die grosse G-Marke, das Wabenraster samt seinem Kachel-Erzeuger, die Punkte und die Musterauswahl mit ihrer Taste. Ebenso das durchgehende Band: Sechsecke auf den Naehten, Band und G-Marke, CSS, Schalter und Taste. Beim Aufraeumen war zwischenzeitlich ".bg > * { display: none; }" mit verschwunden. Diese eine Zeile hatte das Band die ganze Zeit verdeckt, eine Einblende-Regel gab es dafuer naemlich nie. Ohne sie schwebten Sechsecke und G-Marke ueber den Slides. Die Projektauswahl ist eine Menueleiste ueber die volle Breite: Projekt, Datei, Bearbeiten, Slide, Ansicht. Sie fuehrt nichts selbst aus, sondern betaetigt die vorhandenen Schalter im Bedienfeld, damit jedes Verhalten an genau einer Stelle steht. Haken und graue Eintraege liest sie beim Oeffnen aus denselben Schaltern. post2.html ist eine Kopie von post1.html bis auf Titel, Ueberschrift und Projektschluessel. Co-Authored-By: Claude Opus 5 (1M context) --- post1.html | 421 +++--- post2.html | 3611 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3810 insertions(+), 222 deletions(-) create mode 100644 post2.html diff --git a/post1.html b/post1.html index 3a1b610..88cccdc 100644 --- a/post1.html +++ b/post1.html @@ -30,9 +30,53 @@ body { font-family: 'Manrope', system-ui, sans-serif; background: #17181F; color: #E8EAEE; - height: 100vh; overflow: hidden; display: flex; + height: 100vh; overflow: hidden; + display: flex; flex-direction: column; } + /* ─── Menueleiste ──────────────────────────────────────────────────────── + Statt einer Knopfreihe fuer die Projekte eine Leiste wie in einem + Bildprogramm. Sie bedient keine eigene Logik, sondern klickt die + vorhandenen Schalter im Bedienfeld an: sonst gaebe es zwei Wahrheiten + ueber denselben Zustand. */ + .menubar { + flex: none; display: flex; align-items: stretch; gap: 2px; + height: 34px; padding: 0 8px; + background: #14161C; border-bottom: 1px solid #24262F; + font-size: 13px; user-select: none; position: relative; z-index: 60; + } + .menubar .marke { + display: flex; align-items: center; padding: 0 12px 0 4px; + font-weight: 800; letter-spacing: -0.01em; color: #E8EAEE; + } + .menu { position: relative; } + .menu > button { + height: 100%; padding: 0 11px; cursor: pointer; + background: none; border: 0; color: #C7CCD6; + font-family: inherit; font-size: 13px; + } + .menu > button:hover { background: #1D1F26; } + .menu[data-offen="ja"] > button { background: #262932; color: #fff; } + .menu > .liste { display: none; } + .menu[data-offen="ja"] > .liste { + display: block; position: absolute; top: 100%; left: 0; + min-width: 232px; padding: 5px; + background: #1D1F26; border: 1px solid #2E313B; border-radius: 9px; + } + .menu .liste button { + display: flex; width: 100%; align-items: center; gap: 14px; + padding: 6px 9px; cursor: pointer; text-align: left; + background: none; border: 0; border-radius: 6px; + color: #C7CCD6; font-family: inherit; font-size: 13px; + } + .menu .liste button:hover { background: #2A2D36; color: #fff; } + .menu .liste button:disabled { opacity: .38; cursor: default; background: none; } + .menu .liste button .kurz { margin-left: auto; color: #6E7480; font-size: 11.5px; } + .menu .liste button .haken { width: 12px; color: var(--accent-yellow); } + .menu .liste hr { height: 1px; margin: 5px 4px; background: #2E313B; border: 0; } + + .arbeitsflaeche { flex: 1; display: flex; min-height: 0; } + /* Inhaltsfelder der gewaehlten Slide. Eine Spalte, damit lange Texte nicht in einer schmalen Zelle kleben. */ #inhalt { display: flex; flex-direction: column; gap: 4px; } @@ -96,7 +140,7 @@ /* ─── Control panel ──────────────────────────────────────────────────── */ .panel { - width: 306px; flex: none; height: 100vh; overflow-y: auto; + width: 306px; flex: none; height: 100%; overflow-y: auto; padding: 28px 22px 40px 28px; border-right: 1px solid #24262F; background: #17181F; } @@ -287,121 +331,20 @@ font-family: 'Manrope', system-ui, sans-serif; } - /* ─── Background layers ────────────────────────────────────────────────── - Five interchangeable grounds. Shapes are built from the brand geometry - (chamfered blocks + flat-top hexagons) in --dark-bg, the colour of the dark - story section on the site. */ + /* ─── Grund ────────────────────────────────────────────────────────────── + Ein einziger Grund: das Raster. Formen, Waben, Punkte und die grosse + G-Marke sind raus, ebenso das durchgehende Band mit den Sechsecken auf + den Naehten. Einstellbar bleibt nur die Staerke. */ .bg { position: absolute; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; } .slide[data-int="dezent"] .bg { --int-mul: .55; } .slide[data-int="kraeftig"] .bg { --int-mul: 1; } - - .bg > * { display: none; } - .slide[data-bg="formen"] .layer-shapes, - .slide[data-bg="formen-g"] .layer-shapes, - .slide[data-bg="formen-g"] .layer-gmark, - .slide[data-bg="nur-g"] .layer-shapes, - .slide[data-bg="nur-g"] .layer-gmark, - .slide[data-bg="waben"] .layer-waben, - .slide[data-bg="punkte"] .layer-punkte, - .slide[data-bg="raster"] .layer-raster { display: block; } - - .layer-shapes, .layer-waben, .layer-punkte, .layer-raster { - position: absolute; inset: 0; width: 100%; height: 100%; - } - .layer-gmark { inset: auto; } - .slide[data-bg="nur-g"] .sh-block { display: none; } + .layer-raster { position: absolute; inset: 0; width: 100%; height: 100%; } /* Optische Ausrückung des Tags: Der Kasten steht bündig zur Inhaltskante, sein TEXT dadurch um die 20 px Innenabstand eingerückt gegenüber der Headline. Das negative Margin holt den Text auf dieselbe Linie. Zum Vergleichen umschaltbar. */ - .sh { position: absolute; } - - /* Two large forms anchored to opposite corners and mostly off canvas, plus - the yellow hex as the one warm accent. Everything stays clear of the copy: - shapes crossing the headline are what made an earlier version look thrown - together. */ - .sh-block { - top: -300px; right: -290px; width: 760px; height: 760px; - background: var(--shape-fill); - transform: rotate(-14deg); - clip-path: polygon( - 74px 0, calc(100% - 74px) 0, 100% 74px, 100% calc(100% - 74px), - calc(100% - 74px) 100%, 74px 100%, 0 calc(100% - 74px), 0 74px - ); - } - .sh-hex-line { - bottom: -300px; left: -260px; width: 660px; height: 572px; - opacity: var(--int-mul, 1); - border: 14px solid var(--shape-line); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - } - .sh-hex-accent { - top: 268px; left: -66px; width: 172px; height: 149px; - opacity: var(--int-mul, 1); - background: var(--shape-accent); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - } - .sh-hex-small { - bottom: 296px; right: -40px; width: 108px; height: 94px; - opacity: var(--int-mul, 1); - background: var(--shape-accent-2); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - } - - /* Oversized G behind the device, cropped by whatever sits in front of it, so - only its top peeks out. Same idea as the watermark on the dark comparison - card on the site, just in grey. Lives in the background layer (z-index 0), - so the mockup always covers its lower half. */ - .layer-gmark { - position: absolute; left: 50%; top: 400px; - width: 880px; height: auto; - transform: translateX(-50%); - color: var(--gmark-color); - opacity: var(--int-mul, 1); - } - - /* ─── Durchgehendes Carousel ────────────────────────────────────────────── - Der Post ist ein einziges durchgehendes Blatt, das in 1080er Fenster - geschnitten wird. Seine Breite folgt der Anzahl der Slides (--sheet-w). Jede Slide zeigt ihren Ausschnitt, indem die - Ebene um index * 1080 nach links verschoben wird. Elemente auf den Nähten - werden dadurch zerschnitten und laufen auf der nächsten Slide weiter. */ - .continuum { - position: absolute; top: 0; height: 100%; - left: calc(var(--slide-i, 0) * -1080px); - width: var(--sheet-w, 5400px); - pointer-events: none; - opacity: var(--int-mul, 1); - } - .slide[data-cont="aus"] .continuum { display: none; } - .continuum > * { position: absolute; } - - /* Sechsecke sitzen mittig auf den Nähten (1080, 2160, 3240, 4320) und werden - dort halbiert. Das ist das deutlichste Signal, dass es weitergeht. */ - .ct-hex { - background: var(--shape-fill); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - } - .ct-hex-line { - border: 13px solid var(--shape-line); - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - } - /* Ein Band über die volle Breite: die Klammer, die alle fünf zusammenhält. */ - .ct-band { - left: 0; width: var(--sheet-w, 5400px); height: 54px; bottom: 96px; - background: var(--shape-line); - } - .ct-g { color: var(--gmark-color); } - - .layer-waben { color: var(--pat-color); opacity: calc(var(--pat-strength) * var(--int-mul, 1)); } - - .layer-punkte { - background-image: radial-gradient(circle, var(--pat-color) 3px, transparent 3px); - background-size: 52px 52px; - opacity: calc(var(--pat-strength) * var(--int-mul, 1)); - } - .layer-raster { background-image: linear-gradient(var(--pat-color) 2px, transparent 2px), @@ -780,8 +723,6 @@ --frame-bg: rgba(255,255,255,.11); --shape-fill: #414252; --shape-line: rgba(255,255,255,.10); - --shape-accent: var(--accent-yellow); - --shape-accent-2: rgba(255,255,255,.14); --pat-color: #FFFFFF; --pat-strength: .07; --gmark-color: rgba(255,255,255,.13); --guide-line: rgba(255,255,255,.16); @@ -802,8 +743,6 @@ --frame-bg: #E8EBF0; --shape-fill: var(--dark-bg); --shape-line: rgba(48,49,61,.13); - --shape-accent: var(--accent-yellow); - --shape-accent-2: rgba(48,49,61,.16); --pat-color: #30313D; --pat-strength: .07; --gmark-color: rgba(48,49,61,.16); --guide-line: rgba(48,49,61,.20); @@ -815,6 +754,73 @@ + + +
+
-
- Durchgehend (alle Slides) -
- - -
-
- -
- Muster (nur diese Slide) -
- - - - - - - -
-
-
Intensität
@@ -959,8 +944,8 @@ Tastatur
←→ Slide · V Variante
- L Layout · M Muster · I Intensität
- C Durchgehend · W Ansicht · G Tag
+ L Layout · I Intensität
+ W Ansicht · G Tag
R Bildrahmen
T Perspektive
E Bearbeiten · Pfeile verschieben (⇧ = 10 px)
@@ -1003,6 +988,7 @@
+
@@ -1239,7 +1225,7 @@ let editMode = "aus"; let current = 0; - let variant = "dunkel", tilt = "an", superSample = 2, continuous = "aus", view = "streifen", tagOut = "an", frameStyle = "chamfer"; + let variant = "dunkel", tilt = "an", superSample = 2, view = "streifen", tagOut = "an", frameStyle = "chamfer"; /* ─── Projektstand ──────────────────────────────────────────────────────── Alles, was am Projekt hängt, wird gespeichert: Einstellungen, Layouts, @@ -1253,7 +1239,7 @@ function currentState() { return { - v: STATE_V, variant, tilt, superSample, continuous, view, tagOut, frameStyle, + v: STATE_V, variant, tilt, superSample, view, tagOut, frameStyle, current, layoutState, bgState, edits, // Welche Slides der Post ueberhaupt hat. Ohne das waere eine selbst // angelegte Slide nach dem Neuladen weg. @@ -1380,7 +1366,6 @@ press("variants", "v", variant); press("tilts", "t", tilt); press("quality", "q", String(superSample)); - press("conts", "c", continuous); press("tagouts", "o", tagOut); press("frames", "f", frameStyle); press("views", "w", view); @@ -1511,7 +1496,6 @@ variant = d.variant || variant; tilt = d.tilt || tilt; superSample = d.superSample || superSample; - continuous = d.continuous || continuous; view = d.view || view; tagOut = d.tagOut || tagOut; frameStyle = d.frameStyle || frameStyle; @@ -1538,7 +1522,8 @@ .then(() => location.reload()); } // Per-slide so a single slide can carry a different ground. - const bgState = SLIDES.map(() => ({ bg: "formen", int: "dezent" })); + // Der Grund ist fest das Raster. Einstellbar bleibt nur seine Staerke. + const bgState = SLIDES.map(() => ({ bg: "raster", int: "dezent" })); // Each slide picks its own layout from its own catalogue. const layoutState = SLIDES.map(sl => sl.layouts[0].id); // Every asset is inlined once at boot, so re-rendering a layout stays synchronous. @@ -1603,74 +1588,13 @@ '' + ''; - const SVG_NS = "http://www.w3.org/2000/svg"; - const G_POINTS = "384.5,166.5 336.4,83.2 192.2,166.5 288.3,166.5 240.3,249.7 144.2,249.7 96.1,166.5 144.2,83.2 336.4,83.2 298,16.8 288.3,0 96.1,0 0,166.5 96.1,332.9 288.3,332.9"; - const G_W = 384.5, G_H = 332.9; // Positionen im 5400er Raum. Die Nähte liegen auf 1080 / 2160 / 3240 / 4320. - const CONTINUUM_HTML = - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '
'; - const BG_HTML = - '
' + CONTINUUM_HTML + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '' + - '
' + + '
' + '
' + '
'; - /* Seamless flat-top honeycomb tile, generated from the same G polygon as the - logo mark. Columns step by 3/4 of the hex width and neighbouring columns sit - half a row apart, so one tile is two columns wide and one row high. The - copies hanging past the tile edges are what make the repeat seamless. */ - function buildWaben(svg, uid) { - const colStep = G_W * 0.75, rowStep = G_H; - const tileW = colStep * 2, tileH = rowStep; - const centres = [ - [0, 0], [tileW, 0], [0, tileH], [tileW, tileH], - [colStep, rowStep / 2], [colStep, -rowStep / 2], [colStep, tileH + rowStep / 2], - ]; - const id = "waben-" + uid; - const defs = document.createElementNS(SVG_NS, "defs"); - const pat = document.createElementNS(SVG_NS, "pattern"); - pat.setAttribute("id", id); - pat.setAttribute("patternUnits", "userSpaceOnUse"); - pat.setAttribute("width", tileW); - pat.setAttribute("height", tileH); - pat.setAttribute("patternTransform", "scale(0.46)"); - for (const [cx, cy] of centres) { - const poly = document.createElementNS(SVG_NS, "polygon"); - poly.setAttribute("points", G_POINTS); - poly.setAttribute("fill", "currentColor"); - poly.setAttribute("transform", "translate(" + (cx - G_W / 2) + "," + (cy - G_H / 2) + ")"); - pat.appendChild(poly); - } - defs.appendChild(pat); - svg.appendChild(defs); - const rect = document.createElementNS(SVG_NS, "rect"); - rect.setAttribute("width", "100%"); - rect.setAttribute("height", "100%"); - rect.setAttribute("fill", "url(#" + id + ")"); - svg.appendChild(rect); - } - function contentHtml(s, i) { if (s.type === "feature") { return '

' + s.eyebrow + '

' + @@ -1890,13 +1814,11 @@ el.dataset.bg = bgState[i].bg; el.dataset.int = bgState[i].int; el.dataset.layout = layoutState[i]; - el.dataset.cont = continuous; el.dataset.tagout = tagOut; el.dataset.frame = frameStyle; el.dataset.editmode = editMode; el.style.setProperty("--slide-i", i); el.innerHTML = BG_HTML; - buildWaben(el.querySelector(".layer-waben"), i); /* Jede Slide traegt das vollstaendige Blatt, nicht nur ihre Nachbarn. Vorher waren es i-1 bis i+1, und ein Element liess sich damit genau eine @@ -1997,7 +1919,6 @@ el.dataset.bg = bgState[i].bg; el.dataset.int = bgState[i].int; el.dataset.layout = layoutState[i]; - el.dataset.cont = continuous; el.dataset.tagout = tagOut; el.dataset.frame = frameStyle; if (SLIDES[i].type === "title") rebuildPage(i); @@ -2023,7 +1944,6 @@ // Reflect the active slide's own ground in the panel. function syncBgButtons() { - press("bgs", "b", bgState[current].bg); press("ints", "i", bgState[current].int); } @@ -3352,6 +3272,79 @@ } }); + /* ─── Menueleiste ──────────────────────────────────────────────────────── + Die Eintraege fuehren nichts selbst aus, sondern betaetigen die Schalter + im Bedienfeld. Damit gibt es weiter genau eine Stelle, an der ein + Verhalten steht, und die Leiste kann nicht auseinanderlaufen. + data-klick Knopf mit dieser id anklicken + data-opt Knopf einer Optionsgruppe: gruppe:attribut:wert + data-tun benannte Aktion + data-gehe anderes Projekt oeffnen */ + (function menueleiste() { + const bar = document.getElementById("menubar"); + if (!bar) return; + const menues = [...bar.querySelectorAll(".menu")]; + const zu = () => menues.forEach(m => delete m.dataset.offen); + + const AKTION = { undo, redo }; + + // Haken und graue Eintraege erst beim Oeffnen setzen: vorher weiss die + // Leiste nicht, was gerade gilt. + function stand(m) { + m.querySelectorAll("button[data-opt]").forEach(b => { + const [gruppe, attr, wert] = b.dataset.opt.split(":"); + const q = document.querySelector("#" + gruppe + " button[data-" + attr + '="' + wert + '"]'); + const an = q && q.getAttribute("aria-pressed") === "true"; + b.querySelector(".haken")?.remove(); + b.insertAdjacentHTML("afterbegin", + '' + (an ? "✓" : "") + ""); + }); + m.querySelectorAll("button[data-klick]").forEach(b => { + const q = document.getElementById(b.dataset.klick); + b.disabled = !q || q.disabled; + }); + m.querySelectorAll("button[data-gehe]").forEach(b => { + const hier = b.dataset.gehe.endsWith(location.pathname.split("/").pop() || "post1.html"); + b.querySelector(".haken")?.remove(); + b.insertAdjacentHTML("afterbegin", + '' + (hier ? "✓" : "") + ""); + }); + } + + bar.addEventListener("click", e => { + const titel = e.target.closest(".menu > button"); + if (titel) { + const m = titel.parentElement; + const war = m.dataset.offen === "ja"; + zu(); + if (!war) { m.dataset.offen = "ja"; stand(m); } + return; + } + const el = e.target.closest(".liste button"); + if (!el || el.disabled) return; + zu(); + if (el.dataset.gehe) { location.href = el.dataset.gehe; return; } + if (el.dataset.tun) { (AKTION[el.dataset.tun] || (() => {}))(); return; } + if (el.dataset.klick) { document.getElementById(el.dataset.klick)?.click(); return; } + if (el.dataset.opt) { + const [gruppe, attr, wert] = el.dataset.opt.split(":"); + document.querySelector("#" + gruppe + " button[data-" + attr + '="' + wert + '"]')?.click(); + } + }); + + // Ueberfahren wechselt das offene Menue, wie gewohnt. + bar.addEventListener("mouseover", e => { + const titel = e.target.closest(".menu > button"); + if (!titel || !menues.some(m => m.dataset.offen === "ja")) return; + const m = titel.parentElement; + if (m.dataset.offen === "ja") return; + zu(); m.dataset.offen = "ja"; stand(m); + }); + + document.addEventListener("mousedown", e => { if (!bar.contains(e.target)) zu(); }); + document.addEventListener("keydown", e => { if (e.key === "Escape") zu(); }); + })(); + document.getElementById("reset-all").addEventListener("click", resetAll); // Übersicht der Standards, direkt aus derselben Tabelle wie der Reset. @@ -3478,14 +3471,6 @@ const b = e.target.closest("button"); if (b) { layoutState[current] = b.dataset.l; syncLayoutButtons(); rebuildPage(current); applyAll(); saveState(); } }); - document.getElementById("conts").addEventListener("click", e => { - const b = e.target.closest("button"); - if (b) { continuous = b.dataset.c; press("conts", "c", continuous); applyAll(); saveState(); } - }); - document.getElementById("bgs").addEventListener("click", e => { - const b = e.target.closest("button"); - if (b) { bgState[current].bg = b.dataset.b; syncBgButtons(); applyAll(); saveState(); } - }); document.getElementById("ints").addEventListener("click", e => { const b = e.target.closest("button"); if (b) { bgState[current].int = b.dataset.i; syncBgButtons(); applyAll(); saveState(); } @@ -3511,7 +3496,6 @@ document.getElementById("dl-png").addEventListener("click", guard(downloadOne)); document.getElementById("dl-all").addEventListener("click", guard(downloadAll)); - const BG_CYCLE = ["formen", "formen-g", "nur-g", "waben", "punkte", "raster", "aus"]; /* ⌘/Strg + Z. Eigener Zuhoerer, weil der allgemeine unten alles mit Sondertaste durchlaesst. In Eingabefeldern hat das Zurueckgehen des Browsers Vorrang, sonst kaeme man aus einem Tippfehler nicht mehr heraus. */ @@ -3551,11 +3535,6 @@ layoutState[current] = cat[(n + 1) % cat.length].id; syncLayoutButtons(); rebuildPage(current); applyAll(); saveState(); } - else if (k === "m") { - const st = bgState[current]; - st.bg = BG_CYCLE[(BG_CYCLE.indexOf(st.bg) + 1) % BG_CYCLE.length]; - syncBgButtons(); applyAll(); - } else if (k === "i") { const st = bgState[current]; st.int = st.int === "dezent" ? "kraeftig" : "dezent"; @@ -3573,7 +3552,6 @@ press("frames", "f", frameStyle); applyAll(); saveState(); } else if (k === "g") { tagOut = tagOut === "an" ? "aus" : "an"; press("tagouts", "o", tagOut); applyAll(); saveState(); } - else if (k === "c") { continuous = continuous === "an" ? "aus" : "an"; press("conts", "c", continuous); applyAll(); saveState(); } else if (k === "d") guard(downloadOne)(); else if (k === "a") guard(downloadAll)(); }); @@ -3608,7 +3586,6 @@ press("variants", "v", variant); press("tilts", "t", tilt); press("quality", "q", String(superSample)); - press("conts", "c", continuous); press("tagouts", "o", tagOut); press("frames", "f", frameStyle); press("views", "w", view); diff --git a/post2.html b/post2.html new file mode 100644 index 0000000..e363b20 --- /dev/null +++ b/post2.html @@ -0,0 +1,3611 @@ + + + + + +HiveGrid Post 2 (Carousel) + + + + + + + +
+ + + +
+
+
+
+
+
+
+
+
+

+
+ + +
+
+ + + +
+
+
+ + +
+ + + + + +