@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.
Files changed (65) hide show
  1. package/package.json +7 -3
  2. package/src/components/Head.astro +199 -156
  3. package/src/components/ThemeToggle.astro +2 -2
  4. package/src/components/astro/RLAAccordion.astro +22 -0
  5. package/src/components/astro/RLAButton.astro +104 -118
  6. package/src/components/astro/RLAFooter.astro +17 -43
  7. package/src/components/astro/RLAHeader.astro +21 -80
  8. package/src/components/astro/RLAIcon.astro +14 -39
  9. package/src/components/astro/RLALogo.astro +14 -48
  10. package/src/components/astro/RLAPlaceholder.astro +11 -35
  11. package/src/components/astro/RLAQuote.astro +15 -0
  12. package/src/components/astro/RLAScrollToTop.astro +171 -221
  13. package/src/components/astro/RLASection.astro +210 -0
  14. package/src/components/vue/RLVButton.vue +166 -139
  15. package/src/components/vue/RLVFooter.vue +17 -54
  16. package/src/components/vue/RLVHeader.vue +22 -105
  17. package/src/components/vue/RLVIcon.vue +14 -45
  18. package/src/components/vue/RLVLogo.vue +11 -58
  19. package/src/components/vue/RLVPlaceholder.vue +14 -35
  20. package/src/components/vue/RLVScrollToTop.vue +18 -89
  21. package/src/components/vue/RLVSection.vue +166 -0
  22. package/src/composables/index.ts +0 -1
  23. package/src/env.d.ts +5 -0
  24. package/src/integrations/ui.ts +2 -6
  25. package/src/plugins/index.ts +5 -2
  26. package/src/plugins/starlightAddons/index.ts +3 -64
  27. package/src/plugins/starlightDocsApi/components/ApiEmits.astro +46 -0
  28. package/src/plugins/starlightDocsApi/components/ApiProps.astro +47 -0
  29. package/src/plugins/starlightDocsApi/components/ApiSlots.astro +50 -0
  30. package/src/plugins/starlightDocsApi/components/ApiTheme.astro +27 -0
  31. package/src/plugins/starlightDocsApi/extract-vue.ts +286 -0
  32. package/src/plugins/starlightDocsApi/index.ts +265 -0
  33. package/src/plugins/starlightDocsApi/types.ts +40 -0
  34. package/src/plugins/starlightDocsApi/utils.ts +45 -0
  35. package/src/themes/button.theme.ts +29 -14
  36. package/src/themes/footer.theme.ts +4 -6
  37. package/src/themes/header.theme.ts +4 -28
  38. package/src/themes/icon.theme.ts +4 -2
  39. package/src/themes/index.ts +15 -20
  40. package/src/themes/logo.theme.ts +4 -2
  41. package/src/themes/placeholder.theme.ts +4 -6
  42. package/src/themes/scroll-to-top.theme.ts +4 -6
  43. package/src/themes/section.theme.ts +187 -0
  44. package/src/types/componentVariant.ts +14 -0
  45. package/src/types/index.ts +1 -0
  46. package/src/utils/defineTheme.ts +11 -0
  47. package/src/utils/index.ts +3 -0
  48. package/src/utils/resolveClasses.ts +21 -0
  49. package/src/utils/useUi.ts +19 -0
  50. package/src/composables/useUi.ts +0 -27
  51. package/src/plugins/starlightAddons/Sidebar.astro +0 -89
  52. package/src/plugins/starlightAddons/data.ts +0 -39
  53. package/src/plugins/starlightAddons/libs/config.ts +0 -107
  54. package/src/plugins/starlightAddons/libs/content.ts +0 -20
  55. package/src/plugins/starlightAddons/libs/i18n.ts +0 -51
  56. package/src/plugins/starlightAddons/libs/locals.ts +0 -12
  57. package/src/plugins/starlightAddons/libs/pathname.ts +0 -22
  58. package/src/plugins/starlightAddons/libs/plugin.ts +0 -9
  59. package/src/plugins/starlightAddons/libs/sidebar.ts +0 -183
  60. package/src/plugins/starlightAddons/libs/vite.ts +0 -46
  61. package/src/plugins/starlightAddons/locals.d.ts +0 -14
  62. package/src/plugins/starlightAddons/middleware.ts +0 -132
  63. package/src/plugins/starlightAddons/overrides/Sidebar.astro +0 -8
  64. package/src/plugins/starlightAddons/schema.ts +0 -13
  65. package/src/plugins/starlightAddons/virtual.d.ts +0 -13
