@ciderpress/ui 1.0.0-rc.1 → 1.0.0-rc.11
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/dist/head/css/loader-apple.css +1 -1
- package/dist/head/css/loader-dots.css +1 -1
- package/dist/head/css/themes/amber.css +1 -1
- package/dist/head/css/themes/arcade.css +1 -1
- package/dist/head/css/themes/grannysmith.css +1 -1
- package/dist/head/css/themes/honeycrisp.css +1 -1
- package/dist/head/css/themes/midnight.css +1 -1
- package/dist/head/css/themes/mulled.css +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +4 -3
- package/dist/node.d.ts +1 -1
- package/dist/node.mjs +732 -55
- package/dist/plugins/mermaid/MermaidRenderer.tsx +49 -6
- package/dist/theme/components/footer/site-footer.tsx +68 -9
- package/dist/theme/components/home/cta.css +15 -0
- package/dist/theme/components/home/cta.tsx +10 -2
- package/dist/theme/components/home/feature-card.css +1 -1
- package/dist/theme/components/home/feature-card.tsx +8 -10
- package/dist/theme/components/home/feature.tsx +54 -31
- package/dist/theme/components/home/hero-demo.css +38 -0
- package/dist/theme/components/home/home-visual.tsx +226 -0
- package/dist/theme/components/home/layout.tsx +410 -108
- package/dist/theme/components/home/split.css +46 -19
- package/dist/theme/components/home/split.tsx +28 -8
- package/dist/theme/components/home/tabs.css +299 -0
- package/dist/theme/components/home/tabs.tsx +351 -0
- package/dist/theme/components/home/trust-strip.css +41 -0
- package/dist/theme/components/home/trust-strip.tsx +168 -11
- package/dist/theme/components/home/workspaces.tsx +176 -38
- package/dist/theme/components/nav/branch-tag.tsx +7 -7
- package/dist/theme/components/nav/ciderpress-docs-bar.css +13 -1
- package/dist/theme/components/nav/ciderpress-docs-bar.tsx +33 -2
- package/dist/theme/components/nav/ciderpress-header.css +2 -1
- package/dist/theme/components/nav/ciderpress-header.tsx +26 -3
- package/dist/theme/components/nav/ciderpress-nav-hamburger.css +50 -0
- package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +95 -9
- package/dist/theme/components/nav/ciderpress-nav-menu.css +88 -0
- package/dist/theme/components/nav/ciderpress-nav-menu.tsx +397 -38
- package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +27 -22
- package/dist/theme/components/nav/floating-branch-indicator.tsx +7 -7
- package/dist/theme/components/nav/header-icon.css +24 -0
- package/dist/theme/components/nav/header-icon.tsx +119 -0
- package/dist/theme/components/nav/header-logo.css +16 -0
- package/dist/theme/components/nav/header-logo.tsx +200 -0
- package/dist/theme/components/nav/layout.tsx +117 -16
- package/dist/theme/components/nav/nav-logo.tsx +16 -19
- package/dist/theme/components/openapi/index.ts +0 -2
- package/dist/theme/components/openapi/openapi.css +0 -14
- package/dist/theme/components/shared/card-icon.tsx +37 -0
- package/dist/theme/components/shared/ciderpress-logo.tsx +5 -1
- package/dist/theme/components/shared/icon.tsx +120 -35
- package/dist/theme/components/shared/resolve-card-icon.ts +53 -12
- package/dist/theme/components/shared/section-card.tsx +37 -6
- package/dist/theme/components/sidebar/sidebar-badge.css +50 -0
- package/dist/theme/components/sidebar/sidebar-badge.tsx +153 -0
- package/dist/theme/components/sidebar/sidebar-links.tsx +6 -2
- package/dist/theme/components/sidebar/sidebar-scope.tsx +24 -1
- package/dist/theme/components/theme-provider.tsx +27 -11
- package/dist/theme/components/workspaces/card.css +4 -0
- package/dist/theme/components/workspaces/card.tsx +10 -12
- package/dist/theme/components/workspaces/grid.tsx +18 -6
- package/dist/theme/hooks/use-ciderpress.ts +65 -5
- package/dist/theme/hooks/use-nav-items.ts +82 -11
- package/dist/theme/index.tsx +10 -3
- package/dist/theme/lib/read-social-links.ts +4 -3
- package/dist/theme/lib/rich-text-parse.ts +740 -0
- package/dist/theme/lib/rich-text.test.tsx +342 -0
- package/dist/theme/lib/rich-text.tsx +86 -0
- package/dist/theme/lib/theme-favicon.ts +1 -1
- package/dist/theme/lib/with-mount-base.ts +31 -0
- package/dist/theme/styles/overrides/fonts.css +7 -4
- package/dist/theme/styles/overrides/footnotes.css +54 -0
- package/dist/theme/styles/overrides/home.css +11 -2
- package/dist/theme/styles/overrides/lists.css +83 -0
- package/dist/theme/styles/overrides/rail.css +27 -10
- package/dist/theme/styles/overrides/rspress.css +10 -5
- package/dist/theme/styles/overrides/section-card.css +9 -0
- package/dist/theme/styles/overrides/sidebar.css +22 -0
- package/dist/theme/styles/overrides/tokens.css +41 -23
- package/dist/theme/styles/rich-text.css +106 -0
- package/dist/theme/styles/themes/amber.css +32 -2
- package/dist/theme/styles/themes/arcade.css +16 -1
- package/dist/theme/styles/themes/grannysmith.css +32 -2
- package/dist/theme/styles/themes/honeycrisp.css +37 -7
- package/dist/theme/styles/themes/midnight.css +16 -1
- package/dist/theme/styles/themes/mulled.css +54 -9
- package/package.json +18 -16
- package/src/theme/components/footer/site-footer.tsx +68 -9
- package/src/theme/components/home/cta.css +15 -0
- package/src/theme/components/home/cta.tsx +10 -2
- package/src/theme/components/home/feature-card.css +1 -1
- package/src/theme/components/home/feature-card.tsx +8 -10
- package/src/theme/components/home/feature.tsx +54 -31
- package/src/theme/components/home/hero-demo.css +38 -0
- package/src/theme/components/home/home-visual.tsx +226 -0
- package/src/theme/components/home/layout.tsx +410 -108
- package/src/theme/components/home/split.css +46 -19
- package/src/theme/components/home/split.tsx +28 -8
- package/src/theme/components/home/tabs.css +299 -0
- package/src/theme/components/home/tabs.tsx +351 -0
- package/src/theme/components/home/trust-strip.css +41 -0
- package/src/theme/components/home/trust-strip.tsx +168 -11
- package/src/theme/components/home/workspaces.tsx +176 -38
- package/src/theme/components/nav/branch-tag.tsx +7 -7
- package/src/theme/components/nav/ciderpress-docs-bar.css +13 -1
- package/src/theme/components/nav/ciderpress-docs-bar.tsx +33 -2
- package/src/theme/components/nav/ciderpress-header.css +2 -1
- package/src/theme/components/nav/ciderpress-header.tsx +26 -3
- package/src/theme/components/nav/ciderpress-nav-hamburger.css +50 -0
- package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +95 -9
- package/src/theme/components/nav/ciderpress-nav-menu.css +88 -0
- package/src/theme/components/nav/ciderpress-nav-menu.tsx +397 -38
- package/src/theme/components/nav/ciderpress-nav-social-links.tsx +27 -22
- package/src/theme/components/nav/floating-branch-indicator.tsx +7 -7
- package/src/theme/components/nav/header-icon.css +24 -0
- package/src/theme/components/nav/header-icon.tsx +119 -0
- package/src/theme/components/nav/header-logo.css +16 -0
- package/src/theme/components/nav/header-logo.tsx +200 -0
- package/src/theme/components/nav/layout.tsx +117 -16
- package/src/theme/components/nav/nav-logo.tsx +16 -19
- package/src/theme/components/openapi/index.ts +0 -2
- package/src/theme/components/openapi/openapi.css +0 -14
- package/src/theme/components/shared/card-icon.tsx +37 -0
- package/src/theme/components/shared/ciderpress-logo.tsx +5 -1
- package/src/theme/components/shared/icon.tsx +120 -35
- package/src/theme/components/shared/resolve-card-icon.ts +53 -12
- package/src/theme/components/shared/section-card.tsx +37 -6
- package/src/theme/components/sidebar/sidebar-badge.css +50 -0
- package/src/theme/components/sidebar/sidebar-badge.tsx +153 -0
- package/src/theme/components/sidebar/sidebar-links.tsx +6 -2
- package/src/theme/components/sidebar/sidebar-scope.tsx +24 -1
- package/src/theme/components/theme-provider.tsx +27 -11
- package/src/theme/components/workspaces/card.css +4 -0
- package/src/theme/components/workspaces/card.tsx +10 -12
- package/src/theme/components/workspaces/grid.tsx +18 -6
- package/src/theme/hooks/use-ciderpress.ts +65 -5
- package/src/theme/hooks/use-nav-items.ts +82 -11
- package/src/theme/index.tsx +10 -3
- package/src/theme/lib/read-social-links.ts +4 -3
- package/src/theme/lib/rich-text-parse.ts +740 -0
- package/src/theme/lib/rich-text.test.tsx +342 -0
- package/src/theme/lib/rich-text.tsx +86 -0
- package/src/theme/lib/theme-favicon.ts +1 -1
- package/src/theme/lib/with-mount-base.ts +31 -0
- package/src/theme/styles/overrides/fonts.css +7 -4
- package/src/theme/styles/overrides/footnotes.css +54 -0
- package/src/theme/styles/overrides/home.css +11 -2
- package/src/theme/styles/overrides/lists.css +83 -0
- package/src/theme/styles/overrides/rail.css +27 -10
- package/src/theme/styles/overrides/rspress.css +10 -5
- package/src/theme/styles/overrides/section-card.css +9 -0
- package/src/theme/styles/overrides/sidebar.css +22 -0
- package/src/theme/styles/overrides/tokens.css +41 -23
- package/src/theme/styles/rich-text.css +106 -0
- package/src/theme/styles/themes/amber.css +32 -2
- package/src/theme/styles/themes/arcade.css +16 -1
- package/src/theme/styles/themes/grannysmith.css +32 -2
- package/src/theme/styles/themes/honeycrisp.css +37 -7
- package/src/theme/styles/themes/midnight.css +16 -1
- package/src/theme/styles/themes/mulled.css +54 -9
- package/dist/theme/components/openapi/copy-markdown-button.tsx +0 -41
- package/src/theme/components/openapi/copy-markdown-button.tsx +0 -41
|
@@ -11,6 +11,8 @@ declare const __CIDERPRESS_DEFAULT_VARIANT__: string
|
|
|
11
11
|
declare const __CIDERPRESS_THEME_COLORS__: string
|
|
12
12
|
declare const __CIDERPRESS_THEME_DARK_COLORS__: string
|
|
13
13
|
declare const __CIDERPRESS_THEME_REGISTRY__: string
|
|
14
|
+
declare const __CIDERPRESS_HAS_USER_FAVICON__: boolean
|
|
15
|
+
declare const __CIDERPRESS_LOADER_MIN_MS__: number
|
|
14
16
|
|
|
15
17
|
interface RegistryEntry {
|
|
16
18
|
readonly name: string
|
|
@@ -26,7 +28,7 @@ type ThemeColorKey = keyof ThemeColors
|
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Parsed theme registry — built-in themes plus any user themes from
|
|
29
|
-
* `
|
|
31
|
+
* `theme.themes`. Read from the build-time define so the client bundle
|
|
30
32
|
* does not pull `@ciderpress/theme`'s factory + Zod into the runtime path.
|
|
31
33
|
*/
|
|
32
34
|
const REGISTRY_ENTRIES: readonly RegistryEntry[] = parseRegistry(__CIDERPRESS_THEME_REGISTRY__)
|
|
@@ -123,9 +125,11 @@ const COLOR_VAR_MAP: Readonly<Record<ThemeColorKey, readonly string[]>> = Object
|
|
|
123
125
|
const ALL_CSS_VARS: readonly string[] = Object.values(COLOR_VAR_MAP).flat()
|
|
124
126
|
|
|
125
127
|
/**
|
|
126
|
-
* Minimum time (ms) the loading overlay stays visible before fading
|
|
128
|
+
* Minimum time (ms) the loading overlay stays visible before fading
|
|
129
|
+
* out. Resolved at build time from `brand.loader.minDisplayMs` —
|
|
130
|
+
* defaults to 150ms in `packages/ui/src/config.ts`.
|
|
127
131
|
*/
|
|
128
|
-
const LOADER_MIN_DISPLAY_MS =
|
|
132
|
+
const LOADER_MIN_DISPLAY_MS = __CIDERPRESS_LOADER_MIN_MS__
|
|
129
133
|
|
|
130
134
|
/**
|
|
131
135
|
* Duration (ms) of the CSS fade-out transition. Must match the
|
|
@@ -199,12 +203,14 @@ export function ThemeProvider(): React.ReactElement | null {
|
|
|
199
203
|
applyColorOverrides(html, darkColors)
|
|
200
204
|
}
|
|
201
205
|
|
|
202
|
-
// Sync the document favicon with the active theme's brand colour
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
|
|
206
|
+
// Sync the document favicon with the active theme's brand colour —
|
|
207
|
+
// only when the user has NOT set their own `favicon` in config. When
|
|
208
|
+
// they have, Rspress already points `<link rel="icon">` at the
|
|
209
|
+
// user's asset, and overwriting it with the themed apple data-URI
|
|
210
|
+
// would silently restore ciderpress branding.
|
|
211
|
+
if (!__CIDERPRESS_HAS_USER_FAVICON__) {
|
|
212
|
+
syncThemeFavicon(html)
|
|
213
|
+
}
|
|
208
214
|
|
|
209
215
|
// Observe `.rp-dark` class changes so Rspress's built-in dark toggle
|
|
210
216
|
// stays the single source of truth for variant flips. The new variant
|
|
@@ -253,8 +259,11 @@ export function ThemeProvider(): React.ReactElement | null {
|
|
|
253
259
|
}
|
|
254
260
|
// Re-sync the favicon — brand colour is constant across variants for
|
|
255
261
|
// built-in themes, but surface overrides on the dark variant can
|
|
256
|
-
// affect the chip background colour we bake into the SVG.
|
|
257
|
-
|
|
262
|
+
// affect the chip background colour we bake into the SVG. Skipped
|
|
263
|
+
// when the user supplied their own favicon (see initial sync above).
|
|
264
|
+
if (!__CIDERPRESS_HAS_USER_FAVICON__) {
|
|
265
|
+
syncThemeFavicon(html)
|
|
266
|
+
}
|
|
258
267
|
})
|
|
259
268
|
observer.observe(html, { attributes: true, attributeFilter: ['class'] })
|
|
260
269
|
|
|
@@ -628,6 +637,13 @@ function dismissLoader(html: HTMLElement): () => void {
|
|
|
628
637
|
clearDotsInterval()
|
|
629
638
|
}, LOADER_MIN_DISPLAY_MS + LOADER_FADE_MS)
|
|
630
639
|
|
|
640
|
+
// The forced-dismiss fallback (covering the case where React never
|
|
641
|
+
// hydrates) lives in the inline head script — see `buildHeadScriptBody`
|
|
642
|
+
// in `packages/ui/src/config.ts`. That timer always runs, so a
|
|
643
|
+
// duplicate React-side fallback here would only fire AFTER ThemeProvider
|
|
644
|
+
// has already mounted — at which point the normal fade path above has
|
|
645
|
+
// already won.
|
|
646
|
+
|
|
631
647
|
return () => {
|
|
632
648
|
clearTimeout(fadeTimer)
|
|
633
649
|
clearTimeout(removeTimer)
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
font-size: 15px;
|
|
70
70
|
font-weight: 700;
|
|
71
71
|
color: var(--cp-c-text-1);
|
|
72
|
+
/* Presentational lowercase. Done here rather than in JS because the
|
|
73
|
+
title may carry inline markup — lowercasing the source would also
|
|
74
|
+
lowercase link targets and class names inside it. */
|
|
75
|
+
text-transform: lowercase;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
.cp-workspace-card__desc {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { match, P } from 'massaman/match'
|
|
2
2
|
import type React from 'react'
|
|
3
3
|
|
|
4
|
+
import { renderRichText } from '../../lib/rich-text.tsx'
|
|
4
5
|
import { Card } from '../shared/card'
|
|
5
|
-
import {
|
|
6
|
+
import { CardIcon } from '../shared/card-icon'
|
|
7
|
+
import type { CardIconInput } from '../shared/resolve-card-icon'
|
|
6
8
|
import { resolveCardIcon } from '../shared/resolve-card-icon'
|
|
7
9
|
import { TechTag } from '../shared/tech-tag'
|
|
8
10
|
|
|
@@ -16,9 +18,10 @@ export interface WorkspaceCardProps {
|
|
|
16
18
|
*/
|
|
17
19
|
readonly href: string
|
|
18
20
|
/**
|
|
19
|
-
* Icon config — Iconify identifier string
|
|
21
|
+
* Icon config — Iconify identifier string, `{ id, color }` object, or
|
|
22
|
+
* `{ kind: 'image', src, alt }` for a static image asset.
|
|
20
23
|
*/
|
|
21
|
-
readonly icon?:
|
|
24
|
+
readonly icon?: CardIconInput
|
|
22
25
|
/**
|
|
23
26
|
* Scope prefix shown above the name (e.g. "apps/").
|
|
24
27
|
*/
|
|
@@ -63,17 +66,12 @@ export function WorkspaceCard({
|
|
|
63
66
|
titleLines,
|
|
64
67
|
descriptionLines,
|
|
65
68
|
}: WorkspaceCardProps): React.ReactElement {
|
|
66
|
-
const name = title.toLowerCase()
|
|
67
69
|
const resolved = resolveCardIcon(icon)
|
|
68
70
|
|
|
69
71
|
const iconEl = match(resolved)
|
|
70
|
-
.with(P.nonNullable, (r) => <
|
|
72
|
+
.with(P.nonNullable, (r) => <CardIcon resolved={r} className="cp-card__icon" />)
|
|
71
73
|
.otherwise(() => null)
|
|
72
74
|
|
|
73
|
-
const iconColor = match(resolved)
|
|
74
|
-
.with(P.nonNullable, (r) => r.color)
|
|
75
|
-
.otherwise(() => 'purple')
|
|
76
|
-
|
|
77
75
|
const scopeEl = match(scope)
|
|
78
76
|
.with(
|
|
79
77
|
P.when((s): s is string => s !== undefined && s.length > 0),
|
|
@@ -95,7 +93,7 @@ export function WorkspaceCard({
|
|
|
95
93
|
className={clampClass('cp-workspace-card__desc', descriptionLines)}
|
|
96
94
|
style={clampStyle(descriptionLines)}
|
|
97
95
|
>
|
|
98
|
-
{d}
|
|
96
|
+
{renderRichText(d)}
|
|
99
97
|
</span>
|
|
100
98
|
))
|
|
101
99
|
.otherwise(() => null)
|
|
@@ -117,14 +115,14 @@ export function WorkspaceCard({
|
|
|
117
115
|
<Card href={href} className="cp-workspace-card">
|
|
118
116
|
<div className="cp-workspace-card__header">
|
|
119
117
|
<div className="cp-workspace-card__identity">
|
|
120
|
-
|
|
118
|
+
{iconEl}
|
|
121
119
|
<div className="cp-workspace-card__title">
|
|
122
120
|
{scopeEl}
|
|
123
121
|
<span
|
|
124
122
|
className={clampClass('cp-workspace-card__name', titleLines)}
|
|
125
123
|
style={clampStyle(titleLines)}
|
|
126
124
|
>
|
|
127
|
-
{
|
|
125
|
+
{renderRichText(title)}
|
|
128
126
|
</span>
|
|
129
127
|
</div>
|
|
130
128
|
</div>
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import { match, P } from 'massaman/match'
|
|
1
2
|
import type React from 'react'
|
|
2
3
|
|
|
4
|
+
import { renderRichText } from '../../lib/rich-text.tsx'
|
|
5
|
+
|
|
3
6
|
import './card.css'
|
|
4
7
|
|
|
5
8
|
export interface WorkspaceGridProps {
|
|
6
9
|
/**
|
|
7
|
-
* Section heading (e.g. "Apps", "Packages").
|
|
10
|
+
* Section heading (e.g. "Apps", "Packages"). Omitted for an ungrouped
|
|
11
|
+
* grid, such as a showcase block with an explicit `source` list.
|
|
8
12
|
*/
|
|
9
|
-
readonly heading
|
|
13
|
+
readonly heading?: string
|
|
10
14
|
/**
|
|
11
|
-
* Brief description rendered below the heading.
|
|
15
|
+
* Brief description rendered below the heading. Omitted for an
|
|
16
|
+
* ungrouped grid.
|
|
12
17
|
*/
|
|
13
|
-
readonly description
|
|
18
|
+
readonly description?: string
|
|
14
19
|
/**
|
|
15
20
|
* Number of grid columns.
|
|
16
21
|
*/
|
|
@@ -38,8 +43,15 @@ export function WorkspaceGrid({
|
|
|
38
43
|
|
|
39
44
|
return (
|
|
40
45
|
<>
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
{/* Rich text, matching the card titles and descriptions this grid
|
|
47
|
+
wraps — a group heading was the one string in the block that
|
|
48
|
+
showed its `**markers**` literally. */}
|
|
49
|
+
{match(heading)
|
|
50
|
+
.with(P.string, (h) => <h2>{renderRichText(h)}</h2>)
|
|
51
|
+
.otherwise(() => null)}
|
|
52
|
+
{match(description)
|
|
53
|
+
.with(P.string, (d) => <p className="cp-workspace-section__desc">{renderRichText(d)}</p>)
|
|
54
|
+
.otherwise(() => null)}
|
|
43
55
|
<div className="cp-workspace-grid" style={style}>
|
|
44
56
|
{children}
|
|
45
57
|
</div>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { FooterConfig, HomeConfig,
|
|
1
|
+
import type { BadgeConfig, FooterConfig, HomeConfig, SerializedIcon } from '@ciderpress/config'
|
|
2
2
|
import { useSite } from '@rspress/core/runtime'
|
|
3
3
|
|
|
4
4
|
export interface CiderpressSidebarItem {
|
|
5
5
|
readonly text?: string
|
|
6
6
|
readonly link?: string
|
|
7
|
-
readonly icon?:
|
|
7
|
+
readonly icon?: SerializedIcon
|
|
8
8
|
readonly items?: readonly CiderpressSidebarItem[]
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface CiderpressSidebarLink {
|
|
12
12
|
readonly text: string
|
|
13
13
|
readonly link: string
|
|
14
|
-
readonly icon?:
|
|
14
|
+
readonly icon?: SerializedIcon
|
|
15
15
|
readonly style?: 'brand' | 'alt' | 'ghost'
|
|
16
16
|
readonly shape?: 'square' | 'rounded' | 'circle'
|
|
17
17
|
}
|
|
@@ -19,7 +19,7 @@ export interface CiderpressSidebarLink {
|
|
|
19
19
|
export interface WorkspaceCardData {
|
|
20
20
|
readonly title: string
|
|
21
21
|
readonly href: string
|
|
22
|
-
readonly icon:
|
|
22
|
+
readonly icon: SerializedIcon | undefined
|
|
23
23
|
readonly scope: string | undefined
|
|
24
24
|
readonly description: string | undefined
|
|
25
25
|
readonly tags: readonly string[]
|
|
@@ -33,6 +33,65 @@ export interface WorkspaceGroupData {
|
|
|
33
33
|
readonly cards: readonly WorkspaceCardData[]
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Serialised view of the unified `CiderpressConfig` that the runtime
|
|
38
|
+
* theme components still read through. The `site` field is rebuilt in
|
|
39
|
+
* `packages/ui/src/config.ts` (`buildSiteBlock`) from the new top-level
|
|
40
|
+
* `editLink` / `reportLink` / `topbar` / `sidebar` / `footer` / `version`
|
|
41
|
+
* config — kept under the legacy `site.*` name so theme components don't
|
|
42
|
+
* need to be rewired to look up each field individually.
|
|
43
|
+
*/
|
|
44
|
+
export interface CiderpressSiteBlock {
|
|
45
|
+
readonly version: string | undefined
|
|
46
|
+
readonly edit:
|
|
47
|
+
| {
|
|
48
|
+
readonly repo: string
|
|
49
|
+
readonly branch?: string
|
|
50
|
+
readonly directory?: string
|
|
51
|
+
readonly label?: string
|
|
52
|
+
}
|
|
53
|
+
| undefined
|
|
54
|
+
readonly report:
|
|
55
|
+
| {
|
|
56
|
+
readonly repo: string
|
|
57
|
+
readonly branch?: string
|
|
58
|
+
readonly directory?: string
|
|
59
|
+
readonly label?: string
|
|
60
|
+
}
|
|
61
|
+
| undefined
|
|
62
|
+
readonly topbarCta: { readonly text: string; readonly href: string } | undefined
|
|
63
|
+
readonly sidebarPromo:
|
|
64
|
+
| {
|
|
65
|
+
readonly title: string
|
|
66
|
+
readonly body: string
|
|
67
|
+
readonly cta: { readonly text: string; readonly href: string }
|
|
68
|
+
}
|
|
69
|
+
| undefined
|
|
70
|
+
readonly announcement:
|
|
71
|
+
| {
|
|
72
|
+
readonly id?: string
|
|
73
|
+
readonly lead?: string
|
|
74
|
+
readonly message: string
|
|
75
|
+
readonly cta?: { readonly href: string; readonly label: string }
|
|
76
|
+
readonly persistent?: boolean
|
|
77
|
+
}
|
|
78
|
+
| undefined
|
|
79
|
+
readonly footer:
|
|
80
|
+
| {
|
|
81
|
+
readonly columns?: readonly {
|
|
82
|
+
readonly heading: string
|
|
83
|
+
readonly links: readonly { readonly text: string; readonly href: string }[]
|
|
84
|
+
}[]
|
|
85
|
+
readonly tagline?: string
|
|
86
|
+
readonly brandMark?: string
|
|
87
|
+
}
|
|
88
|
+
| undefined
|
|
89
|
+
readonly feedback: {
|
|
90
|
+
readonly enabled: boolean
|
|
91
|
+
readonly question: string | undefined
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
36
95
|
interface CiderpressThemeConfig {
|
|
37
96
|
readonly sidebar: Record<string, readonly CiderpressSidebarItem[]>
|
|
38
97
|
readonly sidebarAbove: readonly CiderpressSidebarLink[] | undefined
|
|
@@ -41,7 +100,8 @@ interface CiderpressThemeConfig {
|
|
|
41
100
|
readonly standaloneScopePaths: readonly string[] | undefined
|
|
42
101
|
readonly home: HomeConfig | undefined
|
|
43
102
|
readonly ciderpressFooter: FooterConfig | undefined
|
|
44
|
-
readonly site:
|
|
103
|
+
readonly site: CiderpressSiteBlock | undefined
|
|
104
|
+
readonly pageBadges: Record<string, readonly BadgeConfig[]> | undefined
|
|
45
105
|
}
|
|
46
106
|
|
|
47
107
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { removeBase } from '@rspress/core/runtime'
|
|
1
2
|
import { useEffect, useState } from 'react'
|
|
2
3
|
|
|
3
4
|
import type { CiderpressNavMenuItem } from '../components/nav/ciderpress-nav-menu'
|
|
@@ -41,34 +42,104 @@ export function useNavItems(): readonly CiderpressNavMenuItem[] {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Reconstruct the primary nav from Rspress's hidden `.rp-nav-menu`,
|
|
46
|
+
* preserving dropdowns. Each top-level `.rp-nav-menu__item` is either a
|
|
47
|
+
* leaf (its container is an anchor) or a dropdown parent (it wraps a
|
|
48
|
+
* `.rp-hover-group` of child links). Items with empty text, or dropdown
|
|
49
|
+
* parents with no usable children, are dropped.
|
|
47
50
|
*
|
|
48
51
|
* @private
|
|
49
52
|
* @returns Nav items currently in the DOM (empty array when not mounted).
|
|
50
53
|
*/
|
|
51
54
|
function scrapeNavItems(): readonly CiderpressNavMenuItem[] {
|
|
52
|
-
|
|
55
|
+
return navMenuRoots()
|
|
56
|
+
.map(scrapeNavItem)
|
|
57
|
+
.filter((item): item is CiderpressNavMenuItem => item !== null)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Collect the top-level `.rp-nav-menu__item` `<li>`s to scrape. Rspress
|
|
62
|
+
* renders separate left and right nav `<ul>`s; the ciderpress topbar is
|
|
63
|
+
* right-aligned, so we read the right menu and only fall back to the
|
|
64
|
+
* unscoped selector when it isn't present.
|
|
65
|
+
*
|
|
66
|
+
* @private
|
|
67
|
+
* @returns Top-level nav item elements.
|
|
68
|
+
*/
|
|
69
|
+
function navMenuRoots(): readonly HTMLElement[] {
|
|
70
|
+
const right = document.querySelectorAll<HTMLElement>('.rp-nav-menu--right > .rp-nav-menu__item')
|
|
71
|
+
if (right.length > 0) {
|
|
72
|
+
return [...right]
|
|
73
|
+
}
|
|
74
|
+
return [...document.querySelectorAll<HTMLElement>('.rp-nav-menu > .rp-nav-menu__item')]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Project a single top-level `.rp-nav-menu__item` element into a nav
|
|
79
|
+
* item, recursing one level into its `.rp-hover-group` dropdown when
|
|
80
|
+
* present.
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
* @param root - Top-level nav `<li>` element.
|
|
84
|
+
* @returns Parsed nav item, or `null` when unusable.
|
|
85
|
+
*/
|
|
86
|
+
function scrapeNavItem(root: HTMLElement): CiderpressNavMenuItem | null {
|
|
87
|
+
const container = root.querySelector(':scope > .rp-nav-menu__item__container')
|
|
88
|
+
if (container === null) {
|
|
89
|
+
return null
|
|
90
|
+
}
|
|
91
|
+
const text = readElementText(container)
|
|
92
|
+
if (text === '') {
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
const group = root.querySelector(':scope > .rp-hover-group')
|
|
96
|
+
if (group !== null) {
|
|
97
|
+
const items = scrapeGroupItems(group)
|
|
98
|
+
if (items.length === 0) {
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
return { text, items }
|
|
102
|
+
}
|
|
103
|
+
const href = container.getAttribute('href')
|
|
104
|
+
if (href === null || href === '') {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
// Un-base the scraped href so `<Link>` re-applies the site `base` once
|
|
108
|
+
// rather than doubling the mount prefix on subpath deploys.
|
|
109
|
+
return { text, link: removeBase(href) }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Read the child links out of a Rspress `.rp-hover-group` dropdown.
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
* @param group - The `.rp-hover-group` element.
|
|
117
|
+
* @returns Child nav items with text + link (empties dropped).
|
|
118
|
+
*/
|
|
119
|
+
function scrapeGroupItems(group: Element): readonly CiderpressNavMenuItem[] {
|
|
120
|
+
const anchors = group.querySelectorAll<HTMLAnchorElement>('.rp-hover-group__item__link')
|
|
53
121
|
return [...anchors]
|
|
54
122
|
.map((anchor) => ({
|
|
55
|
-
text:
|
|
56
|
-
|
|
123
|
+
text: readElementText(anchor),
|
|
124
|
+
// Rspress's rendered hrefs already include the site `base`; strip it so
|
|
125
|
+
// the consuming `<Link>` re-applies it once instead of doubling the mount
|
|
126
|
+
// prefix on subpath deploys (the `/examples/<slug>/examples/<slug>/…` 404).
|
|
127
|
+
link: removeBase(anchor.getAttribute('href') ?? ''),
|
|
57
128
|
}))
|
|
58
129
|
.filter((item) => item.text !== '' && item.link !== '')
|
|
59
130
|
}
|
|
60
131
|
|
|
61
132
|
/**
|
|
62
|
-
* Pull the trimmed text content from an
|
|
133
|
+
* Pull the trimmed text content from an element. Returns an empty
|
|
63
134
|
* string when `textContent` is missing — callers treat empty as "skip
|
|
64
|
-
* this
|
|
135
|
+
* this element".
|
|
65
136
|
*
|
|
66
137
|
* @private
|
|
67
|
-
* @param
|
|
138
|
+
* @param element - Element to read.
|
|
68
139
|
* @returns Trimmed inner text, or empty string when absent.
|
|
69
140
|
*/
|
|
70
|
-
function
|
|
71
|
-
const text =
|
|
141
|
+
function readElementText(element: Element): string {
|
|
142
|
+
const text = element.textContent
|
|
72
143
|
if (text === null) {
|
|
73
144
|
return ''
|
|
74
145
|
}
|
package/dist/theme/index.tsx
CHANGED
|
@@ -19,11 +19,11 @@ import '@rspress/core/dist/theme/components/Sidebar/SidebarDivider.css'
|
|
|
19
19
|
import '@rspress/core/dist/theme/components/Sidebar/SidebarGroup.css'
|
|
20
20
|
import '@rspress/core/dist/theme/components/Sidebar/SidebarItem.css'
|
|
21
21
|
import '@rspress/core/dist/theme/components/Sidebar/SidebarSectionHeader.css'
|
|
22
|
-
|
|
23
22
|
import './styles/layers.css'
|
|
24
23
|
import './styles/overrides/fonts.css'
|
|
25
24
|
import './styles/overrides/tokens.css'
|
|
26
25
|
import './styles/overrides/rspress.css'
|
|
26
|
+
import './styles/rich-text.css'
|
|
27
27
|
// Theme color palettes — scoped via [data-cp-theme][data-cp-variant] selectors.
|
|
28
28
|
// `mulled.css` ships first because it is `DEFAULT_THEME_NAME` — its rules emit
|
|
29
29
|
// the `:root { ... }` FOUC fallback that paints before JS hydrates the
|
|
@@ -39,6 +39,8 @@ import './styles/themes/arcade.css'
|
|
|
39
39
|
// (border trace, neon pulse, CRT scanlines, etc.) scoped to [data-cp-theme='arcade']
|
|
40
40
|
import './styles/themes/arcade-fx.css'
|
|
41
41
|
import './styles/overrides/details.css'
|
|
42
|
+
import './styles/overrides/lists.css'
|
|
43
|
+
import './styles/overrides/footnotes.css'
|
|
42
44
|
import './styles/overrides/scrollbar.css'
|
|
43
45
|
import './styles/overrides/rail.css'
|
|
44
46
|
import './styles/overrides/sidebar.css'
|
|
@@ -54,6 +56,7 @@ import './components/content-footer/feedback.css'
|
|
|
54
56
|
import './components/content-footer/meta-actions.css'
|
|
55
57
|
import './components/content-footer/page-pager.css'
|
|
56
58
|
import './components/sidebar/framework-picker.css'
|
|
59
|
+
import './components/sidebar/sidebar-badge.css'
|
|
57
60
|
import './components/sidebar/sidebar-promo.css'
|
|
58
61
|
import './components/sidebar/sidebar-toggle.css'
|
|
59
62
|
import './components/home/page-rail.css'
|
|
@@ -90,6 +93,8 @@ export { HomeFeature } from './components/home/feature'
|
|
|
90
93
|
export { HomeLayout } from './components/home/layout'
|
|
91
94
|
/** @internal Sidebar override — multi-scope filtering for standalone sections */
|
|
92
95
|
export { Sidebar } from './components/sidebar/sidebar-scope'
|
|
96
|
+
/** @internal Tag override — renders ciderpress sidebar badges, delegates other tags to Rspress */
|
|
97
|
+
export { Tag } from './components/sidebar/sidebar-badge'
|
|
93
98
|
|
|
94
99
|
export { FeatureCard, FeatureGrid } from './components/home/feature-card'
|
|
95
100
|
export type { FeatureCardProps, FeatureItem } from './components/home/feature-card'
|
|
@@ -102,6 +107,10 @@ export { TrustStrip } from './components/home/trust-strip'
|
|
|
102
107
|
export type { TrustStripProps } from './components/home/trust-strip'
|
|
103
108
|
export { HomeSplit } from './components/home/split'
|
|
104
109
|
export type { SplitProps, SplitAction } from './components/home/split'
|
|
110
|
+
export { HomeTabs } from './components/home/tabs'
|
|
111
|
+
export { RichText, renderRichText } from './lib/rich-text.tsx'
|
|
112
|
+
export { hasAccentMarker, toPlainText } from './lib/rich-text-parse.ts'
|
|
113
|
+
export type { HomeTabsProps, HomeTabEntry, TabsAction } from './components/home/tabs'
|
|
105
114
|
export { CTA } from './components/home/cta'
|
|
106
115
|
export type { CTAProps } from './components/home/cta'
|
|
107
116
|
export { WorkspaceCard } from './components/workspaces/card'
|
|
@@ -150,8 +159,6 @@ export type { StepsProps, StepProps } from './components/shared/steps'
|
|
|
150
159
|
export { Field, FieldGroup } from './components/shared/field'
|
|
151
160
|
export type { FieldProps, FieldGroupProps } from './components/shared/field'
|
|
152
161
|
|
|
153
|
-
export { CopyMarkdownButton } from './components/openapi'
|
|
154
|
-
export type { CopyMarkdownButtonProps } from './components/openapi'
|
|
155
162
|
export { OpenAPIOperation } from './components/openapi'
|
|
156
163
|
export type { OpenAPIOperationProps } from './components/openapi'
|
|
157
164
|
export { OpenAPIOverview } from './components/openapi'
|
|
@@ -2,8 +2,9 @@ import type { CiderpressSocialLink } from '../components/nav/ciderpress-nav-soci
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Pull social-link entries (GitHub, npm, etc) from Rspress's `site`
|
|
5
|
-
* shape. Lives on `site.themeConfig.socialLinks` after
|
|
6
|
-
*
|
|
5
|
+
* shape. Lives on `site.themeConfig.socialLinks` after the
|
|
6
|
+
* `packages/ui/src/config.ts` serialiser writes the unified `socials`
|
|
7
|
+
* config into the runtime theme config.
|
|
7
8
|
*
|
|
8
9
|
* @param site - Rspress site data (typically the result of `useSite().site`)
|
|
9
10
|
* @returns Array of social-link entries (empty array when not configured)
|
|
@@ -22,6 +23,6 @@ export function readSocialLinks(site: unknown): readonly CiderpressSocialLink[]
|
|
|
22
23
|
typeof item === 'object' &&
|
|
23
24
|
item !== null &&
|
|
24
25
|
typeof (item as { icon?: unknown }).icon === 'string' &&
|
|
25
|
-
typeof (item as {
|
|
26
|
+
typeof (item as { url?: unknown }).url === 'string'
|
|
26
27
|
)
|
|
27
28
|
}
|