git commit -m "feat(swift): implement Epic 3 - P1 Blocks (E3.S0-S6)" -m "Epic 3 compleet: Alle P1 blocks geïmplementeerd met volledige functionaliteit." -m "E3.S0 - CanvasArea block rendering" -m "- Switch/case voor block types met prefill data" -m "- AnimatePresence voor smooth transitions" -m "- PatientContextCard auto-display wanneer activePatient is gezet" -m "" -m "E3.S1 - Block Container animaties" -m "- Framer Motion animaties voor container, content en close button" -m "- Stagger effecten voor content children" -m "- Hover/tap animaties voor close button" -m "" -m "E3.S2 - DagnotatieBlock" -m "- Patient search met debounced FHIR API integratie" -m "- Category selector (medicatie, adl, gedrag, incident, observatie)" -m "- Textarea met character counter (max 500)" -m "- Opslaan naar /api/reports met validatie en error handling" -m "" -m "E3.S3 - Patient search API" -m "- GET /api/patients/search?q= met fuzzy search" -m "- Match score berekening voor resultaten" -m "- Auth check en error handling" -m "" -m "E3.S4 - ZoekenBlock" -m "- Debounced patient search met dropdown" -m "- Patient selectie → setActivePatient in store" -m "- Auto-close na selectie + recent action" -m "" -m "E3.S5 - PatientContextCard" -m "- Auto-open na patient selectie" -m "- Notities, vitals, diagnoses en risico's secties" -m "- API integratie met /api/overdracht/[patientId]" -m "" -m "E3.S6 - OverdrachtBlock" -m "- Lijst van patiënten met activiteit" -m "- Period selector (1d, 3d, 7d, 14d)" -m "- AI samenvatting generatie per patiënt" -m "- Aandachtspunten en actiepunten weergave" -m "" -m "Technische verbeteringen:" -m "- Technische debt opgelost: BlockContainer animaties, CanvasArea rendering" -m "- PatientContextCard toegevoegd aan blocks" -m "- Alle blocks gebruiken BlockContainer voor consistente styling" -m "" -m "Voortgang: 56 SP / 72 SP (78%) - Epic 3 compleet"
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
import { motion, type Variants } from 'framer-motion';
|
||||
import { X } from 'lucide-react';
|
||||
import { useSwiftStore } from '@/stores/swift-store';
|
||||
import type { BlockSize } from '@/lib/swift/types';
|
||||
@@ -24,27 +25,83 @@ const SIZE_CLASSES: Record<BlockSize, string> = {
|
||||
full: 'max-w-4xl',
|
||||
};
|
||||
|
||||
// Container animations
|
||||
const containerVariants: Variants = {
|
||||
initial: { scale: 0.98, opacity: 0 },
|
||||
animate: {
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
transition: {
|
||||
duration: 0.2,
|
||||
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Content stagger animation
|
||||
const contentVariants: Variants = {
|
||||
initial: { opacity: 0, y: 10 },
|
||||
animate: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 0.1,
|
||||
duration: 0.2,
|
||||
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Close button hover animation
|
||||
const closeButtonVariants = {
|
||||
rest: { scale: 1, rotate: 0 },
|
||||
hover: { scale: 1.1, rotate: 90 },
|
||||
tap: { scale: 0.95 },
|
||||
};
|
||||
|
||||
export function BlockContainer({ title, size = 'md', children }: BlockContainerProps) {
|
||||
const { closeBlock } = useSwiftStore();
|
||||
|
||||
return (
|
||||
<div
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
className={`w-full ${SIZE_CLASSES[size]} bg-slate-800 rounded-xl border border-slate-700 shadow-2xl`}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-4 py-3 border-b border-slate-700">
|
||||
<h2 className="text-lg font-medium text-white">{title}</h2>
|
||||
<button
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.05, duration: 0.2 }}
|
||||
className="text-lg font-medium text-white"
|
||||
>
|
||||
{title}
|
||||
</motion.h2>
|
||||
<motion.button
|
||||
onClick={closeBlock}
|
||||
variants={closeButtonVariants}
|
||||
initial="rest"
|
||||
whileHover="hover"
|
||||
whileTap="tap"
|
||||
className="p-1 rounded hover:bg-slate-700 text-slate-400 hover:text-white transition-colors"
|
||||
title="Sluiten (Esc)"
|
||||
aria-label="Block sluiten"
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</motion.button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4">{children}</div>
|
||||
</div>
|
||||
<motion.div
|
||||
variants={contentVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
className="p-4"
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user