mirror of
https://github.com/harivansh-afk/Austens-Wedding-Guide.git
synced 2026-04-15 06:04:39 +00:00
social class view ui/ux improvements
This commit is contained in:
parent
2cf48254c4
commit
34516c0aa5
3 changed files with 1009 additions and 448 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Box, Typography, Paper, Grid, Tooltip, Card, CardContent, Chip, Dialog, DialogTitle, DialogContent } from '@mui/material';
|
||||
import { Box, Typography, Paper, Grid, Tooltip, Card, CardContent, Chip, Dialog, DialogTitle, DialogContent, Divider } from '@mui/material';
|
||||
import { SocialClass, Character } from '../types/timeline';
|
||||
|
||||
const socialClasses: SocialClass[] = [
|
||||
|
|
@ -124,6 +124,9 @@ export default function SocialClassView() {
|
|||
} else if (selectedCharacter.id !== character.id) {
|
||||
setComparisonCharacter(character);
|
||||
setDialogOpen(true);
|
||||
} else {
|
||||
// Deselect if clicking the same character
|
||||
setSelectedCharacter(null);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -133,121 +136,286 @@ export default function SocialClassView() {
|
|||
setComparisonCharacter(null);
|
||||
};
|
||||
|
||||
// Color constants for the gradient
|
||||
const pyramidColors = {
|
||||
upper: {
|
||||
start: '#4A5D52', // darker sage
|
||||
end: '#6B7F75' // lighter sage
|
||||
},
|
||||
middle: {
|
||||
start: '#5B6E65',
|
||||
end: '#7C8F86'
|
||||
},
|
||||
lower: {
|
||||
start: '#6B7F75',
|
||||
end: '#8C9F96'
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Social Class in Austen's Novels
|
||||
</Typography>
|
||||
|
||||
{/* Social Pyramid */}
|
||||
<Box sx={{ mb: 6, position: 'relative', height: 300 }}>
|
||||
{socialClasses.map((socialClass, index) => (
|
||||
<Tooltip
|
||||
key={socialClass.name}
|
||||
title={
|
||||
<Box>
|
||||
<Typography variant="subtitle2">{socialClass.name}</Typography>
|
||||
<Typography variant="body2">{socialClass.description}</Typography>
|
||||
<Typography variant="caption">Income: {socialClass.incomeRange}</Typography>
|
||||
</Box>
|
||||
}
|
||||
arrow
|
||||
>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
width: `${100 - index * 20}%`,
|
||||
height: 80,
|
||||
transform: `translateX(-50%) translateY(${index * 100}px)`,
|
||||
bgcolor: `primary.${100 + index * 100}`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
'&:hover': {
|
||||
transform: `translateX(-50%) translateY(${index * 100}px) scale(1.02)`,
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" color="text.primary">
|
||||
{socialClass.name}
|
||||
<div className="container mx-auto py-6 space-y-6">
|
||||
<Grid container spacing={3}>
|
||||
{/* Social Pyramid */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card className="border border-sage-200 hover:border-sage-300 transition-all">
|
||||
<CardContent className="p-6">
|
||||
<Typography variant="h5" className="font-cormorant text-sage-900 mb-4">
|
||||
Social Hierarchy
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
{/* Character Grid */}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 4 }}>
|
||||
Character Examples {selectedCharacter && '(Select another character to compare)'}
|
||||
</Typography>
|
||||
<Grid container spacing={2}>
|
||||
{characters.map((character) => (
|
||||
<Grid item xs={12} sm={6} md={4} key={character.id}>
|
||||
<Card
|
||||
onClick={() => handleCharacterClick(character)}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'scale(1.02)',
|
||||
},
|
||||
bgcolor: selectedCharacter?.id === character.id ? 'primary.50' : 'background.paper'
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{character.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
{character.novel}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={character.socialClass.charAt(0).toUpperCase() + character.socialClass.slice(1)}
|
||||
size="small"
|
||||
sx={{ mb: 1 }}
|
||||
/>
|
||||
<Typography variant="body2">
|
||||
Annual Income: {character.annualIncome}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" display="block">
|
||||
Modern Equivalent: {character.modernEquivalent}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
<Box sx={{ position: 'relative', height: 350, mb: 4 }}>
|
||||
{socialClasses.map((socialClass, index) => {
|
||||
const colors = index === 0 ? pyramidColors.upper :
|
||||
index === 1 ? pyramidColors.middle :
|
||||
pyramidColors.lower;
|
||||
return (
|
||||
<Tooltip
|
||||
key={socialClass.name}
|
||||
title={
|
||||
<Box className="p-4 max-w-md">
|
||||
<Typography variant="subtitle1" className="font-cormorant text-sage-900 mb-2 font-semibold">
|
||||
{socialClass.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" className="text-sage-700 mb-3">
|
||||
{socialClass.description}
|
||||
</Typography>
|
||||
<Divider className="bg-sage-200 my-3" />
|
||||
<div className="space-y-2">
|
||||
<Typography variant="caption" className="text-sage-700 block font-medium">
|
||||
Income Range: {socialClass.incomeRange}
|
||||
</Typography>
|
||||
<Typography variant="caption" className="text-sage-700 block font-medium">
|
||||
Modern Equivalent: {socialClass.modernEquivalent}
|
||||
</Typography>
|
||||
</div>
|
||||
<Divider className="bg-sage-200 my-3" />
|
||||
<div className="space-y-2">
|
||||
<Typography variant="caption" className="text-sage-800 font-semibold block">
|
||||
Key Characteristics:
|
||||
</Typography>
|
||||
<ul className="list-disc list-inside text-sage-700 text-sm space-y-1">
|
||||
{socialClass.characteristics.map((char, idx) => (
|
||||
<li key={idx}>{char}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</Box>
|
||||
}
|
||||
arrow
|
||||
placement="right"
|
||||
classes={{
|
||||
tooltip: "bg-white shadow-lg",
|
||||
arrow: "text-white"
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiTooltip-tooltip": {
|
||||
backgroundColor: "white",
|
||||
color: "inherit",
|
||||
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.1)",
|
||||
opacity: 1,
|
||||
maxWidth: "none"
|
||||
},
|
||||
"& .MuiTooltip-arrow": {
|
||||
color: "white",
|
||||
"&::before": {
|
||||
backgroundColor: "white",
|
||||
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.1)"
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={2}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
width: `${100 - index * 20}%`,
|
||||
height: 90,
|
||||
transform: `translateX(-50%) translateY(${index * 110}px)`,
|
||||
background: `linear-gradient(45deg, ${colors.start}, ${colors.end})`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s ease',
|
||||
'&:hover': {
|
||||
transform: `translateX(-50%) translateY(${index * 110}px) scale(1.02)`,
|
||||
boxShadow: 3
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" className="text-white font-cormorant">
|
||||
{socialClass.name}
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
{/* Character Examples */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card className="border border-sage-200 hover:border-sage-300 transition-all">
|
||||
<CardContent className="p-6">
|
||||
<Typography variant="h5" className="font-cormorant text-sage-900 mb-4">
|
||||
Notable Characters
|
||||
</Typography>
|
||||
{selectedCharacter && (
|
||||
<div className="mb-4 p-3 bg-sage-50 border border-sage-200 rounded-lg">
|
||||
<Typography className="text-sage-700 text-sm">
|
||||
<span className="font-semibold">{selectedCharacter.name}</span> selected.
|
||||
Click another character to compare, or click again to deselect.
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-4">
|
||||
{characters.map((character) => (
|
||||
<Card
|
||||
key={character.id}
|
||||
onClick={() => handleCharacterClick(character)}
|
||||
className={`
|
||||
border transition-all cursor-pointer
|
||||
${selectedCharacter?.id === character.id
|
||||
? 'border-sage-500 bg-sage-50 shadow-md transform scale-[1.02]'
|
||||
: 'border-sage-200 bg-white hover:border-sage-300 hover:shadow-sm hover:bg-sage-50/30'
|
||||
}
|
||||
`}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
'&:after': selectedCharacter?.id === character.id ? {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
left: -2,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
width: 4,
|
||||
height: '70%',
|
||||
backgroundColor: '#4A5D52',
|
||||
borderRadius: '0 2px 2px 0'
|
||||
} : {}
|
||||
}}
|
||||
>
|
||||
<CardContent className="p-4">
|
||||
<Box className="flex justify-between items-start">
|
||||
<div>
|
||||
<Typography variant="h6" className={`font-cormorant ${selectedCharacter?.id === character.id ? 'text-sage-900' : 'text-sage-800'}`}>
|
||||
{character.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" className="text-sage-600 mb-2">
|
||||
{character.novel}
|
||||
</Typography>
|
||||
</div>
|
||||
<Chip
|
||||
label={character.socialClass.charAt(0).toUpperCase() + character.socialClass.slice(1)}
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: character.socialClass === 'upper' ? pyramidColors.upper.start :
|
||||
character.socialClass === 'middle' ? pyramidColors.middle.start :
|
||||
pyramidColors.lower.start,
|
||||
color: 'white',
|
||||
fontFamily: '"Lato", sans-serif',
|
||||
transition: 'all 0.2s ease',
|
||||
transform: selectedCharacter?.id === character.id ? 'scale(1.05)' : 'scale(1)'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box className="mt-2 text-sage-700">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span>Annual Income:</span>
|
||||
<span className="font-semibold">{character.annualIncome}</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm text-sage-600">
|
||||
<span>Modern Equivalent:</span>
|
||||
<span>{character.modernEquivalent}</span>
|
||||
</div>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Comparison Dialog */}
|
||||
<Dialog open={dialogOpen} onClose={handleCloseDialog} maxWidth="md" fullWidth>
|
||||
<DialogTitle>Character Comparison</DialogTitle>
|
||||
<DialogContent>
|
||||
<Dialog
|
||||
open={dialogOpen}
|
||||
onClose={handleCloseDialog}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
className: "rounded-lg overflow-hidden"
|
||||
}}
|
||||
>
|
||||
<DialogTitle className="bg-sage-700 text-white font-cormorant py-4">
|
||||
Character Comparison
|
||||
</DialogTitle>
|
||||
<DialogContent className="p-6">
|
||||
{selectedCharacter && comparisonCharacter && (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="h6" gutterBottom>{selectedCharacter.name}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Novel: {selectedCharacter.novel}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Class: {selectedCharacter.socialClass}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Income: {selectedCharacter.annualIncome}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Modern: {selectedCharacter.modernEquivalent}</Typography>
|
||||
<Typography variant="body2">{selectedCharacter.description}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="h6" gutterBottom>{comparisonCharacter.name}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Novel: {comparisonCharacter.novel}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Class: {comparisonCharacter.socialClass}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Income: {comparisonCharacter.annualIncome}</Typography>
|
||||
<Typography variant="body2" gutterBottom>Modern: {comparisonCharacter.modernEquivalent}</Typography>
|
||||
<Typography variant="body2">{comparisonCharacter.description}</Typography>
|
||||
</Grid>
|
||||
<Grid container spacing={4}>
|
||||
{[selectedCharacter, comparisonCharacter].map((char, index) => (
|
||||
<Grid item xs={6} key={char.id}>
|
||||
<Typography variant="h6" className="font-cormorant text-sage-900 mb-3">
|
||||
{char.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={char.socialClass.charAt(0).toUpperCase() + char.socialClass.slice(1)}
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: char.socialClass === 'upper' ? pyramidColors.upper.start :
|
||||
char.socialClass === 'middle' ? pyramidColors.middle.start :
|
||||
pyramidColors.lower.start,
|
||||
color: 'white',
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-3 text-sage-700 mt-4">
|
||||
<div>
|
||||
<Typography variant="body2" className="text-sage-600 font-semibold">
|
||||
Novel
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
{char.novel}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="body2" className="text-sage-600 font-semibold">
|
||||
Annual Income
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
{char.annualIncome}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="body2" className="text-sage-600 font-semibold">
|
||||
Modern Equivalent
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
{char.modernEquivalent}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="body2" className="text-sage-600 font-semibold">
|
||||
Description
|
||||
</Typography>
|
||||
<Typography variant="body1" className="text-sage-700 leading-relaxed">
|
||||
{char.description}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
{index === 0 && (
|
||||
<Divider orientation="vertical" className="absolute right-0 top-0 bottom-0 bg-sage-200" />
|
||||
)}
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useState, useCallback, useRef } from 'react';
|
||||
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { characterNetwork } from '../data/character-network';
|
||||
import { CharacterNode, Relationship, BookNode } from '../types/character-network';
|
||||
import { Box, Typography, Paper, Grid, Card, CardContent, IconButton, Tooltip, Popper } from '@mui/material';
|
||||
import { Box, Typography, Paper, Grid, Card, CardContent, IconButton, Tooltip, Popper, Chip, Divider, Container, CircularProgress, Fade } from '@mui/material';
|
||||
import { ForceGraph2D } from 'react-force-graph';
|
||||
import { ArrowBack, Help } from '@mui/icons-material';
|
||||
import { ArrowBack, Help, ZoomIn, ZoomOut, CenterFocusStrong, Search } from '@mui/icons-material';
|
||||
import * as d3 from 'd3';
|
||||
|
||||
interface NetworkNode {
|
||||
|
|
@ -40,12 +40,40 @@ interface TooltipState {
|
|||
y: number;
|
||||
}
|
||||
|
||||
// Proper typing for ForceGraph methods
|
||||
interface ForceGraphMethods {
|
||||
zoom: (k: number) => void;
|
||||
zoomToFit: (durationMs?: number, padding?: number) => void;
|
||||
d3Force: (forceName: string, force: any) => void;
|
||||
getZoom: () => number;
|
||||
centerAt: (x?: number, y?: number, durationMs?: number) => void;
|
||||
}
|
||||
|
||||
export default function NetworkVisualization() {
|
||||
const [selectedNode, setSelectedNode] = useState<CharacterNode | BookNode | null>(null);
|
||||
const [selectedRelationships, setSelectedRelationships] = useState<Relationship[]>([]);
|
||||
const [selectedBook, setSelectedBook] = useState<string | null>(null);
|
||||
const [tooltip, setTooltip] = useState<TooltipState>({ open: false, content: '', x: 0, y: 0 });
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const graphRef = useRef<ForceGraphMethods>();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isGraphReady, setIsGraphReady] = useState(false);
|
||||
|
||||
// Add loading effect when data changes
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
const timer = setTimeout(() => {
|
||||
setIsLoading(false);
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [selectedBook]);
|
||||
|
||||
// Track when graph is ready
|
||||
useEffect(() => {
|
||||
if (graphRef.current) {
|
||||
setIsGraphReady(true);
|
||||
}
|
||||
}, [graphRef.current]);
|
||||
|
||||
const handleNodeHover = useCallback((node: NetworkNode | null) => {
|
||||
if (node) {
|
||||
|
|
@ -173,6 +201,12 @@ export default function NetworkVisualization() {
|
|||
const size = node.val || 5;
|
||||
const fontSize = Math.max(12 / scale, 2);
|
||||
|
||||
// Add glow effect for highlighted nodes
|
||||
if (node.id === selectedNode?.id) {
|
||||
ctx.shadowColor = node.color || '#fff';
|
||||
ctx.shadowBlur = 15;
|
||||
}
|
||||
|
||||
// Draw node
|
||||
ctx.beginPath();
|
||||
ctx.arc(node.x || 0, node.y || 0, size, 0, 2 * Math.PI);
|
||||
|
|
@ -182,6 +216,10 @@ export default function NetworkVisualization() {
|
|||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Clear shadow effect
|
||||
ctx.shadowColor = 'transparent';
|
||||
ctx.shadowBlur = 0;
|
||||
|
||||
// Only draw labels when zoomed in enough or for book nodes
|
||||
if (scale > 0.7 || node.type === 'book') {
|
||||
const labelDistance = size + fontSize;
|
||||
|
|
@ -189,7 +227,7 @@ export default function NetworkVisualization() {
|
|||
const textWidth = ctx.measureText(node.name).width;
|
||||
|
||||
// Semi-transparent background for better readability
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';
|
||||
const padding = fontSize * 0.3;
|
||||
const backgroundHeight = fontSize + padding * 2;
|
||||
|
||||
|
|
@ -206,7 +244,7 @@ export default function NetworkVisualization() {
|
|||
);
|
||||
|
||||
// Draw text
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillStyle = node.id === selectedNode?.id ? '#1976d2' : '#000';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(
|
||||
|
|
@ -215,7 +253,7 @@ export default function NetworkVisualization() {
|
|||
(node.y || 0) + labelDistance
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
}, [selectedNode]);
|
||||
|
||||
// Helper function for drawing rounded rectangles
|
||||
const roundRect = (
|
||||
|
|
@ -267,171 +305,389 @@ export default function NetworkVisualization() {
|
|||
</Box>
|
||||
);
|
||||
|
||||
const handleZoomIn = () => {
|
||||
if (graphRef.current) {
|
||||
const currentZoom = graphRef.current.getZoom();
|
||||
graphRef.current.zoom(currentZoom * 1.5);
|
||||
}
|
||||
};
|
||||
|
||||
const handleZoomOut = () => {
|
||||
if (graphRef.current) {
|
||||
const currentZoom = graphRef.current.getZoom();
|
||||
graphRef.current.zoom(currentZoom / 1.5);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCenterGraph = () => {
|
||||
if (graphRef.current) {
|
||||
graphRef.current.zoomToFit(400, 50);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
flexDirection: 'column',
|
||||
bgcolor: 'background.default',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
mb: 2,
|
||||
px: 3,
|
||||
pt: 2
|
||||
}}>
|
||||
<Typography variant="h4">
|
||||
Character Network
|
||||
</Typography>
|
||||
<Tooltip title={getLegendTooltip()} arrow placement="right">
|
||||
<IconButton size="small" sx={{ ml: 2 }}>
|
||||
<Help />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={0} sx={{ flex: 1, minHeight: 0 }}>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
height: '100%',
|
||||
minHeight: 700,
|
||||
position: 'relative',
|
||||
borderRadius: 0,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
{selectedBook && (
|
||||
<Tooltip title="Return to book overview" arrow>
|
||||
<IconButton
|
||||
onClick={handleBackClick}
|
||||
sx={{ position: 'absolute', top: 8, left: 8, zIndex: 1 }}
|
||||
>
|
||||
<ArrowBack />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Box sx={{
|
||||
position: 'absolute',
|
||||
top: 8,
|
||||
right: 8,
|
||||
zIndex: 1,
|
||||
bgcolor: 'rgba(255, 255, 255, 0.9)',
|
||||
p: 1,
|
||||
borderRadius: 1
|
||||
<Container maxWidth="xl" sx={{ flex: 1, display: 'flex', flexDirection: 'column', py: 3 }}>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
mb: 3,
|
||||
pb: 2,
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'divider'
|
||||
}}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Typography variant="h4" sx={{
|
||||
fontWeight: 500,
|
||||
color: 'primary.main',
|
||||
fontFamily: '"Cormorant", serif'
|
||||
}}>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{!selectedBook ? 'Click a book to explore its characters' : 'Click characters to view relationships'}
|
||||
</Typography>
|
||||
</Box>
|
||||
<ForceGraph2D
|
||||
graphData={getGraphData()}
|
||||
onNodeHover={handleNodeHover}
|
||||
onNodeClick={handleNodeClick}
|
||||
nodeCanvasObject={(node: NetworkNode, ctx: CanvasRenderingContext2D, scale: number) =>
|
||||
renderNodeCanvas(node, ctx, scale)}
|
||||
linkColor={(link: NetworkLink) => link.color}
|
||||
linkWidth={2}
|
||||
nodeRelSize={6}
|
||||
width={800}
|
||||
height={700}
|
||||
cooldownTicks={50}
|
||||
cooldownTime={3000}
|
||||
linkDirectionalParticles={2}
|
||||
linkDirectionalParticleSpeed={0.003}
|
||||
d3AlphaDecay={0.1}
|
||||
d3VelocityDecay={0.4}
|
||||
minZoom={0.5}
|
||||
maxZoom={4}
|
||||
dagMode={selectedBook ? undefined : 'radialin'}
|
||||
dagLevelDistance={100}
|
||||
enablePanInteraction={true}
|
||||
enableZoomInteraction={true}
|
||||
onEngineStop={() => {
|
||||
if (!selectedBook) {
|
||||
centerGraph(getGraphData());
|
||||
}
|
||||
}}
|
||||
onNodeDragEnd={(node: NetworkNode) => {
|
||||
if (node.x && node.y) {
|
||||
node.fx = node.x;
|
||||
node.fy = node.y;
|
||||
}
|
||||
}}
|
||||
warmupTicks={100}
|
||||
onZoom={() => centerGraph(getGraphData())}
|
||||
centerAt={[400, 350]}
|
||||
zoom={2}
|
||||
enableNodeDrag={true}
|
||||
enableZoomPanInteraction={true}
|
||||
/>
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Box sx={{
|
||||
height: '100%',
|
||||
minHeight: 700,
|
||||
overflow: 'auto',
|
||||
borderLeft: '1px solid rgba(0, 0, 0, 0.12)'
|
||||
}}>
|
||||
{selectedNode && (
|
||||
<Card sx={{ boxShadow: 'none', borderRadius: 0 }}>
|
||||
<CardContent>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
{selectedNode.name}
|
||||
</Typography>
|
||||
<Typography color="textSecondary" gutterBottom>
|
||||
{selectedNode.type === 'book' ? `Published: ${(selectedNode as BookNode).year}` : selectedNode.novel}
|
||||
</Typography>
|
||||
<Typography variant="body1" paragraph>
|
||||
{selectedNode.description}
|
||||
</Typography>
|
||||
|
||||
{selectedNode.type !== 'book' && (
|
||||
<>
|
||||
<Typography variant="body2" sx={{ mt: 2 }} color="textSecondary">
|
||||
Social Class: {(selectedNode as CharacterNode).class}
|
||||
<br />
|
||||
Character Role: {selectedNode.type}
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6" sx={{ mt: 3, mb: 2 }}>
|
||||
Relationships
|
||||
</Typography>
|
||||
{selectedRelationships.map((rel, index) => (
|
||||
<Box key={index} sx={{ mt: 2, p: 2, bgcolor: 'rgba(0, 0, 0, 0.02)', borderRadius: 1 }}>
|
||||
<Typography variant="subtitle1" color="primary">
|
||||
{rel.description}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary" gutterBottom>
|
||||
Type: {rel.type}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ mt: 1 }}>
|
||||
Development:
|
||||
</Typography>
|
||||
<ul style={{ margin: '8px 0', paddingLeft: 20 }}>
|
||||
{rel.development.map((step, i) => (
|
||||
<li key={i}>
|
||||
<Typography variant="body2">{step}</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
Character Network
|
||||
</Typography>
|
||||
<Tooltip title={getLegendTooltip()} arrow placement="right">
|
||||
<IconButton size="small" sx={{ ml: 2 }}>
|
||||
<Help />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: 1,
|
||||
bgcolor: 'background.paper',
|
||||
p: 0.5,
|
||||
borderRadius: 2,
|
||||
boxShadow: 1
|
||||
}}>
|
||||
<Tooltip title="Zoom in" arrow>
|
||||
<IconButton onClick={handleZoomIn} size="small">
|
||||
<ZoomIn />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Zoom out" arrow>
|
||||
<IconButton onClick={handleZoomOut} size="small">
|
||||
<ZoomOut />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Center graph" arrow>
|
||||
<IconButton onClick={handleCenterGraph} size="small">
|
||||
<CenterFocusStrong />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={3} sx={{ flex: 1, minHeight: 0 }}>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Paper
|
||||
elevation={4}
|
||||
sx={{
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
borderRadius: 2,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bgcolor: '#fafafa',
|
||||
boxShadow: theme => `0 0 20px ${theme.palette.divider}`
|
||||
}}
|
||||
ref={containerRef}
|
||||
>
|
||||
{/* Loading overlay */}
|
||||
<Fade in={isLoading} timeout={300}>
|
||||
<Box sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
bgcolor: 'rgba(255, 255, 255, 0.8)',
|
||||
zIndex: 10,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
gap: 2
|
||||
}}>
|
||||
<CircularProgress />
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
{selectedBook ? 'Loading character relationships...' : 'Loading books...'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Fade>
|
||||
|
||||
{/* Graph container */}
|
||||
<Fade in={!isLoading && isGraphReady} timeout={500}>
|
||||
<Box sx={{ width: '100%', height: '100%' }}>
|
||||
<ForceGraph2D
|
||||
// @ts-expect-error - type mismatch with ref
|
||||
ref={graphRef}
|
||||
graphData={getGraphData()}
|
||||
onNodeHover={handleNodeHover}
|
||||
onNodeClick={handleNodeClick}
|
||||
nodeCanvasObject={renderNodeCanvas}
|
||||
linkColor={(link: NetworkLink) => link.color}
|
||||
linkWidth={3}
|
||||
nodeRelSize={8}
|
||||
width={800}
|
||||
height={700}
|
||||
cooldownTicks={50}
|
||||
cooldownTime={3000}
|
||||
linkDirectionalParticles={3}
|
||||
linkDirectionalParticleWidth={2}
|
||||
linkDirectionalParticleSpeed={0.004}
|
||||
d3AlphaDecay={0.1}
|
||||
d3VelocityDecay={0.4}
|
||||
minZoom={0.5}
|
||||
maxZoom={4}
|
||||
dagMode={selectedBook ? undefined : 'radialin'}
|
||||
dagLevelDistance={100}
|
||||
enablePanInteraction={true}
|
||||
enableZoomInteraction={true}
|
||||
onEngineStop={() => {
|
||||
if (!selectedBook) {
|
||||
centerGraph(getGraphData());
|
||||
}
|
||||
}}
|
||||
onNodeDragEnd={(node: NetworkNode) => {
|
||||
if (node.x && node.y) {
|
||||
node.fx = node.x;
|
||||
node.fy = node.y;
|
||||
}
|
||||
}}
|
||||
warmupTicks={100}
|
||||
onZoom={(zoom: number) => {
|
||||
if (!selectedBook) {
|
||||
centerGraph(getGraphData());
|
||||
}
|
||||
}}
|
||||
enableNodeDrag={true}
|
||||
enableZoomPanInteraction={true}
|
||||
/>
|
||||
</Box>
|
||||
</Fade>
|
||||
|
||||
{/* Controls */}
|
||||
{!isLoading && (
|
||||
<>
|
||||
{selectedBook && (
|
||||
<Tooltip title="Return to book overview" arrow>
|
||||
<IconButton
|
||||
onClick={handleBackClick}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 16,
|
||||
left: 16,
|
||||
zIndex: 1,
|
||||
bgcolor: 'background.paper',
|
||||
boxShadow: 2,
|
||||
'&:hover': {
|
||||
bgcolor: 'background.paper',
|
||||
transform: 'scale(1.1)',
|
||||
transition: 'transform 0.2s'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArrowBack />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Box sx={{
|
||||
position: 'absolute',
|
||||
top: 16,
|
||||
right: 16,
|
||||
zIndex: 1,
|
||||
bgcolor: 'background.paper',
|
||||
p: 2,
|
||||
borderRadius: 2,
|
||||
boxShadow: 2,
|
||||
maxWidth: 250,
|
||||
backdropFilter: 'blur(8px)',
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
transition: 'opacity 0.3s',
|
||||
opacity: isGraphReady ? 1 : 0
|
||||
}}>
|
||||
<Typography variant="body2" color="text.secondary" sx={{
|
||||
fontStyle: 'italic',
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}>
|
||||
{!selectedBook ? 'Click a book to explore its characters' : 'Click characters to view relationships'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4} sx={{ height: '100%' }}>
|
||||
<Paper sx={{
|
||||
height: '100%',
|
||||
maxHeight: 'calc(100vh - 120px)', // Account for header and padding
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
borderRadius: 2,
|
||||
bgcolor: 'background.paper',
|
||||
boxShadow: theme => `0 0 20px ${theme.palette.divider}`,
|
||||
position: 'sticky',
|
||||
top: 24
|
||||
}}>
|
||||
<Box sx={{
|
||||
flex: 1,
|
||||
overflowY: 'auto',
|
||||
'&::-webkit-scrollbar': {
|
||||
width: '8px',
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: 'transparent',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
background: theme => theme.palette.divider,
|
||||
borderRadius: '4px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb:hover': {
|
||||
background: theme => theme.palette.action.hover,
|
||||
}
|
||||
}}>
|
||||
{selectedNode ? (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography variant="h5" gutterBottom sx={{
|
||||
color: 'primary.main',
|
||||
fontWeight: 500,
|
||||
fontFamily: '"Cormorant", serif'
|
||||
}}>
|
||||
{selectedNode.name}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1, mb: 2, flexWrap: 'wrap' }}>
|
||||
<Chip
|
||||
label={selectedNode.type === 'book' ? 'Novel' : selectedNode.type}
|
||||
size="small"
|
||||
color={selectedNode.type === 'protagonist' ? 'primary' :
|
||||
selectedNode.type === 'antagonist' ? 'error' : 'default'}
|
||||
sx={{ borderRadius: 1 }}
|
||||
/>
|
||||
{selectedNode.type !== 'book' && (
|
||||
<Chip
|
||||
label={(selectedNode as CharacterNode).class}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ borderRadius: 1 }}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Typography color="text.secondary" gutterBottom sx={{
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}>
|
||||
{selectedNode.type === 'book' ? `Published: ${(selectedNode as BookNode).year}` : selectedNode.novel}
|
||||
</Typography>
|
||||
<Typography variant="body1" paragraph sx={{
|
||||
mt: 2,
|
||||
fontFamily: '"Lato", sans-serif',
|
||||
lineHeight: 1.7
|
||||
}}>
|
||||
{selectedNode.description}
|
||||
</Typography>
|
||||
|
||||
{selectedNode.type !== 'book' && (
|
||||
<>
|
||||
<Divider sx={{ my: 3 }} />
|
||||
<Typography variant="h6" sx={{
|
||||
mb: 2,
|
||||
color: 'primary.main',
|
||||
fontFamily: '"Cormorant", serif'
|
||||
}}>
|
||||
Relationships
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
{selectedRelationships.map((rel, index) => (
|
||||
<Box key={index} sx={{
|
||||
p: 2.5,
|
||||
bgcolor: 'background.default',
|
||||
borderRadius: 2,
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
transition: 'transform 0.2s, box-shadow 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: 1
|
||||
}
|
||||
}}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom sx={{
|
||||
fontFamily: '"Cormorant", serif',
|
||||
fontWeight: 600
|
||||
}}>
|
||||
{rel.description}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={rel.type}
|
||||
size="small"
|
||||
sx={{
|
||||
mb: 2,
|
||||
bgcolor: rel.type === 'family' ? 'success.light' :
|
||||
rel.type === 'romance' ? 'error.light' :
|
||||
rel.type === 'friendship' ? 'primary.light' : 'warning.light',
|
||||
color: '#fff',
|
||||
borderRadius: 1,
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}
|
||||
/>
|
||||
<Typography variant="body2" sx={{
|
||||
fontWeight: 500,
|
||||
mt: 1,
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}>
|
||||
Development:
|
||||
</Typography>
|
||||
<Box component="ul" sx={{
|
||||
mt: 1,
|
||||
pl: 2,
|
||||
mb: 0 // Remove bottom margin from list
|
||||
}}>
|
||||
{rel.development.map((step, i) => (
|
||||
<Box component="li" key={i} sx={{
|
||||
mb: i === rel.development.length - 1 ? 0 : 1.5 // Remove margin from last item
|
||||
}}>
|
||||
<Typography variant="body2" color="text.secondary" sx={{
|
||||
fontFamily: '"Lato", sans-serif',
|
||||
lineHeight: 1.6
|
||||
}}>
|
||||
{step}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{
|
||||
p: 3,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
color: 'text.secondary'
|
||||
}}>
|
||||
<Typography variant="body1" sx={{ fontStyle: 'italic' }}>
|
||||
Select a node to view details
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
|
||||
<Popper
|
||||
open={tooltip.open}
|
||||
|
|
@ -447,11 +703,16 @@ export default function NetworkVisualization() {
|
|||
<Paper sx={{
|
||||
p: 2,
|
||||
maxWidth: 300,
|
||||
bgcolor: 'rgba(255, 255, 255, 0.95)',
|
||||
boxShadow: 3,
|
||||
borderRadius: 1
|
||||
bgcolor: 'background.paper',
|
||||
boxShadow: 4,
|
||||
borderRadius: 2,
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
backdropFilter: 'blur(8px)'
|
||||
}}>
|
||||
<Typography variant="body2" whiteSpace="pre-line">
|
||||
<Typography variant="body2" whiteSpace="pre-line" sx={{
|
||||
fontFamily: '"Lato", sans-serif'
|
||||
}}>
|
||||
{tooltip.content}
|
||||
</Typography>
|
||||
</Paper>
|
||||
|
|
|
|||
|
|
@ -1,194 +1,326 @@
|
|||
import React from 'react';
|
||||
import { Box, Typography, Paper, Grid, Chip, Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
|
||||
import { Typography, Paper, Grid, Chip, Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import SocialClassView from '../components/SocialClassView';
|
||||
|
||||
export default function SocialClass() {
|
||||
return (
|
||||
<Box sx={{ width: '100%', p: 3, maxWidth: 1200, mx: 'auto' }}>
|
||||
<div className="container mx-auto px-4 py-8 max-w-7xl">
|
||||
{/* Header Section */}
|
||||
<Box sx={{ mb: 6, textAlign: 'center' }}>
|
||||
<Typography variant="h3" component="h1" gutterBottom fontFamily="cormorant" color="primary.main">
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="font-cormorant text-4xl md:text-5xl text-sage-900 mb-4">
|
||||
Social Class in Jane Austen's Works
|
||||
</Typography>
|
||||
<Typography variant="h6" color="text.secondary" sx={{ mb: 3, maxWidth: 800, mx: 'auto' }}>
|
||||
</h1>
|
||||
<p className="text-sage-600 text-lg max-w-3xl mx-auto mb-6">
|
||||
An analysis of how social class shapes character relationships, marriage prospects, and social mobility across Austen's novels
|
||||
and their modern retellings.
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'center', flexWrap: 'wrap' }}>
|
||||
<Chip label="Class Mobility" color="primary" />
|
||||
<Chip label="Marriage Market" color="secondary" />
|
||||
<Chip label="Social Status" color="success" />
|
||||
<Chip label="Wealth & Property" color="warning" />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Character Analysis Section */}
|
||||
<Paper elevation={3} sx={{ p: 4, mb: 4, borderRadius: 2 }}>
|
||||
<Typography variant="h5" gutterBottom color="primary" fontFamily="cormorant">
|
||||
Character Studies Across Class Lines
|
||||
</Typography>
|
||||
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="h6" color="secondary">Pride and Prejudice: The Economics of Marriage</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>Upper Class</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Mr. Darcy (£10,000 per year)</strong>: Represents the pinnacle of landed gentry, whose wealth
|
||||
allows him to transcend local social barriers. His initial pride stems from his position, but his
|
||||
character development shows wealth doesn't guarantee happiness or love.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Lady Catherine de Bourgh</strong>: Embodies the aristocracy's resistance to social mobility,
|
||||
particularly in her opposition to Darcy and Elizabeth's marriage. Her character critiques the
|
||||
assumption that high birth equals moral superiority.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>Middle & Lower Classes</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>The Bennet Family</strong>: Despite their genteel status, their precarious financial position
|
||||
(with the entailed estate) demonstrates the vulnerability of women in the period. Mrs. Bennet's
|
||||
anxiety about her daughters' marriages stems from real economic concerns.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>The Servants (via Longbourn)</strong>: Jo Baker's retelling gives voice to characters like
|
||||
Sarah and Mrs. Hill, revealing the hidden labor that maintains the genteel lifestyle of the main characters.
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
<Accordion>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="h6" color="secondary">Mansfield Park: Moral Worth vs. Social Status</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>The Privileged Circle</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>The Bertram Family</strong>: Sir Thomas's wealth from colonial enterprises in Antigua
|
||||
raises questions about the source of aristocratic wealth. His children's poor moral education
|
||||
despite their privileged upbringing challenges assumptions about class and character.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Mary and Henry Crawford</strong>: Their London sophistication and wealth mask moral
|
||||
bankruptcy, contrasting with Fanny's humble virtue. They represent the corruption of urban wealth
|
||||
versus rural values.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>The Dependent Relations</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Fanny Price</strong>: Her position as a poor relation taken in by wealthy relatives
|
||||
highlights the complex dynamics of dependency and gratitude. Her moral strength despite her low
|
||||
status challenges class-based assumptions about worth.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>The Price Family in Portsmouth</strong>: Their cramped, chaotic household provides a
|
||||
stark contrast to Mansfield's luxury, highlighting the material realities of class difference
|
||||
in the period.
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
<Accordion>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="h6" color="secondary">Contemporary Perspectives: Modern Retellings</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>Pride by Ibi Zoboi</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Zuri Benitez</strong>: Reimagines Elizabeth Bennet as a proud Afro-Latina teenager in
|
||||
Brooklyn, exploring how gentrification and cultural identity intersect with class in contemporary
|
||||
America.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Darius Darcy</strong>: As a wealthy African American teenager, his character explores the
|
||||
complexities of privilege within modern racial and social contexts, updating Austen's examination
|
||||
of pride and prejudice.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" color="primary" gutterBottom>Longbourn's Legacy</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>The Servants' Perspective</strong>: Baker's novel reveals the physical labor, limited
|
||||
opportunities, and complex relationships that supported the genteel world of Pride and Prejudice,
|
||||
giving voice to historically silenced characters.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
<strong>Class Intersections</strong>: Through characters like James Smith, the novel explores how
|
||||
war, servitude, and social mobility operated for those below stairs, expanding our understanding
|
||||
of Austen's world.
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Paper>
|
||||
</p>
|
||||
<div className="flex gap-2 justify-center flex-wrap">
|
||||
<Chip
|
||||
label="Class Mobility"
|
||||
sx={{
|
||||
bgcolor: '#4A5D52',
|
||||
color: 'white',
|
||||
'&:hover': { bgcolor: '#3A4D42' }
|
||||
}}
|
||||
/>
|
||||
<Chip
|
||||
label="Marriage Market"
|
||||
sx={{
|
||||
bgcolor: '#5B6E65',
|
||||
color: 'white',
|
||||
'&:hover': { bgcolor: '#4B5E55' }
|
||||
}}
|
||||
/>
|
||||
<Chip
|
||||
label="Social Status"
|
||||
sx={{
|
||||
bgcolor: '#6B7F75',
|
||||
color: 'white',
|
||||
'&:hover': { bgcolor: '#5B6F65' }
|
||||
}}
|
||||
/>
|
||||
<Chip
|
||||
label="Wealth & Property"
|
||||
sx={{
|
||||
bgcolor: '#7C8F86',
|
||||
color: 'white',
|
||||
'&:hover': { bgcolor: '#6C7F76' }
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Interactive View */}
|
||||
<Paper elevation={3} sx={{ p: 4, mb: 4, borderRadius: 2 }}>
|
||||
<Typography variant="h5" gutterBottom color="primary" fontFamily="cormorant" sx={{ mb: 3 }}>
|
||||
Interactive Class Analysis
|
||||
</Typography>
|
||||
<SocialClassView />
|
||||
<Paper className="mb-8 rounded-lg border border-sage-200" elevation={0}>
|
||||
<div className="p-6 md:p-8">
|
||||
<Typography variant="h5" className="font-cormorant text-2xl text-sage-900 mb-4">
|
||||
Interactive Class Analysis
|
||||
</Typography>
|
||||
<div className="bg-sage-50 p-6 rounded-lg mb-6">
|
||||
<Typography variant="h6" className="font-cormorant text-xl text-sage-800 mb-3">
|
||||
Explore Social Class Differences
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<div className="mb-4">
|
||||
<p className="text-sage-800 font-medium mb-2">How to Compare Characters:</p>
|
||||
<div className="pl-4 space-y-2">
|
||||
<p className="leading-relaxed flex items-start">
|
||||
<span className="text-sage-900 font-semibold mr-2">1.</span>
|
||||
Select your first character by clicking on any character card below
|
||||
</p>
|
||||
<p className="leading-relaxed flex items-start">
|
||||
<span className="text-sage-900 font-semibold mr-2">2.</span>
|
||||
Choose a second character to initiate the comparison
|
||||
</p>
|
||||
<p className="leading-relaxed flex items-start">
|
||||
<span className="text-sage-900 font-semibold mr-2">3.</span>
|
||||
Examine their social positions, incomes, and circumstances in the comparison view
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/50 p-4 rounded-lg">
|
||||
<p className="text-sage-800 font-medium mb-2">Suggested Comparisons:</p>
|
||||
<ul className="list-disc list-inside space-y-1 text-sage-600">
|
||||
<li>Mr. Darcy vs. Elizabeth Bennet - Explore the class divide in courtship</li>
|
||||
<li>The Bennet Family vs. The Servants - Understand the full spectrum of social hierarchy</li>
|
||||
<li>Upper Class vs. Working Class - See the economic disparities of Regency England</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p className="text-sage-600 italic border-l-2 border-sage-300 pl-4 mt-4">
|
||||
💡 Tip: Compare characters from different social classes to understand how wealth, status, and opportunities
|
||||
varied dramatically in Austen's world.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<SocialClassView />
|
||||
</div>
|
||||
</Paper>
|
||||
|
||||
{/* Character Analysis Section */}
|
||||
<Paper className="mb-8 rounded-lg border border-sage-200" elevation={0}>
|
||||
<div className="p-6 md:p-8">
|
||||
<Typography variant="h5" className="font-cormorant text-2xl text-sage-900 mb-6">
|
||||
Character Studies Across Class Lines
|
||||
</Typography>
|
||||
|
||||
<Accordion
|
||||
defaultExpanded
|
||||
sx={{
|
||||
border: '1px solid #E2E8F0',
|
||||
'&:before': { display: 'none' },
|
||||
borderRadius: '0.5rem',
|
||||
mb: 2,
|
||||
'&:first-of-type': { borderRadius: '0.5rem' },
|
||||
'&:last-of-type': { borderRadius: '0.5rem' }
|
||||
}}
|
||||
>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon className="text-sage-600" />}
|
||||
className="bg-sage-50 hover:bg-sage-100"
|
||||
>
|
||||
<Typography className="font-cormorant text-xl text-sage-800">
|
||||
Pride and Prejudice: The Economics of Marriage
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className="bg-white p-6">
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
Upper Class
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Mr. Darcy (£10,000 per year)</strong>: Represents the pinnacle of landed gentry, whose wealth
|
||||
allows him to transcend local social barriers. His initial pride stems from his position, but his
|
||||
character development shows wealth doesn't guarantee happiness or love.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Lady Catherine de Bourgh</strong>: Embodies the aristocracy's resistance to social mobility,
|
||||
particularly in her opposition to Darcy and Elizabeth's marriage. Her character critiques the
|
||||
assumption that high birth equals moral superiority.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
Middle & Lower Classes
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>The Bennet Family</strong>: Despite their genteel status, their precarious financial position
|
||||
(with the entailed estate) demonstrates the vulnerability of women in the period. Mrs. Bennet's
|
||||
anxiety about her daughters' marriages stems from real economic concerns.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>The Servants (via Longbourn)</strong>: Jo Baker's retelling gives voice to characters like
|
||||
Sarah and Mrs. Hill, revealing the hidden labor that maintains the genteel lifestyle of the main characters.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
<Accordion
|
||||
sx={{
|
||||
border: '1px solid #E2E8F0',
|
||||
'&:before': { display: 'none' },
|
||||
borderRadius: '0.5rem',
|
||||
mb: 2
|
||||
}}
|
||||
>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon className="text-sage-600" />}
|
||||
className="bg-sage-50 hover:bg-sage-100"
|
||||
>
|
||||
<Typography className="font-cormorant text-xl text-sage-800">
|
||||
Mansfield Park: Moral Worth vs. Social Status
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className="bg-white p-6">
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
The Privileged Circle
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>The Bertram Family</strong>: Sir Thomas's wealth from colonial enterprises in Antigua
|
||||
raises questions about the source of aristocratic wealth. His children's poor moral education
|
||||
despite their privileged upbringing challenges assumptions about class and character.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Mary and Henry Crawford</strong>: Their London sophistication and wealth mask moral
|
||||
bankruptcy, contrasting with Fanny's humble virtue. They represent the corruption of urban wealth
|
||||
versus rural values.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
The Dependent Relations
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Fanny Price</strong>: Her position as a poor relation taken in by wealthy relatives
|
||||
highlights the complex dynamics of dependency and gratitude. Her moral strength despite her low
|
||||
status challenges class-based assumptions about worth.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>The Price Family in Portsmouth</strong>: Their cramped, chaotic household provides a
|
||||
stark contrast to Mansfield's luxury, highlighting the material realities of class difference
|
||||
in the period.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
<Accordion
|
||||
sx={{
|
||||
border: '1px solid #E2E8F0',
|
||||
'&:before': { display: 'none' },
|
||||
borderRadius: '0.5rem'
|
||||
}}
|
||||
>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon className="text-sage-600" />}
|
||||
className="bg-sage-50 hover:bg-sage-100"
|
||||
>
|
||||
<Typography className="font-cormorant text-xl text-sage-800">
|
||||
Contemporary Perspectives: Modern Retellings
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className="bg-white p-6">
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
Pride by Ibi Zoboi
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Zuri Benitez</strong>: Reimagines Elizabeth Bennet as a proud Afro-Latina teenager in
|
||||
Brooklyn, exploring how gentrification and cultural identity intersect with class in contemporary
|
||||
America.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Darius Darcy</strong>: As a wealthy African American teenager, his character explores the
|
||||
complexities of privilege within modern racial and social contexts, updating Austen's examination
|
||||
of pride and prejudice.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography className="font-cormorant text-lg text-sage-800 mb-3">
|
||||
Longbourn's Legacy
|
||||
</Typography>
|
||||
<div className="space-y-4 text-sage-700">
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>The Servants' Perspective</strong>: Baker's novel reveals the physical labor, limited
|
||||
opportunities, and complex relationships that supported the genteel world of Pride and Prejudice,
|
||||
giving voice to historically silenced characters.
|
||||
</Typography>
|
||||
<Typography paragraph className="leading-relaxed">
|
||||
<strong>Class Intersections</strong>: Through characters like James Smith, the novel explores how
|
||||
war, servitude, and social mobility operated for those below stairs, expanding our understanding
|
||||
of Austen's world.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</div>
|
||||
</Paper>
|
||||
|
||||
{/* Critical Analysis */}
|
||||
<Paper elevation={3} sx={{ p: 4, borderRadius: 2 }}>
|
||||
<Typography variant="h5" gutterBottom color="primary" fontFamily="cormorant">
|
||||
Critical Insights
|
||||
</Typography>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Box sx={{ p: 2, bgcolor: 'background.default', borderRadius: 1 }}>
|
||||
<Typography variant="h6" gutterBottom color="secondary">
|
||||
Economic Realities
|
||||
</Typography>
|
||||
<Typography>
|
||||
Austen's precise attention to characters' incomes and property reflects the real economic pressures
|
||||
that shaped marriage choices and social mobility in the Regency period. Her novels acknowledge both
|
||||
the practical necessity of financial security and its moral dangers.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Paper className="rounded-lg border border-sage-200" elevation={0}>
|
||||
<div className="p-6 md:p-8">
|
||||
<Typography variant="h5" className="font-cormorant text-2xl text-sage-900 mb-6">
|
||||
Critical Insights
|
||||
</Typography>
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<div className="bg-sage-50 p-6 rounded-lg">
|
||||
<Typography className="font-cormorant text-xl text-sage-800 mb-3">
|
||||
Economic Realities
|
||||
</Typography>
|
||||
<Typography className="text-sage-700 leading-relaxed">
|
||||
Austen's precise attention to characters' incomes and property reflects the real economic pressures
|
||||
that shaped marriage choices and social mobility in the Regency period. Her novels acknowledge both
|
||||
the practical necessity of financial security and its moral dangers.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<div className="bg-sage-50 p-6 rounded-lg">
|
||||
<Typography className="font-cormorant text-xl text-sage-800 mb-3">
|
||||
Social Mobility
|
||||
</Typography>
|
||||
<Typography className="text-sage-700 leading-relaxed">
|
||||
Through characters like Emma Woodhouse and Elizabeth Bennet, Austen explores the possibilities and
|
||||
limitations of social mobility through marriage, education, and moral development, while acknowledging
|
||||
the rigid class structures of her time.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<div className="bg-sage-50 p-6 rounded-lg">
|
||||
<Typography className="font-cormorant text-xl text-sage-800 mb-3">
|
||||
Modern Relevance
|
||||
</Typography>
|
||||
<Typography className="text-sage-700 leading-relaxed">
|
||||
Contemporary adaptations like Pride and Longbourn demonstrate how Austen's exploration of class,
|
||||
privilege, and social mobility remains relevant to modern discussions of inequality, opportunity,
|
||||
and social justice.
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Box sx={{ p: 2, bgcolor: 'background.default', borderRadius: 1 }}>
|
||||
<Typography variant="h6" gutterBottom color="secondary">
|
||||
Social Mobility
|
||||
</Typography>
|
||||
<Typography>
|
||||
Through characters like Emma Woodhouse and Elizabeth Bennet, Austen explores the possibilities and
|
||||
limitations of social mobility through marriage, education, and moral development, while acknowledging
|
||||
the rigid class structures of her time.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Box sx={{ p: 2, bgcolor: 'background.default', borderRadius: 1 }}>
|
||||
<Typography variant="h6" gutterBottom color="secondary">
|
||||
Modern Relevance
|
||||
</Typography>
|
||||
<Typography>
|
||||
Contemporary adaptations like Pride and Longbourn demonstrate how Austen's exploration of class,
|
||||
privilege, and social mobility remains relevant to modern discussions of inequality, opportunity,
|
||||
and social justice.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
</Paper>
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue