diff --git a/bun.lock b/bun.lock index 796aa29..5d1e794 100644 --- a/bun.lock +++ b/bun.lock @@ -60,7 +60,7 @@ }, "devDependencies": { "@eslint/js": "^9.32.0", - "@lovable.dev/vite-tanstack-config": "^2.7.6", + "@lovable.dev/vite-tanstack-config": "2.7.7", "@types/node": "^22.16.5", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", @@ -232,7 +232,7 @@ "@lovable.dev/vite-plugin-hmr-gate": ["@lovable.dev/vite-plugin-hmr-gate@1.1.3", "", { "peerDependencies": { "vite": ">=5.0.0 <9.0.0" } }, "sha512-edEZzJloDj2IO7lf380So7k1SiNeYDbFLqeLzuqsP8J1qSetKWqTBTR2gAfGxBlLXHZrlayb/dU8Y9S9AlqW0Q=="], - "@lovable.dev/vite-tanstack-config": ["@lovable.dev/vite-tanstack-config@2.7.6", "", { "dependencies": { "@lovable.dev/vite-plugin-dev-server-bridge": "^1.1.1", "@lovable.dev/vite-plugin-hmr-gate": "^1.1.3", "@tanstack/devtools-vite": "^0.8.1", "lightningcss": "^1.30.0" }, "peerDependencies": { "@tailwindcss/vite": ">=4.0.0", "@tanstack/react-start": ">=1.100.0", "@vitejs/plugin-react": ">=4.0.0", "nitro": ">=3.0.260603-beta", "vite": ">=5.0.0 <9.0.0", "vite-tsconfig-paths": ">=6.0.0" }, "optionalPeers": ["nitro"] }, "sha512-OxmPom+MWV54Itezoapqa/T6zN8oSHap4kHG7mse4iiCMGGD+E4qa+q1SctacU6wEDkJiqJHhYPG+QEsSY3IUw=="], + "@lovable.dev/vite-tanstack-config": ["@lovable.dev/vite-tanstack-config@2.7.7", "https://europe-west1-npm.pkg.dev/lovable-core-prod/sandbox-npm-cache/@lovable.dev/vite-tanstack-config/-/vite-tanstack-config-2.7.7.tgz", { "dependencies": { "@lovable.dev/vite-plugin-dev-server-bridge": "^1.2.1", "@lovable.dev/vite-plugin-hmr-gate": "^1.1.3", "@tanstack/devtools-vite": "^0.8.1", "lightningcss": "^1.30.0" }, "peerDependencies": { "@tailwindcss/vite": ">=4.0.0", "@tanstack/react-start": ">=1.100.0", "@vitejs/plugin-react": ">=4.0.0", "nitro": ">=3.0.260603-beta", "vite": ">=5.0.0 <9.0.0", "vite-tsconfig-paths": ">=6.0.0" }, "optionalPeers": ["nitro"] }, "sha512-J7IXGzGaMfsFiEpNUaG3utmA1d/tXv4a7XPJb9ONlG7xyfq7LjPebJ10J087sou4lRl08ndJkJ/reE5paAJH2w=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], diff --git a/package.json b/package.json index d6fafde..84b8474 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ }, "devDependencies": { "@eslint/js": "^9.32.0", - "@lovable.dev/vite-tanstack-config": "^2.7.6", + "@lovable.dev/vite-tanstack-config": "2.7.7", "@types/node": "^22.16.5", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", diff --git a/src/components/page-shell.tsx b/src/components/page-shell.tsx new file mode 100644 index 0000000..5551a97 --- /dev/null +++ b/src/components/page-shell.tsx @@ -0,0 +1,47 @@ +import { Link } from "@tanstack/react-router"; +import { ArrowUpRight, type LucideIcon } from "lucide-react"; + +export function PageHero({ eyebrow, title, lede }: { eyebrow: string; title: string; lede?: string }) { + return ( +
+
+
{eyebrow}
+

{title}

+ {lede &&

{lede}

} +
+
+ ); +} + +export function Section({ children, className = "" }: { children: React.ReactNode; className?: string }) { + return
{children}
; +} + +export function FeatureRow({ img, title, body, reverse, Icon }: { img: string; title: string; body: string; reverse?: boolean; Icon?: LucideIcon }) { + return ( +
*:first-child]:order-2" : ""}`}> + {title} +
+ {Icon && } +

{title}

+

{body}

+
+
+ ); +} + +export function CTA() { + return ( +
+
+
+
Ready when you are
+

Let's design your misting system.

+
+ + Request a quote + +
+
+ ); +} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 20a48e5..19a0845 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -9,8 +9,56 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' +import { Route as SolutionsRouteImport } from './routes/solutions' +import { Route as RentalRouteImport } from './routes/rental' +import { Route as ProjectsRouteImport } from './routes/projects' +import { Route as ProductsRouteImport } from './routes/products' +import { Route as EnquiryRouteImport } from './routes/enquiry' +import { Route as ContactRouteImport } from './routes/contact' +import { Route as ApplicationsRouteImport } from './routes/applications' +import { Route as AboutRouteImport } from './routes/about' import { Route as IndexRouteImport } from './routes/index' +const SolutionsRoute = SolutionsRouteImport.update({ + id: '/solutions', + path: '/solutions', + getParentRoute: () => rootRouteImport, +} as any) +const RentalRoute = RentalRouteImport.update({ + id: '/rental', + path: '/rental', + getParentRoute: () => rootRouteImport, +} as any) +const ProjectsRoute = ProjectsRouteImport.update({ + id: '/projects', + path: '/projects', + getParentRoute: () => rootRouteImport, +} as any) +const ProductsRoute = ProductsRouteImport.update({ + id: '/products', + path: '/products', + getParentRoute: () => rootRouteImport, +} as any) +const EnquiryRoute = EnquiryRouteImport.update({ + id: '/enquiry', + path: '/enquiry', + getParentRoute: () => rootRouteImport, +} as any) +const ContactRoute = ContactRouteImport.update({ + id: '/contact', + path: '/contact', + getParentRoute: () => rootRouteImport, +} as any) +const ApplicationsRoute = ApplicationsRouteImport.update({ + id: '/applications', + path: '/applications', + getParentRoute: () => rootRouteImport, +} as any) +const AboutRoute = AboutRouteImport.update({ + id: '/about', + path: '/about', + getParentRoute: () => rootRouteImport, +} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', @@ -19,28 +67,144 @@ const IndexRoute = IndexRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/about': typeof AboutRoute + '/applications': typeof ApplicationsRoute + '/contact': typeof ContactRoute + '/enquiry': typeof EnquiryRoute + '/products': typeof ProductsRoute + '/projects': typeof ProjectsRoute + '/rental': typeof RentalRoute + '/solutions': typeof SolutionsRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/about': typeof AboutRoute + '/applications': typeof ApplicationsRoute + '/contact': typeof ContactRoute + '/enquiry': typeof EnquiryRoute + '/products': typeof ProductsRoute + '/projects': typeof ProjectsRoute + '/rental': typeof RentalRoute + '/solutions': typeof SolutionsRoute } export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute + '/about': typeof AboutRoute + '/applications': typeof ApplicationsRoute + '/contact': typeof ContactRoute + '/enquiry': typeof EnquiryRoute + '/products': typeof ProductsRoute + '/projects': typeof ProjectsRoute + '/rental': typeof RentalRoute + '/solutions': typeof SolutionsRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' + fullPaths: + | '/' + | '/about' + | '/applications' + | '/contact' + | '/enquiry' + | '/products' + | '/projects' + | '/rental' + | '/solutions' fileRoutesByTo: FileRoutesByTo - to: '/' - id: '__root__' | '/' + to: + | '/' + | '/about' + | '/applications' + | '/contact' + | '/enquiry' + | '/products' + | '/projects' + | '/rental' + | '/solutions' + id: + | '__root__' + | '/' + | '/about' + | '/applications' + | '/contact' + | '/enquiry' + | '/products' + | '/projects' + | '/rental' + | '/solutions' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + AboutRoute: typeof AboutRoute + ApplicationsRoute: typeof ApplicationsRoute + ContactRoute: typeof ContactRoute + EnquiryRoute: typeof EnquiryRoute + ProductsRoute: typeof ProductsRoute + ProjectsRoute: typeof ProjectsRoute + RentalRoute: typeof RentalRoute + SolutionsRoute: typeof SolutionsRoute } declare module '@tanstack/react-router' { interface FileRoutesByPath { + '/solutions': { + id: '/solutions' + path: '/solutions' + fullPath: '/solutions' + preLoaderRoute: typeof SolutionsRouteImport + parentRoute: typeof rootRouteImport + } + '/rental': { + id: '/rental' + path: '/rental' + fullPath: '/rental' + preLoaderRoute: typeof RentalRouteImport + parentRoute: typeof rootRouteImport + } + '/projects': { + id: '/projects' + path: '/projects' + fullPath: '/projects' + preLoaderRoute: typeof ProjectsRouteImport + parentRoute: typeof rootRouteImport + } + '/products': { + id: '/products' + path: '/products' + fullPath: '/products' + preLoaderRoute: typeof ProductsRouteImport + parentRoute: typeof rootRouteImport + } + '/enquiry': { + id: '/enquiry' + path: '/enquiry' + fullPath: '/enquiry' + preLoaderRoute: typeof EnquiryRouteImport + parentRoute: typeof rootRouteImport + } + '/contact': { + id: '/contact' + path: '/contact' + fullPath: '/contact' + preLoaderRoute: typeof ContactRouteImport + parentRoute: typeof rootRouteImport + } + '/applications': { + id: '/applications' + path: '/applications' + fullPath: '/applications' + preLoaderRoute: typeof ApplicationsRouteImport + parentRoute: typeof rootRouteImport + } + '/about': { + id: '/about' + path: '/about' + fullPath: '/about' + preLoaderRoute: typeof AboutRouteImport + parentRoute: typeof rootRouteImport + } '/': { id: '/' path: '/' @@ -53,17 +217,15 @@ declare module '@tanstack/react-router' { const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + AboutRoute: AboutRoute, + ApplicationsRoute: ApplicationsRoute, + ContactRoute: ContactRoute, + EnquiryRoute: EnquiryRoute, + ProductsRoute: ProductsRoute, + ProjectsRoute: ProjectsRoute, + RentalRoute: RentalRoute, + SolutionsRoute: SolutionsRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() - -import type { getRouter } from './router.tsx' -import type { startInstance } from './start.ts' -declare module '@tanstack/react-start' { - interface Register { - ssr: true - router: Awaited> - config: Awaited> - } -} diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 8d8bdc2..362845c 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -7,28 +7,158 @@ import { HeadContent, Scripts, } from "@tanstack/react-router"; -import { useEffect, type ReactNode } from "react"; +import { useEffect, useState, type ReactNode } from "react"; +import { Menu, X, Phone } from "lucide-react"; import appCss from "../styles.css?url"; import { reportLovableError } from "../lib/lovable-error-reporting"; +const NAV = [ + { to: "/", label: "Home" }, + { to: "/about", label: "About" }, + { to: "/applications", label: "Applications" }, + { to: "/products", label: "Products" }, + { to: "/solutions", label: "Solutions" }, + { to: "/projects", label: "Projects" }, + { to: "/enquiry", label: "Enquiry" }, + { to: "/contact", label: "Contact" }, + { to: "/rental", label: "Rental" }, +] as const; + +function TopBar() { + return ( +
+
+ + +971 4 251 5596 + + + +971 55 209 8628 + +
+
+ ); +} + +function Header() { + const [open, setOpen] = useState(false); + return ( +
+
+ + + Pro + mist + + + Misting Systems + + + + +
+ {open && ( +
+
+ {NAV.map((n) => ( + setOpen(false)} + className="text-foreground/80 hover:text-brand-red" + activeProps={{ className: "text-brand-red" }} + activeOptions={{ exact: n.to === "/" }} + > + {n.label} + + ))} +
+
+ )} +
+ ); +} + +function Footer() { + return ( +
+
+
+
+ Pro + mist +
+

+ High-pressure misting systems for cooling, humidification and dust suppression since 1979. +

+
+
+

Explore

+
    + {NAV.slice(1, 6).map((n) => ( +
  • + {n.label} +
  • + ))} +
+
+
+

Company

+
    +
  • Enquiry
  • +
  • Contact
  • +
  • Rental
  • +
+
+
+

Contact

+
    +
  • +971 4 251 5596
  • +
  • +971 55 209 8628
  • +
  • Dubai, United Arab Emirates
  • +
+
+
+
+
+ © {new Date().getFullYear()} Promist Misting Systems. All rights reserved. + Humidity and Control +
+
+
+ ); +} + function NotFoundComponent() { return ( -
+
-

404

-

Page not found

+

404

+

Page not found

The page you're looking for doesn't exist or has been moved.

-
- - Go home - -
+ + Go home +
); @@ -40,32 +170,17 @@ function ErrorComponent({ error, reset }: { error: Error; reset: () => void }) { useEffect(() => { reportLovableError(error, { boundary: "tanstack_root_error_component" }); }, [error]); - return ( -
+
-

- This page didn't load -

-

- Something went wrong on our end. You can try refreshing or head back home. -

-
+

This page didn't load

+

Something went wrong. Try again or head home.

+
- - Go home - + onClick={() => { router.invalidate(); reset(); }} + className="rounded-md bg-brand-red text-white px-4 py-2 text-sm font-medium" + >Try again + Go home
@@ -77,21 +192,19 @@ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()( meta: [ { charSet: "utf-8" }, { name: "viewport", content: "width=device-width, initial-scale=1" }, - { title: "Lovable App" }, - { name: "description", content: "Lovable Generated Project" }, - { name: "author", content: "Lovable" }, - { property: "og:title", content: "Lovable App" }, - { property: "og:description", content: "Lovable Generated Project" }, + { title: "Promist Misting Systems — Humidity and Control" }, + { name: "description", content: "High-pressure misting systems for outdoor cooling, humidification, dust suppression and sanitization in the UAE since 1979." }, + { property: "og:title", content: "Promist Misting Systems" }, + { property: "og:description", content: "High-pressure misting for cooling, humidification and dust suppression." }, { property: "og:type", content: "website" }, { name: "twitter:card", content: "summary_large_image" }, - { name: "twitter:site", content: "@Lovable" }, ], links: [ - { - rel: "stylesheet", - href: appCss, - }, + { rel: "stylesheet", href: appCss }, { rel: "icon", href: "/favicon.ico", type: "image/x-icon" }, + { rel: "preconnect", href: "https://fonts.googleapis.com" }, + { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }, + { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@300;400;500;600;700;800;900&display=swap" }, ], }), shellComponent: RootShell, @@ -103,24 +216,22 @@ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()( function RootShell({ children }: { children: ReactNode }) { return ( - - - - - {children} - - + + {children} ); } function RootComponent() { const { queryClient } = Route.useRouteContext(); - return ( - {/* Required: nested routes render here. Removing breaks all child routes. */} - + +
+
+ +
+