Fix dark theme gradients on home page

This commit is contained in:
TheMaddax 2025-06-01 22:59:10 -06:00
parent 2e429b0af3
commit 512a5df89a
17 changed files with 521 additions and 116 deletions

View file

@ -10,6 +10,15 @@
- Planning authentication implementation for production deployment
## Recent Changes
- **FIXED**: Theme selector functionality has been completely resolved
- Identified and fixed conflicting theme systems (custom context vs next-themes)
- Updated ThemeSelector.tsx to use next-themes useTheme hook with resolvedTheme
- Modified layout.tsx to use proper next-themes configuration (attribute="class", defaultTheme="system")
- Removed conflicting custom context files (ThemeContext.tsx, ClientProviders.tsx)
- Theme switching now works properly with light/dark/system modes
- Used best practices from Perplexity MCP research for Next.js 13+ App Router theme implementation
- Current minor issue: Responsive design on smaller screens hides Donate button and theme selector (to be addressed later)
- Improved dark theme appearance and accessibility:
- Enhanced contrast for navigation menu items in dark mode by using white text
- Fixed site title "Olathe Club of the Deaf" contrast in dark mode by changing to white
@ -84,15 +93,14 @@
- Applied the same blue color used in the "Upcoming Events" button for consistency
## Next Steps
1. Complete backend API integrations:
- Connect admin UI components to backend endpoints (✓ Events management implemented, ✓ Members management implemented, ✓ Videos management implemented, ✓ Documents management implemented)
- Add real data loading with loading states (✓ Implemented for Events, ✓ Implemented for Members, ✓ Implemented for Videos, ✓ Implemented for Documents)
- Implement error handling for API requests (✓ Implemented for Events, ✓ Implemented for Members, ✓ Implemented for Videos, ✓ Implemented for Documents)
- Set up client-side data validation (✓ Implemented for Events, ✓ Implemented for Members, ✓ Implemented for Videos, ✓ Implemented for Documents)
1. Fix responsive navigation design:
- Investigate why mobile menu button isn't showing on smaller screens
- Ensure Donate button and theme selector are accessible on all screen sizes
- Test navigation functionality across different viewport sizes
2. Implement remaining admin features:
- Add form handlers for CRUD operations (✓ Implemented for Events, ✓ Implemented for Members, ✓ Implemented for Videos, ✓ Implemented for Documents)
- Create media upload components (✓ Implemented for Videos, ✓ Implemented for Documents)
- Add user notification system (Next priority)
- Enhance admin dashboard with real-time statistics
- Add advanced filtering and search capabilities
3. Deploy staging environment:
- Set up Docker containers for testing
- Configure environment variables
@ -149,6 +157,11 @@
- Enhanced Apply Filters button with more prominent blue styling to improve visibility
## Special Considerations
- **RESOLVED**: Theme selector functionality has been completely fixed
- Successfully implemented next-themes for proper theme management
- Removed conflicting custom context that was causing state management issues
- Theme switching now works seamlessly with proper SSR/hydration handling
- Minor responsive design issue on smaller screens to be addressed in next phase
- CRITICAL: Re-enable authentication middleware before production deployment
- Members routes (POST, PUT, DELETE, bulk-action)
- Events routes (POST, PUT, DELETE, registration)

View file

@ -97,6 +97,7 @@
- [x] Build media upload functionality
- [x] Simplify document management with improved PDF preview
- [x] Fix API route for proper document handling
- [x] Fix theme selector functionality with proper next-themes implementation
- [ ] Implement user notification system
- [ ] Create advanced filtering for data tables
- [ ] Develop data export functionality
@ -113,6 +114,8 @@
- [x] Improve paragraph text contrast in About and Membership sections
- [x] Fix "Join Our Community" section text contrast by changing background color
- [x] Standardize button styling by changing "View All Events" and "View All Board Members" to primary style
- [x] Fix theme selector functionality with proper next-themes integration
- [ ] Fix responsive navigation design for smaller screen sizes
- [ ] Conduct comprehensive accessibility audit
- [ ] Implement screen reader optimizations
- [ ] Refine keyboard navigation
@ -172,9 +175,9 @@
- [ ] Add comprehensive JSDoc comments
## Project Stats
- **Completed Tasks:** 68
- **Completed Tasks:** 70
- **In Progress Tasks:** 0
- **Upcoming Tasks:** 21
- **Completion Rate:** ~77%
- **Completion Rate:** ~78%
- **Current Phase:** Phase 4 - API Integration & Backend Functionality
- **Next Major Milestone:** Implement user notification system
- **Next Major Milestone:** Implement user notification system and fix responsive navigation

