Skip to content

Commit 4be4cc0

Browse files
committed
feat: rename catalog to plots and add retro code nerd UI elements
Rename the catalog page to "plots" across routes, navigation, SEO, footer, breadcrumbs, and all linking components — aligns with the repo structure and the code-forward brand voice. Add retro developer-tool aesthetic elements to the plots page: - Man-page style header (PLOTS(1) ... anyplot.ai ... PLOTS(1)) - Comment-syntax section dividers (# --- filters / # --- results) - Terminal prompt in search ($ grep plots/) - Editor-style statusline (plots:N showing:N · %% · python) - Box-drawing card headers (┌ spec-id ... library ┐) - cat-style code reveal header on spec detail pages - Line numbers with pipe separator in code blocks https://claude.ai/code/session_016aTonNUwJu7vXeEkPgYyV8
1 parent 74d9841 commit 4be4cc0

18 files changed

+187
-68
lines changed

app/src/components/Breadcrumb.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ import { Breadcrumb } from './Breadcrumb';
44

55
describe('Breadcrumb', () => {
66
it('renders breadcrumb items', () => {
7-
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'catalog' }]} />);
7+
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'plots' }]} />);
88

99
expect(screen.getByText('anyplot.ai')).toBeInTheDocument();
10-
expect(screen.getByText('catalog')).toBeInTheDocument();
10+
expect(screen.getByText('plots')).toBeInTheDocument();
1111
});
1212

1313
it('renders linked items as links', () => {
14-
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'catalog' }]} />);
14+
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'plots' }]} />);
1515

1616
const link = screen.getByText('anyplot.ai');
1717
expect(link.closest('a')).toHaveAttribute('href', '/');
1818
});
1919

2020
it('renders current page as plain text', () => {
21-
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'catalog' }]} />);
21+
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'plots' }]} />);
2222

23-
const current = screen.getByText('catalog');
23+
const current = screen.getByText('plots');
2424
expect(current.closest('a')).toBeNull();
2525
});
2626

2727
it('renders separator between items', () => {
28-
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'catalog' }]} />);
28+
render(<Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'plots' }]} />);
2929

3030
expect(screen.getByText('›')).toBeInTheDocument();
3131
});

app/src/components/Breadcrumb.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ export interface BreadcrumbProps {
2424
* Breadcrumb navigation component.
2525
*
2626
* @example
27-
* // Simple: anyplot.ai > catalog
28-
* <Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'catalog' }]} />
27+
* // Simple: anyplot.ai > plots
28+
* <Breadcrumb items={[{ label: 'anyplot.ai', to: '/' }, { label: 'plots' }]} />
2929
*
3030
* @example
3131
* // With short labels for mobile

