Files
route-commerce/src/app/layout.tsx
T
tyler 1b12a0a95d feat(admin/stops): add tabbed dashboard with calendar and locations views
Replace the table-only stops view with a three-tab 'Harvest Dispatch'
almanac dashboard.

- Calendar tab: month grid with stops as status-colored pins, day-detail
  side panel, prev/next/today nav, weekend tint, sunrise gradient on
  the current day.
- Locations tab: cards grouped by city+state with per-location stats
  (stops/active/upcoming), date range, next-stop ribbon, and inline
  expansion to list every stop at that location. Top of the tab shows
  a six-card almanac stats strip (Locations/Cities/Stops/Active/Upcoming/
  Drafts).
- List tab: condensed read-only list of all stops in date order.

Typography: load Fraunces (display), Manrope (body), and Fragment Mono
(mono) via next/font/google, wired into the Tailwind theme as
--font-display, --font-sans, --font-mono. Add typescript to devDeps
for tsc --noEmit in this environment.

Visual signature: cream parchment cards, forest green + clay accents,
Roman-numeral stat cells, paper-grain noise, binder-tab nav, route
number watermarks on location cards, harvest-pin SVG markers.

Verified with tsc --noEmit, eslint on the new files, and a 200 from
GET /admin/stops in the dev server.
2026-06-04 18:20:11 +00:00

82 lines
2.4 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { Fraunces, Manrope, Fragment_Mono } from "next/font/google";
import "./globals.css";
import { Providers } from "@/components/Providers";
import ToastNotificationContainer from "@/components/notifications/ToastNotification";
import CookieConsentBanner from "@/components/legal/CookieConsentBanner";
const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://routecommerce.com";
const fraunces = Fraunces({
subsets: ["latin"],
display: "swap",
variable: "--font-fraunces",
axes: ["SOFT", "WONK", "opsz"],
});
const manrope = Manrope({
subsets: ["latin"],
display: "swap",
variable: "--font-manrope",
});
const fragmentMono = Fragment_Mono({
subsets: ["latin"],
display: "swap",
variable: "--font-fragment-mono",
weight: "400",
});
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
themeColor: "#0a0a0a",
};
export const metadata: Metadata = {
title: {
default: "Route Commerce | Fresh Produce Wholesale Platform",
template: "%s | Route Commerce",
},
description: "Multi-tenant B2B e-commerce platform for fresh produce wholesale distribution. Brands sell to customers who pick up at scheduled stops or receive shipments.",
keywords: ["wholesale produce", "farm fresh", "B2B e-commerce", "produce distribution", "pickup stops", "fresh produce"],
metadataBase: new URL(BASE_URL),
openGraph: {
title: "Route Commerce | Fresh Produce Wholesale Platform",
description: "Multi-tenant B2B e-commerce platform for fresh produce wholesale distribution.",
url: BASE_URL,
siteName: "Route Commerce",
locale: "en_US",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "Route Commerce | Fresh Produce Wholesale Platform",
description: "Multi-tenant B2B e-commerce platform for fresh produce wholesale distribution.",
site: "@RouteCommerce",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
},
},
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning className={`${fraunces.variable} ${manrope.variable} ${fragmentMono.variable}`}>
<body className="font-sans">
<Providers>{children}</Providers>
<ToastNotificationContainer />
<CookieConsentBanner />
</body>
</html>
);
}