173 lines
4.4 KiB
TypeScript
173 lines
4.4 KiB
TypeScript
import { define } from '../../src'
|
|
import { theme } from './themes'
|
|
|
|
export const Body = define('Body', {
|
|
base: 'body',
|
|
|
|
margin: 0,
|
|
padding: theme('spacing-xl'),
|
|
fontFamily: theme('fonts-mono'),
|
|
background: theme('colors-bg'),
|
|
color: theme('colors-fg'),
|
|
})
|
|
|
|
const Container = define('Container', {
|
|
maxWidth: 1200,
|
|
margin: '0 auto'
|
|
})
|
|
|
|
export const Header = define('Header', {
|
|
base: 'h1',
|
|
|
|
marginBottom: theme('spacing-xl'),
|
|
color: theme('colors-fg'),
|
|
fontSize: 28,
|
|
fontWeight: 400,
|
|
})
|
|
|
|
export const ExampleSection = define('ExampleSection', {
|
|
marginBottom: theme('spacing-xl'),
|
|
|
|
parts: {
|
|
Header: {
|
|
base: 'h2',
|
|
|
|
marginBottom: theme('spacing-md'),
|
|
color: theme('colors-fgMuted'),
|
|
fontSize: 16,
|
|
fontWeight: 400,
|
|
}
|
|
},
|
|
render({ props, parts: { Root, Header } }) {
|
|
return (
|
|
<Root>
|
|
<Header>{props.title}</Header>
|
|
{props.children}
|
|
</Root>
|
|
)
|
|
}
|
|
})
|
|
|
|
const Nav = define({
|
|
base: 'nav',
|
|
|
|
display: 'flex',
|
|
gap: theme('spacing-lg'),
|
|
marginBottom: theme('spacing-xl'),
|
|
padding: theme('spacing-lg'),
|
|
background: theme('colors-bgElevated'),
|
|
border: `1px solid ${theme('colors-border')}`,
|
|
borderRadius: theme('radius-sm'),
|
|
})
|
|
|
|
const NavLink = define({
|
|
base: 'a',
|
|
|
|
color: theme('colors-fgMuted'),
|
|
textDecoration: 'none',
|
|
fontSize: 14,
|
|
|
|
states: {
|
|
hover: {
|
|
color: theme('colors-fg'),
|
|
}
|
|
},
|
|
|
|
selectors: {
|
|
'&[aria-current]': {
|
|
color: theme('colors-fg'),
|
|
textDecoration: 'underline',
|
|
}
|
|
}
|
|
})
|
|
|
|
const ThemePicker = define('ThemePicker', {
|
|
marginLeft: 'auto',
|
|
|
|
parts: {
|
|
Select: {
|
|
base: 'select',
|
|
|
|
padding: `${theme('spacing-xs')} ${theme('spacing-md')}`,
|
|
background: theme('colors-bgElevated'),
|
|
border: `1px solid ${theme('colors-border')}`,
|
|
borderRadius: theme('radius-sm'),
|
|
color: theme('colors-fg'),
|
|
fontSize: 14,
|
|
cursor: 'pointer',
|
|
transition: 'all 0.2s ease',
|
|
|
|
states: {
|
|
':hover': {
|
|
borderColor: theme('colors-borderActive'),
|
|
},
|
|
':focus': {
|
|
outline: 'none',
|
|
borderColor: theme('colors-borderActive'),
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
render({ parts: { Root, Select } }) {
|
|
return (
|
|
<Root>
|
|
<Select id="theme-select" onchange="window.switchTheme(this.value)">
|
|
<option value="dark">Dark</option>
|
|
<option value="light">Light</option>
|
|
</Select>
|
|
</Root>
|
|
)
|
|
}
|
|
})
|
|
|
|
export const Layout = define({
|
|
render({ props }) {
|
|
const path = props.path || ''
|
|
|
|
const themeScript = `
|
|
function switchTheme(themeName) {
|
|
document.body.setAttribute('data-theme', themeName)
|
|
localStorage.setItem('theme', themeName)
|
|
}
|
|
|
|
window.switchTheme = switchTheme
|
|
|
|
// Load saved theme or default to dark
|
|
const savedTheme = localStorage.getItem('theme') || 'dark'
|
|
document.body.setAttribute('data-theme', savedTheme)
|
|
|
|
// Set initial select value
|
|
const select = document.getElementById('theme-select')
|
|
if (select) select.value = savedTheme
|
|
`
|
|
|
|
return (
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>{props.title}</title>
|
|
<link rel="stylesheet" href="/main.css" />
|
|
</head>
|
|
<Body>
|
|
<Container>
|
|
<Nav>
|
|
<NavLink href="/" aria-current={path === '/' ? 'page' : undefined}>Home</NavLink>
|
|
<NavLink href="/ssr" aria-current={path.startsWith('/ssr') && path !== '/ssr/profile' && path !== '/ssr/buttons' && path !== '/ssr/navigation' ? 'page' : undefined}>SSR Examples</NavLink>
|
|
<NavLink href="/ssr/profile" aria-current={path === '/ssr/profile' ? 'page' : undefined}>Profile</NavLink>
|
|
<NavLink href="/ssr/buttons" aria-current={path === '/ssr/buttons' ? 'page' : undefined}>Buttons</NavLink>
|
|
<NavLink href="/ssr/navigation" aria-current={path === '/ssr/navigation' ? 'page' : undefined}>Navigation</NavLink>
|
|
<NavLink href="/ssr/form" aria-current={path === '/ssr/form' ? 'page' : undefined}>Forms</NavLink>
|
|
<ThemePicker />
|
|
</Nav>
|
|
<Header>{props.title}</Header>
|
|
{props.children}
|
|
</Container>
|
|
<script dangerouslySetInnerHTML={{ __html: themeScript }}></script>
|
|
</Body>
|
|
</html>
|
|
)
|
|
}
|
|
})
|