app/src/components/CodeHighlighter.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,23 @@ export default function CodeHighlighter({ code }: CodeHighlighterProps) {
5050
<SyntaxHighlighter
5151
language="python"
5252
style={okabeItoDark}
53+
showLineNumbers
54+
lineNumberStyle={{
55+
color: '#4A4A44',
56+
fontSize: '0.75rem',
57+
minWidth: '2.5em',
58+
paddingRight: '1em',
59+
borderRight: '1px solid rgba(255,255,255,0.06)',
60+
marginRight: '1em',
61+
userSelect: 'none',
62+
}}
5363
customStyle={{
5464
margin: 0,
5565
padding: '28px 32px',
5666
fontSize: '0.85rem',
5767
fontFamily: typography.fontFamily,
5868
background: '#0E0E0C',
59-
borderRadius: '12px',
69+
borderRadius: '0 0 12px 12px',
6070
lineHeight: 1.7,
6171
}}
6272
>

app/src/components/FilterBar.tsx

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -339,19 +339,20 @@ export function FilterBar({
339339
position: { xs: 'static', md: 'relative' },
340340
}}
341341
>
342-
{/* Progress counter - absolute left (desktop only) */}
342+
{/* Editor statusline - absolute left (desktop only) */}
343343
{!isMobile && currentTotal > 0 && (
344344
<Typography
345345
sx={{
346346
position: 'absolute',
347347
left: 0,
348348
fontFamily: typography.fontFamily,
349-
fontSize: fontSize.sm,
349+
fontSize: '10px',
350350
color: semanticColors.mutedText,
351351
whiteSpace: 'nowrap',
352+
letterSpacing: '0.04em',
352353
}}
353354
>
354-
{scrollPercent}% · {currentTotal}
355+
plots:{currentTotal} showing:{displayedCount} · {scrollPercent}% · python
355356
</Typography>
356357
)}
357358
{/* Toolbar actions - absolute right (desktop only) */}
@@ -450,17 +451,33 @@ export function FilterBar({
450451
'&:focus': isSearchExpanded ? {} : { outline: `2px solid ${colors.primary}`, outlineOffset: 2 },
451452
}}
452453
>
453-
<Tooltip title={isSearchExpanded ? '' : 'search'}>
454-
<SearchIcon
455-
className="search-icon"
454+
{isSearchExpanded ? (
455+
<Box
456+
component="span"
456457
sx={{
457-
color: colors.gray[500],
458-
fontSize: isSearchExpanded ? '1rem' : '1.25rem',
459-
transition: 'all 0.2s ease',
458+
fontFamily: typography.fontFamily,
459+
fontSize: fontSize.base,
460+
color: colors.primary,
461+
fontWeight: 700,
460462
flexShrink: 0,
463+
lineHeight: 1,
461464
}}
462-
/>
463-
</Tooltip>
465+
>
466+
$
467+
</Box>
468+
) : (
469+
<Tooltip title="search">
470+
<SearchIcon
471+
className="search-icon"
472+
sx={{
473+
color: colors.gray[500],
474+
fontSize: '1.25rem',
475+
transition: 'all 0.2s ease',
476+
flexShrink: 0,
477+
}}
478+
/>
479+
</Tooltip>
480+
)}
464481
<label htmlFor="filter-search" style={{ position: 'absolute', width: 1, height: 1, overflow: 'hidden', clip: 'rect(0,0,0,0)' }}>
465482
{selectedCategory ? `Search ${FILTER_LABELS[selectedCategory]}` : 'Search filters'}
466483
</label>
@@ -469,7 +486,7 @@ export function FilterBar({
469486
id="filter-search"
470487
name="filter-search"
471488
inputProps={{ 'aria-label': selectedCategory ? `Search ${FILTER_LABELS[selectedCategory]}` : 'Search filters' }}
472-
placeholder={selectedCategory ? FILTER_LABELS[selectedCategory] : ''}
489+
placeholder={selectedCategory ? FILTER_LABELS[selectedCategory] : 'grep plots/'}
473490
value={searchQuery}
474491
onChange={(e) => {
475492
setSearchQuery(e.target.value);
@@ -536,12 +553,13 @@ export function FilterBar({
536553
<Typography
537554
sx={{
538555
fontFamily: typography.fontFamily,
539-
fontSize: fontSize.sm,
556+
fontSize: '10px',
540557
color: semanticColors.mutedText,
541558
whiteSpace: 'nowrap',
559+
letterSpacing: '0.04em',
542560
}}
543561
>
544-
{scrollPercent}% · {currentTotal}
562+
{currentTotal} plots · {scrollPercent}%
545563
</Typography>
546564
) : (
547565
<Box />

app/src/components/Footer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ export function Footer({ onTrackEvent, selectedSpec, selectedLibrary }: FooterPr
5959
<span>·</span>
6060
<Link
6161
component={RouterLink}
62-
to="/catalog"
63-
onClick={() => onTrackEvent?.('internal_link', { destination: 'catalog', spec: selectedSpec, library: selectedLibrary })}
62+
to="/plots"
63+
onClick={() => onTrackEvent?.('internal_link', { destination: 'plots', spec: selectedSpec, library: selectedLibrary })}
6464
sx={linkSx}
6565
>
66-
catalog
66+
plots
6767
</Link>
6868
<span>·</span>
6969
<Link

app/src/components/HeroSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export function HeroSection({ stats }: HeroSectionProps) {
118118
<Box sx={{ display: 'flex', gap: 1.5, flexWrap: 'wrap', animation: 'rise 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) 0.3s backwards' }}>
119119
<Box
120120
component={RouterLink}
121-
to="/catalog"
121+
to="/plots"
122122
sx={{
123123
textDecoration: 'none',
124124
boxSizing: 'border-box',

app/src/components/ImageCard.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,24 @@ export const ImageCard = memo(function ImageCard({
152152
},
153153
}}
154154
>
155+
{/* Box-drawing style header */}
156+
<Box sx={{
157+
fontFamily: typography.fontFamily,
158+
fontSize: '9px',
159+
color: 'var(--ink-muted)',
160+
opacity: 0.4,
161+
px: 1.5,
162+
py: 0.5,
163+
display: 'flex',
164+
justifyContent: 'space-between',
165+
letterSpacing: '0.02em',
166+
borderBottom: '1px solid var(--rule)',
167+
transition: 'opacity 0.2s',
168+
'.MuiCard-root:hover &': { opacity: 0.7 },
169+
}}>
170+
<span>{image.spec_id}</span>
171+
<span>{image.library}</span>
172+
</Box>
155173
<Box component="picture" sx={{ display: 'contents' }}>
156174
<source
157175
type="image/webp"

app/src/components/LibrariesSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function LibrariesSection({ libraries, onLibraryClick }: LibrariesSection
2222
number="§ 01"
2323
title={<>The <em>libraries</em></>}
2424
linkText="view all"
25-
linkTo="/catalog"
25+
linkTo="/plots"
2626
/>
2727

2828
<Box sx={{

app/src/components/NavBar.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import Box from '@mui/material/Box';
44
import { colors, typography } from '../theme';
55

66
interface NavBarProps {
7-
/** Ref to FilterBar search input -- when on /catalog, focuses it; otherwise navigates to /catalog */
7+
/** Ref to FilterBar search input -- when on /plots, focuses it; otherwise navigates to /plots */
88
searchInputRef?: React.RefObject<HTMLInputElement | null>;
99
}
1010

1111
const NAV_LINKS = [
12-
{ label: 'catalog', to: '/catalog' },
12+
{ label: 'plots', to: '/plots' },
1313
{ label: 'specs', to: '/specs' },
1414
{ label: 'palette', to: '/palette' },
1515
{ label: 'mcp', to: '/mcp' },
@@ -58,10 +58,10 @@ export function NavBar({ searchInputRef }: NavBarProps) {
5858
const location = useLocation();
5959

6060
const handleSearch = useCallback(() => {
61-
if (location.pathname === '/catalog' && searchInputRef?.current) {
61+
if (location.pathname === '/plots' && searchInputRef?.current) {
6262
searchInputRef.current.focus();
6363
} else {
64-
navigate('/catalog');
64+
navigate('/plots');
6565
}
6666
}, [location.pathname, searchInputRef, navigate]);
6767

app/src/components/SpecTabs.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export function SpecTabs({
210210
return tagCounts[paramName]?.[value] ?? null;
211211
}, [tagCounts]);
212212

213-
// Handle tag click - navigate to filtered catalog (full page navigation)
213+
// Handle tag click - navigate to filtered plots page (full page navigation)
214214
const handleTagClick = useCallback(
215215
(paramName: string, value: string) => {
216216
onTrackEvent?.('tag_click', { param: paramName, value, source: 'spec_detail' });
@@ -346,11 +346,30 @@ export function SpecTabs({
346346
{copied ? <CheckIcon color="success" /> : <ContentCopyIcon fontSize="small" />}
347347
</IconButton>
348348
</Tooltip>
349+
{/* cat-style terminal header */}
350+
<Box sx={{
351+
fontFamily: typography.fontFamily,
352+
fontSize: '11px',
353+
color: '#6E6D66',
354+
bgcolor: '#0E0E0C',
355+
px: '32px',
356+
pt: 2,
357+
pb: 0,
358+
borderRadius: '12px 12px 0 0',
359+
letterSpacing: '0.04em',
360+
}}>
361+
<Box component="span" sx={{ color: '#009E73' }}>$</Box> cat {specId}/{libraryId}.py
362+
<Box sx={{
363+
mt: 1,
364+
borderBottom: '1px solid rgba(255,255,255,0.06)',
365+
}} />
366+
</Box>
349367
<Box
350368
sx={{
351369
bgcolor: colors.background,
352370
p: 3,
353-
borderRadius: 1,
371+
pt: 0,
372+
borderRadius: '0 0 12px 12px',
354373
}}
355374
>
356375
{highlightedCode}

0 commit comments

Comments
 (0)