@eqtylab/docs 0.3.0 → 0.3.1
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/LICENSE +190 -0
- package/README.md +52 -10
- package/dist/config.js +1 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/runtime/chrome/GlobalSearch.module.css +0 -26
- package/dist/runtime/chrome/GlobalSearch.tsx +0 -422
- package/dist/runtime/chrome/Header.astro +0 -105
- package/dist/runtime/chrome/LinkIcon.astro +0 -35
- package/dist/runtime/chrome/NavDrawer.astro +0 -60
- package/dist/runtime/chrome/NavTree.astro +0 -112
- package/dist/runtime/chrome/NotFoundBody.tsx +0 -12
- package/dist/runtime/chrome/PageFooter.astro +0 -80
- package/dist/runtime/chrome/Prose.astro +0 -169
- package/dist/runtime/chrome/Sidebar.astro +0 -21
- package/dist/runtime/chrome/TableOfContents.astro +0 -86
- package/dist/runtime/chrome/ThemeToggle.tsx +0 -85
- package/dist/runtime/chrome/TocElbow.astro +0 -30
- package/dist/runtime/chrome/TocList.astro +0 -43
- package/dist/runtime/components/AlertBridge.astro +0 -16
- package/dist/runtime/components/CodeFence.astro +0 -38
- package/dist/runtime/components/CodeFenceBridge.astro +0 -20
- package/dist/runtime/components/Link.astro +0 -21
- package/dist/runtime/components/TableBridge.astro +0 -18
- package/dist/runtime/components/index.ts +0 -2
- package/dist/runtime/layouts/DocsPage.astro +0 -50
- package/dist/runtime/layouts/DocsShell.astro +0 -92
- package/dist/runtime/lib/mdx-components.ts +0 -43
- package/dist/runtime/lib/nav-data.ts +0 -74
- package/dist/runtime/lib/summary.ts +0 -57
- package/dist/runtime/lib/theme.ts +0 -84
- package/dist/runtime/routes/docs-md.ts +0 -33
- package/dist/runtime/routes/docs.astro +0 -92
- package/dist/runtime/routes/llms-txt.ts +0 -38
- package/dist/runtime/routes/not-found.astro +0 -16
- package/dist/runtime/scripts/eq-copy.ts +0 -27
- package/dist/runtime/scripts/eq-highlight.ts +0 -24
- package/dist/runtime/scripts/eq-nav-drawer.ts +0 -31
- package/dist/runtime/scripts/eq-nav-group.ts +0 -52
- package/dist/runtime/scripts/eq-toc.ts +0 -166
- package/dist/runtime/styles/chrome.css +0 -30
- package/dist/runtime/styles/prose.css +0 -102
- package/dist/runtime/styles/theme.css +0 -2
- package/dist/runtime/styles/utilities.css +0 -38
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import CONFIG from 'virtual:eqty-docs/config';
|
|
3
|
-
import { withBase } from '@eqtylab/docs/paths';
|
|
4
|
-
import DocsShell from '../layouts/DocsShell.astro';
|
|
5
|
-
import Header from '../chrome/Header.astro';
|
|
6
|
-
import NotFoundBody from '../chrome/NotFoundBody.tsx';
|
|
7
|
-
|
|
8
|
-
const homeHref = withBase(CONFIG.pathPrefix ? `/${CONFIG.pathPrefix}/` : '/', {
|
|
9
|
-
base: import.meta.env.BASE_URL,
|
|
10
|
-
});
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<DocsShell title="Page not found" noIndex>
|
|
14
|
-
<Header />
|
|
15
|
-
<NotFoundBody homeHref={homeHref} client:load />
|
|
16
|
-
</DocsShell>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/** Copy-to-clipboard for static code fences. One delegated listener, so it survives view transitions. */
|
|
2
|
-
const COPIED_MS = 1600;
|
|
3
|
-
|
|
4
|
-
function findFence(target: EventTarget | null): HTMLElement | null {
|
|
5
|
-
if (!(target instanceof Element)) return null;
|
|
6
|
-
return target.closest<HTMLElement>('[data-eq-copy]');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
document.addEventListener('click', async (event) => {
|
|
10
|
-
const trigger = (event.target as Element | null)?.closest('button');
|
|
11
|
-
if (!trigger) return;
|
|
12
|
-
|
|
13
|
-
const fence = findFence(trigger);
|
|
14
|
-
if (!fence) return;
|
|
15
|
-
|
|
16
|
-
const code = fence.dataset.eqCopy;
|
|
17
|
-
if (!code) return;
|
|
18
|
-
|
|
19
|
-
event.preventDefault();
|
|
20
|
-
try {
|
|
21
|
-
await navigator.clipboard.writeText(code);
|
|
22
|
-
fence.setAttribute('data-copied', '');
|
|
23
|
-
window.setTimeout(() => fence.removeAttribute('data-copied'), COPIED_MS);
|
|
24
|
-
} catch {
|
|
25
|
-
// Clipboard denied; do not show a success state.
|
|
26
|
-
}
|
|
27
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Starts highlighting for server-rendered code blocks, whose `useEffect` never
|
|
3
|
-
* runs without hydration. A custom element so it survives view transitions.
|
|
4
|
-
*/
|
|
5
|
-
import { scheduleHighlight } from '@eqtylab/equality';
|
|
6
|
-
|
|
7
|
-
class EqHighlight extends HTMLElement {
|
|
8
|
-
// Captured on connect: a detached element no longer knows its tree, and the rescan on removal drops stale ranges.
|
|
9
|
-
#root?: Node;
|
|
10
|
-
|
|
11
|
-
connectedCallback() {
|
|
12
|
-
this.#root = this.getRootNode();
|
|
13
|
-
void scheduleHighlight(this.#root);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
disconnectedCallback() {
|
|
17
|
-
void scheduleHighlight(this.#root);
|
|
18
|
-
this.#root = undefined;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (!customElements.get('eq-highlight')) {
|
|
23
|
-
customElements.define('eq-highlight', EqHighlight);
|
|
24
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* With no script the Popover API opens and closes the drawer, shuts it on Escape or a
|
|
3
|
-
* click outside, and paints it above everything else. Two things it does not give,
|
|
4
|
-
* both verified in the browser suite rather than assumed:
|
|
5
|
-
*
|
|
6
|
-
* 1. `aria-expanded` on the invoker. No engine adds it, so a screen reader hears a
|
|
7
|
-
* button with no disclosure state.
|
|
8
|
-
* 2. Focus return on dismiss in WebKit. Chromium restores focus to the invoker;
|
|
9
|
-
* desktop Safari, mobile Safari and iPad all leave it on `<body>`, which strands a
|
|
10
|
-
* keyboard user exactly the way `DialogContainer` does. See equality-dialog-repair.
|
|
11
|
-
*
|
|
12
|
-
* Both are reflected off the `toggle` event so they track every dismissal path,
|
|
13
|
-
* rather than being set once and going stale.
|
|
14
|
-
*/
|
|
15
|
-
const drawer = document.getElementById('eq-nav-drawer');
|
|
16
|
-
const trigger = document.querySelector<HTMLElement>('[popovertarget="eq-nav-drawer"]');
|
|
17
|
-
|
|
18
|
-
if (drawer && trigger) {
|
|
19
|
-
trigger.setAttribute('aria-expanded', 'false');
|
|
20
|
-
|
|
21
|
-
drawer.addEventListener('toggle', (event) => {
|
|
22
|
-
const open = (event as ToggleEvent).newState === 'open';
|
|
23
|
-
trigger.setAttribute('aria-expanded', String(open));
|
|
24
|
-
|
|
25
|
-
// Only when the engine left focus nowhere. Clicking a link inside the drawer
|
|
26
|
-
// navigates away, and light-dismissing onto another control should keep it.
|
|
27
|
-
if (!open && document.activeElement === document.body) {
|
|
28
|
-
trigger.focus();
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Animates a navigation group open and closed, on top of `<details>`.
|
|
3
|
-
*
|
|
4
|
-
* Do not swap this for Equality's `MotionCollapsibleContent`. It measures after mount
|
|
5
|
-
* and animates up from zero, so a group that starts open expands on every page load.
|
|
6
|
-
*
|
|
7
|
-
* Duration and easing are that component's, so the motion still matches.
|
|
8
|
-
*/
|
|
9
|
-
const DURATION = 300;
|
|
10
|
-
const EASING = 'ease-in-out';
|
|
11
|
-
|
|
12
|
-
function wire(group: HTMLDetailsElement) {
|
|
13
|
-
const summary = group.querySelector('summary');
|
|
14
|
-
const panel = summary?.nextElementSibling;
|
|
15
|
-
if (!summary || !(panel instanceof HTMLElement)) return;
|
|
16
|
-
|
|
17
|
-
let running: Animation | null = null;
|
|
18
|
-
|
|
19
|
-
summary.addEventListener('click', (event) => {
|
|
20
|
-
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
21
|
-
|
|
22
|
-
// The browser would toggle `open` immediately; the close has to outlive that.
|
|
23
|
-
event.preventDefault();
|
|
24
|
-
running?.cancel();
|
|
25
|
-
|
|
26
|
-
const opening = !group.open;
|
|
27
|
-
// Measured while open in both directions, so interrupting mid-animation does not
|
|
28
|
-
// snap to a stale height.
|
|
29
|
-
if (opening) group.open = true;
|
|
30
|
-
const height = panel.scrollHeight;
|
|
31
|
-
const from = opening ? 0 : panel.getBoundingClientRect().height;
|
|
32
|
-
|
|
33
|
-
panel.style.overflow = 'hidden';
|
|
34
|
-
running = panel.animate(
|
|
35
|
-
{
|
|
36
|
-
height: [`${from}px`, `${opening ? height : 0}px`],
|
|
37
|
-
opacity: [opening ? 0 : 1, opening ? 1 : 0],
|
|
38
|
-
},
|
|
39
|
-
{ duration: DURATION, easing: EASING }
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
running.onfinish = () => {
|
|
43
|
-
running = null;
|
|
44
|
-
panel.style.removeProperty('overflow');
|
|
45
|
-
if (!opening) group.open = false;
|
|
46
|
-
};
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (const group of document.querySelectorAll<HTMLDetailsElement>('details[data-eq-nav-group]')) {
|
|
51
|
-
wire(group);
|
|
52
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scroll-spy for the table of contents, and the lit segment of its rail.
|
|
3
|
-
*
|
|
4
|
-
* Do not swap this for an IntersectionObserver band. A band leaves nothing active at
|
|
5
|
-
* load, and nothing between two headings.
|
|
6
|
-
*
|
|
7
|
-
* The segment is a dash on a path tracing the whole rail, elbows included, so it
|
|
8
|
-
* travels through corners. Its numbers are path length, not pixels.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** Scaling by distance is what makes a corner take visible time. */
|
|
12
|
-
const MS_PER_PX = 8;
|
|
13
|
-
const MIN_MS = 220;
|
|
14
|
-
const MAX_MS = 520;
|
|
15
|
-
const EASE = 'cubic-bezier(0.4, 0, 0.2, 1)';
|
|
16
|
-
|
|
17
|
-
interface Span {
|
|
18
|
-
start: number;
|
|
19
|
-
length: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function measureRail(root: HTMLElement, path: SVGPathElement) {
|
|
23
|
-
const origin = root.getBoundingClientRect();
|
|
24
|
-
const spans = new Map<string, Span>();
|
|
25
|
-
const parts: string[] = [];
|
|
26
|
-
let cursor = 0;
|
|
27
|
-
|
|
28
|
-
const rows = root.querySelectorAll<HTMLElement>('a[data-slug], [data-eq-elbow]');
|
|
29
|
-
for (const row of rows) {
|
|
30
|
-
const box = row.getBoundingClientRect();
|
|
31
|
-
const top = box.top - origin.top;
|
|
32
|
-
const bottom = box.bottom - origin.top;
|
|
33
|
-
const direction = row.getAttribute('data-eq-elbow');
|
|
34
|
-
|
|
35
|
-
if (direction) {
|
|
36
|
-
const left = box.left - origin.left;
|
|
37
|
-
const right = box.right - origin.left;
|
|
38
|
-
const [from, to] = direction === 'in' ? [left, right] : [right, left];
|
|
39
|
-
const mid = (top + bottom) / 2;
|
|
40
|
-
if (parts.length === 0) parts.push(`M ${from} ${top}`);
|
|
41
|
-
parts.push(`C ${from} ${mid}, ${to} ${mid}, ${to} ${bottom}`);
|
|
42
|
-
} else {
|
|
43
|
-
// The border's centre line, so the lit segment covers the grey one exactly.
|
|
44
|
-
const x = box.left - origin.left + parseFloat(getComputedStyle(row).borderLeftWidth) / 2;
|
|
45
|
-
if (parts.length === 0) parts.push(`M ${x} ${top}`);
|
|
46
|
-
parts.push(`L ${x} ${bottom}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
path.setAttribute('d', parts.join(' '));
|
|
50
|
-
const end = path.getTotalLength();
|
|
51
|
-
const slug = row.dataset.slug;
|
|
52
|
-
if (!direction && slug) spans.set(slug, { start: cursor, length: end - cursor });
|
|
53
|
-
cursor = end;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return { spans, total: cursor };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
class EqToc extends HTMLElement {
|
|
60
|
-
#teardown?: () => void;
|
|
61
|
-
|
|
62
|
-
connectedCallback() {
|
|
63
|
-
const slugs = (this.dataset.slugs ?? '').split(',').filter(Boolean);
|
|
64
|
-
|
|
65
|
-
const links = new Map<string, HTMLAnchorElement>();
|
|
66
|
-
for (const link of this.querySelectorAll<HTMLAnchorElement>('a[data-slug]')) {
|
|
67
|
-
if (link.dataset.slug) links.set(link.dataset.slug, link);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const targets = slugs
|
|
71
|
-
.map((slug) => document.getElementById(slug))
|
|
72
|
-
.filter((el): el is HTMLElement => el !== null);
|
|
73
|
-
if (targets.length === 0) return;
|
|
74
|
-
|
|
75
|
-
const path = this.querySelector<SVGPathElement>('[data-eq-toc-rail]');
|
|
76
|
-
const rails = this.querySelector<HTMLElement>('[data-eq-toc-rails]');
|
|
77
|
-
const still = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
78
|
-
|
|
79
|
-
let spans = new Map<string, Span>();
|
|
80
|
-
let total = 0;
|
|
81
|
-
let previous: number | null = null;
|
|
82
|
-
|
|
83
|
-
const remeasure = () => {
|
|
84
|
-
if (!path || !rails) return;
|
|
85
|
-
previous = null;
|
|
86
|
-
({ spans, total } = measureRail(rails, path));
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const light = (slug: string) => {
|
|
90
|
-
if (!path) return;
|
|
91
|
-
const span = spans.get(slug);
|
|
92
|
-
if (!span) return;
|
|
93
|
-
|
|
94
|
-
if (previous === null || still.matches) {
|
|
95
|
-
// No slide into the first position, and none under reduced motion.
|
|
96
|
-
path.style.transition = 'none';
|
|
97
|
-
} else {
|
|
98
|
-
const ms = Math.min(
|
|
99
|
-
MAX_MS,
|
|
100
|
-
Math.max(MIN_MS, Math.round(Math.abs(span.start - previous) * MS_PER_PX))
|
|
101
|
-
);
|
|
102
|
-
path.style.transition = `stroke-dasharray ${ms}ms ${EASE}, stroke-dashoffset ${ms}ms ${EASE}`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
path.style.strokeDasharray = `${span.length} ${total}`;
|
|
106
|
-
path.style.strokeDashoffset = `${-span.start}`;
|
|
107
|
-
if (previous === null) {
|
|
108
|
-
// Commit the jump before the fade, so the segment appears in place.
|
|
109
|
-
void path.getBoundingClientRect();
|
|
110
|
-
path.style.opacity = '1';
|
|
111
|
-
}
|
|
112
|
-
previous = span.start;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
let frame = 0;
|
|
116
|
-
const paint = () => {
|
|
117
|
-
frame = 0;
|
|
118
|
-
// Clicking a heading lands it 96px down (scroll-mt-24), so the line sits below.
|
|
119
|
-
const line = window.innerHeight * 0.2;
|
|
120
|
-
let active = targets[0];
|
|
121
|
-
for (const target of targets) {
|
|
122
|
-
if (target.getBoundingClientRect().top <= line) active = target;
|
|
123
|
-
else break;
|
|
124
|
-
}
|
|
125
|
-
for (const [slug, link] of links) {
|
|
126
|
-
if (slug === active.id) {
|
|
127
|
-
link.setAttribute('data-active', '');
|
|
128
|
-
// `location` is the ARIA value for the current place within a set.
|
|
129
|
-
link.setAttribute('aria-current', 'location');
|
|
130
|
-
} else {
|
|
131
|
-
link.removeAttribute('data-active');
|
|
132
|
-
link.removeAttribute('aria-current');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
light(active.id);
|
|
136
|
-
};
|
|
137
|
-
const schedule = () => {
|
|
138
|
-
if (frame === 0) frame = requestAnimationFrame(paint);
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const onResize = () => {
|
|
142
|
-
remeasure();
|
|
143
|
-
schedule();
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
window.addEventListener('scroll', schedule, { passive: true });
|
|
147
|
-
window.addEventListener('resize', onResize, { passive: true });
|
|
148
|
-
remeasure();
|
|
149
|
-
paint();
|
|
150
|
-
|
|
151
|
-
this.#teardown = () => {
|
|
152
|
-
window.removeEventListener('scroll', schedule);
|
|
153
|
-
window.removeEventListener('resize', onResize);
|
|
154
|
-
if (frame !== 0) cancelAnimationFrame(frame);
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
disconnectedCallback() {
|
|
159
|
-
this.#teardown?.();
|
|
160
|
-
this.#teardown = undefined;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (!customElements.get('eq-toc')) {
|
|
165
|
-
customElements.define('eq-toc', EqToc);
|
|
166
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/* Shared geometry and the variants the chrome needs; component styling is inline
|
|
2
|
-
* Tailwind in the markup. */
|
|
3
|
-
@reference './theme.css';
|
|
4
|
-
|
|
5
|
-
/* The mirror of Equality's own `dark` variant. Needed because the logo and the header
|
|
6
|
-
* link marks ship white, so light is the theme that has to invert them. */
|
|
7
|
-
@custom-variant light (&:where(html[data-equality-theme=light], html[data-equality-theme=light] *));
|
|
8
|
-
|
|
9
|
-
/* Equality's hover fires on `:focus` rather than `:focus-visible`, so a mouse click
|
|
10
|
-
* leaves a control filled as if it were the current page. This undoes it for pointer
|
|
11
|
-
* focus only, leaving the keyboard ring intact. */
|
|
12
|
-
@custom-variant pointer-focus (&:focus:not(:focus-visible));
|
|
13
|
-
|
|
14
|
-
:root {
|
|
15
|
-
--eq-docs-header-height: 4.3125rem;
|
|
16
|
-
--eq-docs-sidebar-width: 18rem;
|
|
17
|
-
--eq-docs-toc-width: 15rem;
|
|
18
|
-
--eq-docs-content-max: 48rem;
|
|
19
|
-
/* eqtylab.io's display-text fade, on tokens so light gets the inverse for free.
|
|
20
|
-
* Used by the header label and the page title. */
|
|
21
|
-
--eq-docs-display-gradient: linear-gradient(
|
|
22
|
-
135deg,
|
|
23
|
-
var(--color-text-primary),
|
|
24
|
-
var(--color-background) 175%
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
body {
|
|
29
|
-
@apply bg-background text-text-primary;
|
|
30
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Docs typography.
|
|
3
|
-
*
|
|
4
|
-
* Only what the page itself wrote is styled, marked `data-eq-md` by `rehypeProseScope`.
|
|
5
|
-
* Drop that guard and every component's children get typeset as body copy.
|
|
6
|
-
*
|
|
7
|
-
* Both guards sit inside :where(), so a consumer can override without !important.
|
|
8
|
-
*/
|
|
9
|
-
@reference './theme.css';
|
|
10
|
-
|
|
11
|
-
.eq-prose {
|
|
12
|
-
& > :first-child {
|
|
13
|
-
@apply mt-0;
|
|
14
|
-
}
|
|
15
|
-
& > :last-child {
|
|
16
|
-
@apply mb-0;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
& :where([data-eq-md]):not(:where([data-eq-chrome], [data-eq-chrome] *)) {
|
|
20
|
-
&:is(h1, h2, h3, h4, h5, h6) {
|
|
21
|
-
@apply scroll-mt-24;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
&:is(h1) {
|
|
25
|
-
@apply mb-3 mt-12 text-4xl font-bold;
|
|
26
|
-
& > code {
|
|
27
|
-
@apply text-3xl;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
&:is(h2) {
|
|
31
|
-
@apply mb-3 mt-12 text-2xl font-semibold;
|
|
32
|
-
& > code {
|
|
33
|
-
@apply text-xl;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
&:is(h3) {
|
|
37
|
-
@apply mb-3 mt-8 text-xl font-medium;
|
|
38
|
-
& > code {
|
|
39
|
-
@apply text-lg;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
&:is(h4) {
|
|
43
|
-
@apply mb-3 mt-6 text-lg font-medium;
|
|
44
|
-
& > code {
|
|
45
|
-
@apply text-base;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
&:is(h5) {
|
|
49
|
-
@apply mb-3 mt-6 text-base font-medium;
|
|
50
|
-
& > code {
|
|
51
|
-
@apply text-sm;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
&:is(h6) {
|
|
55
|
-
@apply mb-3 mt-6 text-sm font-medium;
|
|
56
|
-
& > code {
|
|
57
|
-
@apply text-xs;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/* 16px, which has to stay wider than the 28px line height inside a paragraph,
|
|
62
|
-
* or consecutive blocks read as one. */
|
|
63
|
-
&:is(p) {
|
|
64
|
-
@apply text-text-secondary mb-4 text-base/7 font-normal;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
:is(p, li) &:is(b, strong) {
|
|
68
|
-
@apply text-text-primary font-medium;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
&:is(ul, ol) {
|
|
72
|
-
@apply text-text-secondary mb-4 pl-4;
|
|
73
|
-
|
|
74
|
-
/* Never `space-y-*` here: it unbalances against the `:not(:where(...))` above
|
|
75
|
-
* and compiles to a rule the browser throws away, leaving items unspaced. */
|
|
76
|
-
& > li + li {
|
|
77
|
-
@apply mt-2;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
&:is(ul) {
|
|
81
|
-
@apply list-disc;
|
|
82
|
-
}
|
|
83
|
-
&:is(ol) {
|
|
84
|
-
@apply list-decimal;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
&:is(a) {
|
|
88
|
-
@apply text-text-primary hover:text-lilac-400 font-medium underline underline-offset-4 transition-all;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* Inline code, but never the contents of a highlighted block. */
|
|
92
|
-
:not(pre) > &:is(code) {
|
|
93
|
-
@apply dark:bg-background-overlay bg-greyscale-200 text-text-secondary rounded-sm p-1 text-sm;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* No table rules: markdown tables render through Equality's Table. */
|
|
97
|
-
|
|
98
|
-
&:is(hr) {
|
|
99
|
-
@apply border-border mb-4;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Class recipes shared by more than one piece of chrome. Real utilities, so the markup
|
|
3
|
-
* stays inline everywhere else and the recipe still has one definition.
|
|
4
|
-
*/
|
|
5
|
-
@reference './theme.css';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The header bar's control geometry, shared so the links and the theme toggle cannot
|
|
9
|
-
* drift apart. `display` is deliberately absent: the links are flex rows and the theme
|
|
10
|
-
* toggle is a one-cell grid, and a display utility in here would collide with theirs.
|
|
11
|
-
*/
|
|
12
|
-
@utility eq-nav-control {
|
|
13
|
-
@apply text-text-secondary hover:text-text-primary hover:bg-background;
|
|
14
|
-
@apply h-10 items-center gap-1.5 rounded-md px-3;
|
|
15
|
-
@apply text-sm font-medium no-underline transition-colors;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* eqtylab.io's display-text fade, used by the header label and the page title.
|
|
20
|
-
*
|
|
21
|
-
* Callers add their own `forced-colors:text-*`: the header label inherits, the page
|
|
22
|
-
* title names a token, so the solid colour cannot live in here.
|
|
23
|
-
*/
|
|
24
|
-
@utility eq-display-gradient {
|
|
25
|
-
@apply bg-[image:var(--eq-docs-display-gradient)] bg-clip-text text-transparent;
|
|
26
|
-
/* Clipping the gradient to the text crops descenders without this. */
|
|
27
|
-
@apply py-[0.05em];
|
|
28
|
-
-webkit-background-clip: text;
|
|
29
|
-
-webkit-text-fill-color: transparent;
|
|
30
|
-
|
|
31
|
-
/* Windows High Contrast and similar modes drop the gradient but keep the transparent
|
|
32
|
-
* fill, so the text would vanish. This puts the paint back; the caller supplies the
|
|
33
|
-
* colour. */
|
|
34
|
-
@media (forced-colors: active) {
|
|
35
|
-
background-image: none;
|
|
36
|
-
-webkit-text-fill-color: currentColor;
|
|
37
|
-
}
|
|
38
|
-
}
|