@rxova/astro-ui 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/package.json +2 -2
- package/src/components/Header.astro +1 -1
- package/src/components/SectionNav.astro +26 -0
- package/src/components/SiteFooter.astro +14 -15
- package/src/components/ThemeToggle.astro +1 -1
- package/src/starlight/SocialIcons.astro +4 -4
- package/src/starlight/index.ts +1 -2
- package/src/styles/starlight.css +28 -0
- package/src/components/SiteShell.astro +0 -155
package/README.md
CHANGED
|
@@ -51,19 +51,19 @@ unlayered and would flatten a Starlight page.
|
|
|
51
51
|
|
|
52
52
|
## What's in it
|
|
53
53
|
|
|
54
|
-
| Export | What it is
|
|
55
|
-
| ------------------------------------------ |
|
|
56
|
-
| `@rxova/astro-ui/starlight` | `sharedStarlightConfig()`, the preset every docs site spreads
|
|
57
|
-
| `@rxova/astro-ui/starlight/*.astro` | The Starlight overrides: `SiteTitle`, `SocialIcons`, `Footer`, `ThemeSelect`
|
|
58
|
-
| `@rxova/astro-ui/components/*.astro` | Chrome (`
|
|
59
|
-
| `@rxova/astro-ui/components/icons/*.astro` | Glyphs in the `Icon` frame: `Prev`, `Next`, `Play`, `Pause`, `Replay`, `Expand`, `Collapse`
|
|
60
|
-
| `@rxova/astro-ui/scripts/show-more` | `enhanceShowMore()`: batches a `[data-reveal-list]` behind a `ShowMore`
|
|
61
|
-
| `@rxova/astro-ui/lib/entries` | Ordering, bylines, dates and excerpts shared by /blog and /updates
|
|
62
|
-
| `@rxova/astro-ui/styles/document.css` | For sites that own their document: `chrome.css`, a reset, base element styling
|
|
63
|
-
| `@rxova/astro-ui/styles/chrome.css` | What the header and footer need, with nothing document-level
|
|
64
|
-
| `@rxova/astro-ui/styles/starlight.css` | Maps `--rx-*` onto Starlight's `--sl-*`, plus the footer
|
|
65
|
-
| `@rxova/astro-ui/styles/landing.css` | The Starlight overrides a splash landing page needs; load it through `customCss`
|
|
66
|
-
| `@rxova/astro-ui/styles/mermaid.css` | Restyles `rehype-mermaid`'s build-time SVG with the tokens, so diagrams follow the theme
|
|
54
|
+
| Export | What it is |
|
|
55
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `@rxova/astro-ui/starlight` | `sharedStarlightConfig()`, the preset every docs site spreads |
|
|
57
|
+
| `@rxova/astro-ui/starlight/*.astro` | The Starlight overrides: `SiteTitle`, `SocialIcons`, `Footer`, `ThemeSelect` |
|
|
58
|
+
| `@rxova/astro-ui/components/*.astro` | Chrome (`Header`, `SiteFooter`, …), primitives (`PageHeader`, `BackLink`, `ShowMore`, `VisuallyHidden`, `Icon`) and the components in the gallery |
|
|
59
|
+
| `@rxova/astro-ui/components/icons/*.astro` | Glyphs in the `Icon` frame: `Prev`, `Next`, `Play`, `Pause`, `Replay`, `Expand`, `Collapse` |
|
|
60
|
+
| `@rxova/astro-ui/scripts/show-more` | `enhanceShowMore()`: batches a `[data-reveal-list]` behind a `ShowMore` |
|
|
61
|
+
| `@rxova/astro-ui/lib/entries` | Ordering, bylines, dates and excerpts shared by /blog and /updates |
|
|
62
|
+
| `@rxova/astro-ui/styles/document.css` | For sites that own their document: `chrome.css`, a reset, base element styling |
|
|
63
|
+
| `@rxova/astro-ui/styles/chrome.css` | What the header and footer need, with nothing document-level |
|
|
64
|
+
| `@rxova/astro-ui/styles/starlight.css` | Maps `--rx-*` onto Starlight's `--sl-*`, plus the footer |
|
|
65
|
+
| `@rxova/astro-ui/styles/landing.css` | The Starlight overrides a splash landing page needs; load it through `customCss` |
|
|
66
|
+
| `@rxova/astro-ui/styles/mermaid.css` | Restyles `rehype-mermaid`'s build-time SVG with the tokens, so diagrams follow the theme |
|
|
67
67
|
|
|
68
68
|
There is no barrel: each component has its own path, so a page only loads the
|
|
69
69
|
CSS of the components it imports.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rxova/astro-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Astro components, Starlight preset and shared chrome for rxova.org",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@rxova/brand": "^1.
|
|
49
|
+
"@rxova/brand": "^1.2.0",
|
|
50
50
|
"lucide-static": "^1.45.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
|
-
* The single rxova.org header, rendered by
|
|
3
|
+
* The single rxova.org header, rendered by the website's layout; callers pass
|
|
4
4
|
* the menu fully resolved. Not for the Starlight docs sites, which use `sharedStarlightConfig`.
|
|
5
5
|
*/
|
|
6
6
|
import ThemeToggle from './ThemeToggle.astro'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* The umbrella navigation for a docs site: the project switcher, then the rxova.org sections.
|
|
4
|
+
* Starlight shows it in the header bar on wide screens and in the menu on phones.
|
|
5
|
+
*/
|
|
6
|
+
import { RXOVA_ORIGIN, SECTIONS, type ProjectId } from '@rxova/brand'
|
|
7
|
+
import ProjectSwitcher from './ProjectSwitcher.astro'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
/** The project whose docs these are, marked in the switcher. */
|
|
11
|
+
current?: ProjectId
|
|
12
|
+
/** Prefix for the section links. '' links root-relative, for a build served on rxova.org. */
|
|
13
|
+
origin?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { current, origin = RXOVA_ORIGIN } = Astro.props
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<nav class="rx-sections" aria-label="rxova.org">
|
|
20
|
+
<ProjectSwitcher current={current} />
|
|
21
|
+
{SECTIONS.map((section) => (
|
|
22
|
+
<a class="rx-sections__link" href={`${origin}${section.path}`}>
|
|
23
|
+
{section.label}
|
|
24
|
+
</a>
|
|
25
|
+
))}
|
|
26
|
+
</nav>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
3
|
* The rxova footer on every surface: brand block, link columns, then copyright and legal links.
|
|
4
|
-
* Styles live in `../styles/footer.css
|
|
4
|
+
* Styles live in `../styles/footer.css`. Hrefs are absolute unless `origin` is '' (on rxova.org).
|
|
5
5
|
*/
|
|
6
|
-
import { PROJECTS, RXOVA_ORIGIN,
|
|
6
|
+
import { PROJECTS, RXOVA_ORIGIN, SECTIONS, getProject, type ProjectId } from '@rxova/brand'
|
|
7
7
|
|
|
8
8
|
/** A standalone surface of rxova.org, for the "Site" column. */
|
|
9
9
|
export interface SiteLink {
|
|
10
10
|
label: string
|
|
11
|
-
/**
|
|
11
|
+
/** A page URL ending in `/`: absolute, or root-relative when `origin` is ''. */
|
|
12
12
|
href: string
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -27,27 +27,26 @@ interface Props {
|
|
|
27
27
|
* Defaults to every project, which is right for a docs site.
|
|
28
28
|
*/
|
|
29
29
|
projects?: readonly SiteLink[]
|
|
30
|
+
/** Prefix for every rxova.org link. '' on rxova.org itself, so links stay on the serving origin. */
|
|
31
|
+
origin?: string
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
const { project, docs, site, projects } = Astro.props
|
|
34
|
+
const { project, docs, site, projects, origin = RXOVA_ORIGIN } = Astro.props
|
|
33
35
|
const self = project ? getProject(project) : undefined
|
|
34
36
|
const year = new Date().getFullYear()
|
|
35
37
|
|
|
36
38
|
const projectLinks: readonly SiteLink[] =
|
|
37
|
-
projects ?? PROJECTS.map((p) => ({ label: p.label, href: `${
|
|
39
|
+
projects ?? PROJECTS.map((p) => ({ label: p.label, href: `${origin}${p.mount}` }))
|
|
38
40
|
|
|
39
|
-
const surfaces: readonly SiteLink[] =
|
|
40
|
-
{ label:
|
|
41
|
-
{ label: 'Updates', href: siteUrl('/updates') },
|
|
42
|
-
{ label: 'About', href: siteUrl('/about') },
|
|
43
|
-
]
|
|
41
|
+
const surfaces: readonly SiteLink[] =
|
|
42
|
+
site ?? SECTIONS.map((section) => ({ label: section.label, href: `${origin}${section.path}` }))
|
|
44
43
|
---
|
|
45
44
|
|
|
46
45
|
<footer class="rx-footer">
|
|
47
46
|
<div class="rx-footer__top">
|
|
48
47
|
<div class="rx-footer__brand">
|
|
49
|
-
<a class="rx-footer__mark" href={
|
|
50
|
-
<img src={
|
|
48
|
+
<a class="rx-footer__mark" href={`${origin}/`}>
|
|
49
|
+
<img src={`${origin}/rxova-logo-256.png`} alt="" width="28" height="28" loading="lazy" />
|
|
51
50
|
<span>Rxova</span>
|
|
52
51
|
</a>
|
|
53
52
|
{/* Not "React libraries": most ship a framework-agnostic core; some are extensions/CLIs. */}
|
|
@@ -112,7 +111,7 @@ const surfaces: readonly SiteLink[] = site ?? [
|
|
|
112
111
|
<h2 class="rx-footer__title">Site</h2>
|
|
113
112
|
<ul class="rx-footer__list">
|
|
114
113
|
<li>
|
|
115
|
-
<a href={
|
|
114
|
+
<a href={`${origin}/`}>Home</a>
|
|
116
115
|
</li>
|
|
117
116
|
{surfaces.map((s) => (
|
|
118
117
|
<li>
|
|
@@ -142,8 +141,8 @@ const surfaces: readonly SiteLink[] = site ?? [
|
|
|
142
141
|
<div class="rx-footer__legal">
|
|
143
142
|
<p>© {year} Rxova · MIT licensed</p>
|
|
144
143
|
<div class="rx-footer__legal-links">
|
|
145
|
-
<a href={
|
|
146
|
-
<a href={
|
|
144
|
+
<a href={`${origin}/privacy/`}>Privacy</a>
|
|
145
|
+
<a href={`${origin}/terms/`}>Terms</a>
|
|
147
146
|
</div>
|
|
148
147
|
</div>
|
|
149
148
|
</footer>
|
|
@@ -59,7 +59,7 @@ const { floating = true } = Astro.props
|
|
|
59
59
|
position: fixed;
|
|
60
60
|
top: 1rem;
|
|
61
61
|
right: 1rem;
|
|
62
|
-
/* Above
|
|
62
|
+
/* Above the site's sticky header (z-index 10), so the fixed button stays reachable. */
|
|
63
63
|
z-index: 20;
|
|
64
64
|
width: 2.25rem;
|
|
65
65
|
height: 2.25rem;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
|
-
* Starlight `SocialIcons` override: the
|
|
4
|
-
*
|
|
3
|
+
* Starlight `SocialIcons` override: the umbrella navigation, then the stock icons. Starlight
|
|
4
|
+
* renders this slot in the header on wide screens and in the mobile menu, so one header serves both.
|
|
5
5
|
*/
|
|
6
6
|
import Default from '@astrojs/starlight/components/SocialIcons.astro'
|
|
7
|
-
import
|
|
7
|
+
import SectionNav from '../components/SectionNav.astro'
|
|
8
8
|
import { projectFromBase } from '@rxova/brand'
|
|
9
9
|
|
|
10
10
|
// Overrides receive no props, so the current project is inferred from the base
|
|
@@ -12,7 +12,7 @@ import { projectFromBase } from '@rxova/brand'
|
|
|
12
12
|
const current = projectFromBase(import.meta.env.BASE_URL)
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<
|
|
15
|
+
<SectionNav current={current} />
|
|
16
16
|
<Default>
|
|
17
17
|
<slot />
|
|
18
18
|
</Default>
|
package/src/starlight/index.ts
CHANGED
|
@@ -94,8 +94,7 @@ export function sharedStarlightConfig({
|
|
|
94
94
|
},
|
|
95
95
|
],
|
|
96
96
|
|
|
97
|
-
// Pagefind ships with Starlight
|
|
98
|
-
// journey was carrying.
|
|
97
|
+
// Pagefind ships with Starlight, so docs sites need no third-party search plugin.
|
|
99
98
|
pagefind: true,
|
|
100
99
|
|
|
101
100
|
sidebar,
|
package/src/styles/starlight.css
CHANGED
|
@@ -157,6 +157,34 @@ html[data-rxova-shell] .sl-menu-button {
|
|
|
157
157
|
background: var(--rx-gradient);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/* Umbrella navigation: the switcher and the rxova.org sections, beside the social icons. */
|
|
161
|
+
.rx-sections {
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
gap: 1rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.rx-sections__link {
|
|
168
|
+
color: var(--sl-color-gray-2);
|
|
169
|
+
font-size: var(--sl-text-sm);
|
|
170
|
+
text-decoration: none;
|
|
171
|
+
white-space: nowrap;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.rx-sections__link:hover {
|
|
175
|
+
color: var(--sl-color-white);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* In the mobile menu the icons share a row with the theme picker; the navigation takes a row
|
|
179
|
+
of its own above them. */
|
|
180
|
+
.mobile-preferences .social-icons {
|
|
181
|
+
flex-wrap: wrap;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.mobile-preferences .rx-sections {
|
|
185
|
+
flex-basis: 100%;
|
|
186
|
+
}
|
|
187
|
+
|
|
160
188
|
/* --- Footer -------------------------------------------------------------- */
|
|
161
189
|
|
|
162
190
|
/* Footer styles live in footer.css (imported above) because /blog and /updates need them too. */
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
/**
|
|
3
|
-
* Artifact document for rxova.org's non-Starlight pages: metadata and assets only, no header,
|
|
4
|
-
* footer, analytics or theme bootstrap. rxova-website supplies the public shell at deploy time.
|
|
5
|
-
*/
|
|
6
|
-
import '@rxova/brand/fonts.css'
|
|
7
|
-
import '../styles/document.css'
|
|
8
|
-
|
|
9
|
-
import { canonicalUrl, siteUrl } from '@rxova/brand'
|
|
10
|
-
|
|
11
|
-
interface Props {
|
|
12
|
-
title: string
|
|
13
|
-
description: string
|
|
14
|
-
/** Canonical path, e.g. `/blog/why-rxova-has-a-blog`. Normalised below. */
|
|
15
|
-
path: string
|
|
16
|
-
ogType?: 'website' | 'article'
|
|
17
|
-
/** Absolute URL of the social card, chosen by the caller; defaults to the umbrella card. */
|
|
18
|
-
image?: string
|
|
19
|
-
/** Advertises an RSS feed for this surface, as `rel="alternate"`. */
|
|
20
|
-
feed?: { href: string; title: string }
|
|
21
|
-
/** JSON-LD for this page, emitted verbatim as `application/ld+json`. */
|
|
22
|
-
jsonLd?: unknown
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const { title, description, path, ogType = 'website', image, feed, jsonLd } = Astro.props
|
|
26
|
-
|
|
27
|
-
// Normalised here so no caller can declare a canonical URL without the trailing slash (a 301).
|
|
28
|
-
const canonical = canonicalUrl(path)
|
|
29
|
-
|
|
30
|
-
const ogImage = image ?? siteUrl('/og/rxova.png')
|
|
31
|
-
|
|
32
|
-
/** Serialise JSON-LD for an inline `<script>`; `<` is escaped so a `</script>` cannot close it. */
|
|
33
|
-
const serialiseJsonLd = (value: unknown): string => JSON.stringify(value).replace(/</g, '\\u003c')
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
<!doctype html>
|
|
37
|
-
<html lang="en">
|
|
38
|
-
<head>
|
|
39
|
-
<meta charset="utf-8" />
|
|
40
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
41
|
-
<link rel="canonical" href={canonical} />
|
|
42
|
-
<title>{title}</title>
|
|
43
|
-
<meta name="description" content={description} />
|
|
44
|
-
<meta property="og:title" content={title} />
|
|
45
|
-
<meta property="og:description" content={description} />
|
|
46
|
-
<meta property="og:type" content={ogType} />
|
|
47
|
-
<meta property="og:url" content={canonical} />
|
|
48
|
-
<meta property="og:image" content={ogImage} />
|
|
49
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
50
|
-
{feed && (
|
|
51
|
-
<link rel="alternate" type="application/rss+xml" title={feed.title} href={feed.href} />
|
|
52
|
-
)}
|
|
53
|
-
{jsonLd && (
|
|
54
|
-
<script type="application/ld+json" is:inline set:html={serialiseJsonLd(jsonLd)}></script>
|
|
55
|
-
)}
|
|
56
|
-
</head>
|
|
57
|
-
<body>
|
|
58
|
-
<main>
|
|
59
|
-
<slot />
|
|
60
|
-
</main>
|
|
61
|
-
|
|
62
|
-
<style>
|
|
63
|
-
main {
|
|
64
|
-
max-width: var(--rx-max-wide);
|
|
65
|
-
margin: 0 auto;
|
|
66
|
-
padding: clamp(2rem, 6vh, 3.5rem) 1.5rem 4rem;
|
|
67
|
-
}
|
|
68
|
-
</style>
|
|
69
|
-
|
|
70
|
-
<!-- Prose styling for rendered markdown. Global because <Content /> markup carries no Astro
|
|
71
|
-
scoping attributes. -->
|
|
72
|
-
<style is:global>
|
|
73
|
-
.prose {
|
|
74
|
-
color: var(--rx-muted);
|
|
75
|
-
line-height: 1.7;
|
|
76
|
-
}
|
|
77
|
-
.prose > * + * {
|
|
78
|
-
margin-top: 1.1rem;
|
|
79
|
-
}
|
|
80
|
-
.prose h2 {
|
|
81
|
-
color: var(--rx-fg);
|
|
82
|
-
font-size: 1.25rem;
|
|
83
|
-
font-weight: 640;
|
|
84
|
-
letter-spacing: -0.01em;
|
|
85
|
-
margin-top: 2.5rem;
|
|
86
|
-
}
|
|
87
|
-
.prose h3 {
|
|
88
|
-
color: var(--rx-fg);
|
|
89
|
-
font-size: 1.05rem;
|
|
90
|
-
font-weight: 620;
|
|
91
|
-
margin-top: 2rem;
|
|
92
|
-
}
|
|
93
|
-
.prose a {
|
|
94
|
-
color: var(--rx-fg);
|
|
95
|
-
text-decoration: underline;
|
|
96
|
-
text-underline-offset: 2px;
|
|
97
|
-
}
|
|
98
|
-
.prose strong {
|
|
99
|
-
color: var(--rx-fg);
|
|
100
|
-
font-weight: 620;
|
|
101
|
-
}
|
|
102
|
-
.prose ul,
|
|
103
|
-
.prose ol {
|
|
104
|
-
margin-left: 1.2rem;
|
|
105
|
-
}
|
|
106
|
-
.prose li + li {
|
|
107
|
-
margin-top: 0.35rem;
|
|
108
|
-
}
|
|
109
|
-
.prose code {
|
|
110
|
-
font-family: var(--rx-font-mono);
|
|
111
|
-
font-size: 0.88em;
|
|
112
|
-
background: var(--rx-tag-bg);
|
|
113
|
-
padding: 0.05rem 0.35rem;
|
|
114
|
-
border-radius: 4px;
|
|
115
|
-
}
|
|
116
|
-
.prose pre {
|
|
117
|
-
background: var(--rx-card);
|
|
118
|
-
border: 1px solid var(--rx-rule);
|
|
119
|
-
border-radius: 10px;
|
|
120
|
-
padding: 1rem 1.1rem;
|
|
121
|
-
/* Long lines scroll inside the block; the page itself never does. */
|
|
122
|
-
overflow-x: auto;
|
|
123
|
-
}
|
|
124
|
-
.prose pre code {
|
|
125
|
-
background: none;
|
|
126
|
-
padding: 0;
|
|
127
|
-
}
|
|
128
|
-
.prose blockquote {
|
|
129
|
-
border-left: 2px solid var(--rx-rule);
|
|
130
|
-
padding-left: 1rem;
|
|
131
|
-
color: var(--rx-faint);
|
|
132
|
-
}
|
|
133
|
-
.prose img {
|
|
134
|
-
max-width: 100%;
|
|
135
|
-
height: auto;
|
|
136
|
-
border-radius: 10px;
|
|
137
|
-
}
|
|
138
|
-
.prose table {
|
|
139
|
-
width: 100%;
|
|
140
|
-
border-collapse: collapse;
|
|
141
|
-
font-size: 0.95rem;
|
|
142
|
-
}
|
|
143
|
-
.prose th,
|
|
144
|
-
.prose td {
|
|
145
|
-
border-bottom: 1px solid var(--rx-rule);
|
|
146
|
-
padding: 0.5rem 0.6rem;
|
|
147
|
-
text-align: left;
|
|
148
|
-
}
|
|
149
|
-
.prose th {
|
|
150
|
-
color: var(--rx-fg);
|
|
151
|
-
font-weight: 620;
|
|
152
|
-
}
|
|
153
|
-
</style>
|
|
154
|
-
</body>
|
|
155
|
-
</html>
|