| 1 | {{define "layout"}}<!doctype html> |
| 2 | {{/* layout — every page's document: the head, the estilo bar, <main> |
| 3 | and the footer. |
| 4 | |
| 5 | The bar is estilo's (chrome.Bar, built once per request in |
| 6 | chrome.go), in place of the hand-made rst-page-header nav, which |
| 7 | wrapped onto two rows at 1440px (97px) with its open Help panel over |
| 8 | the Sources and Sign out buttons. estilo's is 52px at every width, |
| 9 | signed in or out, with the account always last in the same corner. |
| 10 | |
| 11 | data-theme is written into the first bytes of the response, from the |
| 12 | Appearance cookie read server-side (chrome.Appearance), so there is |
| 13 | no flash. It is ABSENT for "system", and that is the mechanism: |
| 14 | theme.css's toggle is :root[data-theme="light"|"dark"], and with no |
| 15 | attribute the browser follows the operating system. |
| 16 | |
| 17 | The <title> is built here and only here, "{part} · {part} · Memoria", |
| 18 | so no handler can drift from the suite's separator (spec §10). It |
| 19 | used to be written per page, and they said "—" and "·" by turns. |
| 20 | |
| 21 | <meta charset> comes first, before anything that could be read as |
| 22 | text. The stylesheets are in the suite's fixed order: tokens, theme, |
| 23 | brand, then estilo's base, menu and chrome (and the door's sky), then |
| 24 | memoria.css, then the page's own (head). */}} |
| 25 | <html lang="en"{{with .Frame.Theme}} data-theme="{{.}}"{{end}}> |
| 26 | <head> |
| 27 | <meta charset="utf-8"> |
| 28 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 29 | <title>{{range .Frame.TitleParts}}{{.}} · {{end}}{{.Frame.Chrome.App.Name}}</title> |
| 30 | <link rel="icon" type="image/png" sizes="32x32" href="{{asset "static/brand/icon-32.png"}}"> |
| 31 | <link rel="icon" type="image/svg+xml" href="{{asset "static/brand/icon.svg"}}"> |
| 32 | <link rel="apple-touch-icon" sizes="180x180" href="{{asset "static/brand/apple-touch-icon.png"}}"> |
| 33 | <link rel="stylesheet" href="/static/estilo/fonts/v1/fonts.css"> |
| 34 | <link rel="stylesheet" href="{{asset "static/tokens.css"}}"> |
| 35 | <link rel="stylesheet" href="{{asset "static/busy.css"}}"> |
| 36 | {{/* theme.css carries the palette. tokens.css only USES --rst-bg and |
| 37 | friends — it defines eleven tokens, none of them colours — so |
| 38 | without this link every colour resolves to initial and whole |
| 39 | shorthand declarations become invalid at computed-value time. The |
| 40 | rastrillo scaffold's layout omits it, which is a scaffold bug, not |
| 41 | a choice: the page does not go grey, individual rules vanish. */}} |
| 42 | <link rel="stylesheet" href="{{asset "static/theme.css"}}"> |
| 43 | <link rel="stylesheet" href="{{asset "static/brand/brand.css"}}"> |
| 44 | <link rel="stylesheet" href="{{asset "static/base.css"}}"> |
| 45 | <link rel="stylesheet" href="{{asset "static/menu.css"}}"> |
| 46 | <link rel="stylesheet" href="{{asset "static/chrome.css"}}"> |
| 47 | <link rel="stylesheet" href="{{asset "static/sky.css"}}"> |
| 48 | <link rel="stylesheet" href="{{asset "static/memoria.css"}}"> |
| 49 | <script defer src="{{asset "static/rastrillo.js"}}"></script> |
| 50 | <script defer src="{{asset "static/busy.js"}}"></script> |
| 51 | {{/* chrome.js closes an open bar panel on Escape or an outside click. |
| 52 | Nothing depends on it. */}} |
| 53 | <script defer src="{{asset "static/chrome.js"}}"></script> |
| 54 | {{/* drop.js is inert on every page but the one carrying [rst-dropzone]: |
| 55 | it looks for the zone first and returns if there is none. It is |
| 56 | linked here rather than in index.html because the layout is where |
| 57 | scripts are linked, and it costs a querySelector to load it twice. */}} |
| 58 | <script defer src="{{asset "static/drop.js"}}"></script> |
| 59 | {{/* search.js is the same bargain, keyed on [rst-search]. It shares the |
| 60 | results region with drop.js and does not assume it owns it. */}} |
| 61 | <script defer src="{{asset "static/search.js"}}"></script> |
| 62 | {{iconAssets}} |
| 63 | {{block "head" .}}{{end}} |
| 64 | </head> |
| 65 | <body> |
| 66 | {{/* [estilo-shell] has no styling of its own; it is the wrapper a |
| 67 | full-height page would key its layout on. */}} |
| 68 | <div estilo-shell> |
| 69 | <a rst-skip href="#main">{{.Frame.Chrome.Labels.Skip}}</a> |
| 70 | {{template "estilo-bar" .Frame.Chrome}} |
| 71 | <main rst-page id="main"> |
| 72 | {{template "content" .}} |
| 73 | </main> |
| 74 | {{/* The footer is said only to somebody signed in: its count and its |
| 75 | egress claim are statements about searching (spec §9.2 retires the |
| 76 | claim from the sign-in page), and a visitor who cannot search has |
| 77 | nothing they are true or false about. */}} |
| 78 | {{if .Frame.Signed}}{{block "footer" .}}<footer rst-page-footer> |
| 79 | {{/* An upload that never navigates cannot change the passage count, |
| 80 | so it carries rst-refresh and drop.js swaps it out of a re-fetch |
| 81 | of the page. On /add it is the only region that does. drop.js |
| 82 | aborts the whole swap if a named region is missing from the |
| 83 | answer, so the span is on every signed-in page. |
| 84 | The span wraps ONLY the count: the egress claim beside it is not |
| 85 | derived from anything and has no business travelling with it. |
| 86 | |
| 87 | Both branches are inside the span, deliberately. Chunks is -1 when |
| 88 | the count could not be read at all, and the sentence for that is |
| 89 | the one thing here that must survive a refresh: a region that |
| 90 | carried only the number would refresh a failure into a confident |
| 91 | zero, which is the failure shape this app has already had once. */}} |
| 92 | <p rst-muted> |
| 93 | <span rst-refresh="passages">{{if lt .Chunks 0}}The passage count is unavailable.{{else}}{{.Chunks}} passage{{if ne .Chunks 1}}s{{end}} indexed.{{end}}</span> |
| 94 | {{/* The egress claim, and it depends on the model switch (§8.9). With |
| 95 | AI off the strong sentence is true and is stated. With AI on it is |
| 96 | FALSE: a search that asks for a postal address sends up to eight |
| 97 | passages to TensorX. The first build left the strong sentence on |
| 98 | every page while that happened; a review sent a passage and got |
| 99 | this footer back in the same response. */}} |
| 100 | {{if .ModelOn}}Search is lexical. <strong>AI is on:</strong> a search |
| 101 | that asks for a postal address sends up to eight of its passages to |
| 102 | TensorX, including while you type. No other document leaves this |
| 103 | instance. |
| 104 | {{else}}Search is lexical only — no assistant, and <strong>no document ever |
| 105 | leaves this instance</strong>.{{end}} |
| 106 | </p> |
| 107 | </footer>{{end}}{{end}} |
| 108 | </div> |
| 109 | </body> |
| 110 | </html> |
| 111 | {{end}} |
| 112 | |