@fakhrirafiki/theme-engine 0.4.2 → 0.4.4
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/index.js +322 -178
- package/dist/index.mjs +322 -178
- package/dist/styles/components.css +72 -5
- package/dist/styles/tailwind.css +48 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3870,7 +3870,15 @@ function ThemeScript({ presetStorageKey = "theme-preset", defaultPreset }) {
|
|
|
3870
3870
|
'destructive', 'destructive-foreground', 'border', 'input', 'ring',
|
|
3871
3871
|
'chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5',
|
|
3872
3872
|
'sidebar', 'sidebar-foreground', 'sidebar-primary', 'sidebar-primary-foreground',
|
|
3873
|
-
'sidebar-accent', 'sidebar-accent-foreground', 'sidebar-border', 'sidebar-ring'
|
|
3873
|
+
'sidebar-accent', 'sidebar-accent-foreground', 'sidebar-border', 'sidebar-ring',
|
|
3874
|
+
// Semantic accent colors for status and feedback
|
|
3875
|
+
'accent-info', 'accent-info-foreground',
|
|
3876
|
+
'accent-success', 'accent-success-foreground',
|
|
3877
|
+
'accent-warning', 'accent-warning-foreground',
|
|
3878
|
+
'accent-danger', 'accent-danger-foreground',
|
|
3879
|
+
'accent-brand', 'accent-brand-foreground',
|
|
3880
|
+
'accent-feature', 'accent-feature-foreground',
|
|
3881
|
+
'accent-highlight', 'accent-highlight-foreground'
|
|
3874
3882
|
],
|
|
3875
3883
|
typography: ['font-sans', 'font-serif', 'font-mono'],
|
|
3876
3884
|
layout: ['radius'],
|
|
@@ -3878,6 +3886,106 @@ function ThemeScript({ presetStorageKey = "theme-preset", defaultPreset }) {
|
|
|
3878
3886
|
spacing: ['letter-spacing', 'spacing']
|
|
3879
3887
|
};
|
|
3880
3888
|
|
|
3889
|
+
// Normalize hex/rgb/hsl() colors into "H S% L%" for hsl(var(--token)) usage.
|
|
3890
|
+
function normalizeColorValueToHslTriplet(value) {
|
|
3891
|
+
if (!value) return value;
|
|
3892
|
+
const trimmed = String(value).trim();
|
|
3893
|
+
if (!trimmed) return value;
|
|
3894
|
+
if (trimmed.startsWith('var(')) return trimmed;
|
|
3895
|
+
|
|
3896
|
+
// Already a triplet: "210 40% 98%"
|
|
3897
|
+
if (/^\\d+(?:\\.\\d+)?\\s+\\d+(?:\\.\\d+)?%\\s+\\d+(?:\\.\\d+)?%$/.test(trimmed)) {
|
|
3898
|
+
return trimmed;
|
|
3899
|
+
}
|
|
3900
|
+
|
|
3901
|
+
function clamp(n, min, max) {
|
|
3902
|
+
return Math.min(max, Math.max(min, n));
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3905
|
+
function rgbToHsl(r, g, b) {
|
|
3906
|
+
r /= 255;
|
|
3907
|
+
g /= 255;
|
|
3908
|
+
b /= 255;
|
|
3909
|
+
const max = Math.max(r, g, b);
|
|
3910
|
+
const min = Math.min(r, g, b);
|
|
3911
|
+
const diff = max - min;
|
|
3912
|
+
let h = 0;
|
|
3913
|
+
let s = 0;
|
|
3914
|
+
const l = (max + min) / 2;
|
|
3915
|
+
|
|
3916
|
+
if (diff !== 0) {
|
|
3917
|
+
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
|
|
3918
|
+
switch (max) {
|
|
3919
|
+
case r:
|
|
3920
|
+
h = (g - b) / diff + (g < b ? 6 : 0);
|
|
3921
|
+
break;
|
|
3922
|
+
case g:
|
|
3923
|
+
h = (b - r) / diff + 2;
|
|
3924
|
+
break;
|
|
3925
|
+
case b:
|
|
3926
|
+
h = (r - g) / diff + 4;
|
|
3927
|
+
break;
|
|
3928
|
+
}
|
|
3929
|
+
h /= 6;
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
return {
|
|
3933
|
+
h: Math.round(h * 360),
|
|
3934
|
+
s: Math.round(s * 100),
|
|
3935
|
+
l: Math.round(l * 100),
|
|
3936
|
+
};
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
function hexToRgb(hex) {
|
|
3940
|
+
let clean = hex.replace('#', '').trim();
|
|
3941
|
+
if (clean.length === 3) clean = clean.split('').map(function(c) { return c + c; }).join('');
|
|
3942
|
+
if (clean.length === 8) clean = clean.substring(0, 6); // ignore alpha
|
|
3943
|
+
if (clean.length !== 6) return null;
|
|
3944
|
+
|
|
3945
|
+
const r = parseInt(clean.substring(0, 2), 16);
|
|
3946
|
+
const g = parseInt(clean.substring(2, 4), 16);
|
|
3947
|
+
const b = parseInt(clean.substring(4, 6), 16);
|
|
3948
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
|
|
3949
|
+
return { r: r, g: g, b: b };
|
|
3950
|
+
}
|
|
3951
|
+
|
|
3952
|
+
function toTriplet(hsl) {
|
|
3953
|
+
return String(clamp(hsl.h, 0, 360)) + ' ' + String(clamp(hsl.s, 0, 100)) + '% ' + String(clamp(hsl.l, 0, 100)) + '%';
|
|
3954
|
+
}
|
|
3955
|
+
|
|
3956
|
+
// hsl(...) or raw "H S% L%"
|
|
3957
|
+
if (/^hsl\\(/i.test(trimmed)) {
|
|
3958
|
+
const cleaned = trimmed.replace(/hsl\\(|\\)/gi, '').replace(/[,%]/g, ' ').trim();
|
|
3959
|
+
const parts = cleaned.split(/\\s+/).filter(Boolean);
|
|
3960
|
+
if (parts.length === 3) {
|
|
3961
|
+
const h = parseFloat(parts[0]) || 0;
|
|
3962
|
+
const s = parseFloat(parts[1]) || 0;
|
|
3963
|
+
const l = parseFloat(parts[2]) || 0;
|
|
3964
|
+
return toTriplet({ h: h, s: s, l: l });
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
|
|
3968
|
+
// rgb(...)
|
|
3969
|
+
if (/^rgb\\(/i.test(trimmed)) {
|
|
3970
|
+
const cleaned = trimmed.replace(/rgb\\(|\\)/gi, '').trim();
|
|
3971
|
+
const parts = cleaned.split(',').map(function(p) { return p.trim(); });
|
|
3972
|
+
if (parts.length === 3) {
|
|
3973
|
+
const r = clamp(parseFloat(parts[0]) || 0, 0, 255);
|
|
3974
|
+
const g = clamp(parseFloat(parts[1]) || 0, 0, 255);
|
|
3975
|
+
const b = clamp(parseFloat(parts[2]) || 0, 0, 255);
|
|
3976
|
+
return toTriplet(rgbToHsl(r, g, b));
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
// hex
|
|
3981
|
+
if (trimmed[0] === '#') {
|
|
3982
|
+
const rgb = hexToRgb(trimmed);
|
|
3983
|
+
if (rgb) return toTriplet(rgbToHsl(rgb.r, rgb.g, rgb.b));
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
return value;
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3881
3989
|
// Function to apply all preset properties - with proper clearing and defaults
|
|
3882
3990
|
function applyPresetProperties(colors) {
|
|
3883
3991
|
if (!colors) return;
|
|
@@ -3909,6 +4017,10 @@ function ThemeScript({ presetStorageKey = "theme-preset", defaultPreset }) {
|
|
|
3909
4017
|
|
|
3910
4018
|
// Apply all properties with defaults for missing ones
|
|
3911
4019
|
let appliedCount = 0;
|
|
4020
|
+
const colorProps = {};
|
|
4021
|
+
CSS_CATEGORIES.colors.forEach(function(prop) { colorProps[prop] = true; });
|
|
4022
|
+
colorProps['shadow-color'] = true;
|
|
4023
|
+
|
|
3912
4024
|
allProperties.forEach(function(prop) {
|
|
3913
4025
|
let value = colors[prop];
|
|
3914
4026
|
|
|
@@ -3918,6 +4030,10 @@ function ThemeScript({ presetStorageKey = "theme-preset", defaultPreset }) {
|
|
|
3918
4030
|
}
|
|
3919
4031
|
|
|
3920
4032
|
if (value) {
|
|
4033
|
+
if (colorProps[prop]) {
|
|
4034
|
+
value = normalizeColorValueToHslTriplet(value);
|
|
4035
|
+
}
|
|
4036
|
+
|
|
3921
4037
|
const cssVar = '--' + prop;
|
|
3922
4038
|
// Apply directly like TweakCN does - no conversion, no !important
|
|
3923
4039
|
root.style.setProperty(cssVar, value);
|
|
@@ -3979,6 +4095,138 @@ function ThemeScript({ presetStorageKey = "theme-preset", defaultPreset }) {
|
|
|
3979
4095
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", { dangerouslySetInnerHTML: { __html: scriptContent }, suppressHydrationWarning: true });
|
|
3980
4096
|
}
|
|
3981
4097
|
|
|
4098
|
+
// src/utils/colors.ts
|
|
4099
|
+
function parseHSL(hslString) {
|
|
4100
|
+
try {
|
|
4101
|
+
const cleaned = hslString.replace(/hsl\(|\)/g, "").replace(/[,%]/g, " ").trim();
|
|
4102
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
4103
|
+
if (parts.length !== 3) return null;
|
|
4104
|
+
const h = parseFloat(parts[0]) || 0;
|
|
4105
|
+
const s = parseFloat(parts[1]) || 0;
|
|
4106
|
+
const l = parseFloat(parts[2]) || 0;
|
|
4107
|
+
return {
|
|
4108
|
+
h: Math.max(0, Math.min(360, h)),
|
|
4109
|
+
s: Math.max(0, Math.min(100, s)),
|
|
4110
|
+
l: Math.max(0, Math.min(100, l))
|
|
4111
|
+
};
|
|
4112
|
+
} catch {
|
|
4113
|
+
return null;
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
function parseHex(hexString) {
|
|
4117
|
+
try {
|
|
4118
|
+
let hex = hexString.replace("#", "");
|
|
4119
|
+
if (hex.length === 3) {
|
|
4120
|
+
hex = hex.split("").map((char) => char + char).join("");
|
|
4121
|
+
}
|
|
4122
|
+
if (hex.length !== 6) return null;
|
|
4123
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
4124
|
+
const s = parseInt(hex.substring(2, 4), 16);
|
|
4125
|
+
const l = parseInt(hex.substring(4, 6), 16);
|
|
4126
|
+
if (isNaN(r) || isNaN(s) || isNaN(l)) return null;
|
|
4127
|
+
return { r, g: s, b: l };
|
|
4128
|
+
} catch {
|
|
4129
|
+
return null;
|
|
4130
|
+
}
|
|
4131
|
+
}
|
|
4132
|
+
function hslToRgb(hsl) {
|
|
4133
|
+
const h = hsl.h / 360;
|
|
4134
|
+
const s = hsl.s / 100;
|
|
4135
|
+
const l = hsl.l / 100;
|
|
4136
|
+
if (s === 0) {
|
|
4137
|
+
const gray = Math.round(l * 255);
|
|
4138
|
+
return { r: gray, g: gray, b: gray };
|
|
4139
|
+
}
|
|
4140
|
+
const hue2rgb = (p2, q2, t) => {
|
|
4141
|
+
if (t < 0) t += 1;
|
|
4142
|
+
if (t > 1) t -= 1;
|
|
4143
|
+
if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
|
|
4144
|
+
if (t < 1 / 2) return q2;
|
|
4145
|
+
if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
|
|
4146
|
+
return p2;
|
|
4147
|
+
};
|
|
4148
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
4149
|
+
const p = 2 * l - q;
|
|
4150
|
+
const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255);
|
|
4151
|
+
const g = Math.round(hue2rgb(p, q, h) * 255);
|
|
4152
|
+
const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255);
|
|
4153
|
+
return { r, g, b };
|
|
4154
|
+
}
|
|
4155
|
+
function rgbToHsl(rgb) {
|
|
4156
|
+
const r = rgb.r / 255;
|
|
4157
|
+
const g = rgb.g / 255;
|
|
4158
|
+
const b = rgb.b / 255;
|
|
4159
|
+
const max = Math.max(r, g, b);
|
|
4160
|
+
const min = Math.min(r, g, b);
|
|
4161
|
+
const diff = max - min;
|
|
4162
|
+
let h = 0;
|
|
4163
|
+
let s = 0;
|
|
4164
|
+
const l = (max + min) / 2;
|
|
4165
|
+
if (diff !== 0) {
|
|
4166
|
+
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
|
|
4167
|
+
switch (max) {
|
|
4168
|
+
case r:
|
|
4169
|
+
h = (g - b) / diff + (g < b ? 6 : 0);
|
|
4170
|
+
break;
|
|
4171
|
+
case g:
|
|
4172
|
+
h = (b - r) / diff + 2;
|
|
4173
|
+
break;
|
|
4174
|
+
case b:
|
|
4175
|
+
h = (r - g) / diff + 4;
|
|
4176
|
+
break;
|
|
4177
|
+
}
|
|
4178
|
+
h /= 6;
|
|
4179
|
+
}
|
|
4180
|
+
return {
|
|
4181
|
+
h: Math.round(h * 360),
|
|
4182
|
+
s: Math.round(s * 100),
|
|
4183
|
+
l: Math.round(l * 100)
|
|
4184
|
+
};
|
|
4185
|
+
}
|
|
4186
|
+
function formatHSL(hsl, includeHslWrapper = true) {
|
|
4187
|
+
const values = `${hsl.h} ${hsl.s}% ${hsl.l}%`;
|
|
4188
|
+
return includeHslWrapper ? `hsl(${values})` : values;
|
|
4189
|
+
}
|
|
4190
|
+
function formatRGB(rgb) {
|
|
4191
|
+
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
|
4192
|
+
}
|
|
4193
|
+
function formatHex(rgb) {
|
|
4194
|
+
const toHex = (n) => {
|
|
4195
|
+
const hex = Math.round(Math.max(0, Math.min(255, n))).toString(16);
|
|
4196
|
+
return hex.length === 1 ? "0" + hex : hex;
|
|
4197
|
+
};
|
|
4198
|
+
return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
|
|
4199
|
+
}
|
|
4200
|
+
function formatColor(colorInput, outputFormat = "hsl", includeFunctionWrapper = true) {
|
|
4201
|
+
let hsl = parseHSL(colorInput);
|
|
4202
|
+
if (!hsl) {
|
|
4203
|
+
const rgb = parseHex(colorInput);
|
|
4204
|
+
if (rgb) {
|
|
4205
|
+
hsl = rgbToHsl(rgb);
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
if (!hsl) {
|
|
4209
|
+
return colorInput;
|
|
4210
|
+
}
|
|
4211
|
+
switch (outputFormat) {
|
|
4212
|
+
case "hsl":
|
|
4213
|
+
return formatHSL(hsl, includeFunctionWrapper);
|
|
4214
|
+
case "rgb":
|
|
4215
|
+
return formatRGB(hslToRgb(hsl));
|
|
4216
|
+
case "hex":
|
|
4217
|
+
return formatHex(hslToRgb(hsl));
|
|
4218
|
+
default:
|
|
4219
|
+
return colorInput;
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
function withAlpha(colorInput, alpha) {
|
|
4223
|
+
const hsl = parseHSL(colorInput);
|
|
4224
|
+
if (!hsl) return colorInput;
|
|
4225
|
+
const rgb = hslToRgb(hsl);
|
|
4226
|
+
const clampedAlpha = Math.max(0, Math.min(1, alpha));
|
|
4227
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clampedAlpha})`;
|
|
4228
|
+
}
|
|
4229
|
+
|
|
3982
4230
|
// src/providers/UnifiedThemeProvider.tsx
|
|
3983
4231
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
3984
4232
|
var UnifiedThemeContext = (0, import_react2.createContext)(void 0);
|
|
@@ -4001,6 +4249,14 @@ function setStoredMode(mode, storageKey) {
|
|
|
4001
4249
|
} catch {
|
|
4002
4250
|
}
|
|
4003
4251
|
}
|
|
4252
|
+
function normalizeColorValueToHslTriplet(value) {
|
|
4253
|
+
const trimmed = value.trim();
|
|
4254
|
+
const parsedHsl = parseHSL(trimmed);
|
|
4255
|
+
if (parsedHsl) return formatHSL(parsedHsl, false);
|
|
4256
|
+
const parsedRgb = parseHex(trimmed);
|
|
4257
|
+
if (parsedRgb) return formatHSL(rgbToHsl(parsedRgb), false);
|
|
4258
|
+
return value;
|
|
4259
|
+
}
|
|
4004
4260
|
function ThemeProvider({
|
|
4005
4261
|
children,
|
|
4006
4262
|
defaultMode = "system",
|
|
@@ -4176,6 +4432,9 @@ function ThemeProvider({
|
|
|
4176
4432
|
value = defaultValues[prop];
|
|
4177
4433
|
}
|
|
4178
4434
|
if (value) {
|
|
4435
|
+
if (CSS_PROPERTY_CATEGORIES.colors.includes(prop) || prop === "shadow-color") {
|
|
4436
|
+
value = normalizeColorValueToHslTriplet(String(value));
|
|
4437
|
+
}
|
|
4179
4438
|
const cssVar = `--${prop}`;
|
|
4180
4439
|
root.style.setProperty(cssVar, value);
|
|
4181
4440
|
appliedCount++;
|
|
@@ -4461,140 +4720,6 @@ ThemeToggle.displayName = "ThemeToggle";
|
|
|
4461
4720
|
// src/components/ThemePresetButtons.tsx
|
|
4462
4721
|
var import_react4 = require("react");
|
|
4463
4722
|
var import_clsx2 = require("clsx");
|
|
4464
|
-
|
|
4465
|
-
// src/utils/colors.ts
|
|
4466
|
-
function parseHSL(hslString) {
|
|
4467
|
-
try {
|
|
4468
|
-
const cleaned = hslString.replace(/hsl\(|\)/g, "").replace(/[,%]/g, " ").trim();
|
|
4469
|
-
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
4470
|
-
if (parts.length !== 3) return null;
|
|
4471
|
-
const h = parseFloat(parts[0]) || 0;
|
|
4472
|
-
const s = parseFloat(parts[1]) || 0;
|
|
4473
|
-
const l = parseFloat(parts[2]) || 0;
|
|
4474
|
-
return {
|
|
4475
|
-
h: Math.max(0, Math.min(360, h)),
|
|
4476
|
-
s: Math.max(0, Math.min(100, s)),
|
|
4477
|
-
l: Math.max(0, Math.min(100, l))
|
|
4478
|
-
};
|
|
4479
|
-
} catch {
|
|
4480
|
-
return null;
|
|
4481
|
-
}
|
|
4482
|
-
}
|
|
4483
|
-
function parseHex(hexString) {
|
|
4484
|
-
try {
|
|
4485
|
-
let hex = hexString.replace("#", "");
|
|
4486
|
-
if (hex.length === 3) {
|
|
4487
|
-
hex = hex.split("").map((char) => char + char).join("");
|
|
4488
|
-
}
|
|
4489
|
-
if (hex.length !== 6) return null;
|
|
4490
|
-
const r = parseInt(hex.substring(0, 2), 16);
|
|
4491
|
-
const s = parseInt(hex.substring(2, 4), 16);
|
|
4492
|
-
const l = parseInt(hex.substring(4, 6), 16);
|
|
4493
|
-
if (isNaN(r) || isNaN(s) || isNaN(l)) return null;
|
|
4494
|
-
return { r, g: s, b: l };
|
|
4495
|
-
} catch {
|
|
4496
|
-
return null;
|
|
4497
|
-
}
|
|
4498
|
-
}
|
|
4499
|
-
function hslToRgb(hsl) {
|
|
4500
|
-
const h = hsl.h / 360;
|
|
4501
|
-
const s = hsl.s / 100;
|
|
4502
|
-
const l = hsl.l / 100;
|
|
4503
|
-
if (s === 0) {
|
|
4504
|
-
const gray = Math.round(l * 255);
|
|
4505
|
-
return { r: gray, g: gray, b: gray };
|
|
4506
|
-
}
|
|
4507
|
-
const hue2rgb = (p2, q2, t) => {
|
|
4508
|
-
if (t < 0) t += 1;
|
|
4509
|
-
if (t > 1) t -= 1;
|
|
4510
|
-
if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
|
|
4511
|
-
if (t < 1 / 2) return q2;
|
|
4512
|
-
if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
|
|
4513
|
-
return p2;
|
|
4514
|
-
};
|
|
4515
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
4516
|
-
const p = 2 * l - q;
|
|
4517
|
-
const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255);
|
|
4518
|
-
const g = Math.round(hue2rgb(p, q, h) * 255);
|
|
4519
|
-
const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255);
|
|
4520
|
-
return { r, g, b };
|
|
4521
|
-
}
|
|
4522
|
-
function rgbToHsl(rgb) {
|
|
4523
|
-
const r = rgb.r / 255;
|
|
4524
|
-
const g = rgb.g / 255;
|
|
4525
|
-
const b = rgb.b / 255;
|
|
4526
|
-
const max = Math.max(r, g, b);
|
|
4527
|
-
const min = Math.min(r, g, b);
|
|
4528
|
-
const diff = max - min;
|
|
4529
|
-
let h = 0;
|
|
4530
|
-
let s = 0;
|
|
4531
|
-
const l = (max + min) / 2;
|
|
4532
|
-
if (diff !== 0) {
|
|
4533
|
-
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
|
|
4534
|
-
switch (max) {
|
|
4535
|
-
case r:
|
|
4536
|
-
h = (g - b) / diff + (g < b ? 6 : 0);
|
|
4537
|
-
break;
|
|
4538
|
-
case g:
|
|
4539
|
-
h = (b - r) / diff + 2;
|
|
4540
|
-
break;
|
|
4541
|
-
case b:
|
|
4542
|
-
h = (r - g) / diff + 4;
|
|
4543
|
-
break;
|
|
4544
|
-
}
|
|
4545
|
-
h /= 6;
|
|
4546
|
-
}
|
|
4547
|
-
return {
|
|
4548
|
-
h: Math.round(h * 360),
|
|
4549
|
-
s: Math.round(s * 100),
|
|
4550
|
-
l: Math.round(l * 100)
|
|
4551
|
-
};
|
|
4552
|
-
}
|
|
4553
|
-
function formatHSL(hsl, includeHslWrapper = true) {
|
|
4554
|
-
const values = `${hsl.h} ${hsl.s}% ${hsl.l}%`;
|
|
4555
|
-
return includeHslWrapper ? `hsl(${values})` : values;
|
|
4556
|
-
}
|
|
4557
|
-
function formatRGB(rgb) {
|
|
4558
|
-
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
|
4559
|
-
}
|
|
4560
|
-
function formatHex(rgb) {
|
|
4561
|
-
const toHex = (n) => {
|
|
4562
|
-
const hex = Math.round(Math.max(0, Math.min(255, n))).toString(16);
|
|
4563
|
-
return hex.length === 1 ? "0" + hex : hex;
|
|
4564
|
-
};
|
|
4565
|
-
return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
|
|
4566
|
-
}
|
|
4567
|
-
function formatColor(colorInput, outputFormat = "hsl", includeFunctionWrapper = true) {
|
|
4568
|
-
let hsl = parseHSL(colorInput);
|
|
4569
|
-
if (!hsl) {
|
|
4570
|
-
const rgb = parseHex(colorInput);
|
|
4571
|
-
if (rgb) {
|
|
4572
|
-
hsl = rgbToHsl(rgb);
|
|
4573
|
-
}
|
|
4574
|
-
}
|
|
4575
|
-
if (!hsl) {
|
|
4576
|
-
return colorInput;
|
|
4577
|
-
}
|
|
4578
|
-
switch (outputFormat) {
|
|
4579
|
-
case "hsl":
|
|
4580
|
-
return formatHSL(hsl, includeFunctionWrapper);
|
|
4581
|
-
case "rgb":
|
|
4582
|
-
return formatRGB(hslToRgb(hsl));
|
|
4583
|
-
case "hex":
|
|
4584
|
-
return formatHex(hslToRgb(hsl));
|
|
4585
|
-
default:
|
|
4586
|
-
return colorInput;
|
|
4587
|
-
}
|
|
4588
|
-
}
|
|
4589
|
-
function withAlpha(colorInput, alpha) {
|
|
4590
|
-
const hsl = parseHSL(colorInput);
|
|
4591
|
-
if (!hsl) return colorInput;
|
|
4592
|
-
const rgb = hslToRgb(hsl);
|
|
4593
|
-
const clampedAlpha = Math.max(0, Math.min(1, alpha));
|
|
4594
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clampedAlpha})`;
|
|
4595
|
-
}
|
|
4596
|
-
|
|
4597
|
-
// src/components/ThemePresetButtons.tsx
|
|
4598
4723
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4599
4724
|
var DEFAULT_ANIMATION = {
|
|
4600
4725
|
enabled: true,
|
|
@@ -4617,6 +4742,17 @@ var DEFAULT_LAYOUT = {
|
|
|
4617
4742
|
colorBoxCount: 3,
|
|
4618
4743
|
enableMask: true
|
|
4619
4744
|
};
|
|
4745
|
+
function getPresetButtonWidthPx(label, layout) {
|
|
4746
|
+
const approxCharWidthPx = 7.25;
|
|
4747
|
+
const maxWidthPx = 360;
|
|
4748
|
+
const dotSizePx = 12;
|
|
4749
|
+
const dotGapPx = 4;
|
|
4750
|
+
const dotsWidthPx = layout.showColorBoxes ? layout.colorBoxCount * dotSizePx + Math.max(0, layout.colorBoxCount - 1) * dotGapPx : 0;
|
|
4751
|
+
const contentPaddingPx = 28;
|
|
4752
|
+
const estimatedTextWidthPx = Math.ceil(label.length * approxCharWidthPx);
|
|
4753
|
+
const estimatedWidthPx = contentPaddingPx + dotsWidthPx + estimatedTextWidthPx;
|
|
4754
|
+
return Math.min(maxWidthPx, Math.max(layout.buttonWidth, estimatedWidthPx));
|
|
4755
|
+
}
|
|
4620
4756
|
var ColorBox = ({ color, className }) => {
|
|
4621
4757
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4622
4758
|
"div",
|
|
@@ -4636,6 +4772,8 @@ var PresetButton = ({
|
|
|
4636
4772
|
renderColorBox
|
|
4637
4773
|
}) => {
|
|
4638
4774
|
const colors = preset.colors[mode];
|
|
4775
|
+
const label = preset.name.replace(/-/g, " ");
|
|
4776
|
+
const buttonWidth = Math.max(layout.buttonWidth, Number(preset.metadata?.buttonWidth ?? 0) || layout.buttonWidth);
|
|
4639
4777
|
if (renderPreset) {
|
|
4640
4778
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
4641
4779
|
"div",
|
|
@@ -4647,23 +4785,23 @@ var PresetButton = ({
|
|
|
4647
4785
|
}
|
|
4648
4786
|
);
|
|
4649
4787
|
}
|
|
4650
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-shrink-0", style: {
|
|
4651
|
-
"
|
|
4788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-shrink-0", style: { width: buttonWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
4789
|
+
"button",
|
|
4652
4790
|
{
|
|
4791
|
+
type: "button",
|
|
4653
4792
|
className: (0, import_clsx2.clsx)(
|
|
4654
4793
|
"theme-preset-button",
|
|
4655
|
-
|
|
4656
|
-
"flex w-full h-full items-center justify-center relative transition-all duration-200",
|
|
4657
|
-
"hover:shadow-lg hover:border-primary/20 px-4 py-3",
|
|
4658
|
-
isSelected ? "ring-2 ring-primary/50 shadow-md bg-primary/5" : ""
|
|
4794
|
+
isSelected && "theme-preset-button--selected"
|
|
4659
4795
|
),
|
|
4660
4796
|
onClick,
|
|
4661
|
-
|
|
4662
|
-
|
|
4797
|
+
"aria-pressed": isSelected,
|
|
4798
|
+
title: label,
|
|
4799
|
+
children: [
|
|
4800
|
+
layout.showColorBoxes && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "theme-preset-button__colors", children: [colors.primary, colors.secondary, colors.accent].slice(0, layout.colorBoxCount).map(
|
|
4663
4801
|
(color, index) => renderColorBox ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: renderColorBox(color, index) }, index) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ColorBox, { color }, index)
|
|
4664
4802
|
) }),
|
|
4665
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("
|
|
4666
|
-
]
|
|
4803
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "theme-preset-button__text", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "theme-preset-button__label", children: label }) })
|
|
4804
|
+
]
|
|
4667
4805
|
}
|
|
4668
4806
|
) });
|
|
4669
4807
|
};
|
|
@@ -4679,7 +4817,7 @@ var AnimatedRow = ({
|
|
|
4679
4817
|
}) => {
|
|
4680
4818
|
if (presets.length === 0) return null;
|
|
4681
4819
|
const duplicatedPresets = Array(animation.duplicationFactor).fill(presets).flat();
|
|
4682
|
-
const totalWidth = presets.
|
|
4820
|
+
const totalWidth = presets.reduce((sum, preset) => sum + (Number(preset.metadata?.buttonWidth) || layout.buttonWidth), 0) + presets.length * layout.buttonGap;
|
|
4683
4821
|
const effectiveScrollSpeed = Math.max(0.1, animation.scrollSpeed || 1);
|
|
4684
4822
|
const animationDuration = presets.length * animation.duration / effectiveScrollSpeed;
|
|
4685
4823
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -4747,41 +4885,47 @@ var ThemePresetButtons = ({
|
|
|
4747
4885
|
try {
|
|
4748
4886
|
setLoading(true);
|
|
4749
4887
|
setError(null);
|
|
4750
|
-
|
|
4888
|
+
const builtInPresetList = [];
|
|
4889
|
+
const customPresetList = [];
|
|
4751
4890
|
if (showBuiltIn) {
|
|
4752
|
-
|
|
4753
|
-
id,
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4891
|
+
builtInPresetList.push(
|
|
4892
|
+
...Object.entries(builtInPresets).map(([id, preset]) => ({
|
|
4893
|
+
id,
|
|
4894
|
+
name: preset.label,
|
|
4895
|
+
colors: {
|
|
4896
|
+
light: preset.styles.light,
|
|
4897
|
+
dark: preset.styles.dark
|
|
4898
|
+
},
|
|
4899
|
+
metadata: {
|
|
4900
|
+
buttonWidth: getPresetButtonWidthPx(preset.label, layout),
|
|
4901
|
+
category: preset.label.toLowerCase().includes("minimal") ? "minimal" : preset.label.toLowerCase().includes("violet") || preset.label.toLowerCase().includes("purple") ? "vibrant" : "modern",
|
|
4902
|
+
tags: [preset.label.toLowerCase().replace(/\s+/g, "-")],
|
|
4903
|
+
createdAt: preset.createdAt,
|
|
4904
|
+
provider: "built-in"
|
|
4905
|
+
}
|
|
4906
|
+
}))
|
|
4907
|
+
);
|
|
4767
4908
|
}
|
|
4768
4909
|
if (showCustom) {
|
|
4769
|
-
|
|
4770
|
-
id,
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4910
|
+
customPresetList.push(
|
|
4911
|
+
...Object.entries(customPresets).map(([id, preset]) => ({
|
|
4912
|
+
id,
|
|
4913
|
+
name: preset.label,
|
|
4914
|
+
colors: {
|
|
4915
|
+
light: preset.styles.light,
|
|
4916
|
+
dark: preset.styles.dark
|
|
4917
|
+
},
|
|
4918
|
+
metadata: {
|
|
4919
|
+
buttonWidth: getPresetButtonWidthPx(preset.label, layout),
|
|
4920
|
+
category: preset.label.toLowerCase().includes("minimal") ? "minimal" : preset.label.toLowerCase().includes("violet") || preset.label.toLowerCase().includes("purple") ? "vibrant" : "modern",
|
|
4921
|
+
tags: [preset.label.toLowerCase().replace(/\s+/g, "-")],
|
|
4922
|
+
createdAt: preset.createdAt,
|
|
4923
|
+
provider: "custom"
|
|
4924
|
+
}
|
|
4925
|
+
}))
|
|
4926
|
+
);
|
|
4784
4927
|
}
|
|
4928
|
+
let allPresets = [...customPresetList, ...builtInPresetList];
|
|
4785
4929
|
if (categories && categories.length > 0) {
|
|
4786
4930
|
allPresets = allPresets.filter(
|
|
4787
4931
|
(preset) => categories.includes(preset.metadata?.category || "unknown")
|
|
@@ -4797,7 +4941,7 @@ var ThemePresetButtons = ({
|
|
|
4797
4941
|
} finally {
|
|
4798
4942
|
setLoading(false);
|
|
4799
4943
|
}
|
|
4800
|
-
}, [availablePresets, builtInPresets, customPresets, categories, maxPresets, showBuiltIn, showCustom]);
|
|
4944
|
+
}, [availablePresets, builtInPresets, customPresets, categories, maxPresets, showBuiltIn, showCustom, layout]);
|
|
4801
4945
|
(0, import_react4.useEffect)(() => {
|
|
4802
4946
|
loadPresets();
|
|
4803
4947
|
}, [loadPresets]);
|