base.gohtml (6151B)
1 {{define "base"}}<!DOCTYPE html> 2 <html lang="{{.Lang}}"> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <title>{{.Title}}</title> 7 <link rel="stylesheet" type="text/css" href="{{.StaticPrefix}}demo.css"> 8 {{range .Styles}}<link rel="stylesheet" type="text/css" href="{{$.StaticPrefix}}{{.}}">{{end}} 9 <script> 10 document.addEventListener("DOMContentLoaded", function () { 11 const button = document.getElementById("language-button"); 12 const menu = document.getElementById("language-menu"); 13 function closeMenu() { 14 menu.hidden = true; 15 button.setAttribute("aria-expanded", "false"); 16 } 17 button.addEventListener("click", function (event) { 18 const willOpen = menu.hidden; 19 menu.hidden = !willOpen; 20 button.setAttribute("aria-expanded", String(willOpen)); 21 event.stopPropagation(); 22 }); 23 menu.addEventListener("click", function (event) { event.stopPropagation(); }); 24 document.addEventListener("click", closeMenu); 25 document.addEventListener("keydown", function (event) { 26 if (event.key === "Escape" && !menu.hidden) { 27 closeMenu(); 28 button.focus(); 29 } 30 }); 31 32 const editionInfoButton = document.getElementById("edition-info-button"); 33 const editionInfo = document.getElementById("edition-info"); 34 if (editionInfoButton && editionInfo) { 35 editionInfoButton.addEventListener("click", function () { 36 editionInfo.showModal(); 37 }); 38 editionInfo.addEventListener("click", function (event) { 39 if (event.target !== editionInfo) return; 40 const bounds = editionInfo.getBoundingClientRect(); 41 const inside = event.clientX >= bounds.left && event.clientX <= bounds.right && 42 event.clientY >= bounds.top && event.clientY <= bounds.bottom; 43 if (!inside) editionInfo.close(); 44 }); 45 } 46 47 document.querySelectorAll("[data-copy-value]").forEach(function (copyButton) { 48 copyButton.addEventListener("click", async function () { 49 const value = copyButton.getAttribute("data-copy-value"); 50 const status = document.getElementById(copyButton.getAttribute("aria-describedby")); 51 try { 52 if (navigator.clipboard && window.isSecureContext) { 53 await navigator.clipboard.writeText(value); 54 } else { 55 const input = document.createElement("textarea"); 56 input.value = value; 57 input.setAttribute("readonly", ""); 58 input.style.position = "fixed"; 59 input.style.opacity = "0"; 60 document.body.appendChild(input); 61 input.select(); 62 const copied = document.execCommand("copy"); 63 input.remove(); 64 if (!copied) throw new Error("copy failed"); 65 } 66 status.hidden = false; 67 } catch (error) { 68 window.prompt(copyButton.getAttribute("data-copy-prompt"), value); 69 } 70 }); 71 }); 72 }); 73 </script> 74 </head> 75 <body class="demo-page demo-{{.Active}}"> 76 <a href="#main" class="skip-link">{{tr .Lang "Skip to main content"}}</a> 77 <header class="site-header"> 78 <div class="header-inner"> 79 <div class="heading-lockup"> 80 <a class="taler-brand" href="https://taler.net/"> 81 <picture> 82 <source srcset="{{.StaticPrefix}}taler-logo-dark.svg" media="(prefers-color-scheme: dark)"> 83 {{/* Translators: Alternative text for the GNU Taler brand logo. */}} 84 <img src="{{.StaticPrefix}}taler-logo-light.svg" alt="{{tr .Lang "GNU Taler logo"}}" width="1000" height="448"> 85 </picture> 86 </a> 87 <div class="demo-heading"> 88 <h1><a href="{{.HeaderURL}}">{{.HeaderTitle}}</a></h1> 89 <p>{{.HeaderText}}</p> 90 </div> 91 </div> 92 </div> 93 </header> 94 <div class="nav-shell"> 95 <div class="nav-inner"> 96 <nav class="demo-nav"> 97 {{/* Translators: Name of the introductory demo page, used as a navigation label. */}} 98 <a href="{{.Links.Landing}}" {{if eq .Active "landing"}}class="active" aria-current="page"{{end}}>{{tr .Lang "Introduction"}}</a> 99 {{/* Translators: Navigation label for the demo bank. */}} 100 <a href="{{.Links.Bank}}" {{if eq .Active "bank"}}class="active" aria-current="page"{{end}}>{{tr .Lang "Bank"}}</a> 101 {{/* Translators: Name of the demo shop that sells individual essays. */}} 102 <a href="{{.Links.Blog}}" {{if eq .Active "blog"}}class="active" aria-current="page"{{end}}>{{tr .Lang "Essay Shop"}}</a> 103 {{/* Translators: Name of the donations demo page, used as a navigation label. */}} 104 <a href="{{.Links.Donations}}" {{if eq .Active "donations"}}class="active" aria-current="page"{{end}}>{{tr .Lang "Donations"}}</a> 105 </nav> 106 <div class="language-switcher"> 107 <button class="language-button" id="language-button" type="button" aria-controls="language-menu" aria-expanded="false">{{.LanguageName}}</button> 108 <div class="language-menu" id="language-menu" hidden> 109 {{range .Languages}}{{if ne .Code $.Lang}}<a href="{{$.Prefix}}/{{.Code}}/">{{.Name}}</a>{{end}}{{end}} 110 </div> 111 </div> 112 </div> 113 </div> 114 <main id="main" class="content"> 115 {{template "content" .}} 116 </main> 117 <footer class="site-footer"> 118 <div class="footer-inner"> 119 <p><a href="{{talerURL .Lang}}">{{tr .Lang "Learn more about GNU Taler"}}</a>.</p> 120 <p>Copyright © 2014—2026 Taler Systems SA</p> 121 </div> 122 </footer> 123 </body> 124 </html>{{end}} 125 126 {{define "link-icon"}}<svg class="link-icon" aria-hidden="true" focusable="false" viewBox="0 0 16 16"> 127 <path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5"/> 128 <path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z"/> 129 </svg>{{end}}