@rimelight/ui 0.0.7 → 0.0.9

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.7",
3
+ "version": "0.0.9",
4
4
  "private": false,
5
5
  "description": "Rimelight Entertainment UI Library.",
6
6
  "homepage": "https://rimelight.com/docs",
@@ -25,7 +25,6 @@
25
25
  "./components/*": "./src/components/*",
26
26
  "./components/astro/*": "./src/components/astro/*",
27
27
  "./components/vue/*": "./src/components/vue/*",
28
- "./components/nuxt/*": "./src/components/nuxt/*",
29
28
  "./themes": "./src/themes/index.ts",
30
29
  "./themes/*": "./src/themes/*",
31
30
  "./composables": "./src/composables/index.ts",
@@ -35,9 +34,11 @@
35
34
  "./utils": "./src/utils/index.ts",
36
35
  "./utils/*": "./src/utils/*",
37
36
  "./integrations": "./src/integrations/index.ts",
37
+ "./integrations/vue-entrypoint": "./src/integrations/vue-entrypoint.ts",
38
38
  "./integrations/*": "./src/integrations/*",
39
39
  "./middleware": "./src/middleware/index.ts",
40
40
  "./middleware/*": "./src/middleware/*",
41
+ "./nuxt": "./src/nuxt.ts",
41
42
  "./*": "./src/*"
42
43
  },
43
44
  "publishConfig": {
@@ -47,11 +48,12 @@
47
48
  "@astrojs/vue": "6.0.1",
48
49
  "@iconify-json/lucide": "^1.2.102",
49
50
  "@nuxt/ui": "4.6.1",
51
+ "@tailwindcss/vite": "^4.2.3",
50
52
  "css-variants": "2.3.5",
51
53
  "defu": "6.1.6",
52
54
  "embla-carousel": "8.6.0",
53
55
  "tailwind-merge": "^3.3.1",
54
- "tailwindcss": "4.2.2",
56
+ "tailwindcss": "^4.2.3",
55
57
  "unplugin-icons": "23.0.1"
56
58
  },
