| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import * as React from 'react';
- import { PageSettings, AIGCVideo, AIGCArticle, FormSubmission } from '../types';
- import LinkEditor from './LinkEditor';
- import DesignEditor from './DesignEditor';
- import { Preview } from './Preview';
- import { Icon } from './ui/Icon';
- import { useTranslation } from '../hooks/useI18n';
- interface PageBuilderProps {
- initialTab: 'link' | 'media' | 'design';
- pageSettings: PageSettings;
- onUpdate: (newSettings: PageSettings) => void;
- aigcVideos: AIGCVideo[];
- aigcArticles: AIGCArticle[];
- onOpenShareModal: () => void;
- onFormSubmit: (submission: FormSubmission) => void;
- }
- export const PageBuilder: React.FC<PageBuilderProps> = ({ initialTab, pageSettings, onUpdate, aigcVideos, aigcArticles, onOpenShareModal, onFormSubmit }) => {
- const { t } = useTranslation();
- const [previewMode, setPreviewMode] = React.useState<'personal' | 'enterprise'>('personal');
- const [deviceView, setDeviceView] = React.useState<'pc' | 'mobile'>('pc');
- const [isPreviewFullScreen, setIsPreviewFullScreen] = React.useState(false);
- const handleBlocksUpdate = (newBlocks: any) => {
- onUpdate({ ...pageSettings, blocks: newBlocks });
- };
- const handleDesignUpdate = (newDesign: any) => {
- onUpdate({ ...pageSettings, design: newDesign });
- };
- const renderEditor = () => {
- switch (initialTab) {
- case 'link':
- return <LinkEditor blocks={pageSettings.blocks} setBlocks={handleBlocksUpdate} aigcVideos={aigcVideos} aigcArticles={aigcArticles} />
- case 'media':
- return <div className="p-8 text-gray-500 dark:text-gray-400">Media content editor will be here.</div>
- case 'design':
- return <DesignEditor design={pageSettings.design} setDesign={handleDesignUpdate} />
- default:
- return null
- }
- };
-
- if (isPreviewFullScreen) {
- return (
- <div className="fixed inset-0 bg-gray-100 dark:bg-gray-900 z-50 flex flex-col">
- <div className="flex-shrink-0 bg-white dark:bg-gray-800 p-2 border-b border-gray-200 dark:border-gray-700 flex justify-end items-center">
- <button onClick={() => setIsPreviewFullScreen(false)} className="flex items-center gap-2 bg-brand-primary text-white font-semibold py-2 px-4 rounded-lg hover:bg-brand-secondary transition-colors">
- <Icon className='h-5 w-5'><path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" /></Icon>
- {t('page_builder.exit_fullscreen')}
- </button>
- </div>
- <div className="flex-1 overflow-hidden relative">
- {/* FIX: Pass onFormSubmit prop to Preview component to handle form submissions. */}
- <Preview
- pageSettings={pageSettings}
- aigcVideos={aigcVideos}
- aigcArticles={aigcArticles}
- previewMode={previewMode}
- deviceView={deviceView}
- onFormSubmit={onFormSubmit}
- />
- </div>
- </div>
- );
- }
- return (
- <div className="flex h-full">
- <div className="w-1/2 flex flex-col">
- <header className="p-6 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
- <div>
- <h2 className="text-2xl font-bold text-gray-900 dark:text-white">{t('page_builder.title')}</h2>
- <p className="text-gray-500 dark:text-gray-400 mt-1">{t('page_builder.url_prompt')} <a href="#" className="text-brand-primary hover:underline">greenpage.ai/johndoe</a></p>
- </div>
- <button onClick={onOpenShareModal} className="flex items-center gap-2 bg-brand-primary text-white font-semibold py-2 px-4 rounded-lg hover:bg-brand-secondary transition-colors">
- <Icon className="h-5 w-5"><path strokeLinecap="round" strokeLinejoin="round" d="M8.684 13.342C8.886 12.938 9 12.482 9 12s-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 100-6 3 3 0 000 6z" /></Icon>
- {t('page_builder.share')}
- </button>
- </header>
- <div className="flex-1 overflow-y-auto p-6">
- {renderEditor()}
- </div>
- </div>
- <div className="w-1/2 border-l border-gray-200 dark:border-gray-700 flex flex-col">
- <div className="flex-shrink-0 bg-white dark:bg-gray-800 p-2 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
- <div className="flex items-center gap-1 bg-gray-200 dark:bg-gray-700 p-1 rounded-lg">
- <button onClick={() => setPreviewMode('personal')} className={`px-3 py-1 text-sm rounded-md ${previewMode === 'personal' ? 'bg-brand-primary text-white' : 'hover:bg-gray-300 dark:hover:bg-gray-600'}`}>{t('page_builder.personal_mode')}</button>
- <button onClick={() => setPreviewMode('enterprise')} className={`px-3 py-1 text-sm rounded-md flex items-center gap-2 ${previewMode === 'enterprise' ? 'bg-brand-primary text-white' : 'hover:bg-gray-300 dark:hover:bg-gray-600'}`}>
- {t('page_builder.enterprise_mode')}
- <Icon className='h-4 w-4 text-yellow-400'><path fillRule="evenodd" d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" clipRule="evenodd" /></Icon>
- </button>
- </div>
- <div className="flex items-center gap-1 bg-gray-200 dark:bg-gray-700 p-1 rounded-lg">
- <button onClick={() => setDeviceView('pc')} className={`p-2 rounded-md ${deviceView === 'pc' ? 'bg-brand-primary text-white' : ''}`}>
- <Icon className='h-5 w-5'><path strokeLinecap="round" strokeLinejoin="round" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></Icon>
- </button>
- <button onClick={() => setDeviceView('mobile')} className={`p-2 rounded-md ${deviceView === 'mobile' ? 'bg-brand-primary text-white' : ''}`}>
- <Icon className='h-5 w-5'><path strokeLinecap="round" strokeLinejoin="round" d="M12 18h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" /></Icon>
- </button>
- <button onClick={() => setIsPreviewFullScreen(true)} className="p-2 rounded-md">
- <Icon className='h-5 w-5'><path strokeLinecap="round" strokeLinejoin="round" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5" /></Icon>
- </button>
- </div>
- </div>
- <div className="flex-1 overflow-hidden relative">
- {/* FIX: Pass onFormSubmit prop to Preview component to handle form submissions. */}
- <Preview
- key={`${previewMode}-${deviceView}`}
- pageSettings={pageSettings}
- aigcVideos={aigcVideos}
- aigcArticles={aigcArticles}
- previewMode={previewMode}
- deviceView={deviceView}
- onFormSubmit={onFormSubmit}
- />
- </div>
- </div>
- </div>
- );
- };
|