@writedocs/generator 0.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 (95) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +17 -0
  3. package/astro.config.mjs +419 -0
  4. package/bin/writedocs.js +73 -0
  5. package/package.json +79 -0
  6. package/src/assets/wd_watermark.png +0 -0
  7. package/src/assets/wd_watermark_dark.png +0 -0
  8. package/src/cli/build-auth.js +53 -0
  9. package/src/cli/build.js +40 -0
  10. package/src/cli/dev.js +12 -0
  11. package/src/cli/generate-api-pages.js +359 -0
  12. package/src/cli/init.js +81 -0
  13. package/src/cli/preflight.js +40 -0
  14. package/src/cli/run-astro.js +57 -0
  15. package/src/cli/run-pagefind.js +66 -0
  16. package/src/cli/write-redirects-file.js +80 -0
  17. package/src/components/Accordion.astro +164 -0
  18. package/src/components/AccordionGroup.astro +40 -0
  19. package/src/components/ApiLangSelect.astro +168 -0
  20. package/src/components/ApiPlayground.astro +281 -0
  21. package/src/components/ApiReferencePanel.astro +1754 -0
  22. package/src/components/ApiSchemaField.astro +54 -0
  23. package/src/components/AppIcon.astro +32 -0
  24. package/src/components/Badge.astro +128 -0
  25. package/src/components/Callout.astro +168 -0
  26. package/src/components/Card.astro +136 -0
  27. package/src/components/CardGroup.astro +20 -0
  28. package/src/components/CodeGroup.astro +184 -0
  29. package/src/components/CopyPageMenu.astro +246 -0
  30. package/src/components/Danger.astro +12 -0
  31. package/src/components/Expandable.astro +126 -0
  32. package/src/components/Frame.astro +102 -0
  33. package/src/components/Hint.astro +99 -0
  34. package/src/components/Icon.astro +70 -0
  35. package/src/components/Image.astro +147 -0
  36. package/src/components/Info.astro +12 -0
  37. package/src/components/Note.astro +12 -0
  38. package/src/components/Parameter.astro +119 -0
  39. package/src/components/RequestExample.astro +33 -0
  40. package/src/components/ResponseExample.astro +19 -0
  41. package/src/components/Searchbar.astro +117 -0
  42. package/src/components/Step.astro +10 -0
  43. package/src/components/Steps.astro +32 -0
  44. package/src/components/Tab.astro +9 -0
  45. package/src/components/Tabs.astro +52 -0
  46. package/src/components/Tip.astro +12 -0
  47. package/src/components/Video.astro +135 -0
  48. package/src/components/Warning.astro +12 -0
  49. package/src/components/index.ts +48 -0
  50. package/src/content.config.ts +223 -0
  51. package/src/layout/BaseLayout.astro +750 -0
  52. package/src/layout/components/AnalyticsScripts.astro +77 -0
  53. package/src/layout/components/AskAiWidget.astro +37 -0
  54. package/src/layout/components/Breadcrumbs.astro +97 -0
  55. package/src/layout/components/ImageZoom.astro +19 -0
  56. package/src/layout/components/MobileMenu.astro +200 -0
  57. package/src/layout/components/NavTree.astro +351 -0
  58. package/src/layout/components/SearchModal.astro +42 -0
  59. package/src/layout/components/Sidebar.astro +122 -0
  60. package/src/layout/components/SiteFooter.astro +85 -0
  61. package/src/layout/components/TableOfContents.astro +117 -0
  62. package/src/layout/components/TopBar.astro +311 -0
  63. package/src/layout/styles/banner.css +44 -0
  64. package/src/layout/styles/base.css +234 -0
  65. package/src/layout/styles/dropdown.css +133 -0
  66. package/src/layout/styles/footer.css +108 -0
  67. package/src/layout/styles/image-zoom.css +50 -0
  68. package/src/layout/styles/mobile-menu.css +258 -0
  69. package/src/layout/styles/search-modal.css +122 -0
  70. package/src/layout/styles/topbar.css +437 -0
  71. package/src/lib/config.ts +2131 -0
  72. package/src/lib/mdx-auto-hydrate.js +70 -0
  73. package/src/lib/mdx-inject-builtins.js +87 -0
  74. package/src/lib/mdx-substitute-variables.js +66 -0
  75. package/src/lib/mdx-title-anchor-ids.js +84 -0
  76. package/src/lib/mermaid-rehype.js +72 -0
  77. package/src/lib/openapi-render.ts +479 -0
  78. package/src/lib/shiki-code-block.js +102 -0
  79. package/src/lib/shiki-copy-button.js +45 -0
  80. package/src/lib/styles-asset-integration.js +210 -0
  81. package/src/lib/writedocs-temp-dir.js +93 -0
  82. package/src/pages/404.astro +62 -0
  83. package/src/pages/[...slug].astro +1270 -0
  84. package/src/pages/[...slug].md.ts +78 -0
  85. package/src/pages/llms-full.txt.ts +71 -0
  86. package/src/pages/llms.txt.ts +141 -0
  87. package/src/scripts/banner.ts +20 -0
  88. package/src/scripts/dropdowns.ts +61 -0
  89. package/src/scripts/image-zoom.ts +66 -0
  90. package/src/scripts/mobile-menu.ts +55 -0
  91. package/src/scripts/search.ts +155 -0
  92. package/src/scripts/sidebar-scroll.ts +65 -0
  93. package/src/scripts/theme-toggle.ts +35 -0
  94. package/src/scripts/topbar-offset.ts +141 -0
  95. package/src/styles/global.css +18 -0
