| 1 | package gallery |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "html/template" |
| 6 | "regexp" |
| 7 | |
| 8 | "amadan.net/rastrillo/fiesta/example" |
| 9 | ) |
| 10 | |
| 11 | // The modal route: the modal idiom at the URL the idiom insists on. |
| 12 | // The modal example's frame shows the markup inside a widget; this is |
| 13 | // the same markup as a page of its own, demo-modal.html (modal.html is |
| 14 | // the modal example's page), linked from the Demos group and from that |
| 15 | // page. |
| 16 | // |
| 17 | // The document is the modal example's own, with Rastrillo's three |
| 18 | // deviations, each the difference between a sample and a page that |
| 19 | // exists: the backdrop holds a real screen (a page header and a box) |
| 20 | // instead of a bare heading, so there is something behind the panel; |
| 21 | // the panel's tabs link this page, so switching one keeps the modal |
| 22 | // open rather than landing on a route this tree does not serve; and |
| 23 | // Close returns to the Overview, since the backdrop's screen has no |
| 24 | // address of its own here, which the panel says. The panel stays a |
| 25 | // <dialog open>, never showModal()'d, as the example is. |
| 26 | // |
| 27 | // It is framed as a sample document is: the gallery's assets, noindex, |
| 28 | // frame.js first so a scheme the reader chose comes with them, and the |
| 29 | // padding rule, which leaves a page with a backdrop unpadded. |
| 30 | |
| 31 | // modalHref is the modal route's address. |
| 32 | func (s *site) modalHref(theme, locale string) string { |
| 33 | return s.href(theme, locale, "demo-modal.html") |
| 34 | } |
| 35 | |
| 36 | var ( |
| 37 | // The example's backdrop, a page with one heading. |
| 38 | modalBackdrop = regexp.MustCompile(`(?s)<div rst-backdrop inert>.*?</div>\s*</div>`) |
| 39 | // The panel's tabs and its section, each rewritten whole. |
| 40 | modalNav = regexp.MustCompile(`(?s)<nav>.*?</nav>`) |
| 41 | modalSection = regexp.MustCompile(`(?s)<section>.*?</section>`) |
| 42 | ) |
| 43 | |
| 44 | // modal builds one theme and locale's modal route. |
| 45 | func (s *site) modal(theme, locale string) ([]byte, error) { |
| 46 | const name = "modal" |
| 47 | e, ok := s.m.Entry(name) |
| 48 | if !ok { |
| 49 | return nil, fmt.Errorf("the manifest has no %s example to build the modal route from", name) |
| 50 | } |
| 51 | doc, err := example.Document(s.src, name, e.Default) |
| 52 | if err != nil { |
| 53 | return nil, err |
| 54 | } |
| 55 | say := func(id string) string { return template.HTMLEscapeString(s.say(locale, id)) } |
| 56 | self := s.modalHref(theme, locale) |
| 57 | overview := s.href(theme, locale, s.fileOf("overview")) |
| 58 | steps := []struct { |
| 59 | what string |
| 60 | re *regexp.Regexp |
| 61 | with string |
| 62 | }{ |
| 63 | {"the title", titleTag, "<title>" + template.HTMLEscapeString(s.say(locale, "gallery.title", "page", s.say(locale, "gallery.demos.modal"), "theme", theme)) + "</title>"}, |
| 64 | {"the backdrop", modalBackdrop, `<div rst-backdrop inert> |
| 65 | <main rst-page id="main"> |
| 66 | <header rst-page-header> |
| 67 | <div rst-page-header-titles> |
| 68 | <h1>` + say("gallery.modal.settings") + `</h1> |
| 69 | <p rst-page-header-sub>` + say("gallery.modal.sub") + `</p> |
| 70 | </div> |
| 71 | </header> |
| 72 | <div rst-box-head><h2>` + say("gallery.modal.account") + `</h2></div> |
| 73 | <section rst-box><p>` + say("gallery.modal.own") + `</p></section> |
| 74 | </main> |
| 75 | </div>`}, |
| 76 | {"the panel's tabs", modalNav, `<nav> |
| 77 | <a data-gallery-nav href="` + self + `" aria-current="page">` + say("gallery.modal.profile") + `</a> |
| 78 | <a data-gallery-nav href="` + self + `">` + say("gallery.modal.billing") + `</a> |
| 79 | <a data-gallery-nav href="` + self + `">` + say("gallery.modal.notifications") + `</a> |
| 80 | </nav>`}, |
| 81 | {"the panel's section", modalSection, `<section> |
| 82 | <a rst-modal-close data-gallery-nav href="` + overview + `" aria-label="` + say("gallery.modal.close") + `">✕</a> |
| 83 | <h2 id="modal-title">` + say("gallery.modal.profile") + `</h2> |
| 84 | <p>` + say("gallery.modal.body") + `</p> |
| 85 | <p>` + say("gallery.modal.nojs") + `</p> |
| 86 | <p>` + say("gallery.modal.inapp") + `</p> |
| 87 | <p><a rst-btn data-gallery-nav href="` + overview + `">` + say("gallery.back") + `</a></p> |
| 88 | </section>`}, |
| 89 | } |
| 90 | for _, step := range steps { |
| 91 | if n := len(step.re.FindAllStringIndex(doc, -1)); n != 1 { |
| 92 | return nil, fmt.Errorf("%s/%s has %d of %s to rewrite, want one", name, e.Default, n, step.what) |
| 93 | } |
| 94 | doc = step.re.ReplaceAllLiteralString(doc, step.with) |
| 95 | } |
| 96 | framed, err := s.framed(doc, theme, locale, e, nil) |
| 97 | if err != nil { |
| 98 | return nil, fmt.Errorf("demo-modal.html: %w", err) |
| 99 | } |
| 100 | return []byte(framed), nil |
| 101 | } |
| 102 | |