import React, { useState, useRef, useEffect } from 'react'; import { Menu, X, Upload, ZoomIn, Undo2, Save, Search, PlusCircle, Image as ImageIcon, Lock, Globe, DollarSign, Store, LayoutGrid, Edit3 } from 'lucide-react'; // --- COMPONENTES PRINCIPALES --- export default function App() { const [activeTab, setActiveTab] = useState('editor'); // editor, catalog, store const [isMenuOpen, setIsMenuOpen] = useState(false); const [cards, setCards] = useState([]); // Almacenará las cartas del usuario // Navegación const navItems = [ { id: 'editor', label: 'Editor & Vista Previa', icon: Edit3 }, { id: 'catalog', label: 'Mi Catálogo', icon: LayoutGrid }, { id: 'store', label: 'Tienda Digital', icon: Store }, ]; return (
{/* HEADER / NAVEGACIÓN */}
{/* Logo y Branding */} {/* Navegación Desktop */} {/* Botón Menú Hamburguesa (Móvil) */}
{/* Menú Móvil */} {isMenuOpen && (
{navItems.map((item) => ( ))}
)}
{/* ÁREA DE CONTENIDO PRINCIPAL */}
{activeTab === 'editor' && ( setCards([...cards, newCard])} goToCatalog={() => setActiveTab('catalog')} /> )} {activeTab === 'catalog' && ( setActiveTab('editor')} /> )} {activeTab === 'store' && ( )}
); } // --- VISTA 1: EDITOR Y VISTA PREVIA --- function EditorVistaPrevia({ onSave, goToCatalog }) { const canvasRef = useRef(null); const [imageObj, setImageObj] = useState(null); const [zoom, setZoom] = useState(1); const [zoomHistory, setZoomHistory] = useState([]); // Lógica para cargar la imagen const handleImageUpload = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (event) => { const img = new Image(); img.onload = () => { setImageObj(img); setZoom(1); setZoomHistory([]); drawImage(img, 1); }; img.src = event.target.result; }; reader.readAsDataURL(file); } }; // Dibujar en el Canvas HTML5 const drawImage = (img, scale) => { const canvas = canvasRef.current; if (!canvas || !img) return; const ctx = canvas.getContext('2d'); // Configurar el tamaño del canvas (fijo para vista previa, responsivo visualmente por CSS) canvas.width = 600; canvas.height = 800; // Proporción tipo carta // Limpiar canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Calcular centro y escala const scaledWidth = img.width * scale; const scaledHeight = img.height * scale; const x = (canvas.width - scaledWidth) / 2; const y = (canvas.height - scaledHeight) / 2; // Fondo oscuro para el canvas ctx.fillStyle = '#1e293b'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Dibujar imagen ctx.drawImage(img, x, y, scaledWidth, scaledHeight); }; const handleZoomChange = (e) => { const newZoom = parseFloat(e.target.value); setZoomHistory([...zoomHistory, zoom]); // Guardar estado actual setZoom(newZoom); drawImage(imageObj, newZoom); }; const handleUndo = () => { if (zoomHistory.length > 0) { const previousZoom = zoomHistory[zoomHistory.length - 1]; const newHistory = zoomHistory.slice(0, -1); setZoomHistory(newHistory); setZoom(previousZoom); drawImage(imageObj, previousZoom); } }; const handleSaveToCatalog = async () => { if (!imageObj) return; const canvas = canvasRef.current; // Extraer la imagen editada del canvas const editedImageDataUrl = canvas.toDataURL('image/jpeg', 0.9); // --------------------------------------------------------- // SIMULACIÓN DE CONEXIÓN A BASE DE DATOS WORDPRESS // --------------------------------------------------------- /* En un entorno real de WordPress, aquí haríamos una petición POST a la REST API: const formData = new FormData(); // Convertir dataURL a Blob const blob = await (await fetch(editedImageDataUrl)).blob(); formData.append('file', blob, 'carta-digital.jpg'); fetch('https://capricorniografx.com/wp-json/wp/v2/media', { method: 'POST', headers: { 'Authorization': 'Bearer TU_TOKEN_JWT', }, body: formData }) .then(res => res.json()) .then(data => { // data.source_url contendría algo como: // https://capricorniografx.com/wp-content/uploads/2026/07/carta-digital.jpg }); */ // Para esta demo funcional, guardamos en el estado local simulando la ruta const newCard = { id: Date.now().toString(), name: 'Nueva Carta Digital', image: editedImageDataUrl, // Ruta simulada de WP multimedia wpPathSimulated: `https://capricorniografx.com/wp-content/uploads/${new Date().getFullYear()}/${String(new Date().getMonth() + 1).padStart(2, '0')}/carta-${Date.now()}.jpg`, variants: [], // Para futuras variantes isForSale: false, price: 0.00 }; onSave(newCard); // Pequeño feedback visual y redirección alert('¡Carta guardada en el catálogo exitosamente! (Ruta simulada WP: ' + newCard.wpPathSimulated + ')'); goToCatalog(); }; return (
{/* BARRA LATERAL IZQUIERDA - CONTROLES */}

