1---
2import { TAB_ICONS } from "../../docs-icons";
3import { DOCS_TABS, activeTab } from "../../docs-tabs";
4
5const primary = DOCS_TABS.filter((tab) => tab.slot === "primary");
6const more = DOCS_TABS.filter((tab) => tab.slot === "more");
7const end = DOCS_TABS.filter((tab) => tab.slot === "end");
8
9const current = activeTab(Astro.url.pathname);
10const currentInMore = more.some((tab) => tab.label === current.label);
11
12const categories = [...new Set(more.map((tab) => tab.category))];
13---
14
15<nav class="alc-tabs" aria-label="Documentation sections">
16 <div class="alc-tabs__group">
17 {
18 primary.map((tab) => (
19 <a
20 href={tab.href}
21 class:list={["alc-tabs__tab", { "alc-tabs__tab--active": tab.label === current.label }]}
22 aria-current={tab.label === current.label ? "true" : undefined}
23 >
24 {TAB_ICONS[tab.label] && (
25 <svg
26 class="alc-tabs__icon"
27 aria-hidden="true"
28 width="14"
29 height="14"
30 viewBox="0 0 24 24"
31 set:html={TAB_ICONS[tab.label]}
32 />
33 )}
34 {tab.label}
35 </a>
36 ))
37 }
38
39 {/* Desktop: "More ▾" dropdown. When the active tab lives inside it, the
40 trigger renders as that tab (contextual), keeping your place visible. */}
41 <div class="alc-tabs__more">
42 <button
43 type="button"
44 class:list={["alc-tabs__tab", "alc-tabs__more-trigger", { "alc-tabs__tab--active": currentInMore }]}
45 aria-haspopup="true"
46 >
47 {
48 currentInMore && TAB_ICONS[current.label] && (
49 <svg
50 class="alc-tabs__icon"
51 aria-hidden="true"
52 width="14"
53 height="14"
54 viewBox="0 0 24 24"
55 set:html={TAB_ICONS[current.label]}
56 />
57 )
58 }
59 {currentInMore ? current.label : "More"}
60 <svg
61 class="alc-tabs__chevron"
62 aria-hidden="true"
63 width="12"
64 height="12"
65 viewBox="0 0 24 24"
66 fill="none"
67 stroke="currentColor"
68 stroke-width="2"
69 stroke-linecap="round"
70 stroke-linejoin="round"
71 >
72 <path d="m6 9 6 6 6-6" />
73 </svg>
74 </button>
75 <div class="alc-tabs__menu">
76 {
77 categories.map((category) => (
78 <div class="alc-tabs__menu-section">
79 <div class="alc-tabs__menu-heading">{category}</div>
80 {more
81 .filter((tab) => tab.category === category)
82 .map((tab) => (
83 <a
84 href={tab.href}
85 class:list={["alc-tabs__menu-item", { "alc-tabs__menu-item--active": tab.label === current.label }]}
86 aria-current={tab.label === current.label ? "true" : undefined}
87 >
88 {TAB_ICONS[tab.label] && (
89 <svg
90 class="alc-tabs__icon"
91 aria-hidden="true"
92 width="14"
93 height="14"
94 viewBox="0 0 24 24"
95 set:html={TAB_ICONS[tab.label]}
96 />
97 )}
98 <span class="alc-tabs__menu-text">
99 <span>{tab.label}</span>
100 {tab.hint && <span class="alc-tabs__menu-hint">{tab.hint}</span>}
101 </span>
102 </a>
103 ))}
104 </div>
105 ))
106 }
107 </div>
108 </div>
109
110 </div>
111
112 <div class="alc-tabs__group">
113 {
114 end.map((tab) => (
115 <a
116 href={tab.href}
117 class:list={["alc-tabs__tab", { "alc-tabs__tab--active": tab.label === current.label }]}
118 aria-current={tab.label === current.label ? "true" : undefined}
119 >
120 {TAB_ICONS[tab.label] && (
121 <svg
122 class="alc-tabs__icon"
123 aria-hidden="true"
124 width="14"
125 height="14"
126 viewBox="0 0 24 24"
127 set:html={TAB_ICONS[tab.label]}
128 />
129 )}
130 {tab.label}
131 </a>
132 ))
133 }
134 </div>
135</nav>
136
137<style>
138 .alc-tabs {
139 display: flex;
140 align-items: stretch;
141 justify-content: space-between;
142 gap: 16px;
143 height: var(--alc-tabs-height, 2.5rem);
144 margin: 0 calc(-1 * var(--sl-nav-pad-x));
145 padding: 0 calc(var(--sl-nav-pad-x) - 12px);
146 }
147 .alc-tabs__group {
148 display: flex;
149 align-items: stretch;
150 gap: 2px;
151 }
152 .alc-tabs__tab {
153 display: inline-flex;
154 align-items: center;
155 gap: 7px;
156 padding: 0 12px;
157 font-size: 13.5px;
158 color: var(--alc-fg-2);
159 text-decoration: none;
160 border: 0;
161 border-bottom: 2px solid transparent;
162 background: transparent;
163 font-family: inherit;
164 cursor: pointer;
165 white-space: nowrap;
166 transition: color var(--alc-dur) var(--alc-ease);
167 }
168 .alc-tabs__tab:hover {
169 color: var(--alc-accent-deep);
170 }
171 .alc-tabs__tab--active {
172 color: var(--alc-accent-deep);
173 font-weight: 500;
174 border-bottom-color: var(--alc-accent-deep);
175 }
176 .alc-tabs__icon {
177 flex-shrink: 0;
178 opacity: 0.85;
179 }
180 .alc-tabs__chevron {
181 margin-inline-start: -2px;
182 transition: transform var(--alc-dur) var(--alc-ease);
183 }
184 .alc-tabs__more {
185 position: relative;
186 display: flex;
187 align-items: stretch;
188 }
189 .alc-tabs__more:hover .alc-tabs__chevron,
190 .alc-tabs__more:focus-within .alc-tabs__chevron {
191 transform: rotateZ(180deg);
192 }
193 .alc-tabs__menu {
194 display: none;
195 position: absolute;
196 top: 100%;
197 inset-inline-start: 0;
198 min-width: 280px;
199 z-index: 30;
200 background: var(--alc-bg);
201 border: 1px solid var(--alc-hairline-2);
202 border-radius: 10px;
203 padding: 6px 0;
204 box-shadow: var(--alc-shadow-md, 0 8px 24px rgb(0 0 0 / 0.12));
205 }
206 .alc-tabs__more:hover .alc-tabs__menu,
207 .alc-tabs__more:focus-within .alc-tabs__menu {
208 display: block;
209 }
210 .alc-tabs__menu-section + .alc-tabs__menu-section {
211 border-top: 1px solid var(--alc-hairline);
212 margin-top: 6px;
213 padding-top: 6px;
214 }
215 .alc-tabs__menu-heading {
216 padding: 4px 14px;
217 font-size: 10.5px;
218 font-weight: 600;
219 letter-spacing: 0.07em;
220 text-transform: uppercase;
221 color: var(--alc-fg-4);
222 }
223 .alc-tabs__menu-item {
224 display: flex;
225 align-items: flex-start;
226 gap: 10px;
227 padding: 6px 14px;
228 font-size: 13px;
229 color: var(--alc-fg-2);
230 text-decoration: none;
231 }
232 .alc-tabs__menu-item > .alc-tabs__icon {
233 margin-block-start: calc((1lh - 14px) / 2);
234 }
235 .alc-tabs__menu-item:hover {
236 color: var(--alc-accent-deep);
237 background: var(--alc-bg-elev-1);
238 }
239 .alc-tabs__menu-item--active {
240 color: var(--alc-accent-deep);
241 font-weight: 500;
242 }
243 /* Stacked label + hint: every row renders the same height regardless
244 of hint length; a too-long hint ellipsizes instead of wrapping. */
245 .alc-tabs__menu-text {
246 display: flex;
247 flex-direction: column;
248 gap: 1px;
249 min-width: 0;
250 }
251 .alc-tabs__menu-hint {
252 font-size: 11px;
253 color: var(--alc-fg-4);
254 white-space: nowrap;
255 overflow: hidden;
256 text-overflow: ellipsis;
257 }
258 /* The tab bar is desktop-only: on mobile, product navigation lives in
259 the hamburger drawer's MobileTabSwitcher instead of a horizontally
260 scrollable strip nothing signals you can scroll. */
261 @media (max-width: 50rem) {
262 .alc-tabs {
263 display: none;
264 }
265 }
266</style>