code wiki / _hdl_build / nx_food_menu.nx
nx_food_menu.nx source
↩ module page · 172 lines · 9352 B
1// nx_food_menu.nx -- LIB: per-RESTAURANT availability (the original ask -- "the best stir-fry from the
2// ingredients/options at THEIR local restaurant"). Each restaurant is a record in the store (name, blurb,
3// available-ingredient list); the chooser runs against ONLY that restaurant's menu, so different restaurants
4// yield different recommendations. Also renders a sovereign no-JS directory page. Builds on nx_food_site
5// (fs_render_avail). license_tier: ORIGINAL
6import "nx_food_site.nx"
7import "nx_food_science.nx"
8import "nx_seg_store.nx"
9import "nx_syscalls.nx"
10const K_MAGIC_1024: i64 = 1024
11
12// seed the restaurant records (idempotent). Schema: food:rest:<id> -> name <t> blurb <t> space-separated
13// available ingredient ids; food:restids -> TAB list of restaurant ids.
14func fd_seed_restaurants(prefix: *u8) -> i64 {
15 let keys: *i64 = sys_mmap(8 * 16) as *i64
16 let vals: *i64 = sys_mmap(8 * 16) as *i64
17 var n: i64 = 0
18 keys[n] = "food:restids" as *u8 as i64
19 vals[n] = "goldenwok\tmongoliangrill\tgreenwok\tspicehouse" as *u8 as i64; n = n + 1
20 keys[n] = "food:rest:goldenwok" as *u8 as i64
21 vals[n] = "Golden Wok\tClassic Cantonese-style stir-fry\tbeef chicken tofu broccoli bellpepper onion mushroom garlic ginger scallion soy oyster hoisin" as *u8 as i64; n = n + 1
22 keys[n] = "food:rest:mongoliangrill" as *u8 as i64
23 vals[n] = "Khan's Mongolian Grill\tBuild-your-own Mongolian BBQ bar\tbeef pork chicken tofu broccoli carrot onion snowpea beansprout mushroom garlic ginger chili scallion soy oyster blackbean sweetchili" as *u8 as i64; n = n + 1
24 keys[n] = "food:rest:greenwok" as *u8 as i64
25 vals[n] = "Green Wok\tTofu and vegetable focused, no red meat\ttofu shrimp broccoli bellpepper carrot snowpea mushroom bokchoy beansprout garlic ginger scallion soy hoisin blackbean" as *u8 as i64; n = n + 1
26 keys[n] = "food:rest:spicehouse" as *u8 as i64
27 vals[n] = "Sichuan Spice House\tFiery Sichuan heat\tbeef pork chicken tofu bellpepper onion mushroom garlic ginger chili scallion soy blackbean sweetchili" as *u8 as i64; n = n + 1
28
29 let w: *i64 = ss_begin()
30 var towrite: i64 = 0
31 var i: i64 = 0
32 while i < n {
33 let key: *u8 = keys[i] as *u8
34 let val: *u8 = vals[i] as *u8
35 let vl: i64 = as_len(val)
36 if fd_streq_store(prefix, key, val, vl) == 0 { ss_add(w, 1, key, val, vl); towrite = towrite + 1 }
37 i = i + 1
38 }
39 if towrite > 0 { let seg: i64 = fd_seg_next(prefix); ss_commit(prefix, w, seg) }
40 return towrite
41}
42
43// build an availability mask from a space-separated ingredient-id list; returns the number recognised.
44func fs_avail_from_idlist(world: *i64, listbuf: *u8, listlen: i64, avail: *i64) -> i64 {
45 let n: i64 = world[0]
46 fd_set_all(avail, n, 0)
47 var i: i64 = 0
48 var ls: i64 = 0
49 var recog: i64 = 0
50 while i <= listlen {
51 var sep: i64 = 0
52 if i == listlen { sep = 1 } else { if listbuf[i] == (32 as u8) { sep = 1 } }
53 if sep == 1 {
54 let tl: i64 = i - ls
55 if tl > 0 {
56 let tok: *u8 = sys_mmap(48)
57 var t: i64 = 0
58 while t < tl { tok[t] = listbuf[ls + t]; t = t + 1 }
59 tok[tl] = 0 as u8
60 if fd_set_id(world, avail, tok, 1) == 1 { recog = recog + 1 }
61 }
62 ls = i + 1
63 }
64 i = i + 1
65 }
66 return recog
67}
68
69// fill avail[] for restaurant `rest_id` and copy its display name into name_out; 1 if found, 0 if not.
70func fs_restaurant_avail(store_prefix: *u8, rest_id: *u8, avail: *i64, name_out: *u8) -> i64 {
71 let key: *u8 = sys_mmap(80)
72 var o: i64 = 0
73 o = as_append(key, o, "food:rest:" as *u8)
74 o = as_append(key, o, rest_id)
75 key[o] = 0 as u8
76 let pq: *i64 = sys_mmap(16) as *i64
77 let lq: *i64 = sys_mmap(16) as *i64
78 if ss_get(store_prefix, key, pq, lq) != 1 { return 0 }
79 let rec: *u8 = pq[0] as *u8
80 let rl: i64 = lq[0]
81 fd_field(rec, rl, 0, name_out)
82 let availlist: *u8 = sys_mmap(512)
83 let all_len: i64 = fd_field(rec, rl, 2, availlist)
84 let world: *i64 = fd_world_open(store_prefix)
85 fs_avail_from_idlist(world, availlist, all_len, avail)
86 return 1
87}
88
89// render a per-restaurant recommendation page (only that restaurant's menu available, neutral preference).
90// Returns byte length, or 0 if the restaurant id is unknown.
91func fs_render_restaurant(store_prefix: *u8, catpath: *u8, rest_id: *u8, out: *u8) -> i64 {
92 let avail: *i64 = sys_mmap(8 * 64) as *i64
93 let avoid: *i64 = sys_mmap(8 * 64) as *i64
94 let prefw: *i64 = sys_mmap(8 * 8) as *i64
95 let name: *u8 = sys_mmap(128)
96 if fs_restaurant_avail(store_prefix, rest_id, avail, name) == 0 { return 0 }
97 let world: *i64 = fd_world_open(store_prefix)
98 fd_set_all(avoid, world[0], 0)
99 var z: i64 = 0; while z < FOOD_NAX { prefw[z] = 0; z = z + 1 }
100 return fs_render_avail(store_prefix, catpath, name, avail, avoid, prefw, out)
101}
102
103// emit one restaurant card (link to <id>.html) into out at off; returns new off
104func fs_dir_card(store_prefix: *u8, rest_id: *u8, out: *u8, off: i64) -> i64 {
105 let key: *u8 = sys_mmap(80)
106 var ko: i64 = 0
107 ko = as_append(key, ko, "food:rest:" as *u8)
108 ko = as_append(key, ko, rest_id)
109 key[ko] = 0 as u8
110 let pq: *i64 = sys_mmap(16) as *i64
111 let lq: *i64 = sys_mmap(16) as *i64
112 if ss_get(store_prefix, key, pq, lq) != 1 { return off }
113 let rec: *u8 = pq[0] as *u8
114 let rl: i64 = lq[0]
115 let nm: *u8 = sys_mmap(128); fd_field(rec, rl, 0, nm)
116 let bl: *u8 = sys_mmap(256); fd_field(rec, rl, 1, bl)
117 var o: i64 = off
118 o = as_append(out, o, "<a class='rcard' href='" as *u8)
119 o = as_append(out, o, rest_id)
120 o = as_append(out, o, ".html'><h3>" as *u8)
121 o = as_append_escaped(out, o, nm, as_len(nm))
122 o = as_append(out, o, "</h3><p>" as *u8)
123 o = as_append_escaped(out, o, bl, as_len(bl))
124 o = as_append(out, o, "</p></a>" as *u8)
125 return o
126}
127
128// render the sovereign no-JS restaurant directory (lists every restaurant, links to each page)
129func fs_render_directory(store_prefix: *u8, catpath: *u8, out: *u8) -> i64 {
130 var o: i64 = 0
131 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 — find your restaurant</title><style>:root{--accent:#7a1f1f;--gold:#e3b04b;--bg:#fbf7f0}body{margin:0;font-family:system-ui,sans-serif;color:#1b1410;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}.fbar .tag{color:var(--gold);font-size:.85rem}.hero{padding:48px 22px 32px;text-align:center;background:linear-gradient(180deg,#7a1f1f,#9a3a2a);color:#fff}.hero h1{margin:0 0 8px;font-size:1.7rem}.hero .sub{margin:0;color:#f5ddc9}main{max-width:660px;margin:0 auto;padding:18px 22px 40px}.grid{display:grid;gap:14px}.rcard{display:block;background:#fff;border-radius:12px;padding:16px 18px;text-decoration:none;color:inherit;box-shadow:0 1px 0 #e8ddc8;border-left:4px solid var(--gold)}.rcard h3{margin:0 0 4px;color:var(--accent)}.rcard p{margin:0;color:#5b4a37}.ftr{padding:24px 22px;text-align:center;color:#8a7a64;font-size:.85rem}</style></head><body>" as *u8)
132 let navb: *u8 = sys_mmap(512)
133 var b: i64 = nw_bind_add(navb, 0, "BRAND" as *u8, "Nishi Stir-Fry" as *u8)
134 b = nw_bind_add(navb, b, "LINKS" as *u8, "Michelin balance at budget prices" as *u8); navb[b] = 0 as u8
135 o = fs_emit_component(catpath, "nav" as *u8, "foodbar" as *u8, navb, out, o)
136 let herob: *u8 = sys_mmap(K_MAGIC_1024)
137 b = nw_bind_add(herob, 0, "TITLE" as *u8, "Find your restaurant" as *u8)
138 b = nw_bind_add(herob, b, "SUB" as *u8, "Pick where you're eating tonight; we'll build the best stir-fry from what they actually serve." as *u8); herob[b] = 0 as u8
139 o = fs_emit_component(catpath, "section" as *u8, "hero" as *u8, herob, out, o)
140 o = as_append(out, o, "<main><div class='grid'>" as *u8)
141 let pq: *i64 = sys_mmap(16) as *i64
142 let lq: *i64 = sys_mmap(16) as *i64
143 if ss_get(store_prefix, "food:restids" as *u8, pq, lq) == 1 {
144 let idsbuf: *u8 = pq[0] as *u8
145 let idslen: i64 = lq[0]
146 var i: i64 = 0
147 var ls: i64 = 0
148 while i <= idslen {
149 var sep: i64 = 0
150 if i == idslen { sep = 1 } else { if idsbuf[i] == (9 as u8) { sep = 1 } }
151 if sep == 1 {
152 let il: i64 = i - ls
153 if il > 0 {
154 let idc: *u8 = sys_mmap(48)
155 var t: i64 = 0
156 while t < il { idc[t] = idsbuf[ls + t]; t = t + 1 }
157 idc[il] = 0 as u8
158 o = fs_dir_card(store_prefix, idc, out, o)
159 }
160 ls = i + 1
161 }
162 i = i + 1
163 }
164 }
165 o = as_append(out, o, "</div></main>" as *u8)
166 let ftrb: *u8 = sys_mmap(512)
167 b = nw_bind_add(ftrb, 0, "COPY" as *u8, "(c) Nishi Family -- sovereign, no tracking, no third-party scripts." as *u8); ftrb[b] = 0 as u8
168 o = fs_emit_component(catpath, "section" as *u8, "footer" as *u8, ftrb, out, o)
169 o = as_append(out, o, "</body></html>" as *u8)
170 out[o] = 0 as u8
171 return o
172}