Skip to content

Commit 8d3ec19

Browse files
committed
Add core, pages, and shell stylesheets with comprehensive design system
- Introduced core.css for foundational styles including font definitions and CSS variables for theming. - Created pages.css to define layout and styling for various page components, enhancing visual hierarchy and responsiveness. - Implemented shell.css for site header, navigation, and footer styles, ensuring a cohesive user experience across the application.
1 parent 0dc5c86 commit 8d3ec19

11 files changed

Lines changed: 505 additions & 992 deletions

File tree

src/components/doc-layout.tsx

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { state } from '@askrjs/askr';
12
import { currentRoute } from '@askrjs/askr/router';
23
import { BookOpenIcon } from '@askrjs/lucide';
34
import { Separator } from '../ui/primitives/separator';
@@ -12,7 +13,6 @@ import {
1213
} from '../pages/shared/content';
1314
import { SiteAnchor } from './site-link';
1415
import { SiteFrame } from './site-shell';
15-
import { BrandMark } from './site-primitives';
1616

1717
export interface DocLayoutProps extends Props {
1818
title: string;
@@ -21,6 +21,17 @@ export interface DocLayoutProps extends Props {
2121
children?: unknown;
2222
}
2323

24+
function toggleDocsNavigation() {
25+
if (typeof document === 'undefined') return;
26+
27+
const sidebar = document.querySelector('.docs-sidebar');
28+
const button = document.querySelector('.docs-mobile-nav-toggle');
29+
const nextOpen = button?.getAttribute('aria-expanded') !== 'true';
30+
31+
sidebar?.classList.toggle('is-open', nextOpen);
32+
button?.setAttribute('aria-expanded', nextOpen ? 'true' : 'false');
33+
}
34+
2435
function renderSidebarItem(item: DocsNavItem, currentPath: string) {
2536
const current = currentPath === item.href;
2637

@@ -116,6 +127,23 @@ export function DocLayout(props: DocLayoutProps) {
116127
const currentItem = props.meta
117128
? findDocsNavItemBySlug(props.meta.slug)
118129
: null;
130+
const [searchQuery, setSearchQuery] = state('');
131+
132+
const query = searchQuery().trim().toLowerCase();
133+
const filteredSections = docsNavSections
134+
.map((section) => ({
135+
...section,
136+
items: section.items.filter((item) => {
137+
if (!query) return true;
138+
const summary = item.description?.toLowerCase() ?? '';
139+
return (
140+
item.label.toLowerCase().includes(query) ||
141+
item.slug.toLowerCase().includes(query) ||
142+
summary.includes(query)
143+
);
144+
}),
145+
}))
146+
.filter((section) => section.items.length > 0);
119147

120148
const toc = props.meta?.toc;
121149
const hasToc = toc && toc.length > 0;
@@ -126,24 +154,52 @@ export function DocLayout(props: DocLayoutProps) {
126154
<div class={hasToc ? 'docs-shell has-toc' : 'docs-shell'}>
127155
<aside class="docs-sidebar">
128156
<div class="docs-sidebar-inner">
129-
<SiteAnchor href="/docs" className="docs-sidebar-home">
130-
<BrandMark compact />
131-
<span class="docs-sidebar-kicker">
132-
Documentation control room
133-
</span>
134-
</SiteAnchor>
157+
<span class="docs-sidebar-kicker">Documentation control room</span>
158+
<button
159+
class="docs-mobile-nav-toggle"
160+
type="button"
161+
aria-expanded="false"
162+
onClick={toggleDocsNavigation}
163+
>
164+
Browse docs sections
165+
</button>
166+
<label class="docs-sidebar-search" for="docs-search">
167+
<span>Search docs</span>
168+
<input
169+
id="docs-search"
170+
type="search"
171+
placeholder="Filter pages, guides, and references"
172+
value={searchQuery}
173+
onInput={(event) => {
174+
const target = event.currentTarget as HTMLInputElement;
175+
setSearchQuery(target.value);
176+
}}
177+
/>
178+
</label>
135179
<Separator class="docs-rule" decorative />
136180
<nav class="docs-sidebar-nav">
137-
{docsNavSections.map((section) =>
181+
{filteredSections.map((section) =>
138182
renderSidebarSection(section, currentPath)
139183
)}
184+
{!filteredSections.length ? (
185+
<p class="docs-sidebar-empty">No docs pages match that search.</p>
186+
) : null}
140187
</nav>
141188
</div>
142189
</aside>
143190

144191
<main class="docs-main">
145192
<div class="docs-main-inner">
146193
<header class="docs-header">
194+
{currentItem ? (
195+
<nav class="docs-breadcrumb" aria-label="Breadcrumb">
196+
<SiteAnchor href="/docs">Docs</SiteAnchor>
197+
<span>/</span>
198+
<span>{currentItem.section}</span>
199+
<span>/</span>
200+
<span aria-current="page">{currentItem.label}</span>
201+
</nav>
202+
) : null}
147203
<div class="docs-header-meta">
148204
<span class="docs-kicker docs-header-kicker">
149205
<BookOpenIcon size={15} />

src/pages/home/index.tsx

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ export function HomePage() {
170170
<SiteFrame>
171171
<main class="site-main home-main">
172172
<SignalHero
173-
eyebrow="Precision reactive UI"
174-
title="Askr"
175-
intro="A fine-grained framework for static sites, apps, and docs that stay explainable from the first route to production output."
173+
eyebrow="Serious infrastructure for developers"
174+
title="Ask better questions."
175+
intro="Type-safe interactive workflows for modern TypeScript applications. Keep rendering explicit, routing predictable, and output production-ready from first commit to deployment."
176176
primary={{
177177
href: docsStartPath,
178178
label: 'Start building',
@@ -200,24 +200,24 @@ export function HomePage() {
200200
/>
201201

202202
<SectionBand
203-
kicker="Route to release"
204-
title="A single path from first page to static output"
205-
description="Every marketing claim has a matching guide, route, or code artifact. The site teaches the same architecture it uses."
203+
kicker="Problem"
204+
title="Most stacks hide intent as complexity grows"
205+
description="Teams lose confidence when state, routing, and delivery paths diverge. Askr keeps the operational model visible so product decisions stay auditable."
206206
>
207207
<LaunchRail steps={launchPath} />
208208
</SectionBand>
209209

210210
<SectionBand
211-
kicker="How it works"
212-
title="Reactivity, routing, and theme tokens in one model"
213-
description="Askr keeps the moving parts explicit: state updates stay local, routes can render three ways, and theme tokens carry the visual system."
211+
kicker="Solution"
212+
title="One coherent model across runtime and output"
213+
description="Fine-grained reactivity, route orchestration, and theme primitives stay connected. You can trace what changed, why it changed, and where it ships."
214214
>
215215
<ArchitecturePass nodes={architecturePass} />
216216
</SectionBand>
217217

218218
<section class="build-confidence">
219219
<div>
220-
<span class="section-kicker">Build with proof</span>
220+
<span class="section-kicker">Developer experience</span>
221221
<h2>{model.featureSection.title}</h2>
222222
<p>{model.featureSection.description}</p>
223223
</div>
@@ -248,12 +248,11 @@ export function HomePage() {
248248
))}
249249

250250
<section class="home-final">
251-
<span class="section-kicker">Next move</span>
252-
<h2>Start with one route, then keep the system honest.</h2>
251+
<span class="section-kicker">Production readiness</span>
252+
<h2>Ship with a system your team can defend.</h2>
253253
<p>
254-
The fastest way to evaluate Askr is to install the stack, render a
255-
first page, and inspect how little framework machinery sits
256-
between state and output.
254+
Validate the architecture quickly: install once, render a working
255+
route, then inspect the exact path from state to final output.
257256
</p>
258257
<div class="home-confidence-grid">
259258
<SiteAnchor href={docsStartPath} className="home-confidence-link">

src/pages/themes-landing/index.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
PaletteIcon,
66
SunIcon,
77
} from '@askrjs/lucide';
8+
import { Button } from '@askrjs/themes/controls';
89

910
import { SiteFrame } from '../../components/site-shell';
1011
import { SiteAnchor } from '../../components/site-link';
@@ -76,6 +77,16 @@ const themeCode = `:root {
7677
border: 1px solid var(--ak-color-border);
7778
}`;
7879

80+
function setTheme(nextTheme: 'light' | 'dark') {
81+
if (typeof document === 'undefined') return;
82+
83+
document.documentElement.setAttribute('data-theme', nextTheme);
84+
85+
if (typeof localStorage !== 'undefined') {
86+
localStorage.setItem('theme', nextTheme);
87+
}
88+
}
89+
7990
export function ThemesLandingPage() {
8091
return (
8192
<SiteFrame>
@@ -104,14 +115,20 @@ export function ThemesLandingPage() {
104115
</div>
105116
<div class="theme-lab" aria-label="Theme token lab">
106117
<div class="theme-lab-modes">
107-
<span>
118+
<Button
119+
className="theme-lab-mode theme-lab-mode-light"
120+
onPress={() => setTheme('light')}
121+
>
108122
<SunIcon size={16} />
109123
light
110-
</span>
111-
<span>
124+
</Button>
125+
<Button
126+
className="theme-lab-mode theme-lab-mode-dark"
127+
onPress={() => setTheme('dark')}
128+
>
112129
<MoonIcon size={16} />
113130
dark
114-
</span>
131+
</Button>
115132
</div>
116133
<div class="theme-lab-card">
117134
<strong>token layer</strong>

src/styles.css

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
@import './styles/foundation.css';
2-
@import './styles/layout.css';
3-
@import './styles/marketing.css';
4-
@import './styles/catalog.css';
1+
@import './styles/core.css';
2+
@import './styles/shell.css';
3+
@import './styles/pages.css';
4+
@import './styles/components.css';
55
@import './styles/docs.css';
66
@import './styles/responsive.css';
7-
@import './styles/apple-polish.css';

0 commit comments

Comments
 (0)