Skip to content

Commit 060b99b

Browse files
authored
docs: More intuitive navigation on the examples page (#2406)
1 parent d4edcf7 commit 060b99b

6 files changed

Lines changed: 99 additions & 44 deletions

File tree

Lines changed: 13 additions & 0 deletions
Loading
Lines changed: 39 additions & 0 deletions
Loading

apps/typegpu-docs/src/components/ControlPanel.tsx

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ import {
88
type ExampleControlParam,
99
exampleControlsAtom,
1010
} from '../utils/examples/exampleControlAtom.ts';
11-
import {
12-
codeEditorShownAtom,
13-
menuShownAtom,
14-
tsoverUsedAtom,
15-
} from '../utils/examples/exampleViewStateAtoms.ts';
11+
import { tsoverUsedAtom } from '../utils/examples/exampleViewStateAtoms.ts';
1612
import { isGPUSupported } from '../utils/isGPUSupported.ts';
1713
import { Button } from './design/Button.tsx';
1814
import { ColorPicker } from './design/ColorPicker.tsx';
@@ -282,13 +278,9 @@ function paramToControlRow(param: ExampleControlParam) {
282278
const unreachable = (_: never) => null;
283279

284280
export function ControlPanel() {
285-
const [menuShowing, setMenuShowing] = useAtom(menuShownAtom);
286-
const [codeEditorShowing, setCodeEditorShowing] = useAtom(codeEditorShownAtom);
287281
const [tsoverUsed, setTsoverUsed] = useAtom(tsoverUsedAtom);
288282
const exampleControlParams = useAtomValue(exampleControlsAtom);
289283

290-
const showLeftMenuId = useId();
291-
const showCodeEditorId = useId();
292284
const tsoverUsedId = useId();
293285

294286
return (
@@ -302,28 +294,6 @@ export function ControlPanel() {
302294
<div className="hidden flex-col gap-4 md:flex">
303295
<h2 className="font-medium text-xl">Control panel</h2>
304296

305-
<label
306-
htmlFor={showLeftMenuId}
307-
className="flex cursor-pointer items-center justify-between gap-3 text-sm"
308-
>
309-
<span>Show left menu</span>
310-
<Toggle
311-
id={showLeftMenuId}
312-
checked={menuShowing}
313-
onChange={(e) => setMenuShowing(e.target.checked)}
314-
/>
315-
</label>
316-
<label
317-
htmlFor={showCodeEditorId}
318-
className="flex cursor-pointer items-center justify-between gap-3 text-sm"
319-
>
320-
<span>Show code editor</span>
321-
<Toggle
322-
id={showCodeEditorId}
323-
checked={codeEditorShowing}
324-
onChange={(e) => setCodeEditorShowing(e.target.checked)}
325-
/>
326-
</label>
327297
<label
328298
htmlFor={tsoverUsedId}
329299
className="flex cursor-pointer items-center justify-between gap-3 text-sm"

apps/typegpu-docs/src/components/ExampleLayout.tsx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useSetAtom } from 'jotai';
22
import type { ReactNode } from 'react';
3-
import { useId, useRef } from 'react';
3+
import { useEffect, useId, useRef } from 'react';
4+
import cs from 'classnames';
45
import CrossSvg from '../assets/cross.svg';
56
import HamburgerSvg from '../assets/hamburger.svg';
67
import {
@@ -22,23 +23,36 @@ export function ExampleLayout(props: ExampleLayoutProps) {
2223
const [menuShown, setMenuShown] = useHydratedAtom(menuShownAtom, false);
2324
const [codeShown, setCodeShown] = useHydratedAtom(codeEditorShownAtom, false);
2425

26+
useEffect(() => {
27+
// Opening the side menu on large screens by default
28+
if (window.innerWidth >= 768) {
29+
setMenuShown(true);
30+
}
31+
}, []);
32+
2533
return (
2634
<>
27-
<div className="absolute top-4 left-4 z-50 flex gap-2 text-sm md:hidden">
35+
<div
36+
className={cs(
37+
'absolute top-4 left-4 md:top-5 md:left-5 z-50 flex gap-2 text-sm',
38+
menuShown && 'md:left-84',
39+
)}
40+
>
2841
{!menuShown && (
2942
<Button onClick={() => setMenuShown(true)}>
30-
<img src={HamburgerSvg.src} alt="menu" className="-m-2 h-6 w-6" />
43+
<img src={HamburgerSvg.src} alt="menu" className="-m-2 h-6 w-6 mr-1" />
44+
Explore
3145
</Button>
3246
)}
3347

3448
<Button onClick={() => setCodeShown((prev) => !prev)}>
35-
{/* Applying the actual label only after the component has been hydrated */}
36-
{codeShown ? 'Preview' : 'Code'}
49+
<span className="md:hidden">{codeShown ? 'Preview' : 'Code'}</span>
50+
<span className="hidden md:block">{codeShown ? 'Hide Code' : 'Show Code'}</span>
3751
</Button>
3852
</div>
39-
4053
<div className="box-border flex h-dvh gap-4 bg-tameplum-50 p-4">
4154
{menuShown && <SideMenu />}
55+
4256
{props.children}
4357
</div>
4458
</>
@@ -57,17 +71,24 @@ function SideMenu() {
5771
const groupByCategoryToggleId = useId();
5872

5973
return (
60-
<aside className="absolute inset-0 z-50 box-border flex w-full flex-col bg-white md:static md:w-75 md:rounded-2xl">
74+
<aside className="absolute inset-0 z-50 box-border flex w-full flex-col bg-white md:relative md:w-75 md:rounded-2xl">
6175
<header className="px-5 py-3">
6276
<div className="grid place-items-center">
6377
<a href="/TypeGPU" className="box-border grid h-12 cursor-pointer place-content-center">
6478
<img className="w-40" src="/TypeGPU/typegpu-logo-light.svg" alt="TypeGPU Logo" />
6579
</a>
6680
</div>
67-
<div className="absolute top-5 right-5 md:hidden">
68-
<Button onClick={() => setMenuShown(false)}>
81+
<div className="absolute top-5 right-5 md:top-2.5 md:right-2.5">
82+
<button
83+
className={cs(
84+
'box-border inline-flex items-center justify-center gap-2 rounded-[6.25rem] px-2.5 py-2.5 text-sm focus:ring-2 focus:ring-gradient-blue',
85+
'bg-white hover:bg-tameplum-20',
86+
)}
87+
type="button"
88+
onClick={() => setMenuShown(false)}
89+
>
6990
<img src={CrossSvg.src} alt="Close menu" className="h-3 w-3" />
70-
</Button>
91+
</button>
7192
</div>
7293
</header>
7394

apps/typegpu-docs/src/components/ExampleView.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,22 @@ export function ExampleView({ example, common }: Props) {
160160
))}
161161
</div>
162162

163-
<div className="absolute right-0 z-5 md:top-15 md:right-8">
163+
<div className="absolute right-0 z-5 md:top-15 md:right-8 md:hidden">
164+
<Button onClick={() => openInStackBlitz(example, common)}>
165+
<span className="font-bold">Edit </span>
166+
<img
167+
src="/TypeGPU/stackblitz-logomark-blue.svg"
168+
alt="stackblitz logo"
169+
className="h-4"
170+
/>
171+
</Button>
172+
</div>
173+
174+
<div className="absolute right-0 z-5 md:top-15 md:right-8 hidden md:block">
164175
<Button onClick={() => openInStackBlitz(example, common)}>
165176
<span className="font-bold">Edit on</span>
166177
<img
167-
src="https://developer.stackblitz.com/img/logo/stackblitz-logo-black_blue.svg"
178+
src="/TypeGPU/stackblitz-logo-black_blue.svg"
168179
alt="stackblitz logo"
169180
className="h-4"
170181
/>

apps/typegpu-docs/src/utils/examples/exampleViewStateAtoms.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { atom } from 'jotai';
12
import { atomWithStorage } from 'jotai/utils';
23

34
const storageOptions = { getOnInit: true };
45

5-
export const menuShownAtom = atomWithStorage('menu-shown', false, undefined, storageOptions);
6+
export const menuShownAtom = atom(false);
67

78
export const codeEditorShownAtom = atomWithStorage(
89
'code-editor-shown',

0 commit comments

Comments
 (0)