Skip to content

Commit f737d4f

Browse files
committed
feat: mobile menu + wpt metrics update
1 parent f1b1316 commit f737d4f

File tree

3 files changed

+215
-3
lines changed

3 files changed

+215
-3
lines changed

components/NavBar.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GithubIcon } from "lucide-preact";
22
import PWAStatus from "../islands/PWAStatus.tsx";
33
import SearchTrigger from "../islands/SearchTrigger.tsx";
4+
import MobileMenu from "../islands/MobileMenu.tsx";
45

56
export default function NavBar() {
67
return (
@@ -83,9 +84,10 @@ export default function NavBar() {
8384
</svg>
8485
</a>
8586
</div>
86-
{/* Mobile menu - show search and GitHub only */}
87+
{/* Mobile menu - show search, hamburger menu and social icons */}
8788
<div class="flex md:hidden items-center space-x-2">
8889
<SearchTrigger variant="navbar" />
90+
<MobileMenu />
8991
<a
9092
href="https://github.com/tryandromeda/andromeda"
9193
class="bg-surface0 hover:bg-surface1 text-text rounded-lg p-2 transition-all duration-200 border border-surface2"

islands/MobileMenu.tsx

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// deno-lint-ignore-file no-window
2+
import { useEffect, useRef, useState } from "preact/hooks";
3+
import { BookOpen, Code, Menu, Newspaper, Satellite, X } from "lucide-preact";
4+
5+
interface NavLink {
6+
href: string;
7+
label: string;
8+
icon: any;
9+
color: string;
10+
hoverBg: string;
11+
}
12+
13+
export default function MobileMenu() {
14+
const [isOpen, setIsOpen] = useState(false);
15+
const menuRef = useRef<HTMLDivElement>(null);
16+
17+
const navLinks: NavLink[] = [
18+
{
19+
href: "/docs/index",
20+
label: "Documentation",
21+
icon: BookOpen,
22+
color: "text-green",
23+
hoverBg: "hover:bg-green/10",
24+
},
25+
{
26+
href: "/satellites",
27+
label: "Satellites",
28+
icon: Satellite,
29+
color: "text-blue",
30+
hoverBg: "hover:bg-blue/10",
31+
},
32+
{
33+
href: "/blog",
34+
label: "Blog",
35+
icon: Newspaper,
36+
color: "text-yellow",
37+
hoverBg: "hover:bg-yellow/10",
38+
},
39+
{
40+
href: "/std",
41+
label: "Standard Library",
42+
icon: Code,
43+
color: "text-mauve",
44+
hoverBg: "hover:bg-mauve/10",
45+
},
46+
];
47+
48+
const handleOpen = () => {
49+
setIsOpen(true);
50+
};
51+
52+
const handleClose = () => {
53+
setIsOpen(false);
54+
};
55+
56+
useEffect(() => {
57+
const handleEscape = (e: KeyboardEvent) => {
58+
if (e.key === "Escape" && isOpen) {
59+
handleClose();
60+
}
61+
};
62+
63+
const handleClickOutside = (e: MouseEvent) => {
64+
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
65+
handleClose();
66+
}
67+
};
68+
69+
if (isOpen) {
70+
document.addEventListener("keydown", handleEscape);
71+
document.addEventListener("mousedown", handleClickOutside);
72+
document.body.style.overflow = "hidden";
73+
}
74+
75+
return () => {
76+
document.removeEventListener("keydown", handleEscape);
77+
document.removeEventListener("mousedown", handleClickOutside);
78+
document.body.style.overflow = "";
79+
};
80+
}, [isOpen]);
81+
82+
83+
return (
84+
<>
85+
{/* Mobile Menu Button - Only visible on mobile */}
86+
<button
87+
type="button"
88+
onClick={handleOpen}
89+
class="md:hidden bg-surface0 hover:bg-surface1 text-text rounded-lg p-2 transition-all duration-200 border border-surface2"
90+
aria-label="Open menu"
91+
>
92+
<Menu class="w-4 h-4" />
93+
</button>
94+
95+
{/* Mobile Menu Modal */}
96+
{isOpen && (
97+
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-start justify-center pt-20 px-4 md:hidden">
98+
<div
99+
ref={menuRef}
100+
class="w-full max-w-md bg-base rounded-2xl shadow-2xl border border-surface1 overflow-hidden"
101+
>
102+
{/* Header */}
103+
<div class="flex items-center justify-between p-4 border-b border-surface1">
104+
<div class="flex items-center gap-2">
105+
<Menu size={20} class="text-subtext1" />
106+
<span class="text-lg font-semibold text-text">Menu</span>
107+
</div>
108+
<button
109+
type="button"
110+
onClick={handleClose}
111+
class="text-subtext1 hover:text-text transition-colors p-2 hover:bg-surface0 rounded-lg"
112+
aria-label="Close menu"
113+
>
114+
<X size={20} />
115+
</button>
116+
</div>
117+
118+
{/* Menu Items */}
119+
<div class="p-2">
120+
{navLinks.map((link) => {
121+
const IconComponent = link.icon;
122+
return (
123+
<a
124+
key={link.href}
125+
href={link.href}
126+
class={`flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-200 ${link.hoverBg} group`}
127+
>
128+
<div class={`${link.color} transition-transform group-hover:scale-110`}>
129+
<IconComponent size={20} />
130+
</div>
131+
<span class="text-text font-medium group-hover:text-text transition-colors">
132+
{link.label}
133+
</span>
134+
</a>
135+
);
136+
})}
137+
</div>
138+
139+
{/* Footer with social links */}
140+
<div class="border-t border-surface1 p-4">
141+
<div class="flex items-center justify-center gap-3">
142+
<a
143+
href="https://github.com/tryandromeda/andromeda"
144+
class="flex items-center gap-2 px-4 py-2 bg-surface0 hover:bg-surface1 rounded-lg transition-all duration-200 border border-surface2 hover:border-blue"
145+
aria-label="GitHub"
146+
>
147+
<svg
148+
xmlns="http://www.w3.org/2000/svg"
149+
class="w-5 h-5"
150+
viewBox="0 0 24 24"
151+
fill="none"
152+
stroke="currentColor"
153+
stroke-width="2"
154+
stroke-linecap="round"
155+
stroke-linejoin="round"
156+
>
157+
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" />
158+
<path d="M9 18c-4.51 2-5-2-7-2" />
159+
</svg>
160+
<span class="text-sm font-medium">GitHub</span>
161+
</a>
162+
<a
163+
href="https://discord.gg/tgjAnX2Ny3"
164+
class="flex items-center gap-2 px-4 py-2 bg-surface0 hover:bg-surface1 rounded-lg transition-all duration-200 border border-surface2 hover:border-mauve"
165+
aria-label="Discord"
166+
>
167+
<svg
168+
xmlns="http://www.w3.org/2000/svg"
169+
class="w-5 h-5"
170+
viewBox="0 0 16 16"
171+
>
172+
<path
173+
fill="currentColor"
174+
d="M9 8.5c0 .826.615 1.5 1.36 1.5c.762 0 1.35-.671 1.36-1.5S11.125 7 10.36 7C9.592 7 9 7.677 9 8.5M5.63 10c-.747 0-1.36-.671-1.36-1.5S4.866 7 5.63 7S7.01 7.677 7 8.5c-.013.826-.602 1.5-1.36 1.5z"
175+
/>
176+
<path
177+
fill="currentColor"
178+
fill-rule="evenodd"
179+
d="M13.3 2.72a1 1 0 0 1 .41.342c1.71 2.47 2.57 5.29 2.25 8.53a1 1 0 0 1-.405.71c-1.16.851-2.47 1.5-3.85 1.91a.99.99 0 0 1-1.08-.357a10 10 0 0 1-.665-1.01a9.4 9.4 0 0 1-3.87 0a9 9 0 0 1-.664 1.01a1 1 0 0 1-1.09.357a12.8 12.8 0 0 1-3.85-1.91a1 1 0 0 1-.405-.711c-.269-2.79.277-5.64 2.25-8.52c.103-.151.246-.271.413-.347c.999-.452 2.05-.774 3.14-.957c.415-.07.83.128 1.04.494l.089.161q1.01-.087 2.03 0l.088-.161a1 1 0 0 1 1.04-.494c1.08.181 2.14.502 3.14.955zm-3.67.776a11 11 0 0 0-3.21 0a8 8 0 0 0-.37-.744c-.998.168-1.97.465-2.89.882c-1.83 2.68-2.32 5.29-2.08 7.86c1.07.783 2.27 1.38 3.54 1.76a8 8 0 0 0 .461-.681q.158-.26.297-.53a7.5 7.5 0 0 1-1.195-.565q.15-.109.293-.218a8.5 8.5 0 0 0 1.886.62a8.4 8.4 0 0 0 4.146-.217a8 8 0 0 0 1.04-.404q.144.117.293.218a11 11 0 0 1-.282.157a8 8 0 0 1-.915.41a9 9 0 0 0 .518.872q.117.17.241.337c1.27-.38 2.47-.975 3.54-1.76c.291-2.98-.497-5.57-2.08-7.86c-.92-.417-1.89-.712-2.89-.879q-.204.362-.37.744z"
180+
clip-rule="evenodd"
181+
/>
182+
</svg>
183+
<span class="text-sm font-medium">Discord</span>
184+
</a>
185+
</div>
186+
</div>
187+
</div>
188+
</div>
189+
)}
190+
</>
191+
);
192+
}

islands/WPTMetrics.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,21 @@ export default function WPTMetrics() {
158158
</div>
159159
<div class="text-xs text-subtext1">Pass Rate</div>
160160
</div>
161+
162+
<div class="text-center">
163+
<div class="text-2xl font-bold text-peach mb-1">{overall.crash}</div>
164+
<div class="text-xs text-subtext1">Crash</div>
165+
</div>
166+
167+
<div class="text-center">
168+
<div class="text-2xl font-bold text-blue mb-1">{overall.timeout}</div>
169+
<div class="text-xs text-subtext1">Timeout</div>
170+
</div>
171+
172+
<div class="text-center">
173+
<div class="text-2xl font-bold text-subtext0 mb-1">{overall.skip}</div>
174+
<div class="text-xs text-subtext1">Skip</div>
175+
</div>
161176
</div>
162177

163178
<div>
@@ -173,10 +188,13 @@ export default function WPTMetrics() {
173188
<div class="text-xs text-subtext1">{s.total_tests} tests</div>
174189
</div>
175190

176-
<div class="flex items-center gap-4">
191+
<div class="flex items-center gap-3 flex-wrap">
177192
<div class="text-sm text-green">Pass {s.pass}</div>
178193
<div class="text-sm text-red">Fail {s.fail}</div>
179-
<div class="text-sm text-subtext1">
194+
<div class="text-sm text-peach">Crash {s.crash}</div>
195+
<div class="text-sm text-blue">Timeout {s.timeout}</div>
196+
<div class="text-sm text-subtext0">Skip {s.skip}</div>
197+
<div class="text-sm text-subtext1 font-medium">
180198
{formatPercent(s.pass_rate)}
181199
</div>
182200
</div>

0 commit comments

Comments
 (0)