From d7b010fc1ee9baaf5af45df63ffdf9fce7dd0847 Mon Sep 17 00:00:00 2001 From: Harun CAN Date: Thu, 16 Apr 2026 14:16:57 +0200 Subject: [PATCH] main --- src/app/api/media/[...path]/route.ts | 47 +++++++++++++++++++ src/components/project/scene-card.tsx | 66 +++++++++++++++------------ 2 files changed, 83 insertions(+), 30 deletions(-) create mode 100644 src/app/api/media/[...path]/route.ts diff --git a/src/app/api/media/[...path]/route.ts b/src/app/api/media/[...path]/route.ts new file mode 100644 index 0000000..cab4244 --- /dev/null +++ b/src/app/api/media/[...path]/route.ts @@ -0,0 +1,47 @@ +import { NextRequest, NextResponse } from 'next/server'; + +/** + * Medya dosyalarını backend'den proxy eden API route. + * Docker konteyner içinde INTERNAL_API_URL üzerinden backend'e ulaşır. + * Tarayıcı /media/... isteklerini bu route üzerinden yönlendirir. + * + * URL formatı: /api/media/[projectId]/images/[filename] + */ +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ path: string[] }> } +) { + const { path } = await params; + const mediaPath = path.join('/'); + + // Docker içinde backend internal URL, yoksa localhost + const internalUrl = process.env.INTERNAL_API_URL; + const backendBase = internalUrl + ? internalUrl.replace(/\/api$/, '') + : 'http://localhost:3000'; + + const targetUrl = `${backendBase}/media/${mediaPath}`; + + try { + const response = await fetch(targetUrl); + + if (!response.ok) { + return new NextResponse(null, { status: response.status }); + } + + const buffer = await response.arrayBuffer(); + const contentType = response.headers.get('content-type') || 'application/octet-stream'; + + return new NextResponse(buffer, { + status: 200, + headers: { + 'Content-Type': contentType, + 'Cache-Control': 'public, max-age=86400, immutable', + 'Cross-Origin-Resource-Policy': 'cross-origin', + }, + }); + } catch (error) { + console.error(`Media proxy error: ${targetUrl}`, error); + return new NextResponse(null, { status: 502 }); + } +} diff --git a/src/components/project/scene-card.tsx b/src/components/project/scene-card.tsx index c70c4b7..311ee43 100644 --- a/src/components/project/scene-card.tsx +++ b/src/components/project/scene-card.tsx @@ -1,6 +1,7 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { createPortal } from 'react-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Pencil, Check, X, RefreshCw, Clock, ArrowRight, Wand2, Image as ImageIcon, Mic, Maximize2, Sparkles } from 'lucide-react'; @@ -43,6 +44,9 @@ export function SceneCard({ const [editNarration, setEditNarration] = useState(scene.narrationText); const [editVisual, setEditVisual] = useState(scene.visualPrompt); const [lightboxOpen, setLightboxOpen] = useState(false); + const [mounted, setMounted] = useState(false); + + useEffect(() => { setMounted(true); }, []); const handleSave = () => { onUpdate?.(scene.id, { @@ -97,8 +101,7 @@ export function SceneCard({
- - )} - + e.stopPropagation()} + /> + + + )} + , + document.body + )} ); }