@@ -1,118 +1,104 @@
1
- ---
2
- import { scv, cx } from "css-variants"
3
- import { twMerge } from "tailwind-merge"
4
- import defu from "defu"
5
- import { buttonTheme } from "../../themes/button.theme.ts"
6
- import { getUIConfig } from "virtual:rimelight-ui"
7
-
8
- const button = scv({
9
- slots: [...buttonTheme.slots],
10
- base: buttonTheme.base,
11
- variants: buttonTheme.variants,
12
- compoundVariants: [...buttonTheme.compoundVariants],
13
- defaultVariants: buttonTheme.defaultVariants,
14
- classNameResolver: (...args) => twMerge(cx(...args)),
15
- });
16
-
17
- export interface RLAButtonProps {
18
- variant?: keyof typeof buttonTheme.variants.variant;
19
- color?: keyof typeof buttonTheme.variants.color;
20
- size?: keyof typeof buttonTheme.variants.size;
21
- href?: string;
22
- label?: string;
23
- leadingIcon?: string;
24
- trailingIcon?: string;
25
- loading?: boolean;
26
- square?: boolean;
27
- block?: boolean;
28
- active?: boolean;
29
- activeColor?: keyof typeof buttonTheme.variants.color;
30
- activeVariant?: keyof typeof buttonTheme.variants.variant;
31
- ui?: Partial<Record<string, string>>;
32
- class?: string;
33
- [key: string]: unknown;
34
- }
35
-
36
- const {
37
- variant = "solid",
38
- color = "primary",
39
- size = "md",
40
- class: className,
41
- ui: uiProp,
42
- href,
43
- label,
44
- leadingIcon,
45
- trailingIcon,
46
- loading = false,
47
- square = false,
48
- block = false,
49
- active = false,
50
- activeColor,
51
- activeVariant,
52
- ...rest
53
- } = Astro.props as RLAButtonProps
54
-
55
- const globalConfig = getUIConfig();
56
-
57
- const mergedUI = defu(
58
- uiProp ?? {},
59
- (globalConfig.button as Record<string, unknown>) ?? {},
60
- ) as Record<string, string | undefined>;
61
-
62
- const isLeading = (leadingIcon || Astro.slots.has("leading")) || loading
63
- const isTrailing = (trailingIcon || Astro.slots.has("trailing")) || (loading && !isLeading)
64
-
65
- const showLeadingIcon = loading
66
- ? "i-lucide-loader-circle"
67
- : leadingIcon
68
-
69
- const showTrailingIcon = loading
70
- ? "i-lucide-loader-circle"
71
- : trailingIcon
72
-
73
- const leadingClasses = loading ? "animate-spin" : ""
74
- const trailingClasses = loading ? "animate-spin" : ""
75
-
76
- const resolved = button({
77
- variant: active && activeVariant ? activeVariant : variant,
78
- color: active && activeColor ? activeColor : color,
79
- size,
80
- block,
81
- square: square || (!label && !Astro.slots.has("default")),
82
- leading: isLeading,
83
- trailing: isTrailing,
84
- loading,
85
- active
86
- });
87
-
88
- const Tag = href ? "a" : "button";
89
- ---
90
- <Tag
91
- class={twMerge(resolved.root, mergedUI.root, className)}
92
- data-slot="rla-button"
93
- {...(Tag === "a" ? { href } : {})}
94
- {...rest}
95
- >
96
- <slot name="leading" {...{ ui: resolved }}>
97
- {isLeading && (
98
- <span class={twMerge(resolved.leadingIcon, mergedUI.leadingIcon)} data-slot="leading-icon">
99
- <span class={twMerge(showLeadingIcon, leadingClasses)} aria-hidden="true" />
100
- </span>
101
- )}
102
- </slot>
103
-
104
- {label !== undefined && label !== null && (
105
- <span class={twMerge(resolved.label, mergedUI.label)} data-slot="label">
106
- {label}
107
- </span>
108
- )}
109
- {!label && <slot />}
110
-
111
- <slot name="trailing" {...{ ui: resolved }}>
112
- {isTrailing && (
113
- <span class={twMerge(resolved.trailingIcon, mergedUI.trailingIcon)} data-slot="trailing-icon">
114
- <span class={twMerge(showTrailingIcon, trailingClasses)} aria-hidden="true" />
115
- </span>
116
- )}
117
- </slot>
118
- </Tag>
1
+ ---
2
+ import { scv, cx } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentVariants, ComponentSlots } from "../../types"
5
+ import buttonTheme from "../../themes/button.theme"
6
+
7
+ const button = scv(buttonTheme)
8
+ type ButtonVariants = ComponentVariants<typeof buttonTheme>
9
+
10
+ export interface RLAButtonProps {
11
+ variant?: ButtonVariants['variant'];
12
+ color?: ButtonVariants['color'];
13
+ size?: ButtonVariants['size'];
14
+ href?: string;
15
+ label?: string;
16
+ leadingIcon?: string;
17
+ trailingIcon?: string;
18
+ loading?: boolean;
19
+ square?: boolean;
20
+ block?: boolean;
21
+ active?: boolean;
22
+ activeColor?: ButtonVariants['color'];
23
+ activeVariant?: ButtonVariants['variant'];
24
+ ui?: ComponentSlots<typeof buttonTheme>;
25
+ class?: any;
26
+ [key: string]: unknown;
27
+ }
28
+
29
+ const {
30
+ variant = "solid",
31
+ color = "primary",
32
+ size = "md",
33
+ href,
34
+ label,
35
+ leadingIcon,
36
+ trailingIcon,
37
+ loading = false,
38
+ square = false,
39
+ block = false,
40
+ active = false,
41
+ activeColor,
42
+ activeVariant,
43
+ ui: uiProp,
44
+ class: className,
45
+ ...rest
46
+ } = Astro.props as RLAButtonProps
47
+
48
+ const isLeading = !!(leadingIcon || Astro.slots.has("leading")) || loading
49
+ const isTrailing = !!(trailingIcon || Astro.slots.has("trailing")) || (loading && !isLeading)
50
+
51
+ const showLeadingIcon = loading
52
+ ? "i-lucide-loader-circle"
53
+ : leadingIcon
54
+
55
+ const showTrailingIcon = loading
56
+ ? "i-lucide-loader-circle"
57
+ : trailingIcon
58
+
59
+ const leadingIconClass = loading ? "animate-spin" : ""
60
+ const trailingIconClass = loading ? "animate-spin" : ""
61
+
62
+ const classes = resolveClasses(button, {
63
+ variant: active && activeVariant ? activeVariant : variant,
64
+ color: active && activeColor ? activeColor : color,
65
+ size,
66
+ block,
67
+ square: square || (!label && !Astro.slots.has("default")),
68
+ leading: isLeading,
69
+ trailing: isTrailing,
70
+ loading,
71
+ active
72
+ }, useUi("button", uiProp), className);
73
+
74
+ const Tag = href ? "a" : "button";
75
+ ---
76
+ <Tag
77
+ class={classes.root}
78
+ data-slot="root"
79
+ {...(Tag === "a" ? { href } : {})}
80
+ {...rest}
81
+ >
82
+ <slot name="leading" {...{ ui: classes }}>
83
+ {isLeading && (
84
+ <span class={classes.leadingIcon} data-slot="leading-icon">
85
+ <span class={cx(showLeadingIcon, leadingIconClass)} aria-hidden="true" />
86
+ </span>
87
+ )}
88
+ </slot>
89
+
90
+ {label !== undefined && label !== null && (
91
+ <span class={classes.label} data-slot="label">
92
+ {label}
93
+ </span>
94
+ )}
95
+ {!label && <slot />}
96
+
97
+ <slot name="trailing" {...{ ui: classes }}>
98
+ {isTrailing && (
99
+ <span class={classes.trailingIcon} data-slot="trailing-icon">
100
+ <span class={cx(showTrailingIcon, trailingIconClass)} aria-hidden="true" />
101
+ </span>
102
+ )}
103
+ </slot>
104
+ </Tag>
@@ -1,68 +1,42 @@
1
1
  ---
