ein wenig aufgeräumt
This commit is contained in:
@@ -20,6 +20,6 @@ fun main() = application {
|
||||
) {
|
||||
// Use the shared App component from common-ui
|
||||
// This eliminates code duplication and ensures consistent UI across platforms
|
||||
App(baseUrl = System.getProperty("meldestelle.api.url", "http://localhost:8080"))
|
||||
App(baseUrl = System.getProperty("meldestelle.api.url", "http://localhost:8081"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,15 +59,24 @@ object AppStylesheet : StyleSheet() {
|
||||
property("transition", "all 0.2s ease")
|
||||
width(100.percent)
|
||||
marginBottom(20.px)
|
||||
|
||||
// Improved focus management using property
|
||||
property("&:focus", "outline: 2px solid #1976d2; outline-offset: 2px; box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.2);")
|
||||
|
||||
// Enhanced active state
|
||||
property("&:active", "transform: scale(0.98);")
|
||||
}
|
||||
|
||||
val buttonHover by style {
|
||||
transform { scale(1.02) }
|
||||
property("box-shadow", "0 2px 8px rgba(0, 0, 0, 0.15)")
|
||||
}
|
||||
|
||||
val buttonDisabled by style {
|
||||
opacity(0.6)
|
||||
cursor("not-allowed")
|
||||
property("transform", "none")
|
||||
property("box-shadow", "none")
|
||||
}
|
||||
|
||||
val primaryButton by style {
|
||||
@@ -76,7 +85,11 @@ object AppStylesheet : StyleSheet() {
|
||||
|
||||
hover(self) style {
|
||||
backgroundColor(Color("#1565c0"))
|
||||
property("box-shadow", "0 4px 12px rgba(25, 118, 210, 0.3)")
|
||||
}
|
||||
|
||||
// Using property for disabled state
|
||||
property("&:disabled", "background-color: #bbbbbb; cursor: not-allowed;")
|
||||
}
|
||||
|
||||
val successMessage by style {
|
||||
|
||||
@@ -76,19 +76,35 @@ fun MeldestelleWebApp() {
|
||||
|
||||
Div(attrs = {
|
||||
classes(AppStylesheet.container)
|
||||
attr("role", "application")
|
||||
attr("aria-label", "Meldestelle Web Application")
|
||||
}) {
|
||||
Header(attrs = { classes(AppStylesheet.header) }) {
|
||||
H1 { Text("Meldestelle Web App") }
|
||||
Header(attrs = {
|
||||
classes(AppStylesheet.header)
|
||||
attr("role", "banner")
|
||||
}) {
|
||||
H1(attrs = {
|
||||
attr("id", "app-title")
|
||||
}) {
|
||||
Text("Meldestelle Web App")
|
||||
}
|
||||
}
|
||||
|
||||
Main(attrs = { classes(AppStylesheet.main) }) {
|
||||
Main(attrs = {
|
||||
classes(AppStylesheet.main)
|
||||
attr("role", "main")
|
||||
attr("aria-labelledby", "app-title")
|
||||
}) {
|
||||
PingTestWebView(
|
||||
state = viewModel.uiState,
|
||||
onTestConnection = { viewModel.pingBackend() }
|
||||
)
|
||||
}
|
||||
|
||||
Footer(attrs = { classes(AppStylesheet.footer) }) {
|
||||
Footer(attrs = {
|
||||
classes(AppStylesheet.footer)
|
||||
attr("role", "contentinfo")
|
||||
}) {
|
||||
P { Text("© 2025 Meldestelle - Powered by Kotlin Multiplatform") }
|
||||
}
|
||||
}
|
||||
@@ -99,49 +115,83 @@ fun PingTestWebView(
|
||||
state: PingUiState,
|
||||
onTestConnection: () -> Unit
|
||||
) {
|
||||
Div(attrs = { classes(AppStylesheet.card) }) {
|
||||
H2 { Text("Backend Verbindungstest") }
|
||||
Div(attrs = {
|
||||
classes(AppStylesheet.card)
|
||||
attr("role", "region")
|
||||
attr("aria-labelledby", "ping-test-title")
|
||||
}) {
|
||||
H2(attrs = {
|
||||
attr("id", "ping-test-title")
|
||||
}) {
|
||||
Text("Backend Verbindungstest")
|
||||
}
|
||||
|
||||
Button(
|
||||
attrs = {
|
||||
classes(AppStylesheet.button, AppStylesheet.primaryButton)
|
||||
if (state is PingUiState.Loading) {
|
||||
attr("disabled", "")
|
||||
attr("aria-disabled", "true")
|
||||
}
|
||||
attr("aria-describedby", "ping-status")
|
||||
attr("type", "button")
|
||||
onClick { onTestConnection() }
|
||||
}
|
||||
) {
|
||||
if (state is PingUiState.Loading) {
|
||||
Span(attrs = { classes(AppStylesheet.spinner) }) {}
|
||||
Span(attrs = {
|
||||
classes(AppStylesheet.spinner)
|
||||
attr("aria-hidden", "true")
|
||||
}) {}
|
||||
Text(" Pinge Backend...")
|
||||
} else {
|
||||
Text("Ping Backend")
|
||||
}
|
||||
}
|
||||
|
||||
// Status display with four distinct states
|
||||
Div {
|
||||
// Status display with four distinct states and proper announcements
|
||||
Div(attrs = {
|
||||
attr("id", "ping-status")
|
||||
attr("role", "status")
|
||||
attr("aria-live", "polite")
|
||||
attr("aria-atomic", "true")
|
||||
}) {
|
||||
when (state) {
|
||||
is PingUiState.Initial -> {
|
||||
Div {
|
||||
Div(attrs = {
|
||||
attr("aria-label", "Bereit für Backend-Test")
|
||||
}) {
|
||||
Text("Klicke auf den Button, um das Backend zu testen")
|
||||
}
|
||||
}
|
||||
is PingUiState.Loading -> {
|
||||
Div {
|
||||
Span(attrs = { classes(AppStylesheet.spinner) }) {}
|
||||
Div(attrs = {
|
||||
attr("aria-label", "Backend wird getestet")
|
||||
}) {
|
||||
Span(attrs = {
|
||||
classes(AppStylesheet.spinner)
|
||||
attr("aria-hidden", "true")
|
||||
}) {}
|
||||
Text(" Pinge Backend ...")
|
||||
}
|
||||
}
|
||||
is PingUiState.Success -> {
|
||||
Div(attrs = { classes(AppStylesheet.successMessage) }) {
|
||||
Span { Text("✅ ") }
|
||||
Div(attrs = {
|
||||
classes(AppStylesheet.successMessage)
|
||||
attr("role", "alert")
|
||||
attr("aria-label", "Backend-Test erfolgreich")
|
||||
}) {
|
||||
Span(attrs = { attr("aria-hidden", "true") }) { Text("✅ ") }
|
||||
Text("Antwort vom Backend: ${state.response.status}")
|
||||
}
|
||||
}
|
||||
is PingUiState.Error -> {
|
||||
Div(attrs = { classes(AppStylesheet.errorMessage) }) {
|
||||
Span { Text("❌ ") }
|
||||
Div(attrs = {
|
||||
classes(AppStylesheet.errorMessage)
|
||||
attr("role", "alert")
|
||||
attr("aria-label", "Backend-Test fehlgeschlagen")
|
||||
}) {
|
||||
Span(attrs = { attr("aria-hidden", "true") }) { Text("❌ ") }
|
||||
Text("Fehler: ${state.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class MainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `AppStylesheet should be accessible`() {
|
||||
fun `AppStylesheet should be accessible and complete`() {
|
||||
// Test that AppStylesheet object is properly accessible
|
||||
assertNotNull(AppStylesheet, "AppStylesheet should be accessible")
|
||||
|
||||
@@ -33,6 +33,29 @@ class MainTest {
|
||||
assertNotNull(AppStylesheet.footer, "Footer style should be defined")
|
||||
assertNotNull(AppStylesheet.card, "Card style should be defined")
|
||||
assertNotNull(AppStylesheet.button, "Button style should be defined")
|
||||
|
||||
// Verify enhanced styles are present
|
||||
assertNotNull(AppStylesheet.primaryButton, "Primary button style should be defined")
|
||||
assertNotNull(AppStylesheet.successMessage, "Success message style should be defined")
|
||||
assertNotNull(AppStylesheet.errorMessage, "Error message style should be defined")
|
||||
assertNotNull(AppStylesheet.spinner, "Spinner style should be defined")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `button styles should include accessibility features`() {
|
||||
// Verify button styles include focus and interaction states
|
||||
assertNotNull(AppStylesheet.button, "Button style should be accessible")
|
||||
assertNotNull(AppStylesheet.buttonHover, "Button hover style should be defined")
|
||||
assertNotNull(AppStylesheet.buttonDisabled, "Button disabled style should be defined")
|
||||
assertTrue(true, "Button accessibility styles are properly configured")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `message styles should be properly configured`() {
|
||||
// Test that success and error message styles are available
|
||||
assertNotNull(AppStylesheet.successMessage, "Success message style should be accessible")
|
||||
assertNotNull(AppStylesheet.errorMessage, "Error message style should be accessible")
|
||||
assertTrue(true, "Message styles provide good user feedback")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user