code wiki / _hdl_build / nx_food_site.nx
nx_food_site.nx source
↩ module page · 139 lines · 9756 B
1// nx_food_site.nx -- LIB: the CONSUME surface. Renders the restaurant SITE from the LIVE grounded store,
2// composed from the `food` builder domain (catalog templates resolved by nb_lookup + the domain-agnostic
3// nw_render binding substitution). Closes the food loop end to end: seg-store -> engine -> builder domain ->
4// sovereign no-JS page. Boundary defense (rule 12): all data bindings are HTML-escaped by nw_bind_add, so a
5// restaurant name like "<script>" cannot inject markup. license_tier: ORIGINAL
6import "nx_food_science.nx"
7import "nx_web_render.nx"
8import "nx_food_clean_source.nx"
9import "nx_syscalls.nx"
10
11// resolve a FOOD-domain component (kind,id) from the catalog and render it with `bindings` (nw_emit_component
12// is hardcoded to the web domain, so the food branch needs its own thin resolver over the shared nw_render).
13func fs_emit_component(catpath: *u8, kind: *u8, id: *u8, bindings: *u8, out: *u8, off: i64) -> i64 {
14 let tpl: *u8 = sys_mmap(4096)
15 if nb_lookup(catpath, "food" as *u8, kind, id, tpl) == 0 { return off }
16 return nw_render(out, off, tpl, bindings)
17}
18
19// format an integer into a fresh NUL-terminated buffer (for escaped bindings)
20func fs_num(v: i64) -> *u8 {
21 let b: *u8 = sys_mmap(24)
22 let o: i64 = fd_apnum(b, 0, v)
23 b[o] = 0 as u8
24 return b
25}
26
27// join the display names of every build member with role rc into out (", " separated, NUL-terminated)
28func fs_role_names(world: *i64, build: *i64, roles: *i64, nb: i64, rc: i64, out: *u8) -> i64 {
29 let names: *i64 = world[4] as *i64
30 var o: i64 = 0
31 var first: i64 = 1
32 var i: i64 = 0
33 while i < nb {
34 if roles[i] == rc {
35 if first == 0 { o = as_append(out, o, ", " as *u8) }
36 o = as_append(out, o, names[build[i]] as *u8)
37 first = 0
38 }
39 i = i + 1
40 }
41 out[o] = 0 as u8
42 return o
43}
44
45// TEACH the food domain to a builder catalog (durable registry). Idempotent (nb_register skips if present).
46// Returns the food-domain emitter count after teaching.
47func fs_teach(catpath: *u8) -> i64 {
48 nb_register(catpath, "food" as *u8, "nav" as *u8, "foodbar" as *u8, "Food nav bar" as *u8, "<nav class='fbar'><a class='brand' href='/'>{BRAND}</a><span class='tag'>{LINKS}</span></nav>" as *u8)
49 nb_register(catpath, "food" as *u8, "section" as *u8, "hero" as *u8, "Food hero" as *u8, "<header class='hero'><h1>{TITLE}</h1><p class='sub'>{SUB}</p></header>" as *u8)
50 nb_register(catpath, "food" as *u8, "section" as *u8, "recommendation" as *u8, "Stir-fry recommendation" as *u8, "<section class='rec'><h2>{HEAD}</h2><ul class='build'><li><b>Protein:</b> {PROTEIN}</li><li><b>Vegetables:</b> {VEG}</li><li><b>Aromatics:</b> {AROMATIC}</li><li><b>Sauce:</b> {SAUCE}</li></ul><p class='why'>{WHY}</p></section>" as *u8)
51 nb_register(catpath, "food" as *u8, "section" as *u8, "science" as *u8, "Food-science breakdown" as *u8, "<section class='sci'><h2>{HEAD}</h2><dl class='metrics'><dt>Five-taste balance (lower is better)</dt><dd>{BALANCE}</dd><dt>Pairing affinity (recipe-grounded)</dt><dd>{AFFINITY}</dd><dt>Texture contrast</dt><dd>{TEXTURE}</dd><dt>Overall score</dt><dd>{SCORE}</dd></dl><p class='note'>{NOTE}</p></section>" as *u8)
52 nb_register(catpath, "food" as *u8, "section" as *u8, "footer" as *u8, "Food footer" as *u8, "<footer class='ftr'><p>{COPY}</p></footer>" as *u8)
53 return nb_count(catpath, "food" as *u8, "*" as *u8)
54}
55
56// render the full sovereign site (NUL-terminated) into out; returns byte length. Composes nav + hero +
57// recommendation + science + footer from the catalog, bound to the LIVE chooser output over `store_prefix`.
58// all-available, neutral-preference wrapper (the R-SITE flagship page)
59func fs_render(store_prefix: *u8, catpath: *u8, restaurant: *u8, out: *u8) -> i64 {
60 let h0: *i64 = fd_world_open(store_prefix)
61 let n0: i64 = h0[0]
62 let avail0: *i64 = sys_mmap(8 * 64) as *i64
63 let avoid0: *i64 = sys_mmap(8 * 64) as *i64
64 let prefw0: *i64 = sys_mmap(8 * 8) as *i64
65 fd_set_all(avail0, n0, 1); fd_set_all(avoid0, n0, 0)
66 var z0: i64 = 0; while z0 < FOOD_NAX { prefw0[z0] = 0; z0 = z0 + 1 }
67 return fs_render_avail(store_prefix, catpath, restaurant, avail0, avoid0, prefw0, out)
68}
69
70// the core renderer: compose the site for an explicit availability mask + preference profile. Used by the
71// flagship page (all available) AND by per-restaurant pages (only that restaurant's menu available).
72func fs_render_avail(store_prefix: *u8, catpath: *u8, restaurant: *u8, avail: *i64, avoid: *i64, prefw: *i64, out: *u8) -> i64 {
73 let h: *i64 = fd_world_open(store_prefix)
74 let n: i64 = h[0]
75 let frame: *i64 = sys_mmap(8 * 16) as *i64
76 let nframe: i64 = fd_load_frame(store_prefix, frame)
77 let wts: *i64 = sys_mmap(8 * 8) as *i64
78 fd_load_weights(store_prefix, wts)
79 let build: *i64 = sys_mmap(8 * 16) as *i64
80 let roles: *i64 = sys_mmap(8 * 16) as *i64
81 let nb: i64 = fd_choose(h, avail, avoid, prefw, frame, nframe, wts, build, roles)
82
83 let pn: *u8 = sys_mmap(256); fs_role_names(h, build, roles, nb, FROLE_PRO, pn)
84 let vn: *u8 = sys_mmap(256); fs_role_names(h, build, roles, nb, FROLE_VEG, vn)
85 let an: *u8 = sys_mmap(256); fs_role_names(h, build, roles, nb, FROLE_ARO, an)
86 let sn: *u8 = sys_mmap(256); fs_role_names(h, build, roles, nb, FROLE_SAU, sn)
87 let imb: i64 = fd_imbalance(h, build, nb)
88 let aff: i64 = fd_affinity_total(h, build, nb)
89 let tex: i64 = fd_texture_contrast(h, build, nb)
90 let sc: i64 = fd_score(h, build, nb, prefw, wts)
91
92 var o: i64 = 0
93 o = as_append(out, o, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Nishi Stir-Fry</title><style>:root{--ink:#1b1410;--accent:#7a1f1f;--gold:#e3b04b;--bg:#fbf7f0}*{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:var(--ink);background:var(--bg);line-height:1.55}.fbar{display:flex;justify-content:space-between;align-items:center;padding:14px 22px;background:var(--accent);color:#fff}.fbar .brand{color:#fff;text-decoration:none;font-weight:800;letter-spacing:.3px}.fbar .tag{color:var(--gold);font-size:.85rem}.hero{padding:56px 22px 40px;text-align:center;background:linear-gradient(180deg,#7a1f1f,#9a3a2a);color:#fff}.hero h1{margin:0 0 8px;font-size:1.8rem}.hero .sub{margin:0;color:#f5ddc9;max-width:46ch;margin-inline:auto}main{max-width:660px;margin:0 auto;padding:8px 22px 40px}section{background:#fff;border-radius:12px;padding:18px 20px;margin-top:18px;box-shadow:0 1px 0 #e8ddc8}h2{font-size:1.15rem;margin:0 0 10px;border-bottom:2px solid var(--gold);padding-bottom:6px}ul.build{list-style:none;padding:0;margin:0}ul.build li{padding:6px 0;border-bottom:1px solid #f0e7d6}.why{color:#5b4a37;margin:12px 0 0}dl.metrics{display:grid;grid-template-columns:1fr auto;gap:6px 14px;margin:0}dl.metrics dt{color:#5b4a37}dl.metrics dd{margin:0;font-weight:800;font-variant-numeric:tabular-nums;text-align:right}.note{color:#5b4a37;margin:12px 0 0}.ftr{padding:24px 22px;text-align:center;color:#8a7a64;font-size:.85rem}</style></head><body>" as *u8)
94
95 let nbnav: *u8 = sys_mmap(512)
96 var b: i64 = nw_bind_add(nbnav, 0, "BRAND" as *u8, "Nishi Stir-Fry" as *u8)
97 b = nw_bind_add(nbnav, b, "LINKS" as *u8, "Michelin balance at budget prices" as *u8); nbnav[b] = 0 as u8
98 o = fs_emit_component(catpath, "nav" as *u8, "foodbar" as *u8, nbnav, out, o)
99
100 let title: *u8 = sys_mmap(256)
101 var tt: i64 = as_append(title, 0, "The best stir-fry at " as *u8); tt = as_append(title, tt, restaurant); title[tt] = 0 as u8
102 let nbhero: *u8 = sys_mmap(1024)
103 b = nw_bind_add(nbhero, 0, "TITLE" as *u8, title)
104 b = nw_bind_add(nbhero, b, "SUB" as *u8, "Built from what they actually have on hand tonight, balanced by food science." as *u8); nbhero[b] = 0 as u8
105 o = fs_emit_component(catpath, "section" as *u8, "hero" as *u8, nbhero, out, o)
106
107 o = as_append(out, o, "<main>" as *u8)
108
109 let nbrec: *u8 = sys_mmap(2048)
110 b = nw_bind_add(nbrec, 0, "HEAD" as *u8, "Tonight's build" as *u8)
111 b = nw_bind_add(nbrec, b, "PROTEIN" as *u8, pn)
112 b = nw_bind_add(nbrec, b, "VEG" as *u8, vn)
113 b = nw_bind_add(nbrec, b, "AROMATIC" as *u8, an)
114 b = nw_bind_add(nbrec, b, "SAUCE" as *u8, sn)
115 b = nw_bind_add(nbrec, b, "WHY" as *u8, "Chosen to balance the five tastes with an aromatic backbone, textural contrast, and pairings grounded in real recipes." as *u8); nbrec[b] = 0 as u8
116 o = fs_emit_component(catpath, "section" as *u8, "recommendation" as *u8, nbrec, out, o)
117
118 let nbsci: *u8 = sys_mmap(1024)
119 b = nw_bind_add(nbsci, 0, "HEAD" as *u8, "Why this is the best" as *u8)
120 b = nw_bind_add(nbsci, b, "BALANCE" as *u8, fs_num(imb))
121 b = nw_bind_add(nbsci, b, "AFFINITY" as *u8, fs_num(aff))
122 b = nw_bind_add(nbsci, b, "TEXTURE" as *u8, fs_num(tex))
123 b = nw_bind_add(nbsci, b, "SCORE" as *u8, fs_num(sc))
124 b = nw_bind_add(nbsci, b, "NOTE" as *u8, "The Michelin balance, at your local spot's prices." as *u8); nbsci[b] = 0 as u8
125 o = fs_emit_component(catpath, "section" as *u8, "science" as *u8, nbsci, out, o)
126
127 // clean-sourcing badge: the impact economics, joined to the recommendation (covered veg only; honest)
128 o = fc_render_badge(store_prefix, h, build, roles, nb, out, o)
129
130 o = as_append(out, o, "</main>" as *u8)
131
132 let nbftr: *u8 = sys_mmap(512)
133 b = nw_bind_add(nbftr, 0, "COPY" as *u8, "(c) Nishi Family -- sovereign, no tracking, no third-party scripts." as *u8); nbftr[b] = 0 as u8
134 o = fs_emit_component(catpath, "section" as *u8, "footer" as *u8, nbftr, out, o)
135
136 o = as_append(out, o, "</body></html>" as *u8)
137 out[o] = 0 as u8
138 return o
139}