2
- import { scv, cx } from "css-variants";
3
- import { twMerge } from "tailwind-merge";
4
- import defu from "defu";
5
- import { footerTheme } from "../../themes/footer.theme.ts";
6
- import { getUIConfig } from "virtual:rimelight-ui";
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentVariants, ComponentSlots } from "../../types"
5
+ import footerTheme from "../../themes/footer.theme"
7
6
 
8
- const footer = scv({
9
- slots: [...footerTheme.slots],
10
- base: footerTheme.base,
11
- variants: footerTheme.variants,
12
- defaultVariants: footerTheme.defaultVariants,
13
- classNameResolver: (...args) => twMerge(cx(...args)),
14
- });
7
+ const footer = scv(footerTheme)
8
+ type FooterVariants = ComponentVariants<typeof footerTheme>
15
9
 
16
10
  export interface RLAFooterProps {
17
- /**
18
- * Whether to contain the footer content in a max-width container.
19
- * @default false
20
- */
21
- contain?: boolean;
22
- /**
23
- * UI overrides for individual slots, derived from the footer theme.
24
- */
25
- ui?: Partial<Record<keyof typeof footerTheme.base, string>>;
26
- /**
27
- * External class — applied to the root element.
28
- */
29
- class?: string;
30
- /**
31
- * Standard HTML attributes for <footer>
32
- */
11
+ contain?: FooterVariants['contain'];
12
+ ui?: ComponentSlots<typeof footerTheme>;
13
+ class?: any;
33
14
  [key: string]: unknown;
34
15
  }
