@zorgo/next 1.3.0 → 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 +9 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +44 -66
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +43 -65
- package/dist/cli.mjs.map +1 -1
- package/dist/components.d.mts +735 -5
- package/dist/components.d.ts +735 -5
- package/dist/components.js +3692 -525
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +3663 -540
- package/dist/components.mjs.map +1 -1
- package/dist/images.d.mts +25 -13
- package/dist/images.d.ts +25 -13
- package/dist/images.js +18 -8
- package/dist/images.js.map +1 -1
- package/dist/images.mjs +15 -8
- package/dist/images.mjs.map +1 -1
- package/dist/index.d.mts +315 -9
- package/dist/index.d.ts +315 -9
- package/dist/index.js +58 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58 -52
- package/dist/index.mjs.map +1 -1
- package/dist/item-page.d.mts +6 -0
- package/dist/item-page.d.ts +6 -0
- package/dist/item-page.js +4 -2
- package/dist/item-page.js.map +1 -1
- package/dist/item-page.mjs +4 -2
- package/dist/item-page.mjs.map +1 -1
- 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 +56 -1
- package/dist/seo.d.ts +56 -1
- 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 +322 -102
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +322 -104
- package/dist/server.mjs.map +1 -1
- 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/tree/README.md +2 -2
- 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/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 +6 -1
- package/dist/tree/next.config.ts +6 -5
- package/dist/tree/open-next.config.ts +7 -0
- package/dist/tree/package.json.gen.ts +8 -2
- package/package.json +7 -2
- package/dist/tree/app/globals.css.gen.ts +0 -124
package/dist/server.js
CHANGED
|
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var server_exports = {};
|
|
32
32
|
__export(server_exports, {
|
|
33
33
|
SiteTokenError: () => SiteTokenError,
|
|
34
|
+
buildBrandingCss: () => buildBrandingCss,
|
|
35
|
+
buildWranglerToml: () => buildWranglerToml,
|
|
34
36
|
fetchSiteToken: () => fetchSiteToken,
|
|
35
37
|
runPrebuild: () => runPrebuild
|
|
36
38
|
});
|
|
@@ -40,7 +42,87 @@ var import_path2 = __toESM(require("path"));
|
|
|
40
42
|
var import_env = require("@next/env");
|
|
41
43
|
var import_zod = require("zod");
|
|
42
44
|
|
|
45
|
+
// ../../node_modules/date-fns-tz/dist/esm/_lib/tzTokenizeDate/index.js
|
|
46
|
+
var testDateFormatted = new Intl.DateTimeFormat("en-US", {
|
|
47
|
+
hourCycle: "h23",
|
|
48
|
+
timeZone: "America/New_York",
|
|
49
|
+
year: "numeric",
|
|
50
|
+
month: "2-digit",
|
|
51
|
+
day: "2-digit",
|
|
52
|
+
hour: "2-digit",
|
|
53
|
+
minute: "2-digit",
|
|
54
|
+
second: "2-digit"
|
|
55
|
+
}).format(/* @__PURE__ */ new Date("2014-06-25T04:00:00.123Z"));
|
|
56
|
+
|
|
57
|
+
// ../../node_modules/date-fns-tz/dist/esm/format/formatters/index.js
|
|
58
|
+
var MILLISECONDS_IN_MINUTE = 60 * 1e3;
|
|
59
|
+
|
|
60
|
+
// ../zorgo/universal/utils/locationOrderingAvailability.ts
|
|
61
|
+
function wallTime(value) {
|
|
62
|
+
return value.replace(/[+-].*$/, "").trim().slice(0, 5);
|
|
63
|
+
}
|
|
64
|
+
|
|
43
65
|
// src/seo.ts
|
|
66
|
+
var DAYS = [
|
|
67
|
+
"Monday",
|
|
68
|
+
"Tuesday",
|
|
69
|
+
"Wednesday",
|
|
70
|
+
"Thursday",
|
|
71
|
+
"Friday",
|
|
72
|
+
"Saturday",
|
|
73
|
+
"Sunday"
|
|
74
|
+
];
|
|
75
|
+
function restaurantId(info) {
|
|
76
|
+
return `${info.url ?? ""}#restaurant`;
|
|
77
|
+
}
|
|
78
|
+
function branchId(info, location) {
|
|
79
|
+
return `${info.url ?? ""}#location-${location.location_id}`;
|
|
80
|
+
}
|
|
81
|
+
function openingHoursSpecification(location) {
|
|
82
|
+
const byWindow = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const day of DAYS) {
|
|
84
|
+
const key = day.toLowerCase();
|
|
85
|
+
const open = location[`${key}_open`];
|
|
86
|
+
const close = location[`${key}_close`];
|
|
87
|
+
if (!open || !close) continue;
|
|
88
|
+
const window = `${wallTime(open)}|${wallTime(close)}`;
|
|
89
|
+
byWindow.set(window, [...byWindow.get(window) ?? [], `https://schema.org/${day}`]);
|
|
90
|
+
}
|
|
91
|
+
return [...byWindow].map(([window, dayOfWeek]) => {
|
|
92
|
+
const [opens, closes] = window.split("|");
|
|
93
|
+
return { "@type": "OpeningHoursSpecification", dayOfWeek, opens, closes };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
var US_ADDRESS = /^(.+),\s*([^,]+),\s*([A-Z]{2})\s+(\d{5}(?:-\d{4})?)(?:,\s*USA?)?$/;
|
|
97
|
+
function postalAddress(address) {
|
|
98
|
+
const match = US_ADDRESS.exec(address.trim());
|
|
99
|
+
if (!match) return address;
|
|
100
|
+
const [, streetAddress, addressLocality, addressRegion, postalCode] = match;
|
|
101
|
+
if (!streetAddress || !addressLocality || !addressRegion || !postalCode) return address;
|
|
102
|
+
return {
|
|
103
|
+
"@type": "PostalAddress",
|
|
104
|
+
streetAddress: streetAddress.trim(),
|
|
105
|
+
addressLocality: addressLocality.trim(),
|
|
106
|
+
addressRegion,
|
|
107
|
+
postalCode,
|
|
108
|
+
addressCountry: "US"
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function locationFacts(location) {
|
|
112
|
+
const facts = {};
|
|
113
|
+
if (location.address) facts.address = postalAddress(location.address);
|
|
114
|
+
if (location.phone) facts.telephone = location.phone;
|
|
115
|
+
if (location.lat != null && location.lng != null) {
|
|
116
|
+
facts.geo = {
|
|
117
|
+
"@type": "GeoCoordinates",
|
|
118
|
+
latitude: location.lat,
|
|
119
|
+
longitude: location.lng
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const hours = openingHoursSpecification(location);
|
|
123
|
+
if (hours.length) facts.openingHoursSpecification = hours;
|
|
124
|
+
return facts;
|
|
125
|
+
}
|
|
44
126
|
function priceString(cents) {
|
|
45
127
|
return (cents / 100).toFixed(2);
|
|
46
128
|
}
|
|
@@ -81,6 +163,17 @@ function buildRestaurantJsonLd(menu2, info) {
|
|
|
81
163
|
if (info.image) restaurant.image = info.image;
|
|
82
164
|
if (info.description) restaurant.description = info.description;
|
|
83
165
|
if (info.servesCuisine?.length) restaurant.servesCuisine = info.servesCuisine;
|
|
166
|
+
const locations2 = info.locations ?? [];
|
|
167
|
+
if (locations2.length === 1) {
|
|
168
|
+
Object.assign(restaurant, locationFacts(locations2[0]));
|
|
169
|
+
} else if (locations2.length > 1) {
|
|
170
|
+
restaurant["@id"] = restaurantId(info);
|
|
171
|
+
restaurant.subOrganization = locations2.map((location) => ({
|
|
172
|
+
"@type": "Restaurant",
|
|
173
|
+
"@id": branchId(info, location),
|
|
174
|
+
name: location.name
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
84
177
|
restaurant.hasMenu = {
|
|
85
178
|
"@type": "Menu",
|
|
86
179
|
name: "Menu",
|
|
@@ -89,16 +182,19 @@ function buildRestaurantJsonLd(menu2, info) {
|
|
|
89
182
|
return restaurant;
|
|
90
183
|
}
|
|
91
184
|
|
|
92
|
-
// src/internal/
|
|
185
|
+
// src/internal/images.ts
|
|
93
186
|
var import_fs = require("fs");
|
|
187
|
+
var import_promises = require("fs/promises");
|
|
94
188
|
var import_module = require("module");
|
|
95
189
|
var import_path = __toESM(require("path"));
|
|
96
190
|
|
|
97
191
|
// ../zorgo/universal/constants.ts
|
|
98
|
-
var SUPABASE_URL = "https://dhnpoxorllfdobwftkyb.supabase.co";
|
|
99
|
-
var
|
|
192
|
+
var SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.EXPO_PUBLIC_SUPABASE_URL || "https://dhnpoxorllfdobwftkyb.supabase.co";
|
|
193
|
+
var SUPABASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRobnBveG9ybGxmZG9id2Z0a3liIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzkwNTQxMDgsImV4cCI6MjA1NDYzMDEwOH0.zI8PwbgKwijHZ1QmxJqmaPrFvg02w1vOY2Qcs7SddzI";
|
|
194
|
+
var API_BASE_URL = process.env.NODE_ENV === "production" ? "https://api.zorgotech.com" /* Production */ : "http://localhost:3000" /* Development */;
|
|
100
195
|
|
|
101
196
|
// ../zorgo/universal/utils/menuUtils.ts
|
|
197
|
+
var UNSORTED = Number.MAX_SAFE_INTEGER;
|
|
102
198
|
function menuImageUrl(image, absolute = false) {
|
|
103
199
|
if (!image) return null;
|
|
104
200
|
if (image.local_key && !absolute) return `/images/items/${image.local_key}`;
|
|
@@ -108,11 +204,13 @@ function menuImageUrl(image, absolute = false) {
|
|
|
108
204
|
}
|
|
109
205
|
|
|
110
206
|
// src/images.ts
|
|
111
|
-
var
|
|
207
|
+
var IMAGE_WIDTHS = [384, 640, 1080, 1920];
|
|
112
208
|
var ITEM_IMAGE_PREFIX = "/images/items/";
|
|
113
209
|
|
|
114
|
-
// src/internal/
|
|
210
|
+
// src/internal/images.ts
|
|
115
211
|
var AVIF_QUALITY = 60;
|
|
212
|
+
var SITE_IMAGE_SOURCE_DIR = "assets/images";
|
|
213
|
+
var SOURCE_EXTENSIONS = /\.(jpe?g|png|webp|avif|tiff?|gif)$/i;
|
|
116
214
|
function loadSharp(root) {
|
|
117
215
|
for (const from of [root, process.cwd()]) {
|
|
118
216
|
try {
|
|
@@ -125,33 +223,31 @@ function loadSharp(root) {
|
|
|
125
223
|
`sharp is not installed under ${root}. It is pinned in every scaffolded site's package.json \u2014 run an install there.`
|
|
126
224
|
);
|
|
127
225
|
}
|
|
226
|
+
function variantPath(outBase, width) {
|
|
227
|
+
return `${outBase}-${width}.avif`;
|
|
228
|
+
}
|
|
229
|
+
async function encodeLadder(source, outBase, sharp) {
|
|
230
|
+
(0, import_fs.mkdirSync)(import_path.default.dirname(outBase), { recursive: true });
|
|
231
|
+
for (const width of IMAGE_WIDTHS) {
|
|
232
|
+
await sharp(source).resize({ width, withoutEnlargement: true }).avif({ quality: AVIF_QUALITY }).toFile(variantPath(outBase, width));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
128
235
|
function itemImageLocalKey(image) {
|
|
129
236
|
const storagePath = image.processed_path ?? image.raw_path;
|
|
130
237
|
if (!storagePath) return null;
|
|
131
238
|
return storagePath.replace(/\.[^./]+$/, "").replace(/[^a-zA-Z0-9_]+/g, "-").replace(/^-|-$/g, "");
|
|
132
239
|
}
|
|
133
|
-
function itemImageVariantPath(root, key, width) {
|
|
134
|
-
return import_path.default.join(root, "public", ITEM_IMAGE_PREFIX, `${key}-${width}.avif`);
|
|
135
|
-
}
|
|
136
240
|
async function materializeItemImage(image, root) {
|
|
137
241
|
const key = itemImageLocalKey(image);
|
|
138
242
|
if (!key) return null;
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
file: itemImageVariantPath(root, key, width)
|
|
142
|
-
}));
|
|
143
|
-
if (targets.every(({ file }) => (0, import_fs.existsSync)(file))) return key;
|
|
243
|
+
const outBase = import_path.default.join(root, "public", ITEM_IMAGE_PREFIX, key);
|
|
244
|
+
if (IMAGE_WIDTHS.every((width) => (0, import_fs.existsSync)(variantPath(outBase, width)))) return key;
|
|
144
245
|
const url = menuImageUrl(image, true);
|
|
145
246
|
if (!url) return null;
|
|
146
247
|
try {
|
|
147
248
|
const res = await fetch(url);
|
|
148
249
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
149
|
-
|
|
150
|
-
const sharp = loadSharp(root);
|
|
151
|
-
(0, import_fs.mkdirSync)(import_path.default.dirname(targets[0].file), { recursive: true });
|
|
152
|
-
for (const { width, file } of targets) {
|
|
153
|
-
await sharp(source).resize({ width, withoutEnlargement: true }).avif({ quality: AVIF_QUALITY }).toFile(file);
|
|
154
|
-
}
|
|
250
|
+
await encodeLadder(Buffer.from(await res.arrayBuffer()), outBase, loadSharp(root));
|
|
155
251
|
return key;
|
|
156
252
|
} catch (err) {
|
|
157
253
|
console.error(`prebuild: image ${image.image_id} (${url}) failed:`, err);
|
|
@@ -168,6 +264,57 @@ async function stampItemImages(menu2, root) {
|
|
|
168
264
|
console.log(`prebuild: ${stamped}/${images.length} item images localized`);
|
|
169
265
|
}
|
|
170
266
|
}
|
|
267
|
+
function collectSources(dir, prefix = "") {
|
|
268
|
+
return (0, import_fs.readdirSync)(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
269
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
270
|
+
if (entry.isDirectory()) return collectSources(import_path.default.join(dir, entry.name), rel);
|
|
271
|
+
return SOURCE_EXTENSIONS.test(entry.name) ? [rel] : [];
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function siteImageKey(relativePath) {
|
|
275
|
+
return relativePath.replace(/\.[^./]+$/, "").split("/").map((segment) => segment.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-|-$/g, "")).join("/");
|
|
276
|
+
}
|
|
277
|
+
function laddersAreFresh(sourcePath, outBase) {
|
|
278
|
+
const sourceMtime = (0, import_fs.statSync)(sourcePath).mtimeMs;
|
|
279
|
+
return IMAGE_WIDTHS.every((width) => {
|
|
280
|
+
const file = variantPath(outBase, width);
|
|
281
|
+
return (0, import_fs.existsSync)(file) && (0, import_fs.statSync)(file).mtimeMs >= sourceMtime;
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
async function optimizeSiteImages(root) {
|
|
285
|
+
const sourceDir = import_path.default.join(root, SITE_IMAGE_SOURCE_DIR);
|
|
286
|
+
if (!(0, import_fs.existsSync)(sourceDir)) return;
|
|
287
|
+
const sources = collectSources(sourceDir);
|
|
288
|
+
if (sources.length === 0) return;
|
|
289
|
+
const sharp = loadSharp(root);
|
|
290
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
291
|
+
let encoded = 0;
|
|
292
|
+
let failed = 0;
|
|
293
|
+
for (const relativePath of sources) {
|
|
294
|
+
const key = siteImageKey(relativePath);
|
|
295
|
+
const clash = claimed.get(key);
|
|
296
|
+
if (clash) {
|
|
297
|
+
console.warn(
|
|
298
|
+
`prebuild: ${relativePath} and ${clash} both map to /images/${key} \u2014 skipping ${relativePath}`
|
|
299
|
+
);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
claimed.set(key, relativePath);
|
|
303
|
+
const sourcePath = import_path.default.join(sourceDir, relativePath);
|
|
304
|
+
const outBase = import_path.default.join(root, "public", "images", key);
|
|
305
|
+
if (laddersAreFresh(sourcePath, outBase)) continue;
|
|
306
|
+
try {
|
|
307
|
+
await encodeLadder(await (0, import_promises.readFile)(sourcePath), outBase, sharp);
|
|
308
|
+
encoded++;
|
|
309
|
+
} catch (err) {
|
|
310
|
+
failed++;
|
|
311
|
+
console.error(`prebuild: site image ${relativePath} failed:`, err);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
console.log(
|
|
315
|
+
`prebuild: ${sources.length} site images (${encoded} encoded, ${sources.length - encoded - failed} cached, ${failed} failed)`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
171
318
|
|
|
172
319
|
// src/server.ts
|
|
173
320
|
function apiBaseUrl() {
|
|
@@ -230,7 +377,25 @@ var FranchiseSchema = import_zod.z.object({
|
|
|
230
377
|
name: import_zod.z.string().nullish().transform((v) => v ?? process.env.ZORGO_PROJECT_NAME ?? "Restaurant"),
|
|
231
378
|
site_url: import_zod.z.string().nullish().transform((v) => v ?? void 0)
|
|
232
379
|
}).prefault({});
|
|
233
|
-
var
|
|
380
|
+
var LocationsSchema = import_zod.z.array(import_zod.z.unknown()).prefault([]);
|
|
381
|
+
var FeatureConfigSchema = import_zod.z.object({
|
|
382
|
+
catering: import_zod.z.object({
|
|
383
|
+
does_cater: import_zod.z.boolean().nullish(),
|
|
384
|
+
minimum_notice_hours: import_zod.z.number().nullish(),
|
|
385
|
+
minimum_people_required: import_zod.z.number().nullish(),
|
|
386
|
+
minimum_price: import_zod.z.number().nullish(),
|
|
387
|
+
preferred_time: import_zod.z.string().nullish()
|
|
388
|
+
}).nullish().transform((v) => v ?? null),
|
|
389
|
+
catering_bulk_discount: import_zod.z.object({
|
|
390
|
+
is_active: import_zod.z.boolean().nullish(),
|
|
391
|
+
full_discount_at: import_zod.z.number().nullish(),
|
|
392
|
+
maximum_percent_off: import_zod.z.number().nullish()
|
|
393
|
+
}).nullish().transform((v) => v ?? null),
|
|
394
|
+
// Passed through unvalidated: the server already parsed it against
|
|
395
|
+
// FoodTruckConfig, and re-declaring eight money fields here just creates a
|
|
396
|
+
// second place to forget one. The site imports it as FoodTruckConfigValue.
|
|
397
|
+
food_truck: import_zod.z.unknown().transform((v) => v ?? null)
|
|
398
|
+
}).prefault({ food_truck: null });
|
|
234
399
|
var MenuSchema = import_zod.z.object({
|
|
235
400
|
items: import_zod.z.array(import_zod.z.unknown()).default([]),
|
|
236
401
|
categories: import_zod.z.array(import_zod.z.unknown()).default([]),
|
|
@@ -252,8 +417,9 @@ async function fetchData(endpoint, token, schema) {
|
|
|
252
417
|
}
|
|
253
418
|
var FONT_ON_LIGHT = "#0a0a0a";
|
|
254
419
|
var FONT_ON_DARK = "#f5f5f5";
|
|
255
|
-
var
|
|
256
|
-
var
|
|
420
|
+
var NEUTRAL_GRAY = { r: 128, g: 128, b: 128 };
|
|
421
|
+
var SURFACE_SHIFT_SUBTLE = 0.1;
|
|
422
|
+
var SURFACE_SHIFT_STRONG = 0.18;
|
|
257
423
|
function parseHexRgb(background) {
|
|
258
424
|
const hex = background.trim().replace(/^#/, "");
|
|
259
425
|
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
@@ -272,42 +438,39 @@ function toHex({ r, g, b }) {
|
|
|
272
438
|
function relativeLuminance({ r, g, b }) {
|
|
273
439
|
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
274
440
|
}
|
|
275
|
-
function temperatureBiasFor({ r, g, b }) {
|
|
276
|
-
return Math.round(BACKGROUND_TEMPERATURE_BIAS * relativeLuminance({ r, g, b }));
|
|
277
|
-
}
|
|
278
441
|
function deriveFontColor(background) {
|
|
279
442
|
const rgb = parseHexRgb(background);
|
|
280
443
|
if (!rgb) return FONT_ON_LIGHT;
|
|
281
444
|
return relativeLuminance(rgb) > 0.5 ? FONT_ON_LIGHT : FONT_ON_DARK;
|
|
282
445
|
}
|
|
446
|
+
function lerpToward(rgb, target, t) {
|
|
447
|
+
return toHex({
|
|
448
|
+
r: Math.round(rgb.r + (target.r - rgb.r) * t),
|
|
449
|
+
g: Math.round(rgb.g + (target.g - rgb.g) * t),
|
|
450
|
+
b: Math.round(rgb.b + (target.b - rgb.b) * t)
|
|
451
|
+
});
|
|
452
|
+
}
|
|
283
453
|
function deriveElevatedBackground(background) {
|
|
284
454
|
const rgb = parseHexRgb(background);
|
|
285
455
|
if (!rgb) return background;
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
return toHex({
|
|
289
|
-
r: Math.min(255, rgb.r + BACKGROUND_SURFACE_DELTA + warm),
|
|
290
|
-
g: Math.min(255, rgb.g + BACKGROUND_SURFACE_DELTA),
|
|
291
|
-
b: Math.min(255, rgb.b + BACKGROUND_SURFACE_DELTA - bias)
|
|
292
|
-
});
|
|
456
|
+
const t = relativeLuminance(rgb) > 0.5 ? SURFACE_SHIFT_SUBTLE : SURFACE_SHIFT_STRONG;
|
|
457
|
+
return lerpToward(rgb, NEUTRAL_GRAY, t);
|
|
293
458
|
}
|
|
294
459
|
function deriveRecessedBackground(background) {
|
|
295
460
|
const rgb = parseHexRgb(background);
|
|
296
461
|
if (!rgb) return background;
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? siteUrl;
|
|
310
|
-
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
|
|
462
|
+
const t = relativeLuminance(rgb) > 0.5 ? SURFACE_SHIFT_STRONG : SURFACE_SHIFT_SUBTLE;
|
|
463
|
+
return lerpToward(rgb, NEUTRAL_GRAY, t);
|
|
464
|
+
}
|
|
465
|
+
function varsBlock(vars) {
|
|
466
|
+
return Object.entries(vars).filter(([, value]) => value !== "").map(([key, value]) => `${key} = "${value}"`).join("\n");
|
|
467
|
+
}
|
|
468
|
+
function buildWranglerToml(env) {
|
|
469
|
+
const name = env.ZORGO_PROJECT_NAME ?? "zorgo-site";
|
|
470
|
+
const siteUrl = env.NEXT_PUBLIC_SITE_URL ?? "";
|
|
471
|
+
const apiUrl = env.NEXT_PUBLIC_API_BASE_URL ?? "";
|
|
472
|
+
const baseUrl = env.NEXT_PUBLIC_BASE_URL ?? siteUrl;
|
|
473
|
+
const supabaseUrl = env.NEXT_PUBLIC_SUPABASE_URL ?? "";
|
|
311
474
|
let host;
|
|
312
475
|
try {
|
|
313
476
|
host = new URL(siteUrl).hostname;
|
|
@@ -323,32 +486,23 @@ custom_domain = true
|
|
|
323
486
|
pattern = "www.${host}"
|
|
324
487
|
custom_domain = true
|
|
325
488
|
` : "";
|
|
326
|
-
const vars = {
|
|
327
|
-
NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
|
|
328
|
-
NEXT_PUBLIC_API_BASE_URL: apiUrl,
|
|
329
|
-
NEXT_PUBLIC_SITE_URL: siteUrl,
|
|
330
|
-
NEXT_PUBLIC_BASE_URL: baseUrl
|
|
331
|
-
};
|
|
332
|
-
const varsBlock = Object.entries(vars).filter(([, value]) => value !== "").map(([key, value]) => `${key} = "${value}"`).join("\n");
|
|
333
489
|
const toml = `# AUTO-GENERATED by scripts/prebuild.ts from .env \u2014 do not edit.
|
|
334
490
|
name = "${name}"
|
|
335
491
|
main = ".open-next/worker.js"
|
|
336
492
|
compatibility_date = "2024-09-23"
|
|
337
|
-
compatibility_flags = ["
|
|
338
|
-
|
|
339
|
-
# Bundles the Cloudflare worker as part of \`wrangler deploy\` (and \`wrangler dev\`),
|
|
340
|
-
# so the deploy command stays a plain \`wrangler deploy\`. prebuild (which writes
|
|
341
|
-
# this file + lib/generated) must still run first \u2014 on Cloudflare Workers Builds
|
|
342
|
-
# that is the project's Build command; locally it is the npm scripts below.
|
|
343
|
-
[build]
|
|
344
|
-
command = "npx opennextjs-cloudflare build"
|
|
493
|
+
compatibility_flags = ["nodejs_compat_v2"]
|
|
345
494
|
|
|
346
495
|
[assets]
|
|
347
496
|
directory = ".open-next/assets"
|
|
348
497
|
binding = "ASSETS"
|
|
349
498
|
|
|
350
499
|
[vars]
|
|
351
|
-
${varsBlock
|
|
500
|
+
${varsBlock({
|
|
501
|
+
NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
|
|
502
|
+
NEXT_PUBLIC_API_BASE_URL: apiUrl,
|
|
503
|
+
NEXT_PUBLIC_SITE_URL: siteUrl,
|
|
504
|
+
NEXT_PUBLIC_BASE_URL: baseUrl
|
|
505
|
+
})}
|
|
352
506
|
|
|
353
507
|
[observability]
|
|
354
508
|
enabled = true
|
|
@@ -356,8 +510,27 @@ enabled = true
|
|
|
356
510
|
[observability.logs]
|
|
357
511
|
enabled = true
|
|
358
512
|
invocation_logs = true
|
|
359
|
-
${routes}`;
|
|
360
|
-
|
|
513
|
+
${routes}${buildStagingBlock(env, name, supabaseUrl, apiUrl)}`;
|
|
514
|
+
return toml;
|
|
515
|
+
}
|
|
516
|
+
function buildStagingBlock(env, name, supabaseUrl, apiUrl) {
|
|
517
|
+
const stagingUrl = env.NEXT_PUBLIC_STAGING_BASE_URL ?? "";
|
|
518
|
+
return `
|
|
519
|
+
[env.staging]
|
|
520
|
+
name = "${name}-staging"
|
|
521
|
+
routes = []
|
|
522
|
+
|
|
523
|
+
[env.staging.vars]
|
|
524
|
+
${varsBlock({
|
|
525
|
+
NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
|
|
526
|
+
NEXT_PUBLIC_API_BASE_URL: apiUrl,
|
|
527
|
+
NEXT_PUBLIC_SITE_URL: stagingUrl,
|
|
528
|
+
NEXT_PUBLIC_BASE_URL: stagingUrl
|
|
529
|
+
})}
|
|
530
|
+
`;
|
|
531
|
+
}
|
|
532
|
+
function writeWranglerToml() {
|
|
533
|
+
(0, import_fs2.writeFileSync)(import_path2.default.join(process.cwd(), "wrangler.toml"), buildWranglerToml(process.env));
|
|
361
534
|
}
|
|
362
535
|
async function logo({ franchiseId, token }) {
|
|
363
536
|
const logoResponse = await fetch(
|
|
@@ -370,7 +543,6 @@ async function logo({ franchiseId, token }) {
|
|
|
370
543
|
const outDir = import_path2.default.join(process.cwd(), `public/images/`);
|
|
371
544
|
(0, import_fs2.mkdirSync)(outDir, { recursive: true });
|
|
372
545
|
(0, import_fs2.writeFileSync)(import_path2.default.join(outDir, "logo.png"), buffer);
|
|
373
|
-
(0, import_fs2.writeFileSync)(import_path2.default.join(outDir, "logo.jpg"), buffer);
|
|
374
546
|
}
|
|
375
547
|
var dropHeavyColumns = (key, value) => key.endsWith("_vector") || key.endsWith("_embedding") ? void 0 : value;
|
|
376
548
|
function writeMenuModule(menu2) {
|
|
@@ -406,7 +578,7 @@ async function menu({ franchiseId, token }) {
|
|
|
406
578
|
writeMenuModule(parsed);
|
|
407
579
|
return parsed;
|
|
408
580
|
}
|
|
409
|
-
async function jsonLd({ franchiseId, token }, menuData) {
|
|
581
|
+
async function jsonLd({ franchiseId, token }, menuData, locationRows) {
|
|
410
582
|
const franchise = await fetchData(
|
|
411
583
|
`/franchise-info/franchise/${franchiseId}`,
|
|
412
584
|
token,
|
|
@@ -416,7 +588,8 @@ async function jsonLd({ franchiseId, token }, menuData) {
|
|
|
416
588
|
const data = buildRestaurantJsonLd(menuData, {
|
|
417
589
|
name: franchise.name,
|
|
418
590
|
url,
|
|
419
|
-
image: url ? `${url}/images/logo.png` : void 0
|
|
591
|
+
image: url ? `${url}/images/logo.png` : void 0,
|
|
592
|
+
locations: locationRows
|
|
420
593
|
});
|
|
421
594
|
const outDir = import_path2.default.join(process.cwd(), `lib/generated/`);
|
|
422
595
|
(0, import_fs2.mkdirSync)(outDir, { recursive: true });
|
|
@@ -427,8 +600,61 @@ export const restaurantJsonLd = ${JSON.stringify(data, null, 2)};
|
|
|
427
600
|
`
|
|
428
601
|
);
|
|
429
602
|
}
|
|
430
|
-
async function
|
|
431
|
-
await fetchData(
|
|
603
|
+
async function locations({ franchiseId, token }) {
|
|
604
|
+
const rows = await fetchData(
|
|
605
|
+
`/franchise-info/locations/${franchiseId}`,
|
|
606
|
+
token,
|
|
607
|
+
LocationsSchema
|
|
608
|
+
);
|
|
609
|
+
const outDir = import_path2.default.join(process.cwd(), `lib/generated/`);
|
|
610
|
+
(0, import_fs2.mkdirSync)(outDir, { recursive: true });
|
|
611
|
+
(0, import_fs2.writeFileSync)(
|
|
612
|
+
import_path2.default.join(outDir, "locations.ts"),
|
|
613
|
+
`// AUTO-GENERATED by scripts/prebuild.ts \u2014 do not edit.
|
|
614
|
+
import type { Location } from "@zorgo/next";
|
|
615
|
+
|
|
616
|
+
export const locations = ${JSON.stringify(rows, null, 2)} as unknown as Location[];
|
|
617
|
+
`
|
|
618
|
+
);
|
|
619
|
+
return rows;
|
|
620
|
+
}
|
|
621
|
+
async function featureConfig({ franchiseId, token }) {
|
|
622
|
+
const config = await fetchData(
|
|
623
|
+
`/franchise-info/feature-config/${franchiseId}`,
|
|
624
|
+
token,
|
|
625
|
+
FeatureConfigSchema
|
|
626
|
+
);
|
|
627
|
+
const outDir = import_path2.default.join(process.cwd(), `lib/generated/`);
|
|
628
|
+
const outFile = import_path2.default.join(outDir, "featureConfig.ts");
|
|
629
|
+
const empty = !config.catering && !config.catering_bulk_discount && !config.food_truck;
|
|
630
|
+
if (empty && (0, import_fs2.existsSync)(outFile)) {
|
|
631
|
+
console.warn(
|
|
632
|
+
"prebuild: feature-config came back empty \u2014 keeping the existing lib/generated/featureConfig.ts."
|
|
633
|
+
);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
(0, import_fs2.mkdirSync)(outDir, { recursive: true });
|
|
637
|
+
(0, import_fs2.writeFileSync)(
|
|
638
|
+
outFile,
|
|
639
|
+
`// AUTO-GENERATED by scripts/prebuild.ts \u2014 do not edit.
|
|
640
|
+
import type {
|
|
641
|
+
CateringSiteConfig,
|
|
642
|
+
CateringBulkDiscount,
|
|
643
|
+
FoodTruckConfigValue,
|
|
644
|
+
} from "@zorgo/next";
|
|
645
|
+
|
|
646
|
+
export const cateringConfig: CateringSiteConfig | null = ${JSON.stringify(config.catering, null, 2)};
|
|
647
|
+
|
|
648
|
+
export const cateringBulkDiscount: CateringBulkDiscount | null = ${JSON.stringify(config.catering_bulk_discount, null, 2)};
|
|
649
|
+
|
|
650
|
+
export const foodTruck = ${JSON.stringify(config.food_truck ?? null, null, 2)} as FoodTruckConfigValue | null;
|
|
651
|
+
`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
var FONT_FILE_RE = /\.(woff2?|ttf|otf)$/i;
|
|
655
|
+
function hasSelfHostedFonts(cwd) {
|
|
656
|
+
const fontsDir = import_path2.default.join(cwd, "public/fonts");
|
|
657
|
+
return (0, import_fs2.existsSync)(fontsDir) && (0, import_fs2.readdirSync)(fontsDir).some((f) => FONT_FILE_RE.test(f));
|
|
432
658
|
}
|
|
433
659
|
async function styles({ franchiseId, token }) {
|
|
434
660
|
const brand = await fetchData(
|
|
@@ -450,26 +676,23 @@ async function styles({ franchiseId, token }) {
|
|
|
450
676
|
import_path2.default.join(stylesDir, "styles.json"),
|
|
451
677
|
JSON.stringify(branding, null, 2)
|
|
452
678
|
);
|
|
679
|
+
const generatedDir = import_path2.default.join(process.cwd(), "app", "generated");
|
|
680
|
+
(0, import_fs2.mkdirSync)(generatedDir, { recursive: true });
|
|
453
681
|
(0, import_fs2.writeFileSync)(
|
|
454
|
-
import_path2.default.join(
|
|
455
|
-
|
|
682
|
+
import_path2.default.join(generatedDir, "branding.css"),
|
|
683
|
+
buildBrandingCss(brand, { selfHostedFont: hasSelfHostedFonts(process.cwd()) })
|
|
456
684
|
);
|
|
457
685
|
}
|
|
458
|
-
function
|
|
459
|
-
const fontFamilyParam = branding.fontFamily.replace(/ /g, "+");
|
|
686
|
+
function buildBrandingCss(branding, opts) {
|
|
460
687
|
const foreground = deriveFontColor(branding.backgroundBase);
|
|
461
688
|
const primaryForeground = deriveFontColor(branding.primary);
|
|
462
689
|
const accentForeground = deriveFontColor(branding.accent);
|
|
463
690
|
const backgroundElevated = deriveElevatedBackground(branding.backgroundBase);
|
|
464
691
|
const backgroundRecessed = deriveRecessedBackground(branding.backgroundBase);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
their class names are scannable here. */
|
|
470
|
-
@source "../node_modules/@zorgo/next/dist/components.mjs";
|
|
471
|
-
|
|
472
|
-
:root {
|
|
692
|
+
const fontFamilyEscaped = branding.fontFamily.replace(/"/g, '\\"');
|
|
693
|
+
const fontImport = opts.selfHostedFont ? "" : `@import url("https://fonts.googleapis.com/css2?family=${branding.fontFamily.replace(/ /g, "+")}:wght@400;700&display=swap");
|
|
694
|
+
`;
|
|
695
|
+
return `${fontImport}:root {
|
|
473
696
|
--background: ${branding.backgroundBase};
|
|
474
697
|
--background-elevated: ${backgroundElevated};
|
|
475
698
|
--background-recessed: ${backgroundRecessed};
|
|
@@ -478,7 +701,7 @@ function buildGlobalsCss(branding) {
|
|
|
478
701
|
--primary-foreground: ${primaryForeground};
|
|
479
702
|
--accent: ${branding.accent};
|
|
480
703
|
--accent-foreground: ${accentForeground};
|
|
481
|
-
--font-sans: "${
|
|
704
|
+
--font-sans: "${fontFamilyEscaped}", sans-serif;
|
|
482
705
|
}
|
|
483
706
|
|
|
484
707
|
@theme inline {
|
|
@@ -492,22 +715,6 @@ function buildGlobalsCss(branding) {
|
|
|
492
715
|
--color-accent-foreground: var(--accent-foreground);
|
|
493
716
|
--font-sans: var(--font-sans);
|
|
494
717
|
}
|
|
495
|
-
|
|
496
|
-
@layer base {
|
|
497
|
-
button,
|
|
498
|
-
[type="button"],
|
|
499
|
-
[type="submit"],
|
|
500
|
-
[type="reset"] {
|
|
501
|
-
cursor: pointer;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
button:disabled,
|
|
505
|
-
[type="button"]:disabled,
|
|
506
|
-
[type="submit"]:disabled,
|
|
507
|
-
[type="reset"]:disabled {
|
|
508
|
-
cursor: not-allowed;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
718
|
`;
|
|
512
719
|
}
|
|
513
720
|
async function runPrebuild() {
|
|
@@ -521,13 +728,24 @@ async function runPrebuild() {
|
|
|
521
728
|
}
|
|
522
729
|
const payload = JSON.parse(Buffer.from(encodedPayload, "base64url").toString());
|
|
523
730
|
const franchiseId = payload.franchise_ids[0];
|
|
524
|
-
const [menuData] = await Promise.all([
|
|
731
|
+
const [menuData, locationRows] = await Promise.all([
|
|
525
732
|
menu({ franchiseId, token }),
|
|
733
|
+
locations({ franchiseId, token }).catch((err) => {
|
|
734
|
+
console.error("locations failed:", err);
|
|
735
|
+
return [];
|
|
736
|
+
}),
|
|
526
737
|
logo({ franchiseId, token }).catch((err) => console.error("logo failed:", err)),
|
|
527
|
-
|
|
528
|
-
|
|
738
|
+
styles({ franchiseId, token }).catch((err) => console.error("styles failed:", err)),
|
|
739
|
+
featureConfig({ franchiseId, token }).catch(
|
|
740
|
+
(err) => console.error("featureConfig failed:", err)
|
|
741
|
+
),
|
|
742
|
+
// Purely local (assets/images -> public/images), so it needs no token and
|
|
743
|
+
// rides along with the network work instead of adding to the wall clock.
|
|
744
|
+
optimizeSiteImages(process.cwd()).catch(
|
|
745
|
+
(err) => console.error("site images failed:", err)
|
|
746
|
+
)
|
|
529
747
|
]);
|
|
530
|
-
await jsonLd({ franchiseId, token }, menuData).catch(
|
|
748
|
+
await jsonLd({ franchiseId, token }, menuData, locationRows).catch(
|
|
531
749
|
(err) => console.error("jsonLd failed:", err)
|
|
532
750
|
);
|
|
533
751
|
console.log("prebuild script completed");
|
|
@@ -535,6 +753,8 @@ async function runPrebuild() {
|
|
|
535
753
|
// Annotate the CommonJS export names for ESM import in node:
|
|
536
754
|
0 && (module.exports = {
|
|
537
755
|
SiteTokenError,
|
|
756
|
+
buildBrandingCss,
|
|
757
|
+
buildWranglerToml,
|
|
538
758
|
fetchSiteToken,
|
|
539
759
|
runPrebuild
|
|
540
760
|
});
|