283 lines · 7.2 KB
1 ---
2 interface Props {
3 title: string;
4 }
5
6 const { title } = Astro.props;
7 ---
8 <!DOCTYPE html>
9 <html lang="en">
10 <head>
11 <meta charset="UTF-8" />
12 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
13 <title>{title} - gitfastr</title>
14 <script is:inline>
15 (function(){var t=localStorage.getItem('theme');if(t)document.documentElement.setAttribute('data-theme',t)})();
16 </script>
17 <style is:global>
18 :root, [data-theme="dark"] {
19 /* Surfaces — deep navy-slate with subtle blue undertone */
20 --bg: #0c0e14;
21 --bg-secondary: #13151e;
22 --bg-tertiary: #1c1f2b;
23 --border: #2a2d3a;
24
25 /* Text */
26 --text: #e2e4ed;
27 --text-muted: #7c8097;
28 --text-link: #818cf8;
29
30 /* Actions */
31 --accent: #6366f1;
32 --accent-hover: #818cf8;
33 --danger: #f43f5e;
34
35 /* Diff */
36 --diff-add-bg: rgba(52, 211, 153, 0.1);
37 --diff-add-text: #6ee7b7;
38 --diff-add-badge-bg: rgba(52, 211, 153, 0.2);
39 --diff-del-bg: rgba(244, 63, 94, 0.1);
40 --diff-del-text: #fda4af;
41 --diff-del-badge-bg: rgba(244, 63, 94, 0.2);
42 --diff-mod-text: #fbbf24;
43 --diff-mod-badge-bg: rgba(251, 191, 36, 0.2);
44 --diff-hunk-bg: rgba(129, 140, 248, 0.08);
45 --diff-hunk-text: #818cf8;
46
47 /* State badges */
48 --state-open: #6366f1;
49 --state-merged: #a78bfa;
50 --state-closed: #f43f5e;
51
52 /* Misc */
53 --focus-ring: rgba(99, 102, 241, 0.4);
54 --flash-error-bg: rgba(244, 63, 94, 0.08);
55 --flash-error-text: #fb7185;
56 --success-bg: rgba(52, 211, 153, 0.08);
57 --success-border: #34d399;
58 --success-text: #6ee7b7;
59
60 /* Shared */
61 --font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;
62 --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
63 --radius: 8px;
64 }
65
66 [data-theme="light"] {
67 /* Surfaces — warm off-white with subtle warmth */
68 --bg: #fafaf9;
69 --bg-secondary: #f3f2f0;
70 --bg-tertiary: #eae8e4;
71 --border: #d6d3ce;
72
73 /* Text */
74 --text: #1c1917;
75 --text-muted: #78716c;
76 --text-link: #4f46e5;
77
78 /* Actions */
79 --accent: #4f46e5;
80 --accent-hover: #6366f1;
81 --danger: #e11d48;
82
83 /* Diff */
84 --diff-add-bg: rgba(22, 163, 74, 0.08);
85 --diff-add-text: #15803d;
86 --diff-add-badge-bg: rgba(22, 163, 74, 0.12);
87 --diff-del-bg: rgba(225, 29, 72, 0.06);
88 --diff-del-text: #be123c;
89 --diff-del-badge-bg: rgba(225, 29, 72, 0.1);
90 --diff-mod-text: #a16207;
91 --diff-mod-badge-bg: rgba(161, 98, 7, 0.1);
92 --diff-hunk-bg: rgba(79, 70, 229, 0.05);
93 --diff-hunk-text: #4f46e5;
94
95 /* State badges */
96 --state-open: #4f46e5;
97 --state-merged: #7c3aed;
98 --state-closed: #e11d48;
99
100 /* Misc */
101 --focus-ring: rgba(79, 70, 229, 0.3);
102 --flash-error-bg: rgba(225, 29, 72, 0.06);
103 --flash-error-text: #be123c;
104 --success-bg: rgba(22, 163, 74, 0.06);
105 --success-border: #16a34a;
106 --success-text: #15803d;
107 }
108
109 * { margin: 0; padding: 0; box-sizing: border-box; }
110
111 body {
112 font-family: var(--font-sans);
113 background: var(--bg);
114 color: var(--text);
115 line-height: 1.5;
116 }
117
118 a { color: var(--text-link); text-decoration: none; }
119 a:hover { text-decoration: underline; }
120
121 code, pre {
122 font-family: var(--font-mono);
123 font-size: 0.875rem;
124 }
125
126 .container {
127 max-width: 1012px;
128 margin: 0 auto;
129 padding: 0 16px;
130 }
131
132 /* Navigation */
133 nav.top-nav {
134 background: var(--bg-secondary);
135 border-bottom: 1px solid var(--border);
136 padding: 12px 0;
137 }
138
139 nav.top-nav .nav-inner {
140 display: flex;
141 align-items: center;
142 justify-content: space-between;
143 }
144
145 nav.top-nav .brand {
146 font-size: 1.25rem;
147 font-weight: 600;
148 color: var(--text);
149 }
150
151 nav.top-nav .brand:hover { text-decoration: none; }
152
153 nav.top-nav .nav-links {
154 display: flex;
155 gap: 16px;
156 align-items: center;
157 }
158
159 /* Buttons */
160 .btn {
161 display: inline-flex;
162 align-items: center;
163 padding: 5px 16px;
164 font-size: 0.875rem;
165 font-weight: 500;
166 border-radius: var(--radius);
167 border: 1px solid var(--border);
168 background: var(--bg-tertiary);
169 color: var(--text);
170 cursor: pointer;
171 text-decoration: none;
172 }
173
174 .btn:hover {
175 background: var(--border);
176 text-decoration: none;
177 }
178
179 .btn-primary {
180 background: var(--accent);
181 border-color: var(--accent);
182 color: #fff;
183 }
184
185 .btn-primary:hover {
186 background: var(--accent-hover);
187 }
188
189 /* Forms */
190 .form-group {
191 margin-bottom: 16px;
192 }
193
194 .form-group label {
195 display: block;
196 font-size: 0.875rem;
197 font-weight: 600;
198 margin-bottom: 4px;
199 }
200
201 .form-group input[type="text"],
202 .form-group input[type="email"],
203 .form-group input[type="password"],
204 .form-group textarea {
205 width: 100%;
206 padding: 8px 12px;
207 background: var(--bg);
208 border: 1px solid var(--border);
209 border-radius: var(--radius);
210 color: var(--text);
211 font-size: 0.875rem;
212 }
213
214 .form-group input:focus,
215 .form-group textarea:focus {
216 outline: none;
217 border-color: var(--accent);
218 box-shadow: 0 0 0 3px var(--focus-ring);
219 }
220
221 /* Cards */
222 .card {
223 background: var(--bg-secondary);
224 border: 1px solid var(--border);
225 border-radius: var(--radius);
226 padding: 16px;
227 }
228
229 /* Flash messages */
230 .flash-error {
231 background: var(--flash-error-bg);
232 border: 1px solid var(--danger);
233 color: var(--flash-error-text);
234 padding: 12px;
235 border-radius: var(--radius);
236 margin-bottom: 16px;
237 font-size: 0.875rem;
238 }
239 </style>
240 </head>
241 <body>
242 <nav class="top-nav">
243 <div class="container nav-inner">
244 <a href="/" class="brand">gitfastr</a>
245 <div class="nav-links">
246 <button id="theme-toggle" class="btn" style="padding: 5px 10px; font-size: 1rem; line-height: 1;" aria-label="Toggle theme"></button>
247 <a href="/login" class="btn">Sign in</a>
248 <a href="/register" class="btn btn-primary">Sign up</a>
249 </div>
250 </div>
251 </nav>
252 <main>
253 <slot />
254 </main>
255 <script is:inline>
256 (function() {
257 var saved = localStorage.getItem('theme');
258 var theme = saved || 'dark';
259 document.documentElement.setAttribute('data-theme', theme);
260
261 function updateButton() {
262 var btn = document.getElementById('theme-toggle');
263 if (!btn) return;
264 var current = document.documentElement.getAttribute('data-theme') || 'dark';
265 btn.textContent = current === 'dark' ? '\u2600\uFE0F' : '\uD83C\uDF19';
266 }
267
268 updateButton();
269
270 document.addEventListener('click', function(e) {
271 if (e.target && e.target.id === 'theme-toggle') {
272 var current = document.documentElement.getAttribute('data-theme') || 'dark';
273 var next = current === 'dark' ? 'light' : 'dark';
274 document.documentElement.setAttribute('data-theme', next);
275 localStorage.setItem('theme', next);
276 updateButton();
277 }
278 });
279 })();
280 </script>
281 </body>
282 </html>
283