PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.6
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.6
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Services / Theme / Readers / BlocksySettingsReader.php

BlocksySettingsReader.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.6, at app/Services/Theme/Readers/BlocksySettingsReader.php

224 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\Theme\Readers;
4
5 use FluentCart\App\Services\Theme\ColorMath;
6 use FluentCart\App\Services\Theme\ThemePalette;
7 use FluentCart\Framework\Support\Arr;
8
9 /**
10 * Blocksy's Customizer colours, read from its theme mods rather than its slots.
11 *
12 * Blocksy keeps each semantic colour as a theme mod shaped
13 * `['default' => ['color' => …], 'hover' => ['color' => …]]`, whose colour
14 * points at a palette slot (`var(--theme-palette-color-N)`) or holds a custom
15 * colour. Links, Base Text, Borders, Site Background and Buttons are separate
16 * settings — the button is not tied to the link colour — so each role is read
17 * from its own mod.
18 *
19 * A mod the owner never saved, or a sub-key missing from one, takes Blocksy's
20 * own default for it, the same fill `blocksy_get_colors()` applies before
21 * printing (inc/dynamic-styles/global/all.php). A colour saved as Blocksy's
22 * "inherit" sentinel (`CT_CSS_SKIP_RULE…`) counts as unset the same way.
23 *
24 * Palette references are resolved through
25 * `blocksy_manager()->colors->get_color_palette()` (see paletteValues()), and
26 * always kept live: Blocksy Companion's dark mode redefines the palette
27 * properties under `:root[data-color-mode*="dark"]`, which a bare hex would
28 * never follow.
29 *
30 * Verified against Blocksy 2.1.57.
31 */
32 class BlocksySettingsReader implements ThemeSettingsReader
33 {
34 /**
35 * Blocksy's defaults per mod and sub-key (inc/dynamic-styles/global/all.php
36 * and background.php).
37 *
38 * @var array
39 */
40 protected static $defaults = [
41 'linkColor' => ['default' => 'var(--theme-palette-color-1)', 'hover' => 'var(--theme-palette-color-2)'],
42 'fontColor' => ['default' => 'var(--theme-palette-color-3)'],
43 'border_color' => ['default' => 'var(--theme-palette-color-5)'],
44 'buttonColor' => ['default' => 'var(--theme-palette-color-1)', 'hover' => 'var(--theme-palette-color-2)'],
45 'buttonTextColor' => ['default' => '#ffffff', 'hover' => '#ffffff'],
46 'site_background' => ['default' => 'var(--theme-palette-color-7)'],
47 ];
48
49 /**
50 * Detected by Blocksy's own manager, not by theme name, so a child theme
51 * or renamed folder keeps working.
52 *
53 * @return bool
54 */
55 public static function applies(): bool
56 {
57 return function_exists('blocksy_get_theme_mod')
58 && function_exists('blocksy_manager')
59 && is_object(blocksy_manager());
60 }
61
62 /**
63 * @return array Role => hex or `var(--theme-palette-color-N, #hex)`.
64 */
65 public static function roles(): array
66 {
67 if (!self::applies()) {
68 return [];
69 }
70
71 $roles = [
72 'accent' => self::read('linkColor'),
73 'text' => self::read('fontColor'),
74 'border' => self::read('border_color'),
75 'surface' => self::surface(),
76 ];
77
78 // Blocksy states both halves of its button, resting and hover. The
79 // hover belongs to the resting button: without one there is no hover.
80 $button = self::buttonPair('default');
81
82 if ($button) {
83 $roles = array_merge($roles, $button, self::buttonPair('hover', 'button_hover_'));
84 }
85
86 return array_filter($roles, function ($value) {
87 return $value !== '';
88 });
89 }
90
91 /**
92 * Each palette slot's property and current colour: `--theme-palette-color-N`
93 * (or the slot's own `variable`) => hex. The same list Blocksy prints the
94 * properties from and publishes to the editor palette.
95 *
96 * @return array Property => colour, as Blocksy saved it.
97 */
98 public static function paletteValues(): array
99 {
100 if (!self::applies()) {
101 return [];
102 }
103
104 $manager = blocksy_manager();
105 $colors = isset($manager->colors) ? $manager->colors : null;
106
107 if (!is_object($colors) || !method_exists($colors, 'get_color_palette')) {
108 return [];
109 }
110
111 $values = [];
112
113 try {
114 foreach ((array)$colors->get_color_palette() as $slot) {
115 $variable = (string)Arr::get((array)$slot, 'variable', '');
116
117 if ($variable !== '') {
118 $values['--' . ltrim($variable, '-')] = (string)Arr::get((array)$slot, 'color', '');
119 }
120 }
121 } catch (\Throwable $e) {
122 // Blocksy's API misbehaving means no palette values: references
123 // stay bare and unmeasurable, which resolve() already refuses.
124 return [];
125 }
126
127 return $values;
128 }
129
130 /**
131 * One button half-pair: background from `buttonColor`, text from
132 * `buttonTextColor`, both at the same state.
133 *
134 * A background that is set but unwritable (an rgba(), say) is not
135 * replaced by a default — Blocksy is painting it, just not in a form
136 * FluentCart can write — so the pair is omitted. A text that cannot be
137 * written gets the colour that reads on the background.
138 *
139 * @param string $state 'default' or 'hover'.
140 * @param string $prefix Role prefix.
141 * @return array
142 */
143 protected static function buttonPair(string $state, string $prefix = 'button_'): array
144 {
145 $background = self::read('buttonColor', $state);
146
147 if ($background === '') {
148 return [];
149 }
150
151 $text = self::read('buttonTextColor', $state);
152
153 if ($text === '') {
154 $bgHex = ThemePalette::measurable($background);
155 $text = $bgHex !== '' ? ColorMath::readableText($bgHex) : '';
156 }
157
158 return [
159 $prefix . 'bg' => $background,
160 $prefix . 'text' => $text,
161 ];
162 }
163
164 /**
165 * The body background (Site Background). Blocksy saves it flat or per
166 * device; desktop speaks for all, as blocksy_expand_responsive_value()
167 * reads it. A gradient paints no colour (Blocksy writes
168 * `background-color: initial`), so it states no surface.
169 *
170 * @return string
171 */
172 protected static function surface(): string
173 {
174 $value = blocksy_get_theme_mod('site_background', []);
175
176 if (is_array($value) && isset($value['desktop'])) {
177 $value = $value['desktop'];
178 }
179
180 $value = is_array($value) ? $value : [];
181
182 if (Arr::get($value, 'background_type', 'color') === 'gradient') {
183 return '';
184 }
185
186 return self::normalise(
187 Arr::get($value, 'backgroundColor.default.color'),
188 self::$defaults['site_background']['default']
189 );
190 }
191
192 /**
193 * One colour mod at one state, over Blocksy's default for it.
194 *
195 * @param string $mod
196 * @param string $state
197 * @return string
198 */
199 protected static function read(string $mod, string $state = 'default'): string
200 {
201 $value = blocksy_get_theme_mod($mod, []);
202 $raw = is_array($value) ? Arr::get($value, $state . '.color') : null;
203
204 return self::normalise($raw, (string)Arr::get(self::$defaults, $mod . '.' . $state, ''));
205 }
206
207 /**
208 * Unset — missing, empty, or Blocksy's inherit sentinel — takes the
209 * default; anything else is normalised as saved.
210 *
211 * @param mixed $raw
212 * @param string $default
213 * @return string
214 */
215 protected static function normalise($raw, string $default): string
216 {
217 if (!is_string($raw) || trim($raw) === '' || strpos($raw, 'CT_CSS_SKIP_RULE') === 0) {
218 $raw = $default;
219 }
220
221 return ThemePalette::settingValue($raw);
222 }
223 }
224