Skip to content

Commit 1e80eb1

Browse files
aspectrrfukouda
andauthored
Mobile Docs (#11)
* feat: inline code to spec, collapsible code segments, fix llms txt, fix nav * fix: remove changelog filtering * fix: update icon, add in shimmering logo * fix: fix docs nits * fix: docs stuff (#9) * fix: docs stuff * fix: linking + biome errors * docs: mobile mode * fix: add back in flag handlers for code blocks * fix: add more steel-cli docs * fix: add better self hosting docs * fix: add more cli docs * fix: update concurrency limits * feat: make docs mobile friendly * feat: fix up railway docs --------- Co-authored-by: nas <nasr.mohamed244@gmail.com>
1 parent 4556c50 commit 1e80eb1

File tree

6 files changed

+116
-206
lines changed

6 files changed

+116
-206
lines changed

app/theme.css

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
@theme {
22
--font-sans:
3-
ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
4-
"Noto Color Emoji";
3+
ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
4+
"Segoe UI Symbol", "Noto Color Emoji";
55
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
66
--font-mono:
7-
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
8-
monospace;
7+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
8+
"Courier New", monospace;
99
--color-red-50: oklch(0.971 0.013 17.38);
1010
--color-red-100: oklch(0.936 0.032 17.717);
1111
--color-red-200: oklch(0.885 0.062 18.334);
@@ -262,6 +262,9 @@
262262
--color-black: #0d0c0c;
263263
--color-white: #ffffff;
264264
--spacing: 0.25rem;
265+
--breakpoint-3xs: 16rem;
266+
--breakpoint-2xs: 24rem;
267+
--breakpoint-xs: 36rem;
265268
--breakpoint-sm: 40rem;
266269
--breakpoint-md: 48rem;
267270
--breakpoint-lg: 64rem;
@@ -338,8 +341,10 @@
338341
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
339342
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
340343
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
341-
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
342-
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
344+
--shadow-lg:
345+
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
346+
--shadow-xl:
347+
0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
343348
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
344349
--inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);
345350
--inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);

components/layout/mobile-navigation.tsx

Lines changed: 44 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
1-
'use client';
2-
3-
import type { PageTree } from 'fumadocs-core/server';
4-
import { TreeContextProvider } from 'fumadocs-ui/contexts/tree';
5-
import { ChevronRight, X } from 'lucide-react';
6-
import Link from 'next/link';
7-
import { usePathname } from 'next/navigation';
8-
import React, { useMemo, useState } from 'react';
9-
import { baseOptions } from '@/app/layout.config';
10-
import { Sidebar } from '@/components/layouts/docs';
1+
"use client";
2+
3+
import type { PageTree } from "fumadocs-core/server";
4+
import { TreeContextProvider } from "fumadocs-ui/contexts/tree";
5+
import { ChevronRight, X } from "lucide-react";
6+
import Link from "next/link";
7+
import { usePathname } from "next/navigation";
8+
import React, { useMemo, useState } from "react";
9+
import { baseOptions } from "@/app/layout.config";
10+
import { Sidebar } from "@/components/layouts/docs";
1111
import {
1212
Breadcrumb,
1313
BreadcrumbItem,
1414
BreadcrumbLink,
1515
BreadcrumbList,
1616
BreadcrumbPage,
1717
BreadcrumbSeparator,
18-
} from '@/components/ui/breadcrumb';
19-
import { DocsLogo } from '@/components/ui/icon';
20-
import { cn } from '@/lib/utils';
21-
import { SearchToggle } from '../layout/search-toggle';
18+
} from "@/components/ui/breadcrumb";
19+
import { DocsLogo } from "@/components/ui/icon";
20+
import { cn } from "@/lib/utils";
21+
import { SearchToggle } from "../layout/search-toggle";
2222

2323
interface MobileNavigationProps {
2424
isOpen?: boolean;
2525
onClose?: () => void;
2626
tree?: PageTree.Root;
2727
}
2828

