Skip to content

Commit 5313c1b

Browse files
committed
fix(doc): fix broken links in documentation
1 parent 9abd0e1 commit 5313c1b

5 files changed

Lines changed: 289 additions & 3 deletions

File tree

.projenrc.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,11 @@ new TextFile(docsSite, 'astro.config.mjs', {
408408
" href: 'https://github.com/aws-samples/sample-autonomous-cloud-coding-agents',",
409409
' },',
410410
' ],',
411-
' components: {',
412-
" Search: './src/components/Search.astro',",
413-
' },',
411+
' components: {',
412+
" Search: './src/components/Search.astro',",
413+
" SiteTitle: './src/components/SiteTitle.astro',",
414+
" Sidebar: './src/components/Sidebar.astro',",
415+
' },',
414416
' head: [',
415417
' {',
416418
" tag: 'script',",

docs/astro.config.mjs

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

docs/src/components/Sidebar.astro

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
/**
3+
* Starlight Sidebar, but uses our SidebarSublist (absolute home URLs). The default Sidebar imports
4+
* `./SidebarSublist.astro` directly, so overriding only `SidebarSublist` in Starlight config has no effect.
5+
*/
6+
import MobileMenuFooter from 'virtual:starlight/components/MobileMenuFooter';
7+
import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
8+
import SidebarSublist from './SidebarSublist.astro';
9+
10+
const { sidebar } = Astro.locals.starlightRoute;
11+
---
12+
13+
<SidebarPersister>
14+
<!-- Starlight’s `sidebar` type is internal; our sublist markup matches its shape. -->
15+
<SidebarSublist sublist={sidebar as any} />
16+
</SidebarPersister>
17+
18+
<div class="md:sl-hidden">
19+
<MobileMenuFooter />
20+
</div>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
/**
3+
* Starlight SidebarSublist with absolute URLs for the docs home link (same rationale as SiteTitle).
4+
*/
5+
import { Icon, Badge } from '@astrojs/starlight/components';
6+
import SidebarRestorePoint from '@astrojs/starlight/components/SidebarRestorePoint.astro';
7+
8+
/** Mirrors Starlight’s sidebar tree shape (only what this template uses). */
9+
type SidebarLinkEntry = {
10+
type: 'link';
11+
href: string;
12+
label: string;
13+
isCurrent?: boolean;
14+
attrs: Record<string, string | boolean | undefined>;
15+
badge?: { variant: 'note' | 'danger' | 'success' | 'caution' | 'tip' | 'default'; class?: string; text: string };
16+
};
17+
type SidebarGroupEntry = {
18+
type: 'group';
19+
label: string;
20+
entries: SidebarTree[];
21+
collapsed?: boolean;
22+
badge?: SidebarLinkEntry['badge'];
23+
};
24+
type SidebarTree = SidebarLinkEntry | SidebarGroupEntry;
25+
26+
interface Props {
27+
sublist: SidebarTree[];
28+
nested?: boolean;
29+
}
30+
31+
const { sublist, nested } = Astro.props;
32+
33+
const site = Astro.site!;
34+
let homeAbs = new URL(import.meta.env.BASE_URL, site).href;
35+
if (!homeAbs.endsWith('/')) homeAbs += '/';
36+
const homePathNorm = new URL(import.meta.env.BASE_URL, site).pathname.replace(/\/$/, '') || '/';
37+
38+
function flattenSidebar(sidebar: SidebarTree[]): SidebarLinkEntry[] {
39+
return sidebar.flatMap((entry) =>
40+
entry.type === 'group' ? flattenSidebar(entry.entries) : entry
41+
);
42+
}
43+
44+
function resolveHref(href: string): string {
45+
try {
46+
const resolved = new URL(href, site);
47+
const path = resolved.pathname.replace(/\/$/, '') || '/';
48+
if (resolved.origin === new URL(site).origin && path === homePathNorm) {
49+
return homeAbs;
50+
}
51+
} catch {
52+
/* keep href */
53+
}
54+
return href;
55+
}
56+
---
57+
58+
<ul class:list={{ 'top-level': !nested }}>
59+
{
60+
sublist.map((entry) => (
61+
<li>
62+
{entry.type === 'link' ? (
63+
<a
64+
href={resolveHref(entry.href)}
65+
aria-current={entry.isCurrent ? 'page' : undefined}
66+
class:list={[{ large: !nested }, entry.attrs.class]}
67+
{...entry.attrs}
68+
>
69+
<span>{entry.label}</span>
70+
{entry.badge && (
71+
<Badge
72+
variant={entry.badge.variant}
73+
class={entry.badge.class}
74+
text={entry.badge.text}
75+
/>
76+
)}
77+
</a>
78+
) : (
79+
<details
80+
open={flattenSidebar(entry.entries).some((i) => i.isCurrent) || !entry.collapsed}
81+
>
82+
<summary>
83+
<span class="group-label">
84+
<span class="large">{entry.label}</span>
85+
{entry.badge && (
86+
<Badge
87+
variant={entry.badge.variant}
88+
class={entry.badge.class}
89+
text={entry.badge.text}
90+
/>
91+
)}
92+
</span>
93+
<Icon name="right-caret" class="caret" size="1.25rem" />
94+
</summary>
95+
<SidebarRestorePoint />
96+
<Astro.self sublist={entry.entries} nested />
97+
</details>
98+
)}
99+
</li>
100+
))
101+
}
102+
</ul>
103+
104+
<style>
105+
@layer starlight.core {
106+
ul {
107+
--sl-sidebar-item-padding-inline: 0.5rem;
108+
list-style: none;
109+
padding: 0;
110+
}
111+
112+
li {
113+
overflow-wrap: anywhere;
114+
}
115+
116+
ul ul li {
117+
margin-inline-start: var(--sl-sidebar-item-padding-inline);
118+
border-inline-start: 1px solid var(--sl-color-hairline-light);
119+
padding-inline-start: var(--sl-sidebar-item-padding-inline);
120+
}
121+
122+
.large {
123+
font-size: var(--sl-text-lg);
124+
font-weight: 600;
125+
color: var(--sl-color-white);
126+
}
127+
128+
.top-level > li + li {
129+
margin-top: 0.75rem;
130+
}
131+
132+
summary {
133+
display: flex;
134+
align-items: center;
135+
justify-content: space-between;
136+
padding: 0.2em var(--sl-sidebar-item-padding-inline);
137+
line-height: 1.4;
138+
cursor: pointer;
139+
user-select: none;
140+
}
141+
summary::marker,
142+
summary::-webkit-details-marker {
143+
display: none;
144+
}
145+
146+
.caret {
147+
transition: transform 0.2s ease-in-out;
148+
flex-shrink: 0;
149+
}
150+
:global([dir='rtl']) .caret {
151+
transform: rotateZ(180deg);
152+
}
153+
[open] > summary .caret {
154+
transform: rotateZ(90deg);
155+
}
156+
157+
a {
158+
display: block;
159+
border-radius: 0.25rem;
160+
text-decoration: none;
161+
color: var(--sl-color-gray-2);
162+
padding: 0.3em var(--sl-sidebar-item-padding-inline);
163+
line-height: 1.4;
164+
}
165+
166+
a:hover,
167+
a:focus {
168+
color: var(--sl-color-white);
169+
}
170+
171+
[aria-current='page'],
172+
[aria-current='page']:hover,
173+
[aria-current='page']:focus {
174+
font-weight: 600;
175+
color: var(--sl-color-text-invert);
176+
background-color: var(--sl-color-text-accent);
177+
}
178+
179+
a > *:not(:last-child),
180+
.group-label > *:not(:last-child) {
181+
margin-inline-end: 0.25em;
182+
}
183+
184+
@media (min-width: 50rem) {
185+
.top-level > li + li {
186+
margin-top: 0.5rem;
187+
}
188+
.large {
189+
font-size: var(--sl-text-base);
190+
}
191+
a {
192+
font-size: var(--sl-text-sm);
193+
}
194+
}
195+
}
196+
</style>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
/**
3+
* Same as Starlight’s SiteTitle, but the home link uses an absolute URL built from `site` + `base`.
4+
* Root-relative paths like `/repo/` can resolve incorrectly in some environments; matching the
5+
* canonical deployment URL avoids that.
6+
*/
7+
import { logos } from 'virtual:starlight/user-images';
8+
import config from 'virtual:starlight/user-config';
9+
10+
const { siteTitle } = Astro.locals.starlightRoute;
11+
let siteTitleHref = new URL(import.meta.env.BASE_URL, Astro.site!).href;
12+
if (!siteTitleHref.endsWith('/')) siteTitleHref += '/';
13+
---
14+
15+
<a href={siteTitleHref} class="site-title sl-flex">
16+
{
17+
config.logo && logos.dark && (
18+
<>
19+
<img
20+
class:list={{ 'light:sl-hidden print:hidden': !('src' in config.logo) }}
21+
alt={config.logo.alt}
22+
src={logos.dark.src}
23+
width={logos.dark.width}
24+
height={logos.dark.height}
25+
/>
26+
{!('src' in config.logo) && (
27+
<img
28+
class="dark:sl-hidden print:block"
29+
alt={config.logo.alt}
30+
src={logos.light?.src}
31+
width={logos.light?.width}
32+
height={logos.light?.height}
33+
/>
34+
)}
35+
</>
36+
)
37+
}
38+
<span class:list={{ 'sr-only': config.logo?.replacesTitle }} translate="no">
39+
{siteTitle}
40+
</span>
41+
</a>
42+
43+
<style>
44+
@layer starlight.core {
45+
.site-title {
46+
align-items: center;
47+
gap: var(--sl-nav-gap);
48+
font-size: var(--sl-text-h4);
49+
font-weight: 600;
50+
color: var(--sl-color-text-accent);
51+
text-decoration: none;
52+
white-space: nowrap;
53+
min-width: 0;
54+
}
55+
span {
56+
overflow: hidden;
57+
}
58+
img {
59+
height: calc(var(--sl-nav-height) - 2 * var(--sl-nav-pad-y));
60+
width: auto;
61+
max-width: 100%;
62+
object-fit: contain;
63+
object-position: 0 50%;
64+
}
65+
}
66+
</style>

0 commit comments

Comments
 (0)