feat: AI Brand Voice Translator integration and Mesh Content fix
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Save, AlertCircle, Crown, FolderOpen, Sparkles } from 'lucide-react';
|
||||
import { DesignMD, CompanyProfile } from '../types';
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import { Save, AlertCircle, Crown, FolderOpen, Sparkles, Image as ImageIcon, Film, Volume2, Music } from 'lucide-react';
|
||||
import { CustomVideoPlayer } from './ui/CustomVideoPlayer';
|
||||
import { useMediaResolver } from '../hooks/useMediaResolver';
|
||||
import { DesignMD, CompanyProfile, BrandAsset } from '../types';
|
||||
import { BrandTabGeneral } from './brand/BrandTabGeneral';
|
||||
import { BrandTabVisual } from './brand/BrandTabVisual';
|
||||
import { BrandTabTypography } from './brand/BrandTabTypography';
|
||||
import { BrandTabMedia } from './brand/BrandTabMedia';
|
||||
import { BrandTabGenerated } from './brand/BrandTabGenerated';
|
||||
import { BrandTabVoice } from './brand/BrandTabVoice';
|
||||
import { BrandPreview } from './brand/BrandPreview';
|
||||
import { Toast } from './ui/Toast';
|
||||
import { UnifiedMediaItem } from './content-grid/UnifiedMediaLibrary';
|
||||
|
||||
interface BrandArchitectureProps {
|
||||
company: CompanyProfile;
|
||||
@@ -22,8 +25,8 @@ const TABS = [
|
||||
{ id: 'general', label: 'Información', icon: '📋' },
|
||||
{ id: 'visual', label: 'Visual y Colores', icon: '🎨' },
|
||||
{ id: 'typography', label: 'Tipografía', icon: '🔤' },
|
||||
{ id: 'media', label: 'Video y Audio', icon: '🎬' },
|
||||
{ id: 'generated', label: 'Generados', icon: '✨' },
|
||||
{ id: 'voice', label: 'Voz de Marca', icon: '🎙️' },
|
||||
{ id: 'media', label: 'Librería', icon: '📁' },
|
||||
] as const;
|
||||
|
||||
type TabId = typeof TABS[number]['id'];
|
||||
@@ -34,7 +37,9 @@ export const BrandArchitecture: React.FC<BrandArchitectureProps> = ({ company, h
|
||||
const [activeTab, setActiveTab] = useState<TabId>('general');
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
const [validationErrors, setValidationErrors] = useState<string[]>([]);
|
||||
const [selectedMediaItem, setSelectedMediaItem] = useState<BrandAsset | null>(null);
|
||||
|
||||
const { getMediaUrl } = useMediaResolver();
|
||||
const validate = useCallback((): string[] => {
|
||||
const errors: string[] = [];
|
||||
if (!company?.name || company.name.trim().length < 2) {
|
||||
@@ -63,8 +68,8 @@ export const BrandArchitecture: React.FC<BrandArchitectureProps> = ({ company, h
|
||||
|
||||
const handleOpenFolder = async () => {
|
||||
if (window.electronAPI && company?.id) {
|
||||
const workspacePath = await window.electronAPI.fs.getWorkspacePath();
|
||||
const folderPath = `${workspacePath}/${company.id}`;
|
||||
const wp = await window.electronAPI.fs.getWorkspacePath();
|
||||
const folderPath = `${wp}/${company.id}`;
|
||||
await window.electronAPI.fs.openFolder(folderPath);
|
||||
}
|
||||
};
|
||||
@@ -210,26 +215,70 @@ export const BrandArchitecture: React.FC<BrandArchitectureProps> = ({ company, h
|
||||
{activeTab === 'typography' && (
|
||||
<BrandTabTypography designMD={designMD} handleDesignChange={handleDesignChange} />
|
||||
)}
|
||||
{activeTab === 'voice' && (
|
||||
<BrandTabVoice company={company} handleCompanyChange={handleCompanyChange} />
|
||||
)}
|
||||
{activeTab === 'media' && (
|
||||
<BrandTabMedia
|
||||
company={company}
|
||||
designMD={designMD}
|
||||
handleDesignChange={handleDesignChange}
|
||||
onEditAsset={onEditAsset}
|
||||
onSelectAsset={setSelectedMediaItem}
|
||||
selectedAssetId={selectedMediaItem?.id}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 'generated' && (
|
||||
<BrandTabGenerated company={company} />
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Preview Column */}
|
||||
{activeTab === 'generated' ? (
|
||||
<div className="flex-1 bg-neutral-950 flex flex-col items-center justify-center text-neutral-500">
|
||||
<Sparkles className="w-12 h-12 mb-4 opacity-50" />
|
||||
<p>Selecciona un archivo generado para previsualizarlo.</p>
|
||||
{activeTab === 'media' ? (
|
||||
<div className="flex-1 bg-neutral-950 flex flex-col items-center justify-center p-8">
|
||||
{selectedMediaItem ? (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<div className="w-full max-h-[80%] flex items-center justify-center bg-black/40 rounded-xl overflow-hidden border border-neutral-800 shadow-2xl">
|
||||
{selectedMediaItem.type === 'video' ? (
|
||||
<CustomVideoPlayer
|
||||
src={getMediaUrl(selectedMediaItem.url || selectedMediaItem.path || '')}
|
||||
autoPlay
|
||||
className="w-full h-full"
|
||||
/>
|
||||
) : selectedMediaItem.type === 'audio' ? (
|
||||
<div className="flex flex-col items-center gap-6 p-12">
|
||||
<div className="w-24 h-24 rounded-full bg-rose-500/10 flex items-center justify-center">
|
||||
<Music className="w-12 h-12 text-rose-500" />
|
||||
</div>
|
||||
<audio
|
||||
src={getMediaUrl(selectedMediaItem.url || selectedMediaItem.path || '')}
|
||||
controls
|
||||
autoPlay
|
||||
className="w-64"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<img
|
||||
src={getMediaUrl(selectedMediaItem.url || selectedMediaItem.path || '')}
|
||||
alt={selectedMediaItem.id}
|
||||
className="max-w-full max-h-full object-contain"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6 text-center space-y-1">
|
||||
<h3 className="text-lg font-medium text-white font-mono">
|
||||
{selectedMediaItem.id}
|
||||
</h3>
|
||||
<p className="text-sm text-neutral-400">
|
||||
{'date' in selectedMediaItem && selectedMediaItem.date ? new Date((selectedMediaItem as any).date).toLocaleString() : 'Asset Base'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center text-neutral-500">
|
||||
<Sparkles className="w-12 h-12 mb-4 opacity-50" />
|
||||
<p>Selecciona un archivo para previsualizarlo.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<BrandPreview
|
||||
|
||||
Reference in New Issue
Block a user