writeonce/docs/examples/shop/layout/app.wo
shoney.arickathil 89df517613 feat(shop): the program template — MVC on disk; story 37 redirected
- docs/examples/shop: types.wo model, per-feature view modules
  (render() classes), root controller files, layout shell/header/
  footer, static assets controller + real style.css, README with
  Angular file map + run + DX referendum notes
- buy flow proven by hand: stock check/decrement, 409s, traversal
  404, css typed, WAL-durable; builds on the UNPATCHED toolchain
- two language gaps recorded, not fixed (per directive): pub+@table
  cannot combine (controllers forced into root module); @view
  projection classes absent
- story 37 REDIRECTED per Vue-SFC review: view.html compiled by woc
  ({{}} auto-escaped, w:if/w:for, typed against view class, no
  runtime engine); render()-as-concatenation failed the referendum;
  forks revised; shop named the acceptance consumer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 23:57:44 +02:00

34 lines
1.4 KiB
Text

-- layout/app.wo — the app shell (app.html's analog): one full document
-- wrapping every page with the shared header and footer. Styles are NOT
-- inlined here — the shop links /assets/style.css, a real stylesheet
-- served by the static_files controller, so view markup and styling
-- stay separate files exactly as the template promises.
use framework/http
use html
pub fn app_shell(title: Text, content: Text) -> Text {
let d = "<!doctype html><html><head><meta charset=\"utf-8\">";
d = d .. "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">";
d = d .. "<title>${esc(title)}</title>";
d = d .. "<link rel=\"stylesheet\" href=\"/assets/style.css\">";
d = d .. "</head><body>";
d = d .. header();
d = d .. el("main", "site-main", content);
d = d .. footer();
d = d .. "</body></html>";
return d;
}
-- The one transport helper every controller shares: a 200 HTML Resp.
pub fn ok_html(body: Text) -> Resp {
let h: map<Text, Text> = {};
h["content-type"] = "text/html; charset=utf-8";
return Resp { status: 200, headers: h, body: body };
}
pub fn html_error(status: Int, title: Text, msg: Text) -> Resp {
let content = el("h1", "", esc(title)) .. el("p", "", esc(msg)) .. el("p", "", link("/", "", "Back to products"));
let h: map<Text, Text> = {};
h["content-type"] = "text/html; charset=utf-8";
return Resp { status: status, headers: h, body: app_shell("shop — ${title}", content) };
}