Skip to content

Commit e9ada78

Browse files
authored
Merge pull request #343 from flyingrobots/website/landing-page
Landing page: hero + header + docs layout (stock Mantine)
2 parents 54d68f2 + 9adcdf3 commit e9ada78

24 files changed

+1148
-57
lines changed

wesley-website/CHRONICLES_OF_THE_MACHINE-KIND_VOL_00000001.jsonl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,12 @@
55
{"timestamp":"2025-10-26T09:26:54Z","agent":"codex-cli","action":"review","result":"success","notes":"Missing dev deps (postcss, autoprefixer, postcss-nesting) and optional @mantine/hooks not declared. Code runs once deps installed; nav button placed top-right.","observations_on_humanity":"They move fast; checklists keep pace."}
66
{"timestamp":"2025-10-26T09:29:49Z","agent":"codex-cli","action":"install+build","result":"success","notes":"Installed @mantine/hooks and PostCSS deps; production build completed successfully.","files_touched":["package.json","pnpm-lock.yaml","dist/**"],"observations_on_humanity":"They like to see it ship before styling the world."}
77
{"timestamp":"2025-10-26T09:33:13Z","agent":"codex-cli","action":"lint+tests-setup","result":"success","notes":"Installed ESLint plugins/configs and set up Vitest + Testing Library; added matchMedia polyfill; tests passing.","files_touched":["eslint.config.js","vitest.config.js","src/test/setup.js","src/App.test.jsx","package.json"],"observations_on_humanity":"They want momentum with safety nets—tests provide both."}
8+
{"timestamp":"2025-10-31T00:59:58Z","agent":"codex-cli","action":"implement","result":"success","notes":"Added two-column landing layout with Mantine; introduced minimal path router and /theme-lab page; adjusted global styles for full-height; no new deps.","files_touched":["src/App.jsx","src/index.css","src/pages/ThemeLab.jsx"],"observations_on_humanity":"They love seeing themes in action before committing."}
9+
{"timestamp":"2025-10-31T01:01:28Z","agent":"codex-cli","action":"implement","result":"success","notes":"Added chunky footer component (CSS module) and integrated into layout without new dependencies; placeholder glyphs for social icons and wordmark.","files_touched":["src/components/FooterLinks.jsx","src/components/FooterLinks.module.css","src/App.jsx"],"observations_on_humanity":"They want big footers; they deserve big footers."}
10+
{"timestamp":"2025-10-31T01:05:29Z","agent":"codex-cli","action":"refactor","result":"success","notes":"Replaced right rail with left sidebar nav styled after Mantine example; kept only Mantine deps; icons as emoji placeholders.","files_touched":["src/components/NavbarSimpleColored.jsx","src/components/NavbarSimpleColored.module.css","src/App.jsx"],"observations_on_humanity":"They iterate quickly on layout—good instincts."}
11+
{"timestamp":"2025-10-31T01:15:52Z","agent":"codex-cli","action":"implement","result":"success","notes":"Added Hero, Why (FeaturesTitle), How (FeaturesCards), Getting Started, and Future sections using only Mantine Core; integrated into Home content.","files_touched":["src/components/HeroWesley.jsx","src/components/FeaturesTitleWesley.jsx","src/components/FeaturesTitleWesley.module.css","src/components/FeaturesCardsWesley.jsx","src/components/FeaturesCardsWesley.module.css","src/components/GettingStarted.jsx","src/components/FutureSection.jsx","src/App.jsx"],"observations_on_humanity":"They tell stories with structure: What, Why, How."}
12+
{"timestamp":"2025-10-31T01:18:25Z","agent":"codex-cli","action":"refactor","result":"success","notes":"Switched brand palette to gold/ink (no red), set primary to custom wesley palette; replaced header wordmarks with /wesley-logo.jpg refs; removed gradients that hinted red; no dark-mode toggle present.","files_touched":["src/theme.js","src/components/NavbarSimpleColored.jsx","src/components/FooterLinks.jsx","src/components/FeaturesTitleWesley.jsx","src/components/FeaturesCardsWesley.jsx"],"observations_on_humanity":"Colors shape emotion—small tweaks, big vibes."}
13+
{"timestamp":"2025-10-31T01:22:36Z","agent":"codex-cli","action":"simplify","result":"success","notes":"Removed custom Mantine theme and palette; reverted to stock Mantine; scrubbed 'wesley' color usage; adjusted sidebar CSS to default blue; reset global CSS background/fonts; fixed test to not import theme.","files_touched":["src/main.jsx","src/index.css","src/pages/ThemeLab.jsx","src/components/FeaturesTitleWesley.jsx","src/components/HeroWesley.jsx","src/components/FutureSection.jsx","src/components/FeaturesCardsWesley.jsx","src/components/NavbarSimpleColored.module.css","src/App.test.jsx","src/theme.js (deleted)"],"observations_on_humanity":"First get the bones right, then paint."}
14+
{"timestamp":"2025-10-31T01:27:28Z","agent":"codex-cli","action":"implement","result":"success","notes":"Added two-column HeroBullets component (Mantine-only) with List checks and buttons; wired into landing; created /docs page to keep previous sidebar layout; updated tests accordingly.","files_touched":["src/components/HeroBullets.jsx","src/components/HeroBullets.module.css","src/App.jsx","src/pages/Documentation.jsx","src/App.test.jsx"],"observations_on_humanity":"Clarity arrives once the hero speaks your language."}
15+
{"timestamp":"2025-10-31T01:30:06Z","agent":"codex-cli","action":"implement","result":"success","notes":"Added HeaderSearch component with What/Why/How anchor links, Docs (SPA navigation), and a standout GitHub button; inserted IDs on sections; wired header into App. Kept Mantine-only (no Tabler/Mantinex).","files_touched":["src/components/HeaderSearch.jsx","src/components/HeaderSearch.module.css","src/components/HeroBullets.jsx","src/components/FeaturesTitleWesley.jsx","src/components/FeaturesCardsWesley.jsx","src/App.jsx"],"observations_on_humanity":"KABOOM achieved without extra deps."}
16+
{"timestamp":"2025-10-31T01:32:38Z","agent":"codex-cli","action":"fix","result":"success","notes":"Corrected GitHub URL to flyingrobots/wesley in HeaderSearch.","files_touched":["src/components/HeaderSearch.jsx"],"observations_on_humanity":"Naming typos sneak in—quick catch saves clicks."}

