| 1 | package gallery |
| 2 | |
| 3 | // Every gallery page is the sidebar shell Fiesta ships: the gallery |
| 4 | // documents the shell by being one. pageTemplate is Rastrillo's page |
| 5 | // template over Fiesta's seams: say in place of P and T, the scheme |
| 6 | // menu lifted from the scheme-menu example in place of the three |
| 7 | // buttons, the page's Icon and Asset methods, every link the gallery |
| 8 | // owns marked data-gallery-nav, and the scheme store attribute on |
| 9 | // <html> so fiesta.js remembers the choice. |
| 10 | // |
| 11 | // The head loads tokens.css, the theme, shell.css and gallery.css, then |
| 12 | // gallery.js blocking, so a stored scheme is on the root and the |
| 13 | // frame-hiding rule is armed before the first paint; fiesta.js and |
| 14 | // anchor.js deferred, as the scheme-menu example loads them; shell.js |
| 15 | // deferred and render-blocking, as the layouts load it, so the slide's |
| 16 | // direction is set at the first render. |
| 17 | // |
| 18 | // The Overview's phone heading leaves the shell's brand span empty and |
| 19 | // puts the gallery's name in the title span after it. The shell hides |
| 20 | // a brand span with no element in it, as a blank brand, and shows the |
| 21 | // title instead; a brand link would add a tab stop that goes to the |
| 22 | // page it is on. The ds-prefs menu is written once per page, in the |
| 23 | // index's header row or in a content page's back strip, and both it |
| 24 | // and the bar draw their controls from one value, so the two cannot |
| 25 | // differ. |
| 26 | // |
| 27 | // The live region at the foot carries the Copy button's three words |
| 28 | // and the join as data attributes, so the script writes no words of |
| 29 | // its own. |
| 30 | const pageTemplate = `{{define "ds-controls"}}<nav rst-seg-tabs aria-label="{{say "gallery.theme.label"}}">{{range .Themes}}<a data-gallery-nav href="{{.Href}}"{{if .Current}} aria-current="page"{{end}}>{{.Label}}</a>{{end}}</nav> |
| 31 | {{.Scheme}} |
| 32 | <details rst-dropdown rst-locale name="rst-menus"> |
| 33 | <summary>{{say "gallery.language"}}<span rst-caret aria-hidden="true">{{icon "chevron-down"}}</span><span class="rst-sr-only">{{say "gallery.language.current" "language" .LocaleName}}</span></summary> |
| 34 | <div rst-dropdown-menu>{{range .Locales}}<a data-gallery-nav href="{{.Href}}" lang="{{.Code}}" dir="{{.Dir}}"{{if .Current}} aria-current="true"{{end}}>{{.Name}}</a>{{end}}</div> |
| 35 | </details>{{end}} |
| 36 | {{define "ds-prefs"}}<details rst-dropdown class="ds-prefs" id="ds-prefs" name="ds-prefs"><summary aria-label="{{say "gallery.prefs"}}">` + cogIcon + `</summary><div rst-dropdown-menu>{{template "ds-controls" .}}</div></details>{{end}} |
| 37 | {{define "ds-page"}}<!doctype html> |
| 38 | <html lang="{{.Lang}}" dir="{{.Dir}}" {{.HTMLAttrs}}> |
| 39 | <head> |
| 40 | <meta charset="utf-8"> |
| 41 | <meta name="viewport" content="width=device-width"> |
| 42 | <title>{{.Title}}</title> |
| 43 | <link rel="stylesheet" href="{{.Asset "css/tokens.css"}}"> |
| 44 | <link rel="stylesheet" href="{{.Asset (print "css/themes/" .Theme ".css")}}"> |
| 45 | <link rel="stylesheet" href="{{.Asset "css/shell.css"}}"> |
| 46 | <link rel="stylesheet" href="{{.Asset "gallery.css"}}"> |
| 47 | <script src="{{.Asset "gallery.js"}}"></script> |
| 48 | {{range .Scripts}}<script defer src="{{$.Asset (print "js/" .)}}"></script> |
| 49 | {{end}}<script defer blocking="render" src="{{.Asset "js/shell.js"}}"></script> |
| 50 | </head> |
| 51 | <body> |
| 52 | <div rst-shell-sidebar="{{if .Rows}}index{{else}}page{{end}}"> |
| 53 | <a rst-skip href="#main">{{say "gallery.skip"}}</a> |
| 54 | {{with .Up}}<div rst-shell-back><a data-gallery-nav href="{{.}}" rel="up" aria-label="{{say "gallery.up" "name" (say "gallery.up.label")}}">{{say "gallery.up.label"}}</a>{{template "ds-prefs" $.Bar}}</div> |
| 55 | {{end}}<aside class="ds-rail" rst-shell-rail> |
| 56 | {{if .Rows}}<h1 rst-shell-title><span></span><span>{{say "gallery.brand"}}</span></h1> |
| 57 | {{template "ds-prefs" .Bar}} |
| 58 | <p class="ds-index-lead">{{say "gallery.overview.intro"}}</p> |
| 59 | {{end}} <search class="ds-search"> |
| 60 | <label class="rst-sr-only" for="ds-filter">{{say "gallery.filter"}}</label> |
| 61 | {{icon "search"}}<input id="ds-filter" type="search" placeholder="{{say "gallery.filter"}}" autocomplete="off" aria-controls="ds-nav" data-ds-filter> |
| 62 | </search> |
| 63 | <p class="ds-nav__empty" data-ds-filter-empty role="status" hidden>{{say "gallery.filter.empty"}}</p> |
| 64 | {{if .Rows}} <nav class="ds-index" rst-shell-nav aria-label="{{say "gallery.up.label"}}">{{range .Rows}}<a id="{{.ID}}" data-gallery-nav href="{{.Href}}">{{.Title}}</a>{{end}}<p rst-shell-group>{{.Demos.Title}}</p>{{range .Demos.Items}}<a data-gallery-nav href="{{.Href}}" target="_blank" rel="noopener">{{.Label}}<span class="rst-sr-only"> ({{say "gallery.newtab"}})</span></a>{{end}}</nav> |
| 65 | {{end}} <nav class="ds-nav" rst-shell-nav id="ds-nav" aria-label="{{say "gallery.nav.sections"}}"> |
| 66 | {{range .Nav}}{{if .Items}} <details{{if .Current}} open aria-current="page"{{end}}><summary><span rst-caret aria-hidden="true">{{icon "chevron-down"}}</span>{{.Title}}</summary>{{range .Items}}<a data-gallery-nav href="{{.Href}}"{{if .Current}} aria-current="page"{{end}}{{if .Aria}} aria-label="{{.Aria}}"{{end}}{{if .Code}} class="rst-mono"{{end}}{{if .Blank}} target="_blank" rel="noopener"{{end}}{{if .Terms}} data-ds-terms="{{.Terms}}"{{end}}>{{.Label}}{{if .Blank}}<span class="rst-sr-only"> ({{say "gallery.newtab"}})</span>{{end}}</a>{{end}}</details> |
| 67 | {{else}} <a class="ds-nav__page" data-gallery-nav href="{{.Href}}"{{if .Current}} aria-current="page"{{end}}>{{.Title}}</a> |
| 68 | {{end}}{{end}} </nav> |
| 69 | </aside> |
| 70 | <header class="ds-top"> |
| 71 | <a class="ds-top__brand" data-gallery-nav href="{{.Home}}">{{say "gallery.brand"}}</a> |
| 72 | <div class="ds-top__controls">{{template "ds-controls" .Bar}}</div> |
| 73 | </header> |
| 74 | <main rst-shell-main id="main"> |
| 75 | <div rst-page> |
| 76 | <header rst-page-header><div rst-page-header-titles><h1{{with .TitleID}} id="{{.}}"{{end}}{{if .Mono}} class="rst-mono"{{end}}>{{.Name}}</h1></div></header> |
| 77 | {{.Body}} |
| 78 | <nav class="ds-updown" aria-label="{{say "gallery.steps.label"}}">{{with .Prev}}<a class="ds-updown__prev" data-gallery-nav href="{{.Href}}">{{.Label}}</a>{{end}}{{with .Next}}<a class="ds-updown__next" data-gallery-nav href="{{.Href}}">{{.Label}}</a>{{end}}</nav> |
| 79 | <p class="rst-sr-only" role="status" data-ds-copy-status data-copy="{{say "gallery.copy"}}" data-copied="{{say "gallery.copied"}}" data-failed="{{say "gallery.copy.failed"}}" data-join=", "></p> |
| 80 | </div> |
| 81 | </main> |
| 82 | </div> |
| 83 | </body> |
| 84 | </html> |
| 85 | {{end}}` |
| 86 | |
| 87 | // cogIcon is the display settings button's glyph, Lucide's settings |
| 88 | // (ISC, as the icon set), drawn the way the set draws its own. Fiesta's |
| 89 | // icons/ has no settings glyph and is frozen, and this one button is |
| 90 | // the gallery's furniture, not something an app is offered, so it is |
| 91 | // drawn here rather than given a slug. aria-hidden: the button's name |
| 92 | // is its aria-label. |
| 93 | const cogIcon = `<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">` + |
| 94 | `<path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg>` |
| 95 | |
| 96 | func init() { registerTemplate(pageTemplate) } |
| 97 | |