@rimelight/ui 0.0.21 → 0.0.23

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.
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ import { scv, cx } from "css-variants"
3
+ import { twMerge } from "tailwind-merge"
4
+ import defu from "defu"
5
+ import { placeholderTheme } from "../../themes/placeholder.theme.ts"
6
+ import { getUIConfig } from "virtual:rimelight-ui"
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
+ })
16
+
17
+ export interface RLVPlaceholderProps {
18
+ /**
19
+ * UI overrides for individual slots, derived from the placeholder theme.
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
+ */
29
+ [key: string]: unknown
30
+ }
31
+
32
+ const { class: className, ui: uiProp } = defineProps<RLVPlaceholderProps>()
33
+
34
+ defineSlots<{
35
+ /**
36
+ * The default slot for placeholder content.
37
+ */
38
+ default(props: {}): any
39
+ }>()
40
+
41
+ const globalConfig = getUIConfig()
42
+
43
+ const mergedUI = defu(
44
+ uiProp ?? {},
45
+ (globalConfig.placeholder as Record<string, unknown>) ?? {}
46
+ ) as Record<keyof typeof placeholderTheme.base, string | undefined>
47
+
48
+ const { base, svg } = placeholder()
49
+ </script>
50
+
51
+ <template>
52
+ <div :class="twMerge(base, mergedUI.base, className)" v-bind="$attrs">
53
+ <svg :class="twMerge(svg, mergedUI.svg)">
54
+ <defs>
55
+ <pattern
56
+ id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
57
+ x="0"
58
+ y="0"
59
+ width="10"
60
+ height="10"
61
+ patternUnits="userSpaceOnUse"
62
+ >
63
+ <path d="M-3 13 15-5M-5 5l18-18M-1 21 17 3" />
64
+ </pattern>
65
+ </defs>
66
+ <rect
67
+ stroke="none"
68
+ fill="url(#pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e)"
69
+ width="100%"
70
+ height="100%"
71
+ />
72
+ </svg>
73
+
74
+ <slot />
75
+ </div>
76
+ </template>
@@ -1,154 +1,214 @@
1
- <script setup lang="ts">
2
- import { computed } from "vue"
3
- import { scv, cx } from "css-variants"
4
- import { twMerge } from "tailwind-merge"
5
- import defu from "defu"
6
- import { scrollToTopTheme } from "../../themes/scroll-to-top.theme.ts"
7
- import { useScrollToTop } from "../../composables/useScrollToTop"
8
- import { getUIConfig } from "virtual:rimelight-ui"
9
-
10
- export interface RLVScrollToTopProps {
11
- color?: keyof typeof scrollToTopTheme.variants.color
12
- circleStrokeWidth?: number
13
- duration?: number
14
- threshold?: number
15
- ui?: Partial<Record<keyof typeof scrollToTopTheme.base, string>>
16
- class?: string
17
- [key: string]: unknown
18
- }
19
-
20
- const scrollToTop = scv({
21
- slots: [...scrollToTopTheme.slots],
22
- base: scrollToTopTheme.base,
23
- variants: scrollToTopTheme.variants,
24
- compoundVariants: [...scrollToTopTheme.compoundVariants],
25
- defaultVariants: scrollToTopTheme.defaultVariants,
26
- classNameResolver: (...args) => twMerge(cx(...args))
27
- })
28
-
29
- const {
30
- color = "primary",
31
- circleStrokeWidth = 4,
32
- duration = 0.1,
33
- threshold = 200,
34
- ui: uiProp,
35
- class: className,
36
- } = defineProps<RLVScrollToTopProps>()
37
-
38
- const globalConfig = getUIConfig()
39
-
40
- const mergedUI = defu(
41
- uiProp ?? {},
42
- (globalConfig["scroll-to-top"] as Record<string, unknown>) ?? {}
43
- ) as Record<keyof typeof scrollToTopTheme.base, string | undefined>
44
-
45
- defineSlots<{
46
- default(props: {}): any
47
- }>()
48
-
49
- const { root, button, progressBase, svg: svgClass, iconContainer, icon } = scrollToTop({
50
- color
51
- })
52
-
53
- const { isVisible, scrollPercentage, scrollToTop: scrollToTopFn } = useScrollToTop({
54
- threshold
55
- })
56
-
57
- const circumference = 2 * Math.PI * 45
58
- const percentPx = circumference / 100
59
-
60
- const currentPercent = computed(() => scrollPercentage.value)
61
- const percentageInPx = computed(() => `${percentPx}px`)
62
- const durationInSeconds = computed(() => `${duration}s`)
63
- </script>
64
-
65
- <template>
66
- <div
67
- :class="[
68
- 'rla-scroll-to-top fixed bottom-6 right-6 z-50',
69
- { 'visible': isVisible },
70
- twMerge(root, mergedUI.root, className)
71
- ]"
72
- v-bind="$attrs"
73
- >
74
- <button
75
- type="button"
76
- :class="twMerge(button, mergedUI.button)"
77
- aria-label="Scroll to top"
78
- @click="scrollToTopFn"
79
- >
80
- <div :class="twMerge(progressBase, mergedUI.progressBase)">
81
- <svg :class="twMerge(svgClass, mergedUI.svg)" viewBox="0 0 100 100">
82
- <circle
83
- cx="50"
84
- cy="50"
85
- r="45"
86
- fill="var(--color-primary-950)"
87
- :stroke-width="circleStrokeWidth"
88
- stroke-dashoffset="0"
89
- stroke-linecap="round"
90
- class="gauge-secondary-stroke opacity-100"
91
- />
92
- <circle
93
- cx="50"
94
- cy="50"
95
- r="45"
96
- fill="transparent"
97
- :stroke-width="circleStrokeWidth"
98
- stroke-linecap="round"
99
- class="gauge-primary-stroke opacity-100"
100
- :style="{ strokeDasharray: `${(currentPercent / 100) * circumference} ${circumference}` }"
101
- />
102
- </svg>
103
- <div :class="twMerge(iconContainer, mergedUI.iconContainer)">
104
- <svg
105
- xmlns="http://www.w3.org/2000/svg"
106
- width="24"
107
- height="24"
108
- viewBox="0 0 24 24"
109
- fill="none"
110
- stroke="currentColor"
111
- stroke-width="2"
112
- stroke-linecap="round"
113
- stroke-linejoin="round"
114
- :class="twMerge(icon, mergedUI.icon)"
115
- >
116
- <path d="m5 12 7-7 7 7" />
117
- <path d="M12 19V5" />
118
- </svg>
119
- </div>
120
- </div>
121
- </button>
122
- </div>
123
- </template>
124
-
125
- <style scoped>
126
- .rla-scroll-to-top {
127
- opacity: 0;
128
- pointer-events: none;
129
- transition: opacity 0.3s ease-in-out;
130
- }
131
-
132
- .rla-scroll-to-top.visible {
133
- opacity: 1;
134
- pointer-events: auto;
135
- }
136
-
137
- .progress-circle-base {
138
- transform: translateZ(0);
139
- }
140
-
141
- .gauge-primary-stroke {
142
- stroke: var(--color-primary-500);
143
- transition: stroke-dasharray 0.1s ease, stroke 0.1s ease;
144
- transform: rotate(-90deg);
145
- transform-origin: center;
146
- }
147
-
148
- .gauge-secondary-stroke {
149
- stroke: var(--color-primary-900);
150
- stroke-dasharray: 282.6;
151
- transform: rotate(-90deg);
152
- transform-origin: center;
153
- }
154
- </style>
1
+ <script setup lang="ts">
2
+ import { scv, cx } from "css-variants"
3
+ import { twMerge } from "tailwind-merge"
4
+ import defu from "defu"
5
+ import { scrollToTopTheme } from "../../themes/scroll-to-top.theme.ts"
6
+ import { useScrollToTop } from "../../composables/useScrollToTop"
7
+ import { computed } from "vue"
8
+ import { getUIConfig } from "virtual:rimelight-ui"
9
+
10
+ export interface RLVScrollToTopProps {
11
+ /**
12
+ * Button color.
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
+ */
22
+ duration?: number
23
+ /**
24
+ * Scroll threshold (in pixels) before the button becomes visible.
25
+ *
26
+ * @default 200
27
+ */
28
+ threshold?: number
29
+ /**
30
+ * Whether to show the scroll progress indicator.
31
+ *
32
+ * @default false
33
+ */
34
+ showProgress?: boolean
35
+ /**
36
+ * Stroke width of the progress circle.
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
53
+ }
54
+
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
+ const {
65
+ color = "primary",
66
+ progressWidth = 6,
67
+ duration = 0.1,
68
+ threshold = 200,
69
+ showProgress = false,
70
+ ui: uiProp,
71
+ class: className
72
+ } = defineProps<RLVScrollToTopProps>()
73
+
74
+ const globalConfig = getUIConfig()
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
+ })
91
+
92
+ const {
93
+ isVisible,
94
+ scrollPercentage,
95
+ scrollToTop: scrollToTopFn
96
+ } = useScrollToTop({
97
+ threshold
98
+ })
99
+
100
+ const circumference = 2 * Math.PI * 45
101
+ const percentPx = circumference / 100
102
+
103
+ const currentPercent = computed(() => scrollPercentage.value)
104
+ const percentageInPx = computed(() => `${percentPx}px`)
105
+ const durationInSeconds = computed(() => `${duration}s`)
106
+ </script>
107
+
108
+ <template>
109
+ <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
+ ]"
115
+ v-bind="$attrs"
116
+ >
117
+ <button
118
+ type="button"
119
+ :class="twMerge(button, mergedUI.button)"
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
+ >
129
+ <circle
130
+ cx="50"
131
+ cy="50"
132
+ r="45"
133
+ fill="var(--color-primary-950)"
134
+ :stroke-width="progressWidth"
135
+ stroke-dashoffset="0"
136
+ stroke-linecap="round"
137
+ class="gauge-secondary-stroke opacity-100"
138
+ />
139
+ <circle
140
+ v-if="showProgress"
141
+ cx="50"
142
+ cy="50"
143
+ r="45"
144
+ fill="transparent"
145
+ :stroke-width="progressWidth"
146
+ stroke-linecap="round"
147
+ class="gauge-primary-stroke opacity-100"
148
+ :style="{
149
+ '--stroke-percent': currentPercent,
150
+ '--percent-to-px': percentageInPx,
151
+ '--circumference': circumference,
152
+ '--duration': durationInSeconds
153
+ }"
154
+ />
155
+ </svg>
156
+ <div :class="twMerge(iconContainer, mergedUI.iconContainer)">
157
+ <svg
158
+ xmlns="http://www.w3.org/2000/svg"
159
+ width="24"
160
+ height="24"
161
+ viewBox="0 0 24 24"
162
+ fill="none"
163
+ stroke="currentColor"
164
+ stroke-width="2"
165
+ stroke-linecap="round"
166
+ stroke-linejoin="round"
167
+ :class="twMerge(icon, mergedUI.icon)"
168
+ >
169
+ <path d="m5 12 7-7 7 7" />
170
+ <path d="M12 19V5" />
171
+ </svg>
172
+ </div>
173
+ </div>
174
+ </button>
175
+ </div>
176
+ </template>
177
+
178
+ <style scoped>
179
+ .rla-scroll-to-top {
180
+ opacity: 0;
181
+ pointer-events: none;
182
+ transition: opacity 0.3s ease-in-out;
183
+ }
184
+
185
+ .rla-scroll-to-top.visible {
186
+ opacity: 1;
187
+ pointer-events: auto;
188
+ }
189
+
190
+ .progress-circle-base {
191
+ transform: translateZ(0);
192
+ }
193
+
194
+ .gauge-primary-stroke {
195
+ stroke: var(--color-primary-500);
196
+ --stroke-percent: v-bind(currentPercent);
197
+ --percent-to-px: v-bind(percentageInPx);
198
+ --circumference: v-bind(circumference);
199
+ stroke-dasharray: calc(var(--stroke-percent) * var(--percent-to-px)) var(--circumference);
200
+ transition:
201
+ stroke-dasharray v-bind(durationInSeconds) ease,
202
+ stroke v-bind(durationInSeconds) ease;
203
+ transform: rotate(-90deg);
204
+ transform-origin: center;
205
+ shape-rendering: geometricPrecision;
206
+ }
207
+
208
+ .gauge-secondary-stroke {
209
+ stroke: var(--color-primary-900);
210
+ stroke-dasharray: 282.6;
211
+ transform: rotate(-90deg);
212
+ transform-origin: center;
213
+ }
214
+ </style>
@@ -3,7 +3,6 @@ import UnoCSS from "unocss/astro"
3
3
  import vue from "@astrojs/vue"
4
4
  import uiPlugin from "@nuxt/ui/vite"
5
5
  import defu from "defu"
6
- import Icons from "unplugin-icons/vite"
7
6
  import tailwindcss from "@tailwindcss/vite"
8
7
  import { defaultUIConfig } from "../themes"
9
8
 
@@ -11,12 +10,28 @@ import { defaultUIConfig } from "../themes"
11
10
  * Shape of the `ui` config that can be passed to the integration.
12
11
  */
13
12
  export type UIConfigOverrides = {
14
- button?: Partial<(typeof defaultUIConfig)["button"]>
15
- header?: Partial<(typeof defaultUIConfig)["header"]>
13
+ "button"?: Partial<(typeof defaultUIConfig)["button"]>
14
+ "header"?: Partial<(typeof defaultUIConfig)["header"]>
16
15
  "scroll-to-top"?: Partial<(typeof defaultUIConfig)["scroll-to-top"]>
16
+ "logo"?: Partial<(typeof defaultUIConfig)["logo"]>
17
17
  }
18
18
 
19
19
  export interface UIOptions {
20
+ /**
21
+ * Configuration for the Logo component variants.
22
+ */
23
+ logos?: Record<
24
+ string,
25
+ | string
26
+ | {
27
+ light?: string
28
+ dark?: string
29
+ color?: string
30
+ white?: string
31
+ black?: string
32
+ [key: string]: string | undefined
33
+ }
34
+ >
20
35
  /**
21
36
  * Global UI overrides applied to all components. Merged with defaults via `defu` (first arg
22
37
  * wins).
@@ -47,7 +62,8 @@ export interface UIOptions {
47
62
  * })
48
63
  */
49
64
  export function ui(options: UIOptions = {}): AstroIntegration[] {
50
- const resolvedConfig = defu(options.ui ?? {}, defaultUIConfig)
65
+ const resolvedUI = defu(options.ui ?? {}, defaultUIConfig)
66
+ const resolvedConfig = { ...resolvedUI, logos: options.logos ?? {} }
51
67
 
52
68
  const virtualModuleId = "virtual:rimelight-ui"
53
69
  const resolvedVirtualModuleId = "\0" + virtualModuleId
@@ -74,10 +90,6 @@ export function ui(options: UIOptions = {}): AstroIntegration[] {
74
90
  router: false,
75
91
  scanPackages: ["@rimelight/ui"]
76
92
  }),
77
- Icons({
78
- compiler: "astro",
79
- autoInstall: true
80
- }),
81
93
  tailwindcss(),
82
94
  {
83
95
  name: "vite-plugin-rimelight-ui-config",
@@ -1,2 +1,2 @@
1
- export { default as starlightAddons } from "../plugins/starlightAddons"
2
- export type { StarlightAddonsConfig } from "../plugins/starlightAddons"
1
+ export { default as starlightAddons } from "../plugins/starlightAddons"
2
+ export type { StarlightAddonsConfig } from "../plugins/starlightAddons"