feat(surface): Sektionslayouts kommen aus dem Theme - #192
Merged
Merged
Conversation
Ein Theme deklariert in `theme.json`, welche Sektionslayouts es rendern kann und welche Regionen darin liegen. Der Editor bietet ausschließlich das an. Damit bleibt die Token-Achse die Design-Autorität — niemand komponiert ein Raster, das das Theme nicht stylen kann — und es steht kein Layout-Name im Core. Ein Theme kann ein Raster mitbringen, das niemand vorhergesehen hat, ohne Änderung an der Plattform. Das ist auch der Schritt, ohne den Drag & Drop keine Ziele hätte: Der Canvas zeigt jetzt jede Region des Layouts, auch die leere. Bisher zeigte er nur Regionen, in denen schon ein Block lag — eine zweispaltige Sektion mit leerer Spalte sah aus wie eine einspaltige, und es gab keinen Ort, an den sich etwas ziehen ließe. **Der Rückfall bei einem Theme-Wechsel (§7.8)** unterscheidet zwei Fälle, die sonst gleich aussehen. Ein Theme, das `two-2-1` NICHT MEHR kennt, hat es abgelehnt — die Sektion fällt beim Rendern auf `single` zurück, alle Blöcke bleiben, sie steht nur einspaltig statt in einem Raster, das niemand stylt. Ein Theme, das gar keine Layouts deklariert (heute die meisten), sagt zu keinem etwas; dort fällt nichts zurück. Sonst wäre aus einer leeren Liste eine sichtbare Layout-Änderung geworden. Der Editor benennt die betroffenen Sektionen. Das ist der Unterschied zwischen „meine Seite sieht anders aus" und „diese Sektion hängt an einem Layout, das das neue Theme nicht mitbringt". **Ein Layout-Wechsel hängt keine Blöcke um.** Das wäre die scheinbar hilfreiche Variante und die, die Arbeit vernichtet: Wer ein Layout ausprobiert und zurückwechselt, fände seine Seitenspalte im Hauptbereich wieder, ohne dass irgendetwas das rückgängig machen könnte. So bleibt der Wechsel umkehrbar, und heimatlose Blöcke stehen sichtbar hinten in der Sektion. **Der Parser überspringt Kaputtes, statt aufzugeben.** Ein Theme mit einem fehlerhaften Layout bietet seine anderen weiter an; ein Parser, der abbräche, ließe den Editor ohne jedes Layout zurück — und das sieht genauso aus wie ein Theme, das keine deklariert. Regionen als JSON-Spalte statt als zweite Tabelle: Sie werden nie ohne ihr Layout gefragt, und nichts fragt über sie hinweg. Eine Tabelle kaufte einen Join und eine Sortierspalte für eine Liste, die ganz oder gar nicht gelesen wird. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QvepSeijoZeRaBsyiGqoka
Der vorige Commit gab dem Theme die Sprache für Sektionslayouts — nur sagte sie niemand. Es gibt kein `theme.json` im Repo, und `.cal-section` stylte nichts: Der Renderer gab `data-cal-layout` aus, auf das nichts hörte, und der Editor bot keine Wahl an. Beides sah nach einem Fehler aus, wo ein Theme fehlte. Jetzt bringt die Basis-Fläche fünf Layouts mit (`single`, `two-1-1`, `two-2-1`, `sidebar-left`, `three-1-1-1`), gestylt in derselben `tokens.scss`, die auch die neutralen `--cal-*`-Werte trägt. Dieselbe Rolle wie dort: eine Basis, kein Design. Eine frische Installation hat damit etwas, womit sich komponieren lässt. **Ein Plugin-Theme erbt sie und ergänzt die eigenen.** Das ist die sichere Richtung: Das Basis-Stylesheet ist immer geladen, also funktionieren die Basis-Layouts auch unter einem fremden Theme, und wer nur `sidebar-right` beisteuern will, muss die Palette nicht wiederholen. Ein gleichnamiges Layout verdrängt das der Basis VOLLSTÄNDIG — zusammenzuführen wäre der Weg, auf dem ein Theme ein `two-2-1` mit den Regionen der Basis bekäme, obwohl sein CSS zwei andere kennt, und die Blöcke lägen dann in Regionen, die es nicht gibt. Wer ein eigenes Rastersystem durchsetzen will, setzt `inheritSectionLayouts` auf false. Die Liste steht in C# und nicht im TypeScript-Paket, obwohl das CSS dort liegt: Der Kompositions-Renderer muss dieselbe Vererbung kennen wie der Editor, und zwei Listen wären zwei Wahrheiten. `SurfaceBaseSectionLayoutsTests` hält sie gegen `tokens.scss` — über die Sprachgrenze, weil genau dort sonst niemand hinsieht: Ein deklariertes Layout ohne Regel ist ein Angebot, das nichts tut, eine Regel ohne Deklaration ein Raster, das niemand wählen kann. Der Test prüft auch, dass die Spaltenzahl zur Regionenzahl passt und dass nirgends ein fester Pixelwert steht — das wäre genau die Freiheit, die die Token-Achse dem Editor verweigert. Ein kaputter Schalter (`"inheritSectionLayouts": "false"` als Zeichenkette) heißt erben. Ihn als Abschaltung zu lesen ließe den Editor still nur noch das eine Theme-Layout anbieten, und niemand käme auf die Zeichenkette. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QvepSeijoZeRaBsyiGqoka
This was referenced Aug 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1. Why is this change necessary?
Drag & Drop braucht Zielorte, und die gab es nicht.
theme.jsonkannte Templates und Settings,aber keine Sektionslayouts — der Canvas zeigte nur Regionen, in denen schon ein Block lag, also
sah eine zweispaltige Sektion mit leerer Spalte aus wie eine einspaltige.
Deshalb steht dieser Baustein vor Drag & Drop, nicht daneben.
Und die Sprache allein hätte nicht gereicht: Es gibt kein
theme.jsonim Repo, und.cal-sectionstylte nichts. Der Renderer gabdata-cal-layoutaus, auf das niemand hörte, derEditor bot keine Wahl an — beides sah nach einem Fehler aus, wo ein Theme fehlte. Deshalb bringt
die Basis-Fläche die Layouts jetzt selbst mit.
2. What does this change do, exactly?
Die Basis kann es selbst. Fünf Layouts (
single,two-1-1,two-2-1,sidebar-left,three-1-1-1), gestylt in derselbentokens.scss, die schon die neutralen--cal-*-Werteträgt — dieselbe Rolle wie dort: eine Basis, kein Design. Eine frische Installation hat damit
etwas, womit sich komponieren lässt.
Ein Plugin-Theme erbt sie und ergänzt die eigenen. Das Basis-Stylesheet ist immer geladen,
also funktionieren die Basis-Layouts auch unter einem fremden Theme, und wer nur
sidebar-rightbeisteuern will, muss die Palette nicht wiederholen. Ein gleichnamiges Layoutverdrängt das der Basis vollständig — zusammenzuführen wäre der Weg, auf dem ein Theme ein
two-2-1mit den Regionen der Basis bekäme, obwohl sein CSS zwei andere kennt, und die Blöckelägen dann in Regionen, die es nicht gibt.
"inheritSectionLayouts": falsesteht allein.Ein Theme deklariert, welche Sektionslayouts es rendern kann und welche Regionen darin liegen
(§7.1). Der Editor bietet ausschließlich das an.
{ "sectionLayouts": [ { "key": "single", "label": "Eine Spalte", "regions": ["main"] }, { "key": "two-2-1", "label": "Zwei Spalten (2:1)", "regions": [{ "key": "main", "label": "Inhalt" }, { "key": "aside", "label": "Seitenspalte" }] } ] }Damit bleibt die Token-Achse die Design-Autorität — niemand komponiert ein Raster, das das Theme
nicht stylen kann — und es steht kein Layout-Name im Core. Ein Theme bringt ein Raster mit,
das niemand vorhergesehen hat, ohne Änderung an der Plattform.
Der Rückfall bei einem Theme-Wechsel (§7.8) unterscheidet zwei Fälle, die sonst gleich
aussehen. Ein Theme, das
two-2-1nicht mehr kennt, hat es abgelehnt: Die Sektion fällt beimRendern auf
singlezurück, alle Blöcke bleiben, sie steht nur einspaltig statt in einem Raster,das niemand stylt. Ein Theme, das gar keine Layouts deklariert — heute die meisten —, sagt zu
keinem etwas; dort fällt nichts zurück. Ohne diese Unterscheidung wäre aus einer leeren Liste eine
sichtbare Layout-Änderung geworden, auf jeder bestehenden Seite.
Der Editor benennt die betroffenen Sektionen. Das ist der Unterschied zwischen „meine Seite
sieht anders aus" und „diese Sektion hängt an einem Layout, das das neue Theme nicht mitbringt".
Ein Layout-Wechsel hängt keine Blöcke um. Das wäre die scheinbar hilfreiche Variante und die,
die Arbeit vernichtet: Wer ein Layout ausprobiert und zurückwechselt, fände seine Seitenspalte im
Hauptbereich wieder, ohne dass irgendetwas das rückgängig machen könnte. Heimatlose Blöcke stehen
stattdessen sichtbar hinten in der Sektion — verstecken hieße, Inhalt zu verstecken, den das
Dokument noch trägt.
Der Parser überspringt Kaputtes, statt aufzugeben. Ein Theme mit einem fehlerhaften Layout
bietet seine anderen weiter an. Ein Parser, der abbräche, ließe den Editor ohne jedes Layout
zurück — und das sieht genauso aus wie ein Theme, das keine deklariert.
Regionen liegen als JSON-Spalte, nicht als zweite Tabelle: Sie werden nie ohne ihr Layout gefragt,
und nichts fragt über sie hinweg. Eine Tabelle kaufte einen Join und eine Sortierspalte für eine
Liste, die ganz oder gar nicht gelesen wird.
3. Describe each step to reproduce the issue or behaviour.
Zwölf tragende Aussagen sabotiert — alle beißen, darunter die beiden Fälle des Rückfalls, die
Reihenfolge der Regionen (alphabetisch sortiert stünde die Seitenspalte vor dem Inhalt, neben dem
sie sitzt) und die Vererbung.
Neue Migration:
AddWorkspaceSectionLayoutDefinitions.Ein Test über die Sprachgrenze
Die Deklaration steht in C# (der Renderer braucht sie), das CSS in
tokens.scss(die Flächelädt es). Zwei Dateien, zwei Sprachen, dieselbe Sache — und nichts zwingt sie zusammen außer
SurfaceBaseSectionLayoutsTests, der die SCSS-Datei liest: Ein deklariertes Layout ohne Regelist ein Angebot, das nichts tut; eine Regel ohne Deklaration ein Raster, das niemand wählen
kann. Geprüft wird auch, dass die Spaltenzahl zur Regionenzahl passt (zwei Regionen und drei
Spalten wäre eine leere dritte, die niemand füllen kann) und dass nirgends ein fester
Pixelwert steht — das wäre genau die Freiheit, die die Token-Achse dem Editor verweigert, nur
ohne die Möglichkeit, sie zurückzunehmen.
4. Please link to the relevant issues (if any).
Setzt §7.1 (Sektionslayouts aus dem Theme), §7.7 (Guardrail) und §7.8 (Rückfall) um. Baut auf
#190 auf.
Noch nicht drin
ausgelöst, also wird ein reines CSS-plus-Manifest-Theme nie gelesen. Für die Basis spielt das
keine Rolle (sie ist die Runtime), für ein Drittanbieter-Theme schon.
spacingundsurfaceRoleje Sektion — Token-Stufen, die der Renderer schon ausgibt, fürdie der Editor aber noch kein Feld hat.