From 7b5fd063fb6506f10ba4e6b85081c5705974a830 Mon Sep 17 00:00:00 2001 From: Stefan Mogeritsch Date: Sat, 13 Dec 2025 13:00:13 +0100 Subject: [PATCH] =?UTF-8?q?refactor(frontend):=20Landing=E2=80=91Seite=20a?= =?UTF-8?q?ls=20Start=20gesetzt,=20Navigation=20um=20AppScreen.Landing=20e?= =?UTF-8?q?rweitert=20und=20Footer=E2=80=91Text=20modernisiert.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/commonui/components/AppFooter.kt | 2 +- .../clients/shared/navigation/AppScreen.kt | 1 + .../src/commonMain/kotlin/MainApp.kt | 117 +++++++++++++++++- 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/frontend/core/design-system/src/commonMain/kotlin/at/mocode/clients/shared/commonui/components/AppFooter.kt b/frontend/core/design-system/src/commonMain/kotlin/at/mocode/clients/shared/commonui/components/AppFooter.kt index acb32ae9..d3e31e7f 100644 --- a/frontend/core/design-system/src/commonMain/kotlin/at/mocode/clients/shared/commonui/components/AppFooter.kt +++ b/frontend/core/design-system/src/commonMain/kotlin/at/mocode/clients/shared/commonui/components/AppFooter.kt @@ -20,7 +20,7 @@ fun AppFooter() { contentAlignment = Alignment.Center ) { Text( - text = "© 2025 Meldestelle - Built with Kotlin Multiplatform", + text = "© Equest-Events · Entwickelt in Österreich", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center diff --git a/frontend/core/navigation/src/commonMain/kotlin/at/mocode/clients/shared/navigation/AppScreen.kt b/frontend/core/navigation/src/commonMain/kotlin/at/mocode/clients/shared/navigation/AppScreen.kt index 142e7ec1..97e0e1e7 100644 --- a/frontend/core/navigation/src/commonMain/kotlin/at/mocode/clients/shared/navigation/AppScreen.kt +++ b/frontend/core/navigation/src/commonMain/kotlin/at/mocode/clients/shared/navigation/AppScreen.kt @@ -1,6 +1,7 @@ package at.mocode.clients.shared.navigation sealed class AppScreen { + data object Landing : AppScreen() data object Home : AppScreen() data object Login : AppScreen() data object Ping : AppScreen() diff --git a/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt b/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt index 3872b365..c45901f2 100644 --- a/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt +++ b/frontend/shells/meldestelle-portal/src/commonMain/kotlin/MainApp.kt @@ -29,7 +29,7 @@ fun MainApp() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - var currentScreen by remember { mutableStateOf(AppScreen.Home) } + var currentScreen by remember { mutableStateOf(AppScreen.Landing) } // Resolve AuthTokenManager from Koin val authTokenManager = koinInject() @@ -57,6 +57,10 @@ fun MainApp() { } when (currentScreen) { + is AppScreen.Landing -> LandingScreen( + onPrimaryCta = { currentScreen = AppScreen.Login }, + onSecondary = { currentScreen = AppScreen.Home } + ) is AppScreen.Home -> WelcomeScreen( authTokenManager = authTokenManager, onOpenPing = { currentScreen = AppScreen.Ping }, @@ -83,6 +87,117 @@ fun MainApp() { } } +@Composable +private fun LandingScreen( + onPrimaryCta: () -> Unit, + onSecondary: () -> Unit +) { + // Minimal Landing-Layout: Hero → Manifest → Features → Footer + Column(modifier = Modifier.fillMaxSize()) { + // Hero + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 40.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // Wortmarke (Platzhalter) + Text( + text = "Equest‑Events", + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.primary + ) + + Text( + text = "Die kompetente Turnier‑Meldestelle.", + style = MaterialTheme.typography.headlineLarge + ) + Text( + text = "Equest‑Events entwickelt die digitale Infrastruktur des österreichischen Pferdesports – aus der Praxis. Für die Praxis.", + style = MaterialTheme.typography.bodyLarge + ) + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + Button(onClick = onPrimaryCta) { Text("Anmelden (Pilot‑Partner)") } + TextButton(onClick = onSecondary) { Text("Mehr erfahren") } + } + } + + // Manifest + Surface(color = MaterialTheme.colorScheme.surfaceVariant) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 40.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text("Unser Anspruch: Durchdachtes System.", style = MaterialTheme.typography.headlineMedium) + Text( + "Die Meldestelle ist das Herzstück jedes Turniers. Wenn sie stolpert, stockt der Sport. Wir verstehen den Balanceakt zwischen Veranstaltern, Reitern und den Verbänden.", + style = MaterialTheme.typography.bodyLarge + ) + Text( + "Deshalb entwickeln wir Equest‑Events nicht am Reißbrett, sondern direkt am Turnier – aus der Sicht der Meldestelle, der Richter, der Zeitnehmer und aller Funktionäre.", + style = MaterialTheme.typography.bodyLarge + ) + Text( + "Aktuell befindet sich unser System in einer Pilotphase für C‑ und C‑NEU‑Turniere. Wir wachsen organisch – Seite an Seite mit unseren Pilot‑Partnern.", + style = MaterialTheme.typography.bodyLarge + ) + Text( + "Jedes Feedback fließt direkt in die Entwicklung ein, um eine Lösung zu schaffen, die den realen Bedürfnissen vor Ort entspricht.", + style = MaterialTheme.typography.bodyLarge + ) + } + } + + // Features + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 40.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Text("Die drei Säulen", style = MaterialTheme.typography.headlineMedium) + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + FeatureCard( + number = "01", + title = "Regelwerks‑Intelligenz (FEI & ÖTO)", + body = "Wir verbinden ÖTO und FEI – und nehmen Ihnen die Validierungs‑Komplexität ab. Von der Lizenzprüfung bis zur korrekten Anwendung der Bestimmungen." + ) + FeatureCard( + number = "02", + title = "Plattformunabhängig & Offline‑fähig", + body = "Stabil auf Laptop und mobil. Dank Offline‑Unterstützung arbeiten Sie nahtlos weiter – selbst wenn die Internetverbindung am Platz abreißt." + ) + FeatureCard( + number = "03", + title = "Fokus auf den Sport", + body = "Wir reduzieren Administration dort, wo es sinnvoll ist – damit sich alle auf das Wesentliche konzentrieren können: den Reitsport." + ) + } + } + + // Footer + at.mocode.clients.shared.commonui.components.AppFooter() + } +} + +@Composable +private fun FeatureCard(number: String, title: String, body: String) { + Surface( tonalElevation = 0.dp ) { + Row(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.width(56.dp).padding(top = 6.dp)) { + Text(text = number, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary) + } + Column(modifier = Modifier.weight(1f)) { + Text(title, style = MaterialTheme.typography.titleLarge) + Spacer(Modifier.height(4.dp)) + Text(body, style = MaterialTheme.typography.bodyLarge) + } + } + } +} + @Composable private fun WelcomeScreen( authTokenManager: AuthTokenManager,