Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/navbar.mouse-interactivity.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function mockMatchMedia(initialMatches = false) {
listeners.forEach((listener) =>
listener({
matches,
media: '(min-width: 1100px)',
media: '(min-width: 1250px)',
} as MediaQueryListEvent)
);
},
Expand Down
6 changes: 3 additions & 3 deletions app/components/navbar.responsive-breakpoints.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ describe('Navbar Responsive Breakpoints & Menu Toggle', () => {
expect(screen.queryByText('Switch to Dark Mode')).toBeNull();
});

it('3. Closes the mobile menu automatically when the window is resized to desktop (min-width: 1100px)', () => {
it('3. Closes the mobile menu automatically when the window is resized to desktop (min-width: 1250px)', () => {
let changeHandler: ((e: MediaQueryListEvent) => void) | null = null;

// Override the mock specifically to capture the resize event listener
Expand Down Expand Up @@ -147,13 +147,13 @@ describe('Navbar Responsive Breakpoints & Menu Toggle', () => {

const desktopNavRow =
container.querySelector('.hidden.items-center.gap-2.md\\:flex') ||
container.querySelector('.hidden.items-center.gap-2.min-\\[1100px\\]\\:flex');
container.querySelector('.hidden.items-center.gap-2.min-\\[1250px\\]\\:flex');
expect(desktopNavRow).toBeInTheDocument();

const mobileControls =
container.querySelector('.md\\:hidden.inline-flex.items-center.justify-center.gap-1') ||
container.querySelector(
'.min-\\[1100px\\]\\:hidden.inline-flex.items-center.justify-center.gap-1'
'.min-\\[1250px\\]\\:hidden.inline-flex.items-center.justify-center.gap-1'
);
expect(mobileControls).toBeInTheDocument();
});
Expand Down
2 changes: 1 addition & 1 deletion app/components/navbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function mockMatchMedia(initialMatches = false) {
listeners.forEach((listener) => {
listener({
matches,
media: '(min-width: 1100px)',
media: '(min-width: 1250px)',
} as MediaQueryListEvent);
});
},
Expand Down
2 changes: 1 addition & 1 deletion app/components/navbar.timezone-boundaries.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ describe('Navbar Timezone Normalization & Calendar Data Boundary Alignment', ()
// The desktop navigation row must also render, proving no leap-year
// exception silently unmounted a subtree.
const desktopNavRow = container.querySelector(
'.hidden.items-center.gap-2.min-\\[1100px\\]\\:flex'
'.hidden.items-center.gap-2.min-\\[1250px\\]\\:flex'
);
expect(desktopNavRow).toBeInTheDocument();
});
Expand Down
19 changes: 6 additions & 13 deletions app/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ const NAV_LINKS: NavLink[] = [
isExternal: false,
isPrimary: false,
},
{
label: 'Contact',
href: '/contact',
isExternal: false,
isPrimary: false,
},
{
label: 'Login',
href: '/login',
Expand Down Expand Up @@ -242,7 +236,7 @@ export default function Navbar() {
});

useEffect(() => {
const mediaQuery = window.matchMedia('(min-width: 1100px)');
const mediaQuery = window.matchMedia('(min-width: 1250px)');

const handleBreakpointChange = (event: MediaQueryListEvent) => {
if (event.matches) {
Expand Down Expand Up @@ -307,7 +301,6 @@ export default function Navbar() {
if (label === 'Burnout Radar') return t('navbar.burnout_radar');
if (label === 'Customization Studio') return t('navbar.customization_studio');
if (label === 'Generator') return t('navbar.generator');
if (label === 'Contact') return t('navbar.contact', { defaultValue: 'Contact' });
return label;
};

Expand All @@ -318,7 +311,7 @@ export default function Navbar() {
isHidden ? '-translate-y-full opacity-0' : 'translate-y-0 opacity-100'
}`}
>
<div className="mx-auto max-w-6xl">
<div className="mx-auto max-w-300">
<div
ref={shellRef}
className="relative overflow-visible rounded-2xl border border-gray-200/80 bg-white/80 dark:border-white/20 dark:bg-[#0a0a0a]/60 backdrop-blur-xl shadow-sm dark:shadow-[0_8px_30px_rgba(0,0,0,0.8)] transition-all duration-300"
Expand Down Expand Up @@ -368,7 +361,7 @@ export default function Navbar() {
</span>
</Link>

<div className="hidden items-center gap-2 min-[1100px]:flex">
<div className="hidden items-center gap-2 min-[1250px]:flex">
<NavbarSearch />
<LanguageSelector />
{NAV_LINKS.map((link) => {
Expand Down Expand Up @@ -443,7 +436,7 @@ export default function Navbar() {
</div>

{/* Mobile Menu Buttons */}
<div className="min-[1100px]:hidden inline-flex items-center justify-center gap-1">
<div className="min-[1250px]:hidden inline-flex items-center justify-center gap-1">
<button
type="button"
onClick={toggleTheme}
Expand All @@ -468,7 +461,7 @@ export default function Navbar() {
</button>
<button
type="button"
className="min-[1100px]:hidden inline-flex items-center justify-center rounded-xl p-2 text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-white/10 dark:hover:text-white cursor-pointer"
className="min-[1250px]:hidden inline-flex items-center justify-center rounded-xl p-2 text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-white/10 dark:hover:text-white cursor-pointer"
aria-label={open ? t('navbar.menu_close') : t('navbar.menu_open')}
aria-expanded={open}
onClick={() => {
Expand Down Expand Up @@ -509,7 +502,7 @@ export default function Navbar() {

{/* Mobile Dropdown Menu */}
{open ? (
<div className="border-t border-gray-100 dark:border-white/10 px-4 py-4 min-[1100px]:hidden">
<div className="border-t border-gray-100 dark:border-white/10 px-4 py-4 min-[1250px]:hidden">
<ul className="space-y-1">
<li className="mb-2">
<NavbarSearch variant="mobile" onNavigate={() => setOpen(false)} />
Expand Down
6 changes: 0 additions & 6 deletions app/contact/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,6 @@ describe('ContactPage', () => {
});
});

it('renders the "Back to Home" link pointing to "/"', () => {
render(<ContactPage />);
const backLink = screen.getByRole('link', { name: /back to home/i });
expect(backLink).toHaveAttribute('href', '/');
});

it('renders all four social media links', () => {
render(<ContactPage />);
// The page renders social platform links (button row + info card),
Expand Down
72 changes: 34 additions & 38 deletions app/contact/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from 'lucide-react';
import { FaGithub, FaDiscord, FaLinkedin } from 'react-icons/fa';
import { FaXTwitter } from 'react-icons/fa6';
import { Footer } from '../components/Footer';

// SEO: page-level metadata is declared in the root layout.tsx since this is
// a 'use client' component. Add a /contact entry to layout metadata if needed.
Expand Down Expand Up @@ -141,7 +142,7 @@ function Field({ id, label, error, required, children }: FieldProps) {
<label htmlFor={id} className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
{label}
{required && (
<span className="ml-1 text-teal-500" aria-hidden="true">
<span className="ml-1 text-emerald-600 dark:text-emerald-400" aria-hidden="true">
*
</span>
)}
Expand Down Expand Up @@ -252,52 +253,37 @@ export default function ContactPage() {
}, []);

return (
<div className="min-h-screen bg-gradient-to-br from-zinc-50 to-white dark:from-zinc-950 dark:to-zinc-900 py-12 overflow-hidden">
<div className="mx-auto max-w-7xl px-6">
{/* Back link */}
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
>
<Link
href="/"
className="inline-flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400 hover:text-teal-600 dark:hover:text-teal-400 transition-colors mb-10"
>
<ArrowLeft size={16} aria-hidden="true" />
Back to Home
</Link>
</motion.div>
<div className="min-h-screen bg-white dark:bg-[#0a0a0a] overflow-hidden">
<div className="mx-auto max-w-7xl pt-8 pb-20 px-6">
<div className="text-center">
<div className="inline-flex items-center text-center gap-2 px-4 py-1.5 bg-emerald-500/10 border border-emerald-500/25 font-medium rounded-full text-sm mb-6">
<MessageCircle
className="w-5 h-5 text-emerald-600 dark:text-emerald-400"
aria-hidden="true"
/>
<span className="text-emerald-600 dark:text-emerald-400 uppercase">Contact Us</span>
</div>
</div>

<div className="grid lg:grid-cols-2 gap-16 items-start">
{/* ═══ LEFT COLUMN — Hero + Info ══════════════════════════════════ */}
<motion.div
initial={{ opacity: 0, x: -40 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.7 }}
className="lg:sticky lg:top-24 lg:self-start space-y-10"
className="lg:sticky lg:self-start space-y-10 text-center lg:text-left"
>
{/* Hero text */}
<div>
<div className="inline-flex items-center gap-3 px-4 py-2 bg-teal-100 dark:bg-teal-950 rounded-full mb-6">
<MessageCircle
className="w-5 h-5 text-teal-600 dark:text-teal-400"
aria-hidden="true"
/>
<span className="text-sm font-medium text-teal-700 dark:text-teal-300">
Contact Us
</span>
</div>

<h1 className="text-5xl md:text-6xl font-bold text-black dark:text-white leading-tight">
Let&apos;s start a
<br />
<span className="bg-gradient-to-r from-teal-500 to-violet-500 bg-clip-text text-transparent">
<span className="bg-linear-to-r from-teal-500 to-violet-500 bg-clip-text text-transparent">
conversation.
</span>
</h1>

<p className="mt-6 text-xl text-zinc-600 dark:text-zinc-400 max-w-md">
<p className="mt-6 mx-auto lg:mx-0 text-xl text-zinc-600 dark:text-zinc-400 max-w-md">
Have a question, feature idea, or found a bug? Reach out — we respond to every
message.
</p>
Expand All @@ -306,8 +292,12 @@ export default function ContactPage() {
{/* Contact info card */}
<div className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-3xl p-8 space-y-6 shadow-sm">
<div className="flex items-start gap-4">
<div className="flex-shrink-0 w-10 h-10 rounded-2xl bg-teal-500/10 flex items-center justify-center">
<Mail className="text-teal-500 dark:text-teal-400" size={20} aria-hidden="true" />
<div className="shrink-0 w-10 h-10 rounded-2xl bg-emerald-500/10 flex items-center justify-center">
<Mail
className="text-emerald-600 dark:text-emerald-400"
size={20}
aria-hidden="true"
/>
</div>
<div>
<p className="text-sm font-semibold text-zinc-800 dark:text-zinc-200">Email</p>
Expand All @@ -321,7 +311,7 @@ export default function ContactPage() {
</div>

<div className="flex items-start gap-4">
<div className="flex-shrink-0 w-10 h-10 rounded-2xl bg-violet-500/10 flex items-center justify-center">
<div className="shrink-0 w-10 h-10 rounded-2xl bg-violet-500/10 flex items-center justify-center">
<FaDiscord
className="text-violet-500 dark:text-violet-400"
size={20}
Expand All @@ -344,7 +334,7 @@ export default function ContactPage() {
</div>

<div className="flex items-start gap-4">
<div className="flex-shrink-0 w-10 h-10 rounded-2xl bg-zinc-500/10 flex items-center justify-center">
<div className="shrink-0 w-10 h-10 rounded-2xl bg-zinc-500/10 flex items-center justify-center">
<FaGithub
className="text-zinc-500 dark:text-zinc-400"
size={20}
Expand All @@ -369,7 +359,7 @@ export default function ContactPage() {

{/* Social links */}
<div>
<p className="text-xs uppercase tracking-widest text-zinc-500 dark:text-zinc-500 mb-4">
<p className="text-xs uppercase tracking-widest text-zinc-500 dark:text-zinc-500 mb-4 text-left">
Find us online
</p>
<div className="flex flex-wrap gap-3">
Expand Down Expand Up @@ -408,9 +398,9 @@ export default function ContactPage() {
transition={{ duration: 0.4 }}
className="flex flex-col items-center text-center py-12 gap-6"
>
<div className="w-20 h-20 rounded-full bg-teal-500/10 flex items-center justify-center">
<div className="w-20 h-20 rounded-full bg-emerald-500/10 flex items-center justify-center">
<CheckCircle2
className="text-teal-500 dark:text-teal-400"
className="text-emerald-600 dark:text-emerald-400"
size={40}
aria-hidden="true"
/>
Expand Down Expand Up @@ -449,7 +439,9 @@ export default function ContactPage() {
Send us a message
</h2>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Fields marked with <span className="text-teal-500">*</span> are required.
Fields marked with{' '}
<span className="text-emerald-600 dark:text-emerald-400">*</span> are
required.
</p>
</div>

Expand Down Expand Up @@ -591,6 +583,10 @@ export default function ContactPage() {
</motion.div>
</div>
</div>

<div className="mx-auto max-w-7xl px-6 pb-8">
<Footer />
</div>
</div>
);
}
Loading