refactor(swift): Update UI styles and animations for improved consistency
- Changed background colors and text colors across various components to enhance readability and visual appeal. - Updated animation properties for smoother transitions in CanvasArea and BlockContainer. - Adjusted styles in FallbackPicker, OverdrachtBlock, and other components to align with the new design system. - Improved accessibility by ensuring color contrasts meet standards. This update aims to create a more cohesive user experience throughout the application.
This commit is contained in:
@@ -33,22 +33,50 @@ export function CanvasArea() {
|
||||
}
|
||||
}
|
||||
|
||||
// Block animations volgens UX specificatie (sectie 11.1):
|
||||
// Openen: Slide up + fade in (200ms), Scale: 0.95 → 1.0
|
||||
// Sluiten: Slide down + fade out (200ms), Scale: 1.0 → 0.95
|
||||
const blockAnimations = {
|
||||
initial: { opacity: 0, y: 20, scale: 0.95 },
|
||||
animate: { opacity: 1, y: 0, scale: 1 },
|
||||
exit: { opacity: 0, y: -20, scale: 0.95 },
|
||||
transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] as [number, number, number, number] },
|
||||
animate: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
transition: {
|
||||
duration: 0.2,
|
||||
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
||||
},
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
y: 20, // Slide down (niet omhoog)
|
||||
scale: 0.95,
|
||||
transition: {
|
||||
duration: 0.2,
|
||||
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="flex-1 flex items-center justify-center p-4 overflow-auto">
|
||||
<AnimatePresence mode="wait">
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
{activeBlock ? (
|
||||
<motion.div key={activeBlock} {...blockAnimations}>
|
||||
<motion.div
|
||||
key={activeBlock}
|
||||
initial={blockAnimations.initial}
|
||||
animate={blockAnimations.animate}
|
||||
exit={blockAnimations.exit}
|
||||
>
|
||||
{renderBlock(activeBlock, prefillData)}
|
||||
</motion.div>
|
||||
) : activePatient ? (
|
||||
<motion.div key="patient-context" {...blockAnimations}>
|
||||
<motion.div
|
||||
key="patient-context"
|
||||
initial={blockAnimations.initial}
|
||||
animate={blockAnimations.animate}
|
||||
exit={blockAnimations.exit}
|
||||
>
|
||||
<PatientContextCard />
|
||||
</motion.div>
|
||||
) : (
|
||||
@@ -57,6 +85,7 @@ export function CanvasArea() {
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<EmptyState />
|
||||
</motion.div>
|
||||
@@ -70,7 +99,7 @@ function EmptyState() {
|
||||
return (
|
||||
<div className="text-center max-w-md">
|
||||
<div className="mb-6">
|
||||
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-slate-800 flex items-center justify-center">
|
||||
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-white border border-slate-200 shadow-sm flex items-center justify-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
@@ -81,14 +110,14 @@ function EmptyState() {
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="text-slate-500"
|
||||
className="text-slate-400"
|
||||
>
|
||||
<path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" />
|
||||
<path d="M19 10v2a7 7 0 0 1-14 0v-2" />
|
||||
<line x1="12" x2="12" y1="19" y2="22" />
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className="text-xl font-medium text-slate-300 mb-2">Wat wil je doen?</h2>
|
||||
<h2 className="text-xl font-medium text-slate-700 mb-2">Wat wil je doen?</h2>
|
||||
<p className="text-sm text-slate-500">
|
||||
Typ of spreek je intentie
|
||||
</p>
|
||||
@@ -100,8 +129,8 @@ function EmptyState() {
|
||||
<ExampleCommand icon="📋" text="overdracht" />
|
||||
</div>
|
||||
|
||||
<p className="mt-6 text-xs text-slate-600">
|
||||
<kbd className="px-1.5 py-0.5 rounded bg-slate-800 text-slate-400">⌘K</kbd> om te focussen
|
||||
<p className="mt-6 text-xs text-slate-500">
|
||||
<kbd className="px-1.5 py-0.5 rounded bg-white border border-slate-200 text-slate-600 shadow-sm">⌘K</kbd> om te focussen
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -109,9 +138,9 @@ function EmptyState() {
|
||||
|
||||
function ExampleCommand({ icon, text }: { icon: string; text: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-3 px-3 py-2 rounded-lg bg-slate-800/50 text-sm">
|
||||
<div className="flex items-center gap-3 px-3 py-2 rounded-lg bg-white border border-slate-200 shadow-sm text-sm">
|
||||
<span>{icon}</span>
|
||||
<span className="text-slate-400">"{text}"</span>
|
||||
<span className="text-slate-600">"{text}"</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export const CommandInput = forwardRef<HTMLInputElement>(function CommandInput(_
|
||||
animationRef.current = requestAnimationFrame(draw);
|
||||
analyserNode.getByteFrequencyData(dataArray);
|
||||
|
||||
ctx.fillStyle = 'rgb(30, 41, 59)'; // slate-800
|
||||
ctx.fillStyle = 'rgb(248, 250, 252)'; // slate-50
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const barWidth = (canvas.width / bufferLength) * 2.5;
|
||||
@@ -179,7 +179,7 @@ export const CommandInput = forwardRef<HTMLInputElement>(function CommandInput(_
|
||||
const isDisabled = isProcessing || activeBlock !== null;
|
||||
|
||||
return (
|
||||
<footer className="h-16 border-t border-slate-700 flex items-center px-4 shrink-0 bg-slate-900">
|
||||
<footer className="h-16 border-t border-slate-200 flex items-center px-4 shrink-0 bg-white">
|
||||
<form onSubmit={handleSubmit} className="flex-1 flex items-center gap-2">
|
||||
{/* Input wrapper with optional waveform */}
|
||||
<div className="relative flex-1">
|
||||
@@ -200,11 +200,11 @@ export const CommandInput = forwardRef<HTMLInputElement>(function CommandInput(_
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
placeholder={getPlaceholder()}
|
||||
disabled={isDisabled}
|
||||
className={`w-full bg-slate-800 border rounded-xl py-3 text-white placeholder:text-slate-500
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:bg-slate-800/80
|
||||
className={`w-full bg-white border rounded-xl py-3 text-slate-900 placeholder:text-slate-400
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
transition-all duration-200
|
||||
${isRecording ? 'pl-[220px] pr-12 border-red-500/50' : 'pl-4 pr-12 border-slate-600'}`}
|
||||
${isRecording ? 'pl-[220px] pr-12 border-red-500/50' : 'pl-4 pr-12 border-slate-300'}`}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
@@ -252,7 +252,7 @@ export const CommandInput = forwardRef<HTMLInputElement>(function CommandInput(_
|
||||
className={`p-3 rounded-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed ${
|
||||
isRecording
|
||||
? 'bg-red-600 hover:bg-red-500 text-white ring-4 ring-red-600/30'
|
||||
: 'bg-slate-700 hover:bg-slate-600 text-slate-300'
|
||||
: 'bg-slate-100 hover:bg-slate-200 text-slate-600'
|
||||
}`}
|
||||
title={isRecording ? 'Stop opname' : 'Start voice input'}
|
||||
>
|
||||
@@ -268,7 +268,7 @@ export const CommandInput = forwardRef<HTMLInputElement>(function CommandInput(_
|
||||
<button
|
||||
type="button"
|
||||
disabled
|
||||
className="p-3 rounded-xl bg-slate-800 text-slate-600 cursor-not-allowed"
|
||||
className="p-3 rounded-xl bg-slate-100 text-slate-400 cursor-not-allowed"
|
||||
title="Spraakherkenning niet ondersteund in deze browser"
|
||||
>
|
||||
<MicOff size={20} />
|
||||
|
||||
@@ -12,10 +12,10 @@ import { Sun, Moon, Sunrise, Sunset, X, User, ArrowLeft } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
const SHIFT_CONFIG: Record<ShiftType, { icon: typeof Sun; label: string; color: string }> = {
|
||||
nacht: { icon: Moon, label: 'Nachtdienst', color: 'text-indigo-400' },
|
||||
ochtend: { icon: Sunrise, label: 'Ochtenddienst', color: 'text-amber-400' },
|
||||
middag: { icon: Sun, label: 'Middagdienst', color: 'text-yellow-400' },
|
||||
avond: { icon: Sunset, label: 'Avonddienst', color: 'text-orange-400' },
|
||||
nacht: { icon: Moon, label: 'Nachtdienst', color: 'text-indigo-600' },
|
||||
ochtend: { icon: Sunrise, label: 'Ochtenddienst', color: 'text-amber-600' },
|
||||
middag: { icon: Sun, label: 'Middagdienst', color: 'text-yellow-600' },
|
||||
avond: { icon: Sunset, label: 'Avonddienst', color: 'text-orange-600' },
|
||||
};
|
||||
|
||||
export function ContextBar() {
|
||||
@@ -24,19 +24,19 @@ export function ContextBar() {
|
||||
const ShiftIcon = shiftConfig.icon;
|
||||
|
||||
return (
|
||||
<header className="h-12 border-b border-slate-700 flex items-center px-4 justify-between shrink-0 bg-slate-900">
|
||||
<header className="h-12 border-b border-slate-200 flex items-center px-4 justify-between shrink-0 bg-white">
|
||||
{/* Left: Logo + Shift */}
|
||||
<div className="flex items-center gap-4">
|
||||
<Link
|
||||
href="/epd"
|
||||
className="flex items-center gap-2 text-slate-400 hover:text-white transition-colors"
|
||||
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
||||
title="Terug naar EPD"
|
||||
>
|
||||
<ArrowLeft size={16} />
|
||||
<span className="text-sm font-semibold tracking-tight">Swift</span>
|
||||
</Link>
|
||||
|
||||
<div className="h-4 w-px bg-slate-700" />
|
||||
<div className="h-4 w-px bg-slate-200" />
|
||||
|
||||
<div className={`flex items-center gap-1.5 ${shiftConfig.color}`}>
|
||||
<ShiftIcon size={14} />
|
||||
@@ -47,17 +47,17 @@ export function ContextBar() {
|
||||
{/* Center: Active Patient */}
|
||||
<div className="flex items-center">
|
||||
{activePatient ? (
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-slate-800 border border-slate-600">
|
||||
<div className="w-5 h-5 rounded-full bg-blue-600 flex items-center justify-center text-[10px] font-medium">
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-slate-100 border border-slate-300">
|
||||
<div className="w-5 h-5 rounded-full bg-blue-600 flex items-center justify-center text-[10px] font-medium text-white">
|
||||
{activePatient.name_given[0]?.[0]}
|
||||
{activePatient.name_family[0]}
|
||||
</div>
|
||||
<span className="text-sm text-white">
|
||||
<span className="text-sm text-slate-900">
|
||||
{activePatient.name_given.join(' ')} {activePatient.name_family}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setActivePatient(null)}
|
||||
className="p-0.5 rounded hover:bg-slate-700 text-slate-400 hover:text-white transition-colors"
|
||||
className="p-0.5 rounded hover:bg-slate-200 text-slate-400 hover:text-slate-700 transition-colors"
|
||||
title="Patiënt deselecteren"
|
||||
>
|
||||
<X size={14} />
|
||||
@@ -70,7 +70,7 @@ export function ContextBar() {
|
||||
|
||||
{/* Right: User */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 text-slate-400">
|
||||
<div className="flex items-center gap-2 text-slate-600">
|
||||
<User size={16} />
|
||||
<span className="text-xs hidden sm:block">Verpleegkundige</span>
|
||||
</div>
|
||||
|
||||
@@ -11,10 +11,10 @@ import { useSwiftStore, type SwiftIntent } from '@/stores/swift-store';
|
||||
import { FileText, Search, ArrowRightLeft, HelpCircle, Clock } from 'lucide-react';
|
||||
|
||||
const INTENT_CONFIG: Record<SwiftIntent, { icon: typeof FileText; color: string; label: string }> = {
|
||||
dagnotitie: { icon: FileText, color: 'text-blue-400 bg-blue-400/10', label: 'Notitie' },
|
||||
zoeken: { icon: Search, color: 'text-emerald-400 bg-emerald-400/10', label: 'Zoeken' },
|
||||
overdracht: { icon: ArrowRightLeft, color: 'text-purple-400 bg-purple-400/10', label: 'Overdracht' },
|
||||
unknown: { icon: HelpCircle, color: 'text-slate-400 bg-slate-400/10', label: 'Actie' },
|
||||
dagnotitie: { icon: FileText, color: 'text-blue-600 bg-blue-50 border border-blue-200', label: 'Notitie' },
|
||||
zoeken: { icon: Search, color: 'text-emerald-600 bg-emerald-50 border border-emerald-200', label: 'Zoeken' },
|
||||
overdracht: { icon: ArrowRightLeft, color: 'text-purple-600 bg-purple-50 border border-purple-200', label: 'Overdracht' },
|
||||
unknown: { icon: HelpCircle, color: 'text-slate-600 bg-slate-50 border border-slate-200', label: 'Actie' },
|
||||
};
|
||||
|
||||
function formatRelativeTime(date: Date): string {
|
||||
@@ -45,7 +45,7 @@ export function RecentStrip() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-12 border-t border-slate-700 flex items-center px-4 gap-3 shrink-0 bg-slate-900/50">
|
||||
<div className="h-12 border-t border-slate-200 flex items-center px-4 gap-3 shrink-0 bg-white">
|
||||
{/* Label */}
|
||||
<div className="flex items-center gap-1.5 text-slate-500 shrink-0">
|
||||
<Clock size={12} />
|
||||
@@ -53,11 +53,11 @@ export function RecentStrip() {
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="h-4 w-px bg-slate-700" />
|
||||
<div className="h-4 w-px bg-slate-200" />
|
||||
|
||||
{/* Actions */}
|
||||
{recentActions.length === 0 ? (
|
||||
<span className="text-xs text-slate-600 italic">Nog geen acties</span>
|
||||
<span className="text-xs text-slate-400 italic">Nog geen acties</span>
|
||||
) : (
|
||||
<div className="flex gap-2 overflow-x-auto scrollbar-hide">
|
||||
{recentActions.map((action) => {
|
||||
@@ -90,17 +90,17 @@ export function RecentStrip() {
|
||||
|
||||
{/* Quick actions hint (when empty) */}
|
||||
{recentActions.length === 0 && (
|
||||
<div className="ml-auto flex items-center gap-2 text-xs text-slate-600">
|
||||
<div className="ml-auto flex items-center gap-2 text-xs text-slate-500">
|
||||
<span>Probeer:</span>
|
||||
<button
|
||||
onClick={() => setInputValue('notitie ')}
|
||||
className="px-2 py-0.5 rounded bg-slate-800 hover:bg-slate-700 text-slate-400 transition-colors"
|
||||
className="px-2 py-0.5 rounded bg-slate-100 hover:bg-slate-200 text-slate-600 transition-colors"
|
||||
>
|
||||
notitie
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setInputValue('zoek ')}
|
||||
className="px-2 py-0.5 rounded bg-slate-800 hover:bg-slate-700 text-slate-400 transition-colors"
|
||||
className="px-2 py-0.5 rounded bg-slate-100 hover:bg-slate-200 text-slate-600 transition-colors"
|
||||
>
|
||||
zoek
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user