mirror of
https://github.com/harivansh-afk/Austens-Wedding-Guide.git
synced 2026-04-15 10:05:14 +00:00
removed blog post
This commit is contained in:
parent
e06beffcac
commit
2cf48254c4
13 changed files with 35 additions and 533 deletions
|
|
@ -1,5 +1,26 @@
|
|||
# Technical Documentation - ENGL 2502: Jane Austen
|
||||
|
||||
## Recent Changes
|
||||
|
||||
### Character Blogs Removal (Latest Update)
|
||||
|
||||
- Removed character blogs feature completely
|
||||
- Deleted related files:
|
||||
- `src/data/blog-posts.ts`
|
||||
- `src/data/blogPosts.ts`
|
||||
- `src/pages/Blogs.tsx`
|
||||
- `src/components/BlogPost.tsx`
|
||||
- `src/pages/BlogPost/BlogPost.tsx`
|
||||
- `src/types/blog.ts`
|
||||
- Updated navigation:
|
||||
- Removed blog routes from routing configuration
|
||||
- Removed "Character Blogs" from navigation menu
|
||||
- Removed Character Insights section from homepage
|
||||
- Cleaned up dependencies:
|
||||
- Removed unused imports
|
||||
- Fixed linter errors
|
||||
- Removed blog-related types from `src/types/index.ts`
|
||||
|
||||
## Project Overview
|
||||
|
||||
A React-based academic web application focused on analyzing Jane Austen's works, themes, and their modern relevance. The project combines literary analysis with interactive features to provide deep insights into Austen's novels and their contemporary interpretations.
|
||||
|
|
@ -37,45 +58,28 @@ src/
|
|||
│ ├── Navbar.tsx
|
||||
│ ├── Pagination.tsx
|
||||
│ └── theme-provider.tsx
|
||||
│
|
||||
├── data/
|
||||
│ ├── novels/ # Novel-specific content
|
||||
│ │ ├── northanger-abbey.ts
|
||||
│ │ ├── sense-and-sensibility.ts
|
||||
│ │ ├── pride-and-prejudice.ts
|
||||
│ │ └── mansfield-park.ts
|
||||
│ ├── analysis/ # Analysis data
|
||||
│ │ ├── themes.ts
|
||||
│ │ ├── characters.ts
|
||||
│ │ └── social-class.ts
|
||||
│ ├── contemporary/ # Modern retellings data
|
||||
│ │ ├── pride.ts # Pride by Ibi Zoboi
|
||||
│ │ └── longbourn.ts # Longbourn by Jo Baker
|
||||
│ └── timeline.ts # Chronological data
|
||||
│
|
||||
├── pages/
|
||||
│ ├── novels/ # Individual novel pages
|
||||
│ │ ├── NorthangerAbbey.tsx
|
||||
│ │ ├── SenseAndSensibility.tsx
|
||||
│ │ ├── PrideAndPrejudice.tsx
|
||||
│ │ └── MansfieldPark.tsx
|
||||
│ ├── Analysis.tsx # Literary analysis page
|
||||
│ ├── Characters.tsx # Character studies
|
||||
│ ├── Contemporary.tsx # Modern retellings
|
||||
│ ├── Network.tsx # Character network
|
||||
│ ├── Timeline.tsx # Interactive timeline
|
||||
│ └── SocialClass.tsx # Social class analysis
|
||||
```
|
||||
|
||||
## Navigation Structure
|
||||
|
||||
The application uses a new academically-focused navigation structure:
|
||||
The application uses a focused academic navigation structure:
|
||||
|
||||
### Primary Navigation
|
||||
|
||||
- Literary Analysis
|
||||
- Novel Studies
|
||||
- Character Studies
|
||||
- Quiz
|
||||
- Vendors
|
||||
- Success Stories
|
||||
- Market Calculator
|
||||
|
||||
### Analysis Navigation
|
||||
|
||||
- Literary Analysis
|
||||
- Character Network
|
||||
- Timeline
|
||||
- Social Class
|
||||
|
||||
### Course Novels (Norton Critical Editions)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import React, { Suspense } from 'react';
|
|||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import MainLayout from './components/layout/MainLayout';
|
||||
import Home from './pages/Home';
|
||||
import Blogs from './pages/Blogs';
|
||||
import BlogPost from './pages/BlogPost/BlogPost';
|
||||
import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
import SuccessStories from './pages/SuccessStories';
|
||||
import Analysis from './pages/Analysis';
|
||||
|
|
@ -25,8 +23,6 @@ function App() {
|
|||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/blogs" element={<Blogs />} />
|
||||
<Route path="/blogs/:id" element={<BlogPost />} />
|
||||
<Route path="/quiz" element={<Quiz />} />
|
||||
<Route path="/vendors" element={<Vendors />} />
|
||||
<Route path="/success-stories" element={<SuccessStories />} />
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
import { FC } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { format } from 'date-fns';
|
||||
import { BlogPost as BlogPostType } from '@/types/blog';
|
||||
|
||||
interface BlogPostProps {
|
||||
post: BlogPostType;
|
||||
}
|
||||
|
||||
const BlogPost: FC<BlogPostProps> = ({ post }) => {
|
||||
return (
|
||||
<Card className="mb-6">
|
||||
<CardHeader className="flex flex-row items-center gap-4">
|
||||
<Avatar>
|
||||
<AvatarImage src={post.authorImage} alt={post.author} />
|
||||
<AvatarFallback>{post.author[0]}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<CardTitle className="font-serif text-lg">{post.title}</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{format(new Date(post.date), 'MMMM d, yyyy')}
|
||||
</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="prose prose-neutral dark:prose-invert">
|
||||
{post.content.map((paragraph, index) => (
|
||||
<p key={index} className="mb-4 last:mb-0">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPost;
|
||||
|
|
@ -4,7 +4,6 @@ import { useState } from 'react';
|
|||
import { cn } from '@/lib/utils';
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Character Blogs', path: '/blogs' },
|
||||
{ name: 'Bride Quiz', path: '/quiz' },
|
||||
{ name: 'Vendors', path: '/vendors' },
|
||||
{ name: 'Success Stories', path: '/success-stories' },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { Routes as RouterRoutes, Route } from 'react-router-dom';
|
||||
import Home from '@/pages/Home';
|
||||
import Blogs from '@/pages/Blogs';
|
||||
import DearJane from '@/pages/DearJane';
|
||||
import Quiz from '@/pages/Quiz';
|
||||
import SuccessStories from '@/pages/SuccessStories';
|
||||
import Analysis from '@/pages/Analysis';
|
||||
|
|
@ -10,8 +8,6 @@ const Routes = () => {
|
|||
return (
|
||||
<RouterRoutes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/blogs" element={<Blogs />} />
|
||||
<Route path="/dear-jane" element={<DearJane />} />
|
||||
<Route path="/quiz" element={<Quiz />} />
|
||||
<Route path="/success-stories" element={<SuccessStories />} />
|
||||
<Route path="/analysis" element={<Analysis />} />
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
export const blogPosts = {
|
||||
charlotte: [
|
||||
{
|
||||
id: '1',
|
||||
title: 'The Pragmatic Path to Marriage',
|
||||
author: 'Charlotte Lucas',
|
||||
authorImage: '/images/authors/charlotte.jpg',
|
||||
date: '1813-01-15',
|
||||
content: [
|
||||
'My dear readers, I must confess that happiness in marriage is entirely a matter of chance. There will always be vexation and grief, and it is better to know as little as possible of the defects of the person with whom you are to pass your life.',
|
||||
'I am not romantic, you know. I never was. I ask only a comfortable home; and considering Mr. Collins\'s character, connections, and situation in life, I am convinced that my chance of happiness with him is as fair as most people can boast on entering the marriage state.',
|
||||
'Let us be practical in our pursuit of matrimony. A woman must secure her future while she has the power to do so.'
|
||||
]
|
||||
}
|
||||
],
|
||||
marianne: [
|
||||
{
|
||||
id: '2',
|
||||
title: 'The Heart Must Lead',
|
||||
author: 'Marianne Dashwood',
|
||||
authorImage: '/images/authors/marianne.jpg',
|
||||
date: '1813-03-15',
|
||||
content: [
|
||||
'To love is to burn, to be on fire! How can one possibly consider marriage without the deepest feelings of love and devotion?',
|
||||
'I could not be happy with a man whose taste did not in every point coincide with my own. He must enter into all my feelings; the same books, the same music must charm us both.',
|
||||
'Let others speak of prudence and practicality, but I shall never sacrifice the dictates of my heart to the opinions of the world.'
|
||||
]
|
||||
}
|
||||
],
|
||||
fanny: [
|
||||
{
|
||||
id: '3',
|
||||
title: 'On Principle and Affection',
|
||||
author: 'Fanny Price',
|
||||
authorImage: '/images/authors/fanny.jpg',
|
||||
date: '1814-01-15',
|
||||
content: [
|
||||
'We must all be guided by our own understanding of what is right. No circumstance should persuade us to act against our principles.',
|
||||
'True affection grows slowly, nurtured by shared values and mutual respect. It cannot be forced or rushed by the expectations of others.',
|
||||
'In matters of the heart, we must trust our own judgment above all else.'
|
||||
]
|
||||
}
|
||||
],
|
||||
catherine: [
|
||||
{
|
||||
id: '4',
|
||||
title: 'Romance and Reality',
|
||||
author: 'Catherine Morland',
|
||||
authorImage: '/images/authors/catherine.jpg',
|
||||
date: '1814-02-15',
|
||||
content: [
|
||||
'How thrilling it is to discover that real life can be just as fascinating as our favorite novels!',
|
||||
'Yet we must learn to distinguish between romantic fancy and true character. Not every ancient abbey holds a terrible secret, nor is every charming acquaintance hiding dark mysteries.',
|
||||
'The greatest adventures may be found in opening our hearts to genuine friendship and love.'
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
export interface BlogPost {
|
||||
id: number;
|
||||
title: string;
|
||||
character: string;
|
||||
date: string;
|
||||
content: string;
|
||||
imageUrl: string;
|
||||
tags?: string[];
|
||||
likes?: number;
|
||||
}
|
||||
|
||||
export const blogPosts: BlogPost[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "The Spirit of Community",
|
||||
character: "Lewis",
|
||||
date: "Spring 1",
|
||||
content: "As mayor of Pelican Town, nothing brings me more joy than seeing our community thrive. Today, our newest farmer arrived, breathing life into old Grandpa's farm. The look of determination in their eyes reminds me of the valley's golden days. Speaking of which, I should remind everyone about the upcoming Egg Festival - Marnie's chickens have been especially productive this year! And please, if anyone sees Pierre, tell him I need to discuss the flower arrangements for the town square...",
|
||||
imageUrl: "/images/blogs/lewis-blog.png",
|
||||
tags: ["community", "events", "announcements"],
|
||||
likes: 156
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Tales from the Sea",
|
||||
character: "Willy",
|
||||
date: "Spring 15",
|
||||
content: "The morning mist rolled in thick today, just the way I like it. Found something peculiar in my crab pots - a message in a bottle! Reminded me of my old sailor days... For those interested in fishing, the legend of the Crimsonfish resurfaces every summer. Some say it's just a tale, but I've seen things in these waters that would make a seasoned sailor question everything. Drop by the shop if you want to hear more, or need some quality bait.",
|
||||
imageUrl: "/images/blogs/willy-blog.png",
|
||||
tags: ["fishing", "legends", "sea stories"],
|
||||
likes: 89
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Behind the Bar",
|
||||
character: "Gus",
|
||||
date: "Summer 1",
|
||||
content: "Every night at the Stardrop Saloon tells a different story. Yesterday, Pam shared tales of her trucking days while Emily's positive energy kept everyone's spirits high. Shane actually joined a conversation about chicken farming with Marnie - a rare sight indeed! My special spaghetti recipe was a hit again, though I'll never reveal the secret ingredient (sorry, Lewis!). Remember, Fridays mean special discounts on pale ale - locally sourced from our very own farmer!",
|
||||
imageUrl: "/images/blogs/gus-blog.png",
|
||||
tags: ["saloon", "recipes", "community"],
|
||||
likes: 124
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Wizard's Musings",
|
||||
character: "Wizard",
|
||||
date: "Fall 13",
|
||||
content: "The veil between realms grows thin as we approach the season of spirits. I've observed unusual activities in the witch's swamp, and the junimos seem more active than ever. For those brave souls interested in the arcane arts, I'm considering hosting a seminar on mushroom identification and their magical properties. Note: Please stop asking about love potions - they're strictly forbidden and highly unstable...",
|
||||
imageUrl: "/images/blogs/wizard-blog.png",
|
||||
tags: ["magic", "junimos", "mystical"],
|
||||
likes: 201
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Adventures in Mining",
|
||||
character: "Clint",
|
||||
date: "Winter 8",
|
||||
content: "Found an extraordinary geode yesterday - the crystalline structure unlike anything I've seen before. If you're planning to explore the mines, remember to bring your sword and plenty of torches. I'm offering a special discount on tool upgrades this week. And no, I haven't worked up the courage to... well, never mind. Just come by the shop if you need anything forged.",
|
||||
imageUrl: "/images/blogs/clint-blog.png",
|
||||
tags: ["mining", "blacksmith", "tools"],
|
||||
likes: 67
|
||||
}
|
||||
];
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom';
|
||||
import { BlogPost as BlogPostType, blogPosts } from '../../data/blogPosts';
|
||||
import { LoadingSpinner } from '../../components/LoadingSpinner';
|
||||
import { ShareButtons } from '../../components/ShareButtons';
|
||||
import { CommentSection } from '../../components/CommentSection';
|
||||
|
||||
const BlogPost: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [post, setPost] = useState<BlogPostType | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const loadPost = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
// Simulate API call
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const foundPost = blogPosts.find(p => p.id === Number(id));
|
||||
if (!foundPost) {
|
||||
navigate('/blogs');
|
||||
return;
|
||||
}
|
||||
setPost(foundPost);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadPost();
|
||||
}, [id, navigate]);
|
||||
|
||||
if (isLoading) return <LoadingSpinner />;
|
||||
if (!post) return null;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-cream-50 py-8">
|
||||
<article className="max-w-4xl mx-auto px-4">
|
||||
<Link
|
||||
to="/blogs"
|
||||
className="inline-flex items-center text-sage-600 hover:text-sage-800 mb-8"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 mr-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||
/>
|
||||
</svg>
|
||||
Back to Blogs
|
||||
</Link>
|
||||
|
||||
<header className="mb-8">
|
||||
<img
|
||||
src={post.imageUrl}
|
||||
alt={`${post.character}'s blog post`}
|
||||
className="w-full h-[400px] object-cover rounded-xl shadow-lg mb-6"
|
||||
/>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
|
||||
{post.title}
|
||||
</h1>
|
||||
<div className="flex flex-wrap items-center gap-4 text-gray-600">
|
||||
<span className="font-medium">By {post.character}</span>
|
||||
<span>•</span>
|
||||
<span>{post.date}</span>
|
||||
{post.tags && (
|
||||
<>
|
||||
<span>•</span>
|
||||
<div className="flex gap-2">
|
||||
{post.tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="bg-sage-100 text-sage-800 px-2 py-1 rounded-full text-sm"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="prose prose-lg max-w-none mb-8">
|
||||
<p className="whitespace-pre-wrap">{post.content}</p>
|
||||
</div>
|
||||
|
||||
<footer className="border-t border-gray-200 pt-8">
|
||||
<ShareButtons post={post} />
|
||||
<CommentSection postId={post.id} />
|
||||
</footer>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPost;
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { blogPosts, BlogPost } from '../data/blogPosts';
|
||||
import { Pagination } from '../components/Pagination';
|
||||
|
||||
const POSTS_PER_PAGE = 6;
|
||||
|
||||
const BlogCard: React.FC<BlogPost> = ({
|
||||
id,
|
||||
title,
|
||||
character,
|
||||
date,
|
||||
content,
|
||||
imageUrl,
|
||||
tags,
|
||||
likes,
|
||||
}) => {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow duration-300">
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={`${character}'s blog post`}
|
||||
className="w-full h-48 object-cover"
|
||||
/>
|
||||
<div className="p-6">
|
||||
<h3 className="text-xl font-bold text-gray-800 mb-2">{title}</h3>
|
||||
<div className="flex items-center text-sm text-gray-600 mb-4">
|
||||
<span className="font-medium mr-2">By {character}</span>
|
||||
<span>• {date}</span>
|
||||
</div>
|
||||
<p className="text-gray-700 line-clamp-3">{content}</p>
|
||||
{tags && (
|
||||
<div className="flex flex-wrap gap-2 mt-4">
|
||||
{tags.map(tag => (
|
||||
<span
|
||||
key={tag}
|
||||
className="bg-sage-100 text-sage-800 px-2 py-1 rounded-full text-xs"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between mt-4">
|
||||
<Link
|
||||
to={`/blogs/${id}`}
|
||||
className="text-sage-600 hover:text-sage-800 font-medium inline-flex items-center"
|
||||
>
|
||||
Read more
|
||||
<svg
|
||||
className="w-4 h-4 ml-1"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</Link>
|
||||
{likes !== undefined && (
|
||||
<div className="flex items-center text-gray-500">
|
||||
<svg
|
||||
className="w-5 h-5 mr-1"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{likes}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Blogs: React.FC = () => {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [selectedCharacter, setSelectedCharacter] = useState('');
|
||||
const [selectedTag, setSelectedTag] = useState('');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
||||
const characters = useMemo(() => {
|
||||
return [...new Set(blogPosts.map(post => post.character))];
|
||||
}, []);
|
||||
|
||||
const tags = useMemo(() => {
|
||||
const allTags = blogPosts.flatMap(post => post.tags || []);
|
||||
return [...new Set(allTags)];
|
||||
}, []);
|
||||
|
||||
const filteredPosts = useMemo(() => {
|
||||
return blogPosts.filter(post => {
|
||||
const matchesSearch = (
|
||||
post.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
post.content.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
const matchesCharacter = !selectedCharacter || post.character === selectedCharacter;
|
||||
const matchesTag = !selectedTag || post.tags?.includes(selectedTag);
|
||||
return matchesSearch && matchesCharacter && matchesTag;
|
||||
});
|
||||
}, [searchTerm, selectedCharacter, selectedTag]);
|
||||
|
||||
const totalPages = Math.ceil(filteredPosts.length / POSTS_PER_PAGE);
|
||||
const currentPosts = filteredPosts.slice(
|
||||
(currentPage - 1) * POSTS_PER_PAGE,
|
||||
currentPage * POSTS_PER_PAGE
|
||||
);
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchTerm(e.target.value);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
const handleCharacterFilter = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
setSelectedCharacter(e.target.value);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
const handleTagFilter = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
setSelectedTag(e.target.value);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-cream-50 py-8">
|
||||
<div className="container mx-auto px-4">
|
||||
<h1 className="text-4xl font-bold text-center text-gray-900 mb-8">
|
||||
Character Blogs
|
||||
</h1>
|
||||
|
||||
<div className="mb-8 bg-white p-4 rounded-lg shadow-sm">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search blogs..."
|
||||
value={searchTerm}
|
||||
onChange={handleSearch}
|
||||
className="p-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-sage-500 focus:border-transparent"
|
||||
/>
|
||||
<select
|
||||
value={selectedCharacter}
|
||||
onChange={handleCharacterFilter}
|
||||
className="p-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-sage-500 focus:border-transparent"
|
||||
>
|
||||
<option value="">All Characters</option>
|
||||
{characters.map(char => (
|
||||
<option key={char} value={char}>
|
||||
{char}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<select
|
||||
value={selectedTag}
|
||||
onChange={handleTagFilter}
|
||||
className="p-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-sage-500 focus:border-transparent"
|
||||
>
|
||||
<option value="">All Tags</option>
|
||||
{tags.map(tag => (
|
||||
<option key={tag} value={tag}>
|
||||
{tag}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{currentPosts.length === 0 ? (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-gray-500 text-lg">
|
||||
No blog posts found matching your criteria.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
|
||||
{currentPosts.map(post => (
|
||||
<BlogCard key={post.id} {...post} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPageChange={setCurrentPage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Blogs;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Link } from 'react-router-dom';
|
||||
import { ArrowRight, BookOpen, Users, Heart, PenTool, Calendar, BookMarked } from 'lucide-react';
|
||||
import { ArrowRight, BookOpen, Heart, PenTool, Calendar, BookMarked } from 'lucide-react';
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
|
|
@ -76,17 +76,6 @@ const Home = () => {
|
|||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-8 rounded-xl shadow-sm border border-sage-100 hover:shadow-md transition">
|
||||
<Users className="h-10 w-10 text-sage-600 mb-4" />
|
||||
<h3 className="font-cormorant text-2xl text-sage-900 mb-3">Character Insights</h3>
|
||||
<p className="text-sage-700 mb-4">
|
||||
Meet Austen's memorable characters through their blogs, sharing timeless advice on love and marriage.
|
||||
</p>
|
||||
<Link to="/blogs" className="text-sage-600 hover:text-sage-800 inline-flex items-center">
|
||||
Read Blogs <ArrowRight className="ml-1 h-4 w-4" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-8 rounded-xl shadow-sm border border-sage-100 hover:shadow-md transition">
|
||||
<Heart className="h-10 w-10 text-sage-600 mb-4" />
|
||||
<h3 className="font-cormorant text-2xl text-sage-900 mb-3">Success Stories</h3>
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ export default function NetworkVisualization() {
|
|||
pt: 2
|
||||
}}>
|
||||
<Typography variant="h4">
|
||||
Character Network & Timeline
|
||||
Character Network
|
||||
</Typography>
|
||||
<Tooltip title={getLegendTooltip()} arrow placement="right">
|
||||
<IconButton size="small" sx={{ ml: 2 }}>
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
export interface BlogPost {
|
||||
id: string;
|
||||
title: string;
|
||||
author: string;
|
||||
authorImage: string;
|
||||
date: string;
|
||||
content: string[];
|
||||
}
|
||||
|
|
@ -1,12 +1,3 @@
|
|||
export interface BlogPost {
|
||||
id: string;
|
||||
title: string;
|
||||
author: string;
|
||||
content: string;
|
||||
date: string;
|
||||
category: 'charlotte' | 'marianne';
|
||||
}
|
||||
|
||||
export interface QuizQuestion {
|
||||
id: string;
|
||||
question: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue