@zorgo/next 1.1.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.mts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +322 -1
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +322 -1
- package/dist/cli.mjs.map +1 -0
- package/dist/components.d.mts +1047 -89
- package/dist/components.d.ts +1047 -89
- package/dist/components.js +4611 -1048
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +4635 -1149
- package/dist/components.mjs.map +1 -1
- package/dist/images.d.mts +48 -0
- package/dist/images.d.ts +48 -0
- package/dist/images.js +72 -0
- package/dist/images.js.map +1 -0
- package/dist/images.mjs +39 -0
- package/dist/images.mjs.map +1 -0
- package/dist/index.d.mts +489 -14
- package/dist/index.d.ts +489 -14
- package/dist/index.js +168 -1
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +168 -1
- package/dist/index.mjs.map +1 -0
- package/dist/item-page.d.mts +157 -0
- package/dist/item-page.d.ts +157 -0
- package/dist/item-page.js +168 -0
- package/dist/item-page.js.map +1 -0
- package/dist/item-page.mjs +131 -0
- package/dist/item-page.mjs.map +1 -0
- package/dist/legal.d.mts +31 -0
- package/dist/legal.d.ts +31 -0
- package/dist/legal.js +322 -0
- package/dist/legal.js.map +1 -0
- package/dist/legal.mjs +293 -0
- package/dist/legal.mjs.map +1 -0
- package/dist/seo.d.mts +87 -2
- package/dist/seo.d.ts +87 -2
- package/dist/seo.js +111 -2
- package/dist/seo.js.map +1 -1
- package/dist/seo.mjs +106 -1
- package/dist/seo.mjs.map +1 -1
- package/dist/server.d.mts +27 -1
- package/dist/server.d.ts +27 -1
- package/dist/server.js +761 -1
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +722 -1
- package/dist/server.mjs.map +1 -0
- package/dist/slugs.d.mts +2 -1
- package/dist/slugs.d.ts +2 -1
- package/dist/slugs.js +2 -0
- package/dist/slugs.js.map +1 -1
- package/dist/slugs.mjs +1 -0
- package/dist/slugs.mjs.map +1 -1
- package/dist/tree/README.md +2 -2
- package/dist/tree/app/components/ClientItemForm.tsx +7 -0
- package/dist/tree/app/components/Header.tsx +3 -0
- package/dist/tree/app/components/ModalRegistry.tsx +3 -2
- package/dist/tree/app/components/index.ts +2 -1
- package/dist/tree/app/error.tsx +12 -3
- package/dist/tree/app/global-error.tsx +21 -4
- package/dist/tree/app/globals.css +41 -0
- package/dist/tree/app/menu/[slug]/page.tsx +16 -48
- package/dist/tree/app/not-found.tsx +17 -3
- package/dist/tree/app/privacy/page.tsx.gen.ts +28 -9
- package/dist/tree/app/terms/page.tsx.gen.ts +26 -10
- package/dist/tree/gitignore +7 -1
- package/dist/tree/image-loader.ts +4 -0
- package/dist/tree/next.config.ts +13 -0
- package/dist/tree/open-next.config.ts +7 -0
- package/dist/tree/package.json.gen.ts +8 -2
- package/package.json +17 -2
- package/dist/tree/app/globals.css.gen.ts +0 -123
- package/dist/tree/app/menu/[slug]/ItemCustomizationClient.tsx +0 -18
|
@@ -1,57 +1,35 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
ItemCustomizationView as ServerItemForm,
|
|
4
|
+
menuItemMetadata,
|
|
5
|
+
menuItemStaticParams,
|
|
6
|
+
} from "@zorgo/next/item-page";
|
|
7
|
+
import { baseItemIdFromSlug } from "@zorgo/next/slugs";
|
|
4
8
|
import { menu } from "../../../lib/generated/menu";
|
|
5
|
-
import
|
|
9
|
+
import { ClientItemForm } from "../../components/ClientItemForm";
|
|
6
10
|
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
const baseItemId = baseItemIdFromSlug(slug);
|
|
12
|
-
return menu.items.find((item) => item.base_item_id === baseItemId);
|
|
13
|
-
}
|
|
11
|
+
// The server half (hero image, JSON-LD), its metadata, and its static params all
|
|
12
|
+
// live in @zorgo/next/item-page so a package bump updates every site at once.
|
|
13
|
+
// The interactive half is this site's app/components/ClientItemForm.tsx — edit
|
|
14
|
+
// that file to customize the form, not this one.
|
|
14
15
|
|
|
15
16
|
// menu items are known at build time from the prebuilt menu — pre-render
|
|
16
17
|
// every item page instead of rendering on-demand.
|
|
17
18
|
export function generateStaticParams() {
|
|
18
|
-
return menu
|
|
19
|
-
slug: menuItemSlug(item.name, item.base_item_id),
|
|
20
|
-
}));
|
|
19
|
+
return menuItemStaticParams(menu);
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
// only slugs present in the prebuilt menu are valid routes; anything else 404s
|
|
24
23
|
// instead of falling through to an on-demand render.
|
|
25
24
|
export const dynamicParams = false;
|
|
26
25
|
|
|
27
|
-
// per-item title/description/OG so each item ranks on its own long-tail terms
|
|
28
|
-
// and shares with real context, instead of inheriting the generic root title.
|
|
29
|
-
// title is just the item name; the root layout's title template wraps it as
|
|
30
|
-
// `<name> | Brand`. metadataBase (set in the root layout) resolves OG URLs, so
|
|
31
|
-
// nothing absolute is hardcoded here.
|
|
32
26
|
export async function generateMetadata({
|
|
33
27
|
params,
|
|
34
28
|
}: {
|
|
35
29
|
params: Promise<{ slug: string }>;
|
|
36
30
|
}): Promise<Metadata> {
|
|
37
31
|
const { slug } = await params;
|
|
38
|
-
|
|
39
|
-
if (!item) return {};
|
|
40
|
-
|
|
41
|
-
const description =
|
|
42
|
-
item.description ?? `Order ${item.name} online for pickup or delivery.`;
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
title: item.name,
|
|
46
|
-
description,
|
|
47
|
-
openGraph: {
|
|
48
|
-
title: item.name,
|
|
49
|
-
description,
|
|
50
|
-
// Next's typed OpenGraph union has no "product"; "website" is the
|
|
51
|
-
// closest valid value for a standalone item page.
|
|
52
|
-
type: "website",
|
|
53
|
-
},
|
|
54
|
-
};
|
|
32
|
+
return menuItemMetadata(menu, slug);
|
|
55
33
|
}
|
|
56
34
|
|
|
57
35
|
export default async function ItemPage({
|
|
@@ -60,19 +38,9 @@ export default async function ItemPage({
|
|
|
60
38
|
params: Promise<{ slug: string }>;
|
|
61
39
|
}) {
|
|
62
40
|
const { slug } = await params;
|
|
63
|
-
const item = itemFromSlug(slug);
|
|
64
|
-
|
|
65
41
|
return (
|
|
66
|
-
<
|
|
67
|
-
{
|
|
68
|
-
|
|
69
|
-
type="application/ld+json"
|
|
70
|
-
dangerouslySetInnerHTML={{
|
|
71
|
-
__html: JSON.stringify(buildMenuItemJsonLd(item)),
|
|
72
|
-
}}
|
|
73
|
-
/>
|
|
74
|
-
)}
|
|
75
|
-
<ItemCustomizationClient baseItemId={baseItemIdFromSlug(slug)} />
|
|
76
|
-
</div>
|
|
42
|
+
<ServerItemForm menu={menu} slug={slug}>
|
|
43
|
+
<ClientItemForm baseItemId={baseItemIdFromSlug(slug)} />
|
|
44
|
+
</ServerItemForm>
|
|
77
45
|
);
|
|
78
46
|
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
// min-h-full, not a viewport height: this renders inside the layout’s
|
|
4
|
+
// <main>, between a real header and footer, so centring on the viewport would
|
|
5
|
+
// push it below the fold.
|
|
1
6
|
export default function NotFound() {
|
|
2
7
|
return (
|
|
3
|
-
<div>
|
|
4
|
-
<
|
|
5
|
-
<
|
|
8
|
+
<div className="mx-auto flex min-h-full max-w-md flex-col items-center justify-center gap-4 px-4 py-24 text-center">
|
|
9
|
+
<p className="text-6xl font-black text-primary">404</p>
|
|
10
|
+
<h1 className="text-3xl font-bold">We can't find that page</h1>
|
|
11
|
+
<p className="opacity-70">
|
|
12
|
+
It may have moved, or the link that brought you here is out of date.
|
|
13
|
+
</p>
|
|
14
|
+
<Link
|
|
15
|
+
href="/"
|
|
16
|
+
className="mt-2 inline-flex min-h-11 items-center justify-center rounded-xl bg-primary px-6 py-3 font-semibold text-primary-foreground transition-colors duration-300 hover:bg-primary/80"
|
|
17
|
+
>
|
|
18
|
+
Back to the home page
|
|
19
|
+
</Link>
|
|
6
20
|
</div>
|
|
7
21
|
);
|
|
8
22
|
}
|
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
import type { ScaffoldOptions } from "../../../../types";
|
|
2
2
|
|
|
3
|
+
// The policy text itself lives in @zorgo/next/components (src/components/client/legal.ts),
|
|
4
|
+
// so updating the package updates every scaffolded site. Only the brand name and
|
|
5
|
+
// the "last updated" date are baked in here.
|
|
3
6
|
export default function generatePrivacyPage(opts: ScaffoldOptions) {
|
|
7
|
+
if (!opts.includePrivacyPage) return;
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
</div>
|
|
11
|
-
)
|
|
12
|
-
}`;
|
|
13
|
-
}
|
|
9
|
+
const today = new Date().toLocaleDateString("en-US", {
|
|
10
|
+
year: "numeric",
|
|
11
|
+
month: "long",
|
|
12
|
+
day: "numeric",
|
|
13
|
+
});
|
|
14
14
|
|
|
15
|
+
return `import { LegalPage, privacyPolicyHtml } from "@zorgo/next/legal";
|
|
16
|
+
|
|
17
|
+
const BRAND = ${JSON.stringify(opts.franchiseName)};
|
|
18
|
+
|
|
19
|
+
export const metadata = {
|
|
20
|
+
title: "Privacy Policy",
|
|
21
|
+
description: \`How \${BRAND} handles your information.\`,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default function PrivacyPage() {
|
|
25
|
+
return (
|
|
26
|
+
<LegalPage
|
|
27
|
+
title="Privacy Policy"
|
|
28
|
+
lastUpdated="${today}"
|
|
29
|
+
html={privacyPolicyHtml({ brand: BRAND, lastUpdated: "${today}" })}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
15
34
|
}
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import type { ScaffoldOptions } from "../../../../types";
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// See privacy/page.tsx.gen.ts — the terms text is shipped by the package.
|
|
4
4
|
export default function generateTermsPage(opts: ScaffoldOptions) {
|
|
5
|
+
if (!opts.includeTermsPage) return;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</div>
|
|
12
|
-
)
|
|
13
|
-
}`;
|
|
14
|
-
}
|
|
7
|
+
const today = new Date().toLocaleDateString("en-US", {
|
|
8
|
+
year: "numeric",
|
|
9
|
+
month: "long",
|
|
10
|
+
day: "numeric",
|
|
11
|
+
});
|
|
15
12
|
|
|
13
|
+
return `import { LegalPage, termsOfUseHtml } from "@zorgo/next/legal";
|
|
14
|
+
|
|
15
|
+
const BRAND = ${JSON.stringify(opts.franchiseName)};
|
|
16
|
+
|
|
17
|
+
export const metadata = {
|
|
18
|
+
title: "Terms of Service",
|
|
19
|
+
description: \`Terms for ordering online from \${BRAND}.\`,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default function TermsPage() {
|
|
23
|
+
return (
|
|
24
|
+
<LegalPage
|
|
25
|
+
title="Online Ordering Terms of Use"
|
|
26
|
+
lastUpdated="${today}"
|
|
27
|
+
html={termsOfUseHtml({ brand: BRAND, lastUpdated: "${today}" })}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
16
32
|
}
|
package/dist/tree/gitignore
CHANGED
|
@@ -39,6 +39,12 @@ next-env.d.ts
|
|
|
39
39
|
|
|
40
40
|
/.wrangler/
|
|
41
41
|
|
|
42
|
-
# generated from .env by scripts/prebuild.ts
|
|
42
|
+
# generated from .env / franchise_branding by scripts/prebuild.ts
|
|
43
43
|
/wrangler.toml
|
|
44
44
|
/lib/generated/
|
|
45
|
+
/app/generated/
|
|
46
|
+
/public/styles/
|
|
47
|
+
/public/images/items/
|
|
48
|
+
/public/images/logo.*
|
|
49
|
+
# AVIF ladders encoded from assets/images/ — the originals are what's committed
|
|
50
|
+
/public/images/**/*.avif
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// next.config.ts points images.loaderFile here. The implementation lives in the
|
|
2
|
+
// package so a @zorgo/next bump can change the variant ladder without every site
|
|
3
|
+
// editing this file; Next only requires that it default-export a loader.
|
|
4
|
+
export { default } from "@zorgo/next/images";
|
package/dist/tree/next.config.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { NextConfig } from "next";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { IMAGE_WIDTHS } from "@zorgo/next/images";
|
|
3
4
|
|
|
4
5
|
const monorepoRoot = path.resolve(__dirname, "../../..");
|
|
5
6
|
|
|
@@ -9,6 +10,18 @@ const nextConfig: NextConfig = {
|
|
|
9
10
|
root: monorepoRoot,
|
|
10
11
|
},
|
|
11
12
|
transpilePackages: ["@zorgo", "@zorgo-website-core"],
|
|
13
|
+
// Menu item images and the site's own photos in assets/images/ are both
|
|
14
|
+
// resized to a fixed AVIF ladder at prebuild, so nothing needs a runtime
|
|
15
|
+
// optimizer (and no Supabase host in remotePatterns — a custom loader
|
|
16
|
+
// bypasses that check entirely).
|
|
17
|
+
images: {
|
|
18
|
+
loader: "custom",
|
|
19
|
+
loaderFile: "./image-loader.ts",
|
|
20
|
+
// Must mirror the rungs prebuild emits, or Next advertises srcset widths no
|
|
21
|
+
// variant has and the browser picks a candidate narrower than it asked for.
|
|
22
|
+
deviceSizes: [...IMAGE_WIDTHS],
|
|
23
|
+
imageSizes: [],
|
|
24
|
+
},
|
|
12
25
|
};
|
|
13
26
|
|
|
14
27
|
export default nextConfig;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
|
|
2
|
+
import staticAssetsIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/static-assets-incremental-cache";
|
|
2
3
|
|
|
3
4
|
export default defineCloudflareConfig({
|
|
5
|
+
// Without this the cache defaults to "dummy": every prerendered page is a
|
|
6
|
+
// miss, and `dynamicParams = false` turns that miss into a 404. The menu is
|
|
7
|
+
// rebuilt from the prebuilt data on every deploy, so a read-only cache
|
|
8
|
+
// served from Workers assets is enough — swap to r2IncrementalCache if a
|
|
9
|
+
// site ever needs ISR.
|
|
10
|
+
incrementalCache: staticAssetsIncrementalCache,
|
|
4
11
|
});
|
|
@@ -12,8 +12,14 @@ export default function generatePackageJson(opts: ScaffoldOptions): string {
|
|
|
12
12
|
"dev:no-prebuild": "next dev",
|
|
13
13
|
"prebuild": "tsx scripts/prebuild.ts",
|
|
14
14
|
"build": "tsx scripts/prebuild.ts && next build",
|
|
15
|
-
"cloudflare:deploy":
|
|
16
|
-
|
|
15
|
+
"cloudflare:deploy":
|
|
16
|
+
"tsx scripts/prebuild.ts && opennextjs-cloudflare build && wrangler deploy",
|
|
17
|
+
"cloudflare:deploy:staging":
|
|
18
|
+
"tsx scripts/prebuild.ts && opennextjs-cloudflare build && wrangler deploy --env staging",
|
|
19
|
+
"preview":
|
|
20
|
+
"tsx scripts/prebuild.ts && opennextjs-cloudflare build && wrangler dev",
|
|
21
|
+
"preview:staging":
|
|
22
|
+
"tsx scripts/prebuild.ts && opennextjs-cloudflare build && wrangler dev --env staging",
|
|
17
23
|
},
|
|
18
24
|
dependencies: PINNED_VERSIONS,
|
|
19
25
|
devDependencies: DEV_DEPENDENCIES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zorgo/next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"bin": {
|
|
@@ -54,6 +54,21 @@
|
|
|
54
54
|
"require": "./dist/slugs.js",
|
|
55
55
|
"types": "./dist/slugs.d.ts"
|
|
56
56
|
},
|
|
57
|
+
"./images": {
|
|
58
|
+
"import": "./dist/images.mjs",
|
|
59
|
+
"require": "./dist/images.js",
|
|
60
|
+
"types": "./dist/images.d.ts"
|
|
61
|
+
},
|
|
62
|
+
"./legal": {
|
|
63
|
+
"import": "./dist/legal.mjs",
|
|
64
|
+
"require": "./dist/legal.js",
|
|
65
|
+
"types": "./dist/legal.d.ts"
|
|
66
|
+
},
|
|
67
|
+
"./item-page": {
|
|
68
|
+
"import": "./dist/item-page.mjs",
|
|
69
|
+
"require": "./dist/item-page.js",
|
|
70
|
+
"types": "./dist/item-page.d.ts"
|
|
71
|
+
},
|
|
57
72
|
"./seo": {
|
|
58
73
|
"import": "./dist/seo.mjs",
|
|
59
74
|
"require": "./dist/seo.js",
|
|
@@ -77,7 +92,7 @@
|
|
|
77
92
|
"zustand": "^4.x.x"
|
|
78
93
|
},
|
|
79
94
|
"scripts": {
|
|
80
|
-
"build": "tsup && tsx scripts/obfuscate.ts",
|
|
95
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsup && tsx scripts/obfuscate.ts",
|
|
81
96
|
"release": "node scripts/publish.mjs",
|
|
82
97
|
"ship": "changeset && changeset version && node scripts/publish.mjs",
|
|
83
98
|
"dev": "echo \"No build step. Consumers transpile TS sources.\"",
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import type { ScaffoldOptions } from "../../../types";
|
|
2
|
-
|
|
3
|
-
/** Keep in sync with scripts/prebuild.ts HARDCODED_BRANDING until DB branding lands. */
|
|
4
|
-
const HARDCODED_BRANDING = {
|
|
5
|
-
backgroundBase: "#F5F5F5",
|
|
6
|
-
primary: "#3264FF",
|
|
7
|
-
accent: "#9664FF",
|
|
8
|
-
fontFamily: "Inter",
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const FONT_ON_LIGHT = "#0a0a0a";
|
|
12
|
-
const FONT_ON_DARK = "#f5f5f5";
|
|
13
|
-
/** Channel delta toward white (elevated) / black (recessed). */
|
|
14
|
-
const BACKGROUND_SURFACE_DELTA = 15;
|
|
15
|
-
|
|
16
|
-
function parseHexRgb(
|
|
17
|
-
background: string,
|
|
18
|
-
): { r: number; g: number; b: number } | null {
|
|
19
|
-
const hex = background.trim().replace(/^#/, "");
|
|
20
|
-
const full =
|
|
21
|
-
hex.length === 3
|
|
22
|
-
? hex
|
|
23
|
-
.split("")
|
|
24
|
-
.map((c) => c + c)
|
|
25
|
-
.join("")
|
|
26
|
-
: hex;
|
|
27
|
-
if (full.length !== 6 || Number.isNaN(Number.parseInt(full, 16))) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
r: Number.parseInt(full.slice(0, 2), 16),
|
|
32
|
-
g: Number.parseInt(full.slice(2, 4), 16),
|
|
33
|
-
b: Number.parseInt(full.slice(4, 6), 16),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function toHex({ r, g, b }: { r: number; g: number; b: number }): string {
|
|
38
|
-
return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function deriveFontColor(background: string): string {
|
|
42
|
-
const rgb = parseHexRgb(background);
|
|
43
|
-
if (!rgb) return FONT_ON_LIGHT;
|
|
44
|
-
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
45
|
-
return luminance > 0.5 ? FONT_ON_LIGHT : FONT_ON_DARK;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function deriveElevatedBackground(background: string): string {
|
|
49
|
-
const rgb = parseHexRgb(background);
|
|
50
|
-
if (!rgb) return background;
|
|
51
|
-
return toHex({
|
|
52
|
-
r: Math.min(255, rgb.r + BACKGROUND_SURFACE_DELTA),
|
|
53
|
-
g: Math.min(255, rgb.g + BACKGROUND_SURFACE_DELTA),
|
|
54
|
-
b: Math.min(255, rgb.b + BACKGROUND_SURFACE_DELTA),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function deriveRecessedBackground(background: string): string {
|
|
59
|
-
const rgb = parseHexRgb(background);
|
|
60
|
-
if (!rgb) return background;
|
|
61
|
-
return toHex({
|
|
62
|
-
r: Math.max(0, rgb.r - BACKGROUND_SURFACE_DELTA),
|
|
63
|
-
g: Math.max(0, rgb.g - BACKGROUND_SURFACE_DELTA),
|
|
64
|
-
b: Math.max(0, rgb.b - BACKGROUND_SURFACE_DELTA),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export default function generateGlobalsCss(_opts: ScaffoldOptions): string {
|
|
69
|
-
const branding = HARDCODED_BRANDING;
|
|
70
|
-
const fontFamilyParam = branding.fontFamily.replace(/ /g, "+");
|
|
71
|
-
const foreground = deriveFontColor(branding.backgroundBase);
|
|
72
|
-
const primaryForeground = deriveFontColor(branding.primary);
|
|
73
|
-
const accentForeground = deriveFontColor(branding.accent);
|
|
74
|
-
const backgroundElevated = deriveElevatedBackground(branding.backgroundBase);
|
|
75
|
-
const backgroundRecessed = deriveRecessedBackground(branding.backgroundBase);
|
|
76
|
-
|
|
77
|
-
return `@import url("https://fonts.googleapis.com/css2?family=${fontFamilyParam}:wght@400;700&display=swap");
|
|
78
|
-
@import "tailwindcss";
|
|
79
|
-
/* Tailwind v4 skips node_modules; @zorgo/next ships un-obfuscated components so
|
|
80
|
-
their class names are scannable here. */
|
|
81
|
-
@source "../node_modules/@zorgo/next/dist/components.mjs";
|
|
82
|
-
|
|
83
|
-
:root {
|
|
84
|
-
--background: ${branding.backgroundBase};
|
|
85
|
-
--background-elevated: ${backgroundElevated};
|
|
86
|
-
--background-recessed: ${backgroundRecessed};
|
|
87
|
-
--foreground: ${foreground};
|
|
88
|
-
--primary: ${branding.primary};
|
|
89
|
-
--primary-foreground: ${primaryForeground};
|
|
90
|
-
--accent: ${branding.accent};
|
|
91
|
-
--accent-foreground: ${accentForeground};
|
|
92
|
-
--font-sans: "${branding.fontFamily}", sans-serif;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
@theme inline {
|
|
96
|
-
--color-background: var(--background);
|
|
97
|
-
--color-background-elevated: var(--background-elevated);
|
|
98
|
-
--color-background-recessed: var(--background-recessed);
|
|
99
|
-
--color-foreground: var(--foreground);
|
|
100
|
-
--color-primary: var(--primary);
|
|
101
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
102
|
-
--color-accent: var(--accent);
|
|
103
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
104
|
-
--font-sans: var(--font-sans);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
@layer base {
|
|
108
|
-
button,
|
|
109
|
-
[type="button"],
|
|
110
|
-
[type="submit"],
|
|
111
|
-
[type="reset"] {
|
|
112
|
-
cursor: pointer;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
button:disabled,
|
|
116
|
-
[type="button"]:disabled,
|
|
117
|
-
[type="submit"]:disabled,
|
|
118
|
-
[type="reset"]:disabled {
|
|
119
|
-
cursor: not-allowed;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
`;
|
|
123
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useRouter } from "next/navigation";
|
|
3
|
-
import { ItemCustomizationForm } from "@zorgo/next/components";
|
|
4
|
-
|
|
5
|
-
export default function ItemCustomizationClient({
|
|
6
|
-
baseItemId,
|
|
7
|
-
}: {
|
|
8
|
-
baseItemId: number;
|
|
9
|
-
}) {
|
|
10
|
-
const router = useRouter();
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<ItemCustomizationForm
|
|
14
|
-
baseItemId={baseItemId}
|
|
15
|
-
onSubmitSuccess={() => router.push("/menu")}
|
|
16
|
-
/>
|
|
17
|
-
);
|
|
18
|
-
}
|