feat(swift): implementeer ArtifactContainer met tabs (E4.S1)
Epic 4 Story 1 compleet: Basis structuur voor meerdere artifacts met tabs.
E4.S1 - ArtifactContainer Component (5 SP)
- Artifact interface gedefineerd in store
- ArtifactTab component met active state en close button
- ArtifactContainer met conditional tab rendering
- Helper functies voor artifact rendering en titels
Nieuwe Components:
- components/swift/artifacts/artifact-tab.tsx (60 regels)
- Tab UI met title, active state, close button
- Hover effects en opacity animations
- Min/max width, title truncation met tooltip
- Stop propagation op close click
- components/swift/artifacts/artifact-container.tsx (127 regels)
- Props: artifacts[], activeArtifactId, onSelect, onClose
- Tabs alleen bij >1 artifact
- renderArtifactBlock(): switch op artifact type
- getArtifactTitle(): user-friendly titles met patient naam
- Placeholder state wanneer geen artifacts
Artifact Interface:
```typescript
interface Artifact {
id: string;
type: BlockType;
prefill: BlockPrefillData;
title: string;
createdAt: Date;
}
```
Features:
- Tab rendering: alleen bij meerdere artifacts
- Active tab styling: amber-500 border bottom
- Close button: opacity 0 → 100 on hover/active
- Title generation: "Dagnotitie - Jan" voor context
- Block rendering: dagnotitie, zoeken, overdracht, fallback
- Placeholder: "Artifacts verschijnen hier" met voorbeelden
- Responsive: min-w-[140px] max-w-[200px] per tab
Tab Styling:
- Active: bg-white + border-b-2 border-b-amber-500
- Hover: bg-slate-50
- Close button: group-hover:opacity-100
- Text: text-sm font-medium truncate
Build Status:
- ✅ pnpm build succesvol (geen type errors)
- Alleen bekende warnings (Supabase realtime, useCallback)
Note: E4.S1 definieert structuur. E4.S2 voegt store management toe
(openArtifacts[], activeArtifactId, openArtifact(), closeArtifact()).
Voortgang: 53 SP / 85 SP (62%) - 17/31 stories compleet, 2 geskipt
Next: E4.S2 (Artifact lifecycle management) - Store state & actions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
63
components/swift/artifacts/artifact-tab.tsx
Normal file
63
components/swift/artifacts/artifact-tab.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Artifact Tab Component
|
||||
*
|
||||
* Tab voor een individueel artifact in de ArtifactContainer.
|
||||
* Toont titel, close button, en active state.
|
||||
*
|
||||
* Epic: E4 (Artifact Area & Tabs)
|
||||
* Story: E4.S1 (ArtifactContainer component)
|
||||
*/
|
||||
|
||||
import { X } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { Artifact } from '@/stores/swift-store';
|
||||
|
||||
interface ArtifactTabProps {
|
||||
artifact: Artifact;
|
||||
isActive: boolean;
|
||||
onSelect: (id: string) => void;
|
||||
onClose: (id: string) => void;
|
||||
}
|
||||
|
||||
export function ArtifactTab({ artifact, isActive, onSelect, onClose }: ArtifactTabProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'group flex items-center gap-2 px-4 py-2.5 border-r border-slate-200 cursor-pointer transition-colors',
|
||||
'hover:bg-slate-50 min-w-[140px] max-w-[200px]',
|
||||
isActive && 'bg-white border-b-2 border-b-amber-500'
|
||||
)}
|
||||
onClick={() => onSelect(artifact.id)}
|
||||
>
|
||||
{/* Tab title */}
|
||||
<span
|
||||
className={cn(
|
||||
'flex-1 text-sm font-medium truncate',
|
||||
isActive ? 'text-slate-900' : 'text-slate-600'
|
||||
)}
|
||||
title={artifact.title}
|
||||
>
|
||||
{artifact.title}
|
||||
</span>
|
||||
|
||||
{/* Close button */}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClose(artifact.id);
|
||||
}}
|
||||
className={cn(
|
||||
'p-0.5 rounded hover:bg-slate-200 text-slate-400 hover:text-slate-700 transition-colors',
|
||||
'opacity-0 group-hover:opacity-100',
|
||||
isActive && 'opacity-100'
|
||||
)}
|
||||
title="Sluiten"
|
||||
aria-label={`Sluit ${artifact.title}`}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user