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 @@
+ + +' + 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 @@ + + + + + +