From 39bc6794fe4c54996009e28b9cf6b7e9f7b4e416 Mon Sep 17 00:00:00 2001 From: David Bechstein Date: Fri, 7 Aug 2026 12:47:24 +0200 Subject: [PATCH 1/2] feat(surface): Sektionslayouts kommen aus dem Theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Claude-Session: https://claude.ai/code/session_01QvepSeijoZeRaBsyiGqoka --- .../Resources/app/admin/src/CanvasSection.vue | 48 +- .../app/admin/src/ComposerAdminPage.spec.ts | 9 +- .../app/admin/src/ComposerAdminPage.vue | 96 +- .../app/admin/src/ComposerCanvas.vue | 4 + .../app/admin/src/ComposerEditing.spec.ts | 119 +- .../src/Resources/app/admin/src/composer.css | 44 + .../app/admin/src/layout-document.spec.ts | 53 + .../app/admin/src/layout-document.ts | 42 + .../app/admin/src/preview-assets.spec.ts | 14 +- .../Resources/app/admin/src/preview-assets.ts | 47 +- .../app/admin/src/section-layouts.spec.ts | 106 + .../app/admin/src/section-layouts.ts | 85 + docs-site/guides/surface/themes-and-tokens.md | 51 + .../IWorkspaceSectionLayoutStore.cs | 34 + .../Extensions/SectionLayoutDefinition.cs | 27 + .../Extensions/SectionLayoutRegion.cs | 6 + .../Extensions/WorkspacePublicTheme.cs | 8 +- .../WorkspacePublicThemeResolver.cs | 9 +- .../WorkspaceSectionLayoutDefinition.cs | 40 + .../Extensions/SectionLayoutManifestReader.cs | 137 ++ .../ThemeJsonWorkspaceTemplateSyncService.cs | 51 + ...dPersistenceServiceCollectionExtensions.cs | 1 + ...LayoutDefinitionEntityTypeConfiguration.cs | 28 + .../EfWorkspaceSectionLayoutStore.cs | 118 ++ .../Persistence/HostPersistenceDbContext.cs | 3 + ...kspaceSectionLayoutDefinitions.Designer.cs | 1869 +++++++++++++++++ ...56_AddWorkspaceSectionLayoutDefinitions.cs | 52 + .../HostPersistenceDbContextModelSnapshot.cs | 62 + src/Core/PublicAPI.Unshipped.txt | 79 +- .../Api/SurfaceRenderEndpoints.cs | 34 +- src/Surface.Rendering/PublicAPI.Unshipped.txt | 3 +- .../Composition/SurfaceCompositionRenderer.cs | 27 +- src/Workspace/Api/WorkspacePublicEndpoints.cs | 6 +- .../Api/WorkspacePublicEndpointsTests.cs | 2 + .../WorkspacePublicThemeResolverTests.cs | 12 +- .../SectionLayoutManifestReaderTests.cs | 137 ++ ...meJsonWorkspaceTemplateSyncServiceTests.cs | 9 +- .../InMemoryWorkspaceSectionLayoutStore.cs | Bin 0 -> 1536 bytes .../SurfaceCompositionRendererTests.cs | 45 + .../Surface/SurfaceRenderEndpointsTests.cs | 4 + 40 files changed, 3462 insertions(+), 59 deletions(-) create mode 100644 custom/static-plugins/Composer/src/Resources/app/admin/src/section-layouts.spec.ts create mode 100644 custom/static-plugins/Composer/src/Resources/app/admin/src/section-layouts.ts create mode 100644 src/Core/Application/Extensions/IWorkspaceSectionLayoutStore.cs create mode 100644 src/Core/Application/Extensions/SectionLayoutDefinition.cs create mode 100644 src/Core/Application/Extensions/SectionLayoutRegion.cs create mode 100644 src/Core/Domain/Extensions/WorkspaceSectionLayoutDefinition.cs create mode 100644 src/Core/Infrastructure/Extensions/SectionLayoutManifestReader.cs create mode 100644 src/Core/Infrastructure/Persistence/Configurations/WorkspaceSectionLayoutDefinitionEntityTypeConfiguration.cs create mode 100644 src/Core/Infrastructure/Persistence/EfWorkspaceSectionLayoutStore.cs create mode 100644 src/Core/Infrastructure/Persistence/Migrations/20260807102656_AddWorkspaceSectionLayoutDefinitions.Designer.cs create mode 100644 src/Core/Infrastructure/Persistence/Migrations/20260807102656_AddWorkspaceSectionLayoutDefinitions.cs create mode 100644 tests/Callora.Core.Tests/Infrastructure/Extensions/SectionLayoutManifestReaderTests.cs create mode 100644 tests/Callora.Core.Tests/Support/InMemoryWorkspaceSectionLayoutStore.cs diff --git a/custom/static-plugins/Composer/src/Resources/app/admin/src/CanvasSection.vue b/custom/static-plugins/Composer/src/Resources/app/admin/src/CanvasSection.vue index 9c058de1..0d5cb4d5 100644 --- a/custom/static-plugins/Composer/src/Resources/app/admin/src/CanvasSection.vue +++ b/custom/static-plugins/Composer/src/Resources/app/admin/src/CanvasSection.vue @@ -1,6 +1,8 @@