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
15 changes: 15 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// Compress responses with gzip for smaller transfer sizes
compress: true,
// Optimize images and allow external sources if needed
images: {
formats: ["image/avif", "image/webp"],
minimumCacheTTL: 60,
},
// Reduce bundle size by removing console logs in production
compiler: {
removeConsole: process.env.NODE_ENV === "production",
},
// Enable experimental optimisation for package imports
experimental: {
optimizePackageImports: ["lucide-react"],
},
};

export default nextConfig;
27 changes: 27 additions & 0 deletions src/app/dashboard/transactions/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export default function TransactionsLoading() {
return (
<div
className="min-h-screen bg-dark-900 p-6"
aria-label="Loading transactions"
aria-busy="true"
>
<div className="mx-auto max-w-2xl">
{/* Title skeleton */}
<div className="mb-8 h-8 w-40 animate-pulse rounded-lg bg-white/5" />

{/* Form card skeleton */}
<div className="rounded-2xl border border-white/5 bg-dark-800/50 p-8">
<div className="space-y-6">
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className="space-y-2">
<div className="h-3 w-24 animate-pulse rounded bg-white/5" />
<div className="h-11 animate-pulse rounded-xl bg-white/5" />
</div>
))}
<div className="h-12 animate-pulse rounded-lg bg-white/5" />
</div>
</div>
</div>
</div>
);
}
19 changes: 17 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Metadata } from "next";
import "./globals.css";
import { ClientProviders } from "@/components/ClientProviders";
import { ErrorBoundary } from "@/components/ErrorBoundary";
import { DiagnosticsPanel } from "@/components/diagnostics/DiagnosticsPanel";

export const metadata: Metadata = {
metadataBase: new URL("https://neurowealth.app"),
Expand All @@ -19,8 +21,21 @@ export default function RootLayout({
}) {
return (
<html lang="en" className="dark" suppressHydrationWarning>
<body className="antialiased">
<ClientProviders>{children}</ClientProviders>
<body className="antialiased font-sans bg-dark-900 text-slate-200">
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-[9999] focus:px-4 focus:py-2 focus:rounded-lg focus:bg-sky-500 focus:text-white focus:font-semibold focus:shadow-lg"
>
Skip to main content
</a>
{/* WalletProvider is loaded client-side only (ssr:false) to prevent
@creit.tech/stellar-wallets-kit from accessing `window` at SSR time */}
<ClientProviders>
<ErrorBoundary>
{children}
<DiagnosticsPanel />
</ErrorBoundary>
</ClientProviders>
</body>
</html>
);
Expand Down
46 changes: 25 additions & 21 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import { redirect } from "next/navigation";

// Root page — forward to dashboard (middleware handles auth gate)
export default function HomePage() {
redirect("/dashboard");
import dynamic from "next/dynamic";
import { Navbar } from "@/components/Navbar";
import { HeroSection } from "@/features/landing/HeroSection";
import { FeaturesSection } from "@/features/landing/FeaturesSection";
import { HowItWorksSection } from "@/features/landing/HowItWorksSection";
import { StrategiesSection } from "@/features/landing/StrategiesSection";
import { SecuritySection } from "@/features/landing/SecuritySection";
import { CtaSection } from "@/features/landing/CtaSection";
import { HomeFooter } from "@/features/landing/HomeFooter";

const FeaturesSection = dynamic(
() => import("@/features/landing/FeaturesSection").then((m) => m.FeaturesSection),
{ ssr: true }
);
const HowItWorksSection = dynamic(
() => import("@/features/landing/HowItWorksSection").then((m) => m.HowItWorksSection),
{ ssr: true }
);
const StrategiesSection = dynamic(
() => import("@/features/landing/StrategiesSection").then((m) => m.StrategiesSection),
{ ssr: true }
);
const SecuritySection = dynamic(
() => import("@/features/landing/SecuritySection").then((m) => m.SecuritySection),
{ ssr: true }
);
const CtaSection = dynamic(
() => import("@/features/landing/CtaSection").then((m) => m.CtaSection),
{ ssr: true }
);

export default function Home() {
return (
<>
<Navbar />

<main>
{/* Overview */}
<main id="main-content">
{/* Overview — eagerly loaded (above the fold) */}
<HeroSection />

{/* Features */}
{/* Below-fold sections — dynamically split for faster initial load */}
<FeaturesSection />

{/* How It Works */}
<HowItWorksSection />

{/* Strategies */}
<StrategiesSection />

{/* Security */}
<SecuritySection />

{/* Final CTA */}
<CtaSection />
</main>

Expand Down
9 changes: 5 additions & 4 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ export function Navbar() {
}, [isMobileSearchOpen]);

return (
<nav className="fixed top-0 left-0 right-0 z-50 border-b border-white/5 bg-dark-900/80 backdrop-blur-md">
<div className="mx-auto flex max-w-7xl items-center gap-2 px-4 py-4 sm:px-6 md:gap-4 md:px-8 md:py-5">
<Link href="/" className="flex items-center gap-2 text-lg font-bold text-white">
<span className="text-brand-400">&#x2B21;</span> NeuroWealth
<nav aria-label="Main navigation" className="fixed top-0 left-0 right-0 z-50 border-b border-white/5 bg-dark-900/80 backdrop-blur-md">
<div className="mx-auto flex max-w-7xl items-center justify-between gap-2 px-4 py-4 sm:px-6 md:gap-4 md:px-8 md:py-5">
<Link href="/" aria-label="NeuroWealth home" className="flex items-center gap-2 text-lg font-bold text-white">
<span aria-hidden="true" className="text-brand-400">&#x2B21;</span> NeuroWealth
</Link>

<div className="hidden md:flex items-center gap-6 text-sm text-slate-400">
Expand Down Expand Up @@ -100,6 +100,7 @@ export function Navbar() {
</div>
<button
onClick={signOut}
aria-label={`Sign out of ${user.name}'s account`}
className="text-[10px] text-slate-500 hover:text-red-400 transition-colors uppercase font-bold"
>
{messages.navbar.signOut}
Expand Down
Loading