Refine UI towards Apple-style card layout

This commit is contained in:
Dualmind-Assistant
2026-04-21 12:43:26 +00:00
parent a1ccd568b0
commit 8c4205f991
4 changed files with 244 additions and 83 deletions
+82 -14
View File
@@ -64,7 +64,7 @@ async function loadQuestions() {
questions.value = data.questions questions.value = data.questions
} catch (err) { } catch (err) {
console.error('Failed to load questions', err) console.error('Failed to load questions', err)
loadError.value = 'Konfiguration konnte nicht geladen werden.' loadError.value = 'Konfiguration konnte nicht geladen werden. Bitte prüfen, ob der Server läuft.'
} finally { } finally {
isLoadingConfig.value = false isLoadingConfig.value = false
} }
@@ -116,9 +116,13 @@ async function startSession() {
<template> <template>
<main class="app"> <main class="app">
<section class="shell">
<header class="header">
<h1>Triage-Fragen</h1> <h1>Triage-Fragen</h1>
<p class="subtitle">Schnelle Vorab-Erfassung für die Notaufnahme</p>
</header>
<section> <section class="block">
<LanguageSelect v-model="language" /> <LanguageSelect v-model="language" />
</section> </section>
@@ -131,7 +135,7 @@ async function startSession() {
</section> </section>
<template v-if="!isLoadingConfig && !loadError"> <template v-if="!isLoadingConfig && !loadError">
<section v-if="chiefComplaintQuestion"> <section v-if="chiefComplaintQuestion" class="block">
<SymptomSelector <SymptomSelector
v-model="chiefComplaint" v-model="chiefComplaint"
:title="chiefComplaintQuestion.title" :title="chiefComplaintQuestion.title"
@@ -139,7 +143,7 @@ async function startSession() {
/> />
</section> </section>
<section v-if="chiefComplaint && painQuestion"> <section v-if="chiefComplaint && painQuestion" class="block">
<PainSlider <PainSlider
v-model="pain" v-model="pain"
:title="painQuestion.title" :title="painQuestion.title"
@@ -159,7 +163,7 @@ async function startSession() {
{{ submitError }} {{ submitError }}
</section> </section>
<section v-if="result" class="result"> <section v-if="result" class="result block">
<h2>Vorbereitung für MTS</h2> <h2>Vorbereitung für MTS</h2>
<p> <p>
Sitzungs-ID: Sitzungs-ID:
@@ -179,22 +183,50 @@ async function startSession() {
</p> </p>
</section> </section>
</template> </template>
</section>
</main> </main>
</template> </template>
<style scoped> <style scoped>
.app { .app {
min-height: 100vh;
margin: 0;
padding: 1.5rem 1.25rem;
display: flex;
align-items: flex-start;
justify-content: center;
background: #f5f5f7;
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', sans-serif;
color: #111827;
}
.shell {
width: 100%;
max-width: 480px; max-width: 480px;
margin: 0 auto; background: #ffffff;
padding: 1rem; border-radius: 24px;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; box-shadow: 0 18px 40px rgba(0, 0, 0, 0.12);
padding: 1.75rem 1.5rem 2rem;
}
.header {
text-align: center;
margin-bottom: 1.5rem;
} }
h1 { h1 {
text-align: center; font-size: 1.6rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 0.25rem;
} }
section { .subtitle {
font-size: 0.9rem;
color: #6b7280;
}
.block {
margin-top: 1.5rem; margin-top: 1.5rem;
} }
@@ -204,12 +236,38 @@ section {
button.primary { button.primary {
width: 100%; width: 100%;
padding: 1rem; padding: 0.9rem 1rem;
font-size: 1.1rem; font-size: 1.05rem;
font-weight: 600;
border-radius: 999px;
border: none;
background: linear-gradient(135deg, #007aff, #0b84ff);
color: #ffffff;
box-shadow: 0 10px 20px rgba(0, 122, 255, 0.35);
cursor: pointer;
transition: transform 0.08s ease-out, box-shadow 0.08s ease-out, opacity 0.15s ease-out;
}
button.primary:hover:enabled {
transform: translateY(-1px);
box-shadow: 0 14px 26px rgba(0, 122, 255, 0.45);
}
button.primary:active:enabled {
transform: translateY(0);
box-shadow: 0 6px 14px rgba(0, 122, 255, 0.3);
}
button.primary:disabled {
opacity: 0.6;
cursor: default;
box-shadow: none;
} }
.status { .status {
margin-top: 1rem; margin-top: 1rem;
font-size: 0.9rem;
color: #4b5563;
} }
.status.error { .status.error {
@@ -218,8 +276,18 @@ button.primary {
.result { .result {
margin-top: 2rem; margin-top: 2rem;
padding: 1rem; padding: 1.25rem 1rem 1rem;
border-radius: 0.5rem; border-radius: 20px;
background: #f9fafb; background: #f9fafb;
} }
.result h2 {
font-size: 1.1rem;
margin-bottom: 0.75rem;
}
.result p {
margin-top: 0.25rem;
font-size: 0.95rem;
}
</style> </style>
+31 -5
View File
@@ -4,7 +4,7 @@ const modelValue = defineModel<string>()
const options = [ const options = [
{ code: 'de', label: 'Deutsch' }, { code: 'de', label: 'Deutsch' },
{ code: 'en', label: 'English' }, { code: 'en', label: 'English' },
{ code: 'ar', label: 'العربية' } { code: 'ar', label: 'العربية' },
] ]
function select(code: string) { function select(code: string) {
@@ -15,6 +15,7 @@ function select(code: string) {
<template> <template>
<div> <div>
<h2>Sprache auswählen</h2> <h2>Sprache auswählen</h2>
<p class="hint">Interface-Sprache für Fragen und Optionen</p>
<div class="grid"> <div class="grid">
<button <button
v-for="opt in options" v-for="opt in options"
@@ -31,18 +32,43 @@ function select(code: string) {
</template> </template>
<style scoped> <style scoped>
h2 {
font-size: 1rem;
margin-bottom: 0.1rem;
}
.hint {
font-size: 0.8rem;
color: #9ca3af;
margin-bottom: 0.75rem;
}
.grid { .grid {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.5rem; gap: 0.5rem;
} }
.lang-btn { .lang-btn {
padding: 0.75rem 0.5rem; padding: 0.55rem 0.5rem;
border-radius: 999px;
border: 1px solid #e5e7eb;
background: #f9fafb;
font-size: 0.85rem;
color: #111827;
cursor: pointer;
transition: background 0.12s ease-out, color 0.12s ease-out, border-color 0.12s ease-out,
box-shadow 0.12s ease-out, transform 0.08s ease-out;
}
.lang-btn:hover {
background: #f3f4f6;
} }
.lang-btn.active { .lang-btn.active {
background: #2563eb; background: #e5f0ff;
color: white; border-color: #3b82f6;
color: #0b1f4a;
box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2);
} }
</style> </style>
+49 -2
View File
@@ -24,17 +24,64 @@ function onInput(ev: Event) {
:value="modelValue" :value="modelValue"
@input="onInput" @input="onInput"
/> />
<div class="scale">
<span>{{ props.min }}</span>
<span>{{ props.max }}</span>
</div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
h2 {
font-size: 1rem;
margin-bottom: 0.25rem;
}
.value { .value {
text-align: center; text-align: center;
font-size: 1.5rem; font-size: 2rem;
margin-bottom: 0.5rem; font-weight: 600;
margin-bottom: 0.25rem;
color: #111827;
} }
input[type='range'] { input[type='range'] {
-webkit-appearance: none;
width: 100%; width: 100%;
height: 6px;
border-radius: 999px;
background: #e5e7eb;
outline: none;
}
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: #ffffff;
border: 2px solid #f97316;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
cursor: pointer;
margin-top: -9px;
}
input[type='range']::-moz-range-thumb {
width: 24px;
height: 24px;
border-radius: 50%;
background: #ffffff;
border: 2px solid #f97316;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.scale {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
color: #6b7280;
margin-top: 0.25rem;
} }
</style> </style>
+25 -5
View File
@@ -35,18 +35,38 @@ function select(value: string) {
</template> </template>
<style scoped> <style scoped>
h2 {
font-size: 1rem;
margin-bottom: 0.75rem;
}
.grid { .grid {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem; gap: 0.75rem;
} }
.symptom-btn { .symptom-btn {
padding: 1rem 0.5rem; padding: 0.85rem 0.75rem;
border-radius: 18px;
border: 1px solid #e5e7eb;
background: #f9fafb;
text-align: left;
font-size: 0.95rem;
color: #111827;
cursor: pointer;
transition: background 0.12s ease-out, border-color 0.12s ease-out, box-shadow 0.12s ease-out,
transform 0.08s ease-out;
}
.symptom-btn:hover {
background: #f3f4f6;
} }
.symptom-btn.active { .symptom-btn.active {
background: #16a34a; background: linear-gradient(145deg, #22c55e, #16a34a);
color: white; border-color: #16a34a;
color: #ffffff;
box-shadow: 0 10px 20px rgba(34, 197, 94, 0.35);
} }
</style> </style>