Skip to content

Commit c4a1a8b

Browse files
authored
Merge pull request #41 from PureStackStudio/improve-doc-content-readability
Improve frontend documentation readability
2 parents ba6e346 + 2b0f247 commit c4a1a8b

51 files changed

Lines changed: 1868 additions & 134 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎frontend/README.md‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,30 @@ palette variables. Page-specific layout and decorative styles use `styleBuilder`
7272
and `themes.forEach`, with framework breakpoint tokens. They are emitted into
7373
`site.css` and `site.dark.css`; there is no separate handwritten CSS asset.
7474

75-
To change the identity, edit the hues in `theme/studioSkinShared.ts`. To add a
75+
The palette icon before the theme toggle offers Cobalt, Violet, Teal, Emerald,
76+
Amber, and Rose. Edit `theme/studioColorPresets.ts` to adjust each complete color
77+
family: neutrals, accents, companion colors, and semantic roles. Each preset
78+
coordinates page backgrounds, reading surfaces, text, borders, controls, shadows,
79+
and highlights in both modes. Status colors retain their familiar meanings.
80+
`theme/studioSurfaceProfiles.ts` defines each preset's lightness steps for the
81+
page, cards, inset surfaces, and controls, plus border strength, saturation, and
82+
shadow density. Dark presets range from crisp slate to a brighter warm studio.
83+
Documentation derives its colors from these same roles, so its code panels and
84+
copy controls keep their own layers instead of sharing one flat reading surface.
85+
`theme/studioLandingColors.ts` keeps the landing page's original light-paper and
86+
deep-slate brightness while applying the selected color family's hues. Its
87+
palette overrides stay within the studio template; documentation retains each
88+
preset's distinct layer contrast. The initial background style uses the same
89+
template-specific palette before the full stylesheets load.
90+
`studioColorStyles.ts` emits the changed palette variables and documentation
91+
color variables. A tiny inline startup script before the
92+
stylesheet links restores `purestack-site-color` from local storage. The picker
93+
uses the normal `PageScript` asset pipeline for its separately bundled runtime,
94+
supports native radio keyboard controls, and follows changes from other tabs.
95+
If storage is unavailable, the choice still applies for the current visit.
96+
97+
To change a selectable identity, edit its preset; `theme/studioSkinShared.ts`
98+
defines the skin's baseline hues and shared typography. To add a
7699
reusable section,
77100
compose existing primitives in its own file under `components/`, register its
78101
definition in `studioComponents.ts`, and register only the extra layout styles
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { defineComponent, html } from 'regor'
2+
import { studioColorPresets } from '../theme/studioColorPresets'
3+
4+
const template = html`<details class="studio-color-picker">
5+
<summary class="studio-color-picker__trigger" aria-label="Site color" title="Choose site color">
6+
<Icon name="tabler:palette" aria-hidden="true"/>
7+
</summary>
8+
<fieldset class="studio-color-picker__panel">
9+
<legend>Site color</legend>
10+
<p>Choose your site’s color palette.</p>
11+
<div class="studio-color-picker__options">
12+
${studioColorPresets.map(renderColorOption).join('')}
13+
</div>
14+
<span class="studio-color-picker__note">Saved on this device.</span>
15+
</fieldset>
16+
</details><PageScript src="/color-picker.ts"/>`
17+
18+
export function defineStudioColorPickerComponent() {
19+
return defineComponent(template)
20+
}
21+
22+
function renderColorOption(preset: (typeof studioColorPresets)[number]) {
23+
return html`<label class="studio-color-picker__option" data-site-color-option="${preset.id}">
24+
<input type="radio" name="studio-site-color" value="${preset.id}"/>
25+
<span class="studio-color-picker__swatch" aria-hidden="true"><Icon name="tabler:check"/></span>
26+
<span>${preset.label}</span>
27+
</label>`
28+
}