29-
export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNavigationProps) {
29+
export function MobileNavigation({
30+
isOpen = false,
31+
onClose,
32+
tree,
33+
}: MobileNavigationProps) {
3034
const [activeSubmenu, setActiveSubmenu] = useState<string | null>(null);
3135
const [showMainMenu, setShowMainMenu] = useState(false);
3236
const pathname = usePathname();
@@ -41,137 +45,12 @@ export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNaviga
4145
onClose?.();
4246
};
4347

44-
const getMobileBreadcrumb = () => {
45-
if (!tree || !pathname) return <span>Navigation</span>;
46-
47-
const segments = pathname.split('/').filter(Boolean);
48-
if (segments.length === 0) return <span>Navigation</span>;
49-
50-
const displaySegments = [...segments];
51-
let firstSegmentMenu = null;
52-
53-
if (segments[0] === 'reference') {
54-
displaySegments[0] = 'Libraries & SDKs';
55-
firstSegmentMenu = 'Libraries & SDKs';
56-
} else {
57-
// Check if first segment matches a menu item
58-
const firstSegment = segments[0];
59-
const menuItem = baseOptions.links?.find(
60-
(link) =>
61-
link.type === 'menu' &&
62-
typeof link.text === 'string' &&
63-
link.text.toLowerCase() === firstSegment.toLowerCase(),
64-
);
65-
if (menuItem && 'text' in menuItem && typeof menuItem.text === 'string') {
66-
firstSegmentMenu = menuItem.text;
67-
displaySegments[0] = menuItem.text; // Use the properly cased menu text
68-
}
69-
}
70-
71-
const maxDepth = 2;
72-
const limitedSegments = displaySegments.slice(0, maxDepth);
73-
74-
// FIXME: Special formatting
75-
const formattedSegments = limitedSegments.map((segment, index) => {
76-
if (index === 0 && (segment === 'Libraries & SDKs' || firstSegmentMenu)) {
77-
return segment;
78-
}
79-
80-
if (index === 1 && displaySegments[0].toLowerCase() === 'apis') {
81-
const apiMappings: { [key: string]: string } = {
82-
'sessions-api': 'Sessions API',
83-
'credentials-api': 'Credentials API',
84-
'extensions-api': 'Extensions API',
85-
'files-api': 'Files API',
86-
'captchas-api': 'Captchas API',
87-
};
88-
89-
if (apiMappings[segment.toLowerCase()]) {
90-
return apiMappings[segment.toLowerCase()];
91-
}
92-
}
93-
94-
if (index === 1 && displaySegments[0] === 'Tools') {
95-
const toolMappings: { [key: string]: string } = {
96-
'web-automation': 'Web Automation',
97-
'ai-agents': 'AI Agents',
98-
};
99-
100-
if (toolMappings[segment.toLowerCase()]) {
101-
return toolMappings[segment.toLowerCase()];
102-
}
103-
}
104-
105-
return segment.charAt(0).toUpperCase() + segment.slice(1);
106-
});
107-
108-
return (
109-
<Breadcrumb className="text-lg font-mono">
110-
<BreadcrumbList className="gap-1">
111-
<BreadcrumbItem>
112-
<BreadcrumbLink
113-
asChild
114-
className="text-muted-foreground hover:text-primary !font-mono !text-base"
115-
>
116-
<button
117-
type="button"
118-
onClick={() => setShowMainMenu(true)}
119-
onKeyDown={(e) => e.key === 'Enter' && setShowMainMenu(true)}
120-
>
121-
..
122-
</button>
123-
</BreadcrumbLink>
124-
</BreadcrumbItem>
125-
126-
{formattedSegments.map((segment, index) => {
127-
const isLast = index === formattedSegments.length - 1;
128-
const displayName = segment;
129-
130-
const handleClick = () => {
131-
if (index === 0 && firstSegmentMenu) {
132-
setActiveSubmenu(firstSegmentMenu);
133-
} else {
134-
handleClose();
135-
}
136-
};
137-
138-
return (
139-
<React.Fragment key={index}>
140-
<BreadcrumbSeparator className="text-muted-foreground">/</BreadcrumbSeparator>
141-
<BreadcrumbItem>
142-
{isLast ? (
143-
<BreadcrumbPage className="text-primary !font-mono !text-base">
144-
{displayName}
145-
</BreadcrumbPage>
146-
) : (
147-
<BreadcrumbLink
148-
asChild
149-
className="text-muted-foreground hover:text-primary !font-mono !text-base cursor-pointer"
150-
>
151-
<button
152-
type="button"
153-
onClick={handleClick}
154-
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
155-
>
156-
{displayName}
157-
</button>
158-
</BreadcrumbLink>
159-
)}
160-
</BreadcrumbItem>
161-
</React.Fragment>
162-
);
163-
})}
164-
</BreadcrumbList>
165-
</Breadcrumb>
166-
);
167-
};
168-
16948
return (
17049
<div className="fixed inset-0 z-50 md:hidden">
17150
<div
17251
className="fixed inset-0 bg-black/50 transition-opacity duration-200"
17352
onClick={handleClose}
174-
onKeyDown={(e) => e.key === 'Escape' && handleClose()}
53+
onKeyDown={(e) => e.key === "Escape" && handleClose()}
17554
tabIndex={-1}
17655
/>
17756

@@ -205,17 +84,20 @@ export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNaviga
20584
</button>
20685
</BreadcrumbLink>
20786
</BreadcrumbItem>
208-
<BreadcrumbSeparator className="text-muted-foreground">/</BreadcrumbSeparator>
87+
<BreadcrumbSeparator className="text-muted-foreground">
88+
/
89+
</BreadcrumbSeparator>
20990
<BreadcrumbItem>
21091
<BreadcrumbPage className="text-primary !font-mono !text-base">
21192
{activeSubmenu}
21293
</BreadcrumbPage>
21394
</BreadcrumbItem>
21495
</BreadcrumbList>
21596
</Breadcrumb>
216-
) : isInDocsContext && !showMainMenu ? (
217-
getMobileBreadcrumb()
21897
) : (
98+
// isInDocsContext && !showMainMenu ? (
99+
// getMobileBreadcrumb()
100+
// ) :
219101
<Link href="/" onClick={handleClose}>
220102
<DocsLogo />
221103
</Link>
@@ -229,22 +111,30 @@ export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNaviga
229111
{activeSubmenu ? (
230112
(
231113
baseOptions.links?.find(
232-
(item: any) => item.text === activeSubmenu && item.type === 'menu',
114+
(item: any) =>
115+
item.text === activeSubmenu && item.type === "menu",
233116
) as any
234117
)?.items?.map((subItem: any) => {
235-
if (subItem.type === 'custom' || !('url' in subItem) || !subItem.url) return null;
118+
if (
119+
subItem.type === "custom" ||
120+
!("url" in subItem) ||
121+
!subItem.url
122+
)
123+
return null;
236124

237125
return (
238126
<Link
239127
key={subItem.url}
240128
href={subItem.url}
241129
onClick={handleClose}
242130
className={cn(
243-
'flex items-center justify-between px-2 py-3 text-lg hover:bg-accent transition-colors',
244-
subItem.isNew && 'gap-3 justify-start',
131+
"flex items-center justify-between px-2 py-3 text-lg hover:bg-accent transition-colors",
132+
subItem.isNew && "gap-3 justify-start",
245133
)}
246134
>
247-
<span className="font-mono text-muted-foreground">{subItem.text}</span>
135+
<span className="font-mono text-muted-foreground">
136+
{subItem.text}
137+
</span>
248138
{subItem.isNew && (
249139
<span className="font-regular text-[10px] px-1 py-0.5 rounded uppercase bg-orange-500 dark:bg-brand-orange text-neutral-950 border-none">
250140
New
@@ -274,7 +164,7 @@ export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNaviga
274164

275165
{baseOptions.links?.map((item, index) => (
276166
<div key={index} className="">
277-
{item.type === 'menu' ? (
167+
{item.type === "menu" ? (
278168
<button
279169
type="button"
280170
className="w-full flex items-center justify-between px-4 py-3 text-lg hover:bg-accent transition-colors text-left"
@@ -283,11 +173,13 @@ export function MobileNavigation({ isOpen = false, onClose, tree }: MobileNaviga
283173
setShowMainMenu(false);
284174
}}
285175
>
286-
<span className="font-mono text-muted-foreground">{item.text}</span>
176+
<span className="font-mono text-muted-foreground">
177+
{item.text}
178+
</span>
287179
<ChevronRight className="h-4 w-4 text-muted-foreground" />
288180
</button>
289181
) : (
290-
'url' in item && (
182+
"url" in item && (
291183
<Link
292184
href={item.url as string}
293185
onClick={handleClose}

components/layout/search-toggle.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
'use client';
2-
import { useSearchContext } from 'fumadocs-ui/contexts/search';
3-
import { shortcutLabel } from 'lib/utils/is-mac-like';
4-
import { Search, SearchIcon } from 'lucide-react';
5-
import type { ComponentProps } from 'react';
1+
"use client";
2+
import { useSearchContext } from "fumadocs-ui/contexts/search";
3+
import { shortcutLabel } from "lib/utils/is-mac-like";
4+
import { Search, SearchIcon } from "lucide-react";
5+
import type { ComponentProps } from "react";
66

7-
export function SearchToggle(props: ComponentProps<'div'>) {
7+
export function SearchToggle(props: ComponentProps<"div">) {
88
const { enabled, setOpenSearch } = useSearchContext();
99
if (!enabled) return;
1010

@@ -22,7 +22,7 @@ export function SearchToggle(props: ComponentProps<'div'>) {
2222

2323
{/* For desktop, show the search bar */}
2424
<div
25-
className="3xs:hidden 2xs:hidden sm:hidden md:flex w-full max-w-[160px] lg:max-w-[225px] h-9 bg-white dark:bg-background rounded-md shadow-[0px_1px_2px_0px_rgba(0,0,0,0.36)] outline outline-[0.50px] outline-offset-[-0.50px] outline-zinc-800 inline-flex justify-start items-center gap-2 rounded-sm px-2 cursor-pointer group"
25+
className="hidden md:flex w-full max-w-[160px] lg:max-w-[225px] h-9 bg-white dark:bg-background rounded-md shadow-[0px_1px_2px_0px_rgba(0,0,0,0.36)] outline-[0.50px] outline-offset-[-0.50px] outline-zinc-800 justify-start items-center gap-2 px-2 cursor-pointer group"
2626
onClick={() => setOpenSearch(true)}
2727
{...props}
2828
>
@@ -34,7 +34,7 @@ export function SearchToggle(props: ComponentProps<'div'>) {
3434
</div>
3535
<div className="px-1.5 py-[3px] bg-muted rounded-xs outline outline-[0.50px] outline-offset-[-0.50px] outline-zinc-800 inline-flex justify-center items-center">
3636
<div className="text-center justify-center text-zinc-500 text-xs font-normal font-mono leading-none group-hover:text-primary">
37-
{shortcutLabel() || ' '}
37+
{shortcutLabel() || " "}
3838
</div>
3939
</div>
4040
</div>

0 commit comments

Comments
 (0)