Skip to content

Commit c7bc5b4

Browse files
committed
Add mobile responsiveness, light/dark mode, and theme toggle
- Add responsive styles at 640px breakpoint for all sections - Extract all hardcoded colors into CSS variables for theming - Add light mode via prefers-color-scheme with adapted colors - Add nav toggle button (sun/moon) with localStorage persistence - Blocking script in head prevents flash of wrong theme
1 parent 591f1d8 commit c7bc5b4

1 file changed

Lines changed: 120 additions & 30 deletions

File tree

index.html

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,51 @@
77
<meta name="description" content="Train, run, and serve ML models in your Go application. 245 tok/s on Gemma 3 1B — 20% faster than Ollama. Pure Go, zero CGo.">
88
<meta name="theme-color" content="#8B5CF6">
99
<link rel="icon" href="zerfoo.svg" type="image/svg+xml">
10+
<script>(function(){var t=localStorage.getItem('theme');if(t)document.documentElement.classList.add(t)})()</script>
1011
<style>
1112
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
1213
:root{
1314
--purple:#8B5CF6;--blue:#3B82F6;--cyan:#06B6D4;
1415
--bg:#0B0F1A;--bg2:#111827;--bg3:#1F2937;
1516
--fg:#F9FAFB;--fg2:#D1D5DB;--fg3:#9CA3AF;
17+
--border:rgba(255,255,255,.06);--border-hover:rgba(139,92,246,.3);--border-hover-blue:rgba(59,130,246,.3);--border-hover-cyan:rgba(6,182,212,.3);
18+
--nav-bg:rgba(11,15,26,.85);
19+
--gh-btn-hover:#374151;
20+
--bar-muted:var(--bg3);
21+
--bench-note-bg:var(--bg);
22+
--purple-subtle:rgba(139,92,246,.12);--purple-code:rgba(139,92,246,.1);--purple-glow:rgba(139,92,246,.3);--purple-glow-hover:rgba(139,92,246,.45);--purple-tag:rgba(139,92,246,.15);
23+
--syn-kw:#C084FC;--syn-fn:#60A5FA;--syn-str:#34D399;--syn-cmt:#6B7280;--syn-type:#F472B6;--syn-num:#FBBF24;
1624
--grad:linear-gradient(135deg,var(--purple),var(--blue),var(--cyan));
1725
--mono:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;
1826
--sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
1927
--max:1120px;
2028
}
29+
@media(prefers-color-scheme:light){
30+
:root:not(.dark){
31+
--purple:#7C3AED;--blue:#2563EB;--cyan:#0891B2;
32+
--bg:#FFFFFF;--bg2:#F3F4F6;--bg3:#E5E7EB;
33+
--fg:#111827;--fg2:#374151;--fg3:#6B7280;
34+
--border:rgba(0,0,0,.08);--border-hover:rgba(124,58,237,.2);--border-hover-blue:rgba(37,99,235,.2);--border-hover-cyan:rgba(8,145,178,.2);
35+
--nav-bg:rgba(255,255,255,.85);
36+
--gh-btn-hover:#D1D5DB;
37+
--bar-muted:var(--bg3);
38+
--bench-note-bg:var(--bg2);
39+
--purple-subtle:rgba(124,58,237,.08);--purple-code:rgba(124,58,237,.08);--purple-glow:rgba(124,58,237,.2);--purple-glow-hover:rgba(124,58,237,.3);--purple-tag:rgba(124,58,237,.1);
40+
--syn-kw:#7C3AED;--syn-fn:#2563EB;--syn-str:#059669;--syn-cmt:#9CA3AF;--syn-type:#DB2777;--syn-num:#D97706;
41+
}
42+
}
43+
:root.light{
44+
--purple:#7C3AED;--blue:#2563EB;--cyan:#0891B2;
45+
--bg:#FFFFFF;--bg2:#F3F4F6;--bg3:#E5E7EB;
46+
--fg:#111827;--fg2:#374151;--fg3:#6B7280;
47+
--border:rgba(0,0,0,.08);--border-hover:rgba(124,58,237,.2);--border-hover-blue:rgba(37,99,235,.2);--border-hover-cyan:rgba(8,145,178,.2);
48+
--nav-bg:rgba(255,255,255,.85);
49+
--gh-btn-hover:#D1D5DB;
50+
--bar-muted:var(--bg3);
51+
--bench-note-bg:var(--bg2);
52+
--purple-subtle:rgba(124,58,237,.08);--purple-code:rgba(124,58,237,.08);--purple-glow:rgba(124,58,237,.2);--purple-glow-hover:rgba(124,58,237,.3);--purple-tag:rgba(124,58,237,.1);
53+
--syn-kw:#7C3AED;--syn-fn:#2563EB;--syn-str:#059669;--syn-cmt:#9CA3AF;--syn-type:#DB2777;--syn-num:#D97706;
54+
}
2155
html{scroll-behavior:smooth;font-size:16px}
2256
body{background:var(--bg);color:var(--fg);font-family:var(--sans);line-height:1.6;-webkit-font-smoothing:antialiased}
2357
a{color:var(--blue);text-decoration:none;transition:color .15s}
@@ -30,22 +64,33 @@
3064
@media(max-width:768px){section{padding:56px 0}}
3165