35
16
 
36
17
  const {
37
18
  contain = false,
38
- class: className,
39
19
  ui: uiProp,
20
+ class: className,
40
21
  ...rest
41
22
  } = Astro.props as RLAFooterProps
42
23
 
43
- const globalConfig = getUIConfig();
44
-
45
- const mergedUI = defu(
46
- uiProp ?? {},
47
- (globalConfig.footer as Record<string, unknown>) ?? {},
48
- ) as Record<keyof typeof footerTheme.base, string | undefined>;
49
-
50
- const { root, container, left, center, right } = footer({ contain });
24
+ const classes = resolveClasses(footer, { contain }, useUi("footer", uiProp), className)
51
25
  ---
52
26
 
53
27
  <footer
54
- class:list={[twMerge(root, mergedUI.root, className)]}
55
- data-slot="rla-footer"
28
+ class:list={[classes.root]}
29
+ data-slot="root"
56
30
  {...rest}
57
31
  >
58
- <div class:list={[twMerge(container, mergedUI.container)]}>
59
- <div class:list={[twMerge(left, mergedUI.left)]} data-slot="footer-left">
32
+ <div class:list={[classes.container]}>
33
+ <div class:list={[classes.left]} data-slot="left">
60
34
  <slot name="left" />
61
35
  </div>
62
- <div class:list={[twMerge(center, mergedUI.center)]} data-slot="footer-center">
36
+ <div class:list={[classes.center]} data-slot="center">
63
37
  <slot name="center" />
64
38
  </div>
65
- <div class:list={[twMerge(right, mergedUI.right)]} data-slot="footer-right">
39
+ <div class:list={[classes.right]} data-slot="right">
66
40
  <slot name="right" />
67
41
  </div>
68
42
  </div>
@@ -1,59 +1,20 @@
1
1
  ---
