slideshare/src/components/themes/ThemeDetailPage.tsx
Michael Mainguy 6e6c09b5ba Add comprehensive theme routing and browsing system
- Add React Router with theme browser, theme detail, and layout detail pages
- Implement manifest-based theme discovery for better performance
- Add Welcome component as home page with feature overview
- Fix layout and styling issues with proper CSS centering
- Implement introspective theme browsing (dynamically discover colors/variables)
- Add layout preview system with iframe scaling
- Create comprehensive theme detail page with color palette display
- Fix TypeScript errors and build issues
- Remove hardcoded theme assumptions in favor of dynamic discovery

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-20 10:17:55 -05:00

162 lines
5.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
import type { Theme } from '../../types/theme';
import { getTheme } from '../../themes';
import { LayoutPreview } from './LayoutPreview';
import './ThemeDetailPage.css';
export const ThemeDetailPage: React.FC = () => {
const { themeId } = useParams<{ themeId: string }>();
const [theme, setTheme] = useState<Theme | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const loadTheme = async () => {
if (!themeId) {
setError('No theme ID provided');
setLoading(false);
return;
}
try {
setLoading(true);
const themeData = await getTheme(themeId);
if (!themeData) {
setError(`Theme "${themeId}" not found`);
return;
}
setTheme(themeData);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load theme');
} finally {
setLoading(false);
}
};
loadTheme();
}, [themeId]);
if (loading) {
return (
<div className="theme-detail-page">
<div className="loading-spinner">Loading theme...</div>
</div>
);
}
if (error) {
return (
<div className="theme-detail-page">
<div className="error-message">
<h2>Error</h2>
<p>{error}</p>
<Link to="/themes" className="back-link"> Back to Themes</Link>
</div>
</div>
);
}
if (!theme) {
return (
<div className="theme-detail-page">
<div className="not-found">
<h2>Theme Not Found</h2>
<p>The requested theme could not be found.</p>
<Link to="/themes" className="back-link"> Back to Themes</Link>
</div>
</div>
);
}
return (
<div className="theme-detail-page">
<header className="theme-detail-header">
<Link to="/themes" className="back-link"> Back to Themes</Link>
<div className="theme-info">
<h1 className="theme-name">{theme.name}</h1>
<p className="theme-description">{theme.description}</p>
<div className="theme-meta">
{theme.author && <span className="theme-author">by {theme.author}</span>}
{theme.version && <span className="theme-version">v{theme.version}</span>}
</div>
</div>
</header>
{theme.variables && Object.keys(theme.variables).length > 0 && (
<section className="theme-colors">
<h2>Color Palette</h2>
<div className="color-palette-large">
{Object.entries(theme.variables)
.filter(([_, value]) => value.startsWith('#') || value.includes('rgb') || value.includes('hsl'))
.map(([key, value]) => (
<div key={key} className="color-swatch-large">
<div
className="color-preview"
style={{ backgroundColor: value }}
title={`--${key}: ${value}`}
></div>
<div className="color-details">
<div className="color-name">--{key}</div>
<div className="color-value">{value}</div>
</div>
</div>
))}
</div>
</section>
)}
<section className="theme-layouts">
<h2>Available Layouts ({theme.layouts.length})</h2>
<div className="layouts-grid">
{theme.layouts.map((layout) => (
<div key={layout.id} className="layout-card">
<div className="layout-header">
<h3 className="layout-name">{layout.name}</h3>
<span className="layout-slots">{layout.slots.length} slots</span>
<Link
to={`/themes/${theme.id}/layouts/${layout.id}`}
className="layout-detail-link"
>
View Details
</Link>
</div>
<div className="layout-preview-container">
<LayoutPreview layout={layout} theme={theme} />
</div>
</div>
))}
</div>
</section>
{theme.variables && (
<section className="theme-variables">
<h2>CSS Variables</h2>
<div className="variables-grid">
{Object.entries(theme.variables).map(([key, value]) => (
<div key={key} className="variable-card">
<code className="variable-name">--{key}</code>
<span className="variable-value">{value}</span>
</div>
))}
</div>
</section>
)}
<section className="theme-technical">
<h2>Technical Details</h2>
<div className="tech-details">
<div className="tech-item">
<strong>Path:</strong> <code>{theme.basePath}</code>
</div>
<div className="tech-item">
<strong>CSS File:</strong> <code>{theme.cssFile}</code>
</div>
<div className="tech-item">
<strong>Master Slide:</strong> {theme.masterSlideTemplate ? 'Yes' : 'No'}
</div>
</div>
</section>
</div>
);
};