3266
/* Nav */
33-
nav{position:sticky;top:0;z-index:100;background:rgba(11,15,26,.85);backdrop-filter:blur(12px);border-bottom:1px solid rgba(255,255,255,.06)}
67+
nav{position:sticky;top:0;z-index:100;background:var(--nav-bg);backdrop-filter:blur(12px);border-bottom:1px solid var(--border)}
3468
nav .wrap{display:flex;align-items:center;justify-content:space-between;height:64px}
3569
nav .logo{display:flex;align-items:center;gap:10px;font-weight:700;font-size:1.125rem;color:var(--fg)}
3670
nav .logo img{width:32px;height:32px}
3771
nav .links{display:flex;gap:24px;font-size:.875rem;align-items:center}
3872
nav .links a{color:var(--fg2)}
3973
nav .links a:hover{color:var(--fg)}
4074
.gh-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;border-radius:6px;background:var(--bg3);color:var(--fg)!important;font-size:.8125rem;font-weight:500;transition:background .15s}
41-
.gh-btn:hover{background:#374151}
75+
.gh-btn:hover{background:var(--gh-btn-hover)}
4276
.gh-btn svg{width:16px;height:16px;fill:currentColor}
4377

78+
.theme-toggle{background:none;border:none;color:var(--fg2);cursor:pointer;padding:4px;display:flex;align-items:center;transition:color .15s}
79+
.theme-toggle:hover{color:var(--fg)}
80+
.theme-toggle svg{width:18px;height:18px}
81+
.theme-toggle .icon-sun{display:none}
82+
.light .theme-toggle .icon-sun,.dark .theme-toggle .icon-sun{display:block}
83+
.light .theme-toggle .icon-moon,.dark .theme-toggle .icon-moon{display:none}
84+
@media(prefers-color-scheme:light){
85+
:root:not(.dark) .theme-toggle .icon-sun{display:block}
86+
:root:not(.dark) .theme-toggle .icon-moon{display:none}
87+
}
88+
4489
/* Mobile nav */
4590
.nav-toggle{display:none;background:none;border:none;color:var(--fg);cursor:pointer;padding:4px}
4691
@media(max-width:640px){
4792
.nav-toggle{display:block}
48-
nav .links{display:none;position:absolute;top:64px;left:0;right:0;flex-direction:column;background:var(--bg2);padding:16px 24px;gap:16px;border-bottom:1px solid rgba(255,255,255,.06)}
93+
nav .links{display:none;position:absolute;top:64px;left:0;right:0;flex-direction:column;background:var(--bg2);padding:16px 24px;gap:16px;border-bottom:1px solid var(--border)}
4994
nav .links.open{display:flex}
5095
}
5196

@@ -63,14 +108,14 @@
63108
.hero .actions{display:flex;justify-content:center;gap:12px;flex-wrap:wrap}
64109
.btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:8px;font-weight:600;font-size:.9375rem;transition:transform .15s,box-shadow .15s}
65110
.btn:hover{transform:translateY(-1px)}
66-
.btn-primary{background:var(--grad);color:#fff;box-shadow:0 4px 24px rgba(139,92,246,.3)}
67-
.btn-primary:hover{box-shadow:0 6px 32px rgba(139,92,246,.45);color:#fff}
111+
.btn-primary{background:var(--grad);color:#fff;box-shadow:0 4px 24px var(--purple-glow)}
112+
.btn-primary:hover{box-shadow:0 6px 32px var(--purple-glow-hover);color:#fff}
68113
.btn-secondary{background:var(--bg3);color:var(--fg)}
69-
.btn-secondary:hover{background:#374151;color:var(--fg)}
114+
.btn-secondary:hover{background:var(--gh-btn-hover);color:var(--fg)}
70115

71116
/* Install bar */
72117
.install{display:flex;justify-content:center;margin-top:32px}
73-
.install-bar{display:inline-flex;align-items:center;gap:12px;background:var(--bg2);border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:10px 20px;font-family:var(--mono);font-size:.875rem;color:var(--fg2)}
118+
.install-bar{display:inline-flex;align-items:center;gap:12px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:10px 20px;font-family:var(--mono);font-size:.875rem;color:var(--fg2)}
74119
.install-bar .dollar{color:var(--fg3);user-select:none}
75120
.install-bar button{background:none;border:none;color:var(--fg3);cursor:pointer;padding:4px;transition:color .15s}
76121
.install-bar button:hover{color:var(--fg)}
@@ -79,82 +124,108 @@
79124
.code-section{background:var(--bg2)}
80125
.code-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:24px}
81126
@media(max-width:480px){.code-grid{grid-template-columns:1fr}}
82-
.code-card{background:var(--bg);border:1px solid rgba(255,255,255,.06);border-radius:12px;overflow:hidden}
83-
.code-card .card-head{padding:16px 20px;border-bottom:1px solid rgba(255,255,255,.06);display:flex;align-items:center;gap:8px}
127+
.code-card{background:var(--bg);border:1px solid var(--border);border-radius:12px;overflow:hidden}
128+
.code-card .card-head{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}
84129
.code-card .card-head .dot{width:8px;height:8px;border-radius:50%}
85130
.code-card .card-head .dot:nth-child(1){background:#EF4444}
86131
.code-card .card-head .dot:nth-child(2){background:#EAB308}
87132
.code-card .card-head .dot:nth-child(3){background:#22C55E}
88133
.code-card .card-head span:last-child{margin-left:8px;font-size:.75rem;color:var(--fg3);font-family:var(--mono)}
89134
pre{margin:0;padding:20px;overflow-x:auto;font-family:var(--mono);font-size:.8125rem;line-height:1.7;color:var(--fg2)}
90-
pre .kw{color:#C084FC}
91-
pre .fn{color:#60A5FA}
92-
pre .str{color:#34D399}
93-
pre .cmt{color:#6B7280}
94-
pre .type{color:#F472B6}
95-
pre .num{color:#FBBF24}
135+
pre .kw{color:var(--syn-kw)}
136+
pre .fn{color:var(--syn-fn)}
137+
pre .str{color:var(--syn-str)}
138+
pre .cmt{color:var(--syn-cmt)}
139+
pre .type{color:var(--syn-type)}
140+
pre .num{color:var(--syn-num)}
96141

97142
/* Features */
98143
.features{background:var(--bg)}
99144
.section-head{text-align:center;margin-bottom:56px}
100145
.section-head h2{font-size:clamp(1.5rem,3.5vw,2.25rem);font-weight:700;margin-bottom:12px}
101146
.section-head p{color:var(--fg2);max-width:560px;margin:0 auto;font-size:1.0625rem}
102147
.feat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px}
103-
.feat{background:var(--bg2);border:1px solid rgba(255,255,255,.06);border-radius:12px;padding:28px 24px;transition:border-color .2s}
104-
.feat:hover{border-color:rgba(139,92,246,.3)}
105-
.feat .icon{width:40px;height:40px;border-radius:10px;background:rgba(139,92,246,.12);display:flex;align-items:center;justify-content:center;margin-bottom:16px;font-size:1.25rem}
148+
.feat{background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:28px 24px;transition:border-color .2s}
149+
.feat:hover{border-color:var(--border-hover)}
150+
.feat .icon{width:40px;height:40px;border-radius:10px;background:var(--purple-subtle);display:flex;align-items:center;justify-content:center;margin-bottom:16px;font-size:1.25rem}
106151
.feat h3{font-size:1.0625rem;font-weight:600;margin-bottom:8px}
107152
.feat p{color:var(--fg3);font-size:.875rem;line-height:1.6}
108-
.feat code{background:rgba(139,92,246,.1);padding:2px 6px;border-radius:4px;font-size:.8125rem;font-family:var(--mono)}
153+
.feat code{background:var(--purple-code);padding:2px 6px;border-radius:4px;font-size:.8125rem;font-family:var(--mono)}
109154

110155
/* Benchmarks */
111156
.bench{background:var(--bg2)}
112157
.bench-table{width:100%;border-collapse:collapse;margin-top:8px;font-size:.875rem}
113-
.bench-table th,.bench-table td{text-align:left;padding:12px 16px;border-bottom:1px solid rgba(255,255,255,.06)}
158+
.bench-table th,.bench-table td{text-align:left;padding:12px 16px;border-bottom:1px solid var(--border)}
114159
.bench-table th{color:var(--fg3);font-weight:500;font-size:.75rem;text-transform:uppercase;letter-spacing:.05em}
115160
.bench-table td{color:var(--fg2)}
116161
.bench-table .highlight{color:var(--fg);font-weight:600}
117162
.bench-bar{display:flex;align-items:center;gap:12px}
118163
.bench-bar .bar{height:8px;border-radius:4px;background:var(--grad)}
119164
.bench-bar .val{font-size:.8125rem;font-weight:600;color:var(--fg);min-width:72px}
120-
.bench-note{margin-top:24px;padding:16px 20px;background:var(--bg);border-radius:8px;font-size:.8125rem;color:var(--fg3);border-left:3px solid var(--purple)}
165+
.bench-note{margin-top:24px;padding:16px 20px;background:var(--bench-note-bg);border-radius:8px;font-size:.8125rem;color:var(--fg3);border-left:3px solid var(--purple)}
121166

122167
/* Models */
123168
.models{background:var(--bg)}
124169
.model-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px}
125-
.model-card{background:var(--bg2);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:20px 16px;text-align:center;transition:border-color .2s}
126-
.model-card:hover{border-color:rgba(59,130,246,.3)}
170+
.model-card{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:20px 16px;text-align:center;transition:border-color .2s}
171+
.model-card:hover{border-color:var(--border-hover-blue)}
127172
.model-card .name{font-weight:600;font-size:.9375rem;margin-bottom:4px}
128173
.model-card .status{font-size:.75rem;color:var(--fg3)}
129174
.model-card .status.prod{color:#34D399}
130175

131176
/* Blog */
132177
.blog{background:var(--bg2)}
133178
.blog-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px}
134-
.blog-card{display:block;background:var(--bg);border:1px solid rgba(255,255,255,.06);border-radius:12px;padding:28px 24px;transition:border-color .2s,transform .2s}
135-
.blog-card:hover{border-color:rgba(59,130,246,.3);transform:translateY(-2px)}
136-
.blog-card .tag{display:inline-block;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:3px 8px;border-radius:4px;background:rgba(139,92,246,.15);color:var(--purple);margin-bottom:12px}
179+
.blog-card{display:block;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:28px 24px;transition:border-color .2s,transform .2s}
180+
.blog-card:hover{border-color:var(--border-hover-blue);transform:translateY(-2px)}
181+
.blog-card .tag{display:inline-block;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:3px 8px;border-radius:4px;background:var(--purple-tag);color:var(--purple);margin-bottom:12px}
137182
.blog-card h3{font-size:1rem;font-weight:600;margin-bottom:8px;color:var(--fg)}
138183
.blog-card p{color:var(--fg3);font-size:.8125rem;line-height:1.6}
139184

140185
/* Ecosystem */
141186
.eco{background:var(--bg)}
142187
.eco-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
143-
@media(max-width:768px){.eco-grid{grid-template-columns:1fr}}
144-
.eco-card{display:block;background:var(--bg2);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:24px 20px;transition:border-color .2s}
145-
.eco-card:hover{border-color:rgba(6,182,212,.3)}
188+
@media(max-width:768px){.eco-grid{grid-template-columns:1fr}.feat-grid{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}}
189+
.eco-card{display:block;background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:24px 20px;transition:border-color .2s}
190+
.eco-card:hover{border-color:var(--border-hover-cyan)}
146191
.eco-card .mod{font-family:var(--mono);font-size:.8125rem;color:var(--cyan);margin-bottom:8px}
147192
.eco-card h3{font-size:.9375rem;font-weight:600;margin-bottom:6px;color:var(--fg)}
148193
.eco-card p{color:var(--fg3);font-size:.8125rem;line-height:1.5}
149194

150195
/* Footer */
151-
footer{border-top:1px solid rgba(255,255,255,.06);padding:40px 0}
196+
footer{border-top:1px solid var(--border);padding:40px 0}
152197
footer .wrap{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:16px}
153198
footer .left{display:flex;align-items:center;gap:8px;font-size:.8125rem;color:var(--fg3)}
154199
footer .left img{width:20px;height:20px;opacity:.5}
155200
footer .right{display:flex;gap:20px;font-size:.8125rem}
156201
footer .right a{color:var(--fg3)}
157202
footer .right a:hover{color:var(--fg)}
203+
204+
/* Mobile responsive */
205+
@media(max-width:640px){
206+
.wrap{padding:0 16px}
207+
.hero h1{font-size:1.75rem}
208+
.hero .sub{font-size:.9375rem}
209+
.hero .stats{gap:20px}
210+
.hero .stat .num{font-size:1.25rem}
211+
.hero .actions{flex-direction:column;align-items:center}
212+
.btn{width:100%;max-width:320px;justify-content:center}
213+
.install-bar{font-size:.75rem;padding:8px 14px;gap:8px;max-width:100%;overflow-x:auto}
214+
.section-head{margin-bottom:36px}
215+
.section-head h2{font-size:1.375rem}
216+
.section-head p{font-size:.9375rem}
217+
.feat-grid{grid-template-columns:1fr}
218+
.code-grid{grid-template-columns:1fr}
219+
pre{font-size:.75rem;padding:14px}
220+
.bench-table{font-size:.75rem}
221+
.bench-table th,.bench-table td{padding:8px 10px}
222+
.bench-bar .val{font-size:.75rem;min-width:56px}
223+
.model-grid{grid-template-columns:repeat(2,1fr)}
224+
.blog-grid{grid-template-columns:1fr}
225+
footer .wrap{flex-direction:column;text-align:center}
226+
footer .left{flex-direction:column}
227+
footer .right{justify-content:center}
228+
}
158229
</style>
159230
</head>
160231
<body>
@@ -172,6 +243,10 @@
172243
<a href="#models">Models</a>
173244
<a href="#blog">Blog</a>
174245
<a href="https://pkg.go.dev/github.com/zerfoo/zerfoo" target="_blank">Docs</a>
246+
<button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle theme">
247+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
248+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
249+
</button>
175250
<a href="https://github.com/zerfoo/zerfoo" target="_blank" class="gh-btn">
176251
<svg viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
177252
GitHub
@@ -550,5 +625,20 @@ <h2 style="font-size:clamp(1.5rem,3.5vw,2.25rem);font-weight:700;margin-bottom:1
550625
</div>
551626
</footer>
552627

628+
<script>
629+
function toggleTheme(){
630+
var r=document.documentElement;
631+
var isDark=r.classList.contains('dark');
632+
var isLight=r.classList.contains('light');
633+
if(isDark){r.classList.remove('dark');r.classList.add('light');localStorage.setItem('theme','light')}
634+
else if(isLight){r.classList.remove('light');r.classList.add('dark');localStorage.setItem('theme','dark')}
635+
else{
636+
// No manual override yet — toggle from system default
637+
var sysLight=window.matchMedia('(prefers-color-scheme:light)').matches;
638+
if(sysLight){r.classList.add('dark');localStorage.setItem('theme','dark')}
639+
else{r.classList.add('light');localStorage.setItem('theme','light')}
640+
}
641+
}
642+
</script>
553643
</body>
554644
</html>

0 commit comments

Comments
 (0)