2
- import { scv, cx } from "css-variants";
3
- import { twMerge } from "tailwind-merge";
4
- import defu from "defu";
5
- import { headerTheme } from "../../themes/header.theme.ts";
6
- import { getUIConfig } from "virtual:rimelight-ui";
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentVariants, ComponentSlots } from "../../types"
5
+ import headerTheme from "../../themes/header.theme"
7
6
 
8
- const header = scv({
9
- slots: [...headerTheme.slots],
10
- base: headerTheme.base,
11
- variants: headerTheme.variants,
12
- defaultVariants: headerTheme.defaultVariants,
13
- classNameResolver: (...args) => twMerge(cx(...args)),
14
- });
7
+ const header = scv(headerTheme)
8
+ type HeaderVariants = ComponentVariants<typeof headerTheme>
15
9
 
16
10
  export interface RLAHeaderProps {
17
- /**
18
- * Whether to contain the header content in a max-width container.
19
- * @default true
20
- */
21
- contain?: boolean;
22
- /**
23
- * Sticky positioning when `fixed` is false.
24
- * @default true
25
- */
26
- sticky?: boolean;
27
- /**
28
- * Switches to `position: fixed; left: 0; right: 0` (layer mode).
29
- * When true, `stackIndex` controls the exact position and layer order.
30
- * A module `<script>` is emitted to apply styles and attach scroll listeners.
31
- * @default false
32
- */
33
- fixed?: boolean;
34
- /**
35
- * Controls z-index when `fixed` is true: `z-index = 100 - stackIndex`.
36
- * @default 0
37
- */
11
+ contain?: HeaderVariants['contain'];
12
+ sticky?: HeaderVariants['sticky'];
13
+ fixed?: HeaderVariants['fixed'];
38
14
  stackIndex?: number;
39
- /**
40
- * When true, hides the header on scroll-down and shows it on scroll-up.
41
- * Implemented via a bundled Astro `<script>` — no Vue hydration needed.
42
- * Only meaningful when `fixed` is true.
43
- * @default false
44
- */
45
15
  hideOnScroll?: boolean;
46
- /**
47
- * UI overrides for individual slots, derived from the header theme.
48
- */
49
- ui?: Partial<Record<keyof typeof headerTheme.base, string>>;
50
- /**
51
- * External class — applied to the root element.
52
- */
53
- class?: string;
54
- /**
55
- * Standard HTML attributes for <header>.
56
- */
16
+ ui?: ComponentSlots<typeof headerTheme>;
17
+ class?: any;
57
18
  [key: string]: unknown;
58
19
  }
59
20
 
@@ -63,74 +24,54 @@ const {
63
24
  fixed = false,
64
25
  stackIndex = 0,
65
26
  hideOnScroll = false,
66
- class: className,
67
27
  ui: uiProp,
28
+ class: className,
68
29
  ...rest
69
30
  } = Astro.props as RLAHeaderProps;
70
31
 
71
- const globalConfig = getUIConfig();
72
-
73
- const mergedUI = defu(
74
- uiProp ?? {},
75
- (globalConfig.header as Record<string, unknown>) ?? {},
76
- ) as Record<keyof typeof headerTheme.base, string | undefined>;
77
-
78
- // Resolve classes — note: sticky variant is suppressed when fixed is true,
79
- // since the fixed variant's classes replace it.
80
- const { root, content, container, left, center, right } = header({
32
+ const classes = resolveClasses(header, {
81
33
  contain,
82
34
  sticky: fixed ? false : sticky,
83
35
  fixed,
84
- });
36
+ }, useUi("header", uiProp), className);
85
37
 
86
- // Build a unique ID so the script can target this specific header element.
87
38
  const headerId = `rla-header-${Math.random().toString(36).slice(2, 8)}`;
88
39
  const zIndex = 100 - stackIndex;
89
40
  ---
90
41
 
91
42
  <header
92
43
  id={headerId}
93
- class:list={[twMerge(root, mergedUI.root, className)]}
44
+ data-slot="root"
45
+ class:list={[classes.root]}
94
46
  data-rla-header={fixed ? "true" : undefined}
95
47
  data-stack-index={stackIndex}
