/ → Loading page
/app → Main app (shows Narrative by default)
/app → Narrative page (index route)
/app/narrative → Narrative page
/app/videography → Videography page
/app/photography → Photography page
/app/contact → Contact page
// React core imports for rendering
import React from 'react'
import ReactDOM from 'react-dom/client'
// React Router imports for client-side routing
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
// Global CSS styles
import './index.css'
// Import page components
import App from './App'
import Narrative from './pages/Narrative'
import Photography from './pages/Photography'
import Contact from './pages/Contact'
import Loading from './pages/Loading'
import Videography from './pages/Videography'
/**
* Router Configuration
* Defines all routes and their corresponding components
* Uses nested routing structure with parent/child relationships
*/
const router = createBrowserRouter([
{
// Root route - shows loading page first
path: '/',
element: <Loading />,
},
{
// Main app route - parent layout with navigation
path: '/app',
element: <App />,
// Child routes that render inside App component's <Outlet />
children: [
// Index route - shows when visiting /app directly
{ index: true, element: <Narrative /> },
// Individual page routes
{ path: 'narrative', element: <Narrative /> },
{ path: 'videography', element: <Videography />},
{ path: 'photography', element: <Photography /> },
{ path: 'contact', element: <Contact /> },
]
}
])
/**
* App Entry Point
* Renders the React app to the DOM with routing enabled
*/
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
{/* RouterProvider makes routing available throughout the app */}
<RouterProvider router={router} />
</React.StrictMode>
)
App Component:
┌─────────────────────────────────────┐
│ Header (Logo + Navigation) │
├─────────────────────────────────────┤
│ <Outlet /> │ ← Child route renders here
│ (Narrative/Videography/etc.) │
├─────────────────────────────────────┤
│ Footer │
└─────────────────────────────────────┘
header
footer
// React Router imports for navigation and routing functionality
import { Outlet, NavLink, useLocation } from 'react-router-dom'
/**
* Bracket Component
* Renders the opening bracket "[" for active navigation items
* @param active - Boolean indicating if the nav item is currently active
*/
function Bracket({ active }: { active?: boolean }) {
return <span className="tabular-nums">{active ? '[' : ''}</span>
}
function NavItem({ to, children }: { to: string, children: React.ReactNode }) {
return (
<NavLink
to={to}
// Dynamic className that changes based on active state
className={({ isActive }) =>
`tracking-wider uppercase text-sm md:text-base px-2 transition no-underline hover:no-underline ${isActive ? 'text-fg' : 'text-slate-400 hover:text-slate-300'}`
}
>
{/* Render bracket + text + closing bracket for active items */}
{({ isActive }) => <span><Bracket active={isActive} />{children}{isActive ? ']' : ''}</span>}
</NavLink>
)
}
/**
* Main App Component
* Layout component that provides the overall structure for all pages
* Includes header with navigation, main content area, and footer
*/
export default function App() {
// Get current location for potential future use (currently unused)
const location = useLocation()
return (
// Main container with full viewport height, flex column layout, and dark background
<div className="min-h-dvh flex flex-col bg-slate-950">
{/** Navbar */}
<header className="py-6 px-4 md:px-8 flex items-center justify-between">
<a href="/app" className="font-semibold tracking-wider uppercase">SKANG</a>
<nav className="flex gap-3 md:gap-6 items-center">
<NavItem to="/app/narrative">Narrative</NavItem>
<NavItem to="/app/videography">Videography</NavItem>
<NavItem to="/app/photography">Photography</NavItem>
<NavItem to="/app/contact">Contact</NavItem>
</nav>
</header>
{/** Main Content Area -> Outlet renders current child route component */}
<main className="flex-1 py-8 px-4 md:px-8">
<Outlet />
</main>
{/** Footer */}
<footer className="px-4 md:px-8 py-8 text-xs text-slate-400 flex items-center justify-between border-t border-white/10">
<span>© {new Date().getFullYear()} https-sai</span>
</footer>
</div>
)
}