57
59
  "devDependencies": {
@@ -1,153 +1,153 @@
1
- ---
2
- import { ClientRouter } from 'astro:transitions';
3
- import type { SiteConfig } from '@/config';
4
- import UApp from './nuxt/App.vue';
5
-
6
- export interface HeadProps {
7
- /** Page title */
8
- title?: string;
9
- /** Page description */
10
- description?: string;
11
- /** Open Graph image URL */
12
- ogImage?: string;
13
- /** Whether to prevent indexing */
14
- noindex?: boolean;
15
- /** Whether this is a 404 page */
16
- is404?: boolean;
17
- /** Robots metadata (overrides noindex/is404 logic if provided) */
18
- robots?: string;
19
- /** Canonical URL */
20
- canonical?: string;
21
- /** Language alternates for i18n */
22
- languageAlternates?: Array<{ hreflang: string; href: string }>;
23
- /** Site configuration for defaults */
24
- config?: SiteConfig;
25
- /** Whether to enable View Transitions (ClientRouter) */
26
- transitions?: boolean;
27
- /** Meta charset */
28
- charset?: string;
29
- /** Meta viewport */
30
- viewport?: string;
31
- }
32
-
33
- const {
34
- title,
35
- description,
36
- ogImage,
37
- noindex = false,
38
- is404 = false,
39
- robots,
40
- canonical,
41
- languageAlternates = [],
42
- config,
43
- transitions = true,
44
- charset = "utf-8",
45
- viewport = "width=device-width,initial-scale=1",
46
- } = Astro.props as HeadProps
47
-
48
- // Resolve defaults from config if available
49
- const siteName = config?.name || "Rimelight";
50
- const siteUrl = config?.url || "";
51
- const siteDescription = config?.description || "";
52
- const ogImageFallback = config?.seo?.ogImageFallback || config?.ogImage || "";
53
- const themeColor = config?.branding?.colors?.themeColor;
54
- const favicon = config?.branding?.favicon?.svg || "/favicon.svg";
55
- const twitterHandle = config?.seo?.authorHandle;
56
- const titleTemplate = config?.seo?.titleTemplate || `%s | ${siteName}`;
57
-
58
- // Calculated Values
59
- const displayTitle = is404
60
- ? `404 - Not Found | ${siteName}`
61
- : title
62
- ? titleTemplate.replace('%s', title)
63
- : siteName;
64
-
65
- const finalDescription = description || siteDescription;
66
- const safeDescription = finalDescription && config?.seo?.maxDescriptionLength
67
- ? (finalDescription.length > config.seo.maxDescriptionLength
68
- ? finalDescription.slice(0, config.seo.maxDescriptionLength - 3) + "..."
69
- : finalDescription)
70
- : finalDescription;
71
-
72
- const finalOgImage = ogImage || ogImageFallback;
73
- const absoluteOgImage = finalOgImage
74
- ? (finalOgImage.startsWith('http') ? finalOgImage : `${siteUrl}${finalOgImage}`)
75
- : undefined;
76
-
77
- const finalCanonical = canonical || (!is404 ? Astro.url.href : undefined);
78
- ---
79
-
80
- <!-- Basic Metadata -->
81
- <meta charset={charset} />
82
- <meta name="viewport" content={viewport} />
83
- <meta name="generator" content={Astro.generator} />
84
-
85
- <!-- SEO -->
86
- <title>{displayTitle}</title>
87
- {safeDescription && <meta name="description" content={safeDescription} />}
88
- {robots ? <meta name="robots" content={robots} /> : (noindex || is404) && <meta name="robots" content="noindex, nofollow" />}
89
- {finalCanonical && <link rel="canonical" href={finalCanonical} />}
90
-
91
- <!-- i18n Alternates -->
92
- {languageAlternates.map((alt) => (
93
- <link rel="alternate" hreflang={alt.hreflang} href={alt.href} />
94
- ))}
95
-
96
- <!-- Open Graph / Facebook -->
97
- <meta property="og:type" content="website" />
98
- <meta property="og:url" content={Astro.url.href} />
99
- <meta property="og:title" content={title || siteName} />
100
- {safeDescription && <meta property="og:description" content={safeDescription} />}
101
- {absoluteOgImage && <meta property="og:image" content={absoluteOgImage} />}
102
- <meta property="og:site_name" content={siteName} />
103
-
104
- <!-- Twitter -->
105
- <meta property="twitter:card" content="summary_large_image" />
106
- <meta property="twitter:url" content={Astro.url.href} />
107
- <meta property="twitter:title" content={title || siteName} />
108
- {safeDescription && <meta property="twitter:description" content={safeDescription} />}
109
- {absoluteOgImage && <meta property="twitter:image" content={absoluteOgImage} />}
110
- {twitterHandle && <meta property="twitter:site" content={twitterHandle} />}
111
- {twitterHandle && <meta property="twitter:creator" content={twitterHandle} />}
112
-
113
- <!-- Icons -->
114
- <link rel="icon" type="image/svg+xml" href={favicon} />
115
-
116
- <!-- Theme -->
117
- {themeColor && <meta name="theme-color" content={themeColor} />}
118
-
119
- <script is:inline>
120
- const theme = (() => {
121
- if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
122
- return localStorage.getItem('theme');
123
- }
124
- if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
125
- return 'dark';
126
- }
127
- return 'light';
128
- })();
129
-
130
- if (theme === 'dark') {
131
- document.documentElement.classList.add('dark');
132
- } else {
133
- document.documentElement.classList.remove('dark');
134
- }
135
-
136
- window.localStorage.setItem('theme', theme);
137
- </script>
138
-
139
- <script>
140
- document.addEventListener('astro:after-swap', () => {
141
- if (localStorage.getItem('theme') === 'dark') {
142
- document.documentElement.classList.add('dark');
143
- } else {
144
- document.documentElement.classList.remove('dark');
145
- }
146
- });
147
- </script>
148
-
149
- {transitions && <ClientRouter />}
150
-
151
- <UApp client:load>
152
- <slot />
153
- </UApp>
1
+ ---
2
+ import { ClientRouter } from 'astro:transitions';
3
+ import type { SiteConfig } from '@/config';
4
+ import { App } from '../nuxt.ts';
5
+
6
+ export interface HeadProps {
7
+ /** Page title */
8
+ title?: string;
9
+ /** Page description */
10
+ description?: string;
11
+ /** Open Graph image URL */
12
+ ogImage?: string;
13
+ /** Whether to prevent indexing */
14
+ noindex?: boolean;
15
+ /** Whether this is a 404 page */
16
+ is404?: boolean;
17
+ /** Robots metadata (overrides noindex/is404 logic if provided) */
18
+ robots?: string;
19
+ /** Canonical URL */
20
+ canonical?: string;
21
+ /** Language alternates for i18n */
22
+ languageAlternates?: Array<{ hreflang: string; href: string }>;
23
+ /** Site configuration for defaults */
24
+ config?: SiteConfig;
25
+ /** Whether to enable View Transitions (ClientRouter) */
26
+ transitions?: boolean;
27
+ /** Meta charset */
28
+ charset?: string;
29
+ /** Meta viewport */
30
+ viewport?: string;
31
+ }
32
+
33
+ const {
34
+ title,
35
+ description,
36
+ ogImage,
37
+ noindex = false,
38
+ is404 = false,
39
+ robots,
40
+ canonical,
41
+ languageAlternates = [],
42
+ config,
43
+ transitions = true,
44
+ charset = "utf-8",
45
+ viewport = "width=device-width,initial-scale=1",
46
+ } = Astro.props as HeadProps
47
+
48
+ // Resolve defaults from config if available
49
+ const siteName = config?.name || "Rimelight";
50
+ const siteUrl = config?.url || "";
51
+ const siteDescription = config?.description || "";
52
+ const ogImageFallback = config?.seo?.ogImageFallback || config?.ogImage || "";
53
+ const themeColor = config?.branding?.colors?.themeColor;
54
+ const favicon = config?.branding?.favicon?.svg || "/favicon.svg";
55
+ const twitterHandle = config?.seo?.authorHandle;
56
+ const titleTemplate = config?.seo?.titleTemplate || `%s | ${siteName}`;
57
+
58
+ // Calculated Values
59
+ const displayTitle = is404
60
+ ? `404 - Not Found | ${siteName}`
61
+ : title
62
+ ? titleTemplate.replace('%s', title)
63
+ : siteName;
64
+
65
+ const finalDescription = description || siteDescription;
66
+ const safeDescription = finalDescription && config?.seo?.maxDescriptionLength
67
+ ? (finalDescription.length > config.seo.maxDescriptionLength
68
+ ? finalDescription.slice(0, config.seo.maxDescriptionLength - 3) + "..."
69
+ : finalDescription)
70
+ : finalDescription;
71
+
72
+ const finalOgImage = ogImage || ogImageFallback;
73
+ const absoluteOgImage = finalOgImage
74
+ ? (finalOgImage.startsWith('http') ? finalOgImage : `${siteUrl}${finalOgImage}`)
75
+ : undefined;
76
+
77
+ const finalCanonical = canonical || (!is404 ? Astro.url.href : undefined);
78
+ ---
79
+
80
+ <!-- Basic Metadata -->
81
+ <meta charset={charset} />
82
+ <meta name="viewport" content={viewport} />
83
+ <meta name="generator" content={Astro.generator} />
84
+
85
+ <!-- SEO -->
86
+ <title>{displayTitle}</title>
87
+ {safeDescription && <meta name="description" content={safeDescription} />}
88
+ {robots ? <meta name="robots" content={robots} /> : (noindex || is404) && <meta name="robots" content="noindex, nofollow" />}
89
+ {finalCanonical && <link rel="canonical" href={finalCanonical} />}
90
+
91
+ <!-- i18n Alternates -->
92
+ {languageAlternates.map((alt) => (
93
+ <link rel="alternate" hreflang={alt.hreflang} href={alt.href} />
94
+ ))}
95
+
96
+ <!-- Open Graph / Facebook -->
97
+ <meta property="og:type" content="website" />
98
+ <meta property="og:url" content={Astro.url.href} />
99
+ <meta property="og:title" content={title || siteName} />
100
+ {safeDescription && <meta property="og:description" content={safeDescription} />}
101
+ {absoluteOgImage && <meta property="og:image" content={absoluteOgImage} />}
102
+ <meta property="og:site_name" content={siteName} />
103
+
104
+ <!-- Twitter -->
105
+ <meta property="twitter:card" content="summary_large_image" />
106
+ <meta property="twitter:url" content={Astro.url.href} />
107
+ <meta property="twitter:title" content={title || siteName} />
108
+ {safeDescription && <meta property="twitter:description" content={safeDescription} />}
109
+ {absoluteOgImage && <meta property="twitter:image" content={absoluteOgImage} />}
110
+ {twitterHandle && <meta property="twitter:site" content={twitterHandle} />}
111
+ {twitterHandle && <meta property="twitter:creator" content={twitterHandle} />}
112
+
113
+ <!-- Icons -->
114
+ <link rel="icon" type="image/svg+xml" href={favicon} />
115
+
116
+ <!-- Theme -->
117
+ {themeColor && <meta name="theme-color" content={themeColor} />}
118
+
119
+ <script is:inline>
120
+ const theme = (() => {
121
+ if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
122
+ return localStorage.getItem('theme');
123
+ }
124
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
125
+ return 'dark';
126
+ }
127
+ return 'light';
128
+ })();
129
+
130
+ if (theme === 'dark') {
131
+ document.documentElement.classList.add('dark');
132
+ } else {
133
+ document.documentElement.classList.remove('dark');
134
+ }
135
+
136
+ window.localStorage.setItem('theme', theme);
137
+ </script>
138
+
139
+ <script>
140
+ document.addEventListener('astro:after-swap', () => {
141
+ if (localStorage.getItem('theme') === 'dark') {
142
+ document.documentElement.classList.add('dark');
143
+ } else {
144
+ document.documentElement.classList.remove('dark');
145
+ }
146
+ });
147
+ </script>
148
+
149
+ {transitions && <ClientRouter />}
150
+
151
+ <App client:load>
152
+ <slot />
153
+ </App>
package/src/env.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  /// <reference types="astro/client" />
2
2
 
