refactor separate the document envelope from the page landmarks

document_head built <head> and page_header built <header> — one letter and one underscore apart, for metadata versus a visible masthead. The scaffolding family also mixed prefixes with no rule behind it: document_head, document_body, document alongside page_header, page_main, page_footer. Split them on purpose instead. document_* is the envelope a browser reads; page_* is what a reader sees inside it. page_header becomes page_banner, after the ARIA landmark <header> maps to, and page_main becomes page_content, which also states the constraint that there is at most one per document. The interface now documents the two families as subsections and names the confusable pair explicitly.

Commit
20272ed4beb9ba4b96701ca131d4fa93a44427d3
Author
Claude Sonnet 4 <claude@anthropic.invalid>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/views/error.ml
index 08da5fe8..758231ce 100644..100644
@@ -34,12 +34,12 @@
34 34 ~body:
35 35 (Ui.document_body
36 36 [
37 Removed: Ui.page_header ~id:"error-header"
37 Added: Ui.page_banner ~id:"error-header"
38 38 [
39 39 Ui.inline_text ~class_:"error-code" status_code;
40 40 Ui.heading [ Ui.text title ];
41 41 ];
42 Removed: Ui.page_main ~id:"main"
42 Added: Ui.page_content ~id:"main"
43 43 [
44 44 Ui.paragraph_text ~class_:"error-hint" (hint_of_status status);
45 45 Ui.paragraph_text ~class_:"error-detail" message;
lib/views/layout.ml
index a2cecfa5..b48d9c2b 100644..100644
@@ -68,9 +68,9 @@
68 68 match (has_repo, meaningful_subtitle subtitle) with
69 69 | true, "" -> Ui.nothing
70 70 | true, subtitle ->
71 Removed: Ui.page_header ~id:"page-header" [ Ui.paragraph_text subtitle ]
71 Added: Ui.page_banner ~id:"page-header" [ Ui.paragraph_text subtitle ]
72 72 | false, subtitle ->
73 Removed: Ui.page_header ~id:"page-header"
73 Added: Ui.page_banner ~id:"page-header"
74 74 ([
75 75 Ui.image ~class_:"site-logo" ~src:"/static/git_icon.svg" ();
76 76 Ui.heading [ Ui.text page_title ];
@@ -118,7 +118,7 @@
118 118 Ui.skip_link ~href:"#main" "Skip to content";
119 119 navigation;
120 120 toolbar;
121 Removed: Ui.page_main ~id:"main" (header_node :: page_data.content);
121 Added: Ui.page_content ~id:"main" (header_node :: page_data.content);
122 122 mobile;
123 123 footer site.user_name;
124 124 Ui.inline_script highlight_blob;
lib/views/ui.ml
index 18dfcd72..5040001c 100644..100644
@@ -374,10 +374,10 @@
374 374
375 375 let skip_link ~href label = text_link ~class_:"skip-link" ~href label
376 376
377 Removed: let page_header ?id ?class_ children =
377 Added: let page_banner ?id ?class_ children =
378 378 HTML.header (opt_id id @ opt_class class_) children
379 379
380 Removed: let page_main ?id ?class_ children =
380 Added: let page_content ?id ?class_ children =
381 381 HTML.main (opt_id id @ opt_class class_) children
382 382
383 383 let page_footer ?class_ children = HTML.footer (opt_class class_) children
lib/views/ui.mli
index 61fdc897..6dfb63b5 100644..100644
@@ -334,8 +334,14 @@
334 334 there is nothing to show. *)
335 335 end
336 336
337 Removed: (** {1 Document scaffolding} *)
337 Added: (** {1 Document scaffolding}
338 338
339 Added: Two families, kept apart by prefix. The [document_] functions build the
340 Added: envelope a browser reads — [html], [head], [body] — and the [page_]
341 Added: functions build the landmarks a reader sees inside it. [document_head] and
342 Added: [page_banner] are the pair most easily confused: the first is metadata, the
343 Added: second is the visible masthead. *)
344 Added:
339 345 val meta_viewport : node
340 346 (** Opts the page into responsive layout. Without it mobile browsers assume a
341 347 desktop-width viewport and scale the page down. *)
@@ -350,21 +356,35 @@
350 356 (** Inline behaviour. Reserved for progressive enhancement: pages must stay
351 357 usable when it does not run. *)
352 358
353 Removed: val document_head : title:string -> node list -> node
354 Removed: (** The document head. [title] comes first so it cannot be forgotten. *)
355 Removed:
356 359 val skip_link : href:string -> string -> node
357 360 (** A link that jumps past repeated navigation, revealed on focus. Expected on
358 361 every page for keyboard users. *)
359 362
360 Removed: val page_header : ?id:string -> ?class_:string -> node list -> node
361 Removed: val page_main : ?id:string -> ?class_:string -> node list -> node
362 Removed: val page_footer : ?class_:string -> node list -> node
363 Added: (** {2 The document envelope} *)
364 Added:
365 Added: val document_head : title:string -> node list -> node
366 Added: (** The [head] element: title, metadata and asset links. [title] comes first so
367 Added: it cannot be forgotten. *)
368 Added:
363 369 val document_body : ?class_:string -> node list -> node
370 Added: (** The [body] element. *)
364 371
365 372 val document : ?lang:string -> head:node -> body:node -> unit -> node
366 373 (** A complete document. [lang] defaults to ["en"]; set it so screen readers
367 374 pick the right pronunciation. *)
375 Added:
376 Added: (** {2 Landmarks within the page} *)
377 Added:
378 Added: val page_banner : ?id:string -> ?class_:string -> node list -> node
379 Added: (** The [header] element introducing the page — its masthead. Named for the ARIA
380 Added: landmark it maps to, and to keep it distinct from {!val-document_head}. *)
381 Added:
382 Added: val page_content : ?id:string -> ?class_:string -> node list -> node
383 Added: (** The [main] element: the content unique to this page, which the skip link
384 Added: targets. At most one per document. *)
385 Added:
386 Added: val page_footer : ?class_:string -> node list -> node
387 Added: (** The [footer] element closing the page. *)
368 388
369 389 (** {1 Responses} *)
370 390