import React, { useState } from 'react'; import { CardItem } from '../types'; import { getShadowStyle } from '../utils/lighting'; import { Fastener, Stamp, PhotoCorners } from './Fastener'; import { Pencil, Globe, ExternalLink } from 'lucide-react'; interface PaperCardProps { card: CardItem; lightAngle: number; isDragging: boolean; isLocked?: boolean; onPointerDown: (e: React.PointerEvent, card: CardItem) => void; onDoubleClick: (card: CardItem) => void; onToggleTodo?: (cardId: string, index: number) => void; } export const PaperCard: React.FC = ({ card, lightAngle, isDragging, isLocked = false, onPointerDown, onDoubleClick, onToggleTodo }) => { const [isHovered, setIsHovered] = useState(false); // Get dynamic shadow based on light angle and drag state const shadowStyle = getShadowStyle( lightAngle, isDragging, isHovered ? 1.25 : 1.0, card.type === 'sticky' ); return (
onPointerDown(e, card)} onDoubleClick={() => onDoubleClick(card)} onClick={(e) => { if (isLocked && card.type === 'bookmark' && card.url) { e.stopPropagation(); window.open(card.url.startsWith('http') ? card.url : `https://${card.url}`, '_blank', 'noopener,noreferrer'); } }} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > {/* Top Attachment (Washi tape, pin, or paperclip) */} {/* Main Paper Body */}
{/* Subtle Paper Grain Filter Overlay */}
{/* Quick Edit button for Mobile & Hover */} {/* Paper Corner Curled Illusion for Sticky Notes */} {card.type === 'sticky' && (
)} {/* Rubber Stamp */} {/* 1. POLAROID CARD */} {card.type === 'polaroid' && (
{card.imageUrl ? ( {card.title ) : (
No Image
)} {/* Glossy photo finish sheen */}
{card.photoCaption || card.title}
)} {/* 2. STICKY NOTE */} {card.type === 'sticky' && (
{card.title && (
{card.title}
)} {card.todoItems && card.todoItems.length > 0 ? (
{card.todoItems.map((item, idx) => (
{ e.stopPropagation(); onToggleTodo?.(card.id, idx); }} > {item.text}
))}
) : (
{card.content}
)} {card.date && (
{card.date}
)}
)} {/* 3. KRAFT LUGGAGE / PARCEL TAG */} {card.type === 'tag' && (
{/* Tag string & brass eyelet */}
{card.tagNumber || card.subtitle || '#TAG'}
{card.title && (
{card.title}
)} {card.content && (
{card.content}
)} {card.date && (
{card.date}
)}
PRIORITY PARCEL
)} {/* 4. TORN PAPER / LETTER */} {card.type === 'torn' && (
{card.title || 'Memo'} {card.date || 'Fri — late'}
{card.subtitle && (
{card.subtitle}
)} {card.todoItems && card.todoItems.length > 0 ? (
{card.todoItems.map((item, idx) => (
{ e.stopPropagation(); onToggleTodo?.(card.id, idx); }} > {item.text}
))}
) : (
{card.content}
)}
NOTES // LOG CONFIDENTIAL
)} {/* 5. MINIMAL BUSINESS CARD */} {card.type === 'business' && (
[ JL ]
{card.title || 'JULES LAURENT'}
{card.subtitle || 'PRODUCT DESIGNER'}
{card.content}
)} {/* 6. STORE RECEIPT */} {card.type === 'receipt' && (
{card.title || 'MALL STORE'}
{card.subtitle}
{card.date || '10/24 15:34'}
{card.receiptItems?.map((it, idx) => (
= (card.receiptItems?.length || 0) - 2 ? 'font-bold' : ''}> {it.name} {it.price}
))}
{/* Barcode representation */}
{[2, 1, 3, 1, 2, 4, 1, 3, 2, 1, 3, 1, 2, 1, 4, 2, 1, 3, 2, 1].map((w, i) => (
))}
* 8 4 9 2 0 1 8 5 *
)} {/* 7. GRAPH / WIREFRAME SKETCH */} {card.type === 'graph' && (
{card.title} Fig. 1A
{/* SVG Hand-drawn Charts */}
{card.graphType === 'barchart' && ( {/* Hatched bars */} )} {card.graphType === 'flowchart' && ( INPUT TRANS {/* Branch down */} OUTPUT )} {card.graphType === 'curve' && ( )}
scale 1:1 · mm
)} {/* 8. MOODBOARD CARD */} {card.type === 'moodboard' && (
{card.title || 'Moodboard'}
{card.content}
{card.subtitle || 'Creative Direction'} #mood
)} {/* 9. BOOKMARK / WEB PREVIEW CARD */} {card.type === 'bookmark' && (
{/* Header: Favicon + Domain + External Link */}
{card.faviconUrl ? ( ) : ( )} {card.url ? (() => { try { return new URL(card.url.startsWith('http') ? card.url : `https://${card.url}`).hostname.replace('www.', ''); } catch { return 'link'; } })() : 'bookmark'}
{card.url && ( e.stopPropagation()} className="p-1 rounded bg-neutral-200/60 hover:bg-amber-400 hover:text-black text-neutral-600 transition shrink-0" title="Open link in new window" > )}
{/* Thumbnail Preview Image */}
{ if (card.url) { e.stopPropagation(); window.open(card.url.startsWith('http') ? card.url : `https://${card.url}`, '_blank', 'noopener,noreferrer'); } }} > {card.imageUrl ? ( {card.title ) : (
Web Snapshot
)} {/* Hover visit pill */}
Visit
{/* Title & Description */}

{ if (card.url) { e.stopPropagation(); window.open(card.url.startsWith('http') ? card.url : `https://${card.url}`, '_blank', 'noopener,noreferrer'); } }} > {card.title || card.url || 'Web Bookmark'}

{card.content && (

{card.content}

)}
{card.url && (
{card.url} ↗
)}
)} {/* 10. INTERACTIVE CHECKLIST CARD */} {card.type === 'checklist' && (
{card.title || 'To-Do List'} {card.todoItems && card.todoItems.length > 0 && ( {card.todoItems.filter((t) => t.done).length}/{card.todoItems.length} )}
{card.todoItems && card.todoItems.length > 0 ? (
{card.todoItems.map((item, idx) => (
{ e.stopPropagation(); onToggleTodo?.(card.id, idx); }} > {item.text}
))}
) : (
{card.content || 'No tasks listed'}
)}
CHECKLIST {card.date || 'PENDING'}
)} {/* 11. VINTAGE TICKET / BOARDING PASS */} {card.type === 'ticket' && (
{card.subtitle || 'PASS // TICKET'} NO. {card.tagNumber || '78429'}
{card.title || 'BOARDING PASS'}
{card.content || 'ADMIT ONE · GENERAL ACCESS'}
{card.date && (
{card.date}
)}
{/* Perforated barcode tear stub */}
{[1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 3, 1, 2, 1, 3].map((w, i) => (
))}
★ NON-TRANSFERABLE ★
)}
); };