@rimelight/ui 0.0.34 → 0.0.36
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/README.md +1 -0
- package/package.json +19 -24
- package/src/components/astro/RLAAccordion.astro +94 -18
- package/src/components/astro/RLAAvatar.astro +135 -68
- package/src/components/astro/RLABadge.astro +4 -2
- package/src/components/astro/RLABanner.astro +138 -23
- package/src/components/astro/RLABreadcrumb.astro +13 -0
- package/src/components/astro/RLAButton.astro +8 -4
- package/src/components/astro/RLACallout.astro +112 -0
- package/src/components/astro/RLACard.astro +6 -5
- package/src/components/astro/RLACarousel.astro +104 -75
- package/src/components/astro/RLAChart.astro +4 -1
- package/src/components/astro/RLAChip.astro +11 -5
- package/src/components/astro/RLACollapsible.astro +4 -1
- package/src/components/astro/RLAColorArea.astro +432 -0
- package/src/components/astro/RLAColorField.astro +300 -0
- package/src/components/astro/RLAColorSlider.astro +413 -0
- package/src/components/astro/RLAConfirm.astro +13 -11
- package/src/components/astro/RLACopyMarkdown.astro +78 -0
- package/src/components/astro/RLADate.astro +30 -0
- package/src/components/astro/RLADrawer.astro +50 -3
- package/src/components/astro/RLADropdownMenu.astro +78 -51
- package/src/components/astro/RLAFieldGroup.astro +4 -1
- package/src/components/astro/RLAFileUpload.astro +114 -100
- package/src/components/astro/RLAFooter.astro +2 -1
- package/src/components/astro/RLAFormField.astro +10 -6
- package/src/components/astro/RLAGrid.astro +31 -39
- package/src/components/astro/RLAHead.astro +139 -39
- package/src/components/astro/RLAHeader.astro +2 -1
- package/src/components/astro/RLAImage.astro +274 -251
- package/src/components/astro/RLAInput.astro +14 -9
- package/src/components/astro/RLAInputMenu.astro +119 -83
- package/src/components/astro/RLAKbd.astro +5 -5
- package/src/components/astro/RLALayoutGrid.astro +395 -0
- package/src/components/astro/RLALink.astro +23 -1
- package/src/components/astro/RLALinkGroup.astro +99 -99
- package/src/components/astro/RLALocaleSelector.astro +34 -41
- package/src/components/astro/RLALogo.astro +117 -90
- package/src/components/astro/RLAModal.astro +48 -18
- package/src/components/astro/RLANavigationMenu.astro +381 -326
- package/src/components/astro/{RLADocsPackageManagers.astro → RLAPackageManagers.astro} +81 -87
- package/src/components/astro/RLAPageSection.astro +4 -2
- package/src/components/astro/RLAPopover.astro +4 -3
- package/src/components/astro/RLAPost.astro +11 -2
- package/src/components/astro/RLAScrollArea.astro +4 -1
- package/src/components/astro/RLAScrollToTop.astro +200 -172
- package/src/components/astro/RLASearch.astro +282 -0
- package/src/components/astro/RLASelect.astro +78 -55
- package/src/components/astro/RLASeparator.astro +11 -6
- package/src/components/astro/RLAShare.astro +60 -0
- package/src/components/astro/RLAShortcuts.astro +429 -0
- package/src/components/astro/RLASidebar.astro +158 -212
- package/src/components/astro/RLASlideover.astro +47 -17
- package/src/components/astro/RLASplitter.astro +194 -141
- package/src/components/astro/RLASteps.astro +118 -71
- package/src/components/astro/RLASurround.astro +39 -0
- package/src/components/astro/RLATable.astro +4 -1
- package/src/components/astro/RLATableOfContents.astro +109 -23
- package/src/components/astro/RLATabs.astro +147 -133
- package/src/components/astro/RLATextarea.astro +4 -1
- package/src/components/astro/RLAThemeSelector.astro +105 -76
- package/src/components/astro/RLAToast.astro +35 -21
- package/src/components/vue/RLVBanner.vue +230 -0
- package/src/components/vue/RLVButton.vue +3 -2
- package/src/components/vue/RLVCheckbox.vue +4 -2
- package/src/components/vue/RLVFooter.vue +3 -2
- package/src/components/vue/RLVHeader.vue +3 -2
- package/src/components/vue/RLVIcon.vue +4 -2
- package/src/components/vue/RLVInput.vue +5 -4
- package/src/components/vue/RLVLogo.vue +25 -3
- package/src/components/vue/RLVPlaceholder.vue +3 -2
- package/src/components/vue/RLVPost.vue +8 -2
- package/src/components/vue/RLVProgress.vue +60 -0
- package/src/components/vue/RLVScrollToTop.vue +65 -52
- package/src/components/vue/RLVSection.vue +14 -13
- package/src/components/vue/RLVToast.vue +17 -4
- package/src/composables/index.ts +1 -0
- package/src/composables/useHeaderStore.ts +1 -0
- package/src/composables/useShortcuts.ts +11 -0
- package/src/config/security.ts +43 -36
- package/src/config/site.config.ts +1 -0
- package/src/docs/components/ApiChangelog.astro +147 -0
- package/src/{plugins/starlightDocsApi → docs}/components/ApiEmits.astro +4 -4
- package/src/{plugins/starlightDocsApi → docs}/components/ApiProps.astro +4 -4
- package/src/{plugins/starlightDocsApi → docs}/components/ApiSlots.astro +4 -4
- package/src/docs/components/ApiTheme.astro +100 -0
- package/src/docs/extractAll.ts +94 -0
- package/src/docs/extractors/extractAstro.ts +69 -0
- package/src/docs/extractors/extractTheme.ts +56 -0
- package/src/{plugins/starlightDocsApi/extract-vue.ts → docs/extractors/extractVue.ts} +164 -15
- package/src/{plugins/starlightDocsApi → docs}/utils.ts +1 -2
- package/src/env.d.ts +0 -12
- package/src/integrations/ui.ts +35 -19
- package/src/middleware/security.ts +75 -19
- package/src/presets/index.ts +118 -293
- package/src/styles/index.css +0 -2
- package/src/themes/accordion.theme.ts +29 -3
- package/src/themes/aspect-ratio.theme.ts +1 -1
- package/src/themes/avatar-group.theme.ts +1 -1
- package/src/themes/avatar.theme.ts +2 -2
- package/src/themes/badge.theme.ts +2 -3
- package/src/themes/banner.theme.ts +40 -4
- package/src/themes/breadcrumb.theme.ts +1 -1
- package/src/themes/button.theme.ts +21 -22
- package/src/themes/{alert.theme.ts → callout.theme.ts} +12 -39
- package/src/themes/card.theme.ts +17 -9
- package/src/themes/carousel.theme.ts +1 -1
- package/src/themes/checkbox.theme.ts +1 -2
- package/src/themes/chip.theme.ts +2 -3
- package/src/themes/color-area.theme.ts +33 -0
- package/src/themes/color-field.theme.ts +32 -0
- package/src/themes/color-slider.theme.ts +34 -0
- package/src/themes/confirm.theme.ts +1 -1
- package/src/themes/container.theme.ts +1 -1
- package/src/themes/drawer.theme.ts +1 -1
- package/src/themes/footer.theme.ts +2 -2
- package/src/themes/grid.theme.ts +38 -0
- package/src/themes/header.theme.ts +4 -3
- package/src/themes/hover-card.theme.ts +1 -1
- package/src/themes/image.theme.ts +11 -1
- package/src/themes/input.theme.ts +7 -1
- package/src/themes/kbd.theme.ts +2 -3
- package/src/themes/label.theme.ts +1 -1
- package/src/themes/layout-grid.theme.ts +16 -0
- package/src/themes/link-group.theme.ts +0 -4
- package/src/themes/marquee.theme.ts +1 -1
- package/src/themes/modal.theme.ts +1 -1
- package/src/themes/navigation-menu.theme.ts +2 -2
- package/src/themes/page-section.theme.ts +4 -2
- package/src/themes/pagination.theme.ts +1 -1
- package/src/themes/pin-input.theme.ts +1 -1
- package/src/themes/popover.theme.ts +1 -1
- package/src/themes/post.theme.ts +23 -3
- package/src/themes/progress.theme.ts +1 -2
- package/src/themes/scroll-to-top.theme.ts +2 -3
- package/src/themes/search.theme.ts +64 -0
- package/src/themes/separator.theme.ts +1 -1
- package/src/themes/slideover.theme.ts +1 -1
- package/src/themes/slider.theme.ts +1 -2
- package/src/themes/spinner.theme.ts +1 -2
- package/src/themes/{megamenu.theme.ts → steps.theme.ts} +3 -3
- package/src/themes/sticky-surface.theme.ts +1 -1
- package/src/themes/switch.theme.ts +1 -2
- package/src/themes/table-of-contents.theme.ts +21 -2
- package/src/themes/timeline.theme.ts +7 -2
- package/src/themes/toast.theme.ts +1 -1
- package/src/types/components/accordion.ts +35 -2
- package/src/types/components/avatar.ts +16 -0
- package/src/types/components/banner.ts +42 -0
- package/src/types/components/button.ts +3 -4
- package/src/types/components/{alert.ts → callout.ts} +6 -6
- package/src/types/components/color-area.ts +19 -0
- package/src/types/components/color-field.ts +21 -0
- package/src/types/components/color-slider.ts +20 -0
- package/src/types/components/grid.ts +23 -0
- package/src/types/components/input.ts +4 -0
- package/src/types/components/layout-grid.ts +145 -0
- package/src/types/components/link-group.ts +4 -2
- package/src/types/components/link.ts +15 -0
- package/src/types/components/logo.ts +3 -3
- package/src/types/components/post.ts +12 -0
- package/src/types/components/search.ts +29 -0
- package/src/types/components/sidebar.ts +2 -6
- package/src/types/components/{megamenu.ts → steps.ts} +7 -1
- package/src/types/components/table-of-contents.ts +22 -0
- package/src/types/components/toast.ts +4 -0
- package/src/types/docs.ts +40 -0
- package/src/types/index.ts +151 -1
- package/src/types/theme.ts +6 -6
- package/src/utils/color.ts +165 -0
- package/src/utils/docs.ts +260 -110
- package/src/utils/headerStack.ts +24 -4
- package/src/utils/index.ts +2 -0
- package/src/utils/shortcuts.ts +322 -0
- package/src/components/TableOfContents.astro +0 -107
- package/src/components/astro/RLAAlert.astro +0 -93
- package/src/components/astro/RLAChangelog.astro +0 -23
- package/src/components/astro/RLAMegamenu.astro +0 -23
- package/src/plugins/index.ts +0 -2
- package/src/plugins/starlightDocsApi/components/ApiTheme.astro +0 -27
- package/src/plugins/starlightDocsApi/index.ts +0 -272
- package/src/styles/prism.css +0 -42
- package/src/themes/changelog.theme.ts +0 -13
- package/src/types/components/index.ts +0 -134
- /package/src/{plugins/starlightDocsApi → docs}/types.ts +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
export function hexToRgb(hex: string): [number, number, number] {
|
|
2
|
+
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
|
|
3
|
+
const fullHex = hex.replace(shorthandRegex, (_, r, g, b) => r + r + g + g + b + b)
|
|
4
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(fullHex)
|
|
5
|
+
return result
|
|
6
|
+
? [parseInt(result[1]!, 16), parseInt(result[2]!, 16), parseInt(result[3]!, 16)]
|
|
7
|
+
: [0, 0, 0]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function toHex(c: number): string {
|
|
11
|
+
const hex = Math.max(0, Math.min(255, c)).toString(16)
|
|
12
|
+
return hex.length === 1 ? "0" + hex : hex
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function rgbToHex(r: number, g: number, b: number): string {
|
|
16
|
+
return "#" + toHex(r) + toHex(g) + toHex(b)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function rgbToHsl(r: number, g: number, b: number): [number, number, number] {
|
|
20
|
+
r /= 255
|
|
21
|
+
g /= 255
|
|
22
|
+
b /= 255
|
|
23
|
+
const max = Math.max(r, g, b),
|
|
24
|
+
min = Math.min(r, g, b)
|
|
25
|
+
let h = 0,
|
|
26
|
+
s = 0,
|
|
27
|
+
l = (max + min) / 2
|
|
28
|
+
if (max !== min) {
|
|
29
|
+
const d = max - min
|
|
30
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
|
31
|
+
switch (max) {
|
|
32
|
+
case r:
|
|
33
|
+
h = (g - b) / d + (g < b ? 6 : 0)
|
|
34
|
+
break
|
|
35
|
+
case g:
|
|
36
|
+
h = (b - r) / d + 2
|
|
37
|
+
break
|
|
38
|
+
case b:
|
|
39
|
+
h = (r - g) / d + 4
|
|
40
|
+
break
|
|
41
|
+
}
|
|
42
|
+
h /= 6
|
|
43
|
+
}
|
|
44
|
+
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function hue2rgb(p: number, q: number, t: number): number {
|
|
48
|
+
if (t < 0) t += 1
|
|
49
|
+
if (t > 1) t -= 1
|
|
50
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t
|
|
51
|
+
if (t < 1 / 2) return q
|
|
52
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
|
|
53
|
+
return p
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function hslToRgb(h: number, s: number, l: number): [number, number, number] {
|
|
57
|
+
h /= 360
|
|
58
|
+
s /= 100
|
|
59
|
+
l /= 100
|
|
60
|
+
let r = l,
|
|
61
|
+
g = l,
|
|
62
|
+
b = l
|
|
63
|
+
if (s !== 0) {
|
|
64
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
|
65
|
+
const p = 2 * l - q
|
|
66
|
+
r = hue2rgb(p, q, h + 1 / 3)
|
|
67
|
+
g = hue2rgb(p, q, h)
|
|
68
|
+
b = hue2rgb(p, q, h - 1 / 3)
|
|
69
|
+
}
|
|
70
|
+
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function rgbToHsb(r: number, g: number, b: number): [number, number, number] {
|
|
74
|
+
r /= 255
|
|
75
|
+
g /= 255
|
|
76
|
+
b /= 255
|
|
77
|
+
const max = Math.max(r, g, b),
|
|
78
|
+
min = Math.min(r, g, b)
|
|
79
|
+
let h = 0,
|
|
80
|
+
s = 0,
|
|
81
|
+
v = max
|
|
82
|
+
const d = max - min
|
|
83
|
+
s = max === 0 ? 0 : d / max
|
|
84
|
+
if (max !== min) {
|
|
85
|
+
switch (max) {
|
|
86
|
+
case r:
|
|
87
|
+
h = (g - b) / d + (g < b ? 6 : 0)
|
|
88
|
+
break
|
|
89
|
+
case g:
|
|
90
|
+
h = (b - r) / d + 2
|
|
91
|
+
break
|
|
92
|
+
case b:
|
|
93
|
+
h = (r - g) / d + 4
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
h /= 6
|
|
97
|
+
}
|
|
98
|
+
return [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function hsbToRgb(h: number, s: number, b: number): [number, number, number] {
|
|
102
|
+
h /= 360
|
|
103
|
+
s /= 100
|
|
104
|
+
b /= 100
|
|
105
|
+
let r = 0,
|
|
106
|
+
g = 0,
|
|
107
|
+
bl = 0
|
|
108
|
+
const i = Math.floor(h * 6)
|
|
109
|
+
const f = h * 6 - i
|
|
110
|
+
const p = b * (1 - s)
|
|
111
|
+
const q = b * (1 - f * s)
|
|
112
|
+
const t = b * (1 - (1 - f) * s)
|
|
113
|
+
switch (i % 6) {
|
|
114
|
+
case 0:
|
|
115
|
+
r = b
|
|
116
|
+
g = t
|
|
117
|
+
bl = p
|
|
118
|
+
break
|
|
119
|
+
case 1:
|
|
120
|
+
r = q
|
|
121
|
+
g = b
|
|
122
|
+
bl = p
|
|
123
|
+
break
|
|
124
|
+
case 2:
|
|
125
|
+
r = p
|
|
126
|
+
g = b
|
|
127
|
+
bl = t
|
|
128
|
+
break
|
|
129
|
+
case 3:
|
|
130
|
+
r = p
|
|
131
|
+
g = q
|
|
132
|
+
bl = b
|
|
133
|
+
break
|
|
134
|
+
case 4:
|
|
135
|
+
r = t
|
|
136
|
+
g = p
|
|
137
|
+
bl = b
|
|
138
|
+
break
|
|
139
|
+
case 5:
|
|
140
|
+
r = b
|
|
141
|
+
g = p
|
|
142
|
+
bl = q
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
return [Math.round(r * 255), Math.round(g * 255), Math.round(bl * 255)]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function getChannelRange(channel: string): { min: number; max: number } {
|
|
149
|
+
switch (channel) {
|
|
150
|
+
case "hue":
|
|
151
|
+
return { min: 0, max: 360 }
|
|
152
|
+
case "alpha":
|
|
153
|
+
return { min: 0, max: 100 }
|
|
154
|
+
case "red":
|
|
155
|
+
case "green":
|
|
156
|
+
case "blue":
|
|
157
|
+
return { min: 0, max: 255 }
|
|
158
|
+
default:
|
|
159
|
+
return { min: 0, max: 100 }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function clamp(val: number, min: number, max: number): number {
|
|
164
|
+
return Math.max(min, Math.min(max, val))
|
|
165
|
+
}
|
package/src/utils/docs.ts
CHANGED
|
@@ -1,116 +1,252 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
DocsConfig,
|
|
3
|
+
BadgeConfig,
|
|
4
|
+
PropMeta,
|
|
5
|
+
ThemeMeta,
|
|
6
|
+
SidebarItem,
|
|
7
|
+
SidebarScope
|
|
8
|
+
} from "../types"
|
|
2
9
|
|
|
3
10
|
export function defineDocsConfig(config: DocsConfig): DocsConfig {
|
|
4
11
|
return config
|
|
5
12
|
}
|
|
6
13
|
|
|
7
|
-
/**
|
|
8
|
-
* Strip a leading numeric sort prefix from a filename id, e.g. "01.getting-started" →
|
|
9
|
-
* "getting-started"
|
|
10
|
-
*/
|
|
11
|
-
function stripNumericPrefix(id: string): string {
|
|
12
|
-
return id.replace(/^(\d+\.)+/, "")
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Extract a numeric sort key from a doc id for numeric-prefix sorting
|
|
17
|
-
*/
|
|
18
|
-
function numericPrefixOrder(id: string): number {
|
|
19
|
-
const segment = id.split("/").pop() ?? id
|
|
20
|
-
const m = segment.match(/^(\d+)\./)
|
|
21
|
-
return m ? parseInt(m[1], 10) : Infinity
|
|
22
|
-
}
|
|
23
|
-
|
|
24
14
|
export interface ResolvedSidebarItem {
|
|
25
15
|
label: string
|
|
26
|
-
href?: string
|
|
27
|
-
icon?: string
|
|
28
|
-
badge?: string | BadgeConfig
|
|
29
|
-
active?: boolean
|
|
30
|
-
children?: ResolvedSidebarItem[]
|
|
31
|
-
collapsed?: boolean
|
|
16
|
+
href?: string | undefined
|
|
17
|
+
icon?: string | undefined
|
|
18
|
+
badge?: string | BadgeConfig | undefined
|
|
19
|
+
active?: boolean | undefined
|
|
20
|
+
children?: ResolvedSidebarItem[] | undefined
|
|
21
|
+
collapsed?: boolean | undefined
|
|
32
22
|
}
|
|
33
23
|
|
|
34
24
|
export interface ResolvedScope {
|
|
35
25
|
id: string
|
|
36
26
|
label: string
|
|
37
27
|
href: string
|
|
38
|
-
icon?: string
|
|
39
|
-
active?: boolean
|
|
28
|
+
icon?: string | undefined
|
|
29
|
+
active?: boolean | undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatDocsUrl(
|
|
33
|
+
href: string,
|
|
34
|
+
locale: string,
|
|
35
|
+
activeVersion?: string,
|
|
36
|
+
includeVersionInUrl?: boolean
|
|
37
|
+
): string {
|
|
38
|
+
let url = href.replace("{locale}", locale)
|
|
39
|
+
if (activeVersion && includeVersionInUrl) {
|
|
40
|
+
if (url.includes(`/${activeVersion}/`) || url.endsWith(`/${activeVersion}`)) {
|
|
41
|
+
return url
|
|
42
|
+
}
|
|
43
|
+
const docsPattern = new RegExp(`(/${locale}/docs)(/|$)`)
|
|
44
|
+
const companyDocsPattern = new RegExp(`(/${locale}/company/docs)(/|$)`)
|
|
45
|
+
|
|
46
|
+
if (companyDocsPattern.test(url)) {
|
|
47
|
+
url = url.replace(companyDocsPattern, `$1/${activeVersion}$2`)
|
|
48
|
+
} else if (docsPattern.test(url)) {
|
|
49
|
+
url = url.replace(docsPattern, `$1/${activeVersion}$2`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
url = url.replace(/\/{2,}/g, "/")
|
|
53
|
+
}
|
|
54
|
+
return url
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface DocEntry {
|
|
58
|
+
id: string
|
|
59
|
+
[key: string]: any
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getDocsVersions(entries: DocEntry[], locale: string): string[] {
|
|
63
|
+
const versions = new Set<string>()
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const id = entry.id.replace(/\\/g, "/")
|
|
66
|
+
const parts = id.split("/")
|
|
67
|
+
// File structure is: [version]/[locale]/[...slug]
|
|
68
|
+
if (parts[1] === locale && parts[0]?.startsWith("v")) {
|
|
69
|
+
versions.add(parts[0])
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return Array.from(versions).toSorted((a, b) => {
|
|
73
|
+
return b.localeCompare(a, undefined, { numeric: true, sensitivity: "base" })
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function parseDocsSlug(slug: string | undefined, versions: string[]) {
|
|
78
|
+
if (versions.length === 0) {
|
|
79
|
+
return {
|
|
80
|
+
activeVersion: "",
|
|
81
|
+
contentPath: slug || "index",
|
|
82
|
+
includeVersionInUrl: false
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const defaultVersion = versions[0]
|
|
87
|
+
const isMultiVersion = versions.length > 1
|
|
88
|
+
|
|
89
|
+
if (!slug) {
|
|
90
|
+
return {
|
|
91
|
+
activeVersion: defaultVersion,
|
|
92
|
+
contentPath: "index",
|
|
93
|
+
includeVersionInUrl: isMultiVersion
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const parts = slug.split("/")
|
|
98
|
+
const firstPart = parts[0]
|
|
99
|
+
|
|
100
|
+
if (firstPart && versions.includes(firstPart)) {
|
|
101
|
+
return {
|
|
102
|
+
activeVersion: firstPart,
|
|
103
|
+
contentPath: parts.slice(1).join("/") || "index",
|
|
104
|
+
includeVersionInUrl: isMultiVersion
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
activeVersion: defaultVersion,
|
|
110
|
+
contentPath: slug || "index",
|
|
111
|
+
includeVersionInUrl: isMultiVersion
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function findFirstHref(
|
|
116
|
+
items: SidebarItem[],
|
|
117
|
+
locale: string,
|
|
118
|
+
activeVersion?: string,
|
|
119
|
+
includeVersionInUrl?: boolean
|
|
120
|
+
): string | undefined {
|
|
121
|
+
for (const item of items) {
|
|
122
|
+
if (item.href) return formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
123
|
+
const childItems = item.children || item.items
|
|
124
|
+
if (childItems) {
|
|
125
|
+
const found = findFirstHref(childItems, locale, activeVersion, includeVersionInUrl)
|
|
126
|
+
if (found) return found
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return undefined
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getScopePrefix(
|
|
133
|
+
items: SidebarItem[],
|
|
134
|
+
locale: string,
|
|
135
|
+
activeVersion?: string,
|
|
136
|
+
includeVersionInUrl?: boolean
|
|
137
|
+
): string {
|
|
138
|
+
const allHrefs: string[] = []
|
|
139
|
+
|
|
140
|
+
function collect(item: SidebarItem) {
|
|
141
|
+
if (item.href)
|
|
142
|
+
allHrefs.push(formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl))
|
|
143
|
+
const childItems = item.children || item.items
|
|
144
|
+
if (childItems) childItems.forEach(collect)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
items.forEach(collect)
|
|
148
|
+
if (allHrefs.length === 0) return ""
|
|
149
|
+
|
|
150
|
+
const parts = allHrefs.map((h) => h.split("/").filter(Boolean))
|
|
151
|
+
let commonLen = 0
|
|
152
|
+
const firstPart = parts[0]
|
|
153
|
+
if (!firstPart) return ""
|
|
154
|
+
for (let i = 0; i < firstPart.length; i++) {
|
|
155
|
+
if (parts.every((p) => p[i] === firstPart[i])) commonLen++
|
|
156
|
+
else break
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return "/" + firstPart.slice(0, commonLen).join("/") + "/"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function hasPath(
|
|
163
|
+
items: SidebarItem[],
|
|
164
|
+
locale: string,
|
|
165
|
+
normPath: string,
|
|
166
|
+
activeVersion?: string,
|
|
167
|
+
includeVersionInUrl?: boolean
|
|
168
|
+
): boolean {
|
|
169
|
+
for (const item of items) {
|
|
170
|
+
if (
|
|
171
|
+
item.href &&
|
|
172
|
+
formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
173
|
+
.replace(/\/$/, "")
|
|
174
|
+
.toLowerCase() === normPath
|
|
175
|
+
) {
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
const childItems = item.children || item.items
|
|
179
|
+
if (childItems && hasPath(childItems, locale, normPath, activeVersion, includeVersionInUrl)) {
|
|
180
|
+
return true
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false
|
|
40
184
|
}
|
|
41
185
|
|
|
42
186
|
export async function getDocsSidebar(
|
|
43
187
|
config: DocsConfig,
|
|
44
188
|
locale: string,
|
|
45
189
|
currentPath: string,
|
|
46
|
-
|
|
190
|
+
activeVersion?: string,
|
|
191
|
+
includeVersionInUrl?: boolean
|
|
47
192
|
): Promise<{
|
|
48
193
|
items: ResolvedSidebarItem[]
|
|
49
194
|
scopes: ResolvedScope[]
|
|
50
|
-
activeScope?: ResolvedScope
|
|
195
|
+
activeScope?: ResolvedScope | undefined
|
|
51
196
|
}> {
|
|
52
|
-
const docs = await getCollection("docs")
|
|
53
197
|
const normPath = currentPath.replace(/\/$/, "").toLowerCase()
|
|
54
|
-
const docsBase = `/${locale}/docs`
|
|
55
198
|
|
|
56
|
-
const sidebarScopes:
|
|
57
|
-
? config.sidebar.filter(
|
|
58
|
-
|
|
59
|
-
)
|
|
60
|
-
: (config.sidebar as any)?.scopes || []
|
|
199
|
+
const sidebarScopes: SidebarScope[] = Array.isArray(config.sidebar)
|
|
200
|
+
? config.sidebar.filter((item): item is SidebarScope => "id" in item || "scopes" in item)
|
|
201
|
+
: config.sidebar.scopes || []
|
|
61
202
|
|
|
62
203
|
const scopes: ResolvedScope[] = sidebarScopes.map((scope) => {
|
|
63
204
|
const id = scope.id || scope.label
|
|
64
205
|
let href = scope.href || ""
|
|
65
206
|
if (!href && scope.items && scope.items.length > 0) {
|
|
66
|
-
href = scope.items
|
|
207
|
+
href = findFirstHref(scope.items, locale, activeVersion, includeVersionInUrl) || ""
|
|
67
208
|
}
|
|
68
209
|
return {
|
|
69
210
|
id,
|
|
70
211
|
label: scope.label,
|
|
71
|
-
href: href
|
|
212
|
+
href: formatDocsUrl(href, locale, activeVersion, includeVersionInUrl),
|
|
72
213
|
icon: scope.icon
|
|
73
214
|
}
|
|
74
215
|
})
|
|
75
216
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
): boolean {
|
|
81
|
-
for (const item of items) {
|
|
82
|
-
if (item.href && item.href.toLowerCase().replace(/\/$/, "") === href) return true
|
|
83
|
-
if (item.autogenerate && docId) {
|
|
84
|
-
const dir = item.autogenerate.directory.replace(/\/$/, "")
|
|
85
|
-
if (dir === "") {
|
|
86
|
-
if (!docId.includes("/")) return true
|
|
87
|
-
} else if (docId.startsWith(dir + "/") || docId === dir) {
|
|
88
|
-
return true
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const childItems = item.children || item.items
|
|
92
|
-
if (childItems && isDocInItems(childItems, docId, href)) return true
|
|
93
|
-
}
|
|
94
|
-
return false
|
|
95
|
-
}
|
|
217
|
+
// Compute scope prefixes for active detection (separate from clickable hrefs)
|
|
218
|
+
const scopePrefixes: string[] = sidebarScopes.map((scope) =>
|
|
219
|
+
scope.items ? getScopePrefix(scope.items, locale, activeVersion, includeVersionInUrl) : ""
|
|
220
|
+
)
|
|
96
221
|
|
|
97
|
-
// Find active scope — most-specific prefix match, fallback to scanning scope items
|
|
98
222
|
let activeScope = scopes.find((s) => normPath === s.href.replace(/\/$/, "").toLowerCase())
|
|
99
223
|
if (!activeScope) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
224
|
+
for (let i = 0; i < sidebarScopes.length; i++) {
|
|
225
|
+
const scope = sidebarScopes[i]
|
|
226
|
+
if (
|
|
227
|
+
scope &&
|
|
228
|
+
scope.items &&
|
|
229
|
+
hasPath(scope.items, locale, normPath, activeVersion, includeVersionInUrl)
|
|
230
|
+
) {
|
|
231
|
+
activeScope = scopes[i]
|
|
232
|
+
break
|
|
233
|
+
}
|
|
108
234
|
}
|
|
109
235
|
}
|
|
110
236
|
if (!activeScope) {
|
|
111
|
-
|
|
112
|
-
.
|
|
113
|
-
.
|
|
237
|
+
const sorted = [...scopePrefixes.entries()]
|
|
238
|
+
.filter(([, p]) => p)
|
|
239
|
+
.toSorted(([, a], [, b]) => b.length - a.length)
|
|
240
|
+
for (const [i] of sorted) {
|
|
241
|
+
const prefix = scopePrefixes[i]
|
|
242
|
+
if (prefix && normPath.startsWith(prefix.toLowerCase())) {
|
|
243
|
+
activeScope = scopes[i]
|
|
244
|
+
break
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (!activeScope && scopes.length > 0) {
|
|
249
|
+
activeScope = scopes[0]
|
|
114
250
|
}
|
|
115
251
|
if (activeScope) activeScope.active = true
|
|
116
252
|
|
|
@@ -120,44 +256,12 @@ export async function getDocsSidebar(
|
|
|
120
256
|
|
|
121
257
|
const items = sidebarConfig?.items || []
|
|
122
258
|
|
|
123
|
-
async function resolveItem(item:
|
|
124
|
-
if (item.autogenerate) {
|
|
125
|
-
const dir = item.autogenerate.directory
|
|
126
|
-
// Match docs whose id starts with the directory
|
|
127
|
-
const prefix = dir.replace(/\/$/, "")
|
|
128
|
-
const filteredDocs = docs.filter((d) => {
|
|
129
|
-
if (d.data.sidebar?.hidden === true) return false
|
|
130
|
-
if (prefix === "") return !d.id.includes("/")
|
|
131
|
-
return d.id.startsWith(prefix + "/") || d.id === prefix
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
filteredDocs.sort((a, b) => {
|
|
135
|
-
// 1. Frontmatter `order` takes priority
|
|
136
|
-
const aOrder = a.data.sidebar?.order ?? a.data.order ?? numericPrefixOrder(a.id)
|
|
137
|
-
const bOrder = b.data.sidebar?.order ?? b.data.order ?? numericPrefixOrder(b.id)
|
|
138
|
-
if (aOrder !== bOrder) return aOrder - bOrder
|
|
139
|
-
// 2. Fall back to alphabetical by stripped label
|
|
140
|
-
const aLabel = a.data.sidebar?.label ?? a.data.title
|
|
141
|
-
const bLabel = b.data.sidebar?.label ?? b.data.title
|
|
142
|
-
return stripNumericPrefix(aLabel).localeCompare(stripNumericPrefix(bLabel))
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
return filteredDocs.map((doc) => {
|
|
146
|
-
const href = `${docsBase}/${doc.id}/`
|
|
147
|
-
const badge =
|
|
148
|
-
doc.data.sidebar?.badge ?? (doc.data.badge as string | BadgeConfig | undefined)
|
|
149
|
-
return {
|
|
150
|
-
label: doc.data.sidebar?.label ?? doc.data.title,
|
|
151
|
-
href,
|
|
152
|
-
badge,
|
|
153
|
-
active: normPath === href.replace(/\/$/, "").toLowerCase()
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
|
|
259
|
+
async function resolveItem(item: SidebarItem): Promise<ResolvedSidebarItem[]> {
|
|
158
260
|
const resolved: ResolvedSidebarItem = {
|
|
159
|
-
label: item.label,
|
|
160
|
-
href: item.href
|
|
261
|
+
label: item.label || "",
|
|
262
|
+
href: item.href
|
|
263
|
+
? formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
264
|
+
: undefined,
|
|
161
265
|
icon: item.icon,
|
|
162
266
|
badge: item.badge,
|
|
163
267
|
collapsed: item.collapsed
|
|
@@ -170,8 +274,9 @@ export async function getDocsSidebar(
|
|
|
170
274
|
const childItems = item.children || item.items
|
|
171
275
|
if (childItems) {
|
|
172
276
|
const children: ResolvedSidebarItem[] = []
|
|
173
|
-
|
|
174
|
-
|
|
277
|
+
const resolvedChildren = await Promise.all(childItems.map((child) => resolveItem(child)))
|
|
278
|
+
for (const res of resolvedChildren) {
|
|
279
|
+
children.push(...res)
|
|
175
280
|
}
|
|
176
281
|
resolved.children = children
|
|
177
282
|
if (!resolved.active) {
|
|
@@ -183,8 +288,9 @@ export async function getDocsSidebar(
|
|
|
183
288
|
}
|
|
184
289
|
|
|
185
290
|
const resolvedItems: ResolvedSidebarItem[] = []
|
|
186
|
-
|
|
187
|
-
|
|
291
|
+
const resolvedAllItems = await Promise.all(items.map((item) => resolveItem(item)))
|
|
292
|
+
for (const res of resolvedAllItems) {
|
|
293
|
+
resolvedItems.push(...res)
|
|
188
294
|
}
|
|
189
295
|
|
|
190
296
|
return { items: resolvedItems, scopes, activeScope }
|
|
@@ -213,3 +319,47 @@ export function getSurroundItems(sidebar: ResolvedSidebarItem[], currentPath: st
|
|
|
213
319
|
currentIndex >= 0 && currentIndex < flatItems.length - 1 ? flatItems[currentIndex + 1] : null
|
|
214
320
|
}
|
|
215
321
|
}
|
|
322
|
+
|
|
323
|
+
export function kebabToPascal(name: string): string {
|
|
324
|
+
return name
|
|
325
|
+
.split("-")
|
|
326
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
327
|
+
.join("")
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export function filterProps(
|
|
331
|
+
props: PropMeta[],
|
|
332
|
+
options: { hide?: string[]; show?: string[] }
|
|
333
|
+
): PropMeta[] {
|
|
334
|
+
if (options.show?.length) {
|
|
335
|
+
return props.filter((p) => options.show!.includes(p.name))
|
|
336
|
+
}
|
|
337
|
+
if (options.hide?.length) {
|
|
338
|
+
return props.filter((p) => !options.hide!.includes(p.name))
|
|
339
|
+
}
|
|
340
|
+
return props
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function generateThemeCode(componentName: string, theme: ThemeMeta): string {
|
|
344
|
+
const componentConfig: Record<string, unknown> = {
|
|
345
|
+
...(theme.slots.length ? { slots: theme.slots } : {}),
|
|
346
|
+
...(Object.keys(theme.base).length ? { base: theme.base } : {}),
|
|
347
|
+
...(Object.keys(theme.variants).length ? { variants: theme.variants } : {}),
|
|
348
|
+
...(theme.compoundVariants.length ? { compoundVariants: theme.compoundVariants } : {}),
|
|
349
|
+
...(Object.keys(theme.defaultVariants).length ? { defaultVariants: theme.defaultVariants } : {})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return `// astro.config.ts
|
|
353
|
+
import { ui } from "@rimelight/ui"
|
|
354
|
+
import { defineConfig } from "astro/config"
|
|
355
|
+
|
|
356
|
+
export default defineConfig({
|
|
357
|
+
integrations: [
|
|
358
|
+
ui({
|
|
359
|
+
components: {
|
|
360
|
+
${componentName}: ${JSON.stringify(componentConfig, null, 6).replace(/\n/g, "\n ")}
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
]
|
|
364
|
+
})`
|
|
365
|
+
}
|
package/src/utils/headerStack.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface HeaderLayer {
|
|
2
2
|
id: string
|
|
3
|
+
type: "banner" | "header"
|
|
3
4
|
order: number
|
|
4
5
|
naturalHeight: number
|
|
5
6
|
isVisible: boolean
|
|
@@ -13,7 +14,8 @@ export interface HeaderStackManager {
|
|
|
13
14
|
order: number,
|
|
14
15
|
naturalHeight: number,
|
|
15
16
|
isVisible: boolean,
|
|
16
|
-
el: HTMLElement | null
|
|
17
|
+
el: HTMLElement | null,
|
|
18
|
+
type?: "banner" | "header"
|
|
17
19
|
) => void
|
|
18
20
|
unregister: (id: string) => void
|
|
19
21
|
update: () => void
|
|
@@ -49,13 +51,18 @@ export function getHeaderStack(): HeaderStackManager {
|
|
|
49
51
|
order: number,
|
|
50
52
|
naturalHeight: number,
|
|
51
53
|
isVisible: boolean,
|
|
52
|
-
el: HTMLElement | null
|
|
54
|
+
el: HTMLElement | null,
|
|
55
|
+
type: "banner" | "header" = "header"
|
|
53
56
|
) {
|
|
57
|
+
if (el && !el.isConnected) return
|
|
54
58
|
let layer = this.layers.find((l: HeaderLayer) => l.id === id)
|
|
55
59
|
if (!layer) {
|
|
56
|
-
layer = { id, order, naturalHeight, isVisible, el }
|
|
60
|
+
layer = { id, type, order, naturalHeight, isVisible, el }
|
|
57
61
|
this.layers.push(layer)
|
|
58
|
-
this.layers.sort((a: HeaderLayer, b: HeaderLayer) =>
|
|
62
|
+
this.layers.sort((a: HeaderLayer, b: HeaderLayer) => {
|
|
63
|
+
if (a.type !== b.type) return a.type === "banner" ? -1 : 1
|
|
64
|
+
return a.order - b.order
|
|
65
|
+
})
|
|
59
66
|
} else {
|
|
60
67
|
layer.naturalHeight = naturalHeight
|
|
61
68
|
layer.isVisible = isVisible
|
|
@@ -64,6 +71,19 @@ export function getHeaderStack(): HeaderStackManager {
|
|
|
64
71
|
this.update()
|
|
65
72
|
},
|
|
66
73
|
unregister(id: string) {
|
|
74
|
+
const layer = this.layers.find((l: HeaderLayer) => l.id === id)
|
|
75
|
+
if (layer && layer.el) {
|
|
76
|
+
const el = layer.el as HTMLElement & {
|
|
77
|
+
rlScrollListener?: () => void
|
|
78
|
+
rlResizeObserver?: ResizeObserver
|
|
79
|
+
}
|
|
80
|
+
if (el.rlScrollListener) {
|
|
81
|
+
window.removeEventListener("scroll", el.rlScrollListener)
|
|
82
|
+
}
|
|
83
|
+
if (el.rlResizeObserver) {
|
|
84
|
+
el.rlResizeObserver.disconnect()
|
|
85
|
+
}
|
|
86
|
+
}
|
|
67
87
|
this.layers = this.layers.filter((l: HeaderLayer) => l.id !== id)
|
|
68
88
|
this.update()
|
|
69
89
|
},
|