base.layout.tmpl
1{{define "base"}}
2<!doctype html>
3<html lang="en">
4 <head>
5 <meta charset='utf-8'>
6 <meta name="viewport" content="width=device-width, initial-scale=1" />
7 <title>{{template "title" .}}</title>
8 <meta name="keywords" content="git code forge repo repository" />
9 {{template "meta" .}}
10 <style>
11 /* Critical CSS - inlined to prevent FOUC */
12 :root {
13 --line-height: 1.3rem;
14 --grid-height: 0.65rem;
15 --bg-color: #282a36;
16 --text-color: #f8f8f2;
17 --border: #6272a4;
18 --link-color: #8be9fd;
19 --hover: #ff79c6;
20 --visited: #8be9fd;
21 --white: #f2f2f2;
22 --white-light: #f2f2f2;
23 --white-dark: #e8e8e8;
24 --grey: #414558;
25 --grey-light: #6a708e;
26 --code: #414558;
27 --pre: #252525;
28 --blockquote: #bd93f9;
29 --blockquote-bg: #353548;
30 --text-red: #ff5555;
31 --text-green: #50fa7b;
32 }
33 html {
34 background-color: var(--bg-color);
35 color: var(--text-color);
36 font-size: 16px;
37 line-height: var(--line-height);
38 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
39 -webkit-text-size-adjust: 100%;
40 -moz-tab-size: 4;
41 tab-size: 4;
42 }
43 body {
44 margin: 0 auto;
45 max-width: 900px;
46 }
47 *, ::before, ::after { box-sizing: border-box; }
48 </style>
49 <link rel="stylesheet" href="{{.Repo.RootRelative}}{{.Repo.CSSFile}}">
50 </head>
51 <body hx-boost="true" hx-swap="innerHTML transition:true">
52 <header>{{template "header" .}}</header>
53 <main>{{template "content" .}}</main>
54 <hr />
55 <footer>{{template "footer" .}}</footer>
56 <script>
57 (function() {
58 var MINUTE_MS = 60000;
59 var HOUR_MS = 3600000;
60 var DAY_MS = 86400000;
61 var MONTH_MS = 30 * DAY_MS;
62
63 function updateTimes() {
64 var elements = document.querySelectorAll('[data-time]');
65 var now = new Date();
66 var minDiffMs = Infinity;
67
68 elements.forEach(function(el) {
69 var date = new Date(el.getAttribute('data-time'));
70 var diffMs = now - date;
71
72 // Track the smallest difference for interval calculation
73 if (diffMs < minDiffMs && diffMs >= 0) {
74 minDiffMs = diffMs;
75 }
76
77 var diffMins = Math.floor(diffMs / MINUTE_MS);
78 var diffHours = Math.floor(diffMs / HOUR_MS);
79 var diffDays = Math.floor(diffMs / DAY_MS);
80
81 var text;
82 if (diffMins < 1) {
83 text = 'just now';
84 } else if (diffMins < 60) {
85 text = diffMins + ' minute' + (diffMins === 1 ? '' : 's') + ' ago';
86 } else if (diffHours < 24) {
87 text = diffHours + ' hour' + (diffHours === 1 ? '' : 's') + ' ago';
88 } else if (diffDays < 30) {
89 text = diffDays + ' day' + (diffDays === 1 ? '' : 's') + ' ago';
90 } else {
91 // Keep default MMM dd format (already in element text)
92 return;
93 }
94 el.textContent = text;
95 });
96
97 return minDiffMs;
98 }
99
100 function scheduleUpdate() {
101 var minDiffMs = updateTimes();
102 var intervalMs;
103
104 // Determine interval based on smallest time difference
105 if (minDiffMs < HOUR_MS) {
106 // Smallest diff is in minutes - update every minute
107 intervalMs = MINUTE_MS;
108 } else if (minDiffMs < DAY_MS) {
109 // Smallest diff is in hours - update every hour
110 intervalMs = HOUR_MS;
111 } else if (minDiffMs < MONTH_MS) {
112 // Smallest diff is in days - update every day
113 intervalMs = DAY_MS;
114 } else {
115 // All timestamps are > 30 days, no updates needed
116 return;
117 }
118
119 setTimeout(scheduleUpdate, intervalMs);
120 }
121
122 scheduleUpdate();
123 })();
124 </script>
125 <script type="module"
126 src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.esm.min.js"
127 integrity="sha384-PcS7xfab7VmrX3d1pc3sw10FpukcW7k3kZT2sFgm1lti8gAT/ti9n9KEq/qRnfLT"
128 crossorigin="anonymous"></script>
129 </body>
130</html>
131{{end}}