Skip to content

Commit d7e46ea

Browse files
feat(theme): implement dark mode support and update typography
- Add ThemeContext and useTheme hooks for theme management - Introduce useThemeMode hook for persistent theme preference - Update typography styles for editorial aesthetic - Refactor components to utilize CSS variables for theming - Add PaletteStrip and NumbersStrip components for visual elements
1 parent ee32a0d commit d7e46ea

31 files changed

+1448
-267
lines changed

app/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
<link rel="preconnect" href="https://storage.googleapis.com" crossorigin>
2626
<!-- Preconnect to API for faster first request -->
2727
<link rel="preconnect" href="https://api.anyplot.ai" crossorigin>
28+
<!-- Google Fonts: Fraunces (serif headlines) + Inter (sans UI) -->
29+
<link rel="preconnect" href="https://fonts.googleapis.com">
30+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
31+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;0,9..144,600;0,9..144,700;1,9..144,400&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
2832

2933
<!-- Preload MonoLisa Basic Latin (most used, variable font = all weights) -->
3034
<link rel="preload" href="https://storage.googleapis.com/anyplot-static/fonts/0-MonoLisa-normal.woff2" as="font" type="font/woff2" crossorigin>

app/src/components/Breadcrumb.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ export function Breadcrumb({ items, rightAction, sx }: BreadcrumbProps) {
4949
px: 2,
5050
py: 1,
5151
mb: 2,
52-
bgcolor: colors.gray[100],
52+
bgcolor: colors.gray[50],
5353
borderBottom: `1px solid ${colors.gray[200]}`,
54-
fontFamily: typography.fontFamily,
54+
fontFamily: typography.mono,
5555
fontSize: fontSize.base,
5656
...sx,
5757
}}
@@ -83,7 +83,7 @@ export function Breadcrumb({ items, rightAction, sx }: BreadcrumbProps) {
8383
) : item.label}
8484
</Box>
8585
) : (
86-
<Box component="span" sx={{ color: colors.gray[700] }}>
86+
<Box component="span" sx={{ color: colors.gray[600] }}>
8787
{item.shortLabel ? (
8888
<>
8989
<Box component="span" sx={{ display: { xs: 'none', sm: 'inline' } }}>{item.label}</Box>

app/src/components/CodeHighlighter.tsx

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,46 @@
11
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';
2-
import { oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
32
import python from 'react-syntax-highlighter/dist/esm/languages/prism/python';
43
import { typography } from '../theme';
54

65
SyntaxHighlighter.registerLanguage('python', python);
76

7+
// Custom dark theme using Okabe-Ito palette colors
8+
const okabeItoDark: Record<string, React.CSSProperties> = {
9+
'pre[class*="language-"]': {
10+
color: '#E8E8E0',
11+
background: '#0E0E0C',
12+
},
13+
'code[class*="language-"]': {
14+
color: '#E8E8E0',
15+
background: 'none',
16+
},
17+
comment: { color: '#666', fontStyle: 'italic' },
18+
prolog: { color: '#666' },
19+
doctype: { color: '#666' },
20+
cdata: { color: '#666' },
21+
keyword: { color: '#56B4E9' }, // sky blue
22+
builtin: { color: '#56B4E9' },
23+
operator: { color: '#E8E8E0' },
24+
string: { color: '#009E73' }, // green
25+
'attr-value': { color: '#009E73' },
26+
'template-string': { color: '#009E73' },
27+
function: { color: '#E69F00' }, // orange
28+
'function-variable': { color: '#E69F00' },
29+
'class-name': { color: '#E69F00' },
30+
number: { color: '#F0E442' }, // yellow
31+
boolean: { color: '#F0E442' },
32+
variable: { color: '#CC79A7' }, // purple
33+
property: { color: '#CC79A7' },
34+
constant: { color: '#D55E00' }, // vermillion
35+
decorator: { color: '#D55E00' },
36+
punctuation: { color: '#8A8A82' },
37+
selector: { color: '#009E73' },
38+
tag: { color: '#D55E00' },
39+
'attr-name': { color: '#E69F00' },
40+
regex: { color: '#009E73' },
41+
important: { color: '#D55E00', fontWeight: 'bold' },
42+
};
43+
844
interface CodeHighlighterProps {
945
code: string;
1046
}
@@ -13,12 +49,15 @@ export default function CodeHighlighter({ code }: CodeHighlighterProps) {
1349
return (
1450
<SyntaxHighlighter
1551
language="python"
16-
style={oneLight}
52+
style={okabeItoDark}
1753
customStyle={{
1854
margin: 0,
55+
padding: '28px 32px',
1956
fontSize: '0.85rem',
2057
fontFamily: typography.fontFamily,
21-
background: 'transparent',
58+
background: '#0E0E0C',
59+
borderRadius: '12px',
60+
lineHeight: 1.7,
2261
}}
2362
>
2463
{code}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import Box from '@mui/material/Box';
2+
import { SectionHeader } from './SectionHeader';
3+
import { typography } from '../theme';
4+
5+
export function CodeShowcase() {
6+
return (
7+
<Box sx={{ maxWidth: 'var(--max)', mx: 'auto', py: { xs: 6, md: 10 } }}>
8+
<SectionHeader
9+
number="§ 02"
10+
title={<>One <em>import</em>.</>}
11+
/>
12+
13+
<Box sx={{
14+
display: 'grid',
15+
gridTemplateColumns: { xs: '1fr', md: '1fr 1.1fr' },
16+
gap: 6,
17+
alignItems: 'center',
18+
}}>
19+
{/* Left: description */}
20+
<Box>
21+
<Box component="h3" sx={{
22+
fontFamily: typography.serif,
23+
fontSize: { xs: '1.5rem', md: 'clamp(2rem, 4vw, 3rem)' },
24+
fontWeight: 400,
25+
lineHeight: 1.1,
26+
letterSpacing: '-0.02em',
27+
mb: 3,
28+
m: 0,
29+
color: 'var(--ink)',
30+
'& em': { fontStyle: 'italic', color: 'var(--ok-green)' },
31+
}}>
32+
Same palette,<br /><em>every library</em>.
33+
</Box>
34+
<Box sx={{
35+
fontFamily: typography.serif,
36+
fontWeight: 300,
37+
fontSize: '1.125rem',
38+
lineHeight: 1.5,
39+
color: 'var(--ink-soft)',
40+
mb: 2.5,
41+
}}>
42+
Every example in the catalogue uses the same Okabe-Ito palette. Switch libraries
43+
without losing your color grammar — a <em style={{ fontStyle: 'italic' }}>Gentoo penguin</em> is always blue,
44+
whether you draw it in matplotlib or plotly.
45+
</Box>
46+
<Box sx={{
47+
fontFamily: typography.mono,
48+
fontSize: '13px',
49+
color: 'var(--ink-muted)',
50+
}}>
51+
Validated against deuteranopia, protanopia and tritanopia using the Machado et al. (2009) simulation model.
52+
</Box>
53+
</Box>
54+
55+
{/* Right: code block */}
56+
<Box sx={{
57+
background: 'var(--code-bg)',
58+
color: 'var(--code-text)',
59+
p: { xs: 2.5, md: '28px 32px' },
60+
borderRadius: '12px',
61+
fontFamily: typography.mono,
62+
fontSize: '14px',
63+
lineHeight: 1.7,
64+
overflowX: 'auto',
65+
position: 'relative',
66+
boxShadow: '0 24px 48px -16px rgba(0,0,0,0.2)',
67+
'&::before': {
68+
content: '"● ● ●"',
69+
position: 'absolute',
70+
top: 12,
71+
left: 16,
72+
color: '#2A2A27',
73+
fontSize: '10px',
74+
letterSpacing: '4px',
75+
},
76+
}}>
77+
<Box component="pre" sx={{ mt: 3, m: 0, whiteSpace: 'pre' }}>
78+
<Box component="span" sx={{ color: '#666', fontStyle: 'italic' }}>
79+
{'# pick any library. the palette travels with you.\n'}
80+
</Box>
81+
<Box component="span" sx={{ color: '#56B4E9' }}>import</Box>{' anyplot '}
82+
<Box component="span" sx={{ color: '#56B4E9' }}>as</Box>{' ap\n\n'}
83+
{'data = ap.'}
84+
<Box component="span" sx={{ color: '#E69F00' }}>load</Box>
85+
{'('}
86+
<Box component="span" sx={{ color: '#009E73' }}>"penguins"</Box>
87+
{')\n\n'}
88+
<Box component="span" sx={{ color: '#666', fontStyle: 'italic' }}>
89+
{'# matplotlib\n'}
90+
</Box>
91+
{'ap.'}
92+
<Box component="span" sx={{ color: '#E69F00' }}>mpl</Box>
93+
{'.'}
94+
<Box component="span" sx={{ color: '#E69F00' }}>scatter</Box>
95+
{'(data, x='}
96+
<Box component="span" sx={{ color: '#009E73' }}>"bill"</Box>
97+
{', y='}
98+
<Box component="span" sx={{ color: '#009E73' }}>"flipper"</Box>
99+
{',\n hue='}
100+
<Box component="span" sx={{ color: '#009E73' }}>"species"</Box>
101+
{')\n\n'}
102+
<Box component="span" sx={{ color: '#666', fontStyle: 'italic' }}>
103+
{'# plotly — same colors, interactive\n'}
104+
</Box>
105+
{'ap.'}
106+
<Box component="span" sx={{ color: '#E69F00' }}>plotly</Box>
107+
{'.'}
108+
<Box component="span" sx={{ color: '#E69F00' }}>scatter</Box>
109+
{'(data, x='}
110+
<Box component="span" sx={{ color: '#009E73' }}>"bill"</Box>
111+
{', y='}
112+
<Box component="span" sx={{ color: '#009E73' }}>"flipper"</Box>
113+
{',\n hue='}
114+
<Box component="span" sx={{ color: '#009E73' }}>"species"</Box>
115+
{')'}
116+
</Box>
117+
</Box>
118+
</Box>
119+
</Box>
120+
);
121+
}

0 commit comments

Comments
 (0)