View file

@ -10,6 +10,7 @@
"dependencies": {
"framer-motion": "^12.6.0",
"next": "^15.3.3",
"next-themes": "^0.4.6",
"react": "19.0.0",
"react-dom": "19.0.0"
},
@ -4821,6 +4822,16 @@
}
}
},
"node_modules/next-themes": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",

View file

@ -12,6 +12,7 @@
"dependencies": {
"framer-motion": "^12.6.0",
"next": "^15.3.3",
"next-themes": "^0.4.6",
"react": "19.0.0",
"react-dom": "19.0.0"
},

View file

@ -14,7 +14,7 @@ export default function AboutPage() {
<section className="py-16 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">About Olathe Club of the Deaf</h1>
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">About Olathe Club of the Deaf</h1>
<p className="text-xl text-gray-700 dark:text-gray-300">
Connecting and empowering the deaf community in Olathe since 1975.
</p>
@ -88,8 +88,8 @@ export default function AboutPage() {
{Array.from({ length: 4 }).map((_, index) => (
<div key={index} className="text-center">
<div className="w-40 h-40 bg-gray-200 dark:bg-gray-700 rounded-full mx-auto mb-4"></div>
<h3 className="text-xl font-semibold">Board Member</h3>
<p className="text-primary dark:text-primary-light">Position</p>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">Board Member</h3>
<p className="text-blue-600 dark:text-blue-400">Position</p>
</div>
))}
</div>
@ -141,7 +141,7 @@ export default function AboutPage() {
<div className="flex flex-col sm:flex-row justify-center gap-4">
<Link
href="/membership"
className="bg-white text-primary hover:bg-gray-100 px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
className="bg-white text-primary hover:bg-gray-100 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
>
Become a Member
</Link>

View file

@ -14,7 +14,7 @@ export default function ContactPage() {
<section className="py-16 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Contact Us</h1>
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">Contact Us</h1>
<p className="text-xl text-gray-700 dark:text-gray-300">
We'd love to hear from you! Get in touch with any questions, ideas, or feedback.
</p>
@ -39,17 +39,17 @@ export default function ContactPage() {
<div className="space-y-6">
<div>
<h3 className="text-xl font-semibold mb-2">Email</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Email</h3>
<a
href="mailto:info@olathedeafclub.com"
className="text-primary hover:underline"
className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline"
>
info@olathedeafclub.com
</a>
</div>
<div>
<h3 className="text-xl font-semibold mb-2">Meeting Location</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Meeting Location</h3>
<address className="not-italic text-gray-700 dark:text-gray-300">
123 Main Street<br />
Olathe, KS 66061
@ -57,7 +57,7 @@ export default function ContactPage() {
</div>
<div>
<h3 className="text-xl font-semibold mb-2">Connect With Us</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Connect With Us</h3>
<div className="flex space-x-4">
<a
href="https://facebook.com"
@ -126,7 +126,7 @@ export default function ContactPage() {
<p className="text-lg text-gray-700 dark:text-gray-300">
We meet at 123 Main Street, Olathe, KS 66061
</p>
<p className="mt-2 text-primary dark:text-primary-light">
<p className="mt-2 text-blue-600 dark:text-blue-400">
<a
href="https://maps.google.com"
target="_blank"

View file

@ -14,7 +14,7 @@ export default function DonatePage() {
<section className="py-16 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Support Our Mission</h1>
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">Support Our Mission</h1>
<p className="text-xl text-gray-700 dark:text-gray-300">
Your donations help us continue to serve and support the deaf community in Olathe.
</p>
@ -197,25 +197,25 @@ export default function DonatePage() {
<h2 className="text-3xl font-bold mb-12 text-center">Donation FAQs</h2>
<div className="max-w-3xl mx-auto space-y-6">
<div className="card p-6">
<h3 className="text-xl font-semibold mb-2">Is my donation tax-deductible?</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Is my donation tax-deductible?</h3>
<p className="text-gray-600 dark:text-gray-300">
Yes, the Olathe Club of the Deaf is a 501(c)(3) nonprofit organization. All donations are tax-deductible to the extent allowed by law.
</p>
</div>
<div className="card p-6">
<h3 className="text-xl font-semibold mb-2">Can I specify how my donation is used?</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Can I specify how my donation is used?</h3>
<p className="text-gray-600 dark:text-gray-300">
Yes, you can designate your donation for a specific program or project. Please include a note with your donation or contact us to discuss your preferences.
</p>
</div>
<div className="card p-6">
<h3 className="text-xl font-semibold mb-2">Do you accept donations by check or mail?</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Do you accept donations by check or mail?</h3>
<p className="text-gray-600 dark:text-gray-300">
Yes, checks can be made payable to "Olathe Club of the Deaf" and mailed to our office address. Please contact us for the current mailing address.
</p>
</div>
<div className="card p-6">
<h3 className="text-xl font-semibold mb-2">Can I donate in memory or honor of someone?</h3>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">Can I donate in memory or honor of someone?</h3>
<p className="text-gray-600 dark:text-gray-300">
Absolutely. Memorial and honorary donations are a meaningful way to celebrate someone special. We can send a notification of your gift to the person or family you designate.
</p>

View file

@ -21,10 +21,10 @@ const EventCard = ({
return (
<div className="card">
<div className="p-6">
<h3 className="text-xl font-semibold mb-2">{title}</h3>
<p className="text-primary font-medium mb-2">{date}</p>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">{title}</h3>
<p className="text-blue-600 dark:text-blue-400 font-medium mb-2">{date}</p>
<p className="text-gray-600 dark:text-gray-300 mb-4">{description}</p>
<Link href={`/events/${slug}`} className="text-primary hover:underline font-medium">
<Link href={`/events/${slug}`} className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline font-medium">
Learn more
</Link>
</div>
@ -85,7 +85,7 @@ export default function EventsPage() {
<section className="py-16 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Events & Calendar</h1>
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">Events & Calendar</h1>
<p className="text-xl text-gray-700 dark:text-gray-300">
Connect with the deaf community through our regular events and activities.
</p>
@ -126,25 +126,25 @@ export default function EventsPage() {
<h2 className="text-3xl font-bold mb-8 text-center">Event Categories</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="card p-6 text-center">
<h3 className="text-xl font-semibold mb-4">Social Events</h3>
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Social Events</h3>
<p className="text-gray-600 dark:text-gray-300">
Regular gatherings and celebrations for members to connect and socialize.
</p>
</div>
<div className="card p-6 text-center">
<h3 className="text-xl font-semibold mb-4">Educational Workshops</h3>
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Educational Workshops</h3>
<p className="text-gray-600 dark:text-gray-300">
Learning opportunities and skill development sessions for all ages.
</p>
</div>
<div className="card p-6 text-center">
<h3 className="text-xl font-semibold mb-4">Board Meetings</h3>
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Board Meetings</h3>
<p className="text-gray-600 dark:text-gray-300">
Open meetings for members to participate in club governance and planning.
</p>
</div>
<div className="card p-6 text-center">
<h3 className="text-xl font-semibold mb-4">Special Events</h3>
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Special Events</h3>
<p className="text-gray-600 dark:text-gray-300">
Annual celebrations, holiday parties, and community gatherings.
</p>
@ -162,7 +162,7 @@ export default function EventsPage() {
</p>
<Link
href="/contact"
className="bg-white text-primary hover:bg-gray-100 px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
className="bg-white text-primary hover:bg-gray-100 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
>
Contact Us
</Link>

View file

@ -1,6 +1,7 @@
@import "tailwindcss";
:root {
/* Brand Colors - consistent across themes */
--color-primary: #1a56db;
--color-primary-light: #3b82f6;
--color-primary-dark: #1e40af;
@ -13,12 +14,36 @@
--color-accent-light: #ffca28;
--color-accent-dark: #ff8f00;
--color-text: #171717;
--color-text-light: #6b7280;
/* Light Theme Variables - Enhanced Modern Design */
--color-text: #1e293b;
--color-text-light: #64748b;
--color-text-muted: #94a3b8;
--color-bg: #ffffff;
--color-bg-secondary: #f8fafc;
--color-bg-tertiary: #f1f5f9;
--color-bg-soft: #fefefe;
--color-bg-warm: #fefdf9;
--color-border: #e2e8f0;
--color-border-light: #f1f5f9;
/* Light theme gradients */
--gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-secondary: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
--gradient-soft: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
--gradient-cool: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
--gradient-hero: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
/* Enhanced shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
/* Typography */
--font-sans: "Inter", system-ui, sans-serif;
--font-display: "Inter", system-ui, sans-serif;
/* Layout */
--border-radius-sm: 0.25rem;
--border-radius: 0.5rem;
--border-radius-lg: 0.75rem;
@ -27,12 +52,39 @@
--shadow-focus: 0 0 0 3px rgba(59, 130, 246, 0.5);
}
@media (prefers-color-scheme: dark) {
:root {
--color-text: #f3f4f6;
--color-text-light: #e5e7eb;
--color-primary-light: #60a5fa;
}
/* Dark Theme Variables (fully preserved) */
.dark {
/* Dark theme text colors */
--color-text: #f3f4f6;
--color-text-light: #e5e7eb;
--color-text-muted: #9ca3af;
/* Dark theme backgrounds */
--color-bg: #0f172a;
--color-bg-secondary: #1e293b;
--color-bg-tertiary: #334155;
--color-bg-soft: #1e293b;
--color-bg-warm: #1e293b;
/* Dark theme borders */
--color-border: #475569;
--color-border-light: #374151;
/* Dark theme primary colors */
--color-primary-light: #60a5fa;
/* Dark theme gradients */
--gradient-primary: linear-gradient(135deg, #1e293b 0%, #334155 100%);
--gradient-secondary: linear-gradient(135deg, #374151 0%, #475569 100%);
--gradient-soft: linear-gradient(135deg, #1e293b 0%, #334155 100%);
--gradient-cool: linear-gradient(135deg, #1e293b 0%, #374151 100%);
--gradient-hero: linear-gradient(135deg, #1e293b 0%, #334155 100%);
/* Dark theme shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.3);
}
/* Custom styles for focus and skip navigation */
@ -87,10 +139,20 @@
.btn-primary {
background-color: var(--color-primary);
color: white;
padding: 0.75rem 1.5rem;
border-radius: var(--border-radius-lg);
font-weight: 600;
box-shadow: 0 4px 14px 0 rgba(26, 86, 219, 0.25);
transition: all 0.3s ease;
border: none;
cursor: pointer;
text-decoration: none;
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
box-shadow: 0 6px 20px 0 rgba(26, 86, 219, 0.4);
transform: translateY(-2px);
}
.btn-secondary {
@ -113,30 +175,44 @@
}
.card {
background-color: white;
border-radius: var(--border-radius);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
background-color: var(--color-bg-soft);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-md);
overflow: hidden;
border: 1px solid var(--color-border-light);
transition: all 0.3s ease;
}
@media (prefers-color-scheme: dark) {
.card {
background-color: #1f2937;
}
.btn-secondary {
background-color: rgba(255, 255, 255, 0.1);
border-color: var(--color-primary-light);
color: var(--color-primary-light);
}
.btn-secondary:hover {
background-color: rgba(255, 255, 255, 0.2);
}
h2, h3 {
color: var(--color-text);
}
.card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.dark .card {
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
box-shadow: var(--shadow-md);
}
.dark .card:hover {
background-color: var(--color-bg-tertiary);
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.dark .btn-secondary {
background-color: rgba(255, 255, 255, 0.1);
border-color: var(--color-primary-light);
color: var(--color-primary-light);
}
.dark .btn-secondary:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.dark h2,
.dark h3 {
color: var(--color-text);
}
/* Add top padding to account for fixed navigation */
@ -144,6 +220,50 @@ main {
padding-top: 4rem;
}
/* Form styling */
.form-label {
display: block;
font-size: 0.875rem;
font-weight: 500;
color: #374151;
margin-bottom: 0.5rem;
}
.dark .form-label {
color: #f3f4f6;
}
.form-input {
display: block;
width: 100%;
padding: 0.5rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #111827;
background-color: #ffffff;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.form-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.dark .form-input {
color: #f9fafb;
background-color: #374151;
border-color: #6b7280;
}
.dark .form-input:focus {
border-color: var(--color-primary-light);
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2);
}
/* Custom file input styling */
.file-input {
display: block;
@ -168,8 +288,6 @@ main {
background-color: var(--color-primary-dark);
}
@media (prefers-color-scheme: dark) {
.file-input {
color: #d1d5db;
}
.dark .file-input {
color: #d1d5db;
}

View file

@ -4,6 +4,7 @@ import { Inter } from 'next/font/google';
import './globals.css';
import Navigation from '../components/organisms/Navigation';
import Footer from '../components/organisms/Footer';
import { ThemeProvider } from 'next-themes';
// Load Inter font
const inter = Inter({
@ -48,22 +49,30 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<html lang="en" className={inter.variable}>
<html lang="en" className={inter.variable} suppressHydrationWarning>
<body className={inter.className}>
{/* Skip to content link for accessibility */}
<a href="#main-content" className="skip-to-content">
Skip to content
</a>
<header>
<Navigation />
</header>
<main id="main-content">
{children}
</main>
<Footer />
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem={true}
storageKey="ocd-theme"
themes={['light', 'dark', 'system']}
>
{/* Skip to content link for accessibility */}
<a href="#main-content" className="skip-to-content">
Skip to content
</a>
<header>
<Navigation />
</header>
<main id="main-content">
{children}
</main>
<Footer />
</ThemeProvider>
</body>
</html>
);

View file

@ -14,7 +14,7 @@ export default function MembershipPage() {
<section className="py-16 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950">
<div className="container mx-auto px-4">
<div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">Become a Member</h1>
<h1 className="text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white">Become a Member</h1>
<p className="text-xl text-gray-700 dark:text-gray-300">
Join our vibrant community and connect with other deaf and hard-of-hearing individuals in Olathe.
</p>
@ -89,8 +89,8 @@ export default function MembershipPage() {
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
<div className="card p-6">
<div className="text-center mb-6">
<h3 className="text-2xl font-bold mb-2">Regular</h3>
<p className="text-3xl font-bold text-primary">$30/year</p>
<h3 className="text-2xl font-bold mb-2 text-gray-900 dark:text-white">Regular</h3>
<p className="text-3xl font-bold text-primary dark:text-blue-400">$30/year</p>
</div>
<ul className="space-y-3 text-gray-600 dark:text-gray-300 mb-8">
<li className="flex items-start">
@ -117,8 +117,8 @@ export default function MembershipPage() {
<div className="card p-6 border-primary">
<div className="text-center mb-6">
<span className="inline-block bg-primary text-white px-3 py-1 rounded-full text-sm font-medium mb-2">Most Popular</span>
<h3 className="text-2xl font-bold mb-2">Family</h3>
<p className="text-3xl font-bold text-primary">$45/year</p>
<h3 className="text-2xl font-bold mb-2 text-gray-900 dark:text-white">Family</h3>
<p className="text-3xl font-bold text-primary dark:text-blue-400">$45/year</p>
</div>
<ul className="space-y-3 text-gray-600 dark:text-gray-300 mb-8">
<li className="flex items-start">
@ -148,8 +148,8 @@ export default function MembershipPage() {
</div>
<div className="card p-6">
<div className="text-center mb-6">
<h3 className="text-2xl font-bold mb-2">Lifetime</h3>
<p className="text-3xl font-bold text-primary">$500</p>
<h3 className="text-2xl font-bold mb-2 text-gray-900 dark:text-white">Lifetime</h3>
<p className="text-3xl font-bold text-primary dark:text-blue-400">$500</p>
</div>
<ul className="space-y-3 text-gray-600 dark:text-gray-300 mb-8">
<li className="flex items-start">
@ -181,7 +181,7 @@ export default function MembershipPage() {
<div className="mt-10 text-center">
<p className="text-gray-600 dark:text-gray-300">
Note: Student and senior discounts are available. Please
<Link href="/contact" className="text-primary hover:underline"> contact us </Link>
<Link href="/contact" className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline"> contact us </Link>
for more information.
</p>
</div>
@ -261,21 +261,21 @@ export default function MembershipPage() {
<blockquote className="text-gray-600 dark:text-gray-300 mb-4">
"Joining OCD was one of the best decisions I've made. It's helped me connect with the deaf community in Olathe and make lifelong friends."
</blockquote>
<div className="font-semibold">Sarah K.</div>
<div className="font-semibold text-gray-900 dark:text-white">Sarah K.</div>
<div className="text-sm text-gray-500 dark:text-gray-400">Member since 2019</div>
</div>
<div className="card p-6">
<blockquote className="text-gray-600 dark:text-gray-300 mb-4">
"As a parent of a deaf child, OCD has been an invaluable resource for our family. The events and workshops have helped us all learn and grow together."
</blockquote>
<div className="font-semibold">David M.</div>
<div className="font-semibold text-gray-900 dark:text-white">David M.</div>
<div className="text-sm text-gray-500 dark:text-gray-400">Member since 2021</div>
</div>
<div className="card p-6">
<blockquote className="text-gray-600 dark:text-gray-300 mb-4">
"I love being part of such a vibrant and supportive community. The social events and activities have really enriched my life."
</blockquote>
<div className="font-semibold">Maria J.</div>
<div className="font-semibold text-gray-900 dark:text-white">Maria J.</div>
<div className="text-sm text-gray-500 dark:text-gray-400">Member since 2018</div>
</div>
</div>
@ -292,7 +292,7 @@ export default function MembershipPage() {
<div className="flex flex-col sm:flex-row justify-center gap-4">
<Link
href="/contact"
className="bg-white text-primary hover:bg-gray-100 px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
className="bg-white text-primary hover:bg-gray-100 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
>
Request Application
</Link>

View file

@ -23,7 +23,7 @@ const EventCard: React.FC<EventCardProps> = ({
}) => {
return (
<div className="card h-full flex flex-col">
<div className="aspect-video bg-gray-200 relative">
<div className="aspect-video bg-gray-200 dark:bg-gray-600 relative">
{imageUrl ? (
<Image
src={imageUrl}
@ -39,11 +39,11 @@ const EventCard: React.FC<EventCardProps> = ({
)}
</div>
<div className="p-6 flex-grow flex flex-col">
<h3 className="text-xl font-semibold mb-2">{title}</h3>
<p className="text-gray-600 dark:text-white mb-4 flex-grow">{description}</p>
<h3 className="text-xl font-semibold mb-2 text-gray-900 dark:text-white">{title}</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4 flex-grow">{description}</p>
<div className="flex justify-between items-center mt-auto">
<span className="text-primary dark:text-white font-medium">{date}</span>
<Link href={`/events/${slug}`} className="text-primary dark:text-white hover:underline">
<span className="text-blue-600 dark:text-blue-400 font-medium">{date}</span>
<Link href={`/events/${slug}`} className="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline">
Learn more
</Link>
</div>
@ -66,7 +66,7 @@ export default function Home() {
/>
{/* Featured events section */}
<section className="py-16 bg-white dark:bg-gray-900">
<section className="py-16 bg-gradient-to-br from-slate-50 to-blue-50 dark:from-gray-900 dark:to-gray-800">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold mb-8 text-center text-gray-900 dark:text-white">Featured Events</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
@ -101,18 +101,18 @@ export default function Home() {
</section>
{/* About section with video */}
<section className="py-16 bg-gray-50 dark:bg-gray-800">
<section className="py-16 bg-gradient-to-br from-indigo-50 to-white dark:from-gray-800 dark:to-gray-900">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold mb-8 text-center text-gray-900 dark:text-white">About OCD</h2>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
<div>
<p className="text-lg mb-6 dark:text-white">
<p className="text-lg mb-6 text-gray-700 dark:text-gray-200">
Olathe Club of the Deaf (OCD) is a non-profit organization dedicated to serving the deaf and hard-of-hearing community in Olathe and surrounding areas.
</p>
<p className="text-lg mb-6 dark:text-white">
<p className="text-lg mb-6 text-gray-700 dark:text-gray-200">
Our mission is to promote social, educational, and recreational opportunities for deaf individuals and their families while fostering a sense of community and belonging.
</p>
<p className="text-lg mb-6 dark:text-white">
<p className="text-lg mb-6 text-gray-700 dark:text-gray-200">
Founded in 1975, we have a rich history of advocacy and community service, working to bridge the gap between the deaf and hearing communities.
</p>
<Link href="/about" className="btn-primary inline-block">
@ -130,25 +130,25 @@ export default function Home() {
</section>
{/* Membership Benefits */}
<section className="py-16 bg-white dark:bg-gray-900">
<section className="py-16 bg-gradient-to-br from-purple-50 to-pink-50 dark:from-gray-900 dark:to-gray-800">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold mb-8 text-center text-gray-900 dark:text-white">Membership Benefits</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div className="card p-6">
<h3 className="text-xl font-semibold mb-4">Community Events</h3>
<p className="text-gray-600 dark:text-white">
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Community Events</h3>
<p className="text-gray-600 dark:text-gray-300">
Access to all OCD community events, socials, and gatherings throughout the year.
</p>
</div>
<div className="card p-6">
<h3 className="text-xl font-semibold mb-4">Voting Rights</h3>
<p className="text-gray-600 dark:text-white">
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Voting Rights</h3>
<p className="text-gray-600 dark:text-gray-300">
Have your say in club decisions and vote in board elections.
</p>
</div>
<div className="card p-6">
<h3 className="text-xl font-semibold mb-4">Support Network</h3>
<p className="text-gray-600 dark:text-white">
<h3 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Support Network</h3>
<p className="text-gray-600 dark:text-gray-300">
Connect with a supportive network of deaf and hard-of-hearing individuals.
</p>
</div>
@ -165,16 +165,16 @@ export default function Home() {
</section>
{/* Call to action */}
<section className="py-16 bg-primary dark:bg-gray-800">
<section className="py-16 bg-gradient-to-r from-blue-600 to-blue-700 dark:from-gray-800 dark:to-gray-900">
<div className="container mx-auto px-4 text-center">
<h2 className="text-3xl font-bold mb-4 text-white">Join Our Community</h2>
<p className="text-xl max-w-3xl mx-auto mb-8 text-white">
<p className="text-xl max-w-3xl mx-auto mb-8 text-blue-50 dark:text-gray-200">
Become a member today and connect with the deaf community in Olathe.
</p>
<div className="flex flex-col sm:flex-row justify-center gap-4">
<Link
href="/membership"
className="bg-white text-primary hover:bg-gray-100 px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
className="bg-white text-primary hover:bg-gray-100 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white px-6 py-3 rounded-lg font-medium text-lg transition-colors duration-300"
>
Become a Member
</Link>

View file

@ -109,3 +109,84 @@ export const VolumeIcon: React.FC<IconProps> = ({
</svg>
);
};
export const SunIcon: React.FC<IconProps> = ({
className = '',
size = 24,
color = 'currentColor'
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
className={`icon sun-icon ${className}`}
aria-hidden="true"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="5" />
<path d="M12 1v2" />
<path d="M12 21v2" />
<path d="M4.2 4.2l1.4 1.4" />
<path d="M18.4 18.4l1.4 1.4" />
<path d="M1 12h2" />
<path d="M21 12h2" />
<path d="M4.2 19.8l1.4-1.4" />
<path d="M18.4 5.6l1.4-1.4" />
</svg>
);
};
export const MoonIcon: React.FC<IconProps> = ({
className = '',
size = 24,
color = 'currentColor'
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
className={`icon moon-icon ${className}`}
aria-hidden="true"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
</svg>
);
};
export const ContrastIcon: React.FC<IconProps> = ({
className = '',
size = 24,
color = 'currentColor'
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
className={`icon contrast-icon ${className}`}
aria-hidden="true"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M12 2a10 10 0 0 0 0 20z" fill={color} />
</svg>
);
};

View file

@ -60,11 +60,14 @@ const Hero: React.FC<HeroProps> = ({
const heroClass = backgroundImageUrl
? 'text-white'
: 'bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-indigo-950 text-gray-900 dark:text-white';
// Background style only for custom background images
const backgroundStyle = backgroundImageUrl ? bgStyle : {};
return (
<section
className={`py-20 md:py-32 ${heroClass}`}
style={bgStyle}
style={backgroundStyle}
aria-labelledby="hero-title"
>
<div className="container mx-auto px-4 sm:px-6 lg:px-8">

View file

@ -0,0 +1,155 @@
'use client';
import React, { useState, useRef, useEffect } from 'react';
import { useTheme } from 'next-themes';
import { SunIcon, MoonIcon, ContrastIcon } from '../atoms/Icons';
type ThemeType = 'light' | 'dark' | 'high-contrast' | 'system';
const ThemeSelector: React.FC = () => {
const { theme, setTheme, resolvedTheme } = useTheme();
const [isOpen, setIsOpen] = useState(false);
const [mounted, setMounted] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
// Prevent hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return (
<div className="p-2 rounded-md text-gray-700 dark:text-white">
<SunIcon size={20} />
</div>
);
}
// Simple close handler for escape key
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Escape') {
setIsOpen(false);
}
};
const handleThemeChange = (newTheme: ThemeType) => {
setTheme(newTheme);
setIsOpen(false);
};
// Get current theme icon based on resolved theme
const ThemeIcon = () => {
switch (resolvedTheme) {
case 'dark':
return <MoonIcon size={20} />;
default:
return <SunIcon size={20} />;
}
};
// Get theme name for screen readers
const getThemeName = (themeType: string | undefined): string => {
switch (themeType) {
case 'dark':
return 'Dark Mode';
case 'system':
return 'System Theme';
default:
return 'Light Mode';
}
};
return (
<div className="relative" ref={dropdownRef}>
<button
id="theme-selector-button"
aria-haspopup="true"
aria-expanded={isOpen}
aria-label={`Theme Settings: Currently ${getThemeName(theme)}`}
onClick={() => setIsOpen(!isOpen)}
className="p-2 rounded-md text-gray-700 hover:text-gray-900 hover:bg-gray-100 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-primary"
>
<span className="sr-only">Theme Settings: Currently {getThemeName(theme)}</span>
<ThemeIcon />
</button>
{isOpen && (
<div
className="absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5 z-50"
role="menu"
aria-orientation="vertical"
aria-labelledby="theme-selector-button"
>
<div className="py-1" role="none">
<fieldset>
<legend className="sr-only">Choose Website Theme</legend>
<div className="px-4 py-2 text-sm text-gray-700 dark:text-gray-200 font-medium border-b border-gray-200 dark:border-gray-700">
Choose Website Theme
</div>
<div className="theme-options">
<button
className={`w-full text-left px-4 py-2 text-sm flex items-center gap-2 ${
theme === 'light'
? 'bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-white'
: 'text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700'
}`}
role="menuitem"
onClick={() => handleThemeChange('light')}
aria-pressed={theme === 'light'}
>
<SunIcon size={16} />
<span>Light Mode</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-auto">
(Standard brightness and colors)
</span>
</button>
<button
className={`w-full text-left px-4 py-2 text-sm flex items-center gap-2 ${
theme === 'dark'
? 'bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-white'
: 'text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700'
}`}
role="menuitem"
onClick={() => handleThemeChange('dark')}
aria-pressed={theme === 'dark'}
>
<MoonIcon size={16} />
<span>Dark Mode</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-auto">
(Reduced brightness for low light)
</span>
</button>
<button
className={`w-full text-left px-4 py-2 text-sm flex items-center gap-2 ${
theme === 'system'
? 'bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-white'
: 'text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700'
}`}
role="menuitem"
onClick={() => handleThemeChange('system')}
aria-pressed={theme === 'system'}
>
<ContrastIcon size={16} />
<span>System</span>
<span className="text-xs text-gray-500 dark:text-gray-400 ml-auto">
(Follows device preference)
</span>
</button>
</div>
</fieldset>
<div className="px-4 py-2 text-xs text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700">
Keyboard shortcut: Ctrl + T
</div>
</div>
</div>
)}
</div>
);
};
export default ThemeSelector;

View file

@ -3,6 +3,7 @@
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import ThemeSelector from '../molecules/ThemeSelector';
// Icons
const MenuIcon = ({ className = '' }: { className?: string }) => (
@ -126,6 +127,7 @@ const Navigation = () => {
<NavLink href="/membership">Membership</NavLink>
<NavLink href="/contact">Contact</NavLink>
<NavLink href="/donate">Donate</NavLink>
<ThemeSelector />
</div>
</div>
@ -157,6 +159,9 @@ const Navigation = () => {
<NavLink href="/membership" isMobile onClick={closeMenu}>Membership</NavLink>
<NavLink href="/contact" isMobile onClick={closeMenu}>Contact</NavLink>
<NavLink href="/donate" isMobile onClick={closeMenu}>Donate</NavLink>
<div className="px-3 py-2">
<ThemeSelector />
</div>
</div>
</div>
</nav>

View file

@ -16,6 +16,12 @@ export default {
'accent': 'var(--color-accent)',
'accent-light': 'var(--color-accent-light)',
'accent-dark': 'var(--color-accent-dark)',
'bg': 'var(--color-bg)',
'bg-secondary': 'var(--color-bg-secondary)',
'bg-tertiary': 'var(--color-bg-tertiary)',
'border': 'var(--color-border)',
'text': 'var(--color-text)',
'text-light': 'var(--color-text-light)',
'transparent': 'transparent',
'current': 'currentColor',
'black': '#000',
@ -76,6 +82,6 @@ export default {
'full': '9999px',
},
},
darkMode: 'media',
darkMode: 'class',
plugins: [],
};