rapidoc 11.0.1 → 12.1.0

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.
Files changed (96) hide show
  1. package/README.md +171 -54
  2. package/dist/rapidoc-flow-min.js +580 -0
  3. package/dist/rapidoc-flow-min.js.LICENSE.txt +171 -0
  4. package/dist/rapidoc-min.js +645 -202
  5. package/dist/rapidoc-min.js.LICENSE.txt +381 -0
  6. package/package.json +57 -42
  7. package/src/README.md +150 -0
  8. package/src/components/README.md +91 -0
  9. package/src/components/api-request.ts +912 -0
  10. package/src/components/api-response.ts +514 -0
  11. package/src/components/json-tree.ts +171 -0
  12. package/src/components/schema-base-element.ts +329 -0
  13. package/src/components/schema-table.ts +475 -0
  14. package/src/components/schema-tree.ts +393 -0
  15. package/src/components/tag-input.ts +180 -0
  16. package/src/flow.js +3 -0
  17. package/src/index.js +6 -0
  18. package/src/oauth-receiver.ts +29 -0
  19. package/src/rapi-flow.ts +1178 -0
  20. package/src/rapidoc-mini.ts +603 -0
  21. package/src/rapidoc.ts +1854 -0
  22. package/src/styles/README.md +96 -0
  23. package/src/styles/auth-styles.js +318 -0
  24. package/src/styles/border-styles.js +24 -0
  25. package/src/styles/css-bundle.js +129 -0
  26. package/src/styles/custom-styles.js +8 -0
  27. package/src/styles/dialog-box-styles.js +102 -0
  28. package/src/styles/endpoint-styles.js +564 -0
  29. package/src/styles/flex-styles.js +16 -0
  30. package/src/styles/flow-styles.js +248 -0
  31. package/src/styles/font-styles.js +432 -0
  32. package/src/styles/info-styles.js +36 -0
  33. package/src/styles/input-styles.js +555 -0
  34. package/src/styles/layout-styles.js +396 -0
  35. package/src/styles/microlighter-styles.js +99 -0
  36. package/src/styles/nav-styles.js +633 -0
  37. package/src/styles/param-list-styles.js +261 -0
  38. package/src/styles/schema-styles.js +296 -0
  39. package/src/styles/tab-styles.js +106 -0
  40. package/src/styles/theme-tokens.js +582 -0
  41. package/src/templates/README.md +89 -0
  42. package/src/templates/advanced-search-dialog-template.js +94 -0
  43. package/src/templates/api-response-template.js +223 -0
  44. package/src/templates/callback-template.js +86 -0
  45. package/src/templates/code-samples-template.js +52 -0
  46. package/src/templates/components-template.js +86 -0
  47. package/src/templates/downloads-template.js +70 -0
  48. package/src/templates/endpoint-template.js +377 -0
  49. package/src/templates/expanded-endpoint-template.js +270 -0
  50. package/src/templates/focused-endpoint-template.js +146 -0
  51. package/src/templates/header-template.js +92 -0
  52. package/src/templates/logo-template.js +21 -0
  53. package/src/templates/main-body-template.js +102 -0
  54. package/src/templates/navbar-template.js +498 -0
  55. package/src/templates/overview-template.js +104 -0
  56. package/src/templates/request-body-template.js +673 -0
  57. package/src/templates/request-params-template.js +485 -0
  58. package/src/templates/security-scheme-template.js +1272 -0
  59. package/src/templates/server-template.js +153 -0
  60. package/src/utils/README.md +146 -0
  61. package/src/utils/arazzo/README.md +119 -0
  62. package/src/utils/arazzo/components.js +15 -0
  63. package/src/utils/arazzo/graph.js +269 -0
  64. package/src/utils/arazzo/index.js +52 -0
  65. package/src/utils/arazzo/operations.js +106 -0
  66. package/src/utils/arazzo/parse.js +196 -0
  67. package/src/utils/arazzo/refs.js +40 -0
  68. package/src/utils/arazzo/svg.js +707 -0
  69. package/src/utils/auto-color-scheme.js +99 -0
  70. package/src/utils/bind-navbar.js +175 -0
  71. package/src/utils/color-utils.js +59 -0
  72. package/src/utils/common-utils.js +191 -0
  73. package/src/utils/curl-utils.js +126 -0
  74. package/src/utils/highlighter.js +419 -0
  75. package/src/utils/markdown-utils.js +110 -0
  76. package/src/utils/mcp/README.md +155 -0
  77. package/src/utils/mcp/common.js +166 -0
  78. package/src/utils/mcp/manifest.js +382 -0
  79. package/src/utils/mcp/project/server.ts +53 -0
  80. package/src/utils/mcp/project.js +88 -0
  81. package/src/utils/mcp/runtime.js +289 -0
  82. package/src/utils/mcp/schema.js +98 -0
  83. package/src/utils/mcp/workflow-runtime.js +374 -0
  84. package/src/utils/mcp/workflows.js +240 -0
  85. package/src/utils/mcp/zip.js +102 -0
  86. package/src/utils/mcp-generator.js +47 -0
  87. package/src/utils/mock-interceptor.js +557 -0
  88. package/src/utils/oauth-utils.js +87 -0
  89. package/src/utils/request-utils.js +264 -0
  90. package/src/utils/response-utils.js +203 -0
  91. package/src/utils/sanitize.js +57 -0
  92. package/src/utils/schema-utils.js +1954 -0
  93. package/src/utils/slugger.js +187 -0
  94. package/src/utils/spec-parser.js +941 -0
  95. package/src/utils/url-utils.js +246 -0
  96. package/src/utils/xml-utils.js +61 -0
