radiant-docs 0.1.34 → 0.1.38
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/package.json +1 -1
- package/template/astro.config.mjs +27 -0
- package/template/package-lock.json +1027 -513
- package/template/package.json +3 -2
- package/template/scripts/generate-proxy-allowed-origins.mjs +217 -0
- package/template/scripts/generate-robots-txt.mjs +19 -0
- package/template/scripts/stamp-image-versions.mjs +63 -11
- package/template/src/components/Footer.astro +1 -1
- package/template/src/components/Header.astro +9 -9
- package/template/src/components/LogoLink.astro +2 -1
- package/template/src/components/OpenApiPage.astro +18 -18
- package/template/src/components/Search.astro +18 -18
- package/template/src/components/Sidebar.astro +4 -2
- package/template/src/components/SidebarDropdown.astro +82 -79
- package/template/src/components/SidebarGroup.astro +3 -0
- package/template/src/components/SidebarMenu.astro +14 -1
- package/template/src/components/SidebarSegmented.astro +5 -5
- package/template/src/components/SidebarSubgroup.astro +35 -12
- package/template/src/components/TableOfContents.astro +24 -15
- package/template/src/components/ThemeSwitcher.astro +15 -8
- package/template/src/components/chat/AskAiWidget.tsx +10 -5
- package/template/src/components/endpoint/PlaygroundBar.astro +3 -3
- package/template/src/components/endpoint/PlaygroundButton.astro +3 -3
- package/template/src/components/endpoint/PlaygroundField.astro +53 -53
- package/template/src/components/endpoint/PlaygroundForm.astro +51 -37
- package/template/src/components/endpoint/RequestSnippets.astro +54 -21
- package/template/src/components/endpoint/ResponseDisplay.astro +24 -24
- package/template/src/components/endpoint/ResponseFieldTree.astro +12 -12
- package/template/src/components/endpoint/ResponseFields.astro +19 -19
- package/template/src/components/endpoint/ResponseSnippets.astro +66 -29
- package/template/src/components/sidebar/SidebarEndpointLink.astro +18 -15
- package/template/src/components/sidebar/SidebarOpenApiPageLink.astro +56 -0
- package/template/src/components/ui/CodeTabEdge.astro +6 -4
- package/template/src/components/ui/Field.astro +7 -7
- package/template/src/components/ui/Icon.astro +2 -1
- package/template/src/components/ui/demo/Demo.astro +1 -1
- package/template/src/components/user/Accordion.astro +3 -3
- package/template/src/components/user/Callout.astro +8 -8
- package/template/src/components/user/CodeBlock.astro +57 -22
- package/template/src/components/user/CodeGroup.astro +14 -10
- package/template/src/components/user/ComponentPreviewBlock.astro +38 -12
- package/template/src/components/user/Image.astro +6 -2
- package/template/src/components/user/Step.astro +4 -4
- package/template/src/components/user/Tab.astro +1 -1
- package/template/src/components/user/Tabs.astro +15 -20
- package/template/src/layouts/Layout.astro +9 -4
- package/template/src/lib/code/code-block.ts +150 -15
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +639 -0
- package/template/src/lib/pagefind.ts +2 -1
- package/template/src/lib/routes.ts +134 -58
- package/template/src/lib/static-asset-url.ts +62 -0
- package/template/src/lib/utils.ts +48 -0
- package/template/src/lib/validation.ts +115 -27
- package/template/src/pages/404.astro +44 -0
- package/template/src/styles/global.css +28 -19
- package/template/scripts/rewrite-static-asset-host.mjs +0 -408
|
@@ -12,7 +12,7 @@ import { Icon } from "astro-icon/components";
|
|
|
12
12
|
<!-- Search Trigger Button -->
|
|
13
13
|
<button
|
|
14
14
|
x-on:click="open()"
|
|
15
|
-
class="md:bg-white/90 dark:md:bg-neutral-800 flex items-center gap-2 h-[33px] md:min-w-64 px-3 -mr-3 xs:mr-0 text-xs text-neutral-500/80 dark:text-neutral-400/
|
|
15
|
+
class="md:bg-white/90 dark:md:bg-neutral-800 flex items-center gap-2 h-[33px] md:min-w-64 px-3 -mr-3 xs:mr-0 text-xs text-neutral-500/80 dark:text-neutral-400/70 hover:text-neutral-500 dark:hover:text-neutral-400 md:border border-border rounded-lg cursor-pointer md:shadow-xs md:hover:shadow-sm transition"
|
|
16
16
|
>
|
|
17
17
|
<Icon name="lucide:search" class="size-5 md:size-4" />
|
|
18
18
|
<span class="hidden md:inline">Search documentation</span>
|
|
@@ -49,11 +49,11 @@ import { Icon } from "astro-icon/components";
|
|
|
49
49
|
<!-- Search Input -->
|
|
50
50
|
<div
|
|
51
51
|
class="flex items-center gap-3 px-4"
|
|
52
|
-
:class="{ 'border-b border-neutral-200/80': results.length > 0 || (query.length > 0 && !loading) }"
|
|
52
|
+
:class="{ 'border-b border-neutral-200/80 dark:border-neutral-700/70': results.length > 0 || (query.length > 0 && !loading) }"
|
|
53
53
|
>
|
|
54
54
|
<Icon
|
|
55
55
|
name="lucide:search"
|
|
56
|
-
class="size-5 sm:size-[18px] text-neutral-400 shrink-0"
|
|
56
|
+
class="size-5 sm:size-[18px] text-neutral-400 dark:text-neutral-500 shrink-0"
|
|
57
57
|
/>
|
|
58
58
|
<input
|
|
59
59
|
x-ref="searchInput"
|
|
@@ -65,18 +65,18 @@ import { Icon } from "astro-icon/components";
|
|
|
65
65
|
x-on:keydown.enter.prevent="goToSelected()"
|
|
66
66
|
type="text"
|
|
67
67
|
placeholder="Search documentation..."
|
|
68
|
-
class="flex-1 py-4 text-base bg-transparent outline-none placeholder:text-neutral-400 sm:text-sm"
|
|
68
|
+
class="flex-1 py-4 text-base bg-transparent text-neutral-900 dark:text-neutral-100 outline-none placeholder:text-neutral-400 dark:placeholder:text-neutral-500 sm:text-sm"
|
|
69
69
|
/>
|
|
70
70
|
<div x-show="loading" class="shrink-0 p-1">
|
|
71
71
|
<Icon
|
|
72
72
|
name="lucide:loader"
|
|
73
|
-
class="w-4 h-4 text-neutral-400 animate-spin"
|
|
73
|
+
class="w-4 h-4 text-neutral-400 dark:text-neutral-500 animate-spin"
|
|
74
74
|
/>
|
|
75
75
|
</div>
|
|
76
76
|
<button
|
|
77
77
|
x-show="query.length > 0 && !loading"
|
|
78
78
|
x-on:click="clear()"
|
|
79
|
-
class="shrink-0 p-1 text-neutral-400 hover:text-neutral-600 transition-colors"
|
|
79
|
+
class="shrink-0 p-1 text-neutral-400 dark:text-neutral-500 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors"
|
|
80
80
|
>
|
|
81
81
|
<Icon name="lucide:x" class="w-4 h-4" />
|
|
82
82
|
</button>
|
|
@@ -87,14 +87,14 @@ import { Icon } from "astro-icon/components";
|
|
|
87
87
|
<!-- No Results -->
|
|
88
88
|
<div
|
|
89
89
|
x-show="query.length > 0 && results.length === 0 && !loading"
|
|
90
|
-
class="px-4 py-8 text-center text-neutral-500"
|
|
90
|
+
class="px-4 py-8 text-center text-neutral-500 dark:text-neutral-400"
|
|
91
91
|
>
|
|
92
92
|
<Icon
|
|
93
93
|
name="lucide:search-slash"
|
|
94
|
-
class="size-8 mx-auto mb-3 text-neutral-300"
|
|
94
|
+
class="size-8 mx-auto mb-3 text-neutral-300 dark:text-neutral-600"
|
|
95
95
|
/>
|
|
96
96
|
<p class="text-sm">
|
|
97
|
-
No results found for <strong class="text-neutral-600"
|
|
97
|
+
No results found for <strong class="text-neutral-600 dark:text-neutral-300"
|
|
98
98
|
>"<span x-text="query"></span>"</strong
|
|
99
99
|
>.
|
|
100
100
|
</p>
|
|
@@ -103,7 +103,7 @@ import { Icon } from "astro-icon/components";
|
|
|
103
103
|
<!-- Results List -->
|
|
104
104
|
<ul
|
|
105
105
|
x-show="results.length > 0"
|
|
106
|
-
class="divide-y divide-neutral-200/80"
|
|
106
|
+
class="divide-y divide-neutral-200/80 dark:divide-neutral-700/70"
|
|
107
107
|
>
|
|
108
108
|
<template
|
|
109
109
|
x-for="(result, index) in results"
|
|
@@ -115,30 +115,30 @@ import { Icon } from "astro-icon/components";
|
|
|
115
115
|
x-on:click="close()"
|
|
116
116
|
x-on:mouseenter="selectedIndex = index"
|
|
117
117
|
class="flex flex-col gap-1 px-4 py-3 transition-colors"
|
|
118
|
-
:class="{ 'bg-neutral-100/60': selectedIndex === index }"
|
|
118
|
+
:class="{ 'bg-neutral-100/60 dark:bg-neutral-700/30': selectedIndex === index }"
|
|
119
119
|
>
|
|
120
120
|
<div class="flex items-center gap-2">
|
|
121
121
|
<!-- Page icon -->
|
|
122
122
|
<Icon
|
|
123
123
|
name="lucide:file"
|
|
124
124
|
x-show="result.type === 'page'"
|
|
125
|
-
class="w-4 h-4 text-neutral-400 shrink-0"
|
|
125
|
+
class="w-4 h-4 text-neutral-400 dark:text-neutral-500 shrink-0"
|
|
126
126
|
/>
|
|
127
127
|
<!-- Heading icon -->
|
|
128
128
|
<Icon
|
|
129
129
|
name="lucide:hash"
|
|
130
130
|
x-show="result.type === 'heading'"
|
|
131
|
-
class="w-4 h-4 text-neutral-400 shrink-0"
|
|
131
|
+
class="w-4 h-4 text-neutral-400 dark:text-neutral-500 shrink-0"
|
|
132
132
|
/>
|
|
133
133
|
<!-- Content/body text icon -->
|
|
134
134
|
<Icon
|
|
135
135
|
name="lucide:text"
|
|
136
136
|
x-show="result.type === 'content'"
|
|
137
|
-
class="w-4 h-4 text-neutral-400 shrink-0"
|
|
137
|
+
class="w-4 h-4 text-neutral-400 dark:text-neutral-500 shrink-0"
|
|
138
138
|
/>
|
|
139
139
|
<!-- Parent title breadcrumb -->
|
|
140
140
|
<span
|
|
141
|
-
class="text-sm text-neutral-500 truncate"
|
|
141
|
+
class="text-sm text-neutral-500 dark:text-neutral-400 truncate"
|
|
142
142
|
x-show="result.parentTitle"
|
|
143
143
|
>
|
|
144
144
|
<span x-text="result.parentTitle"></span>
|
|
@@ -147,17 +147,17 @@ import { Icon } from "astro-icon/components";
|
|
|
147
147
|
<!-- Title: highlighted for page/heading, plain for content -->
|
|
148
148
|
<span
|
|
149
149
|
x-show="result.type === 'page' || result.type === 'heading'"
|
|
150
|
-
class="font-medium text-neutral-900 truncate [&_mark]:bg-neutral-200 [&_mark]:text-neutral-900 [&_mark]:rounded [&_mark]:px-0.5"
|
|
150
|
+
class="font-medium text-neutral-900 dark:text-neutral-100 truncate [&_mark]:bg-neutral-200 [&_mark]:text-neutral-900 dark:[&_mark]:bg-neutral-700 dark:[&_mark]:text-neutral-100 [&_mark]:rounded [&_mark]:px-0.5"
|
|
151
151
|
x-html="highlightMatch(result.title, query)"></span>
|
|
152
152
|
<span
|
|
153
153
|
x-show="result.type === 'content'"
|
|
154
|
-
class="font-medium text-neutral-900 truncate"
|
|
154
|
+
class="font-medium text-neutral-900 dark:text-neutral-100 truncate"
|
|
155
155
|
x-text="result.title"></span>
|
|
156
156
|
</div>
|
|
157
157
|
<!-- Excerpt: only for content type -->
|
|
158
158
|
<p
|
|
159
159
|
x-show="result.type === 'content'"
|
|
160
|
-
class="text-sm text-neutral-600 line-clamp-2 pl-6 [&_mark]:bg-neutral-200 [&_mark]:text-neutral-900 [&_mark]:rounded [&_mark]:px-0.5"
|
|
160
|
+
class="text-sm text-neutral-600 dark:text-neutral-300 line-clamp-2 pl-6 [&_mark]:bg-neutral-200 [&_mark]:text-neutral-900 dark:[&_mark]:bg-neutral-700 dark:[&_mark]:text-neutral-100 [&_mark]:rounded [&_mark]:px-0.5"
|
|
161
161
|
x-html="result.excerpt"
|
|
162
162
|
>
|
|
163
163
|
</p>
|
|
@@ -7,11 +7,13 @@ const config: DocsConfig = await getConfig();
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<aside class="flex flex-col h-full">
|
|
10
|
-
<nav
|
|
10
|
+
<nav
|
|
11
|
+
class="overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
|
12
|
+
>
|
|
11
13
|
<SidebarMenu navigation={config.navigation} />
|
|
12
14
|
</nav>
|
|
13
15
|
<div
|
|
14
|
-
class="mt-auto bg-
|
|
16
|
+
class="mt-auto bg-background z-10 p-3 border-t border-t-border-light flex gap-1.5 justify-end items-center"
|
|
15
17
|
>
|
|
16
18
|
<span class="text-neutral-400 text-xs font-light">Theme</span>
|
|
17
19
|
<ThemeSwitcher />
|
|
@@ -69,88 +69,91 @@ const currentPrefix = parentSlug
|
|
|
69
69
|
<div x-data=`{
|
|
70
70
|
open: false,
|
|
71
71
|
}`>
|
|
72
|
-
<div
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
72
|
+
<div class="mt-3 mx-2 z-10 relative dark:bg-neutral-900 rounded-lg">
|
|
73
|
+
<div
|
|
74
|
+
class:list={[
|
|
75
|
+
"",
|
|
76
|
+
menu.label &&
|
|
77
|
+
"rounded-lg bg-neutral-100 dark:bg-neutral-800/60 p-[3px]",
|
|
78
|
+
]}
|
|
79
|
+
>
|
|
80
|
+
{
|
|
81
|
+
menu.label && (
|
|
82
|
+
<label class="font-semibold text-xs px-2 py-1.5 block">
|
|
83
|
+
{menu.label}
|
|
84
|
+
</label>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
<div class="relative">
|
|
88
|
+
<button
|
|
89
|
+
class="flex items-center w-full text-sm text-neutral-700 dark:text-neutral-200 bg-white dark:bg-neutral-700/30 border-t border-x border-neutral-200/70 dark:border-neutral-700/40 dark:border-b rounded-lg shadow-xs px-3 py-2 cursor-pointer"
|
|
90
|
+
x-on:click="open = true"
|
|
91
|
+
aria-haspopup="menu"
|
|
92
|
+
aria-expanded
|
|
93
|
+
>
|
|
94
|
+
{
|
|
95
|
+
menu.items[currentMenuIndex].icon && (
|
|
96
|
+
<Icon
|
|
97
|
+
class="mr-2 size-4 opacity-80"
|
|
98
|
+
name={menu.items[currentMenuIndex].icon}
|
|
99
|
+
/>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
<span class="font-medium">{menu.items[currentMenuIndex].label}</span>
|
|
103
|
+
<Icon class="ml-auto" name="lucide:chevrons-up-down" />
|
|
104
|
+
</button>
|
|
105
|
+
<div class="fixed inset-0 z-50" x-show="open" x-on:click="open = false">
|
|
106
|
+
</div>
|
|
107
|
+
<ul
|
|
108
|
+
class:list={[
|
|
109
|
+
"z-50 absolute bg-white dark:bg-neutral-800 border dark:border-neutral-700/40 rounded-lg inset-x-0 top-full py-[3px] shadow-xl overflow-hidden",
|
|
110
|
+
menu.label ? "mt-1.5" : "mt-1",
|
|
111
|
+
]}
|
|
112
|
+
x-init
|
|
113
|
+
role="menu"
|
|
114
|
+
x-show="open"
|
|
115
|
+
x-transition.origin.top
|
|
116
|
+
x-cloak
|
|
117
|
+
>
|
|
118
|
+
{
|
|
119
|
+
menu.items.map(({ label }, index) => {
|
|
120
|
+
return (
|
|
121
|
+
<li
|
|
122
|
+
x-data={`{
|
|
121
123
|
index: ${index}
|
|
122
124
|
}`}
|
|
123
|
-
|
|
124
|
-
>
|
|
125
|
-
<a
|
|
126
|
-
class="flex items-center px-3 py-2 cursor-pointer text-sm text-neutral-700 relative z-0 before:-z-10 before:absolute before:inset-x-1 before:inset-y-px before:rounded-md before:duration-150"
|
|
127
|
-
class:list={[
|
|
128
|
-
index === currentMenuIndex
|
|
129
|
-
? "before:bg-neutral-200/50 text-neutral-900"
|
|
130
|
-
: "hover:before:bg-neutral-100/70",
|
|
131
|
-
]}
|
|
132
|
-
href={firstHrefOfMenuItems[index] ?? "/"}
|
|
125
|
+
role="menuitem"
|
|
133
126
|
>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
127
|
+
<a
|
|
128
|
+
class="flex items-center px-3 py-2 cursor-pointer text-sm text-neutral-700 dark:text-neutral-300 relative z-0 before:-z-10 before:absolute before:inset-x-1 before:inset-y-px before:rounded-md before:duration-150"
|
|
129
|
+
class:list={[
|
|
130
|
+
index === currentMenuIndex
|
|
131
|
+
? "before:bg-neutral-200/50 dark:before:bg-neutral-700/50 text-neutral-900 dark:text-white"
|
|
132
|
+
: "hover:before:bg-neutral-100/70 dark:hover:before:bg-neutral-700/30",
|
|
133
|
+
]}
|
|
134
|
+
href={firstHrefOfMenuItems[index] ?? "/"}
|
|
135
|
+
>
|
|
136
|
+
{menu.items[index].icon && (
|
|
137
|
+
<Icon
|
|
138
|
+
class="mr-2 size-4 opacity-75"
|
|
139
|
+
name={menu.items[index].icon}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
{label}
|
|
143
|
+
{index === currentMenuIndex && (
|
|
144
|
+
<Icon
|
|
145
|
+
class="ml-auto text-primary [&_path]:stroke-3"
|
|
146
|
+
name="lucide:check"
|
|
147
|
+
stroke-width={10}
|
|
148
|
+
/>
|
|
149
|
+
)}
|
|
150
|
+
</a>
|
|
151
|
+
</li>
|
|
152
|
+
);
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
</ul>
|
|
156
|
+
</div>
|
|
154
157
|
</div>
|
|
155
158
|
</div>
|
|
156
159
|
<div
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { NavGroup } from "../lib/validation";
|
|
3
3
|
import SidebarLink from "./SidebarLink.astro";
|
|
4
|
+
import SidebarOpenApiPageLink from "./sidebar/SidebarOpenApiPageLink.astro";
|
|
4
5
|
import SidebarSubgroup from "./SidebarSubgroup.astro";
|
|
5
6
|
import { slugify } from "../lib/utils";
|
|
6
7
|
import Tag from "./ui/Tag.astro";
|
|
@@ -38,6 +39,8 @@ const currentPrefix = parentSlug ? `${parentSlug}/${groupSlug}` : groupSlug;
|
|
|
38
39
|
title={child.title}
|
|
39
40
|
groupSlug={currentPrefix}
|
|
40
41
|
/>
|
|
42
|
+
) : "openapi" in child ? (
|
|
43
|
+
<SidebarOpenApiPageLink item={child} parentSlug={currentPrefix} />
|
|
41
44
|
) : (
|
|
42
45
|
<SidebarSubgroup item={child} parentSlug={currentPrefix} />
|
|
43
46
|
)}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
NavGroup,
|
|
4
|
+
NavigationItem,
|
|
5
|
+
NavOpenApiPage,
|
|
6
|
+
NavPage,
|
|
7
|
+
} from "../lib/validation";
|
|
3
8
|
import SidebarOpenApi from "./sidebar/SidebarOpenApi.astro";
|
|
9
|
+
import SidebarOpenApiPageLink from "./sidebar/SidebarOpenApiPageLink.astro";
|
|
4
10
|
import SidebarDropdown from "./SidebarDropdown.astro";
|
|
5
11
|
import SidebarSegmented from "./SidebarSegmented.astro";
|
|
6
12
|
import SidebarGroup from "./SidebarGroup.astro";
|
|
@@ -24,6 +30,13 @@ let { navigation, parentSlug = "" } = Astro.props;
|
|
|
24
30
|
</li>
|
|
25
31
|
) : "group" in item ? (
|
|
26
32
|
<SidebarGroup item={item as NavGroup} parentSlug={parentSlug} />
|
|
33
|
+
) : "openapi" in item ? (
|
|
34
|
+
<li>
|
|
35
|
+
<SidebarOpenApiPageLink
|
|
36
|
+
item={item as NavOpenApiPage}
|
|
37
|
+
parentSlug={parentSlug}
|
|
38
|
+
/>
|
|
39
|
+
</li>
|
|
27
40
|
) : (
|
|
28
41
|
<li>
|
|
29
42
|
<SidebarLink
|
|
@@ -65,22 +65,22 @@ const currentPrefix = parentSlug
|
|
|
65
65
|
: menuItemSlug;
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
-
<div class="mt-3 mx-2">
|
|
68
|
+
<div class="mt-3 mx-2 z-10 relative dark:bg-neutral-900 rounded-lg">
|
|
69
69
|
{
|
|
70
70
|
menu.label && (
|
|
71
71
|
<label class="font-semibold text-xs px-2 pb-1 block">{menu.label}</label>
|
|
72
72
|
)
|
|
73
73
|
}
|
|
74
|
-
<ul class="rounded-lg bg-neutral-100 p-[3px]">
|
|
74
|
+
<ul class="rounded-lg bg-neutral-100 dark:bg-neutral-800/60 p-[3px]">
|
|
75
75
|
{
|
|
76
76
|
menu.items.map((item, index) => (
|
|
77
77
|
<li>
|
|
78
78
|
<a
|
|
79
|
-
class="flex items-center px-3 py-1.5 cursor-pointer text-sm rounded-md border-x border-t"
|
|
79
|
+
class="flex items-center px-3 py-1.5 cursor-pointer text-sm rounded-md border-x border-t transition-colors duration-150"
|
|
80
80
|
class:list={[
|
|
81
81
|
index === currentMenuIndex
|
|
82
|
-
? "bg-white border-neutral-200/70 shadow-sm shadow-neutral-200 text-neutral-900"
|
|
83
|
-
: "text-neutral-600 border-transparent",
|
|
82
|
+
? "bg-white dark:bg-neutral-700/30 border-neutral-200/70 dark:border-neutral-700/40 dark:border-b shadow-sm shadow-neutral-200/80 dark:shadow-neutral-950/20 text-neutral-900 dark:text-white"
|
|
83
|
+
: "text-neutral-600 dark:text-neutral-300 border-transparent hover:text-primary dark:hover:text-primary",
|
|
84
84
|
]}
|
|
85
85
|
href={firstHrefOfMenuItems[index] ?? "/"}
|
|
86
86
|
>
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getConfig, type NavGroup } from "../lib/validation";
|
|
3
3
|
import SidebarLink from "./SidebarLink.astro";
|
|
4
|
-
import
|
|
4
|
+
import SidebarOpenApiPageLink from "./sidebar/SidebarOpenApiPageLink.astro";
|
|
5
|
+
import {
|
|
6
|
+
buildMdxPageHref,
|
|
7
|
+
buildOpenApiEndpointHref,
|
|
8
|
+
parseOpenApiEndpoint,
|
|
9
|
+
slugify,
|
|
10
|
+
} from "../lib/utils";
|
|
5
11
|
import Tag from "./ui/Tag.astro";
|
|
6
12
|
import Icon from "./ui/Icon.astro";
|
|
7
13
|
|
|
@@ -21,22 +27,37 @@ const listId = `list-${groupId}`;
|
|
|
21
27
|
|
|
22
28
|
// Check if any child page is active (shallow check, no recursion needed)
|
|
23
29
|
const containsActivePage = item.pages.some((child) => {
|
|
24
|
-
|
|
25
|
-
typeof child === "string" ? child : "pages" in child ? null : child.page;
|
|
30
|
+
let href: string | null = null;
|
|
26
31
|
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
filePath:
|
|
32
|
+
if (typeof child === "string") {
|
|
33
|
+
href = buildMdxPageHref({
|
|
34
|
+
filePath: child,
|
|
30
35
|
groupSlug: currentPrefix,
|
|
31
36
|
homePath: config.home,
|
|
32
37
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
} else if ("page" in child) {
|
|
39
|
+
href = buildMdxPageHref({
|
|
40
|
+
filePath: child.page,
|
|
41
|
+
groupSlug: currentPrefix,
|
|
42
|
+
homePath: config.home,
|
|
43
|
+
});
|
|
44
|
+
} else if ("openapi" in child) {
|
|
45
|
+
const parsedEndpoint = parseOpenApiEndpoint(child.openapi.endpoint);
|
|
46
|
+
if (parsedEndpoint) {
|
|
47
|
+
href = buildOpenApiEndpointHref({
|
|
48
|
+
path: parsedEndpoint.path,
|
|
49
|
+
method: parsedEndpoint.method,
|
|
50
|
+
groupSlug: currentPrefix,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
38
53
|
}
|
|
39
|
-
|
|
54
|
+
|
|
55
|
+
if (!href) return false;
|
|
56
|
+
|
|
57
|
+
// Normalize paths for comparison (remove trailing slashes)
|
|
58
|
+
const normalizedCurrent = Astro.url.pathname.replace(/\/$/, "");
|
|
59
|
+
const normalizedTarget = href.replace(/\/$/, "");
|
|
60
|
+
return normalizedCurrent === normalizedTarget;
|
|
40
61
|
});
|
|
41
62
|
---
|
|
42
63
|
|
|
@@ -100,6 +121,8 @@ const containsActivePage = item.pages.some((child) => {
|
|
|
100
121
|
title={child.title}
|
|
101
122
|
groupSlug={currentPrefix}
|
|
102
123
|
/>
|
|
124
|
+
) : "openapi" in child ? (
|
|
125
|
+
<SidebarOpenApiPageLink item={child} parentSlug={currentPrefix} />
|
|
103
126
|
) : null}
|
|
104
127
|
</li>
|
|
105
128
|
))
|
|
@@ -33,15 +33,15 @@ for (const heading of headings) {
|
|
|
33
33
|
aria-label="Table of Contents"
|
|
34
34
|
data-slugs={JSON.stringify(headings.map((h) => h.slug))}
|
|
35
35
|
>
|
|
36
|
-
<div class="text-sm font-medium mb-3">On this page</div>
|
|
37
|
-
<div class="flex text-neutral-600/90">
|
|
36
|
+
<div class="text-sm font-medium mb-3 text-neutral-900 dark:text-neutral-100">On this page</div>
|
|
37
|
+
<div class="flex text-neutral-600/90 dark:text-neutral-300/90">
|
|
38
38
|
<svg viewBox="0 0 22 100" width="22px" height="100" class="shrink-0">
|
|
39
39
|
<path
|
|
40
40
|
id="toc-bg-path"
|
|
41
41
|
d=""
|
|
42
42
|
stroke-width="1.2"
|
|
43
43
|
vector-effect="non-scaling-stroke"
|
|
44
|
-
class="stroke-neutral-200"
|
|
44
|
+
class="stroke-neutral-200 dark:stroke-neutral-700/70"
|
|
45
45
|
fill="none"
|
|
46
46
|
stroke-linecap="round"
|
|
47
47
|
stroke-linejoin="round"></path>
|
|
@@ -50,7 +50,7 @@ for (const heading of headings) {
|
|
|
50
50
|
d=""
|
|
51
51
|
stroke-width="1.4"
|
|
52
52
|
vector-effect="non-scaling-stroke"
|
|
53
|
-
class="stroke-
|
|
53
|
+
class="stroke-neutral-700/70 dark:stroke-neutral-300/80 transition-[stroke-dasharray] duration-200"
|
|
54
54
|
fill="none"
|
|
55
55
|
stroke-linecap="round"
|
|
56
56
|
stroke-linejoin="round"></path>
|
|
@@ -63,7 +63,7 @@ for (const heading of headings) {
|
|
|
63
63
|
{heading.text && (
|
|
64
64
|
<a
|
|
65
65
|
href={`#${heading.slug}`}
|
|
66
|
-
class="block transition duration-200 hover:text-neutral-900"
|
|
66
|
+
class="block transition duration-200 hover:text-neutral-900 dark:hover:text-neutral-100"
|
|
67
67
|
data-slug={heading.slug}
|
|
68
68
|
>
|
|
69
69
|
{heading.text}
|
|
@@ -75,7 +75,7 @@ for (const heading of headings) {
|
|
|
75
75
|
<li class:list={["", heading.text ? "mt-3" : "mt-0"]}>
|
|
76
76
|
<a
|
|
77
77
|
href={`#${subHeading.slug}`}
|
|
78
|
-
class="block transition duration-200 hover:text-neutral-900"
|
|
78
|
+
class="block transition duration-200 hover:text-neutral-900 dark:hover:text-neutral-100"
|
|
79
79
|
data-slug={subHeading.slug}
|
|
80
80
|
>
|
|
81
81
|
{subHeading.text}
|
|
@@ -239,10 +239,11 @@ for (const heading of headings) {
|
|
|
239
239
|
);
|
|
240
240
|
circle.setAttribute("cx", String(item.x));
|
|
241
241
|
circle.setAttribute("cy", String(midY));
|
|
242
|
-
circle.setAttribute("r", "2.
|
|
242
|
+
circle.setAttribute("r", "2.25");
|
|
243
243
|
circle.setAttribute("fill", "currentColor");
|
|
244
244
|
circle.classList.add(
|
|
245
245
|
"fill-neutral-300",
|
|
246
|
+
"dark:fill-neutral-600",
|
|
246
247
|
"transition-all",
|
|
247
248
|
"duration-200"
|
|
248
249
|
);
|
|
@@ -328,13 +329,21 @@ for (const heading of headings) {
|
|
|
328
329
|
circles?.forEach((circle) => {
|
|
329
330
|
const slug = (circle as SVGCircleElement).dataset.slug;
|
|
330
331
|
if (slug && visibleSlugs.has(slug)) {
|
|
331
|
-
circle.classList.remove("fill-neutral-300");
|
|
332
|
-
circle.classList.add(
|
|
333
|
-
|
|
332
|
+
circle.classList.remove("fill-neutral-300", "dark:fill-neutral-600");
|
|
333
|
+
circle.classList.add(
|
|
334
|
+
"fill-neutral-700",
|
|
335
|
+
"dark:fill-neutral-200",
|
|
336
|
+
"delay-100"
|
|
337
|
+
);
|
|
338
|
+
circle.setAttribute("r", "2.75");
|
|
334
339
|
} else {
|
|
335
|
-
circle.classList.remove(
|
|
336
|
-
|
|
337
|
-
|
|
340
|
+
circle.classList.remove(
|
|
341
|
+
"fill-neutral-700",
|
|
342
|
+
"dark:fill-neutral-200",
|
|
343
|
+
"delay-100"
|
|
344
|
+
);
|
|
345
|
+
circle.classList.add("fill-neutral-300", "dark:fill-neutral-600");
|
|
346
|
+
circle.setAttribute("r", "2.25");
|
|
338
347
|
}
|
|
339
348
|
});
|
|
340
349
|
|
|
@@ -343,9 +352,9 @@ for (const heading of headings) {
|
|
|
343
352
|
tocLinks?.forEach((link) => {
|
|
344
353
|
const slug = (link as HTMLAnchorElement).dataset.slug;
|
|
345
354
|
if (slug && visibleSlugs.has(slug)) {
|
|
346
|
-
link.classList.add("text-neutral-900");
|
|
355
|
+
link.classList.add("text-neutral-900", "dark:text-neutral-100");
|
|
347
356
|
} else {
|
|
348
|
-
link.classList.remove("text-neutral-900");
|
|
357
|
+
link.classList.remove("text-neutral-900", "dark:text-neutral-100");
|
|
349
358
|
}
|
|
350
359
|
});
|
|
351
360
|
}
|
|
@@ -9,6 +9,7 @@ import { Icon } from "astro-icon/components";
|
|
|
9
9
|
return mode === 'light' || mode === 'dark' ? mode : null;
|
|
10
10
|
})(),
|
|
11
11
|
theme: localStorage.getItem('theme') || 'system',
|
|
12
|
+
themeSwitchFrameId: null,
|
|
12
13
|
init() {
|
|
13
14
|
if (this.forcedTheme) {
|
|
14
15
|
this.theme = this.forcedTheme;
|
|
@@ -43,16 +44,22 @@ import { Icon } from "astro-icon/components";
|
|
|
43
44
|
});
|
|
44
45
|
},
|
|
45
46
|
updateDOM() {
|
|
46
|
-
document.documentElement
|
|
47
|
+
const root = document.documentElement;
|
|
48
|
+
root.classList.add('is-switching-theme');
|
|
47
49
|
const activeTheme = this.forcedTheme || this.theme;
|
|
48
50
|
const isDark = activeTheme === 'dark' ||
|
|
49
51
|
(activeTheme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
root.classList.toggle('dark', isDark);
|
|
54
|
+
root.dataset.theme = isDark ? 'dark' : 'light';
|
|
55
|
+
|
|
56
|
+
if (this.themeSwitchFrameId !== null) {
|
|
57
|
+
cancelAnimationFrame(this.themeSwitchFrameId);
|
|
58
|
+
}
|
|
59
|
+
this.themeSwitchFrameId = requestAnimationFrame(() => {
|
|
60
|
+
root.classList.remove('is-switching-theme');
|
|
61
|
+
this.themeSwitchFrameId = null;
|
|
62
|
+
});
|
|
56
63
|
},
|
|
57
64
|
markerStyle: { left: null, width: null },
|
|
58
65
|
updateMarker() {
|
|
@@ -67,10 +74,10 @@ import { Icon } from "astro-icon/components";
|
|
|
67
74
|
}
|
|
68
75
|
}
|
|
69
76
|
}"
|
|
70
|
-
class="relative flex gap-[3px] p-px bg-
|
|
77
|
+
class="relative flex gap-[3px] p-px bg-background-dark dark:bg-neutral-800/40 rounded-full w-fit text-neutral-500"
|
|
71
78
|
>
|
|
72
79
|
<div
|
|
73
|
-
class="anchor-pill absolute top-px bottom-px bg-white dark:bg-neutral-
|
|
80
|
+
class="anchor-pill absolute top-px dark:top-0.5 bottom-px dark:bottom-0.5 bg-white dark:bg-neutral-800 rounded-full shadow-xs border-[0.5px] border-neutral-200/80 dark:border-neutral-700/50 ease-out z-0 flex items-center justify-center animate-[scaleIn_0.5s_ease-out]"
|
|
74
81
|
style="left: 3px;"
|
|
75
82
|
:style="markerStyle.width ? `left: ${markerStyle.left}; width: ${markerStyle.width}` : ''"
|
|
76
83
|
>
|