@rimelight/ui 0.0.44 → 0.0.45

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimelight/ui",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "private": false,
5
5
  "description": "Rimelight Entertainment's UI Package",
6
6
  "homepage": "https://rimelight.com/docs",
@@ -26,6 +26,10 @@
26
26
  "publishConfig": {
27
27
  "access": "public"
28
28
  },
29
+ "scripts": {
30
+ "astro": "astro",
31
+ "check": "vp check --fix && astro check"
32
+ },
29
33
  "dependencies": {
30
34
  "@unocss/vite": "66.8.1",
31
35
  "unocss": "66.8.1"
@@ -35,11 +39,11 @@
35
39
  "@astrojs/solid-js": "7.0.2",
36
40
  "@astrojs/ts-plugin": "1.10.11",
37
41
  "@astrojs/vue": "7.0.2",
38
- "@rimelight/config": "0.0.3",
39
- "astro": "7.2.7",
42
+ "@rimelight/config": "workspace:*",
43
+ "astro": "7.2.9",
40
44
  "solid-js": "1.9.15",
41
45
  "typescript": "6.0.3",
42
- "vue": "3.5.41"
46
+ "vue": "3.5.42"
43
47
  },
44
48
  "peerDependencies": {
45
49
  "@astrojs/solid-js": ">=7.0.1",
@@ -65,8 +69,5 @@
65
69
  "engines": {
66
70
  "node": ">=26.7.0"
67
71
  },
68
- "scripts": {
69
- "astro": "astro",
70
- "check": "vp check --fix && astro check"
71
- }
72
- }
72
+ "packageManager": "pnpm@12.0.0"
73
+ }
@@ -75,7 +75,7 @@ const RLSButton: Component<RLSButtonProps> = (allProps) => {
75
75
  justify: props.justify,
76
76
  block: props.block,
77
77
  square: props.square !== undefined ? props.square : !props.label && !props.children,
78
- rounded: props.rounded,
78
+ rounded: props.rounded ?? false,
79
79
  leading: isLeading(),
80
80
  trailing: isTrailing(),
81
81
  loading: props.loading,
@@ -15,9 +15,6 @@ const classes = dashboardSidebarTheme({
15
15
  ...Astro.props,
16
16
  collapsed: collapsible && collapsed
17
17
  });
18
-
19
- const collapsedWidth = "4rem";
20
- const defaultWidth = "16rem";
21
18
  ---
22
19
 
23
20
  <div
@@ -26,11 +23,10 @@ const defaultWidth = "16rem";
26
23
  data-collapsible={collapsible ? "true" : "false"}
27
24
  data-collapsed={collapsible && collapsed ? "true" : "false"}
28
25
  data-slot="root"
29
- class={classes.root}
26
+ class:list={[classes.root, className]}
30
27
  {...rest}
31
- style={`width: ${collapsible && collapsed ? collapsedWidth : defaultWidth}; min-width: ${collapsible && collapsed ? collapsedWidth : defaultWidth}; flex-shrink: 0; --width: ${defaultWidth}; --collapsed-width: ${collapsedWidth}`}
32
28
  >
33
- <div data-slot="header" class={classes.header} style="height: 4rem; min-height: 4rem; padding: 1rem 1.5rem; display: flex; align-items: center; gap: 0.75rem; box-sizing: border-box;">
29
+ <div data-slot="header" class={classes.header}>
34
30
  <slot name="header" />
35
31
  </div>
36
32
 
@@ -48,15 +44,15 @@ const defaultWidth = "16rem";
48
44
  <div
49
45
  data-dashboard-sidebar-mobile
50
46
  data-slot="content"
51
- class={classes.content + " fixed inset-y-0 left-0 z-50 w-64 bg-default shadow-xl border-e border-default transform -translate-x-full transition-transform duration-300"}
47
+ class:list={[classes.content, "fixed inset-y-0 left-0 z-50 w-72 max-w-[85vw] bg-default shadow-2xl border-e border-default transform -translate-x-full transition-transform duration-300 flex flex-col h-full"]}
52
48
  >
53
- <div data-slot="header" class={classes.header + " " + "sm:px-6"} data-menu>
49
+ <div data-slot="header" class:list={[classes.header, "sm:px-6 shrink-0"]} data-menu>
54
50
  <slot name="header" />
55
51
  </div>
56
- <div data-slot="body" class={classes.body + " " + "sm:px-6"} data-menu>
52
+ <div data-slot="body" class:list={[classes.body, "sm:px-6 overflow-y-auto flex-1"]} data-menu>
57
53
  <slot />
58
54
  </div>
59
- <div data-slot="footer" class={classes.footer + " " + "sm:px-6"} data-menu>
55
+ <div data-slot="footer" class:list={[classes.footer, "sm:px-6 shrink-0"]} data-menu>
60
56
  <slot name="footer" />
61
57
  </div>
62
58
  </div>
@@ -70,20 +66,34 @@ const defaultWidth = "16rem";
70
66
  const mobilePanel = document.querySelector<HTMLElement>('[data-dashboard-sidebar-mobile]');
71
67
  const overlay = document.querySelector<HTMLElement>('[data-dashboard-sidebar-overlay]');
72
68
 
73
- const toggleMobile = () => {
69
+ const openMobile = () => {
70
+ if (!mobilePanel || !overlay) return;
71
+ mobilePanel.classList.remove('-translate-x-full');
72
+ mobilePanel.classList.add('translate-x-0');
73
+ overlay.classList.remove('hidden');
74
+ };
75
+
76
+ const closeMobile = () => {
74
77
  if (!mobilePanel || !overlay) return;
75
- const isOpen = mobilePanel.classList.toggle('translate-x-0');
76
- mobilePanel.classList.toggle('-translate-x-full', !isOpen);
77
- overlay.classList.toggle('hidden', !isOpen);
78
+ mobilePanel.classList.add('-translate-x-full');
79
+ mobilePanel.classList.remove('translate-x-0');
80
+ overlay.classList.add('hidden');
81
+ };
82
+
83
+ const toggleMobile = () => {
84
+ if (!mobilePanel) return;
85
+ if (mobilePanel.classList.contains('translate-x-0')) {
86
+ closeMobile();
87
+ } else {
88
+ openMobile();
89
+ }
78
90
  };
79
91
 
80
92
  const collapseSidebar = (val?: boolean) => {
81
93
  if (!collapsible) return;
82
94
  const isCollapsed = val !== undefined ? val : sidebar.dataset.collapsed !== 'true';
83
- const w = isCollapsed ? '4rem' : '16rem';
84
- sidebar.style.width = w;
85
- sidebar.style.minWidth = w;
86
- sidebar.style.setProperty('--width', w);
95
+ sidebar.dataset.collapsed = isCollapsed ? 'true' : 'false';
96
+ sidebar.setAttribute('data-collapsed', isCollapsed ? 'true' : 'false');
87
97
 
88
98
  document.querySelectorAll('[data-dashboard-toggle="collapse"]').forEach(btn => {
89
99
  btn.querySelectorAll('[data-dashboard-collapse-icon]').forEach(el => {
@@ -92,16 +102,32 @@ const defaultWidth = "16rem";
92
102
  });
93
103
  };
94
104
 
95
- document.addEventListener('click', (e: MouseEvent) => {
105
+ const handleClick = (e: MouseEvent) => {
96
106
  const target = e.target as Element | null;
97
- const toggle = target?.closest<HTMLElement>('[data-dashboard-toggle]');
107
+ if (!target) return;
108
+
109
+ // Toggle buttons (mobile drawer + collapse)
110
+ const toggle = target.closest<HTMLElement>('[data-dashboard-toggle]');
98
111
  if (toggle) {
99
112
  const side = toggle.dataset.dashboardToggle;
100
113
  if (side === 'mobile') toggleMobile();
101
114
  if (side === 'collapse') collapseSidebar();
115
+ return;
116
+ }
117
+
118
+ // Backdrop overlay click
119
+ if (target.closest('[data-dashboard-sidebar-overlay]')) {
120
+ closeMobile();
121
+ return;
102
122
  }
103
123
 
104
- const navItem = target?.closest<HTMLElement>('[data-dashboard-nav]');
124
+ // Close the mobile drawer when clicking a navigation link inside it
125
+ if (target.closest('[data-dashboard-sidebar-mobile] a')) {
126
+ closeMobile();
127
+ return;
128
+ }
129
+
130
+ const navItem = target.closest<HTMLElement>('[data-dashboard-nav]');
105
131
  if (navItem) {
106
132
  const container = navItem.closest('[data-dashboard-nav-container]');
107
133
  if (container) {
@@ -113,10 +139,13 @@ const defaultWidth = "16rem";
113
139
  navItem.classList.add('bg-muted', 'text-highlighted');
114
140
  }
115
141
  }
116
- });
142
+ };
117
143
 
118
- overlay?.addEventListener('click', toggleMobile);
144
+ const handleKey = (e: KeyboardEvent) => {
145
+ if (e.key === 'Escape') closeMobile();
146
+ };
119
147
 
120
- (window as any).dashboardSidebar = { toggleMobile, collapseSidebar };
148
+ document.addEventListener('click', handleClick);
149
+ document.addEventListener('keydown', handleKey);
121
150
  })();
122
151
  </script>
@@ -3,12 +3,12 @@ import { defineTheme } from "../../resolver"
3
3
  export const dashboardSidebarTheme = defineTheme("dashboard-sidebar", {
4
4
  slots: ["root", "header", "body", "footer", "toggle", "handle", "content", "overlay"],
5
5
  base: {
6
- root: "group relative flex flex-col h-full min-h-0 min-w-16 w-64 shrink-0 transition-[width] duration-300",
6
+ root: "group relative hidden lg:flex flex-col h-full min-h-0 shrink-0 transition-[width] duration-300 w-64 min-w-64 max-w-64 data-[collapsed=true]:w-16 data-[collapsed=true]:min-w-16 data-[collapsed=true]:max-w-16 data-[collapsed=true]:overflow-hidden data-[collapsed=false]:w-64 data-[collapsed=false]:min-w-64 data-[collapsed=false]:max-w-64",
7
7
  header:
8
- "h-16 min-h-16 shrink-0 flex items-center gap-3 px-6 py-4 border-b border-default group-data-[collapsed=true]:justify-center group-data-[collapsed=true]:gap-0 group-data-[collapsed=true]:px-0",
9
- body: "flex flex-col gap-1 flex-1 overflow-y-auto px-3 py-3",
8
+ "h-16 min-h-16 shrink-0 flex items-center gap-3 px-6 py-4 border-b border-default group-data-[collapsed=true]:justify-center group-data-[collapsed=true]:items-center group-data-[collapsed=true]:gap-0 group-data-[collapsed=true]:px-0",
9
+ body: "flex flex-col gap-1 flex-1 overflow-y-auto px-3 py-3 group-data-[collapsed=true]:items-center group-data-[collapsed=true]:px-0 group-data-[collapsed=true]:overflow-hidden",
10
10
  footer:
11
- "shrink-0 flex items-center gap-1.5 px-3 py-3 group-data-[collapsed=true]:px-0 border-t border-default/40",
11
+ "shrink-0 flex items-center gap-1.5 px-3 py-3 border-t border-default/40 group-data-[collapsed=true]:justify-center group-data-[collapsed=true]:items-center group-data-[collapsed=true]:px-0",
12
12
  toggle: "",
13
13
  handle: "",
14
14
  content: "lg:hidden",
@@ -32,7 +32,7 @@ export const dashboardSidebarTheme = defineTheme("dashboard-sidebar", {
32
32
  },
33
33
  collapsed: {
34
34
  true: {
35
- root: "w-16 w-[var(--collapsed-width,4rem)] overflow-hidden",
35
+ root: "w-16 min-w-16 max-w-16 overflow-hidden",
36
36
  body: "overflow-hidden"
37
37
  }
38
38
  }
@@ -16,7 +16,7 @@ const RLSIcon: Component<IconProps> = (allProps) => {
16
16
  return (
17
17
  <span class={classes().root} data-slot="icon" aria-hidden="true" {...rest}>
18
18
  {resolved().isClass ? (
19
- <span class={`${resolved().content} size-full`} />
19
+ <span class={`${resolved().content} block size-full`} />
20
20
  ) : (
21
21
  <span innerHTML={resolved().content} />
22
22
  )}
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  import type { ModalProps } from "./modal"
3
3
  import { modalTheme } from "./modal.theme"
4
- import RLAIcon from "../icon/RLAIcon.astro"
4
+ import RLAButton from "../button/RLAButton.astro"
5
5
 
6
6
 
7
7
 
@@ -49,15 +49,18 @@ const modalId = `rla-modal-${Math.random().toString(36).substring(2, 9)}`
49
49
  data-unmount-on-hide={unmountOnHide ? "true" : "false"}
50
50
  {...rest}
51
51
  >
52
- <button
52
+ <RLAButton
53
53
  class={classes.closeButton}
54
54
  data-slot="close-button"
55
55
  type="button"
56
+ variant="ghost"
57
+ color="neutral"
58
+ size="sm"
59
+ square
60
+ leadingIcon="i-rl-close"
56
61
  data-dialog-close={modalId}
57
62
  aria-label="Close modal"
58
- >
59
- <RLAIcon name="i-rl-close" class="size-4" aria-hidden="true" />
60
- </button>
63
+ />
61
64
 
62
65
  <div class={classes.header} data-slot="header">
63
66
  {title && <h3 class={classes.title} data-slot="title">{title}</h3>}
@@ -10,7 +10,7 @@ import {
10
10
  } from "solid-js"
11
11
  import type { ModalProps } from "./modal"
12
12
  import { modalTheme } from "./modal.theme"
13
- import RLSIcon from "../icon/RLSIcon"
13
+ import RLSButton from "../button/RLSButton"
14
14
 
15
15
  export interface RLSModalProps extends ModalProps {
16
16
  onClose?: () => void
@@ -41,6 +41,7 @@ const RLSModal: Component<RLSModalProps> = (allProps) => {
41
41
 
42
42
  const closeOnClickOutside = () => props.closeOnClickOutside !== false
43
43
  const closeOnEscape = () => props.closeOnEscape !== false
44
+ const unmountOnHide = () => props.unmountOnHide !== false
44
45
 
45
46
  const handleClose = () => {
46
47
  props.onClose?.()
@@ -54,8 +55,8 @@ const RLSModal: Component<RLSModalProps> = (allProps) => {
54
55
  e.preventDefault()
55
56
  } else {
56
57
  e.preventDefault()
57
- handleClose()
58
58
  }
59
+ handleClose()
59
60
  }
60
61
  const handleClick = (e: MouseEvent) => {
61
62
  // Clicking the ::backdrop means e.target IS the dialog element
@@ -91,24 +92,28 @@ const RLSModal: Component<RLSModalProps> = (allProps) => {
91
92
  })
92
93
 
93
94
  return (
94
- <Show when={props.open || !props.unmountOnHide}>
95
+ <Show when={props.open || !unmountOnHide()}>
95
96
  <dialog
96
97
  ref={(el) => (dialogRef = el)}
97
- class={`w-full rounded-xl border border-default bg-default p-6 shadow-xl outline-none flex flex-col max-h-[90vh] overflow-y-auto text-highlighted backdrop:bg-black/60 backdrop:backdrop-blur-sm ${
98
- resolvedClasses().content || ""
99
- } ${props.class || ""}`}
98
+ class={`w-[calc(100%-1.5rem)] sm:w-full rounded-xl border border-default bg-default p-5 sm:p-6 shadow-xl outline-none flex flex-col max-h-[calc(100dvh-1.5rem)] sm:max-h-[90vh] overflow-y-auto text-highlighted backdrop:bg-black/60 backdrop:backdrop-blur-sm ${
99
+ props.open ? "" : "hidden"
100
+ } ${resolvedClasses().content || ""} ${props.class || ""}`}
101
+ data-state={props.open ? "open" : "closed"}
100
102
  data-slot="content"
101
103
  {...rest}
102
104
  >
103
- <button
105
+ <RLSButton
104
106
  type="button"
105
- class="absolute right-4 top-4 rounded-md p-1 text-muted hover:text-highlighted hover:bg-neutral-100 dark:hover:bg-neutral-800 transition cursor-pointer border-none bg-transparent"
106
- data-slot="close-button"
107
+ variant="ghost"
108
+ color="neutral"
109
+ size="sm"
110
+ square
111
+ leadingIcon="close"
107
112
  aria-label="Close modal"
113
+ data-slot="close-button"
114
+ class="absolute right-4 top-4 text-muted hover:text-highlighted"
108
115
  onClick={handleClose}
109
- >
110
- <RLSIcon name="close" size="sm" aria-hidden="true" />
111
- </button>
116
+ />
112
117
 
113
118
  {props.title || props.description || props.titleSlot || props.descriptionSlot ? (
114
119
  <div class={resolvedClasses().header || "mb-4"} data-slot="header">
@@ -17,8 +17,9 @@ export const modalTheme = defineTheme("modal", {
17
17
  trigger: "",
18
18
  backdrop: "fixed inset-0 z-50 bg-black/60 backdrop-blur-sm transition-all duration-300",
19
19
  content: [
20
- "fixed left-1/2 top-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl border border-default",
21
- "bg-default p-6 shadow-xl transition-all duration-300 outline-none",
20
+ "fixed left-1/2 top-1/2 z-50 w-[calc(100%-1.5rem)] sm:w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl border border-default",
21
+ "bg-default p-5 sm:p-6 shadow-xl transition-all duration-300 outline-none",
22
+ "max-h-[calc(100dvh-1.5rem)] sm:max-h-[90vh] overflow-y-auto",
22
23
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-1/2",
23
24
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-1/2"
24
25
  ],
@@ -27,8 +28,8 @@ export const modalTheme = defineTheme("modal", {
27
28
  description: "text-sm text-muted leading-relaxed",
28
29
  footer: "flex flex-col-reverse sm:flex-row sm:justify-end gap-2 mt-6",
29
30
  closeButton: [
30
- "absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100",
31
- "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"
31
+ "absolute right-4 top-4 opacity-70 transition-opacity hover:opacity-100",
32
+ "focus:outline-none"
32
33
  ]
33
34
  },
34
35
  variants: {
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Rimelight Entertainment
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.