Files
ALwrity/frontend/src/components/BlogWriter/SEO/MetadataDisplay/PreviewCard.tsx

389 lines
16 KiB
TypeScript

/**
* Preview Card Component
*
* Displays live previews of how the metadata will appear in:
* - Search engine results
* - Social media platforms
* - Rich snippets
*/
import React from 'react';
import {
Box,
Typography,
Paper,
Grid,
Card,
CardContent,
Chip,
Divider,
Alert,
IconButton,
Tooltip,
Button
} from '@mui/material';
import {
ContentCopy as CopyIcon,
Check as CheckIcon,
Search as SearchIcon,
Share as ShareIcon,
Code as CodeIcon,
Facebook as FacebookIcon,
Twitter as TwitterIcon,
LinkedIn as LinkedInIcon,
Google as GoogleIcon
} from '@mui/icons-material';
interface PreviewCardProps {
metadata: any;
blogTitle: string;
}
export const PreviewCard: React.FC<PreviewCardProps> = ({
metadata,
blogTitle
}) => {
const copyToClipboard = async (text: string, itemId: string) => {
try {
await navigator.clipboard.writeText(text);
// You could add a state to show "Copied!" feedback here
} catch (err) {
console.error('Failed to copy to clipboard:', err);
}
};
const getCurrentDate = () => {
return new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
};
const getCurrentTime = () => {
return new Date().toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
});
};
return (
<Box>
<Typography variant="h6" sx={{ mb: 3, display: 'flex', alignItems: 'center', gap: 1 }}>
<SearchIcon sx={{ color: 'primary.main' }} />
Live Preview
</Typography>
<Grid container spacing={3}>
{/* Google Search Results Preview */}
<Grid item xs={12}>
<Paper sx={{ p: 3, background: 'rgba(255,255,255,0.8)', border: '1px solid rgba(0,0,0,0.1)' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
<GoogleIcon sx={{ color: '#4285F4' }} />
<Typography variant="h6" sx={{ fontWeight: 600 }}>
Google Search Results
</Typography>
<Chip label="SERP Preview" size="small" color="primary" />
</Box>
<Card sx={{ border: '1px solid #e0e0e0', boxShadow: 'none' }}>
<CardContent sx={{ p: 2 }}>
{/* URL */}
<Typography variant="caption" sx={{ color: '#1a0dab', mb: 1, display: 'block' }}>
{metadata.canonical_url || 'https://yourwebsite.com/blog-post'}
</Typography>
{/* Title */}
<Typography
variant="h6"
sx={{
color: '#1a0dab',
fontWeight: 400,
fontSize: '1.1rem',
lineHeight: 1.3,
mb: 1,
cursor: 'pointer',
'&:hover': { textDecoration: 'underline' }
}}
>
{metadata.seo_title || blogTitle}
</Typography>
{/* Description */}
<Typography variant="body2" sx={{ color: '#4d5156', lineHeight: 1.4, mb: 1 }}>
{metadata.meta_description || 'Your meta description will appear here in Google search results...'}
</Typography>
{/* Additional Info */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 1 }}>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{getCurrentDate()}
</Typography>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
</Typography>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{metadata.reading_time || 5} min read
</Typography>
{metadata.blog_tags && metadata.blog_tags.length > 0 && (
<>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
</Typography>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{metadata.blog_tags.slice(0, 2).join(', ')}
</Typography>
</>
)}
</Box>
</CardContent>
</Card>
<Alert severity="info" sx={{ mt: 2 }}>
This is how your blog post will appear in Google search results
</Alert>
</Paper>
</Grid>
{/* Social Media Previews */}
<Grid item xs={12} md={6}>
<Paper sx={{ p: 3, background: 'rgba(255,255,255,0.8)', border: '1px solid rgba(0,0,0,0.1)' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
<FacebookIcon sx={{ color: '#1877F2' }} />
<Typography variant="h6" sx={{ fontWeight: 600 }}>
Facebook Preview
</Typography>
<Chip label="Open Graph" size="small" color="primary" />
</Box>
<Card sx={{ border: '1px solid #e0e0e0', boxShadow: 'none', maxWidth: 400 }}>
<CardContent sx={{ p: 0 }}>
{/* Image placeholder */}
<Box sx={{
height: 200,
bgcolor: '#f5f5f5',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderBottom: '1px solid #e0e0e0'
}}>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
{metadata.open_graph?.image ? 'Image loaded' : 'No image set'}
</Typography>
</Box>
<Box sx={{ p: 2 }}>
{/* URL */}
<Typography variant="caption" sx={{ color: '#65676b', mb: 1, display: 'block' }}>
{metadata.canonical_url || 'yourwebsite.com'}
</Typography>
{/* Title */}
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 1, lineHeight: 1.3 }}>
{metadata.open_graph?.title || metadata.seo_title || blogTitle}
</Typography>
{/* Description */}
<Typography variant="body2" sx={{ color: '#65676b', lineHeight: 1.4 }}>
{metadata.open_graph?.description || metadata.meta_description || 'Your description will appear here...'}
</Typography>
</Box>
</CardContent>
</Card>
</Paper>
</Grid>
<Grid item xs={12} md={6}>
<Paper sx={{ p: 3, background: 'rgba(255,255,255,0.8)', border: '1px solid rgba(0,0,0,0.1)' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
<TwitterIcon sx={{ color: '#1DA1F2' }} />
<Typography variant="h6" sx={{ fontWeight: 600 }}>
Twitter Preview
</Typography>
<Chip label="Twitter Card" size="small" color="info" />
</Box>
<Card sx={{ border: '1px solid #e0e0e0', boxShadow: 'none', maxWidth: 400 }}>
<CardContent sx={{ p: 0 }}>
{/* Image placeholder */}
<Box sx={{
height: 200,
bgcolor: '#f5f5f5',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderBottom: '1px solid #e0e0e0'
}}>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
{metadata.twitter_card?.image ? 'Image loaded' : 'No image set'}
</Typography>
</Box>
<Box sx={{ p: 2 }}>
{/* URL */}
<Typography variant="caption" sx={{ color: '#536471', mb: 1, display: 'block' }}>
{metadata.canonical_url || 'yourwebsite.com'}
</Typography>
{/* Title */}
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 1, lineHeight: 1.3 }}>
{metadata.twitter_card?.title || metadata.seo_title || blogTitle}
</Typography>
{/* Description */}
<Typography variant="body2" sx={{ color: '#536471', lineHeight: 1.4 }}>
{metadata.twitter_card?.description || metadata.meta_description || 'Your description will appear here...'}
</Typography>
{/* Twitter handle */}
{metadata.twitter_card?.site && (
<Typography variant="caption" sx={{ color: '#536471', mt: 1, display: 'block' }}>
{metadata.twitter_card.site}
</Typography>
)}
</Box>
</CardContent>
</Card>
</Paper>
</Grid>
{/* Rich Snippets Preview */}
<Grid item xs={12}>
<Paper sx={{ p: 3, background: 'rgba(255,255,255,0.8)', border: '1px solid rgba(0,0,0,0.1)' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
<CodeIcon sx={{ color: '#34A853' }} />
<Typography variant="h6" sx={{ fontWeight: 600 }}>
Rich Snippets Preview
</Typography>
<Chip label="JSON-LD Schema" size="small" color="success" />
</Box>
<Card sx={{ border: '1px solid #e0e0e0', boxShadow: 'none' }}>
<CardContent sx={{ p: 2 }}>
{/* Article Schema Preview */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
{metadata.json_ld_schema?.headline || metadata.seo_title || blogTitle}
</Typography>
<Chip label="Article" size="small" color="success" />
</Box>
<Typography variant="body2" sx={{ color: '#4d5156', mb: 2 }}>
{metadata.json_ld_schema?.description || metadata.meta_description || 'Article description...'}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, flexWrap: 'wrap' }}>
{metadata.json_ld_schema?.author?.name && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
By {metadata.json_ld_schema.author.name}
</Typography>
</Box>
)}
{metadata.json_ld_schema?.datePublished && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{new Date(metadata.json_ld_schema.datePublished).toLocaleDateString()}
</Typography>
</Box>
)}
{metadata.reading_time && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{metadata.reading_time} min read
</Typography>
</Box>
)}
{metadata.json_ld_schema?.wordCount && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography variant="caption" sx={{ color: '#4d5156' }}>
{metadata.json_ld_schema.wordCount} words
</Typography>
</Box>
)}
</Box>
{metadata.json_ld_schema?.keywords && metadata.json_ld_schema.keywords.length > 0 && (
<Box sx={{ mt: 2 }}>
<Typography variant="caption" sx={{ color: '#4d5156', display: 'block', mb: 1 }}>
Keywords:
</Typography>
<Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>
{metadata.json_ld_schema.keywords.slice(0, 5).map((keyword: string, index: number) => (
<Chip key={index} label={keyword} size="small" variant="outlined" />
))}
</Box>
</Box>
)}
</CardContent>
</Card>
<Alert severity="success" sx={{ mt: 2 }}>
Rich snippets help search engines understand your content and may display additional information in search results
</Alert>
</Paper>
</Grid>
{/* Metadata Summary */}
<Grid item xs={12}>
<Paper sx={{ p: 3, background: 'rgba(255,255,255,0.8)', border: '1px solid rgba(0,0,0,0.1)' }}>
<Typography variant="h6" sx={{ fontWeight: 600, mb: 3, display: 'flex', alignItems: 'center', gap: 1 }}>
<SearchIcon />
Metadata Summary
</Typography>
<Grid container spacing={2}>
<Grid item xs={12} sm={6} md={3}>
<Box sx={{ textAlign: 'center', p: 2, bgcolor: 'rgba(76, 175, 80, 0.1)', borderRadius: 2 }}>
<Typography variant="h4" sx={{ fontWeight: 600, color: 'success.main' }}>
{metadata.optimization_score || 0}%
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
Optimization Score
</Typography>
</Box>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Box sx={{ textAlign: 'center', p: 2, bgcolor: 'rgba(33, 150, 243, 0.1)', borderRadius: 2 }}>
<Typography variant="h4" sx={{ fontWeight: 600, color: 'primary.main' }}>
{metadata.reading_time || 0}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
Reading Time (min)
</Typography>
</Box>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Box sx={{ textAlign: 'center', p: 2, bgcolor: 'rgba(156, 39, 176, 0.1)', borderRadius: 2 }}>
<Typography variant="h4" sx={{ fontWeight: 600, color: 'secondary.main' }}>
{metadata.blog_tags?.length || 0}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
Tags
</Typography>
</Box>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Box sx={{ textAlign: 'center', p: 2, bgcolor: 'rgba(255, 152, 0, 0.1)', borderRadius: 2 }}>
<Typography variant="h4" sx={{ fontWeight: 600, color: 'warning.main' }}>
{metadata.blog_categories?.length || 0}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
Categories
</Typography>
</Box>
</Grid>
</Grid>
</Paper>
</Grid>
</Grid>
</Box>
);
};