## Styling und CSS-Integration Keluna verwendet die System-WebView als Renderer. Deshalb sollte **CSS die primäre Styling-Technologie** sein. Der Kotlin-Code beschreibt Komponenten, Zustand und Verhalten; CSS beschreibt deren visuelle Darstellung. Dabei soll CSS nicht als getrennte, globale „Web-Schicht“ behandelt werden. Komponenten sollen **nach Fachlichkeit bzw. Feature gruppiert** werden können, sodass Kotlin-Code und zugehöriges Styling direkt nebeneinander liegen. ### Grundprinzip Eine Keluna-Komponente könnte beispielsweise so organisiert sein: ```text projectbrowser/ ├── ProjectBrowser.kt ├── ProjectBrowser.css ├── ProjectEntry.kt └── ProjectEntry.css ``` Damit wird nicht nach Technologien wie `kotlin/`, `css/` und `javascript/` getrennt, sondern nach Komponenten bzw. Features. ### CSS-Klassen als Styling-Schnittstelle Komponenten sollten ihren relevanten DOM-Elementen semantische CSS-Klassen geben können. ```kotlin component("project-entry") { div(classes = "project-entry") { span(classes = "project-entry__name") { text(project.name) } span(classes = "project-entry__status") { text(project.status) } } } ``` Dazu liegt direkt daneben beispielsweise: ```css .project-entry { display: flex; align-items: center; gap: 0.5rem; } .project-entry__name { font-weight: 600; } .project-entry__status { opacity: 0.7; } ``` Die CSS-Klasse ist damit Teil der Styling-Schnittstelle einer Komponente. ### IDs nicht als primärer Styling-Mechanismus Keluna benötigt intern eindeutige IDs, um DOM-Knoten mit Komponenten im Kotlin-Component-Tree zu verbinden. Diese IDs sollten jedoch **keine öffentliche Styling-Schnittstelle** sein. Intern könnte Keluna beispielsweise erzeugen: ```html ``` Diese ID wird automatisch generiert und ausschließlich für Runtime, Events und Synchronisation verwendet. CSS sollte sich deshalb nicht darauf beziehen. Falls der Entwickler selbst eine DOM-ID benötigt, etwa für Accessibility, Tests oder die Integration einer externen Web-Komponente, sollte Keluna auch explizite IDs erlauben. Deren Eindeutigkeit liegt dann jedoch in der Verantwortung der Anwendung. ### Komponentenlokales CSS Keluna sollte CSS-Dateien direkt einer Komponente zuordnen können. Konzeptionell: ```kotlin class ProjectEntry : Component() { override val stylesheet = stylesheet("ProjectEntry.css") } ``` oder deklarativer: ```kotlin component("project-entry") { stylesheet("ProjectEntry.css") // ... } ``` Das Keluna-Gradle-Plugin sammelt diese Stylesheets beim Build und bettet sie zusammen mit den übrigen Web-Ressourcen in die Anwendung ein. Der Entwickler muss dafür weder einen Webserver noch einen JavaScript-Bundler konfigurieren. ### CSS-Isolation Lokales CSS sollte möglichst nicht versehentlich andere Komponenten beeinflussen. Keluna könnte deshalb jedem Komponententyp automatisch einen Scope geben: ```html
...
``` Das Framework kann das lokale CSS beim Build entsprechend scopen. Aus: ```css .title { font-weight: bold; } ``` wird intern beispielsweise: ```css [data-keluna-scope="project-entry"] .title { font-weight: bold; } ``` Damit kann eine Komponente einfache Klassennamen verwenden, ohne globale Namenskollisionen zu verursachen. Die konkrete Implementierung des Scopings ist noch eine Designentscheidung. Denkbar sind: - Selector-Rewriting beim Build - modernes CSS Scoping - Shadow DOM für dafür geeignete Komponenten Für normale Keluna-Komponenten erscheint **Light DOM mit automatisch gescoptem CSS** zunächst attraktiver als Shadow DOM, da globales Theming und die Integration mit der restlichen Anwendung einfacher bleiben. ### Globales Styling und Themes Neben komponentenlokalem CSS braucht eine Anwendung globale Designregeln. Beispielsweise: ```text src/ ├── App.kt ├── theme.css └── projectbrowser/ ├── ProjectBrowser.kt └── ProjectBrowser.css ``` `theme.css` könnte globale Design-Tokens über CSS Custom Properties definieren: ```css :root { --keluna-font-family: system-ui, sans-serif; --keluna-font-size: 14px; --keluna-spacing: 0.5rem; --keluna-border-radius: 4px; } ``` Eine Komponente verwendet diese Variablen: ```css .project-entry { gap: var(--keluna-spacing); border-radius: var(--keluna-border-radius); } ``` Keluna sollte nach Möglichkeit auch Systempräferenzen wie Dark Mode über normale CSS-Möglichkeiten nutzbar machen: ```css @media (prefers-color-scheme: dark) { :root { /* anwendungsspezifische Anpassungen */ } } ``` ### Drei Styling-Ebenen Keluna sollte Styling auf drei Ebenen ermöglichen: 1. **Framework Defaults** Minimale Standarddarstellung der Keluna-Komponenten. 2. **Application Theme** Globale Typografie, Farben, Abstände und Design-Tokens der Anwendung. 3. **Component Styles** Direkt bei einer fachlichen Komponente liegendes CSS für deren konkrete Darstellung. Konzeptionell: ```text Keluna defaults ↓ Application theme ↓ Component-local CSS ``` ### Inline-Styles aus Kotlin Keluna sollte einfache dynamische Style-Eigenschaften auch direkt aus Kotlin setzen können. ```kotlin progressBar { style.width = "${progress}%" } ``` Das ist sinnvoll für Werte, die tatsächlich aus dem Anwendungszustand entstehen. Statisches Design sollte dagegen im CSS bleiben. Die Trennung sollte lauten: > **Kotlin beschreibt Zustand und Verhalten; CSS beschreibt Design.** ### Zustandsabhängiges Styling Anwendungszustände sollten möglichst über Klassen oder Attribute an CSS übergeben werden. ```kotlin projectEntry { cssClass("selected", selected) attribute("data-status", project.status) } ``` Daraus könnte entstehen: ```html
``` Das CSS bleibt dann deklarativ: ```css .project-entry.selected { outline: 2px solid currentColor; } .project-entry[data-status="modified"] { font-style: italic; } ``` Dadurch muss Kotlin keine konkreten Farben, Abstände oder anderen Designentscheidungen kennen. ### Kein JavaScript im normalen Anwendungscode Das Styling-Konzept erfordert **kein JavaScript vom Keluna-Anwendungsentwickler**. Die kleine JavaScript-Schicht, die Keluna für DOM-Synchronisation und Event-Weiterleitung benötigt, ist Bestandteil des Frameworks. Für normale Anwendungen besteht der Stack damit aus: ```text Kotlin + CSS ↓ Keluna Runtime ↓ interne JavaScript-Bridge ↓ System-WebView ``` JavaScript bleibt ein möglicher Escape Hatch für spezielle Web-Komponenten oder externe Bibliotheken, ist aber **keine Voraussetzung für die Entwicklung einer Keluna-Anwendung**. ### Designziel Ein Feature besteht idealerweise aus: ```text ProjectBrowser.kt ProjectBrowser.css ``` Kotlin enthält: - Komponentenstruktur - Zustand - Events - Anwendungslogik CSS enthält: - Layout - Typografie - Farben - Animationen - Responsive-Verhalten - visuelle Zustände Beides liegt direkt nebeneinander und bildet gemeinsam die Komponente. Das erlaubt eine **fachliche Projektstruktur statt einer technologischen Trennung** und nutzt gleichzeitig die ausgereiften Styling-Fähigkeiten moderner WebViews.