@rxova/astro-ui 0.1.0 → 0.3.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 +22 -10
- package/package.json +3 -2
- package/src/components/CodeRecipes.astro +67 -0
- package/src/components/CtaBand.astro +121 -0
- package/src/components/DataTable.astro +114 -0
- package/src/components/DocAccordion.astro +15 -0
- package/src/components/DocAccordionItem.astro +83 -0
- package/src/components/Header.astro +1 -1
- package/src/components/Icon.astro +29 -0
- package/src/components/ModeTabs.astro +124 -0
- package/src/components/ProofStats.astro +207 -0
- package/src/components/QuickStart.astro +156 -0
- package/src/components/ScreenshotGrid.astro +164 -0
- package/src/components/Section.astro +103 -0
- package/src/components/SiteFooter.astro +15 -13
- package/src/components/SizeTable.astro +118 -0
- package/src/components/ThemeToggle.astro +1 -1
- package/src/components/ValueGrid.astro +116 -0
- package/src/components/icons/Collapse.astro +11 -0
- package/src/components/icons/Expand.astro +11 -0
- package/src/components/icons/Next.astro +11 -0
- package/src/components/icons/Pause.astro +11 -0
- package/src/components/icons/Play.astro +11 -0
- package/src/components/icons/Prev.astro +11 -0
- package/src/components/icons/Replay.astro +11 -0
- package/src/lib/icons.ts +15 -0
- package/src/starlight/index.ts +1 -2
- package/src/styles/landing.css +55 -0
- package/src/styles/mermaid.css +75 -0
- package/src/components/SiteShell.astro +0 -155
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Per-package bundle budgets as a real table: right-aligned tabular figures are the shape that
|
|
4
|
+
* supports comparing against whatever the reader ships today.
|
|
5
|
+
*/
|
|
6
|
+
export interface SizeRow {
|
|
7
|
+
pkg: string
|
|
8
|
+
entry: string
|
|
9
|
+
limitKb: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
rows: readonly SizeRow[]
|
|
14
|
+
/** The column heading: "brotli", "gzip". */
|
|
15
|
+
compression: string
|
|
16
|
+
caption: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { rows, compression, caption } = Astro.props
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
{/* Focusable and labelled: the box scrolls sideways on a narrow viewport, and a scrollable region needs a tab stop. */}
|
|
23
|
+
<div class="rx-sizes" tabindex="0" role="region" aria-label="Bundle size budgets">
|
|
24
|
+
<table class="rx-sizes__table">
|
|
25
|
+
<caption class="rx-sizes__caption">{caption}</caption>
|
|
26
|
+
<thead>
|
|
27
|
+
<tr>
|
|
28
|
+
<th scope="col">Package</th>
|
|
29
|
+
<th scope="col">You import</th>
|
|
30
|
+
<th scope="col" class="rx-sizes__num">
|
|
31
|
+
{compression}
|
|
32
|
+
</th>
|
|
33
|
+
</tr>
|
|
34
|
+
</thead>
|
|
35
|
+
<tbody>
|
|
36
|
+
{rows.map((row) => (
|
|
37
|
+
<tr>
|
|
38
|
+
<th scope="row" class="rx-sizes__pkg">
|
|
39
|
+
{row.pkg}
|
|
40
|
+
</th>
|
|
41
|
+
<td>
|
|
42
|
+
<code>{row.entry}</code>
|
|
43
|
+
</td>
|
|
44
|
+
<td class="rx-sizes__num">≤ {row.limitKb} kB</td>
|
|
45
|
+
</tr>
|
|
46
|
+
))}
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
.rx-sizes {
|
|
53
|
+
overflow-x: auto;
|
|
54
|
+
border: 1px solid var(--rx-rule);
|
|
55
|
+
border-radius: var(--rx-radius);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.rx-sizes__table {
|
|
59
|
+
width: 100%;
|
|
60
|
+
border-collapse: collapse;
|
|
61
|
+
font-size: 0.9rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.rx-sizes__caption {
|
|
65
|
+
padding: 1rem 1.25rem;
|
|
66
|
+
/* --rx-muted, not --rx-faint: faint on the card is ~3.4:1 and fails AA here. */
|
|
67
|
+
color: var(--rx-muted);
|
|
68
|
+
font-size: 0.82rem;
|
|
69
|
+
line-height: 1.5;
|
|
70
|
+
text-align: start;
|
|
71
|
+
caption-side: bottom;
|
|
72
|
+
border-top: 1px solid var(--rx-rule);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.rx-sizes__table th,
|
|
76
|
+
.rx-sizes__table td {
|
|
77
|
+
padding: 0.85rem 1.25rem;
|
|
78
|
+
text-align: start;
|
|
79
|
+
border-bottom: 1px solid var(--rx-rule);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.rx-sizes__table thead th {
|
|
83
|
+
background: var(--rx-card);
|
|
84
|
+
color: var(--rx-muted);
|
|
85
|
+
font-size: 0.75rem;
|
|
86
|
+
font-weight: 700;
|
|
87
|
+
letter-spacing: 0.06em;
|
|
88
|
+
text-transform: uppercase;
|
|
89
|
+
white-space: nowrap;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.rx-sizes__table tbody tr:last-child th,
|
|
93
|
+
.rx-sizes__table tbody tr:last-child td {
|
|
94
|
+
border-bottom: 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.rx-sizes__pkg {
|
|
98
|
+
color: var(--rx-fg);
|
|
99
|
+
font-family: var(--rx-font-mono);
|
|
100
|
+
font-size: 0.84rem;
|
|
101
|
+
font-weight: 500;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.rx-sizes__table code {
|
|
106
|
+
color: var(--rx-muted);
|
|
107
|
+
font-family: var(--rx-font-mono);
|
|
108
|
+
font-size: 0.84rem;
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.rx-sizes__num {
|
|
113
|
+
text-align: end;
|
|
114
|
+
color: var(--rx-fg);
|
|
115
|
+
font-variant-numeric: tabular-nums;
|
|
116
|
+
white-space: nowrap;
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
@@ -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;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* A grid of claims in the landing's language: a gradient hairline over each, a faint-ink Lucide
|
|
4
|
+
* icon beside the title, the body hanging under it. `icon` is a `lucide-static` name, inlined at build time.
|
|
5
|
+
*/
|
|
6
|
+
import { lucideGlyph } from '../lib/icons.ts'
|
|
7
|
+
|
|
8
|
+
export interface ValueItem {
|
|
9
|
+
title: string
|
|
10
|
+
/** Set as HTML, so it may carry inline `<code>`. */
|
|
11
|
+
body: string
|
|
12
|
+
icon: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
items: readonly ValueItem[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { items } = Astro.props
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<ul class="rx-vg">
|
|
23
|
+
{items.map((item) => (
|
|
24
|
+
<li class="rx-vg__item">
|
|
25
|
+
<svg
|
|
26
|
+
class="rx-vg__icon"
|
|
27
|
+
viewBox="0 0 24 24"
|
|
28
|
+
fill="none"
|
|
29
|
+
stroke="currentColor"
|
|
30
|
+
stroke-width="1.5"
|
|
31
|
+
stroke-linecap="round"
|
|
32
|
+
stroke-linejoin="round"
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
set:html={lucideGlyph(item.icon)}
|
|
35
|
+
/>
|
|
36
|
+
<h3 class="rx-vg__title">{item.title}</h3>
|
|
37
|
+
<p class="rx-vg__body" set:html={item.body} />
|
|
38
|
+
</li>
|
|
39
|
+
))}
|
|
40
|
+
</ul>
|
|
41
|
+
|
|
42
|
+
<style>
|
|
43
|
+
.rx-vg {
|
|
44
|
+
display: grid;
|
|
45
|
+
gap: 2rem 2.5rem;
|
|
46
|
+
margin: 0;
|
|
47
|
+
padding: 0;
|
|
48
|
+
list-style: none;
|
|
49
|
+
grid-template-columns: 1fr;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Explicit counts: auto-fit lands on four at the wide measure and leaves a half-empty last row. */
|
|
53
|
+
@media (min-width: 38rem) {
|
|
54
|
+
.rx-vg {
|
|
55
|
+
grid-template-columns: repeat(2, 1fr);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (min-width: 60rem) {
|
|
60
|
+
.rx-vg {
|
|
61
|
+
grid-template-columns: repeat(3, 1fr);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Icon beside the title, body under the title; 2px of the gradient over each binds them into one set. */
|
|
66
|
+
.rx-vg__item {
|
|
67
|
+
display: grid;
|
|
68
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
69
|
+
column-gap: 0.7rem;
|
|
70
|
+
row-gap: 0.4rem;
|
|
71
|
+
align-content: start;
|
|
72
|
+
padding-top: 1rem;
|
|
73
|
+
border-top: 2px solid transparent;
|
|
74
|
+
border-image: var(--rx-gradient) 1;
|
|
75
|
+
border-image-width: 2px 0 0 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.rx-vg__icon {
|
|
79
|
+
grid-column: 1;
|
|
80
|
+
grid-row: 1;
|
|
81
|
+
width: 1.375rem;
|
|
82
|
+
height: 1.375rem;
|
|
83
|
+
align-self: center;
|
|
84
|
+
color: var(--rx-faint);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.rx-vg__title {
|
|
88
|
+
grid-column: 2;
|
|
89
|
+
grid-row: 1;
|
|
90
|
+
margin: 0;
|
|
91
|
+
color: var(--rx-fg);
|
|
92
|
+
font-size: 1.05rem;
|
|
93
|
+
font-weight: 620;
|
|
94
|
+
line-height: 1.3;
|
|
95
|
+
letter-spacing: -0.015em;
|
|
96
|
+
text-wrap: balance;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.rx-vg__body {
|
|
100
|
+
grid-column: 2;
|
|
101
|
+
grid-row: 2;
|
|
102
|
+
margin: 0;
|
|
103
|
+
color: var(--rx-muted);
|
|
104
|
+
font-size: 0.95rem;
|
|
105
|
+
line-height: 1.55;
|
|
106
|
+
text-wrap: pretty;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.rx-vg__body :global(code) {
|
|
110
|
+
padding: 0.1em 0.35em;
|
|
111
|
+
background: var(--rx-tag-bg);
|
|
112
|
+
border-radius: var(--rx-radius-sm);
|
|
113
|
+
font-family: var(--rx-font-mono);
|
|
114
|
+
font-size: 0.86em;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** Four corners pointing in. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M6 2.75V6H2.75M13.25 6H10V2.75M10 13.25V10h3.25M2.75 10H6v3.25"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** Four corners pointing out. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M2.75 6V2.75H6M10 2.75h3.25V6M13.25 10v3.25H10M6 13.25H2.75V10"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** A right chevron. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M6 3.5 10.5 8 6 12.5"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** Two bars. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M5.25 3.5v9M10.75 3.5v9"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** A solid triangle. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props} solid>
|
|
10
|
+
<path d="M5 3.2v9.6L12.6 8z"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** A left chevron. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M10 3.5 5.5 8l4.5 4.5"></path>
|
|
11
|
+
</Icon>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
import Icon from '../Icon.astro'
|
|
4
|
+
|
|
5
|
+
/** An arrow turning back to its start. */
|
|
6
|
+
type Props = Omit<ComponentProps<typeof Icon>, 'solid'>
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<Icon {...Astro.props}>
|
|
10
|
+
<path d="M3.2 8a4.8 4.8 0 1 0 1.4-3.4M4.2 2.4v2.8H7"></path>
|
|
11
|
+
</Icon>
|
package/src/lib/icons.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Lucide icons as inline markup, read from `lucide-static` at build time so nothing ships to the client. */
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { createRequire } from 'node:module'
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
|
|
8
|
+
/** What sits inside a Lucide icon's root `<svg>`, so the caller's own element owns size and accessibility. */
|
|
9
|
+
export function lucideGlyph(name: string): string {
|
|
10
|
+
const svg = readFileSync(require.resolve(`lucide-static/icons/${name}.svg`), 'utf8')
|
|
11
|
+
return svg
|
|
12
|
+
.replace(/^[\s\S]*?<svg[^>]*>/, '')
|
|
13
|
+
.replace(/<\/svg>[\s\S]*$/, '')
|
|
14
|
+
.trim()
|
|
15
|
+
}
|
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,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rules a Starlight splash landing needs around the landing components. Load it through
|
|
3
|
+
* `customCss`; every rule is gated on `[data-has-hero]`, which Starlight sets only on a page with a hero.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* Starlight's 45rem prose measure is wrong for a stat band or a card grid; take the brand's wide bound. */
|
|
7
|
+
html[data-has-hero] .sl-container {
|
|
8
|
+
max-width: var(--rx-max-wide);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* The sections carry their own rhythm, so Starlight's 1.5rem between top-level children compounds. */
|
|
12
|
+
html[data-has-hero] .sl-container > * + * {
|
|
13
|
+
margin-top: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Starlight's clamp tops out at 10rem of padding, which pushes the first call to action below the fold. */
|
|
17
|
+
html[data-has-hero] .hero {
|
|
18
|
+
padding-block: clamp(2.5rem, 1rem + 6vmin, 5rem);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Without a hero image the second grid column is dead space holding the headline off to one side. */
|
|
22
|
+
html[data-has-hero] .hero:not(:has(img)) {
|
|
23
|
+
grid-template-columns: 1fr;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Starlight caps every hero child at 50ch: right for the tagline, far too wide for a display headline. */
|
|
27
|
+
html[data-has-hero] .hero h1 {
|
|
28
|
+
max-width: 22ch;
|
|
29
|
+
text-wrap: balance;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
html[data-has-hero] .hero .tagline {
|
|
33
|
+
max-width: 56ch;
|
|
34
|
+
text-wrap: pretty;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* The first section's 7rem margin is separating from the hero, which already ends in its own padding. */
|
|
38
|
+
html[data-has-hero] .sl-markdown-content > :first-child {
|
|
39
|
+
margin-top: 2rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* A pill above the headline, for a version: the hero title is frontmatter HTML, so it is styled by class. */
|
|
43
|
+
html[data-has-hero] .hero .rx-tag {
|
|
44
|
+
display: inline-block;
|
|
45
|
+
margin-bottom: 0.9rem;
|
|
46
|
+
padding: 0.28rem 0.7rem;
|
|
47
|
+
color: var(--rx-primary);
|
|
48
|
+
background: var(--rx-tag-bg);
|
|
49
|
+
border-radius: var(--rx-radius-pill);
|
|
50
|
+
font-family: var(--rx-font-mono);
|
|
51
|
+
font-size: 0.78rem;
|
|
52
|
+
font-weight: 500;
|
|
53
|
+
letter-spacing: 0;
|
|
54
|
+
line-height: 1.4;
|
|
55
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme-aware mermaid diagrams for `rehype-mermaid`'s build-time SVG, which bakes in a light palette.
|
|
3
|
+
* Mermaid scopes its own <style> by id, which outranks any class rule, so the colours here need !important.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.sl-markdown-content svg[aria-roledescription] {
|
|
7
|
+
max-width: 100%;
|
|
8
|
+
height: auto;
|
|
9
|
+
/* Mermaid sizes the viewBox to the diagram; let it breathe on the page. */
|
|
10
|
+
margin-block: 1.5rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Node and cluster surfaces. */
|
|
14
|
+
.sl-markdown-content svg[aria-roledescription] .node rect,
|
|
15
|
+
.sl-markdown-content svg[aria-roledescription] .node circle,
|
|
16
|
+
.sl-markdown-content svg[aria-roledescription] .node polygon,
|
|
17
|
+
.sl-markdown-content svg[aria-roledescription] .node path,
|
|
18
|
+
.sl-markdown-content svg[aria-roledescription] .label-container {
|
|
19
|
+
fill: var(--rx-card) !important;
|
|
20
|
+
stroke: var(--rx-rule-strong) !important;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.sl-markdown-content svg[aria-roledescription] .cluster rect {
|
|
24
|
+
fill: color-mix(in srgb, var(--rx-tag-bg) 60%, transparent) !important;
|
|
25
|
+
stroke: var(--rx-rule) !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* All text: labels, cluster titles, edge labels, actor names. */
|
|
29
|
+
.sl-markdown-content svg[aria-roledescription] text,
|
|
30
|
+
.sl-markdown-content svg[aria-roledescription] .nodeLabel,
|
|
31
|
+
.sl-markdown-content svg[aria-roledescription] .edgeLabel,
|
|
32
|
+
.sl-markdown-content svg[aria-roledescription] .cluster-label,
|
|
33
|
+
.sl-markdown-content svg[aria-roledescription] .messageText,
|
|
34
|
+
.sl-markdown-content svg[aria-roledescription] .loopText {
|
|
35
|
+
fill: var(--rx-fg) !important;
|
|
36
|
+
color: var(--rx-fg) !important;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Edge labels sit on an opaque plate; mermaid renders them as HTML in a <foreignObject>, so cover both. */
|
|
40
|
+
.sl-markdown-content svg[aria-roledescription] .edgeLabel,
|
|
41
|
+
.sl-markdown-content svg[aria-roledescription] .edgeLabel *,
|
|
42
|
+
.sl-markdown-content svg[aria-roledescription] .labelBkg {
|
|
43
|
+
background-color: var(--rx-bg) !important;
|
|
44
|
+
color: var(--rx-fg) !important;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.sl-markdown-content svg[aria-roledescription] .edgeLabel rect,
|
|
48
|
+
.sl-markdown-content svg[aria-roledescription] .labelBkg rect {
|
|
49
|
+
fill: var(--rx-bg) !important;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Connectors. */
|
|
53
|
+
.sl-markdown-content svg[aria-roledescription] .edgePath path,
|
|
54
|
+
.sl-markdown-content svg[aria-roledescription] .flowchart-link,
|
|
55
|
+
.sl-markdown-content svg[aria-roledescription] line,
|
|
56
|
+
.sl-markdown-content svg[aria-roledescription] .messageLine0,
|
|
57
|
+
.sl-markdown-content svg[aria-roledescription] .messageLine1 {
|
|
58
|
+
stroke: var(--rx-faint) !important;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sl-markdown-content svg[aria-roledescription] marker path,
|
|
62
|
+
.sl-markdown-content svg[aria-roledescription] .arrowMarkerPath {
|
|
63
|
+
fill: var(--rx-faint) !important;
|
|
64
|
+
stroke: var(--rx-faint) !important;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Sequence-diagram participant boxes and lifelines. */
|
|
68
|
+
.sl-markdown-content svg[aria-roledescription='sequence'] .actor {
|
|
69
|
+
fill: var(--rx-card) !important;
|
|
70
|
+
stroke: var(--rx-rule-strong) !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sl-markdown-content svg[aria-roledescription='sequence'] .actor-line {
|
|
74
|
+
stroke: var(--rx-rule-strong) !important;
|
|
75
|
+
}
|
|
@@ -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>
|