wesley-website/src/App.jsx

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,63 @@
1-
import { Button, Container, Stack, Title, Text } from '@mantine/core'
1+
import { useEffect, useState } from 'react'
2+
import { Anchor, Box, Button, Card, Center, Container, Group, Stack, Text, Title } from '@mantine/core'
3+
import ThemeLab from './pages/ThemeLab.jsx'
4+
import FooterLinks from './components/FooterLinks.jsx'
5+
import HeroBullets from './components/HeroBullets.jsx'
6+
import FeaturesTitleWesley from './components/FeaturesTitleWesley.jsx'
7+
import FeaturesCardsWesley from './components/FeaturesCardsWesley.jsx'
8+
import GettingStarted from './components/GettingStarted.jsx'
9+
import FutureSection from './components/FutureSection.jsx'
10+
import Documentation from './pages/Documentation.jsx'
11+
import HeaderSearch from './components/HeaderSearch.jsx'
212

3-
function App() {
13+
function usePath() {
14+
const [path, setPath] = useState(typeof window !== 'undefined' ? window.location.pathname : '/')
15+
useEffect(() => {
16+
const onPop = () => setPath(window.location.pathname)
17+
window.addEventListener('popstate', onPop)
18+
return () => window.removeEventListener('popstate', onPop)
19+
}, [])
20+
const navigate = (to) => {
21+
if (to === path) return
22+
window.history.pushState({}, '', to)
23+
setPath(to)
24+
}
25+
return { path, navigate }
26+
}
27+
28+
// Note: We avoid adding a router dependency; navigation is handled in App.
29+
30+
// Right rail removed; replaced with left sidebar nav
31+
32+
function HomeContent({ onNavigate }) {
433
return (
5-
<>
6-
<nav style={{ position: 'fixed', top: 16, right: 16 }}>
7-
<Button color="wesley" variant="filled" size="md" radius="md">
8-
Wesley
9-
</Button>
10-
</nav>
34+
<Box>
35+
<HeroBullets onNavigate={onNavigate} />
36+
<FeaturesTitleWesley />
37+
<FeaturesCardsWesley />
38+
<GettingStarted />
39+
<FutureSection />
40+
</Box>
41+
)
42+
}
1143

12-
<Container size="sm" p="xl">
13-
<Stack gap="md" align="center">
14-
<Title order={1}>Wesley</Title>
15-
<Text c="dimmed">Minimal Mantine Lite™ starter</Text>
16-
</Stack>
17-
</Container>
18-
</>
44+
function App() {
45+
const { path, navigate } = usePath()
46+
47+
return (
48+
<Box style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
49+
<HeaderSearch onNavigate={navigate} />
50+
<Box style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>
51+
{path === '/docs' ? (
52+
<Documentation />
53+
) : path === '/theme-lab' ? (
54+
<ThemeLab />
55+
) : (
56+
<HomeContent onNavigate={navigate} />
57+
)}
58+
</Box>
59+
<FooterLinks />
60+
</Box>
1961
)
2062
}
2163

wesley-website/src/App.test.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { render, screen } from '@testing-library/react'
22
import { MantineProvider } from '@mantine/core'
3-
import { theme } from './theme'
43
import App from './App'
54

65
describe('App', () => {
7-
it('renders a single Wesley button in the nav', () => {
6+
it('renders the Wesley hero title', () => {
87
render(
9-
<MantineProvider theme={theme} defaultColorScheme="light">
8+
<MantineProvider defaultColorScheme="light">
109
<App />
1110
</MantineProvider>
1211
)
1312

14-
const btn = screen.getByRole('button', { name: /wesley/i })
15-
expect(btn).toBeInTheDocument()
13+
// Pick the hero H1 specifically to avoid matching other "Wesley" headings
14+
const heading = screen.getByRole('heading', { level: 1 })
15+
expect(heading).toBeInTheDocument()
16+
expect(heading).toHaveTextContent(/wesley/i)
1617
})
1718
})
18-
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Badge, Card, Container, Group, SimpleGrid, Text, Title } from '@mantine/core'
2+
import classes from './FeaturesCardsWesley.module.css'
3+
4+
const tech = [
5+
{
6+
title: 'Directive‑Driven Design',
7+
description:
8+
'GraphQL directives encode database semantics (indexes, FKs, defaults). The compiler turns intent into concrete DDL.',
9+
icon: '📑',
10+
},
11+
{
12+
title: 'Event‑Sourced Generation',
13+
description:
14+
'Every transformation emits events you can observe, extend, or replay for custom outputs.',
15+
icon: '📡',
16+
},
17+
{
18+
title: 'Hexagonal Architecture',
19+
description:
20+
'A dependency‑free core with adapters for platforms and outputs keeps it portable and testable.',
21+
icon: '⬡',
22+
},
23+
{
24+
title: 'Command Pattern',
25+
description:
26+
'All operations are replayable commands — perfect for time‑travel, audits, and determinism.',
27+
icon: '⌁',
28+
},
29+
{
30+
title: 'Platform Abstraction',
31+
description:
32+
'Run anywhere: Node, Deno, Browser, Edge. Outputs are decoupled from execution.',
33+
icon: '🧭',
34+
},
35+
]
36+
37+
export default function FeaturesCardsWesley() {
38+
const features = tech.map((feature) => (
39+
<Card key={feature.title} shadow="md" radius="md" className={classes.card} padding="xl">
40+
<div style={{ fontSize: 40 }} aria-hidden>{feature.icon}</div>
41+
<Text fz="lg" fw={600} className={classes.cardTitle} mt="md">
42+
{feature.title}
43+
</Text>
44+
<Text fz="sm" c="dimmed" mt="sm">
45+
{feature.description}
46+
</Text>
47+
</Card>
48+
))
49+
50+
return (
51+
<Container size="lg" py="xl" id="how">
52+
<Group justify="center">
53+
<Badge variant="filled" size="lg">
54+
HOW IT WORKS
55+
</Badge>
56+
</Group>
57+
58+
<Title order={2} className={classes.title} ta="center" mt="sm">
59+
Under the hood — the Wesley engine
60+
</Title>
61+
62+
<Text c="dimmed" className={classes.description} ta="center" mt="md">
63+
Not just a generator — a rethinking of the data layer. Encode intent with directives, then
64+
project that intent into concrete systems.
65+
</Text>
66+
67+
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="xl" mt={50}>
68+
{features}
69+
</SimpleGrid>
70+
</Container>
71+
)
72+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.title {
2+
font-size: 28px;
3+
font-weight: 700;
4+
line-height: 1.2;
5+
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
6+
}
7+
8+
.description {
9+
max-width: 56ch;
10+
margin-left: auto;
11+
margin-right: auto;
12+
}
13+
14+
.card {
15+
background-color: var(--mantine-color-body);
16+
}
17+
18+
.cardTitle {
19+
line-height: 1.2;
20+
}
21+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Grid, SimpleGrid, Text, ThemeIcon, Title } from '@mantine/core'
2+
import classes from './FeaturesTitleWesley.module.css'
3+
4+
const items = [
5+
{
6+
icon: '🚨',
7+
title: 'The Problem',
8+
description:
9+
'Every developer writes the same data shape 5+ times: SQL DDL, GraphQL, TypeScript, Zod, JSON Schema. It’s error‑prone and wasteful.',
10+
},
11+
{
12+
icon: '✅',
13+
title: 'The Solution',
14+
description:
15+
'GraphQL is the single source of truth. Everything else is generated — types, migrations, APIs, and docs.',
16+
},
17+
{
18+
icon: '📐',
19+
title: 'The Philosophy',
20+
description:
21+
'Schema first. Migrations are diffs, not a task. Evolve your schema and get migrations for free.',
22+
},
23+
{
24+
icon: '🎯',
25+
title: 'Why This Matters',
26+
description:
27+
'Write once, generate everywhere. Teams review the schema (the contract) and ship with fewer sync bugs.',
28+
},
29+
]
30+
31+
export default function FeaturesTitleWesley() {
32+
const features = items.map((feature) => (
33+
<div key={feature.title}>
34+
<ThemeIcon size={44} radius="md" variant="gradient" gradient={{ deg: 133, from: 'blue', to: 'cyan' }}>
35+
<span aria-hidden style={{ fontSize: 22, lineHeight: 1 }}>{feature.icon}</span>
36+
</ThemeIcon>
37+
<Text fz="lg" mt="sm" fw={600}>
38+
{feature.title}
39+
</Text>
40+
<Text c="dimmed" fz="sm">
41+
{feature.description}
42+
</Text>
43+
</div>
44+
))
45+
46+
return (
47+
<div className={classes.wrapper} id="why">
48+
<Grid gutter={80}>
49+
<Grid.Col span={{ base: 12, md: 5 }}>
50+
<Title className={classes.title} order={2}>
51+
Why Wesley?
52+
</Title>
53+
<Text c="dimmed">
54+
Stop duplicating your data layer. Use GraphQL as the canonical schema and let Wesley
55+
generate the rest. Faster iteration, fewer bugs, happier teams.
56+
</Text>
57+
</Grid.Col>
58+
<Grid.Col span={{ base: 12, md: 7 }}>
59+
<SimpleGrid cols={{ base: 1, md: 2 }} spacing={30}>
60+
{features}
61+
</SimpleGrid>
62+
</Grid.Col>
63+
</Grid>
64+
</div>
65+
)
66+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.wrapper {
2+
padding: calc(var(--mantine-spacing-xl) * 2) var(--mantine-spacing-xl);
3+
}
4+
5+
.title {
6+
font-family: var(--mantine-font-family);
7+
font-size: 36px;
8+
font-weight: 600;
9+
line-height: 1.1;
10+
margin-bottom: var(--mantine-spacing-md);
11+
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
12+
}
13+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { ActionIcon, Box, Container, Group, Text, Title } from '@mantine/core'
2+
import classes from './FooterLinks.module.css'
3+
4+
const data = [
5+
{
6+
title: 'About',
7+
links: [
8+
{ label: 'Features', link: '#' },
9+
{ label: 'Pricing', link: '#' },
10+
{ label: 'Support', link: '#' },
11+
{ label: 'Forums', link: '#' },
12+
],
13+
},
14+
{
15+
title: 'Project',
16+
links: [
17+
{ label: 'Contribute', link: '#' },
18+
{ label: 'Media assets', link: '#' },
19+
{ label: 'Changelog', link: '#' },
20+
{ label: 'Releases', link: '#' },
21+
],
22+
},
23+
{
24+
title: 'Community',
25+
links: [
26+
{ label: 'Join Discord', link: '#' },
27+
{ label: 'Follow on Twitter', link: '#' },
28+
{ label: 'Email newsletter', link: '#' },
29+
{ label: 'GitHub discussions', link: '#' },
30+
],
31+
},
32+
]
33+
34+
export default function FooterLinks() {
35+
const groups = data.map((group) => {
36+
const links = group.links.map((link, index) => (
37+
<Text
38+
key={index}
39+
className={classes.link}
40+
component="a"
41+
href={link.link}
42+
onClick={(event) => event.preventDefault()}
43+
>
44+
{link.label}
45+
</Text>
46+
))
47+
48+
return (
49+
<div className={classes.wrapper} key={group.title}>
50+
<Text className={classes.title}>{group.title}</Text>
51+
{links}
52+
</div>
53+
)
54+
})
55+
56+
return (
57+
<footer className={classes.footer}>
58+
<Container className={classes.inner}>
59+
<div className={classes.logo}>
60+
<img src="/wesley-logo.jpg" alt="Wesley logo" style={{ display: 'block', width: 160, height: 'auto' }} />
61+
<Text size="xs" c="dimmed" className={classes.description}>
62+
Build fully functional accessible web applications faster than ever
63+
</Text>
64+
</div>
65+
<div className={classes.groups}>{groups}</div>
66+
</Container>
67+
<Container className={classes.afterFooter}>
68+
<Text c="dimmed" size="sm">
69+
© {new Date().getFullYear()} wesley.dev. All rights reserved.
70+
</Text>
71+
72+
<Group gap={0} className={classes.social} justify="flex-end" wrap="nowrap">
73+
{/* Social icons as placeholders to keep dependencies minimal */}
74+
<ActionIcon size="lg" color="gray" variant="subtle" aria-label="Twitter">
75+
<Box component="span" aria-hidden>𝕏</Box>
76+
</ActionIcon>
77+
<ActionIcon size="lg" color="gray" variant="subtle" aria-label="YouTube">
78+
<Box component="span" aria-hidden>▶︎</Box>
79+
</ActionIcon>
80+
<ActionIcon size="lg" color="gray" variant="subtle" aria-label="Instagram">
81+
<Box component="span" aria-hidden></Box>
82+
</ActionIcon>
83+
</Group>
84+
</Container>
85+
</footer>
86+
)
87+
}

0 commit comments

Comments
 (0)