96
48
  data-hide-on-scroll={String(hideOnScroll)}
97
49
  style={fixed ? `z-index: ${zIndex};` : undefined}
98
50
  {...rest}
99
51
  >
100
- <!--
101
- content wrapper: present in all modes; in fixed+hideOnScroll mode the inline
102
- script observes this element's offsetHeight for accurate measurement.
103
- -->
104
- <div class:list={[twMerge(content, mergedUI.content)]} data-header-content>
105
- <div class:list={[twMerge(container, mergedUI.container)]}>
106
- <div class:list={[twMerge(left, mergedUI.left)]} data-slot="header-left">
52
+ <div class:list={[classes.content]} data-header-content>
53
+ <div class:list={[classes.container]}>
54
+ <div class:list={[classes.left]} data-slot="left">
107
55
  <slot name="left" />
108
56
  </div>
109
- <div class:list={[twMerge(center, mergedUI.center)]} data-slot="header-center">
57
+ <div class:list={[classes.center]} data-slot="center">
110
58
  <slot name="center" />
111
59
  </div>
112
- <div class:list={[twMerge(right, mergedUI.right)]} data-slot="header-right">
60
+ <div class:list={[classes.right]} data-slot="right">
113
61
  <slot name="right" />
114
62
  </div>
115
63
  </div>
116
64
  </div>
117
65
  </header>
118
66
 
