Skip to content

Commit d9bcc16

Browse files
committed
feat: add basic support for revision selector
1 parent d5729cb commit d9bcc16

File tree

22 files changed

+323
-57
lines changed

22 files changed

+323
-57
lines changed

astro.config.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ export default defineConfig({
3838
{
3939
label: "CppDoc Development Guide",
4040
autogenerate: { directory: "development" },
41-
}
41+
},
4242
],
4343
locales: {
4444
root: {
4545
label: "English",
4646
lang: "en",
4747
},
4848
},
49+
components: {
50+
TableOfContents: "./src/components/starlight/TableOfContents.astro",
51+
},
4952
plugins: [
5053
starlightAutoSidebar(),
5154
starlightContextualMenu({

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@astrojs/starlight": "^0.36.2",
1515
"@lorenzo_lewis/starlight-utils": "0.3.2",
1616
"astro": "^5.6.1",
17+
"nanostores": "^1.1.0",
1718
"sharp": "^0.34.2",
1819
"starlight-auto-sidebar": "0.1.3",
1920
"starlight-contextual-menu": "0.1.5",

src/components/decl-doc/DeclDoc.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
---
2+
import { autoRev, type AutorevProps } from "@components/revision/autorev";
23
import AutoCollapse from "../AutoCollapse.astro";
34
4-
interface Props {
5+
interface Props extends AutorevProps {
56
id?: number;
67
}
78
89
const { id } = Astro.props;
910
const hasId = id !== undefined;
1011
---
1112

12-
<div class="decl-doc">
13+
<div class="decl-doc" {...autoRev(Astro.props)}>
1314
{hasId ? (
1415
<div class="decl-id">Declaration #{id}</div>
1516
) : <></>}

src/components/desc-list/Desc.astro

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
---
2-
interface Props {
2+
import { autoRev, type AutorevProps } from "@components/revision";
3+
4+
interface Props extends AutorevProps {
35
kind?: string;
46
}
57
68
const { kind } = Astro.props;
79
const hasKind = kind !== undefined;
810
---
911

10-
<div class="desc">
12+
<div class="desc" {...autoRev(Astro.props)}>
1113
<div class="desc-items">
1214
<slot name="item" />
1315
</div>
@@ -28,6 +30,10 @@ const hasKind = kind !== undefined;
2830
padding-bottom: calc(var(--sl-content-gap-y) * 0.35);
2931
}
3032

33+
.desc.autorev-hidden {
34+
display: none;
35+
}
36+
3137
.desc > .desc-content {
3238
margin: 0;
3339
}

src/components/desc-list/DescItem.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
---
2+
import { autoRev, type AutorevProps } from "@components/revision";
23
4+
interface Props extends AutorevProps {}
35
---
46

5-
<div class="desc-item">
7+
<div class="desc-item" {...autoRev(Astro.props)}>
68
<slot />
79
</div>
810

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
---
2-
import type { RevisionInfo } from "./types";
2+
import type { RevisionRange } from "@src/types";
33
import RevisionTags from "./RevisionTags.astro";
4+
import { autoRev } from "./autorev";
45
5-
interface Props extends RevisionInfo {
6+
interface Props extends RevisionRange {
67
noborder?: boolean;
78
}
89
9-
const { noborder } = Astro.props;
10+
const { noborder, since, until } = Astro.props;
1011
---
1112

12-
<span class:list={["revision", { noborder }]}>
13+
<span
14+
class:list={["revision-span", { noborder }]}
15+
{...autoRev({ autorevSince: since, autorevUntil: until })}
16+
>
1317
<slot />
14-
<RevisionTags as="span" {...Astro.props} />
18+
<span class="revision-tags">
19+
<RevisionTags as="span" {...Astro.props} />
20+
</span>
1521
</span>
1622

1723
<style>
18-
.revision:not(.noborder) {
24+
.revision-span:not(.noborder) {
1925
border: 1px solid var(--sl-color-gray-4);
2026
padding: 2px;
2127
border-radius: 4px;
2228
}
23-
24-
.revision > .revision-tag {
25-
font-size: var(--cppdoc-font-size-revision);
26-
color: var(--cppdoc-color-revision);
27-
}
2829
</style>
Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
2-
import type { RevisionInfo } from "./types";
32
import RevisionTags from "./RevisionTags.astro";
3+
import { autoRev } from ".";
4+
import type { RevisionInfo } from "./types";
45
56
type LayoutDirection = "h" | "v";
67
@@ -9,14 +10,17 @@ interface Props extends RevisionInfo {
910
dir?: LayoutDirection;
1011
}
1112
12-
const { noborder } = Astro.props;
13+
const { since, until, noborder } = Astro.props;
1314
const dir = Astro.props.dir ?? "h";
1415
1516
const horizontal = dir === "h";
1617
const vertical = dir === "v";
1718
---
1819

19-
<div class:list={["revision", { noborder, horizontal, vertical }]}>
20+
<div
21+
class:list={["revision-block", { noborder, horizontal, vertical }]}
22+
{...autoRev({ autorevSince: since, autorevUntil: until })}
23+
>
2024
<div class="revision-content">
2125
<slot />
2226
</div>
@@ -26,37 +30,41 @@ const vertical = dir === "v";
2630
</div>
2731

2832
<style>
29-
.revision {
33+
.revision-block {
3034
display: flex;
3135
}
3236

33-
.revision:not(.noborder) {
37+
.revision-block.autorev-hidden {
38+
display: none;
39+
}
40+
41+
.revision-block:not(.noborder) {
3442
border: 1px solid var(--sl-color-gray-4);
3543
padding-left: calc(var(--sl-content-gap-y) * 0.5);
3644
padding-right: calc(var(--sl-content-gap-y) * 0.5);
3745
padding-top: calc(var(--sl-content-gap-y) * 0.25);
3846
padding-bottom: calc(var(--sl-content-gap-y) * 0.25);
3947
}
4048

41-
.revision .revision-tags {
49+
.revision-block .revision-tags {
4250
margin: 0;
4351
}
4452

45-
.revision.horizontal {
53+
.revision-block.horizontal {
4654
align-items: center;
4755
column-gap: 1em;
4856
}
4957

50-
.revision.horizontal > .revision-content {
58+
.revision-block.horizontal > .revision-content {
5159
flex-grow: 1;
5260
}
5361

54-
.revision.horizontal > .revision-tags {
62+
.revision-block.horizontal > .revision-tags {
5563
flex-shrink: 0;
5664
flex-grow: 0;
5765
}
5866

59-
.revision.vertical {
67+
.revision-block.vertical {
6068
flex-direction: column;
6169
}
6270
</style>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
import type { CxxRevision, Language } from "@src/types";
3+
import { getRevisions } from "@src/lib/revision";
4+
5+
const pageRevision = Astro.locals.starlightRoute.entry.data.cppdoc?.revision;
6+
const since = pageRevision?.since as CxxRevision | undefined;
7+
const until = pageRevision?.until as CxxRevision | undefined;
8+
9+
// This may look hacky, but we now infer whether the current page is for C or
10+
// C++ by examining the page's path in the file system.
11+
const path = Astro.locals.starlightRoute.entry.filePath;
12+
let language: Language;
13+
if (pageRevision?.lang) {
14+
language = pageRevision.lang as Language;
15+
} else if (path.includes("src/content/docs/cpp/")) {
16+
language = "C++";
17+
} else {
18+
language = "C";
19+
}
20+
21+
const revisions = getRevisions(language, { since, until });
22+
---
23+
24+
<select id="revision-selector" class="revision-selector">
25+
<option value="">Select a revision ...</option>
26+
{revisions.map((rev) => <option value={rev}>{rev}</option>)}
27+
</select>
28+
29+
<style>
30+
.revision-selector {
31+
font-size: 0.9em;
32+
}
33+
</style>
34+
35+
<style is:global>
36+
.autorev-hidden {
37+
display: none;
38+
}
39+
</style>
40+
41+
<script>
42+
import { selectedRevision } from "./store";
43+
import { isRevisionInRange } from "@src/lib/revision";
44+
import type { CxxRevision } from "@src/types";
45+
46+
const selector = document.getElementById(
47+
"revision-selector"
48+
) as HTMLSelectElement | null;
49+
if (selector) {
50+
selector.addEventListener("change", () => {
51+
if (selector.value === "") {
52+
// The user selects the "Select a revision ..." option.
53+
selectedRevision.set(null);
54+
} else {
55+
selectedRevision.set(selector.value as CxxRevision);
56+
}
57+
});
58+
}
59+
60+
selectedRevision.subscribe((rev) => {
61+
// Toggle all HTML elements with data-autorev-since and data-autorev-until
62+
// attributes.
63+
const elements = document.querySelectorAll<HTMLElement>(
64+
"[data-autorev-since], [data-autorev-until]"
65+
);
66+
elements.forEach((el) => {
67+
if (!rev) {
68+
el.classList.remove("autorev-hidden");
69+
return;
70+
}
71+
72+
const since = el.dataset.autorevSince as CxxRevision | undefined;
73+
const until = el.dataset.autorevUntil as CxxRevision | undefined;
74+
const inRangeTest = isRevisionInRange(rev, { since, until });
75+
if (inRangeTest === undefined || inRangeTest) {
76+
// An undefined inRangeTest indicates that the revisions associated with
77+
// the element are of a language different than the page's language. We
78+
// should always display such elements.
79+
el.classList.remove("autorev-hidden");
80+
} else {
81+
el.classList.add("autorev-hidden");
82+
}
83+
});
84+
});
85+
</script>

src/components/revision/autorev.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { CxxRevision } from "@src/types";
2+
3+
interface HTMLAutoRevisionAttributes {
4+
"data-autorev-since"?: CxxRevision;
5+
"data-autorev-until"?: CxxRevision;
6+
}
7+
8+
export interface AutorevProps {
9+
autorevSince?: CxxRevision;
10+
autorevUntil?: CxxRevision;
11+
}
12+
13+
export function autoRev(props: AutorevProps): HTMLAutoRevisionAttributes {
14+
return {
15+
"data-autorev-since": props.autorevSince,
16+
"data-autorev-until": props.autorevUntil,
17+
};
18+
}

0 commit comments

Comments
 (0)