Skip to content

Commit 6be9df7

Browse files
authored
fix: make docs website compatible with phones (#15)
## What? Documentation website needs to be compatible with phones, collapsing the sidebar ## Why? Very hard to read from a phone Signed-off-by: drew <me@andrinoff.com>
1 parent 4d3d9a3 commit 6be9df7

4 files changed

Lines changed: 231 additions & 45 deletions

File tree

docs/src/app/[...slug]/page.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import fs from "node:fs/promises";
22
import path from "node:path";
3+
import remarkCallout from "@r4ai/remark-callout";
34
import matter from "gray-matter";
45
import { notFound } from "next/navigation";
56
import { MDXRemote } from "next-mdx-remote/rsc";
6-
import remarkGfm from "remark-gfm";
7-
import remarkFrontmatter from "remark-frontmatter";
8-
import remarkCallout from "@r4ai/remark-callout";
97
import rehypeHighlight from "rehype-highlight";
8+
import remarkFrontmatter from "remark-frontmatter";
9+
import remarkGfm from "remark-gfm";
1010
import { Sidebar } from "@/components/Sidebar";
1111

1212
const CONTENT = path.join(process.cwd(), "content");
@@ -22,7 +22,9 @@ async function load(slug: string[]) {
2222

2323
export default async function DocPage({
2424
params,
25-
}: { params: Promise<{ slug: string[] }> }) {
25+
}: {
26+
params: Promise<{ slug: string[] }>;
27+
}) {
2628
const { slug } = await params;
2729
const doc = await load(slug);
2830
if (!doc) notFound();

docs/src/app/globals.css

Lines changed: 184 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
--callout-caution: #f85149;
1616
}
1717

18-
* { box-sizing: border-box; }
18+
* {
19+
box-sizing: border-box;
20+
}
1921

20-
html, body {
22+
html,
23+
body {
2124
margin: 0;
2225
padding: 0;
2326
background: var(--bg);
@@ -27,8 +30,13 @@ html, body {
2730
-webkit-font-smoothing: antialiased;
2831
}
2932

30-
a { color: var(--accent); text-decoration: none; }
31-
a:hover { text-decoration: underline; }
33+
a {
34+
color: var(--accent);
35+
text-decoration: none;
36+
}
37+
a:hover {
38+
text-decoration: underline;
39+
}
3240

3341
.site-header {
3442
display: flex;
@@ -50,10 +58,18 @@ a:hover { text-decoration: underline; }
5058
font-family: "JetBrains Mono", ui-monospace, monospace;
5159
}
5260

53-
.site-header nav a { color: var(--muted); margin-left: 1.5rem; }
54-
.site-header nav a:hover { color: var(--fg); text-decoration: none; }
61+
.site-header nav a {
62+
color: var(--muted);
63+
margin-left: 1.5rem;
64+
}
65+
.site-header nav a:hover {
66+
color: var(--fg);
67+
text-decoration: none;
68+
}
5569

56-
main { min-height: calc(100vh - 4rem); }
70+
main {
71+
min-height: calc(100vh - 4rem);
72+
}
5773

5874
.docs-layout {
5975
display: grid;
@@ -72,12 +88,26 @@ main { min-height: calc(100vh - 4rem); }
7288
align-self: start;
7389
}
7490

75-
.docs-sidebar ul { list-style: none; padding: 0; margin: 0; }
76-
.docs-sidebar li { margin: 0.5rem 0; }
77-
.docs-sidebar a { color: var(--muted); font-size: 0.9375rem; }
78-
.docs-sidebar a:hover { color: var(--fg); text-decoration: none; }
91+
.docs-sidebar ul {
92+
list-style: none;
93+
padding: 0;
94+
margin: 0;
95+
}
96+
.docs-sidebar li {
97+
margin: 0.5rem 0;
98+
}
99+
.docs-sidebar a {
100+
color: var(--muted);
101+
font-size: 0.9375rem;
102+
}
103+
.docs-sidebar a:hover {
104+
color: var(--fg);
105+
text-decoration: none;
106+
}
79107

80-
.docs-content { max-width: 48rem; }
108+
.docs-content {
109+
max-width: 48rem;
110+
}
81111

82112
.docs-content h1 {
83113
font-size: 2.25rem;
@@ -93,7 +123,10 @@ main { min-height: calc(100vh - 4rem); }
93123
border-bottom: 1px solid var(--border);
94124
}
95125

96-
.docs-content h3 { font-size: 1.2rem; margin-top: 2rem; }
126+
.docs-content h3 {
127+
font-size: 1.2rem;
128+
margin-top: 2rem;
129+
}
97130

98131
.docs-content pre {
99132
background: var(--surface);
@@ -115,13 +148,20 @@ main { min-height: calc(100vh - 4rem); }
115148
border: 1px solid var(--border);
116149
}
117150

118-
.docs-content table { border-collapse: collapse; width: 100%; margin: 1rem 0; }
119-
.docs-content th, .docs-content td {
151+
.docs-content table {
152+
border-collapse: collapse;
153+
width: 100%;
154+
margin: 1rem 0;
155+
}
156+
.docs-content th,
157+
.docs-content td {
120158
border: 1px solid var(--border);
121159
padding: 0.5rem 0.75rem;
122160
text-align: left;
123161
}
124-
.docs-content th { background: var(--surface); }
162+
.docs-content th {
163+
background: var(--surface);
164+
}
125165

126166
/* Callouts */
127167
.docs-content [data-callout] {
@@ -132,11 +172,21 @@ main { min-height: calc(100vh - 4rem); }
132172
border-radius: 0.375rem;
133173
margin: 1.25rem 0;
134174
}
135-
.docs-content [data-callout][data-callout-type="note"] { border-left-color: var(--callout-note); }
136-
.docs-content [data-callout][data-callout-type="tip"] { border-left-color: var(--callout-tip); }
137-
.docs-content [data-callout][data-callout-type="important"] { border-left-color: var(--callout-important); }
138-
.docs-content [data-callout][data-callout-type="warning"] { border-left-color: var(--callout-warning); }
139-
.docs-content [data-callout][data-callout-type="caution"] { border-left-color: var(--callout-caution); }
175+
.docs-content [data-callout][data-callout-type="note"] {
176+
border-left-color: var(--callout-note);
177+
}
178+
.docs-content [data-callout][data-callout-type="tip"] {
179+
border-left-color: var(--callout-tip);
180+
}
181+
.docs-content [data-callout][data-callout-type="important"] {
182+
border-left-color: var(--callout-important);
183+
}
184+
.docs-content [data-callout][data-callout-type="warning"] {
185+
border-left-color: var(--callout-warning);
186+
}
187+
.docs-content [data-callout][data-callout-type="caution"] {
188+
border-left-color: var(--callout-caution);
189+
}
140190

141191
.docs-content [data-callout-title] {
142192
display: flex;
@@ -165,17 +215,118 @@ main { min-height: calc(100vh - 4rem); }
165215
mask-position: center;
166216
}
167217

168-
.docs-content [data-callout][data-callout-type="note"] { --callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'/%3E%3C/svg%3E"); }
169-
.docs-content [data-callout][data-callout-type="tip"] { --callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z'/%3E%3C/svg%3E"); }
170-
.docs-content [data-callout][data-callout-type="important"] { --callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'/%3E%3C/svg%3E"); }
171-
.docs-content [data-callout][data-callout-type="warning"] { --callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'/%3E%3C/svg%3E"); }
172-
.docs-content [data-callout][data-callout-type="caution"] { --callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .39.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.39.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'/%3E%3C/svg%3E"); }
218+
.docs-content [data-callout][data-callout-type="note"] {
219+
--callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'/%3E%3C/svg%3E");
220+
}
221+
.docs-content [data-callout][data-callout-type="tip"] {
222+
--callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z'/%3E%3C/svg%3E");
223+
}
224+
.docs-content [data-callout][data-callout-type="important"] {
225+
--callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'/%3E%3C/svg%3E");
226+
}
227+
.docs-content [data-callout][data-callout-type="warning"] {
228+
--callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'/%3E%3C/svg%3E");
229+
}
230+
.docs-content [data-callout][data-callout-type="caution"] {
231+
--callout-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .39.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.39.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'/%3E%3C/svg%3E");
232+
}
233+
234+
.docs-content [data-callout][data-callout-type="note"] [data-callout-title] {
235+
color: var(--callout-note);
236+
}
237+
.docs-content [data-callout][data-callout-type="tip"] [data-callout-title] {
238+
color: var(--callout-tip);
239+
}
240+
.docs-content
241+
[data-callout][data-callout-type="important"]
242+
[data-callout-title] {
243+
color: var(--callout-important);
244+
}
245+
.docs-content [data-callout][data-callout-type="warning"] [data-callout-title] {
246+
color: var(--callout-warning);
247+
}
248+
.docs-content [data-callout][data-callout-type="caution"] [data-callout-title] {
249+
color: var(--callout-caution);
250+
}
173251

174-
.docs-content [data-callout][data-callout-type="note"] [data-callout-title] { color: var(--callout-note); }
175-
.docs-content [data-callout][data-callout-type="tip"] [data-callout-title] { color: var(--callout-tip); }
176-
.docs-content [data-callout][data-callout-type="important"] [data-callout-title] { color: var(--callout-important); }
177-
.docs-content [data-callout][data-callout-type="warning"] [data-callout-title] { color: var(--callout-warning); }
178-
.docs-content [data-callout][data-callout-type="caution"] [data-callout-title] { color: var(--callout-caution); }
252+
.docs-content [data-callout-body] > :first-child {
253+
margin-top: 0;
254+
}
255+
.docs-content [data-callout-body] > :last-child {
256+
margin-bottom: 0;
257+
}
258+
/* --- Responsive: collapsible sidebar + mobile layout --- */
259+
.sidebar-toggle {
260+
display: none;
261+
}
262+
.docs-sidebar a[aria-current="page"] {
263+
color: var(--fg);
264+
font-weight: 600;
265+
}
266+
.docs-content {
267+
overflow-wrap: break-word;
268+
}
179269

180-
.docs-content [data-callout-body] > :first-child { margin-top: 0; }
181-
.docs-content [data-callout-body] > :last-child { margin-bottom: 0; }
270+
@media (max-width: 820px) {
271+
.docs-layout {
272+
grid-template-columns: 1fr;
273+
gap: 1.25rem;
274+
padding: 1.5rem 1.15rem;
275+
}
276+
.docs-sidebar {
277+
position: static;
278+
top: auto;
279+
border-right: none;
280+
border-bottom: 1px solid var(--border);
281+
padding: 0 0 0.75rem;
282+
padding-right: 0;
283+
}
284+
.sidebar-toggle {
285+
display: flex;
286+
align-items: center;
287+
justify-content: space-between;
288+
width: 100%;
289+
padding: 0.6rem 0.85rem;
290+
background: var(--surface);
291+
color: var(--fg);
292+
border: 1px solid var(--border);
293+
border-radius: 0.5rem;
294+
font: inherit;
295+
font-weight: 600;
296+
cursor: pointer;
297+
}
298+
.sidebar-toggle-icon {
299+
color: var(--muted);
300+
font-size: 1.1rem;
301+
line-height: 1;
302+
}
303+
.sidebar-nav ul {
304+
display: none;
305+
margin-top: 0.6rem;
306+
}
307+
.sidebar-nav[data-open="true"] ul {
308+
display: block;
309+
}
310+
.docs-content {
311+
max-width: 100%;
312+
}
313+
.docs-content h1 {
314+
font-size: 1.8rem;
315+
}
316+
.docs-content h2 {
317+
font-size: 1.3rem;
318+
}
319+
.docs-content pre {
320+
font-size: 0.8rem;
321+
}
322+
.docs-content table {
323+
display: block;
324+
overflow-x: auto;
325+
}
326+
.site-header {
327+
padding: 0.85rem 1.15rem;
328+
}
329+
.site-header nav a {
330+
margin-left: 1rem;
331+
}
332+
}

docs/src/app/layout.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ export const metadata: Metadata = {
88
"Sandboxed terminal image rendering for Go. Kitty, Sixel, and half-block. Fast CGo decode via stb_image.",
99
};
1010

11-
export default function RootLayout({ children }: { children: React.ReactNode }) {
11+
export default function RootLayout({
12+
children,
13+
}: {
14+
children: React.ReactNode;
15+
}) {
1216
return (
1317
<html lang="en">
1418
<body>
@@ -25,3 +29,5 @@ export default function RootLayout({ children }: { children: React.ReactNode })
2529
</html>
2630
);
2731
}
32+
33+
export const viewport = { width: "device-width", initialScale: 1 };

docs/src/components/Sidebar.tsx

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
"use client";
2+
13
import Link from "next/link";
4+
import { usePathname } from "next/navigation";
5+
import { useState } from "react";
26

37
const SECTIONS = [
48
{ title: "Introduction", slug: "introduction" },
@@ -10,14 +14,37 @@ const SECTIONS = [
1014
];
1115

1216
export function Sidebar() {
17+
const [open, setOpen] = useState(false);
18+
const pathname = usePathname();
1319
return (
14-
<nav>
15-
<ul>
16-
{SECTIONS.map((s) => (
17-
<li key={s.slug}>
18-
<Link href={`/${s.slug}`}>{s.title}</Link>
19-
</li>
20-
))}
20+
<nav className="sidebar-nav" data-open={open}>
21+
<button
22+
type="button"
23+
className="sidebar-toggle"
24+
aria-expanded={open}
25+
aria-controls="sidebar-list"
26+
onClick={() => setOpen((v) => !v)}
27+
>
28+
<span>Documentation</span>
29+
<span className="sidebar-toggle-icon" aria-hidden="true">
30+
{open ? "✕" : "☰"}
31+
</span>
32+
</button>
33+
<ul id="sidebar-list">
34+
{SECTIONS.map((s) => {
35+
const href = `/${s.slug}`;
36+
return (
37+
<li key={s.slug}>
38+
<Link
39+
href={href}
40+
aria-current={pathname === href ? "page" : undefined}
41+
onClick={() => setOpen(false)}
42+
>
43+
{s.title}
44+
</Link>
45+
</li>
46+
);
47+
})}
2148
</ul>
2249
</nav>
2350
);

0 commit comments

Comments
 (0)