rimelight-components 2.1.85 → 2.1.86

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/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.85",
3
+ "version": "2.1.86",
4
4
  "docs": "https://rimelight.com/tools/rimelight-components",
5
5
  "configKey": "rimelightComponents",
6
6
  "compatibility": {
package/dist/module.mjs CHANGED
@@ -4,7 +4,7 @@ import { readdirSync } from 'node:fs';
4
4
  import { basename } from 'node:path';
5
5
 
6
6
  const name = "rimelight-components";
7
- const version = "2.1.85";
7
+ const version = "2.1.86";
8
8
  const homepage = "https://rimelight.com/tools/rimelight-components";
9
9
 
10
10
  const defaultOptions = {
@@ -1,25 +1,26 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
+ import chroma from "chroma-js";
3
4
  import ColorSwatch from "./ColorSwatch.vue";
4
5
  import { tv } from "../../internal/tv";
5
- import { useRC } from "../../composables";
6
+ import { useRC, useHeaderStack } from "../../composables";
6
7
  const { css = "", rc: rcProp } = defineProps({
7
8
  css: { type: String, required: false },
8
9
  rc: { type: Object, required: false }
9
10
  });
10
11
  const { rc } = useRC("ColorPalette", rcProp);
12
+ const { totalHeight } = useHeaderStack();
13
+ const stickyTop = computed(() => `${totalHeight.value + 32}px`);
11
14
  const paletteStyles = tv({
12
15
  slots: {
13
- root: "flex flex-col gap-12",
14
- section: "flex flex-col gap-6",
15
- title: "",
16
+ root: "w-full",
16
17
  grid: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
17
18
  }
18
19
  });
19
- const { root, section: sectionStyle, title: titleStyle, grid } = paletteStyles();
20
- const sections = computed(() => {
20
+ const { root, grid } = paletteStyles();
21
+ const tabItems = computed(() => {
21
22
  if (!css) return [];
22
- const result = [];
23
+ const tabs = [];
23
24
  const lines = css.split("\n");
24
25
  const stack = [];
25
26
  function getFormat(value) {
@@ -44,13 +45,26 @@ const sections = computed(() => {
44
45
  if (colorMatch && !line.trim().startsWith("/*")) {
45
46
  const fullVarName = colorMatch[1] ?? "";
46
47
  const value = colorMatch[2]?.trim() ?? "";
47
- const title = stack.length > 0 ? stack.join(" \u203A ") : "Other";
48
- let section = result.find((s) => s.title === title);
49
- if (!section) {
50
- section = { title, swatches: [] };
51
- result.push(section);
48
+ const activeStack = stack[0] === "Colors" ? stack.slice(1) : stack;
49
+ const topLevelLabel = activeStack[0] || "Other";
50
+ const subLevelLabel = activeStack.length > 1 ? activeStack.slice(1).join(" \u203A ") : topLevelLabel;
51
+ let tab = tabs.find((t) => t.label === topLevelLabel);
52
+ if (!tab) {
53
+ tab = {
54
+ label: topLevelLabel,
55
+ subsections: []
56
+ };
57
+ tabs.push(tab);
52
58
  }
53
- section.swatches.push({
59
+ let subSection = tab.subsections.find((s) => s.label === subLevelLabel);
60
+ if (!subSection) {
61
+ subSection = {
62
+ label: subLevelLabel,
63
+ swatches: []
64
+ };
65
+ tab.subsections.push(subSection);
66
+ }
67
+ subSection.swatches.push({
54
68
  name: getName(fullVarName),
55
69
  value,
56
70
  format: getFormat(value)
@@ -60,14 +74,46 @@ const sections = computed(() => {
60
74
  stack.pop();
61
75
  }
62
76
  });
63
- return result;
77
+ return tabs;
64
78
  });
79
+ function parseOklch(str) {
80
+ const match = str.match(/oklch\(([\d.]+%?)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*[\d.]+%?)?\)/);
81
+ if (match) {
82
+ let l = parseFloat(match[1] ?? "0");
83
+ if (match[1]?.endsWith("%")) l /= 100;
84
+ const c = parseFloat(match[2] ?? "0");
85
+ const h = parseFloat(match[3] ?? "0");
86
+ return [l, c, h];
87
+ }
88
+ return null;
89
+ }
65
90
  function getSwatchProps(swatch) {
66
91
  const p = { name: swatch.name };
67
- if (swatch.format !== "unknown") {
68
- p[swatch.format] = swatch.value;
69
- } else {
70
- p.oklch = swatch.value;
92
+ try {
93
+ let color;
94
+ if (swatch.format === "oklch") {
95
+ const oklchValues = parseOklch(swatch.value);
96
+ if (oklchValues) {
97
+ color = chroma.oklch(...oklchValues);
98
+ } else {
99
+ color = chroma(swatch.value);
100
+ }
101
+ } else {
102
+ color = chroma(swatch.value);
103
+ }
104
+ p.hex = color.hex();
105
+ p.rgb = color.css();
106
+ p.hsl = color.css("hsl");
107
+ const [l, c, h] = color.oklch();
108
+ p.oklch = `oklch(${Math.round(l * 1e3) / 10}% ${Math.round(c * 1e3) / 1e3} ${Math.round(h * 100) / 100})`;
109
+ const [cy, m, y, k] = color.cmyk();
110
+ p.cmyk = `cmyk(${Math.round(cy * 100)}%, ${Math.round(m * 100)}%, ${Math.round(y * 100)}%, ${Math.round(k * 100)}%)`;
111
+ } catch (e) {
112
+ if (swatch.format !== "unknown") {
113
+ p[swatch.format] = swatch.value;
114
+ } else {
115
+ p.oklch = swatch.value;
116
+ }
71
117
  }
72
118
  return p;
73
119
  }
@@ -75,22 +121,43 @@ function getSwatchProps(swatch) {
75
121
 
76
122
  <template>
77
123
  <div :class="root({ class: rc.root })">
78
- <section
79
- v-for="section in sections"
80
- :key="section.title"
81
- :class="sectionStyle({ class: rc.section })"
124
+ <UTabs
125
+ :items="tabItems"
126
+ orientation="vertical"
127
+ variant="link"
128
+ :style="{ '--palette-sticky-top': stickyTop }"
129
+ :ui="{
130
+ root: 'flex flex-col md:flex-row gap-12 items-start overflow-visible',
131
+ list: 'md:w-64 shrink-0 md:sticky md:top-[var(--palette-sticky-top)] self-start z-10 overflow-visible',
132
+ content: 'flex-1 min-w-0'
133
+ }"
82
134
  >
83
- <h2 :class="titleStyle({ class: ['text-3xl font-bold text-highlighted', rc.title] })">
84
- {{ section.title }}
85
- </h2>
86
- <div :class="grid({ class: rc.grid })">
87
- <ColorSwatch
88
- v-for="swatch in section.swatches"
89
- :key="swatch.name"
90
- v-bind="getSwatchProps(swatch)"
91
- :class="rc.swatch"
92
- />
93
- </div>
94
- </section>
135
+ <template #content="{ item }">
136
+ <h2 class="text-3xl font-bold text-highlighted mb-8">
137
+ {{ item.label }}
138
+ </h2>
139
+ <UAccordion
140
+ :items="item.subsections"
141
+ type="multiple"
142
+ class="w-full"
143
+ :ui="{
144
+ item: 'border-b border-default last:border-b-0',
145
+ trigger: 'text-xl font-bold py-4',
146
+ body: 'py-6 px-4'
147
+ }"
148
+ >
149
+ <template #body="{ item: subSection }">
150
+ <div :class="grid({ class: rc.grid })">
151
+ <ColorSwatch
152
+ v-for="swatch in subSection.swatches"
153
+ :key="swatch.name"
154
+ v-bind="getSwatchProps(swatch)"
155
+ :class="rc.swatch"
156
+ />
157
+ </div>
158
+ </template>
159
+ </UAccordion>
160
+ </template>
161
+ </UTabs>
95
162
  </div>
96
163
  </template>
@@ -0,0 +1,18 @@
1
+ export interface FontPaletteProps {
2
+ /**
3
+ * Raw CSS content to parse
4
+ */
5
+ css?: string;
6
+ /**
7
+ * UI custom classes
8
+ */
9
+ rc?: {
10
+ root?: string;
11
+ section?: string;
12
+ title?: string;
13
+ grid?: string;
14
+ };
15
+ }
16
+ declare const __VLS_export: import("vue").DefineComponent<FontPaletteProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FontPaletteProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
+ declare const _default: typeof __VLS_export;
18
+ export default _default;
@@ -0,0 +1,186 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useRC, useHeaderStack } from "../../composables";
4
+ import { tv } from "../../internal/tv";
5
+ const { css = "", rc: rcProp } = defineProps({
6
+ css: { type: String, required: false },
7
+ rc: { type: Object, required: false }
8
+ });
9
+ const { rc } = useRC("FontPalette", rcProp);
10
+ const { totalHeight } = useHeaderStack();
11
+ const stickyTop = computed(() => `${totalHeight.value + 32}px`);
12
+ const paletteStyles = tv({
13
+ slots: {
14
+ root: "w-full",
15
+ section: "flex flex-col gap-12"
16
+ }
17
+ });
18
+ const { root } = paletteStyles();
19
+ const parsedData = computed(() => {
20
+ if (!css) return { fonts: [], colors: [] };
21
+ const fonts = [];
22
+ const colors = [];
23
+ const lines = css.split("\n");
24
+ lines.forEach((line) => {
25
+ const fontMatch = line.match(/^\s*--font-([\w-]+):\s*(.*?);/);
26
+ if (fontMatch && !line.trim().startsWith("/*")) {
27
+ fonts.push({
28
+ name: fontMatch[1] ?? "",
29
+ family: fontMatch[2]?.trim() ?? ""
30
+ });
31
+ }
32
+ const textColorMatch = line.match(/^\s*--text-([\w-]+):\s*(.*?);/);
33
+ if (textColorMatch && !line.trim().startsWith("/*")) {
34
+ const name = textColorMatch[1] ?? "";
35
+ const isSize = /^(xs|sm|md|lg|xl|\d+xl|hero|base|desc)$/.test(name);
36
+ if (!isSize) {
37
+ colors.push({
38
+ name,
39
+ value: textColorMatch[2]?.trim() ?? ""
40
+ });
41
+ }
42
+ }
43
+ });
44
+ const uniqueColors = [];
45
+ colors.forEach((c) => {
46
+ if (!uniqueColors.find((uc) => uc.name === c.name)) {
47
+ uniqueColors.push(c);
48
+ }
49
+ });
50
+ return { fonts, colors: uniqueColors };
51
+ });
52
+ const sampleText = "The quick brown fox jumps over the lazy dog";
53
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
54
+ const alphabetLower = "abcdefghijklmnopqrstuvwxyz";
55
+ const numbers = "0123456789";
56
+ const symbols = `!@#$%^&*()_+-=[]{};':",./<>?`;
57
+ const headingLevels = [
58
+ { tag: "h1", label: "Heading 1" },
59
+ { tag: "h2", label: "Heading 2" },
60
+ { tag: "h3", label: "Heading 3" },
61
+ { tag: "h4", label: "Heading 4" },
62
+ { tag: "h5", label: "Heading 5" },
63
+ { tag: "h6", label: "Heading 6" }
64
+ ];
65
+ const tabItems = computed(() => {
66
+ return parsedData.value.fonts.map((f) => ({
67
+ label: f.name.charAt(0).toUpperCase() + f.name.slice(1),
68
+ font: f,
69
+ slot: "content"
70
+ }));
71
+ });
72
+ function getFontStyles(family) {
73
+ return { fontFamily: family };
74
+ }
75
+ </script>
76
+
77
+ <template>
78
+ <div :class="root({ class: rc.root })">
79
+ <UTabs
80
+ :items="tabItems"
81
+ orientation="vertical"
82
+ variant="link"
83
+ :style="{ '--palette-sticky-top': stickyTop }"
84
+ :ui="{
85
+ root: 'flex flex-col md:flex-row gap-12 items-start overflow-visible',
86
+ list: 'md:w-64 shrink-0 md:sticky md:top-[var(--palette-sticky-top)] self-start z-10 overflow-visible',
87
+ content: 'flex-1 min-w-0'
88
+ }"
89
+ >
90
+ <template #content="{ item }">
91
+ <div class="flex flex-col gap-8">
92
+ <header>
93
+ <h2 class="text-3xl font-bold text-highlighted mb-2">
94
+ {{ item.label }}
95
+ </h2>
96
+ <code class="text-sm text-muted">{{ item.font.family }}</code>
97
+ </header>
98
+
99
+ <UAccordion
100
+ multiple
101
+ :items="[
102
+ { label: 'Specimen', slot: 'specimen' },
103
+ { label: 'Hierarchy', slot: 'hierarchy' },
104
+ { label: 'Color Test', slot: 'colors' }
105
+ ]"
106
+ :ui="{
107
+ item: 'border-b border-default last:border-b-0',
108
+ trigger: 'text-xl font-bold py-4',
109
+ body: 'py-6 px-4'
110
+ }"
111
+ >
112
+ <template #specimen>
113
+ <div
114
+ class="flex flex-col gap-4 py-4 text-highlighted"
115
+ :style="getFontStyles(item.font.family)"
116
+ >
117
+ <div class="text-4xl break-all line-height-none tracking-tight">
118
+ {{ alphabet }}
119
+ </div>
120
+ <div class="text-4xl break-all line-height-none tracking-tight">
121
+ {{ alphabetLower }}
122
+ </div>
123
+ <div class="text-4xl">
124
+ {{ numbers }}
125
+ </div>
126
+ <div class="text-4xl">
127
+ {{ symbols }}
128
+ </div>
129
+ </div>
130
+ </template>
131
+
132
+ <template #hierarchy>
133
+ <div class="flex flex-col gap-8" :style="getFontStyles(item.font.family)">
134
+ <div
135
+ v-for="h in headingLevels"
136
+ :key="h.tag"
137
+ class="flex flex-col md:flex-row md:items-baseline gap-4"
138
+ >
139
+ <span class="w-12 text-xs text-muted font-mono uppercase shrink-0">{{
140
+ h.tag
141
+ }}</span>
142
+ <component :is="h.tag" class="m-0">{{ h.label }}</component>
143
+ </div>
144
+ <div class="flex flex-col md:flex-row md:items-baseline gap-4">
145
+ <span class="w-12 text-xs text-muted font-mono uppercase shrink-0">p</span>
146
+ <p class="m-0 leading-relaxed max-w-2xl">
147
+ {{ sampleText }}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
148
+ do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
149
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
150
+ consequat.
151
+ </p>
152
+ </div>
153
+ </div>
154
+ </template>
155
+
156
+ <template #colors>
157
+ <div
158
+ class="grid grid-cols-1 sm:grid-cols-2 gap-x-12 gap-y-8"
159
+ :style="getFontStyles(item.font.family)"
160
+ >
161
+ <div
162
+ v-for="c in parsedData.colors"
163
+ :key="c.name"
164
+ class="flex flex-col gap-2 p-4 rounded border border-transparent hover:border-default transition-colors"
165
+ >
166
+ <div class="flex items-center justify-between text-xs font-mono text-muted mb-2">
167
+ <span>--text-{{ c.name }}</span>
168
+ <span class="opacity-50 uppercase">{{ c.value }}</span>
169
+ </div>
170
+ <div
171
+ class="p-4 rounded border border-default/10"
172
+ :class="c.name === 'inverted' ? 'bg-highlighted' : 'bg-default/5'"
173
+ >
174
+ <p class="text-xl font-bold" :style="{ color: `var(--text-${c.name})` }">
175
+ {{ sampleText }}
176
+ </p>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ </template>
181
+ </UAccordion>
182
+ </div>
183
+ </template>
184
+ </UTabs>
185
+ </div>
186
+ </template>
@@ -0,0 +1,18 @@
1
+ export interface FontPaletteProps {
2
+ /**
3
+ * Raw CSS content to parse
4
+ */
5
+ css?: string;
6
+ /**
7
+ * UI custom classes
8
+ */
9
+ rc?: {
10
+ root?: string;
11
+ section?: string;
12
+ title?: string;
13
+ grid?: string;
14
+ };
15
+ }
16
+ declare const __VLS_export: import("vue").DefineComponent<FontPaletteProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FontPaletteProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
+ declare const _default: typeof __VLS_export;
18
+ export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.85",
3
+ "version": "2.1.86",
4
4
  "description": "A component library by Rimelight Entertainment.",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -89,6 +89,7 @@
89
89
  "@nuxt/ui": "^4.2.1",
90
90
  "@nuxtjs/i18n": "^10.2.1",
91
91
  "@tauri-apps/plugin-http": "^2.5.7",
92
+ "@types/chroma-js": "^3.1.2",
92
93
  "@types/node": "^25.2.0",
93
94
  "@vueuse/core": "^14.2.0",
94
95
  "@vueuse/nuxt": "^14.2.0",