PluginProbe
Extendify / trunk
Extendify vtrunk
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | src/Agent/workflows/theme/components/change-site-design/SelectSiteDesign.jsx +92 -27 3.1.1 → trunk View file →
@@ -1,13 +1,19 @@
1 +import { usePaletteOverride } from '@agent/hooks/usePaletteOverride';
2 +import { usePalettes } from '@agent/hooks/usePalettes';
1 3 import { useSiteVibesOverride } from '@agent/hooks/useSiteVibesOverride';
2 4 import { useSiteVibesVariations } from '@agent/hooks/useSiteVibesVariations';
3 5 import { useVariationOverride } from '@agent/hooks/useVariationOverride';
6 +import { refreshBlockHighlight } from '@agent/lib/block-highlight';
4 7 import { DesignOption } from '@agent/workflows/theme/components/change-site-design/DesignOption';
8 +import { fontsOnlyVariation } from '@agent/workflows/theme/components/change-site-design/utils/fontsOnlyVariation';
5 9 import { removeAnimationClasses } from '@agent/workflows/theme/components/change-site-design/utils/removeAnimationClasses';
6 10 import { handleSiteImages } from '@auto-launch/fetchers/get-images';
7 -import { handleSiteStrings } from '@auto-launch/fetchers/get-strings';
8 11 import { useUserSelectionStore } from '@launch/state/user-selections';
12 +import { paletteDuotone } from '@shared/lib/palette-preview';
13 +import { samplePalettes } from '@shared/lib/palettes';
9 14 import { safeParseJson } from '@shared/lib/parsing';
15 +import { normalizeSiteImages } from '@shared/lib/site-images';
10 16 import apiFetch from '@wordpress/api-fetch';
11 17 import { registerCoreBlocks } from '@wordpress/block-library';
12 18 import { getBlockTypes, parse, serialize } from '@wordpress/blocks';
13 19 import { Spinner } from '@wordpress/components';
@@ -57,8 +63,31 @@
57 63 const isAdmin = context?.adminPage;
58 64
59 65 const PAGE_SIZE = 5;
60 66
67 +const hasImages = ({ hero, general }) => hero.length > 0 || general.length > 0;
68 +
69 +const resolveSiteImages = async ({ storedSiteImages, siteProfile }) => {
70 + const stored = normalizeSiteImages(storedSiteImages);
71 + if (hasImages(stored)) return stored;
72 +
73 + // A browser that didn't run Launch otherwise reuses one image on every option.
74 + const localized = normalizeSiteImages(window.extSharedData.siteImages);
75 + if (hasImages(localized)) return localized;
76 +
77 + if (siteProfile) {
78 + const { siteImages } = await handleSiteImages({ siteProfile });
79 + const fetched = normalizeSiteImages(siteImages);
80 + if (hasImages(fetched)) return fetched;
81 + }
82 +
83 + const saved = await apiFetch({
84 + path: '/extendify/v1/shared/site-images',
85 + }).catch(() => null);
86 +
87 + return normalizeSiteImages(saved?.siteImages);
88 +};
89 +
61 90 export const SelectSiteDesign = ({ onConfirm, onCancel }) => {
62 91 const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);
63 92 const [isLoading, setIsLoading] = useState(false);
64 93 const [isSaving, setIsSaving] = useState(false);
@@ -71,8 +100,9 @@
71 100
72 101 const [selectedColorAndFonts, setSelectedColorAndFonts] = useState();
73 102 const [selectedHeroPattern, setSelectedHeroPattern] = useState();
74 103 const [selectedVibe, setSelectedVibe] = useState();
104 + const [selectedPalette, setSelectedPalette] = useState();
75 105
76 106 const { updateSettings } = useDispatch('core/block-editor');
77 107
78 108 const injectedLinksRef = useRef([]);
@@ -99,14 +129,35 @@
99 129 });
100 130 injectedLinksRef.current = [];
101 131 };
102 132
133 + const {
134 + palettes,
135 + preferred,
136 + css: paletteCss,
137 + isLoading: isLoadingPalettes,
138 + } = usePalettes();
139 + const onPalettes = Boolean(palettes?.length);
140 + const shownPalettes = useMemo(
141 + () => samplePalettes(palettes, preferred),
142 + [palettes, preferred],
143 + );
144 + const paletteFor = (index) =>
145 + onPalettes ? shownPalettes[index % shownPalettes.length] : undefined;
146 +
103 147 const { undoChange: undoColorAndFontsChange } = useVariationOverride({
104 148 css: !isAdmin && selectedColorAndFonts?.css,
105 149 duotoneTheme:
106 - !isAdmin && selectedColorAndFonts?.settings?.color?.duotone?.theme,
150 + !isAdmin &&
151 + !onPalettes &&
152 + selectedColorAndFonts?.settings?.color?.duotone?.theme,
107 153 });
108 154
155 + const { undoChange: undoPaletteChange } = usePaletteOverride({
156 + css: (!isAdmin && paletteCss?.[selectedPalette?.slug]) || '',
157 + duotoneTheme: (!isAdmin && paletteDuotone(selectedPalette)) || null,
158 + });
159 +
109 160 const { undoChange: undoVibesChange } = useSiteVibesOverride({
110 161 css: !isAdmin && selectedVibe?.css,
111 162 slug: !isAdmin && selectedVibe?.slug,
112 163 });
@@ -114,9 +165,10 @@
114 165 const { data: vibesData, isLoading: isLoadingVibes } =
115 166 useSiteVibesVariations();
116 167
117 168 const vibes = useMemo(() => {
118 - if (isLoadingVibes) return null;
169 + // Null for a theme with no block variations, which .css would throw on.
170 + if (isLoadingVibes || !vibesData?.css) return [];
119 171
120 172 const vibes = Object.entries(vibesData.css)
121 173 .filter(([slug]) => slug !== vibesData.currentVibe)
122 174 .map(([slug, css]) => ({
@@ -121,8 +173,13 @@
121 173 .filter(([slug]) => slug !== vibesData.currentVibe)
122 174 .map(([slug, css]) => ({
123 175 slug,
124 176 css: css?.replaceAll(slug, 'natural-1'),
177 + // Css only adds, so a cloned page keeps the applied vibe's slots.
178 + previewCss: `${vibesData.resets?.[slug] ?? ''}${css ?? ''}`.replaceAll(
179 + slug,
180 + 'natural-1',
181 + ),
125 182 }))
126 183 .sort(() => Math.random() - 0.5);
127 184
128 185 return [...vibes, ...vibes.slice(0, 3)];
@@ -175,25 +232,14 @@
175 232 const storedSiteImages =
176 233 stored?.state?.siteImages ?? launchState?.siteImages?.siteImages ?? [];
177 234 const siteProfile = stored?.state?.siteProfile ?? launchState?.siteProfile;
178 235
179 - const storedDescription =
180 - description ??
181 - stored?.state?.heroDescription ??
182 - launchState?.siteStrings?.heroDescription ??
183 - null;
184 -
185 236 (async () => {
186 - const siteImages =
187 - storedSiteImages.length > 0 || !siteProfile
188 - ? storedSiteImages
189 - : (await handleSiteImages({ siteProfile })).siteImages;
237 + const siteImages = await resolveSiteImages({
238 + storedSiteImages,
239 + siteProfile,
240 + });
190 241
191 - const resolvedDescription =
192 - storedDescription || !siteProfile
193 - ? storedDescription
194 - : (await handleSiteStrings({ siteProfile })).heroDescription;
195 -
196 242 apiFetch({
197 243 path: '/extendify/v1/agent/site-design-variations',
198 244 method: 'POST',
199 245 data: {
@@ -200,9 +246,9 @@
200 246 title,
201 247 images: domImages,
202 248 siteImages,
203 249 postId: context?.postId,
204 - description: resolvedDescription,
250 + description,
205 251 currentHeroPattern: heroPatternName,
206 252 source: 'change-site-design-workflow',
207 253 cta: {
208 254 label: cta?.textContent,
@@ -246,12 +292,21 @@
246 292
247 293 const undoChanges = () => {
248 294 undoHeroSectionChange();
249 295 undoColorAndFontsChange();
296 + undoPaletteChange();
250 297 undoVibesChange();
251 298 removeInjectedLinks();
299 + refreshBlockHighlight();
252 300 };
253 301
302 + const confirmed = useRef(false);
303 + useEffect(() => {
304 + return () => {
305 + if (!confirmed.current) undoChanges();
306 + };
307 + }, []);
308 +
254 309 const handleCancel = () => {
255 310 undoChanges();
256 311 onCancel();
257 312 };
@@ -259,8 +314,9 @@
259 314 const handleConfirm = async () => {
260 315 if (!selectedHeroPattern) return;
261 316
262 317 if (selectedHeroPattern.isCurrent) {
318 + confirmed.current = true;
263 319 onConfirm({
264 320 data: { postId: context?.postId },
265 321 shouldRefreshPage: false,
266 322 });
@@ -295,14 +351,18 @@
295 351 return parse(selectedHeroPattern.code)?.[0] || block;
296 352 }),
297 353 );
298 354
355 + confirmed.current = true;
299 356 onConfirm({
300 357 data: {
301 358 updatedPageBlocks,
302 359 postId,
303 360 vibeSlug: selectedVibe.slug,
304 - colorAndFontsVariation: selectedColorAndFonts,
361 + colorAndFontsVariation: onPalettes
362 + ? fontsOnlyVariation(selectedColorAndFonts)
363 + : selectedColorAndFonts,
364 + colorPalette: selectedPalette?.slug,
305 365 },
306 366 shouldRefreshPage: true,
307 367 });
308 368 } catch (error) {
@@ -311,18 +371,18 @@
311 371 setIsSaving(false);
312 372 }
313 373 };
314 374
315 - if (isLoading || isLoadingVibes) {
375 + if (isLoading || isLoadingVibes || isLoadingPalettes) {
316 376 return (
317 - <div className="flex justify-center flex-col gap-1">
318 - <Spinner />
377 + <div className="min-h-24 p-2 text-center text-sm">
378 + {__('Loading design options...', 'extendify-local')}
319 379 </div>
320 380 );
321 381 }
322 382
323 383 return (
324 - <div className="mb-4 ml-10 mr-2 flex flex-col rounded-lg border border-gray-300 bg-gray-50 rtl:ml-2 rtl:mr-10">
384 + <div className="mb-4 ms-2 me-2 flex flex-col rounded-lg border border-gray-300 bg-gray-50">
325 385 <div className="rounded-lg border-b border-gray-300 bg-white">
326 386 <div className="flex flex-col gap-4 p-3">
327 387 {currentHeroHtml && (
328 388 <DesignOption
@@ -332,8 +392,9 @@
332 392 onClick={() => {
333 393 setSelectedHeroPattern(currentDesignOption);
334 394 setSelectedColorAndFonts(null);
335 395 setSelectedVibe(null);
396 + setSelectedPalette(null);
336 397
337 398 undoChanges();
338 399 }}
339 400 />
@@ -345,11 +406,13 @@
345 406 isSelected={selectedHeroPattern?.id === heroPattern.id}
346 407 styles={{
347 408 linkStyles: heroPattern.linkStyles,
348 409 colorAndFontsVariations: colorAndFontsVariations[i].css,
349 - duotoneTheme:
350 - colorAndFontsVariations[i]?.settings?.color?.duotone?.theme,
351 - vibes: vibes[i]?.css,
410 + paletteCss: paletteCss?.[paletteFor(i)?.slug],
411 + duotoneTheme: onPalettes
412 + ? paletteDuotone(paletteFor(i))
413 + : colorAndFontsVariations[i]?.settings?.color?.duotone?.theme,
414 + vibes: vibes[i]?.previewCss,
352 415 blockSupportsCss: heroPattern.blockSupportsCss,
353 416 }}
354 417 onClick={() => {
355 418 setSelectedHeroPattern(heroPattern);
@@ -354,8 +417,9 @@
354 417 onClick={() => {
355 418 setSelectedHeroPattern(heroPattern);
356 419 setSelectedColorAndFonts(colorAndFontsVariations[i]);
357 420 setSelectedVibe(vibes[i]);
421 + setSelectedPalette(paletteFor(i));
358 422
359 423 if (!isAdmin) {
360 424 const blockSupportsCss = heroPattern.blockSupportsCss;
361 425 if (blockSupportsCss) {
@@ -370,8 +434,9 @@
370 434
371 435 injectLinkStyles(heroPattern.linkStyles);
372 436
373 437 updateHeroSection(heroPattern.renderedHtml);
438 + refreshBlockHighlight();
374 439 }
375 440 }}
376 441 />
377 442 ))}