‎frontend/components/studioComponents.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { defineStudioActivityChartComponent } from './studioActivityChart'
22
import { defineStudioBrandComponent } from './studioBrand'
33
import { defineStudioCommandComponent } from './studioCommand'
4+
import { defineStudioColorPickerComponent } from './studioColorPicker'
45
import { defineStudioCopyComponent } from './studioCopy'
56
import { defineStudioFaqComponent } from './studioFaq'
67
import { defineStudioFeatureComponent } from './studioFeature'
@@ -11,6 +12,7 @@ import { defineStudioWorkbenchComponent } from './studioWorkbench'
1112
export function defineStudioComponents() {
1213
return {
1314
studioBrand: defineStudioBrandComponent(),
15+
studioColorPicker: defineStudioColorPickerComponent(),
1416
studioFeature: defineStudioFeatureComponent(),
1517
studioPackage: defineStudioPackageComponent(),
1618
studioRegorConnection: defineStudioRegorConnectionComponent(),
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/** Add native section permalinks without changing headings in live examples. */
2+
export function addDocumentationLinks(document: Document) {
3+
if (!document.body.classList.contains('template-doc')) return
4+
if (document.body.classList.contains('preview')) return
5+
const article = document.querySelector('.doc-main > .doc-content')
6+
if (!article) return
7+
8+
for (const heading of article.children) {
9+
if (!['H2', 'H3'].includes(heading.tagName) || !heading.id) continue
10+
if (heading.querySelector('a')) continue
11+
const link = document.createElement('a')
12+
link.className = 'doc-heading-link'
13+
link.setAttribute('href', `#${encodeURIComponent(heading.id)}`)
14+
link.setAttribute('aria-label', `Link to ${heading.textContent?.trim()}`)
15+
link.setAttribute('title', 'Link to this section')
16+
link.setAttribute('data-pagefind-ignore', '')
17+
link.textContent = '#'
18+
heading.appendChild(link)
19+
}
20+
}

‎frontend/docs/previewTemplate.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ const frameScript = `
2929
document.querySelectorAll('.site-guide-sample details.sign-in').forEach(menu=>menu.open=true);
3030
document.querySelectorAll('.site-guide-sample .consent__banner').forEach(banner=>{banner.hidden=false;banner.removeAttribute('aria-hidden')});
3131
if(window.parent!==window){
32-
const sync=()=>{document.documentElement.dataset.theme=parent.document.documentElement.dataset.theme||'light';document.documentElement.setAttribute('data-theme-ready','true')};
32+
const sync=()=>{document.documentElement.dataset.theme=parent.document.documentElement.dataset.theme||'light';document.documentElement.dataset.siteColor=parent.document.documentElement.dataset.siteColor||'cobalt';document.documentElement.setAttribute('data-theme-ready','true')};
3333
sync();
34-
new MutationObserver(sync).observe(parent.document.documentElement,{attributes:true,attributeFilter:['data-theme']});
34+
new MutationObserver(sync).observe(parent.document.documentElement,{attributes:true,attributeFilter:['data-theme','data-site-color']});
3535
const minimumHeight=frameElement ? parseFloat(frameElement.style.height)||0 : 0;
3636
const resize=()=>{if(frameElement)frameElement.style.height=Math.max(minimumHeight,Math.ceil(document.body.getBoundingClientRect().height))+'px'};
3737
new ResizeObserver(resize).observe(document.body);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
DEFAULT_SITE_COLOR,
3+
isSiteColor,
4+
SITE_COLOR_STORAGE_KEY,
5+
studioColorPresets,
6+
type SiteColor,
7+
} from '../theme/studioColorPresets'
8+
9+
const root = document.documentElement
10+
const pickerSelector = '.studio-color-picker'
11+
12+
function applyColor(color: SiteColor) {
13+
root.dataset.siteColor = color
14+
const label = studioColorPresets.find((preset) => preset.id === color)?.label
15+
for (const picker of document.querySelectorAll<HTMLDetailsElement>(
16+
pickerSelector,
17+
)) {
18+
picker
19+
.querySelector('summary')
20+
?.setAttribute('aria-label', `Site color: ${label}`)
21+
for (const input of picker.querySelectorAll<HTMLInputElement>(
22+
'input[type="radio"]',
23+
)) {
24+
input.checked = input.value === color
25+
}
26+
}
27+
}
28+
29+
function saveColor(color: SiteColor) {
30+
applyColor(color)
31+
let message = 'Saved on this device.'
32+
try {
33+
localStorage.setItem(SITE_COLOR_STORAGE_KEY, color)
34+
} catch {
35+
message = 'Applied for this visit.'
36+
}
37+
for (const note of document.querySelectorAll('.studio-color-picker__note')) {
38+
note.textContent = message
39+
}
40+
}
41+
42+
function closePickers(returnFocus = false) {
43+
for (const picker of document.querySelectorAll<HTMLDetailsElement>(
44+
`${pickerSelector}[open]`,
45+
)) {
46+
picker.open = false
47+
if (returnFocus) picker.querySelector('summary')?.focus()
48+
}
49+
}
50+
51+
document.addEventListener('change', (event) => {
52+
const input = event.target
53+
if (!(input instanceof HTMLInputElement) || !input.closest(pickerSelector))
54+
return
55+
if (isSiteColor(input.value)) saveColor(input.value)
56+
})
57+
58+
document.addEventListener('click', (event) => {
59+
if (event.target instanceof Element && !event.target.closest(pickerSelector))
60+
closePickers()
61+
})
62+
63+
document.addEventListener('keydown', (event) => {
64+
if (event.key === 'Escape') closePickers(true)
65+
})
66+
67+
window.addEventListener('storage', (event) => {
68+
if (event.key !== SITE_COLOR_STORAGE_KEY && event.key !== null) return
69+
applyColor(isSiteColor(event.newValue) ? event.newValue : DEFAULT_SITE_COLOR)
70+
})
71+
72+
const initial = root.dataset.siteColor
73+
applyColor(isSiteColor(initial) ? initial : DEFAULT_SITE_COLOR)

‎frontend/purestack.studio/components/header.mdx‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
1-
<TopBar tone="neutral" variant="glass" class="spotlight-from-top-right">
1+
<TopBar tone="neutral" variant="surface">
2+
<template #before-actions><StudioColorPicker/></template>
23
<template #actions>
3-
<a class="topbar__icon" href="https://github.com/PureStackStudio/PureStack" target="_blank" rel="noopener" aria-label="PureStack GitHub repository">
4+
<a
5+
class="topbar__icon"
6+
href="https://github.com/PureStackStudio/PureStack"
7+
target="_blank"
8+
rel="noopener"
9+
aria-label="PureStack GitHub repository"
10+
>
411
<Icon name="tabler:brand-github"/>
512
</a>
6-
<a class="topbar__icon" href="https://regor.purestack.studio" target="_blank" rel="noopener" aria-label="Regor website">
13+
<a
14+
class="topbar__icon"
15+
href="https://regor.purestack.studio"
16+
target="_blank"
17+
rel="noopener"
18+
aria-label="Regor website"
19+
>
720
<Icon name="lucide:orbit"/>
821
</a>
9-
<a class="topbar__icon" href="https://x.com/purestackstudio" target="_blank" rel="noopener" aria-label="PureStack Studio on X">
22+
<a
23+
class="topbar__icon"
24+
href="https://x.com/purestackstudio"
25+
target="_blank"
26+
rel="noopener"
27+
aria-label="PureStack Studio on X"
28+
>
1029
<Icon name="tabler:brand-x"/>
1130
</a>
1231
</template>

‎frontend/purestack.studio/components/index.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ nav:
1515

1616
Explore all 67 public components and browser entry points. Each guide brings together working examples, the source behind them, behavior guidance and a focused API reference.
1717

18-
<Panel tone="accent" variant="surface" bodyClass="p-4">
18+
<Panel tone="accent" variant="surface" bodyClass="p-4" class="mb-5">
1919
<SectionHeader
2020
title="Find the right piece"
2121
titleTag="h2"

‎frontend/purestack.studio/components/site/top-bar/top-bar.mdx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ TopBar renders a fixed doc-nav-toggle ID and should appear once per document. It
231231

232232
<div class="api-contract">
233233
<p>
234-
Use the actions slot to add links or controls beside the theme toggle.
234+
Use the before-actions slot to add controls before the theme toggle, and
235+
the actions slot to add links or controls after it.
235236
Register defineTopBarComponents and the selected logo component,
236237
SearchBox, ThemeToggle, SignIn, Flex and Icon families. Standard SSG
237238
registration provides these dependencies.

‎frontend/purestack.studio/guides/header.mdx‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
1-
<TopBar tone="neutral" variant="glass" class="spotlight-from-top-right">
1+
<TopBar tone="neutral" variant="surface">
2+
<template #before-actions><StudioColorPicker/></template>
23
<template #actions>
3-
<a class="topbar__icon" href="https://github.com/PureStackStudio/PureStack" target="_blank" rel="noopener" aria-label="PureStack GitHub repository">
4+
<a
5+
class="topbar__icon"
6+
href="https://github.com/PureStackStudio/PureStack"
7+
target="_blank"
8+
rel="noopener"
9+
aria-label="PureStack GitHub repository"
10+
>
411
<Icon name="tabler:brand-github"/>
512
</a>
6-
<a class="topbar__icon" href="https://regor.purestack.studio" target="_blank" rel="noopener" aria-label="Regor website">
13+
<a
14+
class="topbar__icon"
15+
href="https://regor.purestack.studio"
16+
target="_blank"
17+
rel="noopener"
18+
aria-label="Regor website"
19+
>
720
<Icon name="lucide:orbit"/>
821
</a>
9-
<a class="topbar__icon" href="https://x.com/purestackstudio" target="_blank" rel="noopener" aria-label="PureStack Studio on X">
22+
<a
23+
class="topbar__icon"
24+
href="https://x.com/purestackstudio"
25+
target="_blank"
26+
rel="noopener"
27+
aria-label="PureStack Studio on X"
28+
>
1029
<Icon name="tabler:brand-x"/>
1130
</a>
1231
</template>

0 commit comments

Comments
 (0)