- Standardize quote number format from Q-YYYY-MM-NNN to QYYYYMMNNN across all client, server, test and API code - Add atomic backfill logic for quote counters to avoid sequence collisions with existing records - Rearrange Delivery Notes and Repairs to the Operations sidebar section - Add supplier count badge to pricelist catalogue and improve filter tab overflow styling - Optimize font loading in root layout to skip preloading unused font weights - Improve table styling for customer and company pages with better text wrapping and empty states - Fix rep display logic in quotes page to show "Unassigned" when no rep is assigned - Add supporting documentation, PocketBase counter schemas and setup migration scripts - Remove embedded SupplierMap from suppliers page for cleaner layout - Improve invoice card layout for company and customer info spacing - Improve filter label styling and accessibility in collection map page
179 lines
4.8 KiB
TypeScript
179 lines
4.8 KiB
TypeScript
import type { Metadata, Viewport } from "next";
|
|
import {
|
|
Geist,
|
|
Geist_Mono,
|
|
Inter,
|
|
Space_Grotesk,
|
|
DM_Sans,
|
|
Playfair_Display,
|
|
Lato,
|
|
Nunito,
|
|
Outfit,
|
|
JetBrains_Mono,
|
|
} from "next/font/google";
|
|
import "leaflet/dist/leaflet.css";
|
|
import "./globals.css";
|
|
import { ThemeProvider } from "@/components/theme-provider";
|
|
import { AuthProvider } from "@/components/auth-provider";
|
|
import { Toaster } from "@/components/ui/sonner";
|
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
import { ServiceWorkerRegistration } from "@/components/service-worker-registration";
|
|
import { ThemeBootstrapScript } from "@/components/theme-bootstrap";
|
|
|
|
// Geist (default app fonts)
|
|
const geistSans = Geist({
|
|
variable: "--font-geist-sans",
|
|
subsets: ["latin"],
|
|
});
|
|
const geistMono = Geist_Mono({
|
|
variable: "--font-geist-mono",
|
|
subsets: ["latin"],
|
|
});
|
|
|
|
// Theme-bound fonts (registered as CSS vars for the theme picker to swap).
|
|
// Each font is restricted to the two weights actually used in the app
|
|
// (400 regular + 700 bold). Without these, next/font/google preloads
|
|
// every available weight and the browser logs warnings about unused
|
|
// preload tags (and the page wastes bandwidth fetching woff2 files
|
|
// that will never render).
|
|
const inter = Inter({
|
|
variable: "--font-inter",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const spaceGrotesk = Space_Grotesk({
|
|
variable: "--font-space-grotesk",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const dmSans = DM_Sans({
|
|
variable: "--font-dm-sans",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const playfair = Playfair_Display({
|
|
variable: "--font-playfair",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const lato = Lato({
|
|
variable: "--font-lato",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const nunito = Nunito({
|
|
variable: "--font-nunito",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const outfit = Outfit({
|
|
variable: "--font-outfit",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
const jetbrainsMono = JetBrains_Mono({
|
|
variable: "--font-jetbrains-mono",
|
|
subsets: ["latin"],
|
|
weight: ["400", "700"],
|
|
display: "swap",
|
|
});
|
|
|
|
export const viewport: Viewport = {
|
|
width: "device-width",
|
|
initialScale: 1,
|
|
viewportFit: "cover",
|
|
themeColor: "#4C96D7",
|
|
};
|
|
|
|
export const metadata: Metadata = {
|
|
title: "WFDASH - Business CRM",
|
|
description: "Business CRM for managing customers, companies, suppliers, quotes, and orders",
|
|
manifest: "/manifest.json",
|
|
applicationName: "WFDASH",
|
|
authors: [{ name: "WFDASH" }],
|
|
keywords: ["CRM", "Business", "Quotes", "Orders", "Customers", "Suppliers"],
|
|
appleWebApp: {
|
|
capable: true,
|
|
statusBarStyle: "default",
|
|
title: "WFDASH",
|
|
},
|
|
icons: {
|
|
icon: [
|
|
{ url: "/favicon.ico", sizes: "any" },
|
|
{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" },
|
|
{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" },
|
|
{ url: "/favicon-96x96.png", sizes: "96x96", type: "image/png" },
|
|
{ url: "/android-chrome-192x192.png", sizes: "192x192", type: "image/png" },
|
|
{ url: "/android-chrome-512x512.png", sizes: "512x512", type: "image/png" },
|
|
],
|
|
apple: "/apple-touch-icon.png",
|
|
},
|
|
openGraph: {
|
|
type: "website",
|
|
title: "WFDASH - Business CRM",
|
|
description: "Business CRM for managing customers, companies, suppliers, quotes, and orders",
|
|
siteName: "WFDASH",
|
|
images: [
|
|
{
|
|
url: "/og-image.png",
|
|
width: 1200,
|
|
height: 630,
|
|
alt: "WFDASH - Business CRM",
|
|
},
|
|
],
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: "WFDASH - Business CRM",
|
|
description: "Business CRM for managing customers, companies, suppliers, quotes, and orders",
|
|
images: ["/twitter-image.png"],
|
|
},
|
|
};
|
|
|
|
// All theme-bound CSS vars must be present on <html> so themes can swap them
|
|
const FONT_VARS = [
|
|
geistSans.variable,
|
|
geistMono.variable,
|
|
inter.variable,
|
|
spaceGrotesk.variable,
|
|
dmSans.variable,
|
|
playfair.variable,
|
|
lato.variable,
|
|
nunito.variable,
|
|
outfit.variable,
|
|
jetbrainsMono.variable,
|
|
].join(" ");
|
|
|
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html
|
|
lang="en"
|
|
className={`${FONT_VARS} h-full antialiased`}
|
|
data-theme="crisp"
|
|
suppressHydrationWarning
|
|
>
|
|
<head>
|
|
{/* Apply persisted theme before hydration to prevent flash of wrong theme */}
|
|
<ThemeBootstrapScript />
|
|
</head>
|
|
<body className="min-h-full flex flex-col">
|
|
<ServiceWorkerRegistration />
|
|
<ThemeProvider>
|
|
<TooltipProvider>
|
|
<AuthProvider>
|
|
{children}
|
|
</AuthProvider>
|
|
</TooltipProvider>
|
|
<Toaster richColors />
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|