284 lines
11 KiB
TypeScript
284 lines
11 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState } from "react";
|
||
import { JournalPost, MoodType, PostType } from "./types";
|
||
import { MOODS } from "./mockData";
|
||
import { X, Feather, Sparkles, Tag, StickyNote, BookOpen, Code, Camera, Volume2, Check } from "lucide-react";
|
||
|
||
interface NewPostModalProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
onAddPost: (post: JournalPost) => void;
|
||
}
|
||
|
||
export const NewPostModal: React.FC<NewPostModalProps> = ({
|
||
isOpen,
|
||
onClose,
|
||
onAddPost,
|
||
}) => {
|
||
const [type, setType] = useState<PostType>("sticky");
|
||
const [mood, setMood] = useState<MoodType>("spark");
|
||
const [title, setTitle] = useState("");
|
||
const [content, setContent] = useState("");
|
||
const [marginNote, setMarginNote] = useState("");
|
||
const [tagInput, setTagInput] = useState("");
|
||
const [codeSnippet, setCodeSnippet] = useState("");
|
||
const [stampedText, setStampedText] = useState("KARALAMA");
|
||
|
||
if (!isOpen) return null;
|
||
|
||
const handleSubmit = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (!content.trim()) return;
|
||
|
||
const now = new Date();
|
||
const dateStr = now.toLocaleDateString("tr-TR", {
|
||
day: "2-digit",
|
||
month: "short",
|
||
year: "numeric",
|
||
}).toUpperCase();
|
||
|
||
const timeStr = now.toLocaleTimeString("tr-TR", {
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
});
|
||
|
||
const moodObj = MOODS.find((m) => m.id === mood) || MOODS[0];
|
||
const tags = tagInput
|
||
.split(",")
|
||
.map((t) => t.trim().replace(/^#/, ""))
|
||
.filter((t) => t.length > 0);
|
||
|
||
if (tags.length === 0) tags.push("yeni-not");
|
||
|
||
const newPost: JournalPost = {
|
||
id: `post-${Date.now()}`,
|
||
type,
|
||
date: dateStr,
|
||
timestamp: timeStr,
|
||
mood,
|
||
moodLabel: moodObj.label,
|
||
title: title.trim() ? title : undefined,
|
||
content,
|
||
marginNotes: marginNote.trim() ? [marginNote.trim()] : undefined,
|
||
tags,
|
||
likes: 1,
|
||
stampedText: stampedText || moodObj.stampText,
|
||
codeSnippet: type === "code" && codeSnippet.trim() ? codeSnippet : undefined,
|
||
codeLanguage: type === "code" ? "typescript" : undefined,
|
||
};
|
||
|
||
onAddPost(newPost);
|
||
// Reset form
|
||
setTitle("");
|
||
setContent("");
|
||
setMarginNote("");
|
||
setTagInput("");
|
||
setCodeSnippet("");
|
||
onClose();
|
||
};
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-xs animate-in fade-in duration-200">
|
||
<div
|
||
className="relative w-full max-w-xl notebook-sheet rounded-2xl p-6 sm:p-8 shadow-2xl border border-[#18181B]/15 max-h-[90vh] overflow-y-auto"
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
{/* Washi Tape across top */}
|
||
<div className="washi-tape washi-tape-rose top-[-10px] left-1/2 -translate-x-1/2 w-40" />
|
||
|
||
{/* Header */}
|
||
<div className="flex items-center justify-between pb-4 border-b border-[#18181B]/10 mb-5">
|
||
<div className="flex items-center gap-2.5">
|
||
<div className="w-8 h-8 rounded-full bg-[#E11D48] text-white flex items-center justify-center">
|
||
<Feather className="w-4 h-4" />
|
||
</div>
|
||
<div>
|
||
<h2 className="font-heading font-extrabold text-lg text-[#18181B]">
|
||
Yeni Düşünce Karala
|
||
</h2>
|
||
<p className="text-xs font-handwritten text-[#787D89] text-base leading-none">
|
||
Aklına gelen o saçma veya harika şeyi hemen kaydet
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
onClick={onClose}
|
||
title="Kapat"
|
||
aria-label="Kapat"
|
||
className="p-1.5 rounded-lg text-[#787D89] hover:text-[#18181B] hover:bg-[#18181B]/5 transition-colors cursor-pointer"
|
||
>
|
||
<X className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
|
||
<form onSubmit={handleSubmit} className="space-y-4">
|
||
{/* Format Selector */}
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1.5">
|
||
Not Formatı:
|
||
</label>
|
||
<div className="grid grid-cols-3 gap-2">
|
||
<button
|
||
type="button"
|
||
onClick={() => setType("sticky")}
|
||
className={`flex items-center justify-center gap-1.5 p-2 rounded-lg text-xs font-heading font-semibold border transition-all cursor-pointer ${
|
||
type === "sticky"
|
||
? "bg-[#FEF3C7] border-[#D97706] text-[#B45309] shadow-xs"
|
||
: "bg-[#FAF7F2] border-[#18181B]/10 text-[#52525B]"
|
||
}`}
|
||
>
|
||
<StickyNote className="w-3.5 h-3.5" />
|
||
<span>Post-it / Fikir</span>
|
||
</button>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setType("notebook")}
|
||
className={`flex items-center justify-center gap-1.5 p-2 rounded-lg text-xs font-heading font-semibold border transition-all cursor-pointer ${
|
||
type === "notebook"
|
||
? "bg-[#FAF7F2] border-[#18181B] text-[#18181B] shadow-xs font-bold"
|
||
: "bg-[#FAF7F2] border-[#18181B]/10 text-[#52525B]"
|
||
}`}
|
||
>
|
||
<BookOpen className="w-3.5 h-3.5" />
|
||
<span>Derin Yazı</span>
|
||
</button>
|
||
|
||
<button
|
||
type="button"
|
||
onClick={() => setType("code")}
|
||
className={`flex items-center justify-center gap-1.5 p-2 rounded-lg text-xs font-heading font-semibold border transition-all cursor-pointer ${
|
||
type === "code"
|
||
? "bg-[#1E232D] border-[#1E232D] text-white shadow-xs"
|
||
: "bg-[#FAF7F2] border-[#18181B]/10 text-[#52525B]"
|
||
}`}
|
||
>
|
||
<Code className="w-3.5 h-3.5" />
|
||
<span>Kod Kırıntısı</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Mood Selector */}
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1.5">
|
||
Ruh Hali (Mood):
|
||
</label>
|
||
<div className="flex items-center gap-2 overflow-x-auto pb-1 scrollbar-none">
|
||
{MOODS.filter((m) => m.id !== "all").map((m) => (
|
||
<button
|
||
key={m.id}
|
||
type="button"
|
||
onClick={() => setMood(m.id)}
|
||
className={`px-3 py-1.5 rounded-lg text-xs font-heading font-semibold shrink-0 border transition-all cursor-pointer ${
|
||
mood === m.id
|
||
? "bg-[#18181B] text-[#FAF7F2] border-[#18181B]"
|
||
: "bg-[#FAF7F2] text-[#52525B] border-[#18181B]/10 hover:bg-[#EFE7D6]"
|
||
}`}
|
||
>
|
||
{m.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Title (for notebook or code) */}
|
||
{type !== "sticky" && (
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1">
|
||
Başlık (Opsiyonel):
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={title}
|
||
onChange={(e) => setTitle(e.target.value)}
|
||
placeholder="Yazı veya karalama başlığı..."
|
||
className="w-full px-3 py-2 text-sm bg-white/80 border border-[#18181B]/15 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#E11D48]/30 font-serif"
|
||
/>
|
||
</div>
|
||
)}
|
||
|
||
{/* Main Content */}
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1">
|
||
Düşünce / İçerik:
|
||
</label>
|
||
<textarea
|
||
required
|
||
rows={4}
|
||
value={content}
|
||
onChange={(e) => setContent(e.target.value)}
|
||
placeholder="Aklındakileri dök... (Filtresiz ve dürüst)"
|
||
className="w-full px-3.5 py-2.5 text-sm bg-white/80 border border-[#18181B]/15 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#E11D48]/30 font-serif leading-relaxed"
|
||
/>
|
||
</div>
|
||
|
||
{/* Code Snippet (if code type) */}
|
||
{type === "code" && (
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1">
|
||
Kod Parçası:
|
||
</label>
|
||
<textarea
|
||
rows={3}
|
||
value={codeSnippet}
|
||
onChange={(e) => setCodeSnippet(e.target.value)}
|
||
placeholder="// const bug = fixLater();"
|
||
className="w-full px-3.5 py-2 text-xs font-mono bg-[#1E232D] text-emerald-400 border border-white/10 rounded-lg focus:outline-none"
|
||
/>
|
||
</div>
|
||
)}
|
||
|
||
{/* Margin Notes Input */}
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1">
|
||
El Yazısı Kenar Notu:
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={marginNote}
|
||
onChange={(e) => setMarginNote(e.target.value)}
|
||
placeholder="← tam olarak bu! / not al"
|
||
className="w-full px-3 py-1.5 text-sm bg-white/80 border border-[#18181B]/15 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#E11D48]/30 font-handwritten text-lg text-[#E11D48]"
|
||
/>
|
||
</div>
|
||
|
||
{/* Tags */}
|
||
<div>
|
||
<label className="block text-[11px] font-mono uppercase text-[#787D89] font-bold mb-1">
|
||
Etiketler (Virgülle ayırın):
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={tagInput}
|
||
onChange={(e) => setTagInput(e.target.value)}
|
||
placeholder="felsefe, gece, kahve, kod"
|
||
className="w-full px-3 py-1.5 text-xs bg-white/80 border border-[#18181B]/15 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#E11D48]/30 font-mono"
|
||
/>
|
||
</div>
|
||
|
||
{/* Actions */}
|
||
<div className="flex items-center justify-end gap-2.5 pt-3 border-t border-[#18181B]/10">
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
className="px-4 py-2 rounded-lg text-xs font-heading font-semibold text-[#52525B] hover:bg-[#18181B]/5 transition-colors cursor-pointer"
|
||
>
|
||
Vazgeç
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
className="flex items-center gap-1.5 px-5 py-2 rounded-lg bg-[#E11D48] text-white text-xs font-heading font-bold hover:bg-[#9F1239] shadow-sm transition-all cursor-pointer"
|
||
>
|
||
<Feather className="w-3.5 h-3.5" />
|
||
<span>Deftere Ekle</span>
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|