Editor

{/* Instrucciones */}

Instrucciones:

  1. Sube la imagen de tu carta.
  2. Ajusta el zoom para encuadrarla.
  3. Usa deshacer si te equivocas.
  4. Guarda en tu catálogo personal.
{/* Controles de carga */}
{/* Controles de Zoom */}
{/* Botón Guardar */}
{/* ÁREA DE VISTA PREVIA (CENTRAL) */}
{!imageObj && (

La vista previa de tu carta aparecerá aquí

)}
); } // --- VISTA 2: MI CATÁLOGO (ESTILO PINTEREST) --- function MiCatalogo({ cards, setCards, goToEditor }) { const [boardName, setBoardName] = useState("Colección Principal"); const [isEditingBoardName, setIsEditingBoardName] = useState(false); const [isPublic, setIsPublic] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const filteredCards = cards.filter(card => card.name.toLowerCase().includes(searchQuery.toLowerCase()) ); const updateCardName = (id, newName) => { setCards(cards.map(c => c.id === id ? { ...c, name: newName } : c)); }; return (
{/* Cabecera del Tablero */}
{/* Info del Tablero */}
{isEditingBoardName ? (
setBoardName(e.target.value)} className="text-3xl font-bold border-b-2 border-blue-500 focus:outline-none bg-transparent px-1 py-1 text-gray-800" autoFocus />
) : (

setIsEditingBoardName(true)} title="Clic para editar nombre" > {boardName}

)}

{cards.length} {cards.length === 1 ? 'carta' : 'cartas'} en total

{/* Controles del Tablero (Toggle Público/Privado) */}
Privado {/* Toggle Switch Personalizado (Fondo azul y check blanco) */} Público
{/* Buscador y Botón de Añadir */}
setSearchQuery(e.target.value)} />
{/* Grid estilo Pinterest (Masonry-like con CSS Columns) */} {filteredCards.length === 0 ? (

No hay cartas aquí

Agrega tu primera carta digital usando el editor.

) : (
{filteredCards.map((card) => (
{/* Imagen de la carta */}
{card.name} {/* Overlay on hover */}
ID: {card.id.slice(-6)}
{/* Nombre Editable */} updateCardName(card.id, e.target.value)} className="w-full font-bold text-gray-800 text-lg border-b border-transparent hover:border-gray-300 focus:border-blue-500 focus:outline-none transition-colors bg-transparent mb-3" placeholder="Nombre de la carta..." /> {/* Slider de Variantes a Futuro */}

Variantes (Próximamente)

{/* Mockups de variantes */} {[1, 2, 3].map(i => (
V{i}
))}
))}
)}
); } // --- VISTA 3: TIENDA DIGITAL --- function TiendaDigital({ cards, setCards }) { const updateStoreSettings = (id, field, value) => { setCards(cards.map(c => c.id === id ? { ...c, [field]: value } : c)); }; const formatPrice = (value) => { // Asegurar formato 0.00 const num = parseFloat(value); return isNaN(num) ? "0.00" : num.toFixed(2); }; return (
{/* Banner Promocional Artículos */}
{/* Decoración de fondo */}
Promoción Exclusiva

Mercado de Cartas
Capricornio Grafx

Monetiza tu colección. Configura los precios de tus variantes digitales y ponlas a la venta directamente desde tu catálogo.

Gestión de Ventas

{cards.length === 0 ? (

Tu catálogo está vacío. Sube cartas en el Editor para poder venderlas aquí.

) : (
{cards.map((card) => (
{/* Imagen */}
{card.name} {card.isForSale && (
EN VENTA
)}
{/* Controles de Tienda (Sin sobreponer elementos visuales sobre la imagen) */}

{card.name}

{/* Control de Precio Formato $ 0.00 */}
$
updateStoreSettings(card.id, 'price', e.target.value)} onBlur={(e) => updateStoreSettings(card.id, 'price', formatPrice(e.target.value))} disabled={card.isForSale} // Prevenir cambio de precio si ya está a la venta className={`block w-full pl-8 pr-12 py-2.5 sm:text-sm border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500 transition-colors ${ card.isForSale ? 'bg-gray-100 text-gray-500 cursor-not-allowed border-transparent' : 'bg-white border-gray-300' }`} placeholder="0.00" />
USD
{/* Botón Poner a la venta */}
))}
)}
); }