@kilivi/payloadcms-theme-management 2.0.0 → 2.2.0
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/README.md +346 -845
- package/dist/components/AppearanceSessionControls.d.ts +15 -0
- package/dist/components/AppearanceSessionControls.d.ts.map +1 -0
- package/dist/components/AppearanceSessionControls.js +152 -0
- package/dist/components/AppearanceSessionControls.js.map +1 -0
- package/dist/components/ColorModeToggle.css +42 -0
- package/dist/components/ColorModeToggle.d.ts +40 -0
- package/dist/components/ColorModeToggle.d.ts.map +1 -0
- package/dist/components/ColorModeToggle.js +111 -0
- package/dist/components/ColorModeToggle.js.map +1 -0
- package/dist/components/ServerThemeInjector.d.ts +13 -1
- package/dist/components/ServerThemeInjector.d.ts.map +1 -1
- package/dist/components/ServerThemeInjector.js +65 -15
- package/dist/components/ServerThemeInjector.js.map +1 -1
- package/dist/components/ThemeLivePreviewSync.d.ts +4 -0
- package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -1
- package/dist/components/ThemeLivePreviewSync.js +28 -4
- package/dist/components/ThemeLivePreviewSync.js.map +1 -1
- package/dist/components/ThemeSwitcher.d.ts +36 -0
- package/dist/components/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher.js +89 -0
- package/dist/components/ThemeSwitcher.js.map +1 -0
- package/dist/components/typographyPreviewUtils.d.ts +5 -0
- package/dist/components/typographyPreviewUtils.d.ts.map +1 -1
- package/dist/components/typographyPreviewUtils.js +24 -11
- package/dist/components/typographyPreviewUtils.js.map +1 -1
- package/dist/constants/devicePreviews.d.ts +35 -0
- package/dist/constants/devicePreviews.d.ts.map +1 -0
- package/dist/constants/devicePreviews.js +43 -0
- package/dist/constants/devicePreviews.js.map +1 -0
- package/dist/constants/themeFonts.d.ts +94 -168
- package/dist/constants/themeFonts.d.ts.map +1 -1
- package/dist/constants/themeFonts.js +260 -140
- package/dist/constants/themeFonts.js.map +1 -1
- package/dist/endpoints/themeFonts.d.ts +5 -0
- package/dist/endpoints/themeFonts.d.ts.map +1 -0
- package/dist/endpoints/themeFonts.js +138 -0
- package/dist/endpoints/themeFonts.js.map +1 -0
- package/dist/extended-presets.d.ts +0 -4
- package/dist/extended-presets.d.ts.map +1 -1
- package/dist/extended-presets.js +1 -18
- package/dist/extended-presets.js.map +1 -1
- package/dist/extended-themes.d.ts.map +1 -1
- package/dist/extended-themes.js +428 -0
- package/dist/extended-themes.js.map +1 -1
- package/dist/fields/AccessibilityAuditField.d.ts +2 -0
- package/dist/fields/AccessibilityAuditField.d.ts.map +1 -0
- package/dist/fields/AccessibilityAuditField.js +303 -0
- package/dist/fields/AccessibilityAuditField.js.map +1 -0
- package/dist/fields/AppearancePreviewField.d.ts +2 -0
- package/dist/fields/AppearancePreviewField.d.ts.map +1 -0
- package/dist/fields/AppearancePreviewField.js +826 -0
- package/dist/fields/AppearancePreviewField.js.map +1 -0
- package/dist/fields/ColorPickerField.d.ts.map +1 -1
- package/dist/fields/ColorPickerField.js +89 -85
- package/dist/fields/ColorPickerField.js.map +1 -1
- package/dist/fields/FontSelectField.css +155 -0
- package/dist/fields/FontSelectField.d.ts +8 -0
- package/dist/fields/FontSelectField.d.ts.map +1 -1
- package/dist/fields/FontSelectField.js +223 -188
- package/dist/fields/FontSelectField.js.map +1 -1
- package/dist/fields/PaletteGeneratorField.d.ts +7 -0
- package/dist/fields/PaletteGeneratorField.d.ts.map +1 -0
- package/dist/fields/PaletteGeneratorField.js +327 -0
- package/dist/fields/PaletteGeneratorField.js.map +1 -0
- package/dist/fields/StylePresetField.d.ts +3 -0
- package/dist/fields/StylePresetField.d.ts.map +1 -0
- package/dist/fields/StylePresetField.js +463 -0
- package/dist/fields/StylePresetField.js.map +1 -0
- package/dist/fields/ThemeColorPickerField.css +115 -35
- package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
- package/dist/fields/ThemeColorPickerField.js +204 -70
- package/dist/fields/ThemeColorPickerField.js.map +1 -1
- package/dist/fields/ThemeExportField.d.ts +6 -0
- package/dist/fields/ThemeExportField.d.ts.map +1 -0
- package/dist/fields/ThemeExportField.js +202 -0
- package/dist/fields/ThemeExportField.js.map +1 -0
- package/dist/fields/ThemePresetImportField.d.ts.map +1 -1
- package/dist/fields/ThemePresetImportField.js +56 -25
- package/dist/fields/ThemePresetImportField.js.map +1 -1
- package/dist/fields/ThemePreviewField.css +444 -5
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +265 -170
- package/dist/fields/ThemePreviewField.js.map +1 -1
- package/dist/fields/ThemeTokenSelectField.d.ts.map +1 -1
- package/dist/fields/ThemeTokenSelectField.js +278 -80
- package/dist/fields/ThemeTokenSelectField.js.map +1 -1
- package/dist/fields/colorFieldHelpers.d.ts +90 -0
- package/dist/fields/colorFieldHelpers.d.ts.map +1 -0
- package/dist/fields/colorFieldHelpers.js +133 -0
- package/dist/fields/colorFieldHelpers.js.map +1 -0
- package/dist/fields/colorModeFields.d.ts +1 -1
- package/dist/fields/colorModeFields.d.ts.map +1 -1
- package/dist/fields/colorModeFields.js +49 -7
- package/dist/fields/colorModeFields.js.map +1 -1
- package/dist/fields/themeConfigurationField.d.ts +8 -1
- package/dist/fields/themeConfigurationField.d.ts.map +1 -1
- package/dist/fields/themeConfigurationField.js +1209 -228
- package/dist/fields/themeConfigurationField.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js +8 -4
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.js +81 -26
- package/dist/globals/ThemeSettings/FontPicker/index.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/styles.css +98 -41
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts +6 -0
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/translations.js +14 -2
- package/dist/globals/ThemeSettings/FontPicker/translations.js.map +1 -1
- package/dist/globals/ThemeSettings/config.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/config.js +76 -79
- package/dist/globals/ThemeSettings/config.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js +63 -62
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js +22 -25
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js.map +1 -1
- package/dist/hooks/useAppearanceSession.d.ts +50 -0
- package/dist/hooks/useAppearanceSession.d.ts.map +1 -0
- package/dist/hooks/useAppearanceSession.js +91 -0
- package/dist/hooks/useAppearanceSession.js.map +1 -0
- package/dist/hooks/useNativeLivePreview.d.ts +15 -0
- package/dist/hooks/useNativeLivePreview.d.ts.map +1 -0
- package/dist/hooks/useNativeLivePreview.js +18 -0
- package/dist/hooks/useNativeLivePreview.js.map +1 -0
- package/dist/hooks/useThemeFonts.d.ts +10 -0
- package/dist/hooks/useThemeFonts.d.ts.map +1 -0
- package/dist/hooks/useThemeFonts.js +36 -0
- package/dist/hooks/useThemeFonts.js.map +1 -0
- package/dist/hooks/useThemeTranslations.d.ts +13 -0
- package/dist/hooks/useThemeTranslations.d.ts.map +1 -0
- package/dist/hooks/useThemeTranslations.js +22 -0
- package/dist/hooks/useThemeTranslations.js.map +1 -0
- package/dist/i18n.d.ts +53 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +53 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -29
- package/dist/index.js.map +1 -1
- package/dist/next-fonts.d.ts +3 -0
- package/dist/next-fonts.d.ts.map +1 -0
- package/dist/next-fonts.js +360 -0
- package/dist/next-fonts.js.map +1 -0
- package/dist/payload-types.d.ts +34 -6
- package/dist/payload-types.d.ts.map +1 -1
- package/dist/payload-types.js.map +1 -1
- package/dist/presets.d.ts +14 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js.map +1 -1
- package/dist/providers/Theme/index.d.ts.map +1 -1
- package/dist/providers/Theme/index.js +75 -11
- package/dist/providers/Theme/index.js.map +1 -1
- package/dist/providers/Theme/themeConfig.d.ts.map +1 -1
- package/dist/providers/Theme/themeConfig.js +104 -0
- package/dist/providers/Theme/themeConfig.js.map +1 -1
- package/dist/providers/Theme/types.d.ts +1 -1
- package/dist/providers/Theme/types.d.ts.map +1 -1
- package/dist/providers/Theme/types.js +10 -1
- package/dist/providers/Theme/types.js.map +1 -1
- package/dist/style-presets.d.ts +75 -0
- package/dist/style-presets.d.ts.map +1 -0
- package/dist/style-presets.js +738 -0
- package/dist/style-presets.js.map +1 -0
- package/dist/translations.d.ts +164 -1
- package/dist/translations.d.ts.map +1 -1
- package/dist/translations.js +320 -9
- package/dist/translations.js.map +1 -1
- package/dist/tweakcn-special-themes.d.ts.map +1 -1
- package/dist/tweakcn-special-themes.js +585 -9
- package/dist/tweakcn-special-themes.js.map +1 -1
- package/dist/types/css.d.js +3 -0
- package/dist/types/css.d.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/getThemeSettings.d.ts.map +1 -1
- package/dist/utilities/getThemeSettings.js +2 -14
- package/dist/utilities/getThemeSettings.js.map +1 -1
- package/dist/utils/contrast.d.ts +63 -0
- package/dist/utils/contrast.d.ts.map +1 -0
- package/dist/utils/contrast.js +158 -0
- package/dist/utils/contrast.js.map +1 -0
- package/dist/utils/exportTokens.d.ts +30 -0
- package/dist/utils/exportTokens.d.ts.map +1 -0
- package/dist/utils/exportTokens.js +183 -0
- package/dist/utils/exportTokens.js.map +1 -0
- package/dist/utils/generatePalette.d.ts +46 -0
- package/dist/utils/generatePalette.d.ts.map +1 -0
- package/dist/utils/generatePalette.js +127 -0
- package/dist/utils/generatePalette.js.map +1 -0
- package/dist/utils/generateThemeCSS.d.ts.map +1 -1
- package/dist/utils/generateThemeCSS.js +2 -40
- package/dist/utils/generateThemeCSS.js.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.d.ts +22 -3
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.js +48 -15
- package/dist/utils/livePreviewThemeRuntime.js.map +1 -1
- package/dist/utils/localizedText.d.ts +8 -0
- package/dist/utils/localizedText.d.ts.map +1 -0
- package/dist/utils/localizedText.js +21 -0
- package/dist/utils/localizedText.js.map +1 -0
- package/dist/utils/resolveThemeConfiguration.d.ts +60 -1
- package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
- package/dist/utils/resolveThemeConfiguration.js +53 -13
- package/dist/utils/resolveThemeConfiguration.js.map +1 -1
- package/dist/utils/themeColors.d.ts +3 -0
- package/dist/utils/themeColors.d.ts.map +1 -1
- package/dist/utils/themeColors.js +30 -1
- package/dist/utils/themeColors.js.map +1 -1
- package/dist/utils/themeHtmlAttributes.d.ts +32 -12
- package/dist/utils/themeHtmlAttributes.d.ts.map +1 -1
- package/dist/utils/themeHtmlAttributes.js +38 -5
- package/dist/utils/themeHtmlAttributes.js.map +1 -1
- package/dist/utils/themeUtils.d.ts +3 -5
- package/dist/utils/themeUtils.d.ts.map +1 -1
- package/dist/utils/themeUtils.js +474 -6
- package/dist/utils/themeUtils.js.map +1 -1
- package/dist/utils/tweakcnConverter.d.ts +1 -3
- package/dist/utils/tweakcnConverter.d.ts.map +1 -1
- package/dist/utils/tweakcnConverter.js +1 -3
- package/dist/utils/tweakcnConverter.js.map +1 -1
- package/package.json +15 -5
- package/dist/components/ThemePreview.d.ts +0 -3
- package/dist/components/ThemePreview.d.ts.map +0 -1
- package/dist/components/ThemePreview.js +0 -321
- package/dist/components/ThemePreview.js.map +0 -1
- package/dist/plugin.d.ts +0 -2
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -3
- package/dist/plugin.js.map +0 -1
package/dist/utils/themeUtils.js
CHANGED
|
@@ -5,7 +5,7 @@ import { borderRadiusPresets } from '../providers/Theme/themeConfig.js';
|
|
|
5
5
|
const cssRules = [];
|
|
6
6
|
const customization = config.customization;
|
|
7
7
|
const themeSelector = config.theme ? `:root[data-theme='${config.theme}']` : ':root';
|
|
8
|
-
//
|
|
8
|
+
// ── :root block — CSS custom properties ─────────────────────────────────
|
|
9
9
|
cssRules.push(`${themeSelector} {`);
|
|
10
10
|
applyCustomizationRootRules(cssRules, customization);
|
|
11
11
|
applyBorderRadiusRule(cssRules, config);
|
|
@@ -13,12 +13,17 @@ import { borderRadiusPresets } from '../providers/Theme/themeConfig.js';
|
|
|
13
13
|
applySpacingRule(cssRules, config);
|
|
14
14
|
applyAnimationRule(cssRules, config);
|
|
15
15
|
applyTypographyRules(cssRules, config);
|
|
16
|
+
applyVisualEffectsCSSVars(cssRules, config);
|
|
17
|
+
applyComponentStyleCSSVars(cssRules, config);
|
|
16
18
|
cssRules.push('}');
|
|
17
|
-
//
|
|
19
|
+
// ── Element-level effect rules (outside :root) ──────────────────────────
|
|
20
|
+
applyTypographyBaseRules(cssRules, config);
|
|
21
|
+
applyEffectElementRules(cssRules, config);
|
|
22
|
+
// ── Color mode overrides ────────────────────────────────────────────────
|
|
18
23
|
applyDarkModeOverrides(cssRules, config, customization, themeSelector);
|
|
19
|
-
// Animation
|
|
24
|
+
// ── Animation: none — respect prefers-reduced-motion ───────────────────
|
|
20
25
|
applyReducedMotionOverride(cssRules, config);
|
|
21
|
-
// Custom CSS
|
|
26
|
+
// ── Custom CSS ──────────────────────────────────────────────────────────
|
|
22
27
|
appendCustomCSS(cssRules, customization);
|
|
23
28
|
return cssRules.join('\n');
|
|
24
29
|
}
|
|
@@ -109,6 +114,10 @@ function applySpacingRule(rules, config) {
|
|
|
109
114
|
const multiplier = spacingMultipliers[config.spacing] ?? '1';
|
|
110
115
|
rules.push(` --spacing-scale: ${multiplier};`);
|
|
111
116
|
rules.push(` --theme-spacing: ${multiplier};`);
|
|
117
|
+
// Ready-to-use rhythm tokens so the spacing choice is visible without extra math.
|
|
118
|
+
rules.push(` --section-spacing: calc(clamp(3rem, 8vw, 6rem) * ${multiplier});`);
|
|
119
|
+
rules.push(` --card-padding: calc(1.5rem * ${multiplier});`);
|
|
120
|
+
rules.push(` --stack-gap: calc(1rem * ${multiplier});`);
|
|
112
121
|
}
|
|
113
122
|
function applyAnimationRule(rules, config) {
|
|
114
123
|
if (!config.animationLevel) return;
|
|
@@ -128,7 +137,7 @@ function applyAnimationRule(rules, config) {
|
|
|
128
137
|
easing: 'ease-out',
|
|
129
138
|
scale: '1'
|
|
130
139
|
},
|
|
131
|
-
|
|
140
|
+
high: {
|
|
132
141
|
duration: '0.3s',
|
|
133
142
|
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
134
143
|
scale: '1.2'
|
|
@@ -136,7 +145,6 @@ function applyAnimationRule(rules, config) {
|
|
|
136
145
|
};
|
|
137
146
|
const level = config.animationLevel;
|
|
138
147
|
const settings = animationSettings[level] ?? animationSettings.medium;
|
|
139
|
-
if (!settings) return;
|
|
140
148
|
rules.push(` --animation-duration: ${settings.duration};`);
|
|
141
149
|
rules.push(` --animation-easing: ${settings.easing};`);
|
|
142
150
|
rules.push(` --animation-scale: ${settings.scale};`);
|
|
@@ -171,6 +179,466 @@ function applyTypographyRules(rules, config) {
|
|
|
171
179
|
}
|
|
172
180
|
});
|
|
173
181
|
}
|
|
182
|
+
if (typography.headingWeight) {
|
|
183
|
+
rules.push(` --typography-headingWeight: ${typography.headingWeight};`);
|
|
184
|
+
}
|
|
185
|
+
if (typography.headingLetterSpacing) {
|
|
186
|
+
rules.push(` --typography-headingLetterSpacing: ${typography.headingLetterSpacing};`);
|
|
187
|
+
}
|
|
188
|
+
if (typography.headingTransform) {
|
|
189
|
+
rules.push(` --typography-headingTransform: ${typography.headingTransform};`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Zero-specificity base rules (`:where()`), so the chosen fonts show up on a site
|
|
194
|
+
* that has no typography CSS of its own, while any rule the site does have wins.
|
|
195
|
+
*/ function applyTypographyBaseRules(rules, config) {
|
|
196
|
+
// Only when the editor chose typography explicitly: sites that never touched it
|
|
197
|
+
// keep rendering exactly as before.
|
|
198
|
+
if (!config.typography || !config.typographyOverridden) return;
|
|
199
|
+
rules.push('');
|
|
200
|
+
rules.push('/* ── Typography base (zero specificity — site CSS always wins) ── */');
|
|
201
|
+
rules.push(':where(html[data-theme]) :where(body) {');
|
|
202
|
+
rules.push(' font-family: var(--typography-fontFamily, system-ui, sans-serif);');
|
|
203
|
+
rules.push(' font-size: calc(var(--typography-baseFontSize, 16px) * var(--theme-font-scale, 1));');
|
|
204
|
+
rules.push(' line-height: var(--typography-lineHeight, 1.6);');
|
|
205
|
+
rules.push('}');
|
|
206
|
+
rules.push(':where(html[data-theme]) :where(h1, h2, h3, h4, h5, h6) {');
|
|
207
|
+
rules.push(' font-family: var(--typography-headingFamily, var(--typography-fontFamily, inherit));');
|
|
208
|
+
rules.push(' font-weight: var(--typography-headingWeight, var(--typography-fontWeights-bold, 700));');
|
|
209
|
+
rules.push(' letter-spacing: var(--typography-headingLetterSpacing, normal);');
|
|
210
|
+
rules.push(' text-transform: var(--typography-headingTransform, none);');
|
|
211
|
+
rules.push('}');
|
|
212
|
+
}
|
|
213
|
+
function getVE(config) {
|
|
214
|
+
return config.visualEffects ?? null;
|
|
215
|
+
}
|
|
216
|
+
function getCS(config) {
|
|
217
|
+
return config.componentStyles ?? null;
|
|
218
|
+
}
|
|
219
|
+
const SHADOW_MAP = {
|
|
220
|
+
none: 'none',
|
|
221
|
+
subtle: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)',
|
|
222
|
+
medium: '0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)',
|
|
223
|
+
strong: '0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)',
|
|
224
|
+
dramatic: '0 25px 50px -12px rgba(0,0,0,0.25)'
|
|
225
|
+
};
|
|
226
|
+
const BLUR_PX_MAP = {
|
|
227
|
+
none: '0px',
|
|
228
|
+
slight: '4px',
|
|
229
|
+
medium: '8px',
|
|
230
|
+
strong: '16px',
|
|
231
|
+
heavy: '24px'
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* CSS custom properties for visual effects (emitted inside :root {})
|
|
235
|
+
*/ function applyVisualEffectsCSSVars(rules, config) {
|
|
236
|
+
const ve = getVE(config);
|
|
237
|
+
if (!ve) return;
|
|
238
|
+
if (ve.effectStyle) rules.push(` --effect-style: ${ve.effectStyle};`);
|
|
239
|
+
if (ve.shadowIntensity) {
|
|
240
|
+
rules.push(` --shadow-intensity: ${ve.shadowIntensity};`);
|
|
241
|
+
const shadow = SHADOW_MAP[ve.shadowIntensity];
|
|
242
|
+
if (shadow) rules.push(` --card-shadow: ${shadow};`);
|
|
243
|
+
}
|
|
244
|
+
if (ve.backdropBlur) {
|
|
245
|
+
const blurPx = BLUR_PX_MAP[ve.backdropBlur] ?? '0px';
|
|
246
|
+
rules.push(` --backdrop-blur: ${blurPx};`);
|
|
247
|
+
// Token form (none|slight|...) — read by the client ThemeProvider to mirror
|
|
248
|
+
// the SSR data-backdrop-blur attribute.
|
|
249
|
+
rules.push(` --backdrop-blur-level: ${ve.backdropBlur};`);
|
|
250
|
+
}
|
|
251
|
+
if (ve.borderStyle) rules.push(` --border-style: ${ve.borderStyle};`);
|
|
252
|
+
if (ve.borderWidth) rules.push(` --border-width: ${ve.borderWidth};`);
|
|
253
|
+
if (ve.glassOpacity != null) {
|
|
254
|
+
const opacity = Math.min(100, Math.max(0, ve.glassOpacity)) / 100;
|
|
255
|
+
rules.push(` --glass-opacity: ${opacity.toFixed(2)};`);
|
|
256
|
+
}
|
|
257
|
+
// Always emit --card-bg-opacity and --card-backdrop-filter so .glass-card / .glass
|
|
258
|
+
// fallback rules in consumer globals.css can be overridden regardless of cached state.
|
|
259
|
+
// Glass effect: translucent card; all other effects: reset to opaque/none.
|
|
260
|
+
const opacity = ve.glassOpacity != null ? (ve.glassOpacity / 100).toFixed(2) : '0.60';
|
|
261
|
+
const blur = BLUR_PX_MAP[ve.backdropBlur ?? 'medium'] ?? '8px';
|
|
262
|
+
rules.push(` --card-bg-opacity: ${opacity};`);
|
|
263
|
+
rules.push(` --card-backdrop-filter: blur(${blur});`);
|
|
264
|
+
rules.push(` --card-bg-opacity-non-glass: 1.0;`);
|
|
265
|
+
rules.push(` --card-backdrop-filter-non-glass: none;`);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* CSS custom properties for component styles (emitted inside :root {})
|
|
269
|
+
*/ function applyComponentStyleCSSVars(rules, config) {
|
|
270
|
+
// Brand gradient composite — always emitted so gradient buttons / cards / text
|
|
271
|
+
// can reference a single token. Falls back to primary→accent when the editor
|
|
272
|
+
// has not set explicit gradient stops.
|
|
273
|
+
rules.push(' --gradient-brand: linear-gradient(' + 'var(--gradient-angle, 135deg), ' + 'var(--gradient-from, var(--primary)), ' + 'var(--gradient-via, var(--gradient-from, var(--primary))), ' + 'var(--gradient-to, var(--accent)));');
|
|
274
|
+
const cs = getCS(config);
|
|
275
|
+
if (!cs) return;
|
|
276
|
+
if (cs.buttonVariant) rules.push(` --button-variant: ${cs.buttonVariant};`);
|
|
277
|
+
if (cs.buttonSize) rules.push(` --button-size: ${cs.buttonSize};`);
|
|
278
|
+
if (cs.cardStyle) rules.push(` --card-style: ${cs.cardStyle};`);
|
|
279
|
+
if (cs.cardHoverEffect) rules.push(` --card-hover-effect: ${cs.cardHoverEffect};`);
|
|
280
|
+
if (cs.imageStyle) rules.push(` --image-style: ${cs.imageStyle};`);
|
|
281
|
+
if (cs.navbarStyle) rules.push(` --navbar-style: ${cs.navbarStyle};`);
|
|
282
|
+
if (cs.footerStyle) rules.push(` --footer-style: ${cs.footerStyle};`);
|
|
283
|
+
if (cs.linkStyle) rules.push(` --link-style: ${cs.linkStyle};`);
|
|
284
|
+
if (cs.enableScrollReveal != null) {
|
|
285
|
+
rules.push(` --scroll-reveal: ${cs.enableScrollReveal ? '1' : '0'};`);
|
|
286
|
+
}
|
|
287
|
+
if (cs.enableHoverAnimations != null) {
|
|
288
|
+
rules.push(` --hover-animations: ${cs.enableHoverAnimations ? '1' : '0'};`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Element-level CSS overrides based on effect + component styles.
|
|
293
|
+
* These rules are emitted OUTSIDE the :root {} block so they target
|
|
294
|
+
* actual DOM elements. They rely on data-effect-style / data-card-style
|
|
295
|
+
* attributes set on <html> by layout.tsx (SSR) and ThemeProvider (client).
|
|
296
|
+
*/ function applyEffectElementRules(rules, config) {
|
|
297
|
+
const ve = getVE(config);
|
|
298
|
+
const cs = getCS(config);
|
|
299
|
+
if (!ve && !cs) return;
|
|
300
|
+
rules.push('');
|
|
301
|
+
rules.push('/* ── Effect element overrides ── */');
|
|
302
|
+
// ── Card border style / width (effect rules below may still replace it) ──
|
|
303
|
+
// Skipped for the field defaults (solid / 1px) so existing cards are unchanged.
|
|
304
|
+
if (ve?.borderStyle && (ve.borderStyle !== 'solid' || (ve.borderWidth ?? '1px') !== '1px')) {
|
|
305
|
+
rules.push(`html[data-border-style] [data-card] {`);
|
|
306
|
+
rules.push(` border-style: var(--border-style, solid);`);
|
|
307
|
+
rules.push(` border-width: var(--border-width, 1px);`);
|
|
308
|
+
rules.push(` border-color: var(--border);`);
|
|
309
|
+
rules.push(`}`);
|
|
310
|
+
}
|
|
311
|
+
// ── Glass effect ──────────────────────────────────────────────────────
|
|
312
|
+
// NOTE: All effect-style blocks are ALWAYS emitted regardless of the saved
|
|
313
|
+
// effectStyle value. The CSS selectors are scoped by html[data-effect-style='X']
|
|
314
|
+
// so only the matching data-attribute activates the rules. This means the CSS
|
|
315
|
+
// is always correct even when stale cached/draft data is served.
|
|
316
|
+
{
|
|
317
|
+
const opacity = ve?.glassOpacity != null ? ve.glassOpacity : 60;
|
|
318
|
+
const blur = BLUR_PX_MAP[ve?.backdropBlur ?? 'strong'] ?? '16px';
|
|
319
|
+
rules.push(`html[data-effect-style='glass'] [data-card],`);
|
|
320
|
+
rules.push(`html[data-effect-style='glass'] .glass-card,`);
|
|
321
|
+
rules.push(`html[data-effect-style='glass'] .glass {`);
|
|
322
|
+
rules.push(` background-color: color-mix(in srgb, var(--card) ${opacity}%, transparent) !important;`);
|
|
323
|
+
rules.push(` backdrop-filter: blur(${blur}) saturate(150%) !important;`);
|
|
324
|
+
rules.push(` -webkit-backdrop-filter: blur(${blur}) saturate(150%) !important;`);
|
|
325
|
+
rules.push(` border-color: color-mix(in srgb, var(--border) 40%, transparent) !important;`);
|
|
326
|
+
rules.push(` box-shadow: 0 4px 24px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.1) !important;`);
|
|
327
|
+
rules.push(`}`);
|
|
328
|
+
rules.push(`html[data-effect-style='glass'] [data-card]:hover,`);
|
|
329
|
+
rules.push(`html[data-effect-style='glass'] .glass-card:hover,`);
|
|
330
|
+
rules.push(`html[data-effect-style='glass'] .glass:hover {`);
|
|
331
|
+
rules.push(` background-color: color-mix(in srgb, var(--card) ${Math.min(opacity + 10, 90)}%, transparent) !important;`);
|
|
332
|
+
rules.push(` box-shadow: 0 8px 32px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,0.15) !important;`);
|
|
333
|
+
rules.push(`}`);
|
|
334
|
+
// Apply the glass surface to the navbar container, but never to a <nav>
|
|
335
|
+
// nested inside a <header> (or <footer>) — otherwise the inner nav paints a
|
|
336
|
+
// second glass layer on top of the header's, producing a visible double-tint.
|
|
337
|
+
// A standalone top-level <nav> (header-less layouts) still gets the surface.
|
|
338
|
+
rules.push(`html[data-effect-style='glass'] header, html[data-effect-style='glass'] nav:not(header nav):not(footer nav) {`);
|
|
339
|
+
rules.push(` background-color: color-mix(in srgb, var(--background) 65%, transparent) !important;`);
|
|
340
|
+
rules.push(` backdrop-filter: blur(${blur}) saturate(150%) !important;`);
|
|
341
|
+
rules.push(` -webkit-backdrop-filter: blur(${blur}) saturate(150%) !important;`);
|
|
342
|
+
rules.push(`}`);
|
|
343
|
+
}
|
|
344
|
+
// ── Neumorphic effect ──────────────────────────────────────────────────
|
|
345
|
+
{
|
|
346
|
+
rules.push(`html[data-effect-style='neumorphic'] [data-card],`);
|
|
347
|
+
rules.push(`html[data-effect-style='neumorphic'] .glass-card,`);
|
|
348
|
+
rules.push(`html[data-effect-style='neumorphic'] .glass {`);
|
|
349
|
+
rules.push(` background-color: var(--background) !important;`);
|
|
350
|
+
rules.push(` border: none !important;`);
|
|
351
|
+
rules.push(` backdrop-filter: none !important;`);
|
|
352
|
+
rules.push(` -webkit-backdrop-filter: none !important;`);
|
|
353
|
+
rules.push(` box-shadow: 6px 6px 12px rgba(0,0,0,0.12), -6px -6px 12px rgba(255,255,255,0.75) !important;`);
|
|
354
|
+
rules.push(`}`);
|
|
355
|
+
rules.push(`html[data-effect-style='neumorphic'] [data-card]:hover,`);
|
|
356
|
+
rules.push(`html[data-effect-style='neumorphic'] .glass-card:hover,`);
|
|
357
|
+
rules.push(`html[data-effect-style='neumorphic'] .glass:hover {`);
|
|
358
|
+
rules.push(` box-shadow: 8px 8px 16px rgba(0,0,0,0.15), -8px -8px 16px rgba(255,255,255,0.85) !important;`);
|
|
359
|
+
rules.push(`}`);
|
|
360
|
+
rules.push(`html[data-effect-style='neumorphic'][data-theme-mode='dark'] [data-card],`);
|
|
361
|
+
rules.push(`html[data-effect-style='neumorphic'].dark [data-card],`);
|
|
362
|
+
rules.push(`html[data-effect-style='neumorphic'][data-theme-mode='dark'] .glass-card,`);
|
|
363
|
+
rules.push(`html[data-effect-style='neumorphic'].dark .glass-card {`);
|
|
364
|
+
rules.push(` box-shadow: 6px 6px 12px rgba(0,0,0,0.4), -6px -6px 12px rgba(255,255,255,0.04) !important;`);
|
|
365
|
+
rules.push(`}`);
|
|
366
|
+
}
|
|
367
|
+
// ── Clay effect ────────────────────────────────────────────────────────
|
|
368
|
+
{
|
|
369
|
+
rules.push(`html[data-effect-style='clay'] [data-card],`);
|
|
370
|
+
rules.push(`html[data-effect-style='clay'] .glass-card,`);
|
|
371
|
+
rules.push(`html[data-effect-style='clay'] .glass {`);
|
|
372
|
+
rules.push(` border-radius: var(--radius-large, 1.5rem) !important;`);
|
|
373
|
+
rules.push(` box-shadow: 4px 4px 0px rgba(0,0,0,0.22), 0 8px 20px rgba(0,0,0,0.08) !important;`);
|
|
374
|
+
rules.push(` border: none !important;`);
|
|
375
|
+
rules.push(` backdrop-filter: none !important;`);
|
|
376
|
+
rules.push(` -webkit-backdrop-filter: none !important;`);
|
|
377
|
+
rules.push(` transition: transform 200ms ease, box-shadow 200ms ease !important;`);
|
|
378
|
+
rules.push(`}`);
|
|
379
|
+
rules.push(`html[data-effect-style='clay'] [data-card]:hover,`);
|
|
380
|
+
rules.push(`html[data-effect-style='clay'] .glass-card:hover,`);
|
|
381
|
+
rules.push(`html[data-effect-style='clay'] .glass:hover {`);
|
|
382
|
+
rules.push(` transform: translateY(-3px) !important;`);
|
|
383
|
+
rules.push(` box-shadow: 6px 6px 0px rgba(0,0,0,0.25), 0 12px 24px rgba(0,0,0,0.12) !important;`);
|
|
384
|
+
rules.push(`}`);
|
|
385
|
+
}
|
|
386
|
+
// ── Elevated effect ────────────────────────────────────────────────────
|
|
387
|
+
{
|
|
388
|
+
const shadow = ve?.shadowIntensity ? SHADOW_MAP[ve.shadowIntensity] ?? SHADOW_MAP.medium : SHADOW_MAP.medium;
|
|
389
|
+
rules.push(`html[data-effect-style='elevated'] [data-card],`);
|
|
390
|
+
rules.push(`html[data-effect-style='elevated'] .glass-card,`);
|
|
391
|
+
rules.push(`html[data-effect-style='elevated'] .glass {`);
|
|
392
|
+
rules.push(` box-shadow: ${shadow} !important;`);
|
|
393
|
+
rules.push(` border: none !important;`);
|
|
394
|
+
rules.push(` backdrop-filter: none !important;`);
|
|
395
|
+
rules.push(` -webkit-backdrop-filter: none !important;`);
|
|
396
|
+
rules.push(` transition: box-shadow 200ms ease, transform 200ms ease !important;`);
|
|
397
|
+
rules.push(`}`);
|
|
398
|
+
rules.push(`html[data-effect-style='elevated'] [data-card]:hover,`);
|
|
399
|
+
rules.push(`html[data-effect-style='elevated'] .glass-card:hover,`);
|
|
400
|
+
rules.push(`html[data-effect-style='elevated'] .glass:hover {`);
|
|
401
|
+
rules.push(` box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1) !important;`);
|
|
402
|
+
rules.push(` transform: translateY(-2px) !important;`);
|
|
403
|
+
rules.push(`}`);
|
|
404
|
+
}
|
|
405
|
+
// ── Flat effect ────────────────────────────────────────────────────────
|
|
406
|
+
{
|
|
407
|
+
rules.push(`html[data-effect-style='flat'] [data-card],`);
|
|
408
|
+
rules.push(`html[data-effect-style='flat'] .glass-card,`);
|
|
409
|
+
rules.push(`html[data-effect-style='flat'] .glass {`);
|
|
410
|
+
rules.push(` box-shadow: none !important;`);
|
|
411
|
+
rules.push(` backdrop-filter: none !important;`);
|
|
412
|
+
rules.push(` -webkit-backdrop-filter: none !important;`);
|
|
413
|
+
rules.push(`}`);
|
|
414
|
+
}
|
|
415
|
+
// ── Border overrides ───────────────────────────────────────────────────
|
|
416
|
+
if (ve?.borderWidth && ve.borderWidth !== '1px' && ve.borderWidth !== '0px') {
|
|
417
|
+
rules.push(`html[data-border-width='${ve.borderWidth}'] [data-card],`);
|
|
418
|
+
rules.push(`html[data-border-width='${ve.borderWidth}'] .glass-card {`);
|
|
419
|
+
rules.push(` border-width: ${ve.borderWidth} !important;`);
|
|
420
|
+
rules.push(`}`);
|
|
421
|
+
}
|
|
422
|
+
// ── Card style: bordered (used by brutalism etc.) ──────────────────────
|
|
423
|
+
if (cs?.cardStyle === 'bordered') {
|
|
424
|
+
const bw = ve?.borderWidth ?? '2px';
|
|
425
|
+
rules.push(`html[data-card-style='bordered'] [data-card],`);
|
|
426
|
+
rules.push(`html[data-card-style='bordered'] .glass-card {`);
|
|
427
|
+
rules.push(` border-width: ${bw} !important;`);
|
|
428
|
+
rules.push(` border-style: solid !important;`);
|
|
429
|
+
rules.push(` border-color: var(--foreground) !important;`);
|
|
430
|
+
rules.push(` box-shadow: 4px 4px 0 var(--foreground) !important;`);
|
|
431
|
+
rules.push(` border-radius: 0 !important;`);
|
|
432
|
+
rules.push(` background-color: var(--card) !important;`);
|
|
433
|
+
rules.push(` backdrop-filter: none !important;`);
|
|
434
|
+
rules.push(` -webkit-backdrop-filter: none !important;`);
|
|
435
|
+
rules.push(`}`);
|
|
436
|
+
rules.push(`html[data-card-style='bordered'] [data-card]:hover,`);
|
|
437
|
+
rules.push(`html[data-card-style='bordered'] .glass-card:hover {`);
|
|
438
|
+
rules.push(` box-shadow: 6px 6px 0 var(--foreground) !important;`);
|
|
439
|
+
rules.push(` transform: translate(-2px, -2px) !important;`);
|
|
440
|
+
rules.push(`}`);
|
|
441
|
+
}
|
|
442
|
+
// ── Card style: gradient-border ────────────────────────────────────────
|
|
443
|
+
if (cs?.cardStyle === 'gradient-border') {
|
|
444
|
+
rules.push(`html[data-card-style='gradient-border'] [data-card],`);
|
|
445
|
+
rules.push(`html[data-card-style='gradient-border'] .glass-card {`);
|
|
446
|
+
rules.push(` border-image: var(--gradient-brand) 1 !important;`);
|
|
447
|
+
rules.push(` border-width: 2px !important;`);
|
|
448
|
+
rules.push(` border-style: solid !important;`);
|
|
449
|
+
rules.push(`}`);
|
|
450
|
+
}
|
|
451
|
+
// ── Navbar styles ──────────────────────────────────────────────────────
|
|
452
|
+
const navbarStyle = cs?.navbarStyle;
|
|
453
|
+
if (navbarStyle === 'blur') {
|
|
454
|
+
rules.push(`html[data-navbar-style='blur'] header {`);
|
|
455
|
+
rules.push(` background-color: color-mix(in srgb, var(--background) 70%, transparent) !important;`);
|
|
456
|
+
rules.push(` backdrop-filter: blur(12px) !important;`);
|
|
457
|
+
rules.push(` -webkit-backdrop-filter: blur(12px) !important;`);
|
|
458
|
+
rules.push(`}`);
|
|
459
|
+
} else if (navbarStyle === 'transparent') {
|
|
460
|
+
rules.push(`html[data-navbar-style='transparent'] header {`);
|
|
461
|
+
rules.push(` background-color: transparent !important;`);
|
|
462
|
+
rules.push(` border-bottom-color: transparent !important;`);
|
|
463
|
+
rules.push(`}`);
|
|
464
|
+
} else if (navbarStyle === 'floating') {
|
|
465
|
+
rules.push(`html[data-navbar-style='floating'] header {`);
|
|
466
|
+
rules.push(` margin: 12px 16px 0;`);
|
|
467
|
+
rules.push(` border-radius: var(--radius-large, 1.5rem);`);
|
|
468
|
+
rules.push(` border: 1px solid var(--border);`);
|
|
469
|
+
rules.push(` box-shadow: 0 4px 24px rgba(0,0,0,0.08);`);
|
|
470
|
+
rules.push(`}`);
|
|
471
|
+
} else if (navbarStyle === 'minimal') {
|
|
472
|
+
rules.push(`html[data-navbar-style='minimal'] header {`);
|
|
473
|
+
rules.push(` border-bottom-color: transparent !important;`);
|
|
474
|
+
rules.push(` box-shadow: none !important;`);
|
|
475
|
+
rules.push(`}`);
|
|
476
|
+
}
|
|
477
|
+
// ── Button variant: brutal ─────────────────────────────────────────────
|
|
478
|
+
if (cs?.buttonVariant === 'brutal') {
|
|
479
|
+
rules.push(`html[data-button-variant='brutal'] [data-btn] {`);
|
|
480
|
+
rules.push(` border: 2px solid var(--foreground) !important;`);
|
|
481
|
+
rules.push(` border-radius: 0 !important;`);
|
|
482
|
+
rules.push(` box-shadow: 3px 3px 0 var(--foreground) !important;`);
|
|
483
|
+
rules.push(` transition: box-shadow 100ms ease, transform 100ms ease !important;`);
|
|
484
|
+
rules.push(`}`);
|
|
485
|
+
rules.push(`html[data-button-variant='brutal'] [data-btn]:hover {`);
|
|
486
|
+
rules.push(` box-shadow: 5px 5px 0 var(--foreground) !important;`);
|
|
487
|
+
rules.push(` transform: translate(-2px, -2px) !important;`);
|
|
488
|
+
rules.push(`}`);
|
|
489
|
+
rules.push(`html[data-button-variant='brutal'] [data-btn]:active {`);
|
|
490
|
+
rules.push(` box-shadow: 1px 1px 0 var(--foreground) !important;`);
|
|
491
|
+
rules.push(` transform: translate(2px, 2px) !important;`);
|
|
492
|
+
rules.push(`}`);
|
|
493
|
+
}
|
|
494
|
+
// ── Button variant: pill ───────────────────────────────────────────────
|
|
495
|
+
if (cs?.buttonVariant === 'pill') {
|
|
496
|
+
rules.push(`html[data-button-variant='pill'] [data-btn] {`);
|
|
497
|
+
rules.push(` border-radius: 9999px !important;`);
|
|
498
|
+
rules.push(`}`);
|
|
499
|
+
}
|
|
500
|
+
// ── Button variants: outlined / ghost ──────────────────────────────────
|
|
501
|
+
if (cs?.buttonVariant === 'outlined') {
|
|
502
|
+
rules.push(`html[data-button-variant='outlined'] [data-btn] {`);
|
|
503
|
+
rules.push(` background-color: transparent !important;`);
|
|
504
|
+
rules.push(` color: var(--primary) !important;`);
|
|
505
|
+
rules.push(` border: 1.5px solid var(--primary) !important;`);
|
|
506
|
+
rules.push(` box-shadow: none !important;`);
|
|
507
|
+
rules.push(`}`);
|
|
508
|
+
rules.push(`html[data-button-variant='outlined'] [data-btn]:hover {`);
|
|
509
|
+
rules.push(` background-color: color-mix(in srgb, var(--primary) 10%, transparent) !important;`);
|
|
510
|
+
rules.push(`}`);
|
|
511
|
+
} else if (cs?.buttonVariant === 'ghost') {
|
|
512
|
+
rules.push(`html[data-button-variant='ghost'] [data-btn] {`);
|
|
513
|
+
rules.push(` background-color: transparent !important;`);
|
|
514
|
+
rules.push(` color: var(--primary) !important;`);
|
|
515
|
+
rules.push(` border-color: transparent !important;`);
|
|
516
|
+
rules.push(` box-shadow: none !important;`);
|
|
517
|
+
rules.push(`}`);
|
|
518
|
+
rules.push(`html[data-button-variant='ghost'] [data-btn]:hover {`);
|
|
519
|
+
rules.push(` background-color: color-mix(in srgb, var(--primary) 10%, transparent) !important;`);
|
|
520
|
+
rules.push(`}`);
|
|
521
|
+
}
|
|
522
|
+
// ── Card hover effects ─────────────────────────────────────────────────
|
|
523
|
+
if (cs?.cardHoverEffect === 'lift') {
|
|
524
|
+
rules.push(`html[data-card-hover='lift'] [data-card]:hover,`);
|
|
525
|
+
rules.push(`html[data-card-hover='lift'] .glass-card:hover {`);
|
|
526
|
+
rules.push(` transform: translateY(-6px) !important;`);
|
|
527
|
+
rules.push(` box-shadow: 0 20px 40px rgba(0,0,0,0.12) !important;`);
|
|
528
|
+
rules.push(`}`);
|
|
529
|
+
} else if (cs?.cardHoverEffect === 'scale') {
|
|
530
|
+
rules.push(`html[data-card-hover='scale'] [data-card]:hover,`);
|
|
531
|
+
rules.push(`html[data-card-hover='scale'] .glass-card:hover {`);
|
|
532
|
+
rules.push(` transform: scale(1.02) !important;`);
|
|
533
|
+
rules.push(`}`);
|
|
534
|
+
} else if (cs?.cardHoverEffect === 'glow') {
|
|
535
|
+
rules.push(`html[data-card-hover='glow'] [data-card]:hover,`);
|
|
536
|
+
rules.push(`html[data-card-hover='glow'] .glass-card:hover {`);
|
|
537
|
+
rules.push(` box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 25%, transparent), 0 8px 32px rgba(0,0,0,0.1) !important;`);
|
|
538
|
+
rules.push(`}`);
|
|
539
|
+
} else if (cs?.cardHoverEffect === 'tilt') {
|
|
540
|
+
rules.push(`html[data-card-hover='tilt'] [data-card],`);
|
|
541
|
+
rules.push(`html[data-card-hover='tilt'] .glass-card {`);
|
|
542
|
+
rules.push(` transition: transform 200ms ease !important;`);
|
|
543
|
+
rules.push(`}`);
|
|
544
|
+
rules.push(`html[data-card-hover='tilt'] [data-card]:hover,`);
|
|
545
|
+
rules.push(`html[data-card-hover='tilt'] .glass-card:hover {`);
|
|
546
|
+
rules.push(` transform: perspective(1000px) rotateX(2deg) rotateY(-2deg) !important;`);
|
|
547
|
+
rules.push(`}`);
|
|
548
|
+
}
|
|
549
|
+
// ── Button variant: gradient ───────────────────────────────────────────
|
|
550
|
+
if (cs?.buttonVariant === 'gradient') {
|
|
551
|
+
rules.push(`html[data-button-variant='gradient'] [data-btn] {`);
|
|
552
|
+
rules.push(` background-image: var(--gradient-brand) !important;`);
|
|
553
|
+
rules.push(` background-color: transparent !important;`);
|
|
554
|
+
rules.push(` color: var(--primary-foreground) !important;`);
|
|
555
|
+
rules.push(` border: none !important;`);
|
|
556
|
+
rules.push(`}`);
|
|
557
|
+
}
|
|
558
|
+
// ── Button sizes ────────────────────────────────────────────────────────
|
|
559
|
+
if (cs?.buttonSize) {
|
|
560
|
+
const sizeMap = {
|
|
561
|
+
small: {
|
|
562
|
+
py: '0.375rem',
|
|
563
|
+
px: '0.75rem',
|
|
564
|
+
fs: '0.8125rem'
|
|
565
|
+
},
|
|
566
|
+
medium: {
|
|
567
|
+
py: '0.5rem',
|
|
568
|
+
px: '1rem',
|
|
569
|
+
fs: '0.875rem'
|
|
570
|
+
},
|
|
571
|
+
large: {
|
|
572
|
+
py: '0.625rem',
|
|
573
|
+
px: '1.5rem',
|
|
574
|
+
fs: '1rem'
|
|
575
|
+
},
|
|
576
|
+
xl: {
|
|
577
|
+
py: '0.875rem',
|
|
578
|
+
px: '2rem',
|
|
579
|
+
fs: '1.125rem'
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
const s = sizeMap[cs.buttonSize] ?? sizeMap.medium;
|
|
583
|
+
rules.push(`html[data-button-size='${cs.buttonSize}'] [data-btn] {`);
|
|
584
|
+
rules.push(` padding: ${s.py} ${s.px} !important;`);
|
|
585
|
+
rules.push(` font-size: ${s.fs} !important;`);
|
|
586
|
+
rules.push(`}`);
|
|
587
|
+
}
|
|
588
|
+
// ── Image styles ───────────────────────────────────────────────────────
|
|
589
|
+
// Target both [data-img] attributes and the .themed-image helper class.
|
|
590
|
+
if (cs?.imageStyle && cs.imageStyle !== 'default') {
|
|
591
|
+
const style = cs.imageStyle;
|
|
592
|
+
const sel = `html[data-image-style='${style}'] [data-img], html[data-image-style='${style}'] .themed-image`;
|
|
593
|
+
const hoverSel = `html[data-image-style='${style}'] [data-img]:hover, html[data-image-style='${style}'] .themed-image:hover`;
|
|
594
|
+
if (style === 'rounded') {
|
|
595
|
+
rules.push(`${sel} { border-radius: var(--radius-large, 1rem) !important; overflow: hidden; }`);
|
|
596
|
+
} else if (style === 'circle') {
|
|
597
|
+
rules.push(`${sel} { border-radius: 9999px !important; aspect-ratio: 1 / 1; object-fit: cover; }`);
|
|
598
|
+
} else if (style === 'grayscale') {
|
|
599
|
+
rules.push(`${sel} { filter: grayscale(1); transition: filter 300ms ease; }`);
|
|
600
|
+
rules.push(`${hoverSel} { filter: grayscale(0); }`);
|
|
601
|
+
} else if (style === 'duotone') {
|
|
602
|
+
rules.push(`${sel} { filter: grayscale(1) contrast(1.05); mix-blend-mode: luminosity; }`);
|
|
603
|
+
} else if (style === 'vignette') {
|
|
604
|
+
rules.push(`${sel} { box-shadow: inset 0 0 60px rgba(0,0,0,0.45); }`);
|
|
605
|
+
} else if (style === 'polaroid') {
|
|
606
|
+
rules.push(`${sel} { background: #fff; padding: 10px 10px 36px; box-shadow: 0 6px 16px rgba(0,0,0,0.18); border-radius: 2px; }`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// ── Link styles ─────────────────────────────────────────────────────────
|
|
610
|
+
if (cs?.linkStyle) {
|
|
611
|
+
const style = cs.linkStyle;
|
|
612
|
+
const sel = `html[data-link-style='${style}'] [data-link], html[data-link-style='${style}'] .themed-link`;
|
|
613
|
+
const hoverSel = `html[data-link-style='${style}'] [data-link]:hover, html[data-link-style='${style}'] .themed-link:hover`;
|
|
614
|
+
if (style === 'underline') {
|
|
615
|
+
rules.push(`${sel} { text-decoration: underline; text-underline-offset: 0.15em; }`);
|
|
616
|
+
} else if (style === 'none') {
|
|
617
|
+
rules.push(`${sel} { text-decoration: none; }`);
|
|
618
|
+
} else if (style === 'underline-hover') {
|
|
619
|
+
rules.push(`${sel} { text-decoration: none; }`);
|
|
620
|
+
rules.push(`${hoverSel} { text-decoration: underline; text-underline-offset: 0.15em; }`);
|
|
621
|
+
} else if (style === 'highlight') {
|
|
622
|
+
rules.push(`${sel} { text-decoration: none; background-image: linear-gradient(transparent 60%, color-mix(in srgb, var(--primary) 28%, transparent) 0); }`);
|
|
623
|
+
} else if (style === 'animated') {
|
|
624
|
+
rules.push(`${sel} { text-decoration: none; background-image: var(--gradient-brand); background-size: 0% 2px; background-position: 0 100%; background-repeat: no-repeat; transition: background-size 300ms ease; }`);
|
|
625
|
+
rules.push(`${hoverSel} { background-size: 100% 2px; }`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
// ── Footer styles ─────────────────────────────────────────────────────────
|
|
629
|
+
if (cs?.footerStyle === 'dark') {
|
|
630
|
+
rules.push(`html[data-footer-style='dark'] footer { background-color: var(--foreground) !important; color: var(--background) !important; }`);
|
|
631
|
+
} else if (cs?.footerStyle === 'full-color') {
|
|
632
|
+
rules.push(`html[data-footer-style='full-color'] footer { background-color: var(--primary) !important; color: var(--primary-foreground) !important; }`);
|
|
633
|
+
} else if (cs?.footerStyle === 'gradient-top') {
|
|
634
|
+
rules.push(`html[data-footer-style='gradient-top'] footer { border-top: 3px solid transparent; border-image: var(--gradient-brand) 1; }`);
|
|
635
|
+
} else if (cs?.footerStyle === 'minimal') {
|
|
636
|
+
rules.push(`html[data-footer-style='minimal'] footer { background: transparent !important; border-top: 1px solid var(--border) !important; box-shadow: none !important; }`);
|
|
637
|
+
}
|
|
638
|
+
// ── Hover animations off — neutralise interactive transforms ──────────────
|
|
639
|
+
if (cs?.enableHoverAnimations === false) {
|
|
640
|
+
rules.push(`html[data-hover-animations='off'] [data-card]:hover, html[data-hover-animations='off'] .glass-card:hover, html[data-hover-animations='off'] [data-btn]:hover { transform: none !important; }`);
|
|
641
|
+
}
|
|
174
642
|
}
|
|
175
643
|
function applyDarkModeOverrides(rules, config, customization, selector) {
|
|
176
644
|
if (config.colorMode !== 'dark' && config.colorMode !== 'auto') return;
|