Refine UI towards Apple-style card layout
This commit is contained in:
+139
-71
@@ -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,85 +116,117 @@ async function startSession() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="app">
|
<main class="app">
|
||||||
<h1>Triage-Fragen</h1>
|
<section class="shell">
|
||||||
|
<header class="header">
|
||||||
|
<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 v-if="isLoadingConfig" class="status">
|
||||||
|
Konfiguration wird geladen ...
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="loadError" class="status error">
|
||||||
|
{{ loadError }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<template v-if="!isLoadingConfig && !loadError">
|
||||||
|
<section v-if="chiefComplaintQuestion" class="block">
|
||||||
|
<SymptomSelector
|
||||||
|
v-model="chiefComplaint"
|
||||||
|
:title="chiefComplaintQuestion.title"
|
||||||
|
:options="chiefComplaintQuestion.options ?? []"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="chiefComplaint && painQuestion" class="block">
|
||||||
|
<PainSlider
|
||||||
|
v-model="pain"
|
||||||
|
:title="painQuestion.title"
|
||||||
|
:min="painQuestion.min ?? 0"
|
||||||
|
:max="painQuestion.max ?? 10"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="chiefComplaint" class="actions">
|
||||||
|
<button class="primary" type="button" :disabled="isSubmitting" @click="startSession">
|
||||||
|
<span v-if="!isSubmitting">Weiter</span>
|
||||||
|
<span v-else>Wird gesendet ...</span>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="submitError" class="status error">
|
||||||
|
{{ submitError }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-if="result" class="result block">
|
||||||
|
<h2>Vorbereitung für MTS</h2>
|
||||||
|
<p>
|
||||||
|
Sitzungs-ID:
|
||||||
|
<strong>{{ result.session_id }}</strong>
|
||||||
|
</p>
|
||||||
|
<p v-if="result.proposed_presenting_flowchart">
|
||||||
|
Vorgeschlagenes Flussdiagramm:
|
||||||
|
<strong>{{ result.proposed_presenting_flowchart }}</strong>
|
||||||
|
</p>
|
||||||
|
<p v-if="result.red_flag_indicators.length">
|
||||||
|
Red Flags:
|
||||||
|
<strong>{{ result.red_flag_indicators.join(', ') }}</strong>
|
||||||
|
</p>
|
||||||
|
<p v-if="result.suggested_priority_level">
|
||||||
|
Vorgeschlagene Priorität:
|
||||||
|
<strong>{{ result.suggested_priority_level }}</strong>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section v-if="isLoadingConfig" class="status">
|
|
||||||
Konfiguration wird geladen ...
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="loadError" class="status error">
|
|
||||||
{{ loadError }}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<template v-if="!isLoadingConfig && !loadError">
|
|
||||||
<section v-if="chiefComplaintQuestion">
|
|
||||||
<SymptomSelector
|
|
||||||
v-model="chiefComplaint"
|
|
||||||
:title="chiefComplaintQuestion.title"
|
|
||||||
:options="chiefComplaintQuestion.options ?? []"
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="chiefComplaint && painQuestion">
|
|
||||||
<PainSlider
|
|
||||||
v-model="pain"
|
|
||||||
:title="painQuestion.title"
|
|
||||||
:min="painQuestion.min ?? 0"
|
|
||||||
:max="painQuestion.max ?? 10"
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="chiefComplaint" class="actions">
|
|
||||||
<button class="primary" type="button" :disabled="isSubmitting" @click="startSession">
|
|
||||||
<span v-if="!isSubmitting">Weiter</span>
|
|
||||||
<span v-else>Wird gesendet ...</span>
|
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="submitError" class="status error">
|
|
||||||
{{ submitError }}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="result" class="result">
|
|
||||||
<h2>Vorbereitung für MTS</h2>
|
|
||||||
<p>
|
|
||||||
Sitzungs-ID:
|
|
||||||
<strong>{{ result.session_id }}</strong>
|
|
||||||
</p>
|
|
||||||
<p v-if="result.proposed_presenting_flowchart">
|
|
||||||
Vorgeschlagenes Flussdiagramm:
|
|
||||||
<strong>{{ result.proposed_presenting_flowchart }}</strong>
|
|
||||||
</p>
|
|
||||||
<p v-if="result.red_flag_indicators.length">
|
|
||||||
Red Flags:
|
|
||||||
<strong>{{ result.red_flag_indicators.join(', ') }}</strong>
|
|
||||||
</p>
|
|
||||||
<p v-if="result.suggested_priority_level">
|
|
||||||
Vorgeschlagene Priorität:
|
|
||||||
<strong>{{ result.suggested_priority_level }}</strong>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
</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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user