Skip to content

Commit 1a3a5e7

Browse files
committed
docs: improve mobile UI
1 parent 85a29f1 commit 1a3a5e7

6 files changed

Lines changed: 185 additions & 28 deletions

File tree

packages/docs/src/components/Header/Header.module.css

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,8 @@
131131
color: var(--color-text);
132132
}
133133

134-
@media (max-width: 768px) {
134+
@media (max-width: 1024px) {
135135
.nav {
136136
display: none;
137137
}
138-
139-
.menuButton {
140-
display: flex;
141-
}
142138
}

packages/docs/src/components/Header/Header.tsx

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import styles from "./Header.module.css";
22

3-
export const Header: React.FC = () => {
3+
interface HeaderProps {
4+
menuSlot?: React.ReactNode;
5+
}
6+
7+
export const Header: React.FC<HeaderProps> = ({ menuSlot }) => {
48
return (
59
<header className={styles.header}>
610
<div className={styles.container}>
@@ -41,24 +45,7 @@ export const Header: React.FC = () => {
4145
</a>
4246
</nav>
4347

44-
<button
45-
className={styles.menuButton}
46-
aria-label="Open menu"
47-
type="button"
48-
>
49-
<svg
50-
width="24"
51-
height="24"
52-
viewBox="0 0 24 24"
53-
fill="none"
54-
stroke="currentColor"
55-
strokeWidth="2"
56-
>
57-
<line x1="3" y1="6" x2="21" y2="6" />
58-
<line x1="3" y1="12" x2="21" y2="12" />
59-
<line x1="3" y1="18" x2="21" y2="18" />
60-
</svg>
61-
</button>
48+
{menuSlot}
6249
</div>
6350
</header>
6451
);

packages/docs/src/components/Layout/Layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type React from "react";
22
import { Header } from "../Header/Header";
3+
import { MobileMenu } from "../MobileMenu/MobileMenu";
34
import { Sidebar } from "../Sidebar/Sidebar";
45
import styles from "./Layout.module.css";
56

@@ -19,7 +20,7 @@ export const Layout: React.FC<LayoutProps> = ({
1920

2021
return (
2122
<div className={`${styles.layout} ${layoutClass}`}>
22-
<Header />
23+
<Header menuSlot={<MobileMenu />} />
2324
<div className={styles.main}>
2425
{variant === "docs" && <Sidebar />}
2526
<main
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
.menuButton {
2+
display: none;
3+
width: 40px;
4+
height: 40px;
5+
align-items: center;
6+
justify-content: center;
7+
border-radius: var(--radius-md);
8+
color: var(--color-text-secondary);
9+
background: none;
10+
border: none;
11+
cursor: pointer;
12+
}
13+
14+
.menuButton:hover {
15+
background-color: var(--color-bg-tertiary);
16+
color: var(--color-text);
17+
}
18+
19+
@media (max-width: 1024px) {
20+
.menuButton {
21+
display: flex;
22+
}
23+
}
24+
25+
.overlay {
26+
position: fixed;
27+
inset: 0;
28+
top: var(--header-height);
29+
background-color: rgba(0, 0, 0, 0.5);
30+
z-index: 40;
31+
}
32+
33+
.sidebar {
34+
position: fixed;
35+
top: var(--header-height);
36+
left: 0;
37+
width: 100%;
38+
max-width: 300px;
39+
height: calc(100vh - var(--header-height));
40+
background-color: var(--color-bg-secondary);
41+
border-right: 1px solid var(--color-border);
42+
overflow-y: auto;
43+
padding: var(--spacing-lg);
44+
z-index: 50;
45+
box-shadow: var(--shadow-xl);
46+
}
47+
48+
.section {
49+
margin-bottom: var(--spacing-xl);
50+
}
51+
52+
.sectionTitle {
53+
font-size: var(--text-xs);
54+
font-weight: 600;
55+
text-transform: uppercase;
56+
letter-spacing: 0.05em;
57+
color: var(--color-text-muted);
58+
margin-bottom: var(--spacing-sm);
59+
padding: 0 var(--spacing-sm);
60+
}
61+
62+
.navList {
63+
display: flex;
64+
flex-direction: column;
65+
gap: var(--spacing-xs);
66+
}
67+
68+
.navItem {
69+
display: block;
70+
padding: var(--spacing-sm) var(--spacing-md);
71+
font-size: var(--text-sm);
72+
color: var(--color-text-secondary);
73+
text-decoration: none;
74+
border-radius: var(--radius-md);
75+
transition:
76+
color var(--transition-fast),
77+
background-color var(--transition-fast);
78+
}
79+
80+
.navItem:hover {
81+
color: var(--color-text);
82+
background-color: var(--color-bg-tertiary);
83+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"use client";
2+
3+
import { useState, useEffect } from "react";
4+
import { navigation } from "../Sidebar/Sidebar";
5+
import styles from "./MobileMenu.module.css";
6+
7+
export const MobileMenu: React.FC = () => {
8+
const [isOpen, setIsOpen] = useState(false);
9+
10+
useEffect(() => {
11+
const handleEscape = (event: KeyboardEvent) => {
12+
if (event.key === "Escape") {
13+
setIsOpen(false);
14+
}
15+
};
16+
17+
if (isOpen) {
18+
document.addEventListener("keydown", handleEscape);
19+
document.body.style.overflow = "hidden";
20+
}
21+
22+
return () => {
23+
document.removeEventListener("keydown", handleEscape);
24+
document.body.style.overflow = "";
25+
};
26+
}, [isOpen]);
27+
28+
return (
29+
<>
30+
<button
31+
className={styles.menuButton}
32+
aria-label={isOpen ? "Close menu" : "Open menu"}
33+
aria-expanded={isOpen}
34+
type="button"
35+
onClick={() => setIsOpen(!isOpen)}
36+
>
37+
<svg
38+
width="24"
39+
height="24"
40+
viewBox="0 0 24 24"
41+
fill="none"
42+
stroke="currentColor"
43+
strokeWidth="2"
44+
>
45+
{isOpen ? (
46+
<>
47+
<line x1="6" y1="6" x2="18" y2="18" />
48+
<line x1="6" y1="18" x2="18" y2="6" />
49+
</>
50+
) : (
51+
<>
52+
<line x1="3" y1="6" x2="21" y2="6" />
53+
<line x1="3" y1="12" x2="21" y2="12" />
54+
<line x1="3" y1="18" x2="21" y2="18" />
55+
</>
56+
)}
57+
</svg>
58+
</button>
59+
60+
{isOpen && (
61+
<>
62+
<div
63+
className={styles.overlay}
64+
onClick={() => setIsOpen(false)}
65+
aria-hidden="true"
66+
/>
67+
<aside className={styles.sidebar}>
68+
{navigation.map((section) => (
69+
<div key={section.title} className={styles.section}>
70+
<h3 className={styles.sectionTitle}>{section.title}</h3>
71+
<nav className={styles.navList}>
72+
{section.items.map((item) => (
73+
<a
74+
key={item.href}
75+
href={item.href}
76+
className={styles.navItem}
77+
onClick={() => setIsOpen(false)}
78+
>
79+
{item.label}
80+
</a>
81+
))}
82+
</nav>
83+
</div>
84+
))}
85+
</aside>
86+
</>
87+
)}
88+
</>
89+
);
90+
};

packages/docs/src/components/Sidebar/Sidebar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import styles from "./Sidebar.module.css";
22

3-
interface NavItem {
3+
export interface NavItem {
44
label: string;
55
href: string;
66
}
77

8-
interface NavSection {
8+
export interface NavSection {
99
title: string;
1010
items: NavItem[];
1111
}
1212

13-
const navigation: NavSection[] = [
13+
export const navigation: NavSection[] = [
1414
{
1515
title: "Getting Started",
1616
items: [

0 commit comments

Comments
 (0)