"use client"; import React, { useState } from "react"; import { JournalPost } from "./types"; import { Heart, MessageSquare, Tag, Play, Pause, Maximize2, Terminal, Volume2, CornerDownRight, Check, Sparkles } from "lucide-react"; interface JournalCardProps { post: JournalPost; onOpenDetail: (post: JournalPost) => void; onTagClick: (tag: string) => void; } export const JournalCard: React.FC = ({ post, onOpenDetail, onTagClick, }) => { const [likes, setLikes] = useState(post.likes); const [hasLiked, setHasLiked] = useState(false); const [isPlayingAudio, setIsPlayingAudio] = useState(false); const [stampFeedback, setStampFeedback] = useState(false); const audioRef = React.useRef(null); const audioContextRef = React.useRef(null); const synthTimerRef = React.useRef(null); React.useEffect(() => { return () => { if (audioRef.current) { audioRef.current.pause(); } if (synthTimerRef.current) { clearInterval(synthTimerRef.current); } if (audioContextRef.current) { audioContextRef.current.close().catch(() => {}); } }; }, []); const handleLike = (e: React.MouseEvent) => { e.stopPropagation(); if (!hasLiked) { setLikes((prev) => prev + 1); setHasLiked(true); setStampFeedback(true); setTimeout(() => setStampFeedback(false), 1200); } else { setLikes((prev) => prev - 1); setHasLiked(false); } }; const toggleAudio = (e: React.MouseEvent) => { e.stopPropagation(); if (isPlayingAudio) { stopAudio(); } else { startAudio(); } }; const stopAudio = () => { if (audioRef.current) { audioRef.current.pause(); } if (synthTimerRef.current) { clearInterval(synthTimerRef.current); synthTimerRef.current = null; } if (audioContextRef.current) { audioContextRef.current.close().catch(() => {}); audioContextRef.current = null; } setIsPlayingAudio(false); }; const startAudio = () => { if (post.audioUrl) { if (!audioRef.current) { audioRef.current = new Audio(post.audioUrl); audioRef.current.onended = () => setIsPlayingAudio(false); audioRef.current.onpause = () => setIsPlayingAudio(false); } audioRef.current.play() .then(() => setIsPlayingAudio(true)) .catch(() => playSynthFallback()); } else { playSynthFallback(); } }; const playSynthFallback = () => { try { const AudioCtx = window.AudioContext || (window as any).webkitAudioContext; if (!AudioCtx) { setIsPlayingAudio(true); return; } const ctx = new AudioCtx(); audioContextRef.current = ctx; setIsPlayingAudio(true); const notes = [261.63, 293.66, 329.63, 392.00, 440.00, 523.25]; let noteIdx = 0; const playNextNote = () => { if (!audioContextRef.current || ctx.state === "closed") return; const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.type = "sine"; osc.frequency.setValueAtTime(notes[noteIdx % notes.length], ctx.currentTime); gain.gain.setValueAtTime(0.06, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.5); osc.connect(gain); gain.connect(ctx.destination); osc.start(); osc.stop(ctx.currentTime + 0.5); noteIdx++; }; playNextNote(); synthTimerRef.current = setInterval(playNextNote, 450); } catch (e) { setIsPlayingAudio(true); } }; // Render format based on type if (post.type === "sticky") { return (
onOpenDetail(post)} className="group relative bg-[#FEF3C7] border border-[#D97706]/20 p-5 sm:p-6 rounded-lg shadow-sm hover:shadow-md transition-all duration-300 transform hover:-translate-y-1 rotate-[-1deg] cursor-pointer flex flex-col justify-between" > {/* Washi Tape across top */}
{/* Header */}
{post.date} • {post.timestamp} {post.stampedText && ( {post.stampedText} )}
{/* Content */}

“{post.content}”

{/* Margin Notes */} {post.marginNotes && post.marginNotes.length > 0 && (
{post.marginNotes.map((note, idx) => (
{note}
))}
)}
{/* Footer */}
{post.tags.map((tag) => ( ))}
); } if (post.type === "polaroid") { return (
onOpenDetail(post)} className="group relative bg-[#FAF7F2] border border-[#18181B]/12 p-3 sm:p-4 rounded-sm shadow-sm hover:shadow-lg transition-all duration-300 transform hover:rotate-[0.5deg] rotate-[1deg] cursor-pointer" > {/* Washi Tape */}
{/* Image Container */}
{post.imageUrl && ( {post.imageCaption )}
{post.date}
{/* Polaroid Handwritten Caption */}
{post.imageCaption || post.content}

{post.content}

{/* Margin Note */} {post.marginNotes && post.marginNotes.length > 0 && (
{post.marginNotes[0]}
)} {/* Footer */}
{post.tags.map((tag) => ( ))}
); } if (post.type === "code") { return (
onOpenDetail(post)} className="group relative bg-[#1E232D] text-[#FAF7F2] p-5 sm:p-6 rounded-xl shadow-md hover:shadow-xl transition-all duration-300 border border-white/10 cursor-pointer" > {/* Terminal Header */}
{post.title || "terminal_scrap.rs"}
{post.codeLanguage || "code"}
{/* Snippet */} {post.codeSnippet && (
            {post.codeSnippet}
          
)} {/* Narrative */}

{post.content}

{/* Handwritten Margin Note on Dark Card */} {post.marginNotes && post.marginNotes.length > 0 && (
>> {post.marginNotes.join(" • ")}
)} {/* Footer */}
{post.tags.map((tag) => ( ))}
); } if (post.type === "audio") { return (
onOpenDetail(post)} className="group relative bg-[#F3ECE2] border border-[#18181B]/12 p-5 sm:p-6 rounded-xl shadow-sm hover:shadow-md transition-all duration-300 cursor-pointer" > {/* Brass clip top right */}
{/* Header */}
SES KAYDI • {post.date} {post.audioDuration || "01:00"}
{/* Cassette Tape Mockup */}
{post.audioTitle || "voice_note.m4a"}
{/* Animated Audio Bars */}
{[40, 75, 30, 90, 60, 85, 45, 95, 35, 70, 50, 80, 65, 40].map((h, i) => (
))}

{post.content}

{post.marginNotes && post.marginNotes.length > 0 && (
* {post.marginNotes[0]}
)} {/* Footer */}
{post.tags.map((tag) => ( ))}
); } // Default: Field Notebook Page (Longform / Deep Note) return (
onOpenDetail(post)} className="group relative notebook-sheet rounded-xl p-5 sm:p-7 shadow-sm hover:shadow-lg transition-all duration-300 border border-[#18181B]/10 cursor-pointer" > {/* Top Binder Clip */}
{/* Header with stamped date and mood badge */}
{post.date} • {post.timestamp} {post.moodLabel}
{post.title && (

{post.title}

)}
{post.stampedText && ( {post.stampedText} )}
{/* Body with Highlighter markers */}

{post.content}

{/* Marginalia & Handwritten Comments */} {post.marginNotes && post.marginNotes.length > 0 && (
Kenar Notları:
{post.marginNotes.map((note, idx) => (
{note}
))}
)} {/* Footer */}
{post.tags.map((tag) => ( ))}
Oku
); };