@@ -0,0 +1,498 @@
1
+ /**
2
+ * Renders the sidebar navigation panel with search filter, tag groupings, method badges, and link routing.
3
+ */
4
+ import { html, nothing } from "lit";
5
+ import Slugger from "github-slugger";
6
+ import { getMatchedPaths, isInternalOrHidden } from "~/utils/common-utils";
7
+
8
+ export function expandCollapseNavBarTag(navLinkEl, action = "toggle") {
9
+ const tagAndPathEl = navLinkEl?.closest(".nav-bar-tag-and-paths");
10
+ if (tagAndPathEl) {
11
+ const isExpanded = tagAndPathEl.classList.contains("expanded");
12
+ if (isExpanded && (action === "toggle" || action === "collapse")) {
13
+ tagAndPathEl.classList.replace("expanded", "collapsed");
14
+ tagAndPathEl.querySelector(".nav-bar-tag")?.setAttribute("aria-expanded", "false");
15
+ } else if (!isExpanded && (action === "toggle" || action === "expand")) {
16
+ tagAndPathEl.classList.replace("collapsed", "expanded");
17
+ tagAndPathEl.querySelector(".nav-bar-tag")?.setAttribute("aria-expanded", "true");
18
+ }
19
+ }
20
+ }
21
+
22
+ export function expandCollapseNavBarTagGroup(navLinkEl, action = "toggle") {
23
+ const tagGroupEl = navLinkEl?.closest(".nav-bar-tag-group");
24
+ if (tagGroupEl) {
25
+ const isExpanded = tagGroupEl.classList.contains("expanded");
26
+ if (isExpanded && (action === "toggle" || action === "collapse")) {
27
+ tagGroupEl.classList.replace("expanded", "collapsed");
28
+ tagGroupEl.querySelector(".nav-bar-tag-group-header")?.setAttribute("aria-expanded", "false");
29
+ } else if (!isExpanded && (action === "toggle" || action === "expand")) {
30
+ tagGroupEl.classList.replace("collapsed", "expanded");
31
+ tagGroupEl.querySelector(".nav-bar-tag-group-header")?.setAttribute("aria-expanded", "true");
32
+ }
33
+ }
34
+ }
35
+
36
+ export function expandParentNavContainers(navLinkEl) {
37
+ if (!navLinkEl) return;
38
+ expandCollapseNavBarTagGroup(navLinkEl, "expand");
39
+ expandCollapseNavBarTag(navLinkEl, "expand");
40
+ }
41
+
42
+ export { isInternalOrHidden };
43
+
44
+ export function isNavPathVisible(path, searchVal, tagName) {
45
+ if (isInternalOrHidden(path)) {
46
+ return false;
47
+ }
48
+ if (searchVal) {
49
+ return getMatchedPaths(searchVal, path, tagName);
50
+ }
51
+ return true;
52
+ }
53
+
54
+ export function isNavTagVisible(tag, searchVal) {
55
+ if (isInternalOrHidden(tag)) {
56
+ return false;
57
+ }
58
+ // A description-only tag (show-unused-tags) has no operations to match, so the filter hides it
59
+ if (tag.descriptionOnly) {
60
+ return !searchVal;
61
+ }
62
+ return (tag.paths || []).some((path) => isNavPathVisible(path, searchVal, tag.name));
63
+ }
64
+
65
+ export function isNavTagGroupVisible(group, searchVal) {
66
+ if (isInternalOrHidden(group)) {
67
+ return false;
68
+ }
69
+ return (group.tags || []).some((tag) => isNavTagVisible(tag, searchVal));
70
+ }
71
+
72
+ export function expandCollapseAll(event, action = "expand-all") {
73
+ if (!(event.type === "click" || (event.type === "keyup" && event.keyCode === 13))) {
74
+ return;
75
+ }
76
+ const navEl = event.target.closest(".nav-scroll");
77
+ const groupList = [...navEl.querySelectorAll(".nav-bar-tag-group")];
78
+ if (action === "expand-all") {
79
+ groupList.forEach((el) => {
80
+ el.classList.replace("collapsed", "expanded");
81
+ el.querySelector(".nav-bar-tag-group-header")?.setAttribute("aria-expanded", "true");
82
+ });
83
+ } else {
84
+ groupList.forEach((el) => {
85
+ el.classList.replace("expanded", "collapsed");
86
+ el.querySelector(".nav-bar-tag-group-header")?.setAttribute("aria-expanded", "false");
87
+ });
88
+ }
89
+ const elList = [...navEl.querySelectorAll(".nav-bar-tag-and-paths")];
90
+ if (action === "expand-all") {
91
+ elList.forEach((el) => {
92
+ el.classList.replace("collapsed", "expanded");
93
+ });
94
+ } else {
95
+ elList.forEach((el) => {
96
+ el.classList.replace("expanded", "collapsed");
97
+ });
98
+ }
99
+ }
100
+
101
+ export function navBarClickAndEnterHandler(event) {
102
+ if (!(event.type === "click" || (event.type === "keyup" && event.keyCode === 13))) {
103
+ return;
104
+ }
105
+ const navEl = event.target.closest("[data-action]") || event.target;
106
+ // Ignore clicks or enter inside the search / filter controls or logo slot
107
+ if (
108
+ navEl.closest("#nav-bar-search") ||
109
+ navEl.closest("#advanced-search-btn") ||
110
+ navEl.closest('[part~="btn-clear-filter"]') ||
111
+ navEl.closest('slot[name="nav-logo"]')
112
+ ) {
113
+ return;
114
+ }
115
+ event.stopPropagation();
116
+ if (navEl.dataset?.action === "navigate") {
117
+ this.scrollToEventTarget(event, false);
118
+ const navBarEl = event.currentTarget.closest("#nav-bar");
119
+ // hide the navigation bar incase of floating navigation
120
+ if (navBarEl.classList.contains("floating-nav")) {
121
+ navBarEl.classList.remove("floating-nav");
122
+ }
123
+ } else if (navEl.dataset?.action === "expand-all" || navEl.dataset?.action === "collapse-all") {
124
+ expandCollapseAll(event, navEl.dataset.action);
125
+ } else if (navEl.dataset?.action === "expand-collapse-tag-group") {
126
+ expandCollapseNavBarTagGroup(navEl, "toggle");
127
+ } else if (navEl.dataset?.action === "expand-collapse-tag") {
128
+ expandCollapseNavBarTag(navEl, "toggle");
129
+ }
130
+ }
131
+
132
+ export default function navbarTemplate() {
133
+ const slugger = new Slugger();
134
+ let isFirstNavItem = true;
135
+ function checkFirstNav() {
136
+ if (isFirstNavItem) {
137
+ isFirstNavItem = false;
138
+ return true;
139
+ }
140
+ return false;
141
+ }
142
+ if (!this.resolvedSpec || this.resolvedSpec.specLoadError) {
143
+ return html`<nav class="nav-bar" part="section-navbar">
144
+ <div class="nav-bar-header" part="section-navbar-header">
145
+ <slot name="nav-logo" class="logo" part="section-navbar-logo"></slot>
146
+ </div>
147
+ </nav>`;
148
+ }
149
+ return html`
150
+ <button id="nav-bar-btn" part="btn-navbar" class="btn" @click="${this.onOpenNavBarToggle}">☰</button>
151
+ <nav id="nav-bar" class="nav-bar ${this.renderStyle} overflow-${this.navItemOverflow || "ellipsis"}" part="section-navbar">
152
+ <div
153
+ class="nav-scroll"
154
+ tabindex="-1"
155
+ part="section-navbar-scroll"
156
+ @click="${(e) => navBarClickAndEnterHandler.call(this, e)}"
157
+ @keyup="${(e) => navBarClickAndEnterHandler.call(this, e)}"
158
+ >
159
+ <div class="nav-bar-header" part="section-navbar-header">
160
+ <slot name="nav-logo" class="logo" part="section-navbar-logo"></slot>
161
+ ${
162
+ this.allowSearch === "false" && this.allowAdvancedSearch === "false"
163
+ ? ""
164
+ : html`
165
+ <div
166
+ class="nav-bar-search-container ${this.allowAdvancedSearch === "false" ? "has-bottom-border" : ""}"
167
+ part="section-navbar-search"
168
+ >
169
+ ${
170
+ this.allowSearch === "false"
171
+ ? ""
172
+ : html`
173
+ <div class="nav-bar-search-input-wrapper">
174
+ <input
175
+ id="nav-bar-search"
176
+ part="textbox textbox-nav-filter"
177
+ class="nav-bar-search-input"
178
+ type="text"
179
+ placeholder="Filter"
180
+ @change="${this.onSearchChange}"
181
+ spellcheck="false"
182
+ />
183
+ <div class="nav-bar-search-icon" @click="${this.onSearchChange}">&#x21a9;</div>
184
+ </div>
185
+ ${
186
+ this.searchVal
187
+ ? html` <button
188
+ @click="${this.onClearSearch}"
189
+ class="btn btn-outline btn-clear-filter"
190
+ part="btn btn-outline btn-clear-filter"
191
+ >
192
+ CLEAR
193
+ </button>`
194
+ : ""
195
+ }
196
+ `
197
+ }
198
+ ${
199
+ this.allowAdvancedSearch === "false" || this.searchVal
200
+ ? ""
201
+ : html`
202
+ <button
203
+ id="advanced-search-btn"
204
+ class="btn btn-primary"
205
+ part="btn btn-fill btn-search"
206
+ @click="${this.onShowAdvancedSearchClicked}"
207
+ >
208
+ SEARCH
209
+ </button>
210
+ `
211
+ }
212
+ </div>
213
+ `
214
+ }
215
+ </div>
216
+ ${
217
+ this.showInfo === "false" || !this.resolvedSpec.info
218
+ ? ""
219
+ : html`
220
+ ${
221
+ this.infoDescriptionHeadingsInNavBar === "true"
222
+ ? html`
223
+ ${
224
+ this.resolvedSpec.infoDescriptionHeaders.length > 0
225
+ ? (() => {
226
+ const isFirst = checkFirstNav();
227
+ return html`<div
228
+ class="nav-bar-info${isFirst ? " first-nav-item" : ""}"
229
+ id="link-overview"
230
+ data-content-id="overview"
231
+ data-action="navigate"
232
+ data-first-nav-item="${isFirst ? "true" : nothing}"
233
+ tabindex="0"
234
+ part="section-navbar-item section-navbar-overview"
235
+ >
236
+ ${this.resolvedSpec.info?.title?.trim() || "Overview"}
237
+ </div>`;
238
+ })()
239
+ : ""
240
+ }
241
+ <div class="overview-headers">
242
+ ${this.resolvedSpec.infoDescriptionHeaders.map((header) => {
243
+ const headerElId = slugger.slug(header.text);
244
+ return html`<div
245
+ class="nav-bar-h${header.depth}"
246
+ id="link-overview--${headerElId}"
247
+ data-action="navigate"
248
+ data-content-id="overview--${headerElId}"
249
+ >
250
+ ${header.text}
251
+ </div>`;
252
+ })}
253
+ </div>
254
+ ${
255
+ this.resolvedSpec.infoDescriptionHeaders.length > 0
256
+ ? html`<hr style="border-top: 1px solid var(--muted); border-width:1px 0 0 0; margin: 15px 0 0 0" />`
257
+ : ""
258
+ }
259
+ `
260
+ : (() => {
261
+ const isFirst = checkFirstNav();
262
+ return html`<div
263
+ class="nav-bar-info${isFirst ? " first-nav-item" : ""}"
264
+ id="link-overview"
265
+ data-action="navigate"
266
+ data-content-id="overview"
267
+ data-first-nav-item="${isFirst ? "true" : nothing}"
268
+ tabindex="0"
269
+ >
270
+ ${this.resolvedSpec.info?.title?.trim() || "Overview"}
271
+ </div>`;
272
+ })()
273
+ }
274
+ `
275
+ }
276
+ ${
277
+ this.allowServerSelection === "false"
278
+ ? ""
279
+ : (() => {
280
+ const isFirst = checkFirstNav();
281
+ return html`<div
282
+ class="nav-bar-info${isFirst ? " first-nav-item" : ""}"
283
+ id="link-servers"
284
+ data-action="navigate"
285
+ data-content-id="servers"
286
+ data-first-nav-item="${isFirst ? "true" : nothing}"
287
+ tabindex="0"
288
+ part="section-navbar-item section-navbar-servers"
289
+ >
290
+ API Servers
291
+ </div>`;
292
+ })()
293
+ }
294
+ ${
295
+ this.allowAuthentication === "false" || !this.resolvedSpec.securitySchemes
296
+ ? ""
297
+ : (() => {
298
+ const isFirst = checkFirstNav();
299
+ return html`<div
300
+ class="nav-bar-info${isFirst ? " first-nav-item" : ""}"
301
+ id="link-auth"
302
+ data-action="navigate"
303
+ data-content-id="auth"
304
+ data-first-nav-item="${isFirst ? "true" : nothing}"
305
+ tabindex="0"
306
+ part="section-navbar-item section-navbar-auth"
307
+ >
308
+ Authentication
309
+ </div>`;
310
+ })()
311
+ }
312
+
313
+ <div
314
+ id="link-operations-top"
315
+ class="nav-bar-section operations"
316
+ data-action="navigate"
317
+ data-content-id="${this.renderStyle === "focused" ? "" : "operations-top"}"
318
+ part="section-navbar-item section-navbar-operations-top"
319
+ >
320
+ <div style="font-size:16px; display:flex; margin-left:10px;">
321
+ ${
322
+ this.renderStyle === "focused"
323
+ ? html`<div class="nav-bar-expand-all" data-action="expand-all" tabindex="0" title="Expand all">▸</div>
324
+ <div class="nav-bar-collapse-all" data-action="collapse-all" tabindex="0" title="Collapse all">▸</div>`
325
+ : ""
326
+ }
327
+ </div>
328
+ <div class="nav-bar-section-title">OPERATIONS</div>
329
+ </div>
330
+
331
+ <!-- TAGS AND PATHS (3-tier if tagGroups exist, else 2-tier) -->
332
+ ${(() => {
333
+ const renderNavTagItem = (tag) => {
334
+ // A description-only tag is a link to its section: no operations to expand or collapse
335
+ if (tag.descriptionOnly) {
336
+ if (!isNavTagVisible(tag, this.searchVal)) return "";
337
+ return html` <div class="nav-bar-tag-and-paths description-only">
338
+ <div
339
+ class="nav-bar-tag"
340
+ part="section-navbar-item section-navbar-tag"
341
+ id="link-${tag.elementId}"
342
+ data-action="navigate"
343
+ data-content-id="${tag.elementId}"
344
+ tabindex="0"
345
+ >
346
+ <div class="nav-bar-tag-title">${tag.displayName || tag.name}</div>
347
+ </div>
348
+ </div>`;
349
+ }
350
+ const visiblePaths = (tag.paths || []).filter((p) =>
351
+ isNavPathVisible(p, this.searchVal, tag.name),
352
+ );
353
+ if (visiblePaths.length === 0) return "";
354
+ const firstPathId = visiblePaths[0].elementId;
355
+
356
+ return html` <div class="nav-bar-tag-and-paths ${tag.expanded ? "expanded" : "collapsed"}">
357
+ <div
358
+ class="nav-bar-tag"
359
+ part="section-navbar-item section-navbar-tag"
360
+ id="link-${tag.elementId}"
361
+ data-action="expand-collapse-tag"
362
+ data-first-path-id="${firstPathId}"
363
+ tabindex="0"
364
+ role="button"
365
+ aria-expanded="${tag.expanded ? "true" : "false"}"
366
+ >
367
+ <div class="nav-bar-tag-title">${tag.displayName || tag.name}</div>
368
+ <div class="nav-bar-tag-icon" tabindex="0" data-action="expand-collapse-tag"></div>
369
+ </div>
370
+ ${
371
+ this.infoDescriptionHeadingsInNavBar === "true"
372
+ ? html` <div class="tag-headers">
373
+ ${(() => {
374
+ const tagSlugger = new Slugger();
375
+ return tag.headers.map((header) => {
376
+ const headerElId = tagSlugger.slug(header.text);
377
+ return html` <div
378
+ class="nav-bar-h${header.depth}"
379
+ part="section-navbar-item section-navbar-h${header.depth}"
380
+ id="link-${tag.elementId}--${headerElId}"
381
+ data-action="navigate"
382
+ data-content-id="${tag.elementId}--${headerElId}"
383
+ tabindex="0"
384
+ >
385
+ ${header.text}
386
+ </div>`;
387
+ });
388
+ })()}
389
+ </div>`
390
+ : ""
391
+ }
392
+ <div class="nav-bar-paths-under-tag">
393
+ <!-- Paths in each tag (endpoints) -->
394
+ ${visiblePaths.map((p) => {
395
+ const isFirst = checkFirstNav();
396
+ return html` <div
397
+ class="nav-bar-path${isFirst ? " first-nav-item" : ""}"
398
+ style="${p.deprecated ? "filter:opacity(0.5);" : ""}"
399
+ part="section-navbar-item section-navbar-path"
400
+ data-action="navigate"
401
+ data-content-id="${p.elementId}"
402
+ data-first-nav-item="${isFirst ? "true" : nothing}"
403
+ id="link-${p.elementId}"
404
+ tabindex="0"
405
+ >
406
+ <span class="nav-bar-path-label">
407
+ ${p.isWebhook ? html`<span class="nav-bar-webhook">WEBHOOK</span>` : ""}
408
+ ${this.usePathInNavBar === "true" ? html`<span class="mono-font">${p.path}</span>` : p.summary || p.shortSummary}
409
+ </span>
410
+ ${html`<span class="nav-method ${this.showMethodInNavBar} ${p.method}">
411
+ ${this.showMethodInNavBar === "as-colored-block" ? p.method.substring(0, 3).toUpperCase() : p.method.toUpperCase()}
412
+ </span>`}
413
+ </div>`;
414
+ })}
415
+ </div>
416
+ </div>`;
417
+ };
418
+
419
+ if (this.resolvedSpec.tagGroups && this.resolvedSpec.tagGroups.length > 0) {
420
+ const assignedTagNames = new Set();
421
+ this.resolvedSpec.tagGroups.forEach((group) => {
422
+ (group.tags || []).forEach((tag) => {
423
+ assignedTagNames.add(tag.name.toLowerCase());
424
+ });
425
+ });
426
+
427
+ const renderedGroups = this.resolvedSpec.tagGroups
428
+ .filter((group) => isNavTagGroupVisible(group, this.searchVal))
429
+ .map((group) => {
430
+ const groupTags = group.tags.filter((tag) => isNavTagVisible(tag, this.searchVal));
431
+ if (groupTags.length === 0) return "";
432
+ return html`
433
+ <div class="nav-bar-tag-group ${group.expanded ? "expanded" : "collapsed"}" id="link-${group.elementId}">
434
+ <div
435
+ class="nav-bar-tag-group-header"
436
+ part="section-navbar-item section-navbar-tag-group"
437
+ data-action="expand-collapse-tag-group"
438
+ tabindex="0"
439
+ role="button"
440
+ aria-expanded="${group.expanded ? "true" : "false"}"
441
+ >
442
+ <div class="nav-bar-tag-group-title">${group.displayName || group.name}</div>
443
+ <div class="nav-bar-tag-group-icon" tabindex="0" data-action="expand-collapse-tag-group"></div>
444
+ </div>
445
+ <div class="nav-bar-tags-under-group">${groupTags.map((tag) => renderNavTagItem(tag))}</div>
446
+ </div>
447
+ `;
448
+ });
449
+
450
+ const remainingTags = (this.resolvedSpec.tags || [])
451
+ .filter(
452
+ (tag) =>
453
+ !assignedTagNames.has(tag.name.toLowerCase()) &&
454
+ isNavTagVisible(tag, this.searchVal),
455
+ )
456
+ .map((tag) => renderNavTagItem(tag));
457
+
458
+ return html`${renderedGroups}${remainingTags}`;
459
+ }
460
+
461
+ return (this.resolvedSpec.tags || [])
462
+ .filter((tag) => isNavTagVisible(tag, this.searchVal))
463
+ .map((tag) => renderNavTagItem(tag));
464
+ })()}
465
+
466
+ <!-- COMPONENTS -->
467
+ ${
468
+ this.resolvedSpec.components && this.showComponents === "true"
469
+ ? html` <div id="link-components" class="nav-bar-section components">
470
+ <div class="nav-bar-section-title">COMPONENTS</div>
471
+ </div>
472
+ ${this.resolvedSpec.components.map((component) =>
473
+ component.subComponents.length
474
+ ? html` <div
475
+ class="nav-bar-tag"
476
+ part="section-navbar-item section-navbar-tag"
477
+ data-action="navigate"
478
+ data-content-id="cmp--${component.name.toLowerCase()}"
479
+ id="link-cmp--${component.name.toLowerCase()}"
480
+ >
481
+ ${component.name}
482
+ </div>
483
+ ${component.subComponents
484
+ .filter((p) => p.expanded !== false)
485
+ .map(
486
+ (p) =>
487
+ html` <div class="nav-bar-path" data-action="navigate" data-content-id="cmp--${p.id}" id="link-cmp--${p.id}">
488
+ <span style="pointer-events: none;"> ${p.name} </span>
489
+ </div>`,
490
+ )}`
491
+ : "",
492
+ )}`
493
+ : ""
494
+ }
495
+ </div>
496
+ </nav>
497
+ `;
498
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Renders the API specification overview header with metadata, description markdown, contact, license, and download links.
3
+ */
4
+ import { fixRenderedAnchorLinks } from "~/utils/markdown-utils";
5
+ import { html } from "lit";
6
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
7
+ import { sanitizeHTML } from "../utils/sanitize.js";
8
+ import Slugger from "github-slugger";
9
+ import { marked } from "marked";
10
+
11
+ function headingRenderer() {
12
+ const slugger = new Slugger();
13
+ const renderer = new marked.Renderer();
14
+ // renderer.heading = (text, level, raw, slugger) => `<h${level} class="observe-me" id="overview--${slugger.slug(raw)}">${text}</h${level}>`;
15
+ renderer.heading = ({ text, depth }) =>
16
+ `<h${depth} class="observe-me" id="overview--${slugger.slug(text)}">${text}</h${depth}>`;
17
+ fixRenderedAnchorLinks(renderer);
18
+ return renderer;
19
+ }
20
+
21
+ export default function overviewTemplate() {
22
+ return html`
23
+ <section
24
+ id="overview"
25
+ part="section-overview"
26
+ class="observe-me ${this.renderStyle === "view" ? "section-gap" : "section-gap--read-mode"}"
27
+ >
28
+ ${
29
+ this.resolvedSpec?.info
30
+ ? html`
31
+ <h1 id="api-title" class="rapidoc-heading" part="section-overview-title heading heading-1">
32
+ ${this.resolvedSpec.info.title}
33
+ ${
34
+ !this.resolvedSpec.info.version
35
+ ? ""
36
+ : html`<span class="version" part="label-overview-version">${this.resolvedSpec.info.version}</span>`
37
+ }
38
+ </h1>
39
+ <div id="api-info">
40
+ ${
41
+ this.resolvedSpec.info.contact?.email
42
+ ? html`<span
43
+ >${this.resolvedSpec.info.contact.name || "Email"}:
44
+ <a href="mailto:${this.resolvedSpec.info.contact.email}" part="anchor anchor-overview"
45
+ >${this.resolvedSpec.info.contact.email}</a
46
+ >
47
+ </span>`
48
+ : ""
49
+ }
50
+ ${
51
+ this.resolvedSpec.info.contact?.url
52
+ ? html`<span
53
+ >URL:
54
+ <a href="${this.resolvedSpec.info.contact.url}" part="anchor anchor-overview"
55
+ >${this.resolvedSpec.info.contact.url}</a
56
+ ></span
57
+ >`
58
+ : ""
59
+ }
60
+ ${
61
+ this.resolvedSpec.info.license
62
+ ? html`<span
63
+ >License:
64
+ ${
65
+ this.resolvedSpec.info.license.url
66
+ ? html`<a href="${this.resolvedSpec.info.license.url}" part="anchor anchor-overview"
67
+ >${this.resolvedSpec.info.license.name}</a
68
+ >`
69
+ : this.resolvedSpec.info.license.name
70
+ }
71
+ </span>`
72
+ : ""
73
+ }
74
+ ${
75
+ this.resolvedSpec.info.termsOfService
76
+ ? html`<span
77
+ ><a href="${this.resolvedSpec.info.termsOfService}" part="anchor anchor-overview">Terms of Service</a></span
78
+ >`
79
+ : ""
80
+ }
81
+ </div>
82
+ <slot name="overview"></slot>
83
+ ${
84
+ this.resolvedSpec.info.description
85
+ ? html`<div id="api-description" class="m-markdown regular-font">
86
+ ${unsafeHTML(
87
+ sanitizeHTML(
88
+ marked(
89
+ this.resolvedSpec.info.description,
90
+ this.infoDescriptionHeadingsInNavBar === "true"
91
+ ? { renderer: headingRenderer() }
92
+ : undefined,
93
+ ),
94
+ ),
95
+ )}
96
+ </div>`
97
+ : ""
98
+ }
99
+ `
100
+ : ""
101
+ }
102
+ </section>
103
+ `;
104
+ }