@@ -0,0 +1,99 @@
1
+ ---
2
+ // Inline, text-level component - unlike every other built-in here
3
+ // (Callout, Card, Accordion, ...), which are all block-level and get
4
+ // their own line, a Hint sits mid-sentence: `word <Hint tip="...">this
5
+ // bit</Hint> continues`. That's why this renders a <span>, not a <div>,
6
+ // and why its own trigger area is exactly its slotted text - no icon,
7
+ // no padding box drawing attention to itself the way a Callout does.
8
+ //
9
+ // tip is a plain string prop (not a slot) deliberately - the tooltip
10
+ // bubble itself needs to be one line of plain text CSS can center/
11
+ // position predictably; a second <slot> would let an author put
12
+ // arbitrary markup (another Hint, a link, a whole paragraph) in there,
13
+ // which the hover-bubble layout below was never built to hold.
14
+ interface Props {
15
+ tip: string;
16
+ }
17
+ const { tip } = Astro.props as Props;
18
+ ---
19
+
20
+ <span class="wd-hint" tabindex="0">
21
+ <span class="wd-hint-trigger"><slot /></span>
22
+ <span class="wd-hint-tooltip" role="tooltip">{tip}</span>
23
+ </span>
24
+ <style>
25
+ .wd-hint {
26
+ position: relative;
27
+ /* display: inline, not inline-block - this needs to be able to wrap
28
+ across a line break exactly like the plain text around it would
29
+ (it's often a whole sentence, not one short word), which
30
+ inline-block would prevent by forcing the whole span to stay on
31
+ one line or break as a single rigid box. */
32
+ display: inline;
33
+ /* tabindex above + :focus-visible below make this reachable and
34
+ revealable by keyboard, not just a mouse hover - the underline
35
+ and cursor: help both double as the visual cue that there's a
36
+ hint here at all, since nothing about plain underlined text
37
+ otherwise signals "hover me" the way an icon or button would. */
38
+ cursor: help;
39
+ border-bottom: 1px solid var(--wd-text);
40
+ }
41
+ .wd-hint-tooltip {
42
+ position: absolute;
43
+ bottom: calc(100% + 0.55rem);
44
+ left: 50%;
45
+ transform: translateX(-50%) translateY(4px);
46
+ /* Fixed dark-on-light regardless of [data-theme] - deliberately not
47
+ var(--wd-text)/var(--wd-background) (which flip a Hint's own
48
+ tooltip to light-on-dark in dark mode) since the bubble needs to
49
+ read as "a label floating above the page", the same fixed
50
+ look in both themes, not as page content that itself follows the
51
+ theme - the same reasoning Card.astro's method badges already
52
+ settled on for their own always-colored, never-theme-flipping
53
+ backgrounds. */
54
+ background: #18181b;
55
+ color: #fff;
56
+ padding: 0.45rem 0.75rem;
57
+ border-radius: 0.4rem;
58
+ font-size: 0.75rem;
59
+ font-weight: 700;
60
+ line-height: 1.3;
61
+ /* No white-space: nowrap - a long tip (a UUID example, a full
62
+ sentence) needs to actually wrap onto a second line within
63
+ max-width; nowrap combined with max-width caps the *box* but
64
+ leaves overflow: visible's default behavior letting the text
65
+ itself spill out past the painted background/border-radius
66
+ instead of wrapping inside it - exactly the "text sticking out
67
+ past the dark bubble" bug a real screenshot caught. Wrapping
68
+ normally keeps the background sized to whatever it's actually
69
+ covering, at the cost of a short tip's box no longer perfectly
70
+ hugging one line's width (an intentional trade - a tip that's
71
+ readable matters more than one that's minimally-sized). */
72
+ max-width: 16rem;
73
+ width: max-content;
74
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
75
+ opacity: 0;
76
+ visibility: hidden;
77
+ pointer-events: none;
78
+ transition:
79
+ opacity 0.15s ease,
80
+ transform 0.15s ease,
81
+ visibility 0.15s;
82
+ z-index: 30;
83
+ }
84
+ .wd-hint-tooltip::after {
85
+ content: "";
86
+ position: absolute;
87
+ top: 100%;
88
+ left: 50%;
89
+ transform: translateX(-50%);
90
+ border: 5px solid transparent;
91
+ border-top-color: #18181b;
92
+ }
93
+ .wd-hint:hover .wd-hint-tooltip,
94
+ .wd-hint:focus-visible .wd-hint-tooltip {
95
+ opacity: 1;
96
+ visibility: visible;
97
+ transform: translateX(-50%) translateY(0);
98
+ }
99
+ </style>
@@ -0,0 +1,70 @@
1
+ ---
2
+ // Renders either a real icon (via `icon`) or a custom image (via
3
+ // `src`) inline with surrounding text - modeled on Mintlify's own Icon
4
+ // (https://www.mintlify.com/docs/components/icons), which documents
5
+ // exactly this "one of `icon` or `src`" split. `icon` reuses
6
+ // AppIcon.astro - the same Lucide/Iconify/literal-text resolution
7
+ // every other icon prop on this site already goes through (Card,
8
+ // Badge, writedocs.json's own tab/dropdown/product icons) - so this
9
+ // component's `icon` prop behaves identically to theirs, just laid out
10
+ // for inline text flow instead of block/flex placement.
11
+ //
12
+ // The `src` branch is a second, independent code path (a plain <img>,
13
+ // not AppIcon) since it isn't resolving an icon set at all - it's
14
+ // dropping in an arbitrary image (a project-local file or an external
15
+ // URL) and just needs to sit inline at a controlled height, the exact
16
+ // behavior of the InlineImage React component this was modeled on
17
+ // (display: inline, a `height` prop controlling size, no margin).
18
+ import AppIcon from './AppIcon.astro';
19
+
20
+ interface Props {
21
+ icon?: string;
22
+ src?: string;
23
+ alt?: string;
24
+ // Only meaningful for the `icon` branch - a pixel size (Mintlify's
25
+ // own `size` prop is a number, not a CSS length) and a CSS color,
26
+ // applied as an inline style since these are arbitrary per-instance
27
+ // values, not a fixed set of classes.
28
+ size?: number;
29
+ color?: string;
30
+ // Only meaningful for the `src` branch - a CSS length string (not a
31
+ // bare number, unlike `size` above), matching the InlineImage
32
+ // reference component's own `height` prop and its "1.6em" default.
33
+ height?: string;
34
+ }
35
+ const { icon, src, alt = '', size, color, height = '1.6em' } = Astro.props as Props;
36
+
37
+ const iconStyle =
38
+ [size ? `width:${size}px` : null, size ? `height:${size}px` : null, color ? `color:${color}` : null]
39
+ .filter(Boolean)
40
+ .join(';') || undefined;
41
+ ---
42
+
43
+ {
44
+ src ? (
45
+ <img src={src} alt={alt} class="wd-icon-image" style={`height:${height}`} />
46
+ ) : icon ? (
47
+ <AppIcon icon={icon} class="wd-icon-inline" style={iconStyle} />
48
+ ) : null
49
+ }
50
+ <style>
51
+ .wd-icon-image {
52
+ display: inline;
53
+ vertical-align: middle;
54
+ height: 1.6em;
55
+ margin: 0;
56
+ }
57
+ /* :global() is load-bearing, same reason as every other AppIcon
58
+ consumer's identical comment (Card.astro, Badge.astro): AppIcon
59
+ renders this span/svg, not Icon.astro, so it never carries this
60
+ component's own scope attribute. 1em default (overridden inline
61
+ via the `size` prop's style attribute when set) keeps an
62
+ unsized icon proportional to its surrounding text, the same way a
63
+ real glyph would be. */
64
+ :global(.wd-icon-inline) {
65
+ display: inline;
66
+ vertical-align: middle;
67
+ width: 1em;
68
+ height: 1em;
69
+ }
70
+ </style>
@@ -0,0 +1,147 @@
1
+ ---
2
+ // Block-level (own line, centered) - unlike Hint (inline/text-level),
3
+ // this is meant to be dropped in on its own the way Callout/Card are.
4
+ //
5
+ // src/srcDark render as two separate <img> tags, both always in the
6
+ // markup, CSS shows only the one matching the active [data-theme] - the
7
+ // exact same dual light/dark-asset pattern base.css's own .wd-logo-light/
8
+ // .wd-logo-dark rules already establish for TopBar/MobileMenu/SiteFooter's
9
+ // logo (see that comment there) - base.css's own comment on those rules
10
+ // spells out exactly why they get to write [data-theme='dark'] .wd-logo-x
11
+ // completely unscoped: base.css is a *plain imported* .css file, never run
12
+ // through Astro's scoped-CSS compiler at all, unlike this component's own
13
+ // <style> block below. [data-theme] lives on <html>, set by BaseLayout's
14
+ // anti-FOUC script - nowhere near this component's own template - so
15
+ // inside a *scoped* <style> (this one) that ancestor selector has to be
16
+ // wrapped in :global() or Astro's compiler appends this component's own
17
+ // scope attribute onto it too, requiring <html> to carry that attribute,
18
+ // which it never will. .wd-image-light/.wd-image-dark themselves don't
19
+ // need :global() - unlike AppIcon-rendered markup (Card/Accordion's own
20
+ // icon rules), both <img> tags here are rendered directly by *this*
21
+ // component's own template, so they already carry its scope attribute
22
+ // normally.
23
+ interface Props {
24
+ src: string;
25
+ srcDark?: string;
26
+ // Width at full (unconstrained) viewport width - a raw CSS length or
27
+ // percentage string ("80%", "480px", "40rem", ...), passed straight
28
+ // through as a custom property with no parsing/validation, the same
29
+ // "trust the site author, this is their writedocs.json/content" latitude
30
+ // every other pass-through string prop here already gets (Card's
31
+ // icon, Callout's title, ...). Applied to the *figure* (see below),
32
+ // not the <img> tags directly - an earlier version set it on the img
33
+ // instead, which left the figure itself (and, when caption is set,
34
+ // its whole bordered card) always full-width regardless of `size`,
35
+ // so a size="70%" image ended up sitting inside a card twice as wide
36
+ // as it needed to be, with a large empty gap on both sides - caught
37
+ // via a real screenshot showing exactly that gap. max-width: 100%
38
+ // below is what actually makes this shrink on a narrower viewport
39
+ // instead of overflowing it, regardless of which form `size` takes -
40
+ // a percentage already scales with its container on its own, but a
41
+ // fixed px/rem value doesn't, and needs that separate cap to behave
42
+ // the same way.
43
+ size?: string;
44
+ alt?: string;
45
+ // Optional caption shown below the image. Set it and the whole thing
46
+ // gains the same bordered/rounded "card" background Frame's own
47
+ // caption case uses (border + background + padding, image inset
48
+ // inside it) - deliberately conditional on caption being set rather
49
+ // than always-on: without a caption this needs to render exactly as
50
+ // it always has (a plain image, no chrome), so an existing
51
+ // <Image src="..." /> with no caption keeps its current look with
52
+ // zero visual change - only opting a page into the card look actually
53
+ // opts it in.
54
+ caption?: string;
55
+ // Opts this image out of the site-wide click-to-zoom lightbox (see
56
+ // src/scripts/image-zoom.ts) - rendered as a bare `nozoom` attribute
57
+ // on both <img> tags, the same attribute a raw
58
+ // `<img nozoom src="..." />` written directly in MDX would carry, so
59
+ // one selector in image-zoom.ts handles both cases identically rather
60
+ // than needing to special-case this component.
61
+ noZoom?: boolean;
62
+ }
63
+ const { src, srcDark, size, alt = "", caption, noZoom } = Astro.props as Props;
64
+ const sizeStyle = size ? `--wd-image-size:${size}` : undefined;
65
+ ---
66
+
67
+ <figure
68
+ class:list={["wd-image-figure", caption && "wd-image-figure-framed", srcDark && "wd-image-has-dark"]}
69
+ style={sizeStyle}
70
+ >
71
+ <img src={src} alt={alt} class="wd-image wd-image-light" nozoom={noZoom || undefined} />
72
+ {srcDark && <img src={srcDark} alt={alt} class="wd-image wd-image-dark" nozoom={noZoom || undefined} />}
73
+ {caption && <figcaption class="wd-image-caption">{caption}</figcaption>}
74
+ </figure>
75
+ <style>
76
+ /* width: var(--wd-image-size, 100%) here (not on the img - see the
77
+ `size` prop's own comment above) is what makes the *whole figure*,
78
+ card background and all, actually match the image's own size
79
+ instead of always spanning the full content column. margin: ...
80
+ auto only has anything to center once this has a definite width
81
+ smaller than its container - at the 100% default it's a no-op,
82
+ same as before this prop existed. */
83
+ .wd-image-figure {
84
+ width: var(--wd-image-size, 100%);
85
+ max-width: 100%;
86
+ margin: 1.25rem auto;
87
+ }
88
+ /* Same card language as Frame's own bordered case (border + rounded +
89
+ surface background + padding) - deliberately duplicated here rather
90
+ than shared, the same way Card/Callout/Accordion each carry their
91
+ own near-identical CSS rather than a shared base class; Astro's
92
+ scoped <style> blocks are per-component anyway, so there's no
93
+ lighter-weight way to share this without introducing a global
94
+ stylesheet dependency neither component otherwise needs. Padding
95
+ is what creates the "image inset within the card" look - the img's
96
+ own width: 100% below resolves against this padded content box,
97
+ not the figure's own outer edge.
98
+ box-shadow is a deliberate belt-and-suspenders addition on top of
99
+ the border - var(--wd-border)/var(--wd-surface) are both very
100
+ light, low-contrast tokens by default (see BaseLayout.astro's own
101
+ --wd-border/--wd-surface light-mode values), so on a page whose own
102
+ background is similarly pale (or, worse, uses the literal same
103
+ image asset as its background - confirmed as the actual root cause
104
+ of a real earlier "the card is invisible" report), the border alone
105
+ can end up nearly imperceptible even though it's genuinely being
106
+ applied. A soft shadow gives the card a second, independent visual
107
+ cue that doesn't depend on border/surface contrast against
108
+ whatever the page happens to look like. */
109
+ .wd-image-figure-framed {
110
+ border: 1px solid var(--wd-border);
111
+ border-radius: 0.75rem;
112
+ background: var(--wd-surface);
113
+ padding: 0.5rem;
114
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
115
+ }
116
+ .wd-image {
117
+ display: block;
118
+ width: 100%;
119
+ height: auto;
120
+ border-radius: 0.75rem;
121
+ }
122
+ .wd-image-dark {
123
+ display: none;
124
+ }
125
+ /* .wd-image-light only hides in dark mode when a dark variant is
126
+ actually there to replace it - .wd-image-has-dark only gets added
127
+ to the figure when srcDark is set (see the frontmatter above); with
128
+ no srcDark, there's no second <img> in the markup at all, so
129
+ unconditionally hiding the light one (an earlier version of this
130
+ rule had no such scoping) left dark mode with literally nothing to
131
+ show - a real user report caught exactly that: light-only Image
132
+ usages went blank in dark mode instead of just keeping the one
133
+ image they had, same as base.css's own dual-logo comment already
134
+ notes for a site that only configures one logo. */
135
+ :global([data-theme="dark"]) .wd-image-figure.wd-image-has-dark .wd-image-light {
136
+ display: none;
137
+ }
138
+ :global([data-theme="dark"]) .wd-image-dark {
139
+ display: block;
140
+ }
141
+ .wd-image-caption {
142
+ margin-top: 0.6rem;
143
+ text-align: center;
144
+ color: var(--wd-text-muted);
145
+ font-size: 0.75rem;
146
+ }
147
+ </style>
@@ -0,0 +1,12 @@
1
+ ---
2
+ // Shorthand for <Callout type="info">. See Callout.astro's own comment.
3
+ import Callout from './Callout.astro';
4
+ interface Props {
5
+ title?: string;
6
+ // See Callout.astro's own comment - set automatically by
7
+ // remarkCalloutAnchorIds, not meant to be passed by hand.
8
+ _titleId?: string;
9
+ }
10
+ const { title, _titleId } = Astro.props as Props;
11
+ ---
12
+ <Callout type="info" title={title} _titleId={_titleId}><slot /></Callout>
@@ -0,0 +1,12 @@
1
+ ---
2
+ // Shorthand for <Callout type="note">. See Callout.astro's own comment.
3
+ import Callout from './Callout.astro';
4
+ interface Props {
5
+ title?: string;
6
+ // See Callout.astro's own comment - set automatically by
7
+ // remarkCalloutAnchorIds, not meant to be passed by hand.
8
+ _titleId?: string;
9
+ }
10
+ const { title, _titleId } = Astro.props as Props;
11
+ ---
12
+ <Callout type="note" title={title} _titleId={_titleId}><slot /></Callout>
@@ -0,0 +1,119 @@
1
+ ---
2
+ // The name+type+description row used throughout API reference content -
3
+ // modeled directly on Mintlify's own ParamField/ResponseField
4
+ // (https://www.mintlify.com/docs/components/expandables), which this
5
+ // was explicitly asked to match. Deliberately one component covering
6
+ // both "this is a request parameter" and "this is a response field"
7
+ // use cases (Mintlify itself ships two near-identical components for
8
+ // that split) - nothing here actually depends on which direction the
9
+ // data flows, so there was no real reason to duplicate it.
10
+ //
11
+ // Only `name` is required - `type` is optional (a parameter's shape is
12
+ // sometimes obvious from context, or genuinely untyped), so its badge
13
+ // only renders when passed.
14
+ //
15
+ // Nests naturally: a Parameter's own slot can contain plain description
16
+ // text, an <Expandable> wrapping more Parameters for a nested object's
17
+ // own properties, or both - see Expandable.astro's own comment for that
18
+ // half of the pattern.
19
+ interface Props {
20
+ name: string;
21
+ type?: string;
22
+ required?: boolean;
23
+ default?: string;
24
+ }
25
+ const { name, type, required = false, default: defaultValue } = Astro.props as Props;
26
+ ---
27
+
28
+ <div class="wd-parameter">
29
+ <div class="wd-parameter-head">
30
+ <span class="wd-parameter-name">{name}</span>
31
+ {type && <span class="wd-parameter-type">{type}</span>}
32
+ {required && <span class="wd-parameter-required">required</span>}
33
+ {defaultValue && <span class="wd-parameter-default">default: {defaultValue}</span>}
34
+ </div>
35
+ <div class="wd-parameter-body">
36
+ <slot />
37
+ </div>
38
+ </div>
39
+ <style>
40
+ .wd-parameter {
41
+ padding: 0.9rem 0;
42
+ }
43
+ /* Divider between consecutive fields, not around the group as a
44
+ whole - a first-child Parameter (the common case: the very first
45
+ field in a list, or the only field passed to Expandable) shouldn't
46
+ render a line above itself with nothing there to separate it
47
+ from. */
48
+ .wd-parameter + .wd-parameter {
49
+ border-top: 1px solid var(--wd-border);
50
+ }
51
+ .wd-parameter-head {
52
+ display: flex;
53
+ align-items: center;
54
+ flex-wrap: wrap;
55
+ gap: 0.5rem;
56
+ margin-bottom: 0.4rem;
57
+ }
58
+ .wd-parameter-name {
59
+ font-family: monospace;
60
+ font-weight: 700;
61
+ color: var(--wd-primary);
62
+ }
63
+ /* border/background/border-radius match base.css's own global inline
64
+ <code> pill exactly (var(--wd-surface)/var(--wd-border)/0.35em) -
65
+ reusing those instead of inventing new chip colors is the actual
66
+ "apply the same styles as our api pages" part of the request: a
67
+ type name here should read as the same kind of chip a reader
68
+ already sees for inline `code` anywhere else in this site's
69
+ content. font-family: monospace is added on top (base.css's own
70
+ inline code doesn't force one, it inherits the body font) - every
71
+ other API-page element that reads as "code" (ApiPlayground's param
72
+ inputs, CodeGroup's tab labels, ApiReferencePanel's own field
73
+ labels) already sets it explicitly the same way, and the reference
74
+ screenshot this was built from clearly renders field names/types
75
+ in a monospace face too. */
76
+ .wd-parameter-type {
77
+ font-family: monospace;
78
+ font-size: 0.8rem;
79
+ background: var(--wd-surface);
80
+ border: 1px solid var(--wd-border);
81
+ border-radius: 0.35em;
82
+ padding: 0.1em 0.5em;
83
+ color: var(--wd-text-muted);
84
+ }
85
+ /* Same chip shape as .wd-parameter-type (border/radius/padding/
86
+ font-family), just recolored red - matches the reference
87
+ screenshot, where "required" reads as the same kind of badge as
88
+ the type chip next to it, not a plain-text label. */
89
+ .wd-parameter-required {
90
+ font-family: monospace;
91
+ font-size: 0.8rem;
92
+ font-weight: 600;
93
+ background: color-mix(in srgb, #dc2626 8%, var(--wd-surface));
94
+ border: 1px solid color-mix(in srgb, #dc2626 35%, var(--wd-border));
95
+ border-radius: 0.35em;
96
+ padding: 0.1em 0.5em;
97
+ color: #dc2626;
98
+ }
99
+ .wd-parameter-default {
100
+ font-size: 0.78rem;
101
+ color: var(--wd-text-muted);
102
+ }
103
+ .wd-parameter-body {
104
+ color: var(--wd-text-muted);
105
+ }
106
+ .wd-parameter-body :global(p:first-child) {
107
+ margin-top: 0;
108
+ }
109
+ .wd-parameter-body :global(p:last-child) {
110
+ margin-bottom: 0;
111
+ }
112
+ /* A nested <Expandable> (see its own comment) sits inside this same
113
+ body slot, right below the description text - a little breathing
114
+ room above it so it doesn't crowd directly against the last line
115
+ of description. */
116
+ .wd-parameter-body :global(.wd-expandable) {
117
+ margin-top: 0.75rem;
118
+ }
119
+ </style>
@@ -0,0 +1,33 @@
1
+ ---
2
+ // Pins its code example(s) in the right sidebar - in place of the page's
3
+ // normal table of contents - on desktop; falls back to a plain in-place
4
+ // CodeGroup on narrower viewports where that sidebar column doesn't
5
+ // render at all. Modeled on Mintlify's own RequestExample/
6
+ // ResponseExample (https://www.mintlify.com/docs/components/examples):
7
+ // "work similarly to CodeGroup... but display the code in the sidebar
8
+ // instead of inline" - reuses CodeGroup.astro itself internally (tabs
9
+ // by default, or its own `dropdown` prop for a <select> switcher
10
+ // instead) rather than reimplementing that tab/dropdown-switching logic
11
+ // a second time.
12
+ //
13
+ // The actual relocation into the sidebar is handled entirely by
14
+ // src/scripts/example-panels.ts, mounted once from [...slug].astro - see
15
+ // its own comment for why a client-side DOM move (rather than an
16
+ // Astro-slot/build-time split) is what this needs: MDX compiles this
17
+ // component's children into one single content flow, with no way for a
18
+ // build-time render to place part of that flow into a *different*
19
+ // column's own slot output.
20
+ //
21
+ // wd-example-panel is the marker class that script looks for; it's
22
+ // otherwise a completely plain wrapper.
23
+ import CodeGroup from './CodeGroup.astro';
24
+ interface Props {
25
+ dropdown?: boolean;
26
+ }
27
+ const { dropdown = false } = Astro.props as Props;
28
+ ---
29
+ <div class="wd-example-panel wd-request-example">
30
+ <CodeGroup dropdown={dropdown}>
31
+ <slot />
32
+ </CodeGroup>
33
+ </div>
@@ -0,0 +1,19 @@
1
+ ---
2
+ // See RequestExample.astro's own comment - identical in every respect
3
+ // except the marker class (wd-response-example vs wd-request-example),
4
+ // which src/scripts/example-panels.ts uses to always dock Response
5
+ // panels below Request panels in the sidebar regardless of which order
6
+ // they're written in a page's own MDX, matching Mintlify's own stated
7
+ // behavior ("ResponseExample... pins code examples in the right sidebar
8
+ // beneath any RequestExample content on the same page").
9
+ import CodeGroup from './CodeGroup.astro';
10
+ interface Props {
11
+ dropdown?: boolean;
12
+ }
13
+ const { dropdown = false } = Astro.props as Props;
14
+ ---
15
+ <div class="wd-example-panel wd-response-example">
16
+ <CodeGroup dropdown={dropdown}>
17
+ <slot />
18
+ </CodeGroup>
19
+ </div>
@@ -0,0 +1,117 @@
1
+ ---
2
+ // Wraps a GFM table (or any other block-level slot content, though a
3
+ // table is the intended/primary use case) with a text input above it
4
+ // that live-filters rows by their own text content - "let users filter
5
+ // the content inside the wrapper" per the request that spawned this.
6
+ //
7
+ // A markdown table always lands as a *direct* child of .wd-article
8
+ // (see [...slug].astro's own comment on this at its `<style is:global>`
9
+ // block), which is what its own global table CSS rule
10
+ // (`.wd-article > table`) deliberately targets - once wrapped in this
11
+ // component's own .wd-searchbar-content div, that table is no longer a
12
+ // direct child of .wd-article, so that rule's ">" combinator stops
13
+ // matching it. Rather than loosening that combinator sitewide (it's
14
+ // intentionally direct-child-only - see its own comment for why), the
15
+ // exact same declarations are duplicated here, scoped to
16
+ // .wd-searchbar-content instead, so a wrapped table still renders
17
+ // identically to every unwrapped one.
18
+ interface Props {
19
+ placeholder?: string;
20
+ }
21
+ const { placeholder = "Search..." } = Astro.props as Props;
22
+ ---
23
+
24
+ <div class="wd-searchbar">
25
+ <input type="text" class="wd-searchbar-input" placeholder={placeholder} aria-label={placeholder} />
26
+ <div class="wd-searchbar-content">
27
+ <slot />
28
+ </div>
29
+ <p class="wd-searchbar-empty">No results found.</p>
30
+ </div>
31
+ <script>
32
+ // Filters by each <tbody> row's own full text content - simplest
33
+ // approach that works regardless of column count/order, and needs no
34
+ // knowledge of the table's shape. Only <tbody> rows are ever
35
+ // filtered (querySelector scopes to "table tbody tr"), so the
36
+ // header row is never a candidate for hiding.
37
+ function initSearchbars(root: ParentNode) {
38
+ root.querySelectorAll<HTMLElement>(".wd-searchbar").forEach((wrapper) => {
39
+ if (wrapper.dataset.wdInit) return;
40
+ wrapper.dataset.wdInit = "true";
41
+ const input = wrapper.querySelector<HTMLInputElement>(".wd-searchbar-input");
42
+ const empty = wrapper.querySelector<HTMLElement>(".wd-searchbar-empty");
43
+ const rows = Array.from(wrapper.querySelectorAll<HTMLTableRowElement>(".wd-searchbar-content table tbody tr"));
44
+ if (!input || rows.length === 0) return;
45
+ input.addEventListener("input", () => {
46
+ const query = input.value.trim().toLowerCase();
47
+ let visibleCount = 0;
48
+ rows.forEach((row) => {
49
+ const isMatch = !query || (row.textContent ?? "").toLowerCase().includes(query);
50
+ row.style.display = isMatch ? "" : "none";
51
+ if (isMatch) visibleCount++;
52
+ });
53
+ if (empty) empty.style.display = visibleCount === 0 ? "block" : "none";
54
+ });
55
+ });
56
+ }
57
+ initSearchbars(document);
58
+ document.addEventListener("astro:page-load", () => initSearchbars(document));
59
+ </script>
60
+ <style>
61
+ .wd-searchbar {
62
+ margin: 1.25rem 0;
63
+ }
64
+ .wd-searchbar-input {
65
+ box-sizing: border-box;
66
+ width: 100%;
67
+ border: 1px solid var(--wd-border);
68
+ border-radius: 0.6rem;
69
+ padding: 0.6rem 1rem;
70
+ margin-bottom: 1rem;
71
+ color: var(--wd-text);
72
+ background: var(--wd-background);
73
+ font-size: 0.9rem;
74
+ font-family: inherit;
75
+ }
76
+ .wd-searchbar-input::placeholder {
77
+ color: var(--wd-text-muted);
78
+ }
79
+ .wd-searchbar-input:focus {
80
+ outline: none;
81
+ border-color: var(--wd-primary);
82
+ }
83
+ /* Matches .wd-article > table's own global styling exactly (see this
84
+ file's own top comment for why it has to be duplicated here rather
85
+ than reused directly) - width/border-collapse/font-size on the
86
+ table itself, cell padding/border/alignment on th and td, and the
87
+ muted uppercase treatment on th. :global() throughout since slot
88
+ content (the author's own MDX table) never carries this
89
+ component's own scope attribute. */
90
+ .wd-searchbar-content :global(table) {
91
+ width: 100%;
92
+ border-collapse: collapse;
93
+ margin: 0;
94
+ font-size: 0.9rem;
95
+ }
96
+ .wd-searchbar-content :global(th),
97
+ .wd-searchbar-content :global(td) {
98
+ text-align: left;
99
+ padding: 0.55rem 0.75rem;
100
+ border-bottom: 1px solid var(--wd-border);
101
+ vertical-align: top;
102
+ }
103
+ .wd-searchbar-content :global(th) {
104
+ color: var(--wd-text-muted);
105
+ font-weight: 600;
106
+ font-size: 0.8rem;
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.03em;
109
+ }
110
+ .wd-searchbar-empty {
111
+ display: none;
112
+ padding: 1.5rem 0;
113
+ text-align: center;
114
+ color: var(--wd-text-muted);
115
+ font-size: 0.9rem;
116
+ }
117
+ </style>
@@ -0,0 +1,10 @@
1
+ ---
2
+ interface Props {
3
+ title?: string;
4
+ }
5
+ const { title } = Astro.props as Props;
6
+ ---
7
+ <div class="wd-step">
8
+ {title && <p class="wd-step-title"><strong>{title}</strong></p>}
9
+ <slot />
10
+ </div>