119
- {/*
120
- Astro Module Script — automatically hydrates all static Astro headers
121
- with the global Vanilla JS stack manager. It only executes once per page
122
- load, managing all headers efficiently.
123
- */}
124
67
  {fixed && (
125
68
  <script>
126
69
  import { getHeaderStack } from "../../utils/headerStack";
127
70
 
128
- // This script runs exactly once per page load, managing all Astro headers
129
71
  const stack = getHeaderStack();
130
72
  const headers = document.querySelectorAll("[data-rla-header='true']");
131
73
 
132
74
  headers.forEach(header => {
133
- // Prevent double-initialization
134
75
  if ((header as any)._rl_initialized) return;
135
76
  (header as any)._rl_initialized = true;
136
77
 
@@ -1,61 +1,36 @@
1
1
  ---
2
- import { scv, cx } from "css-variants"
3
- import { twMerge } from "tailwind-merge"
4
- import defu from "defu"
5
- import { iconTheme } from "../../themes/icon.theme"
6
- import { getUIConfig } from "virtual:rimelight-ui"
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentVariants, ComponentSlots } from "../../types"
5
+ import iconTheme from "../../themes/icon.theme"
7
6
 
8
- const icon = scv({
9
- slots: [...iconTheme.slots],
10
- base: iconTheme.base,
11
- variants: iconTheme.variants,
12
- defaultVariants: iconTheme.defaultVariants,
13
- classNameResolver: (...args) => twMerge(cx(...args))
14
- })
7
+ const icon = scv(iconTheme)
8
+ type IconVariants = ComponentVariants<typeof iconTheme>
15
9
 
16
10
  export interface RLAIconProps {
17
- /**
18
- * Icon name following the UnoCSS icons format.
19
- * @example "i-lucide-home"
20
- */
21
11
  name: string
22
- /**
23
- * Size variant for the icon.
24
- */
25
- size?: keyof typeof iconTheme.variants.size
26
- /**
27
- * External class applied to the root element.
28
- */
29
- class?: string
30
- /**
31
- * UI overrides for individual slots.
32
- */
33
- ui?: Partial<Record<keyof typeof iconTheme.base, string>>
12
+ size?: IconVariants['size']
13
+ ui?: ComponentSlots<typeof iconTheme>
14
+ class?: any
34
15
  [key: string]: unknown
35
16
  }
36
17
 
37
18
  const {
38
19
  name,
39
20
  size = "md",
40
- class: className,
41
21
  ui: uiProp,
22
+ class: className,
42
23
  ...rest
43
24
  } = Astro.props as RLAIconProps
44
25
 
45
- const globalConfig = getUIConfig()
46
-
47
- const mergedUI = defu(
48
- uiProp ?? {},
49
- (globalConfig.icon as Record<string, unknown>) ?? {}
50
- ) as Record<keyof typeof iconTheme.base, string | undefined>
51
-
52
- const { root } = icon({ size })
26
+ const classes = resolveClasses(icon, { size }, useUi("icon", uiProp), className)
53
27
  ---
54
28
 
55
29
  <span
56
- class={twMerge(root, mergedUI.root, className, name)}
57
- data-slot="rla-icon"
30
+ class={classes.root}
31
+ data-slot="root"
58
32
  aria-hidden="true"
59
33
  {...rest}
60
34
  >
35
+ <span class={name} />
61
36
  </span>
@@ -1,48 +1,19 @@
1
1
  ---
2
- import { scv, cx } from "css-variants"
3
- import { twMerge } from "tailwind-merge"
4
- import defu from "defu"
5
- import { logoTheme } from "../../themes/logo.theme.ts"
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import type { ComponentSlots } from "../../types"
5
+ import logoTheme from "../../themes/logo.theme"
6
6
  import { getUIConfig } from "virtual:rimelight-ui"
7
7
 
8
- const logo = scv({
9
- slots: [...logoTheme.slots],
10
- base: logoTheme.base,
11
- variants: logoTheme.variants,
12
- defaultVariants: logoTheme.defaultVariants,
13
- classNameResolver: (...args) => twMerge(cx(...args)),
14
- });
8
+ const logo = scv(logoTheme)
15
9
 
16
10
  export interface RLALogoProps {
17
- /**
18
- * The variant of the logo to display.
19
- * @default "logomark"
20
- */
21
11
  variant?: string;
22
- /**
23
- * Override the color mode.
24
- */
25
12
  mode?: "color" | "white" | "black";
26
- /**
27
- * The URL to link to.
28
- * @default "/"
29
- */
30
13
  href?: string;
31
- /**
32
- * UI overrides for individual slots, derived from the logo theme.
33
- */
34
- ui?: Partial<Record<keyof typeof logoTheme.base, string>>;
35
- /**
36
- * External class — applied to the root element.
37
- */
38
- class?: string;
39
- /**
40
- * The alt text for the logo image.
41
- */
42
14
  alt?: string;
43
- /**
44
- * Standard HTML attributes for <a>
45
- */
15
+ ui?: ComponentSlots<typeof logoTheme>;
16
+ class?: any;
46
17
  [key: string]: unknown;
47
18
  }
48
19
 
@@ -50,22 +21,17 @@ const {
50
21
  variant = "logomark",
51
22
  mode,
52
23
  href = "/",
53
- class: className,
54
- ui: uiProp,
55
24
  alt,
25
+ ui: uiProp,
26
+ class: className,
56
27
  ...rest
57
28
  } = Astro.props as RLALogoProps;
58
29
 
59
- const globalConfig = getUIConfig();
60
-
61
- const mergedUI = defu(
62
- uiProp ?? {},
63
- (globalConfig.logo as Record<string, unknown>) ?? {},
64
- ) as Record<keyof typeof logoTheme.base, string | undefined>;
65
-
66
- const { root } = logo();
30
+ const classes = resolveClasses(logo, {}, useUi("logo", uiProp), className);
67
31
 
32
+ const globalConfig = getUIConfig();
68
33
  const rcLogos = globalConfig.logos as Record<string, any>;
34
+
69
35
  let logoSrc: string | null = null;
70
36
 
71
37
  if (rcLogos && typeof rcLogos === "object") {
@@ -82,10 +48,10 @@ const isIcon = logoSrc && (logoSrc.includes(":") || logoSrc.startsWith("i-"));
82
48
  ---
83
49
 
84
50
  <a
85
- class={twMerge(root, mergedUI.root, className)}
51
+ class={classes.root}
86
52
  href={href}
87
53
  aria-label={alt || variant}
88
- data-slot="rla-logo"
54
+ data-slot="root"
89
55
  {...rest}
90
56
  >
91
57
  {logoSrc ? (