slideshare/src/components/themes/LayoutPreview.tsx
Michael Mainguy 15d3789bb4 Add full-screen layout preview route and fix iframe sandbox issue
- Create LayoutPreviewPage component for full-screen layout previews
- Add preview route /themes/:themeId/layouts/:layoutId/preview to App routing
- Update theme components with preview links and improved navigation
- Fix iframe sandbox error by adding allow-scripts permission
- Enhance template renderer with layout metadata support
- Replace PostCSS with regex-only CSS parsing for browser compatibility
- Add comprehensive standards documentation for code quality
- Clean up CSS slot indicators to be always visible with descriptions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-20 13:48:13 -05:00

69 lines
2.1 KiB
TypeScript

import React, { useRef, useEffect } from 'react';
import type { SlideLayout, Theme } from '../../types/theme';
import { renderTemplateWithSampleData, createPreviewDocument } from '../../utils/templateRenderer';
interface LayoutPreviewProps {
layout: SlideLayout;
theme: Theme;
className?: string;
}
export const LayoutPreview: React.FC<LayoutPreviewProps> = ({
layout,
theme,
className = ''
}) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
if (!iframeRef.current) return;
const iframe = iframeRef.current;
// Render the template with sample data
const renderedTemplate = renderTemplateWithSampleData(layout.htmlTemplate, layout);
// Create the preview document with theme CSS
const themeCssUrl = `${theme.basePath}/${theme.cssFile}`;
const previewDocument = createPreviewDocument(renderedTemplate, themeCssUrl);
// Write the document to the iframe
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
if (iframeDoc) {
iframeDoc.open();
iframeDoc.write(previewDocument);
iframeDoc.close();
}
}, [layout, theme]);
return (
<div className={`layout-preview ${className}`}>
<div className="layout-preview-header">
<h5 className="layout-preview-title">{layout.name}</h5>
<span className="layout-preview-slots">
{layout.slots.length} slot{layout.slots.length !== 1 ? 's' : ''}
</span>
</div>
<div className="layout-preview-container">
<iframe
ref={iframeRef}
className="layout-preview-frame"
title={`Preview of ${layout.name}`}
sandbox="allow-same-origin allow-scripts"
/>
</div>
<div className="layout-preview-details">
<p className="layout-preview-description">{layout.description}</p>
<div className="layout-preview-slot-types">
{Array.from(new Set(layout.slots.map(slot => slot.type))).map(type => (
<span key={type} className={`slot-type-badge slot-type-${type}`}>
{type}
</span>
))}
</div>
</div>
</div>
);
};