@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.
- package/LICENSE +15 -0
- package/README.md +17 -0
- package/astro.config.mjs +419 -0
- package/bin/writedocs.js +73 -0
- package/package.json +79 -0
- package/src/assets/wd_watermark.png +0 -0
- package/src/assets/wd_watermark_dark.png +0 -0
- package/src/cli/build-auth.js +53 -0
- package/src/cli/build.js +40 -0
- package/src/cli/dev.js +12 -0
- package/src/cli/generate-api-pages.js +359 -0
- package/src/cli/init.js +81 -0
- package/src/cli/preflight.js +40 -0
- package/src/cli/run-astro.js +57 -0
- package/src/cli/run-pagefind.js +66 -0
- package/src/cli/write-redirects-file.js +80 -0
- package/src/components/Accordion.astro +164 -0
- package/src/components/AccordionGroup.astro +40 -0
- package/src/components/ApiLangSelect.astro +168 -0
- package/src/components/ApiPlayground.astro +281 -0
- package/src/components/ApiReferencePanel.astro +1754 -0
- package/src/components/ApiSchemaField.astro +54 -0
- package/src/components/AppIcon.astro +32 -0
- package/src/components/Badge.astro +128 -0
- package/src/components/Callout.astro +168 -0
- package/src/components/Card.astro +136 -0
- package/src/components/CardGroup.astro +20 -0
- package/src/components/CodeGroup.astro +184 -0
- package/src/components/CopyPageMenu.astro +246 -0
- package/src/components/Danger.astro +12 -0
- package/src/components/Expandable.astro +126 -0
- package/src/components/Frame.astro +102 -0
- package/src/components/Hint.astro +99 -0
- package/src/components/Icon.astro +70 -0
- package/src/components/Image.astro +147 -0
- package/src/components/Info.astro +12 -0
- package/src/components/Note.astro +12 -0
- package/src/components/Parameter.astro +119 -0
- package/src/components/RequestExample.astro +33 -0
- package/src/components/ResponseExample.astro +19 -0
- package/src/components/Searchbar.astro +117 -0
- package/src/components/Step.astro +10 -0
- package/src/components/Steps.astro +32 -0
- package/src/components/Tab.astro +9 -0
- package/src/components/Tabs.astro +52 -0
- package/src/components/Tip.astro +12 -0
- package/src/components/Video.astro +135 -0
- package/src/components/Warning.astro +12 -0
- package/src/components/index.ts +48 -0
- package/src/content.config.ts +223 -0
- package/src/layout/BaseLayout.astro +750 -0
- package/src/layout/components/AnalyticsScripts.astro +77 -0
- package/src/layout/components/AskAiWidget.astro +37 -0
- package/src/layout/components/Breadcrumbs.astro +97 -0
- package/src/layout/components/ImageZoom.astro +19 -0
- package/src/layout/components/MobileMenu.astro +200 -0
- package/src/layout/components/NavTree.astro +351 -0
- package/src/layout/components/SearchModal.astro +42 -0
- package/src/layout/components/Sidebar.astro +122 -0
- package/src/layout/components/SiteFooter.astro +85 -0
- package/src/layout/components/TableOfContents.astro +117 -0
- package/src/layout/components/TopBar.astro +311 -0
- package/src/layout/styles/banner.css +44 -0
- package/src/layout/styles/base.css +234 -0
- package/src/layout/styles/dropdown.css +133 -0
- package/src/layout/styles/footer.css +108 -0
- package/src/layout/styles/image-zoom.css +50 -0
- package/src/layout/styles/mobile-menu.css +258 -0
- package/src/layout/styles/search-modal.css +122 -0
- package/src/layout/styles/topbar.css +437 -0
- package/src/lib/config.ts +2131 -0
- package/src/lib/mdx-auto-hydrate.js +70 -0
- package/src/lib/mdx-inject-builtins.js +87 -0
- package/src/lib/mdx-substitute-variables.js +66 -0
- package/src/lib/mdx-title-anchor-ids.js +84 -0
- package/src/lib/mermaid-rehype.js +72 -0
- package/src/lib/openapi-render.ts +479 -0
- package/src/lib/shiki-code-block.js +102 -0
- package/src/lib/shiki-copy-button.js +45 -0
- package/src/lib/styles-asset-integration.js +210 -0
- package/src/lib/writedocs-temp-dir.js +93 -0
- package/src/pages/404.astro +62 -0
- package/src/pages/[...slug].astro +1270 -0
- package/src/pages/[...slug].md.ts +78 -0
- package/src/pages/llms-full.txt.ts +71 -0
- package/src/pages/llms.txt.ts +141 -0
- package/src/scripts/banner.ts +20 -0
- package/src/scripts/dropdowns.ts +61 -0
- package/src/scripts/image-zoom.ts +66 -0
- package/src/scripts/mobile-menu.ts +55 -0
- package/src/scripts/search.ts +155 -0
- package/src/scripts/sidebar-scroll.ts +65 -0
- package/src/scripts/theme-toggle.ts +35 -0
- package/src/scripts/topbar-offset.ts +141 -0
- package/src/styles/global.css +18 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/* Base element styles + the .wd-shell three-column layout (sidebar / main
|
|
2
|
+
/ toc) - imported once by BaseLayout.astro. Everything here consumes the
|
|
3
|
+
semantic --wd-* custom properties (--wd-primary, --wd-background, etc.)
|
|
4
|
+
set on :root by BaseLayout's own inline <style define:vars> block, not
|
|
5
|
+
the raw wdPrimaryLight/wdPrimaryDark values themselves - so, unlike that
|
|
6
|
+
block, none of this needs to live inside an .astro file's own scoped
|
|
7
|
+
<style> to work. A plain imported .css file is never scoped by Astro in
|
|
8
|
+
the first place, so every selector below is already effectively global -
|
|
9
|
+
no :global() wrapper needed (and, if left in by mistake, :global(...) is
|
|
10
|
+
not valid CSS outside Astro's own scoped-<style> processing, so a rule
|
|
11
|
+
written that way here would just silently never match anything). */
|
|
12
|
+
|
|
13
|
+
* {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
body {
|
|
17
|
+
margin: 0;
|
|
18
|
+
/* Sticky-footer layout: body is the flex column, .wd-page (everything
|
|
19
|
+
above the footer - banner/topbar/.wd-shell, see BaseLayout.astro) is
|
|
20
|
+
its flex: 1 0 auto item below, and <footer class="wd-footer"> is a
|
|
21
|
+
plain sibling after it - on a page short enough not to need
|
|
22
|
+
scrolling, .wd-page's flex-grow fills the leftover space down to the
|
|
23
|
+
viewport's bottom edge, pushing the footer flush against it (rather
|
|
24
|
+
than the footer trailing right after a half-empty page with its own
|
|
25
|
+
background peeking through beneath it); on a page tall enough to
|
|
26
|
+
already fill/exceed the viewport, .wd-page just settles at its own
|
|
27
|
+
natural (larger) height and the footer trails normally at the real
|
|
28
|
+
end of the document, exactly as before this rule existed. Doesn't
|
|
29
|
+
apply in `mode: "blank"` (no .wd-page wrapper, no footer at all in
|
|
30
|
+
that branch - see BaseLayout.astro) - a blank page already controls
|
|
31
|
+
100% of its own layout.
|
|
32
|
+
*/
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
min-height: 100vh;
|
|
36
|
+
/* theme.background (writedocs.json) - --wd-page-bg-color/--wd-page-bg-image
|
|
37
|
+
default to the same value as --wd-background/'none' (see
|
|
38
|
+
BaseLayout.astro's lightPageBgColor/lightPageBgImage resolution), so
|
|
39
|
+
an unconfigured site renders identically to a plain background: var(
|
|
40
|
+
--wd-background) rule. background-attachment: fixed keeps a
|
|
41
|
+
configured image sized to the viewport rather than the full
|
|
42
|
+
(possibly very tall) document - the more expected look for a
|
|
43
|
+
decorative page background, not something that stretches/tiles
|
|
44
|
+
across a long scrolling doc. The topbar and footer each get their
|
|
45
|
+
own explicit opaque background (topbar.css, footer.css)
|
|
46
|
+
specifically so this doesn't show through them - the sidebar, main
|
|
47
|
+
content, and toc columns all have no background of their own, so a
|
|
48
|
+
configured page background/image shows through all three. */
|
|
49
|
+
background-color: var(--wd-page-bg-color);
|
|
50
|
+
background-image: var(--wd-page-bg-image);
|
|
51
|
+
background-size: cover;
|
|
52
|
+
background-position: center;
|
|
53
|
+
background-repeat: no-repeat;
|
|
54
|
+
background-attachment: fixed;
|
|
55
|
+
color: var(--wd-text);
|
|
56
|
+
/* --wd-font-family-body/--wd-font-family (BaseLayout.astro's own
|
|
57
|
+
define:vars <style> block, driven by theme.fonts - see
|
|
58
|
+
resolveFonts()/fontsSchema in lib/config.ts) are always both set to a
|
|
59
|
+
real, already-resolved font stack, never left for this rule's own
|
|
60
|
+
fallback to cover - an unconfigured site still resolves to Inter here
|
|
61
|
+
(genuinely loaded via a Google Fonts <link>, not just named as a
|
|
62
|
+
fallback the way this line used to work before theme.fonts existed).
|
|
63
|
+
The literal fallback stack below only matters in the narrow window
|
|
64
|
+
before that <style> block itself has been parsed. */
|
|
65
|
+
font-family: var(--wd-font-family-body, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
|
|
66
|
+
line-height: 1.6;
|
|
67
|
+
}
|
|
68
|
+
a {
|
|
69
|
+
color: var(--wd-primary);
|
|
70
|
+
}
|
|
71
|
+
/* theme.fonts.heading (or the site-wide theme.fonts.family/Inter default,
|
|
72
|
+
when no heading-specific override is configured - see
|
|
73
|
+
--wd-font-family-heading's own resolution in BaseLayout.astro) - applies
|
|
74
|
+
everywhere a heading renders (article prose, the auto-generated
|
|
75
|
+
.wd-article-header h1, etc.), not just inside .wd-article specifically,
|
|
76
|
+
since nothing site-wide should render headings in a different font by
|
|
77
|
+
accident just because it happens to sit outside that one container. */
|
|
78
|
+
h1,
|
|
79
|
+
h2,
|
|
80
|
+
h3,
|
|
81
|
+
h4,
|
|
82
|
+
h5,
|
|
83
|
+
h6 {
|
|
84
|
+
font-family: var(--wd-font-family-heading, inherit);
|
|
85
|
+
}
|
|
86
|
+
code {
|
|
87
|
+
background: var(--wd-surface);
|
|
88
|
+
border: 1px solid var(--wd-border);
|
|
89
|
+
padding: 0.15em 0.45em;
|
|
90
|
+
border-radius: 0.35em;
|
|
91
|
+
font-size: 1em;
|
|
92
|
+
font-weight: 500;
|
|
93
|
+
}
|
|
94
|
+
pre code {
|
|
95
|
+
background: none;
|
|
96
|
+
border: none;
|
|
97
|
+
padding: 0;
|
|
98
|
+
font-weight: normal;
|
|
99
|
+
}
|
|
100
|
+
pre {
|
|
101
|
+
padding: 1rem;
|
|
102
|
+
border-radius: 0.5rem;
|
|
103
|
+
overflow-x: auto;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* flex: 1 0 auto (not the shorthand `flex: 1` main.wd-shell below also
|
|
107
|
+
uses) so this never shrinks below its own natural content height even
|
|
108
|
+
inside a flex *column* ancestor shorter than that - see body's own
|
|
109
|
+
comment above for the sticky-footer layout this is the growing half
|
|
110
|
+
of. */
|
|
111
|
+
.wd-page {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
flex: 1 0 auto;
|
|
115
|
+
}
|
|
116
|
+
.wd-shell {
|
|
117
|
+
display: flex;
|
|
118
|
+
max-width: 1440px;
|
|
119
|
+
margin: 0 auto;
|
|
120
|
+
width: 100%;
|
|
121
|
+
/* Grows to fill .wd-page's remaining height (after the banner/topbar
|
|
122
|
+
above it take their own natural height) on a short page - see body's
|
|
123
|
+
comment above. .wd-sidebar-col/.wd-toc-col below then stretch to
|
|
124
|
+
match *this* element's own height for free, via flexbox's own
|
|
125
|
+
default `align-items: stretch` on a row - no min-height of their own
|
|
126
|
+
needed (this replaces one on .wd-sidebar-col that used to hardcode
|
|
127
|
+
100vh instead, which overshot on a page with a banner/tall topbar
|
|
128
|
+
above it, or undershot the real page height on a page taller than
|
|
129
|
+
one viewport). */
|
|
130
|
+
flex: 1;
|
|
131
|
+
}
|
|
132
|
+
.wd-sidebar-col {
|
|
133
|
+
width: 260px;
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
border-right: 1px solid var(--wd-border);
|
|
136
|
+
}
|
|
137
|
+
.wd-main-col {
|
|
138
|
+
flex: 1;
|
|
139
|
+
min-width: 0;
|
|
140
|
+
}
|
|
141
|
+
.wd-toc-col {
|
|
142
|
+
width: 230px;
|
|
143
|
+
flex-shrink: 0;
|
|
144
|
+
border-left: 1px solid var(--wd-border);
|
|
145
|
+
}
|
|
146
|
+
@media (max-width: 1150px) {
|
|
147
|
+
.wd-toc-col {
|
|
148
|
+
display: none;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
@media (max-width: 860px) {
|
|
152
|
+
.wd-shell {
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
}
|
|
155
|
+
/* The sidebar itself no longer stacks full-width above the page content
|
|
156
|
+
at this width - it moved into MobileMenu.astro's own panel instead
|
|
157
|
+
(see its own <slot name="sidebar" /> copy), which renders its own
|
|
158
|
+
second copy of the same sidebar content. This copy (inside
|
|
159
|
+
.wd-sidebar-col) just disappears rather than being repositioned. */
|
|
160
|
+
.wd-sidebar-col {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
/* Sidebar.astro's .wd-sidebar is sticky-with-its-own-scrollbar on wide
|
|
164
|
+
screens (see its own style block for why) - not appropriate for the
|
|
165
|
+
copy now living inside MobileMenu.astro's own scroll area, which
|
|
166
|
+
already has its own scroll area; this makes it flow as a plain block
|
|
167
|
+
there instead of trying to run a second, nested one. This selector
|
|
168
|
+
reaches into Sidebar.astro's own scoped class from a plain external
|
|
169
|
+
stylesheet - works with no special syntax needed (unlike the
|
|
170
|
+
:global() wrapper this rule needed back when it lived in BaseLayout's
|
|
171
|
+
own scoped <style> block), since a plain .css file was never scoped
|
|
172
|
+
to begin with. */
|
|
173
|
+
.wd-sidebar {
|
|
174
|
+
position: static;
|
|
175
|
+
max-height: none;
|
|
176
|
+
overflow-y: visible;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Dual light/dark logo: both <img> tags are always in the markup (see
|
|
181
|
+
TopBar.astro/MobileMenu.astro/SiteFooter.astro, all three of which
|
|
182
|
+
render this same pair), CSS shows only the one matching the active
|
|
183
|
+
[data-theme] - set by the inline anti-FOUC script in BaseLayout's
|
|
184
|
+
<head> + the theme-toggle click handler (src/scripts/theme-toggle.ts).
|
|
185
|
+
A site that only gave one logo path gets the same <img> rendered twice
|
|
186
|
+
with both classes worth of visibility rules, i.e. it's just always
|
|
187
|
+
shown. Kept here (not co-located with any one of the three components
|
|
188
|
+
above) since all three need it identically. */
|
|
189
|
+
.wd-logo-dark {
|
|
190
|
+
display: none;
|
|
191
|
+
}
|
|
192
|
+
[data-theme="dark"] .wd-logo-light {
|
|
193
|
+
display: none;
|
|
194
|
+
}
|
|
195
|
+
[data-theme="dark"] .wd-logo-dark {
|
|
196
|
+
display: block;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* Same dual-image/CSS-toggle mechanism as the logo pair above, for the
|
|
200
|
+
"Powered by writedocs" sidebar watermark (Sidebar.astro) - kept as
|
|
201
|
+
plain global rules here rather than a `:global()`-wrapped selector
|
|
202
|
+
inside that component's own scoped <style> block, matching this
|
|
203
|
+
proven pattern exactly instead of a second, more exotic variant of
|
|
204
|
+
it. */
|
|
205
|
+
.wd-watermark-dark {
|
|
206
|
+
display: none;
|
|
207
|
+
}
|
|
208
|
+
[data-theme="dark"] .wd-watermark-light {
|
|
209
|
+
display: none;
|
|
210
|
+
}
|
|
211
|
+
[data-theme="dark"] .wd-watermark-dark {
|
|
212
|
+
display: block;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Astro's Shiki output (both the built-in MDX code-fence pipeline,
|
|
216
|
+
configured with dual themes in astro.config.mjs, and the <Code />
|
|
217
|
+
component used for the API playground's request/response snippets)
|
|
218
|
+
bakes the "light" theme as each element's base color/background and
|
|
219
|
+
stashes the dark equivalents in --shiki-dark/--shiki-dark-bg custom
|
|
220
|
+
properties. Swapping to those on [data-theme='dark'] is the officially
|
|
221
|
+
documented way to make Shiki-highlighted code follow a manual
|
|
222
|
+
(non-media-query) theme toggle - see
|
|
223
|
+
https://docs.astro.build/en/guides/syntax-highlighting/#setting-light-and-dark-mode-themes.
|
|
224
|
+
Site-wide/article-content concern, unrelated to any one layout
|
|
225
|
+
component, which is why it lives here rather than in any of the
|
|
226
|
+
feature-specific stylesheets. */
|
|
227
|
+
[data-theme="dark"] .astro-code,
|
|
228
|
+
[data-theme="dark"] .astro-code span {
|
|
229
|
+
color: var(--shiki-dark) !important;
|
|
230
|
+
background-color: var(--shiki-dark-bg) !important;
|
|
231
|
+
font-style: var(--shiki-dark-font-style) !important;
|
|
232
|
+
font-weight: var(--shiki-dark-font-weight) !important;
|
|
233
|
+
text-decoration: var(--shiki-dark-text-decoration) !important;
|
|
234
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* The .wd-dropdown/.wd-dropdown-trigger/.wd-dropdown-menu/
|
|
2
|
+
.wd-dropdown-menu-panel pattern below (plus initDropdowns() in
|
|
3
|
+
src/scripts/dropdowns.ts) is written to be reused by any component that
|
|
4
|
+
wants a click-to-toggle dropdown, not just the topbar selectors/tab
|
|
5
|
+
dropdowns it was first built for - CopyPageMenu.astro is another
|
|
6
|
+
consumer. Imported by TopBar.astro (which owns most of this markup:
|
|
7
|
+
switchers, tabs, the small-screen topbar.links ellipsis) and also by
|
|
8
|
+
MobileMenu.astro, for the .wd-tab-icon/.wd-selector-tag primitives its
|
|
9
|
+
own accordion rows reuse (MobileMenu doesn't render any .wd-dropdown
|
|
10
|
+
markup itself today, but importing this costs nothing extra - Vite
|
|
11
|
+
dedupes a CSS file imported from more than one component). */
|
|
12
|
+
.wd-dropdown {
|
|
13
|
+
position: relative;
|
|
14
|
+
}
|
|
15
|
+
.wd-dropdown-trigger {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: 0.35rem;
|
|
19
|
+
padding: 0.4rem 0.75rem;
|
|
20
|
+
border-radius: 0.4rem;
|
|
21
|
+
border: none;
|
|
22
|
+
background: none;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
color: var(--wd-text-muted);
|
|
25
|
+
font-size: 0.9rem;
|
|
26
|
+
font-weight: 500;
|
|
27
|
+
font-family: inherit;
|
|
28
|
+
}
|
|
29
|
+
.wd-dropdown-trigger:hover {
|
|
30
|
+
color: var(--wd-text);
|
|
31
|
+
}
|
|
32
|
+
.wd-dropdown-caret {
|
|
33
|
+
transition: transform 0.12s ease;
|
|
34
|
+
}
|
|
35
|
+
.wd-topbar-tabs .wd-dropdown-caret {
|
|
36
|
+
margin-top: 4px;
|
|
37
|
+
}
|
|
38
|
+
.wd-dropdown.open .wd-dropdown-caret {
|
|
39
|
+
transform: rotate(180deg);
|
|
40
|
+
}
|
|
41
|
+
/* .wd-dropdown-menu itself sits flush against the trigger (top: 100%, no
|
|
42
|
+
gap) and is what actually receives :hover/.open - the visible white box
|
|
43
|
+
(background/border/shadow/padding) lives on the .wd-dropdown-menu-panel
|
|
44
|
+
child instead, offset down via padding-top on the parent. This is
|
|
45
|
+
deliberate: an earlier version put that 0.4rem breathing room directly
|
|
46
|
+
on .wd-dropdown-menu's own `top` offset, which left a dead strip between
|
|
47
|
+
the trigger and the menu that belonged to neither - moving the mouse
|
|
48
|
+
from one to the other crossed unhovered space and closed the menu
|
|
49
|
+
before you could reach it. Padding (unlike a `top`/`margin` offset) is
|
|
50
|
+
still part of the element's own hoverable box, so this keeps the same
|
|
51
|
+
visual gap without the dead zone. */
|
|
52
|
+
.wd-dropdown-menu {
|
|
53
|
+
display: none;
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: 100%;
|
|
56
|
+
left: 0;
|
|
57
|
+
padding-top: 0.4rem;
|
|
58
|
+
z-index: 20;
|
|
59
|
+
}
|
|
60
|
+
.wd-dropdown-menu-panel {
|
|
61
|
+
min-width: 180px;
|
|
62
|
+
background: var(--wd-background);
|
|
63
|
+
border: 1px solid var(--wd-border);
|
|
64
|
+
border-radius: 0.5rem;
|
|
65
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
|
66
|
+
padding: 0.4rem;
|
|
67
|
+
}
|
|
68
|
+
.wd-dropdown.open .wd-dropdown-menu {
|
|
69
|
+
display: block;
|
|
70
|
+
}
|
|
71
|
+
/* Hovering a trigger reveals its menu too, not just clicking it - a plain
|
|
72
|
+
CSS :hover rule alongside the JS-driven .open class (initDropdowns()),
|
|
73
|
+
which still owns click-to-toggle/outside-click-to-close/Escape-to-close.
|
|
74
|
+
Both rules just set the same display:block, so they layer cleanly:
|
|
75
|
+
moving the mouse away closes a hover-only reveal, while a click-opened
|
|
76
|
+
menu (the .open class) stays open regardless of where the mouse is
|
|
77
|
+
until it's explicitly closed. */
|
|
78
|
+
.wd-dropdown:hover .wd-dropdown-caret {
|
|
79
|
+
transform: rotate(180deg);
|
|
80
|
+
}
|
|
81
|
+
.wd-dropdown:hover .wd-dropdown-menu {
|
|
82
|
+
display: block;
|
|
83
|
+
}
|
|
84
|
+
.wd-dropdown-menu a {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 0.5rem;
|
|
88
|
+
padding: 0.45rem 0.6rem;
|
|
89
|
+
border-radius: 0.35rem;
|
|
90
|
+
text-decoration: none;
|
|
91
|
+
color: var(--wd-text);
|
|
92
|
+
font-size: 0.88rem;
|
|
93
|
+
}
|
|
94
|
+
.wd-dropdown-menu a:hover {
|
|
95
|
+
background: var(--wd-surface);
|
|
96
|
+
}
|
|
97
|
+
.wd-dropdown-menu a.active {
|
|
98
|
+
color: var(--wd-primary);
|
|
99
|
+
background: color-mix(in srgb, var(--wd-primary) 10%, transparent);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* .wd-tab-icon is shared by AppIcon's two render modes: a real <svg>
|
|
103
|
+
(astro-icon, sized to the surrounding text) or a <span> (literal
|
|
104
|
+
emoji/text, sized by inherited font-size alone). Used by every dropdown
|
|
105
|
+
option/trigger above, TopBar.astro's tabs row, MobileMenu.astro's own
|
|
106
|
+
accordion rows, topbar.links (both the desktop row and the collapsed
|
|
107
|
+
mobile dropdown - TopBar.astro), and footer column links
|
|
108
|
+
(SiteFooter.astro) - a generic "icon sized to sit next to text" primitive
|
|
109
|
+
despite the tab-specific name, not worth a same-rules second class. */
|
|
110
|
+
svg.wd-tab-icon {
|
|
111
|
+
width: 1em;
|
|
112
|
+
height: 1em;
|
|
113
|
+
flex-shrink: 0;
|
|
114
|
+
}
|
|
115
|
+
span.wd-tab-icon {
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
flex-shrink: 0;
|
|
119
|
+
}
|
|
120
|
+
.wd-selector-tag {
|
|
121
|
+
font-size: 0.65rem;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
text-transform: uppercase;
|
|
124
|
+
letter-spacing: 0.03em;
|
|
125
|
+
padding: 0.1rem 0.4rem;
|
|
126
|
+
border-radius: 999px;
|
|
127
|
+
background: var(--wd-surface);
|
|
128
|
+
color: var(--wd-text-muted);
|
|
129
|
+
}
|
|
130
|
+
.wd-dropdown-menu a.active .wd-selector-tag {
|
|
131
|
+
background: color-mix(in srgb, var(--wd-primary) 15%, transparent);
|
|
132
|
+
color: var(--wd-primary);
|
|
133
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* writedocs.json's `footer.columns`/`socials` - see SiteFooter.astro (only
|
|
2
|
+
rendered at all when one of those has content) and footerSchema/
|
|
3
|
+
`socials` in lib/config.ts. Sits below .wd-shell, same max-width/
|
|
4
|
+
centering convention as .wd-topbar-inner/.wd-shell so its content lines
|
|
5
|
+
up with the rest of the page. */
|
|
6
|
+
.wd-footer {
|
|
7
|
+
border-top: 1px solid var(--wd-border);
|
|
8
|
+
/* Explicit opaque background - previously unset (transparent, just
|
|
9
|
+
showing <body>'s own flat color through it, which looked identical
|
|
10
|
+
to having one). Now load-bearing: theme.background's own color/image
|
|
11
|
+
paints on <body> itself, and this is what keeps that from showing
|
|
12
|
+
through the footer. */
|
|
13
|
+
background: var(--wd-background);
|
|
14
|
+
/* body (base.css) is now the sticky-footer flex column this sits in as
|
|
15
|
+
a plain sibling after .wd-page - flex-shrink: 0 keeps this pinned at
|
|
16
|
+
its own natural height rather than the flex column trying to
|
|
17
|
+
compress it on a page taller than one viewport (harmless in
|
|
18
|
+
practice, since body has no fixed height of its own to overflow
|
|
19
|
+
against, but explicit here to match how every other fixed-size flex
|
|
20
|
+
item in this codebase - .wd-footer-brand, .wd-footer-socials below -
|
|
21
|
+
already spells this out rather than relying on it never coming up). */
|
|
22
|
+
flex-shrink: 0;
|
|
23
|
+
}
|
|
24
|
+
.wd-footer-inner {
|
|
25
|
+
max-width: 1440px;
|
|
26
|
+
margin: 0 auto;
|
|
27
|
+
padding: 2.5rem 1.5rem;
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-wrap: wrap;
|
|
30
|
+
align-items: flex-start;
|
|
31
|
+
justify-content: space-between;
|
|
32
|
+
gap: 2rem;
|
|
33
|
+
}
|
|
34
|
+
/* Only rendered when theme.logo is set (hasLogoImage) - reuses the exact
|
|
35
|
+
same wd-logo-light/wd-logo-dark <img> pair + CSS toggle (base.css) the
|
|
36
|
+
topbar brand link and mobile menu header also use, just in a third spot.
|
|
37
|
+
flex-shrink: 0 so it keeps its own size rather than getting squeezed as
|
|
38
|
+
.wd-footer-columns (flex: 1 below) claims the row's free space. */
|
|
39
|
+
.wd-footer-brand {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
flex-shrink: 0;
|
|
43
|
+
}
|
|
44
|
+
.wd-footer-columns {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-wrap: wrap;
|
|
47
|
+
gap: 2.5rem;
|
|
48
|
+
flex: 1;
|
|
49
|
+
}
|
|
50
|
+
.wd-footer-column-title {
|
|
51
|
+
font-size: 0.78rem;
|
|
52
|
+
font-weight: 600;
|
|
53
|
+
text-transform: uppercase;
|
|
54
|
+
letter-spacing: 0.03em;
|
|
55
|
+
color: var(--wd-text-muted);
|
|
56
|
+
margin-bottom: 0.75rem;
|
|
57
|
+
}
|
|
58
|
+
.wd-footer-column-links {
|
|
59
|
+
list-style: none;
|
|
60
|
+
margin: 0;
|
|
61
|
+
padding: 0;
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: 0.55rem;
|
|
65
|
+
}
|
|
66
|
+
.wd-footer-column-links a {
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 0.4rem;
|
|
70
|
+
color: var(--wd-text-muted);
|
|
71
|
+
text-decoration: none;
|
|
72
|
+
font-size: 0.88rem;
|
|
73
|
+
}
|
|
74
|
+
.wd-footer-column-links a:hover {
|
|
75
|
+
color: var(--wd-text);
|
|
76
|
+
}
|
|
77
|
+
/* flex-shrink: 0 so a wide set of columns wraps/shrinks before this row
|
|
78
|
+
does - social icons staying a fixed size reads better than them
|
|
79
|
+
shrinking or wrapping mid-row. */
|
|
80
|
+
.wd-footer-socials {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: flex-start;
|
|
83
|
+
gap: 0.6rem;
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
}
|
|
86
|
+
.wd-footer-social-link {
|
|
87
|
+
display: inline-flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
width: 2rem;
|
|
91
|
+
height: 2rem;
|
|
92
|
+
border-radius: 0.4rem;
|
|
93
|
+
color: var(--wd-text-muted);
|
|
94
|
+
}
|
|
95
|
+
.wd-footer-social-link:hover {
|
|
96
|
+
color: var(--wd-text);
|
|
97
|
+
background: var(--wd-surface);
|
|
98
|
+
}
|
|
99
|
+
/* AppIcon.astro renders either a real <svg> (astro-icon, for an Iconify
|
|
100
|
+
id) or a <span> (literal text/emoji). */
|
|
101
|
+
svg.wd-footer-social-icon {
|
|
102
|
+
width: 1.1rem;
|
|
103
|
+
height: 1.1rem;
|
|
104
|
+
}
|
|
105
|
+
span.wd-footer-social-icon {
|
|
106
|
+
font-size: 1.1rem;
|
|
107
|
+
line-height: 1;
|
|
108
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* ImageZoom.astro's own styling - the fullscreen lightbox overlay, plus
|
|
2
|
+
the cursor affordance on the content images that open it (see
|
|
3
|
+
src/scripts/image-zoom.ts, which is what actually adds the
|
|
4
|
+
.wd-zoomable class - only images that end up zoomable get the cursor,
|
|
5
|
+
never Card's own image or anything marked nozoom). */
|
|
6
|
+
|
|
7
|
+
.wd-zoomable {
|
|
8
|
+
cursor: zoom-in;
|
|
9
|
+
}
|
|
10
|
+
.wd-zoom-overlay {
|
|
11
|
+
position: fixed;
|
|
12
|
+
inset: 0;
|
|
13
|
+
z-index: 200;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
padding: 2.5rem;
|
|
18
|
+
background: rgba(15, 23, 42, 0.85);
|
|
19
|
+
cursor: zoom-out;
|
|
20
|
+
}
|
|
21
|
+
.wd-zoom-overlay[hidden] {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
.wd-zoom-image {
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
max-height: 100%;
|
|
27
|
+
border-radius: 0.5rem;
|
|
28
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
|
29
|
+
cursor: zoom-out;
|
|
30
|
+
}
|
|
31
|
+
.wd-zoom-close {
|
|
32
|
+
position: fixed;
|
|
33
|
+
top: 1.25rem;
|
|
34
|
+
right: 1.25rem;
|
|
35
|
+
width: 2.25rem;
|
|
36
|
+
height: 2.25rem;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
border: none;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
background: rgba(255, 255, 255, 0.12);
|
|
43
|
+
color: #fff;
|
|
44
|
+
font-size: 1.5rem;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
}
|
|
48
|
+
.wd-zoom-close:hover {
|
|
49
|
+
background: rgba(255, 255, 255, 0.22);
|
|
50
|
+
}
|