3
+ declare module "virtual:nuxt-ui-plugins" {
4
+ import type { Plugin } from "vue"
5
+ const plugin: Plugin
6
+ export default plugin
7
+ }
8
+
3
9
  declare module "virtual:rimelight-ui" {
4
10
  import type { DefaultUIConfig } from "../themes"
5
11
 
@@ -1,106 +1,112 @@
1
- import path from "node:path"
2
- import { fileURLToPath } from "node:url"
3
- import type { AstroIntegration } from "astro"
4
- import vue from "@astrojs/vue"
5
- import uiPlugin from "@nuxt/ui/vite"
6
- import defu from "defu"
7
- import Icons from "unplugin-icons/vite"
8
- import { defaultUIConfig } from "../themes"
9
-
10
- const nuxtUIEntry = fileURLToPath(import.meta.resolve("@nuxt/ui"))
11
- const nuxtUIComponentsPath = path.join(path.dirname(nuxtUIEntry), "runtime/components")
12
-
13
- /**
14
- * Shape of the `ui` config that can be passed to the integration.
15
- */
16
- export type UIConfigOverrides = {
17
- button?: Partial<(typeof defaultUIConfig)["button"]>
18
- header?: Partial<(typeof defaultUIConfig)["header"]>
19
- }
20
-
21
- export interface UIOptions {
22
- /**
23
- * Global UI overrides applied to all components. Merged with defaults via `defu` (first arg
24
- * wins).
25
- */
26
- ui?: UIConfigOverrides
27
- }
28
-
29
- /**
30
- * Astro integration for `@rimelight/ui`.
31
- *
32
- * Provides global UI configuration via a virtual module. Components import `virtual:rimelight-ui`
33
- * to access the merged config.
34
- *
35
- * @example
36
- * // astro.config.mjs
37
- * import { ui } from "@rimelight/ui/integrations"
38
- *
39
- * export default defineConfig({
40
- * integrations: [
41
- * ui({
42
- * ui: {
43
- * button: {
44
- * defaultVariants: { variant: "primary" }
45
- * }
46
- * }
47
- * })
48
- * ]
49
- * })
50
- */
51
- export function ui(options: UIOptions = {}): AstroIntegration[] {
52
- const resolvedConfig = defu(options.ui ?? {}, defaultUIConfig)
53
-
54
- const virtualModuleId = "virtual:rimelight-ui"
55
- const resolvedVirtualModuleId = "\0" + virtualModuleId
56
-
57
- const rimelightUIIntegration: AstroIntegration = {
58
- name: "@rimelight/ui",
59
- hooks: {
60
- "astro:config:setup": ({ updateConfig, logger }) => {
61
- logger.info("Initializing @rimelight/ui core")
62
-
63
- updateConfig({
64
- vite: {
65
- resolve: {
66
- alias: {
67
- "@rimelight/ui/components/nuxt/": `${nuxtUIComponentsPath}/`
68
- }
69
- },
70
- plugins: [
71
- uiPlugin({
72
- router: false,
73
- scanPackages: ["@rimelight/ui"]
74
- }),
75
- Icons({
76
- compiler: "astro",
77
- autoInstall: true
78
- }),
79
- {
80
- name: "vite-plugin-rimelight-ui-config",
81
- enforce: "pre",
82
- resolveId(id: string) {
83
- if (id === virtualModuleId) return resolvedVirtualModuleId
84
- return null
85
- },
86
- load(id: string) {
87
- if (id === resolvedVirtualModuleId) {
88
- return `export const getUIConfig = () => (${JSON.stringify(resolvedConfig)});`
89
- }
90
- return null
91
- }
92
- }
93
- ]
94
- }
95
- })
96
- }
97
- }
98
- }
99
-
100
- return [
101
- vue({
102
- appEntrypoint: "@rimelight/ui/integrations/vue-entrypoint"
103
- }),
104
- rimelightUIIntegration
105
- ]
106
- }
1
+ import type { AstroIntegration } from "astro"
2
+ import vue from "@astrojs/vue"
3
+ import uiPlugin from "@nuxt/ui/vite"
4
+ import defu from "defu"
5
+ import Icons from "unplugin-icons/vite"
6
+ import tailwindcss from "@tailwindcss/vite"
7
+ import { defaultUIConfig } from "../themes"
8
+
9
+ /**
10
+ * Shape of the `ui` config that can be passed to the integration.
11
+ */
12
+ export type UIConfigOverrides = {
13
+ button?: Partial<(typeof defaultUIConfig)["button"]>
14
+ header?: Partial<(typeof defaultUIConfig)["header"]>
15
+ }
16
+
17
+ export interface UIOptions {
18
+ /**
19
+ * Global UI overrides applied to all components. Merged with defaults via `defu` (first arg
20
+ * wins).
21
+ */
22
+ ui?: UIConfigOverrides
23
+ }
24
+
25
+ /**
26
+ * Astro integration for `@rimelight/ui`.
27
+ *
28
+ * Provides global UI configuration via a virtual module. Components import `virtual:rimelight-ui`
29
+ * to access the merged config.
30
+ *
31
+ * @example
32
+ * // astro.config.mjs
33
+ * import { ui } from "@rimelight/ui/integrations"
34
+ *
35
+ * export default defineConfig({
36
+ * integrations: [
37
+ * ui({
38
+ * ui: {
39
+ * button: {
40
+ * defaultVariants: { variant: "primary" }
41
+ * }
42
+ * }
43
+ * })
44
+ * ]
45
+ * })
46
+ */
47
+ export function ui(options: UIOptions = {}): AstroIntegration[] {
48
+ const resolvedConfig = defu(options.ui ?? {}, defaultUIConfig)
49
+
50
+ const virtualModuleId = "virtual:rimelight-ui"
51
+ const resolvedVirtualModuleId = "\0" + virtualModuleId
52
+
53
+ const rimelightUIIntegration: AstroIntegration = {
54
+ name: "@rimelight/ui",
55
+ hooks: {
56
+ "astro:config:setup": ({ updateConfig, logger }) => {
57
+ logger.info("Initializing @rimelight/ui core")
58
+
59
+ updateConfig({
60
+ vite: {
61
+ optimizeDeps: {
62
+ exclude: [
63
+ "@rimelight/ui",
64
+ "@rimelight/ui/vue-plugin",
65
+ "@rimelight/ui/integrations/vue-entrypoint",
66
+ "@nuxt/ui"
67
+ ]
68
+ },
69
+ ssr: {
70
+ noExternal: ["@rimelight/ui", "@nuxt/ui"],
71
+ optimizeDeps: {
72
+ exclude: ["@rimelight/ui/vue-plugin", "@rimelight/ui/integrations/vue-entrypoint"]
73
+ }
74
+ },
75
+ plugins: [
76
+ uiPlugin({
77
+ router: false,
78
+ scanPackages: ["@rimelight/ui"]
79
+ }),
80
+ Icons({
81
+ compiler: "astro",
82
+ autoInstall: true
83
+ }),
84
+ tailwindcss(),
85
+ {
86
+ name: "vite-plugin-rimelight-ui-config",
87
+ enforce: "pre",
88
+ resolveId(id: string) {
89
+ if (id === virtualModuleId) return resolvedVirtualModuleId
90
+ return null
91
+ },
92
+ load(id: string) {
93
+ if (id === resolvedVirtualModuleId) {
94
+ return `export const getUIConfig = () => (${JSON.stringify(resolvedConfig)});`
95
+ }
96
+ return null
97
+ }
98
+ }
99
+ ] as any
100
+ }
101
+ })
102
+ }
103
+ }
104
+ }
105
+
106
+ return [
107
+ vue({
108
+ appEntrypoint: "@rimelight/ui/integrations/vue-entrypoint"
109
+ }),
110
+ rimelightUIIntegration
111
+ ]
112
+ }