/ tutorials / laplace-dirichlet
Sign in
tutorials / laplace-dirichlet
laplace-dirichlet / src / App.tsx
95 lines · 3.2 KBCodeBlameHistory
088be4cAn interactive tutorial on the Dirichlet problem, accuracy against costJeremy Magland 1import { useCallback, useEffect, useState } from 'react'
2import ChapterView from './ui/ChapterView.tsx'
3import LibraryView from './ui/LibraryView.tsx'
4import { CHAPTERS } from './chapters/index.ts'
e5fc8c6An introduction and static figures, and the MATLAB written plainly againJeremy Magland 6const PARTS = ['Introduction', 'One dimension', 'Two dimensions', 'Beyond the square'] as const
8/** The introduction is front matter, so the chapter numbers start after it. */
9const NUMBERED = CHAPTERS.filter((c) => c.part !== 'Introduction')
11function readHash(): string {
12 const h = window.location.hash.replace(/^#\/?/, '')
13 return h === '' ? CHAPTERS[0].id : h
16export default function App() {
17 const [route, setRoute] = useState(readHash)
18 useEffect(() => {
19 const on = () => setRoute(readHash())
20 window.addEventListener('hashchange', on)
21 return () => window.removeEventListener('hashchange', on)
22 }, [])
24 const go = useCallback((id: string) => {
25 window.location.hash = `/${id}`
26 window.scrollTo({ top: 0 })
27 }, [])
29 const chapter = CHAPTERS.find((c) => c.id === route)
30 const index = CHAPTERS.findIndex((c) => c.id === route)
32 return (
33 <div className="app">
34 <nav className="sidebar">
35 <div className="brand">
36 <div className="brand-title">The Dirichlet problem</div>
37 <div className="brand-sub">accuracy against cost, in the browser</div>
38 </div>
39 {PARTS.map((part) => (
40 <div className="nav-part" key={part}>
41 <div className="nav-part-title">{part}</div>
42 <ol>
43 {CHAPTERS.filter((c) => c.part === part).map((c) => (
44 <li key={c.id}>
45 <button className={c.id === route ? 'nav-item active' : 'nav-item'} onClick={() => go(c.id)}>
e5fc8c6An introduction and static figures, and the MATLAB written plainly againJeremy Magland 46 <span className="nav-num">{NUMBERED.indexOf(c) + 1 || ''}</span>
48 </button>
49 </li>
50 ))}
51 </ol>
52 </div>
53 ))}
54 <div className="nav-part">
55 <div className="nav-part-title">Reference</div>
56 <ol>
57 <li>
58 <button className={route === 'library' ? 'nav-item active' : 'nav-item'} onClick={() => go('library')}>
59 <span className="nav-num" />
60 shared MATLAB library
61 </button>
62 </li>
63 </ol>
64 </div>
65 <div className="nav-foot">
66 MATLAB syntax runs in your browser through <a href="https://numbl.org">numbl</a>. Nothing is installed and
67 nothing is sent anywhere.
68 </div>
69 </nav>
71 <main className="main">
72 {route === 'library' ? (
73 <LibraryView />
74 ) : chapter ? (
75 <>
76 <ChapterView chapter={chapter} />
77 <nav className="pager">
78 {index > 0 && (
79 <button onClick={() => go(CHAPTERS[index - 1].id)}>
80 &larr; {CHAPTERS[index - 1].nav}
81 </button>
82 )}
83 <span className="lab-bar-gap" />
84 {index < CHAPTERS.length - 1 && (
85 <button onClick={() => go(CHAPTERS[index + 1].id)}>{CHAPTERS[index + 1].nav} &rarr;</button>
86 )}
87 </nav>
88 </>
89 ) : (
90 <p className="lab-error">no such chapter: {route}</p>
91 )}
92 </main>
93 </div>
94 )
↑↓ move↵openescclose