@rimelight/ui 0.0.24 → 0.0.26
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/package.json +7 -3
- package/src/components/Head.astro +199 -156
- package/src/components/ThemeToggle.astro +2 -2
- package/src/components/astro/RLAAccordion.astro +22 -0
- package/src/components/astro/RLAButton.astro +104 -118
- package/src/components/astro/RLAFooter.astro +17 -43
- package/src/components/astro/RLAHeader.astro +21 -80
- package/src/components/astro/RLAIcon.astro +14 -39
- package/src/components/astro/RLALogo.astro +14 -48
- package/src/components/astro/RLAPlaceholder.astro +11 -35
- package/src/components/astro/RLAQuote.astro +15 -0
- package/src/components/astro/RLAScrollToTop.astro +171 -221
- package/src/components/astro/RLASection.astro +210 -0
- package/src/components/vue/RLVButton.vue +166 -139
- package/src/components/vue/RLVFooter.vue +17 -54
- package/src/components/vue/RLVHeader.vue +22 -105
- package/src/components/vue/RLVIcon.vue +14 -45
- package/src/components/vue/RLVLogo.vue +11 -58
- package/src/components/vue/RLVPlaceholder.vue +14 -35
- package/src/components/vue/RLVScrollToTop.vue +18 -89
- package/src/components/vue/RLVSection.vue +166 -0
- package/src/composables/index.ts +0 -1
- package/src/env.d.ts +5 -0
- package/src/integrations/ui.ts +2 -6
- package/src/plugins/index.ts +5 -2
- package/src/plugins/starlightAddons/index.ts +3 -64
- package/src/plugins/starlightDocsApi/components/ApiEmits.astro +46 -0
- package/src/plugins/starlightDocsApi/components/ApiProps.astro +47 -0
- package/src/plugins/starlightDocsApi/components/ApiSlots.astro +50 -0
- package/src/plugins/starlightDocsApi/components/ApiTheme.astro +27 -0
- package/src/plugins/starlightDocsApi/extract-vue.ts +286 -0
- package/src/plugins/starlightDocsApi/index.ts +265 -0
- package/src/plugins/starlightDocsApi/types.ts +40 -0
- package/src/plugins/starlightDocsApi/utils.ts +45 -0
- package/src/themes/button.theme.ts +29 -14
- package/src/themes/footer.theme.ts +4 -6
- package/src/themes/header.theme.ts +4 -28
- package/src/themes/icon.theme.ts +4 -2
- package/src/themes/index.ts +15 -20
- package/src/themes/logo.theme.ts +4 -2
- package/src/themes/placeholder.theme.ts +4 -6
- package/src/themes/scroll-to-top.theme.ts +4 -6
- package/src/themes/section.theme.ts +187 -0
- package/src/types/componentVariant.ts +14 -0
- package/src/types/index.ts +1 -0
- package/src/utils/defineTheme.ts +11 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/resolveClasses.ts +21 -0
- package/src/utils/useUi.ts +19 -0
- package/src/composables/useUi.ts +0 -27
- package/src/plugins/starlightAddons/Sidebar.astro +0 -89
- package/src/plugins/starlightAddons/data.ts +0 -39
- package/src/plugins/starlightAddons/libs/config.ts +0 -107
- package/src/plugins/starlightAddons/libs/content.ts +0 -20
- package/src/plugins/starlightAddons/libs/i18n.ts +0 -51
- package/src/plugins/starlightAddons/libs/locals.ts +0 -12
- package/src/plugins/starlightAddons/libs/pathname.ts +0 -22
- package/src/plugins/starlightAddons/libs/plugin.ts +0 -9
- package/src/plugins/starlightAddons/libs/sidebar.ts +0 -183
- package/src/plugins/starlightAddons/libs/vite.ts +0 -46
- package/src/plugins/starlightAddons/locals.d.ts +0 -14
- package/src/plugins/starlightAddons/middleware.ts +0 -132
- package/src/plugins/starlightAddons/overrides/Sidebar.astro +0 -8
- package/src/plugins/starlightAddons/schema.ts +0 -13
- package/src/plugins/starlightAddons/virtual.d.ts +0 -13
|
@@ -1,65 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, onMounted, onUnmounted, ref } from "vue"
|
|
3
|
-
import { scv
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import { getHeaderStack } from "../../utils/headerStack
|
|
8
|
-
|
|
9
|
-
// ── Style engine ─────────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
const header = scv({
|
|
12
|
-
slots: [...headerTheme.slots],
|
|
13
|
-
base: headerTheme.base,
|
|
14
|
-
variants: headerTheme.variants,
|
|
15
|
-
defaultVariants: headerTheme.defaultVariants,
|
|
16
|
-
classNameResolver: (...args) => twMerge(cx(...args))
|
|
17
|
-
})
|
|
3
|
+
import { scv } from "css-variants"
|
|
4
|
+
import { useUi, resolveClasses } from "../../utils"
|
|
5
|
+
import type { ComponentVariants, ComponentSlots } from "../../types"
|
|
6
|
+
import headerTheme from "../../themes/header.theme"
|
|
7
|
+
import { getHeaderStack } from "../../utils/headerStack"
|
|
18
8
|
|
|
19
|
-
|
|
9
|
+
const header = scv(headerTheme)
|
|
10
|
+
type HeaderVariants = ComponentVariants<typeof headerTheme>
|
|
20
11
|
|
|
21
12
|
export interface RLVHeaderProps {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* @default true
|
|
26
|
-
*/
|
|
27
|
-
contain?: boolean
|
|
28
|
-
/**
|
|
29
|
-
* Sticky positioning when `fixed` is false.
|
|
30
|
-
*
|
|
31
|
-
* @default true
|
|
32
|
-
*/
|
|
33
|
-
sticky?: boolean
|
|
34
|
-
/**
|
|
35
|
-
* Switches to `position: fixed; left: 0; right: 0` (layer mode). When true, `top` and
|
|
36
|
-
* `stackIndex` control the exact position.
|
|
37
|
-
*
|
|
38
|
-
* @default false
|
|
39
|
-
*/
|
|
40
|
-
fixed?: boolean
|
|
41
|
-
/**
|
|
42
|
-
* Controls z-index when `fixed` is true: `z-index = 100 - stackIndex`. Lower index = higher in
|
|
43
|
-
* the visual stack.
|
|
44
|
-
*
|
|
45
|
-
* @default 0
|
|
46
|
-
*/
|
|
13
|
+
contain?: HeaderVariants["contain"]
|
|
14
|
+
sticky?: HeaderVariants["sticky"]
|
|
15
|
+
fixed?: HeaderVariants["fixed"]
|
|
47
16
|
stackIndex?: number
|
|
48
|
-
/**
|
|
49
|
-
* When true, hides the header on scroll-down and shows it on scroll-up. Uses a passive `scroll`
|
|
50
|
-
* event listener — no external dependencies. Only meaningful when `fixed` is true.
|
|
51
|
-
*
|
|
52
|
-
* @default false
|
|
53
|
-
*/
|
|
54
17
|
hideOnScroll?: boolean
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*/
|
|
58
|
-
ui?: Partial<Record<keyof typeof headerTheme.base, string>>
|
|
59
|
-
/**
|
|
60
|
-
* External class — applied to the root element.
|
|
61
|
-
*/
|
|
62
|
-
class?: string
|
|
18
|
+
ui?: ComponentSlots<typeof headerTheme>
|
|
19
|
+
class?: any
|
|
63
20
|
}
|
|
64
21
|
|
|
65
22
|
const {
|
|
@@ -68,46 +25,19 @@ const {
|
|
|
68
25
|
fixed = false,
|
|
69
26
|
stackIndex = 0,
|
|
70
27
|
hideOnScroll = false,
|
|
71
|
-
|
|
72
|
-
|
|
28
|
+
ui: uiProp,
|
|
29
|
+
class: className
|
|
73
30
|
} = defineProps<RLVHeaderProps>()
|
|
74
31
|
|
|
75
|
-
// ── Slots ─────────────────────────────────────────────────────────────────────
|
|
76
|
-
|
|
77
32
|
defineSlots<{
|
|
78
|
-
/**
|
|
79
|
-
* Content to display on the left side of the header (e.g., Logo).
|
|
80
|
-
*/
|
|
81
33
|
left(props: {}): any
|
|
82
|
-
/**
|
|
83
|
-
* Content to display in the center of the header (e.g., Navigation Links).
|
|
84
|
-
*/
|
|
85
34
|
center(props: {}): any
|
|
86
|
-
/**
|
|
87
|
-
* Content to display on the right side of the header (e.g., User Menu, Theme Toggle).
|
|
88
|
-
*/
|
|
89
35
|
right(props: {}): any
|
|
90
36
|
}>()
|
|
91
37
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// ── Resolved classes ──────────────────────────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
const resolvedClasses = computed(() => {
|
|
99
|
-
const classes = header({ contain, sticky, fixed })
|
|
100
|
-
return {
|
|
101
|
-
root: twMerge(classes.root, mergedUI.value.root as string | undefined),
|
|
102
|
-
content: twMerge(classes.content, mergedUI.value.content as string | undefined),
|
|
103
|
-
container: twMerge(classes.container, mergedUI.value.container as string | undefined),
|
|
104
|
-
left: twMerge(classes.left, mergedUI.value.left as string | undefined),
|
|
105
|
-
center: twMerge(classes.center, mergedUI.value.center as string | undefined),
|
|
106
|
-
right: twMerge(classes.right, mergedUI.value.right as string | undefined)
|
|
107
|
-
}
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
// ── Fixed-mode state ──────────────────────────────────────────────────────────
|
|
38
|
+
const resolvedClasses = computed(() =>
|
|
39
|
+
resolveClasses(header, { contain, sticky, fixed }, useUi("header", uiProp), className)
|
|
40
|
+
)
|
|
111
41
|
|
|
112
42
|
const id = `rlv-header-${Math.random().toString(36).slice(2, 8)}`
|
|
113
43
|
const rootRef = ref<HTMLElement | null>(null)
|
|
@@ -115,9 +45,6 @@ const contentRef = ref<HTMLElement | null>(null)
|
|
|
115
45
|
const naturalHeight = ref(0)
|
|
116
46
|
const isVisible = ref(true)
|
|
117
47
|
|
|
118
|
-
/**
|
|
119
|
-
* Inline style applied to the root element in fixed mode.
|
|
120
|
-
*/
|
|
121
48
|
const fixedStyle = computed(() => {
|
|
122
49
|
if (!fixed) return {}
|
|
123
50
|
return {
|
|
@@ -125,8 +52,6 @@ const fixedStyle = computed(() => {
|
|
|
125
52
|
}
|
|
126
53
|
})
|
|
127
54
|
|
|
128
|
-
// ── Lifecycle: height measurement + scroll listener ───────────────────────────
|
|
129
|
-
|
|
130
55
|
let resizeObserver: ResizeObserver | null = null
|
|
131
56
|
let scrollHandler: (() => void) | null = null
|
|
132
57
|
|
|
@@ -139,7 +64,6 @@ onMounted(() => {
|
|
|
139
64
|
stack.register(id, stackIndex, naturalHeight.value, isVisible.value, rootRef.value)
|
|
140
65
|
}
|
|
141
66
|
|
|
142
|
-
// Measure natural height via ResizeObserver
|
|
143
67
|
if (contentRef.value) {
|
|
144
68
|
naturalHeight.value = contentRef.value.getBoundingClientRect().height
|
|
145
69
|
resizeObserver = new ResizeObserver((entries) => {
|
|
@@ -152,14 +76,12 @@ onMounted(() => {
|
|
|
152
76
|
resizeObserver.observe(contentRef.value)
|
|
153
77
|
}
|
|
154
78
|
|
|
155
|
-
// Raw scroll listener for hideOnScroll
|
|
156
79
|
if (hideOnScroll) {
|
|
157
80
|
let localLastScrollY = window.scrollY
|
|
158
81
|
scrollHandler = () => {
|
|
159
82
|
const current = window.scrollY
|
|
160
83
|
const diff = current - localLastScrollY
|
|
161
84
|
|
|
162
|
-
// Ignore tiny jitter
|
|
163
85
|
if (Math.abs(diff) < 10) return
|
|
164
86
|
|
|
165
87
|
const newVisible = current <= 50 ? true : diff <= 0
|
|
@@ -188,25 +110,20 @@ onUnmounted(() => {
|
|
|
188
110
|
<header
|
|
189
111
|
ref="rootRef"
|
|
190
112
|
:id="id"
|
|
191
|
-
:class="[resolvedClasses.root
|
|
113
|
+
:class="[resolvedClasses.root]"
|
|
192
114
|
:style="fixedStyle"
|
|
193
|
-
data-slot="
|
|
115
|
+
data-slot="root"
|
|
194
116
|
v-bind="$attrs"
|
|
195
117
|
>
|
|
196
|
-
<!--
|
|
197
|
-
content wrapper: always rendered, but only meaningful in fixed mode.
|
|
198
|
-
The ResizeObserver targets this element so the `<header>` root's padding/border
|
|
199
|
-
don't interfere with the height measurement.
|
|
200
|
-
-->
|
|
201
118
|
<div ref="contentRef" :class="resolvedClasses.content">
|
|
202
119
|
<div :class="resolvedClasses.container">
|
|
203
|
-
<div :class="resolvedClasses.left" data-slot="
|
|
120
|
+
<div :class="resolvedClasses.left" data-slot="left">
|
|
204
121
|
<slot name="left" />
|
|
205
122
|
</div>
|
|
206
|
-
<div :class="resolvedClasses.center" data-slot="
|
|
123
|
+
<div :class="resolvedClasses.center" data-slot="center">
|
|
207
124
|
<slot name="center" />
|
|
208
125
|
</div>
|
|
209
|
-
<div :class="resolvedClasses.right" data-slot="
|
|
126
|
+
<div :class="resolvedClasses.right" data-slot="right">
|
|
210
127
|
<slot name="right" />
|
|
211
128
|
</div>
|
|
212
129
|
</div>
|
|
@@ -1,51 +1,25 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue"
|
|
3
|
-
import { scv
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
3
|
+
import { scv } from "css-variants"
|
|
4
|
+
import { useUi, resolveClasses } from "../../utils"
|
|
5
|
+
import type { ComponentVariants, ComponentSlots } from "../../types"
|
|
6
|
+
import iconTheme from "../../themes/icon.theme"
|
|
7
7
|
|
|
8
|
-
const icon = scv(
|
|
9
|
-
|
|
10
|
-
base: iconTheme.base,
|
|
11
|
-
variants: iconTheme.variants,
|
|
12
|
-
defaultVariants: iconTheme.defaultVariants,
|
|
13
|
-
classNameResolver: (...args) => twMerge(cx(...args))
|
|
14
|
-
})
|
|
8
|
+
const icon = scv(iconTheme)
|
|
9
|
+
type IconVariants = ComponentVariants<typeof iconTheme>
|
|
15
10
|
|
|
16
11
|
export interface RLVIconProps {
|
|
17
|
-
/**
|
|
18
|
-
* Icon name following the UnoCSS icons format. Can be a string like "i-lucide-home" or a Vue
|
|
19
|
-
* component.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* "i-lucide-home"
|
|
23
|
-
*/
|
|
24
12
|
name: string
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
size?: keyof typeof iconTheme.variants.size
|
|
29
|
-
/**
|
|
30
|
-
* External class applied to the root element.
|
|
31
|
-
*/
|
|
32
|
-
class?: string
|
|
33
|
-
/**
|
|
34
|
-
* UI overrides for individual slots.
|
|
35
|
-
*/
|
|
36
|
-
ui?: Partial<Record<keyof typeof iconTheme.base, string>>
|
|
13
|
+
size?: IconVariants["size"]
|
|
14
|
+
ui?: ComponentSlots<typeof iconTheme>
|
|
15
|
+
class?: any
|
|
37
16
|
}
|
|
38
17
|
|
|
39
|
-
const { name, size = "md",
|
|
18
|
+
const { name, size = "md", ui: uiProp, class: className } = defineProps<RLVIconProps>()
|
|
40
19
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const { root } = icon({ size })
|
|
45
|
-
return {
|
|
46
|
-
root: twMerge(root, mergedUI.value.root, className)
|
|
47
|
-
}
|
|
48
|
-
})
|
|
20
|
+
const resolvedClasses = computed(() =>
|
|
21
|
+
resolveClasses(icon, { size }, useUi("icon", uiProp), className)
|
|
22
|
+
)
|
|
49
23
|
|
|
50
24
|
defineSlots<{
|
|
51
25
|
default(props: {}): any
|
|
@@ -53,12 +27,7 @@ defineSlots<{
|
|
|
53
27
|
</script>
|
|
54
28
|
|
|
55
29
|
<template>
|
|
56
|
-
<span
|
|
57
|
-
v-bind="$attrs"
|
|
58
|
-
:class="[resolvedClasses.root, name]"
|
|
59
|
-
data-slot="rlv-icon"
|
|
60
|
-
aria-hidden="true"
|
|
61
|
-
>
|
|
30
|
+
<span v-bind="$attrs" :class="[resolvedClasses.root, name]" data-slot="root" aria-hidden="true">
|
|
62
31
|
<slot />
|
|
63
32
|
</span>
|
|
64
33
|
</template>
|
|
@@ -1,51 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue"
|
|
3
|
-
import { scv
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
3
|
+
import { scv } from "css-variants"
|
|
4
|
+
import { useUi, resolveClasses } from "../../utils"
|
|
5
|
+
import type { ComponentSlots } from "../../types"
|
|
6
|
+
import logoTheme from "../../themes/logo.theme"
|
|
7
7
|
import { getUIConfig } from "virtual:rimelight-ui"
|
|
8
8
|
|
|
9
|
-
const logo = scv(
|
|
10
|
-
slots: [...logoTheme.slots],
|
|
11
|
-
base: logoTheme.base,
|
|
12
|
-
variants: logoTheme.variants,
|
|
13
|
-
defaultVariants: logoTheme.defaultVariants,
|
|
14
|
-
classNameResolver: (...args) => twMerge(cx(...args))
|
|
15
|
-
})
|
|
9
|
+
const logo = scv(logoTheme)
|
|
16
10
|
|
|
17
11
|
export interface RLVLogoProps {
|
|
18
|
-
/**
|
|
19
|
-
* The variant of the logo to display.
|
|
20
|
-
*
|
|
21
|
-
* @default "logomark"
|
|
22
|
-
*/
|
|
23
12
|
variant?: string
|
|
24
|
-
/**
|
|
25
|
-
* Override the color mode.
|
|
26
|
-
*/
|
|
27
13
|
mode?: "color" | "white" | "black"
|
|
28
|
-
/**
|
|
29
|
-
* The URL to link to.
|
|
30
|
-
*
|
|
31
|
-
* @default "/"
|
|
32
|
-
*/
|
|
33
14
|
href?: string
|
|
34
|
-
/**
|
|
35
|
-
* UI overrides for individual slots, derived from the logo theme.
|
|
36
|
-
*/
|
|
37
|
-
ui?: Partial<Record<keyof typeof logoTheme.base, string>>
|
|
38
|
-
/**
|
|
39
|
-
* External class — applied to the root element.
|
|
40
|
-
*/
|
|
41
|
-
class?: string
|
|
42
|
-
/**
|
|
43
|
-
* The alt text for the logo image.
|
|
44
|
-
*/
|
|
45
15
|
alt?: string
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*/
|
|
16
|
+
ui?: ComponentSlots<typeof logoTheme>
|
|
17
|
+
class?: any
|
|
49
18
|
[key: string]: unknown
|
|
50
19
|
}
|
|
51
20
|
|
|
@@ -55,30 +24,15 @@ const props = withDefaults(defineProps<RLVLogoProps>(), {
|
|
|
55
24
|
})
|
|
56
25
|
|
|
57
26
|
defineSlots<{
|
|
58
|
-
/**
|
|
59
|
-
* The default slot for the logo content (e.g., text, custom elements).
|
|
60
|
-
*/
|
|
61
27
|
default(props: {}): any
|
|
62
28
|
}>()
|
|
63
29
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const mergedUI = computed(
|
|
67
|
-
() =>
|
|
68
|
-
defu(props.ui ?? {}, (globalConfig.logo as Record<string, unknown>) ?? {}) as Record<
|
|
69
|
-
keyof typeof logoTheme.base,
|
|
70
|
-
string | undefined
|
|
71
|
-
>
|
|
30
|
+
const resolvedClasses = computed(() =>
|
|
31
|
+
resolveClasses(logo, {}, useUi("logo", props.ui), props.class)
|
|
72
32
|
)
|
|
73
33
|
|
|
74
|
-
const resolvedClasses = computed(() => {
|
|
75
|
-
const { root } = logo()
|
|
76
|
-
return {
|
|
77
|
-
root: twMerge(root, mergedUI.value.root, props.class)
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
34
|
const logoSrc = computed<string | null>(() => {
|
|
35
|
+
const globalConfig = getUIConfig()
|
|
82
36
|
const rcLogos = globalConfig.logos as Record<string, any>
|
|
83
37
|
let src: any = null
|
|
84
38
|
|
|
@@ -111,10 +65,9 @@ const Tag = computed(() => (props.href ? "a" : "div"))
|
|
|
111
65
|
:href="Tag === 'a' ? href : undefined"
|
|
112
66
|
:aria-label="alt || variant"
|
|
113
67
|
:class="resolvedClasses.root"
|
|
114
|
-
data-slot="
|
|
68
|
+
data-slot="root"
|
|
115
69
|
>
|
|
116
70
|
<template v-if="logoSrc">
|
|
117
|
-
<!-- Using mode='svg' pattern is not strictly needed for UnoCSS icons -->
|
|
118
71
|
<span v-if="isIcon" :class="[logoSrc, 'size-full block shrink-0']" aria-hidden="true" />
|
|
119
72
|
<img v-else :src="logoSrc" :alt="alt || ''" class="size-full block object-contain shrink-0" />
|
|
120
73
|
</template>
|
|
@@ -1,35 +1,19 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
2
|
+
import { computed } from "vue"
|
|
3
|
+
import { scv } from "css-variants"
|
|
4
|
+
import { useUi, resolveClasses } from "../../utils"
|
|
5
|
+
import type { ComponentSlots } from "../../types"
|
|
6
|
+
import placeholderTheme from "../../themes/placeholder.theme"
|
|
7
7
|
|
|
8
|
-
const placeholder = scv(
|
|
9
|
-
slots: [...placeholderTheme.slots],
|
|
10
|
-
base: placeholderTheme.base,
|
|
11
|
-
variants: placeholderTheme.variants,
|
|
12
|
-
compoundVariants: [...placeholderTheme.compoundVariants],
|
|
13
|
-
defaultVariants: placeholderTheme.defaultVariants,
|
|
14
|
-
classNameResolver: (...args) => twMerge(cx(...args))
|
|
15
|
-
})
|
|
8
|
+
const placeholder = scv(placeholderTheme)
|
|
16
9
|
|
|
17
10
|
export interface RLVPlaceholderProps {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*/
|
|
21
|
-
ui?: Partial<Record<keyof typeof placeholderTheme.base, string>>
|
|
22
|
-
/**
|
|
23
|
-
* External class — applied to the root element.
|
|
24
|
-
*/
|
|
25
|
-
class?: string
|
|
26
|
-
/**
|
|
27
|
-
* Standard HTML attributes.
|
|
28
|
-
*/
|
|
11
|
+
ui?: ComponentSlots<typeof placeholderTheme>
|
|
12
|
+
class?: any
|
|
29
13
|
[key: string]: unknown
|
|
30
14
|
}
|
|
31
15
|
|
|
32
|
-
const {
|
|
16
|
+
const { ui: uiProp, class: className } = defineProps<RLVPlaceholderProps>()
|
|
33
17
|
|
|
34
18
|
defineSlots<{
|
|
35
19
|
/**
|
|
@@ -38,19 +22,14 @@ defineSlots<{
|
|
|
38
22
|
default(props: {}): any
|
|
39
23
|
}>()
|
|
40
24
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
uiProp ?? {},
|
|
45
|
-
(globalConfig.placeholder as Record<string, unknown>) ?? {}
|
|
46
|
-
) as Record<keyof typeof placeholderTheme.base, string | undefined>
|
|
47
|
-
|
|
48
|
-
const { base, svg } = placeholder()
|
|
25
|
+
const resolvedClasses = computed(() =>
|
|
26
|
+
resolveClasses(placeholder, {}, useUi("placeholder", uiProp), className)
|
|
27
|
+
)
|
|
49
28
|
</script>
|
|
50
29
|
|
|
51
30
|
<template>
|
|
52
|
-
<div :class="
|
|
53
|
-
<svg :class="
|
|
31
|
+
<div :class="resolvedClasses.base" v-bind="$attrs">
|
|
32
|
+
<svg :class="resolvedClasses.svg">
|
|
54
33
|
<defs>
|
|
55
34
|
<pattern
|
|
56
35
|
id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
|
|
@@ -1,66 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { scv
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { scv } from "css-variants"
|
|
3
|
+
import { useUi, resolveClasses } from "../../utils"
|
|
4
|
+
import type { ComponentVariants, ComponentSlots } from "../../types"
|
|
5
|
+
import scrollToTopTheme from "../../themes/scroll-to-top.theme"
|
|
6
6
|
import { useScrollToTop } from "../../composables/useScrollToTop"
|
|
7
7
|
import { computed } from "vue"
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
const scrollToTop = scv(scrollToTopTheme)
|
|
10
|
+
type ScrollToTopVariants = ComponentVariants<typeof scrollToTopTheme>
|
|
9
11
|
|
|
10
12
|
export interface RLVScrollToTopProps {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*
|
|
14
|
-
* @default "primary"
|
|
15
|
-
*/
|
|
16
|
-
color?: keyof typeof scrollToTopTheme.variants.color
|
|
17
|
-
/**
|
|
18
|
-
* Transition duration for the progress circle (in seconds).
|
|
19
|
-
*
|
|
20
|
-
* @default 0.1
|
|
21
|
-
*/
|
|
13
|
+
color?: ScrollToTopVariants["color"]
|
|
14
|
+
progressWidth?: number
|
|
22
15
|
duration?: number
|
|
23
|
-
/**
|
|
24
|
-
* Scroll threshold (in pixels) before the button becomes visible.
|
|
25
|
-
*
|
|
26
|
-
* @default 200
|
|
27
|
-
*/
|
|
28
16
|
threshold?: number
|
|
29
|
-
/**
|
|
30
|
-
* Whether to show the scroll progress indicator.
|
|
31
|
-
*
|
|
32
|
-
* @default false
|
|
33
|
-
*/
|
|
34
17
|
showProgress?: boolean
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
* @default 6
|
|
39
|
-
*/
|
|
40
|
-
progressWidth?: number
|
|
41
|
-
/**
|
|
42
|
-
* UI overrides for individual slots, derived from the scroll-to-top theme.
|
|
43
|
-
*/
|
|
44
|
-
ui?: Partial<Record<keyof typeof scrollToTopTheme.base, string>>
|
|
45
|
-
/**
|
|
46
|
-
* External class — applied to the root element.
|
|
47
|
-
*/
|
|
48
|
-
class?: string
|
|
49
|
-
/**
|
|
50
|
-
* Standard HTML attributes.
|
|
51
|
-
*/
|
|
52
|
-
[key: string]: unknown
|
|
18
|
+
ui?: ComponentSlots<typeof scrollToTopTheme>
|
|
19
|
+
class?: any
|
|
53
20
|
}
|
|
54
21
|
|
|
55
|
-
const scrollToTop = scv({
|
|
56
|
-
slots: [...scrollToTopTheme.slots],
|
|
57
|
-
base: scrollToTopTheme.base,
|
|
58
|
-
variants: scrollToTopTheme.variants,
|
|
59
|
-
compoundVariants: [...scrollToTopTheme.compoundVariants],
|
|
60
|
-
defaultVariants: scrollToTopTheme.defaultVariants,
|
|
61
|
-
classNameResolver: (...args) => twMerge(cx(...args))
|
|
62
|
-
})
|
|
63
|
-
|
|
64
22
|
const {
|
|
65
23
|
color = "primary",
|
|
66
24
|
progressWidth = 6,
|
|
@@ -71,23 +29,7 @@ const {
|
|
|
71
29
|
class: className
|
|
72
30
|
} = defineProps<RLVScrollToTopProps>()
|
|
73
31
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
const mergedUI = defu(
|
|
77
|
-
uiProp ?? {},
|
|
78
|
-
(globalConfig["scroll-to-top"] as Record<string, unknown>) ?? {}
|
|
79
|
-
) as Record<keyof typeof scrollToTopTheme.base, string | undefined>
|
|
80
|
-
|
|
81
|
-
const {
|
|
82
|
-
root,
|
|
83
|
-
button,
|
|
84
|
-
progressBase,
|
|
85
|
-
svg: svgClass,
|
|
86
|
-
iconContainer,
|
|
87
|
-
icon
|
|
88
|
-
} = scrollToTop({
|
|
89
|
-
color
|
|
90
|
-
})
|
|
32
|
+
const classes = resolveClasses(scrollToTop, { color }, useUi("scrollToTop", uiProp), className)
|
|
91
33
|
|
|
92
34
|
const {
|
|
93
35
|
isVisible,
|
|
@@ -107,25 +49,12 @@ const durationInSeconds = computed(() => `${duration}s`)
|
|
|
107
49
|
|
|
108
50
|
<template>
|
|
109
51
|
<div
|
|
110
|
-
:class="[
|
|
111
|
-
'rla-scroll-to-top fixed bottom-6 right-6 z-50',
|
|
112
|
-
{ visible: isVisible },
|
|
113
|
-
twMerge(root, mergedUI.root, className)
|
|
114
|
-
]"
|
|
52
|
+
:class="['rla-scroll-to-top fixed bottom-6 right-6 z-50', { visible: isVisible }, classes.root]"
|
|
115
53
|
v-bind="$attrs"
|
|
116
54
|
>
|
|
117
|
-
<button
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
aria-label="Scroll to top"
|
|
121
|
-
@click="scrollToTopFn"
|
|
122
|
-
>
|
|
123
|
-
<div :class="twMerge(progressBase, mergedUI.progressBase)">
|
|
124
|
-
<svg
|
|
125
|
-
:class="twMerge(svgClass, mergedUI.svg)"
|
|
126
|
-
viewBox="0 0 100 100"
|
|
127
|
-
shape-rendering="geometricPrecision"
|
|
128
|
-
>
|
|
55
|
+
<button type="button" :class="classes.button" aria-label="Scroll to top" @click="scrollToTopFn">
|
|
56
|
+
<div :class="classes.progressBase">
|
|
57
|
+
<svg :class="classes.svg" viewBox="0 0 100 100" shape-rendering="geometricPrecision">
|
|
129
58
|
<circle
|
|
130
59
|
cx="50"
|
|
131
60
|
cy="50"
|
|
@@ -153,7 +82,7 @@ const durationInSeconds = computed(() => `${duration}s`)
|
|
|
153
82
|
}"
|
|
154
83
|
/>
|
|
155
84
|
</svg>
|
|
156
|
-
<div :class="
|
|
85
|
+
<div :class="classes.iconContainer">
|
|
157
86
|
<svg
|
|
158
87
|
xmlns="http://www.w3.org/2000/svg"
|
|
159
88
|
width="24"
|
|
@@ -164,7 +93,7 @@ const durationInSeconds = computed(() => `${duration}s`)
|
|
|
164
93
|
stroke-width="2"
|
|
165
94
|
stroke-linecap="round"
|
|
166
95
|
stroke-linejoin="round"
|
|
167
|
-
:class="
|
|
96
|
+
:class="classes.icon"
|
|
168
97
|
>
|
|
169
98
|
<path d="m5 12 7-7 7 7" />
|
|
170
99
|
<path d="M12 19V5" />
|