diff --git a/src/app/api/memories/route.ts b/src/app/api/memories/route.ts
index 51b6d49..280171b 100644
--- a/src/app/api/memories/route.ts
+++ b/src/app/api/memories/route.ts
@@ -20,11 +20,7 @@ export async function GET() {
}
export async function POST(req: NextRequest) {
- if (!isAdmin()) {
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
- }
-
- const { title, content } = await req.json()
+ const { title, content, author } = await req.json()
if (!title?.trim() || !content?.trim()) {
return NextResponse.json(
{ error: 'Titel und Inhalt sind erforderlich' },
@@ -34,8 +30,8 @@ export async function POST(req: NextRequest) {
const db = getDb()
const result = db
- .prepare('INSERT INTO memories (title, content) VALUES (?, ?)')
- .run(title.trim(), content.trim())
+ .prepare('INSERT INTO memories (title, content, author) VALUES (?, ?, ?)')
+ .run(title.trim(), content.trim(), author?.trim() || null)
const memory = db
.prepare('SELECT * FROM memories WHERE id = ?')
.get(result.lastInsertRowid)
diff --git a/src/app/globals.css b/src/app/globals.css
index 7984efe..a93c326 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -19,6 +19,27 @@
}
@layer utilities {
+ /* Film grain overlay */
+ .grain-overlay {
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='1'/%3E%3C/svg%3E");
+ background-size: 200px 200px;
+ animation: grain 0.8s steps(1) infinite;
+ }
+
+ @keyframes grain {
+ 0% { background-position: 0 0; }
+ 10% { background-position: -50px -30px; }
+ 20% { background-position: 30px -60px; }
+ 30% { background-position: -70px 20px; }
+ 40% { background-position: 60px -10px; }
+ 50% { background-position: -20px 50px; }
+ 60% { background-position: 40px 30px; }
+ 70% { background-position: -60px -40px; }
+ 80% { background-position: 20px 60px; }
+ 90% { background-position: -40px -20px; }
+ 100% { background-position: 0 0; }
+ }
+
/* Custom scrollbar */
::-webkit-scrollbar {
width: 5px;
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 16295b2..67dcdc0 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -4,6 +4,7 @@ import HeroSection from '@/components/HeroSection'
import PhotoSlideshow from '@/components/PhotoSlideshow'
import PhotoGallery from '@/components/PhotoGallery'
import MemorySection from '@/components/MemorySection'
+import WriteSection from '@/components/WriteSection'
import MusicPlayer from '@/components/MusicPlayer'
import VideoGallery from '@/components/VideoGallery'
@@ -81,6 +82,9 @@ export default async function HomePage() {
)}
+ {/* Write section – public */}
+
+
In liebevoller Erinnerung
-+
29. November 1944
-+
— 10. Februar 2026 —
{formatDate(memory.created_at)} + {memory.author && ( + — {memory.author} + )}
))} diff --git a/src/components/WriteSection.tsx b/src/components/WriteSection.tsx new file mode 100644 index 0000000..3c3459a --- /dev/null +++ b/src/components/WriteSection.tsx @@ -0,0 +1,187 @@ +'use client' + +import { useState } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { PenLine, CheckCircle } from 'lucide-react' +import { useRouter } from 'next/navigation' + +export default function WriteSection() { + const router = useRouter() + const [open, setOpen] = useState(false) + const [name, setName] = useState('') + const [title, setTitle] = useState('') + const [content, setContent] = useState('') + const [submitting, setSubmitting] = useState(false) + const [done, setDone] = useState(false) + const [error, setError] = useState('') + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + if (!title.trim() || !content.trim()) { + setError('Bitte Titel und Text ausfüllen.') + return + } + setError('') + setSubmitting(true) + try { + const res = await fetch('/api/memories', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ title, content, author: name || null }), + }) + if (!res.ok) throw new Error('Fehler beim Speichern') + setDone(true) + router.refresh() + setTimeout(() => { + setDone(false) + setOpen(false) + setName('') + setTitle('') + setContent('') + }, 2800) + } catch { + setError('Etwas ist schiefgelaufen. Bitte nochmal versuchen.') + } finally { + setSubmitting(false) + } + } + + return ( +
+ Hast du eine Erinnerung,
die du teilen möchtest?
+
+ Danke für deine Worte. +
++ Deine Erinnerung wurde gespeichert. +
+