refactor: completely remove @nav parallel routes and simplify navigation
- Remove entire src/app/@nav directory and all parallel route files - Delete complex AppNav component that handled route-based nav detection - Update layout.tsx to remove nav slot parameter entirely - Create simple PageWithNav component that takes title/emoji as props - Update matching and memory-quiz games to use PageWithNav directly - Each page now controls its own navigation - dead simple and direct This eliminates the over-engineered parallel routes approach in favor of straightforward React prop passing. Much easier to understand and maintain. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7a3e34b4fa
commit
54ff20c755
|
|
@ -1,3 +0,0 @@
|
|||
export default function CreateNav() {
|
||||
return null
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export default function DefaultNav() {
|
||||
return null // No navigation content for routes without specific @nav slots
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
export default function MatchingNav() {
|
||||
return (
|
||||
<h1 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 'bold',
|
||||
background: 'linear-gradient(135deg, #60a5fa, #a78bfa, #f472b6)',
|
||||
backgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
margin: 0
|
||||
}}>
|
||||
🧩 Memory Pairs
|
||||
</h1>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
export default function MemoryQuizNav() {
|
||||
return (
|
||||
<h1 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 'bold',
|
||||
background: 'linear-gradient(135deg, #60a5fa, #a78bfa, #f472b6)',
|
||||
backgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
margin: 0
|
||||
}}>
|
||||
🧠 Memory Lightning
|
||||
</h1>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export default function GamesNav() {
|
||||
return null
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export default function GuideNav() {
|
||||
return null
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export default function HomeNav() {
|
||||
return null
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
import { PageWithNav } from '@/components/PageWithNav'
|
||||
import { MemoryPairsProvider } from './context/MemoryPairsContext'
|
||||
import { MemoryPairsGame } from './components/MemoryPairsGame'
|
||||
|
||||
export default function MatchingPage() {
|
||||
return (
|
||||
<MemoryPairsProvider>
|
||||
<MemoryPairsGame />
|
||||
</MemoryPairsProvider>
|
||||
<PageWithNav navTitle="Memory Pairs" navEmoji="🧩">
|
||||
<MemoryPairsProvider>
|
||||
<MemoryPairsGame />
|
||||
</MemoryPairsProvider>
|
||||
</PageWithNav>
|
||||
)
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import { css } from '../../../../styled-system/css'
|
|||
import { AbacusReact } from '@soroban/abacus-react'
|
||||
import { useAbacusConfig } from '@soroban/abacus-react'
|
||||
import { isPrefix } from '../../../lib/memory-quiz-utils'
|
||||
import { StandardGameLayout } from '../../../components/StandardGameLayout'
|
||||
import { PageWithNav } from '@/components/PageWithNav'
|
||||
|
||||
|
||||
interface QuizCard {
|
||||
|
|
@ -1733,7 +1733,7 @@ export default function MemoryQuizPage() {
|
|||
}, [state.prefixAcceptanceTimeout])
|
||||
|
||||
return (
|
||||
<StandardGameLayout>
|
||||
<PageWithNav navTitle="Memory Lightning" navEmoji="🧠">
|
||||
<style dangerouslySetInnerHTML={{ __html: globalAnimations }} />
|
||||
|
||||
<div
|
||||
|
|
@ -1741,14 +1741,16 @@ export default function MemoryQuizPage() {
|
|||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'auto'
|
||||
overflow: 'auto',
|
||||
padding: '20px 8px',
|
||||
minHeight: '100vh',
|
||||
background: 'linear-gradient(135deg, #f8fafc, #e2e8f0)'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
margin: '0 auto',
|
||||
padding: '0 8px',
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
|
|
@ -1800,6 +1802,6 @@ export default function MemoryQuizPage() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StandardGameLayout>
|
||||
</PageWithNav>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import type { Metadata, Viewport } from 'next'
|
||||
import './globals.css'
|
||||
import { ClientProviders } from '@/components/ClientProviders'
|
||||
import { AppNav } from '@/components/AppNav'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Soroban Flashcard Generator',
|
||||
|
|
@ -17,16 +16,13 @@ export const viewport: Viewport = {
|
|||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
nav,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
nav: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<ClientProviders>
|
||||
<AppNav>{nav}</AppNav>
|
||||
{children}
|
||||
</ClientProviders>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
import React from 'react'
|
||||
import { headers } from 'next/headers'
|
||||
import { AppNavBar } from './AppNavBar'
|
||||
|
||||
interface AppNavProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
function getNavContentForPath(pathname: string): React.ReactNode {
|
||||
// Route-based nav content - no lazy loading needed
|
||||
if (pathname === '/games/matching' || pathname.startsWith('/arcade') && pathname.includes('matching')) {
|
||||
return (
|
||||
<h1 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 'bold',
|
||||
background: 'linear-gradient(135deg, #60a5fa, #a78bfa, #f472b6)',
|
||||
backgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
margin: 0
|
||||
}}>
|
||||
🧩 Memory Pairs
|
||||
</h1>
|
||||
)
|
||||
}
|
||||
|
||||
if (pathname === '/games/memory-quiz' || pathname.startsWith('/arcade') && pathname.includes('memory-quiz')) {
|
||||
return (
|
||||
<h1 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 'bold',
|
||||
background: 'linear-gradient(135deg, #60a5fa, #a78bfa, #f472b6)',
|
||||
backgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
margin: 0
|
||||
}}>
|
||||
🧠 Memory Lightning
|
||||
</h1>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function AppNav({ children }: AppNavProps) {
|
||||
const headersList = headers()
|
||||
const pathname = headersList.get('x-pathname') || ''
|
||||
|
||||
// Use @nav slot content if available, otherwise fall back to route-based detection
|
||||
const navContent = children || getNavContentForPath(pathname)
|
||||
|
||||
return <AppNavBar navSlot={navContent} />
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { AppNavBar } from './AppNavBar'
|
||||
|
||||
interface PageWithNavProps {
|
||||
navTitle?: string
|
||||
navEmoji?: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export function PageWithNav({ navTitle, navEmoji, children }: PageWithNavProps) {
|
||||
// Create nav content if title is provided
|
||||
const navContent = navTitle ? (
|
||||
<h1 style={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 'bold',
|
||||
background: 'linear-gradient(135deg, #60a5fa, #a78bfa, #f472b6)',
|
||||
backgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
margin: 0
|
||||
}}>
|
||||
{navEmoji && `${navEmoji} `}{navTitle}
|
||||
</h1>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppNavBar navSlot={navContent} />
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue