Skip to content

Commit 2593087

Browse files
authored
experimental: more advanced style panel feaures (#4890)
Ref #4816 Closes #4874 ## Description - [x] Memorizing recent properties by instance, so that when user switches between instances and comes back they are still in-place - [x] alt+shift+a for advanced mode shorthand ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
1 parent 18409bb commit 2593087

File tree

4 files changed

+58
-16
lines changed

4 files changed

+58
-16
lines changed

apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { $advancedStyles } from "./stores";
5757
import { $settings } from "~/builder/shared/client-settings";
5858
import { AddStyleInput } from "./add-style-input";
5959
import { parseStyleInput } from "./parse-style-input";
60+
import { $selectedInstanceKey } from "~/shared/awareness";
6061

6162
// Only here to keep the same section module interface
6263
export const properties = [];
@@ -354,7 +355,12 @@ const AdvancedProperty = memo(
354355
export const Section = () => {
355356
const [isAdding, setIsAdding] = useState(false);
356357
const advancedStyles = useStore($advancedStyles);
357-
const [recentProperties, setRecentProperties] = useState<StyleProperty[]>([]);
358+
const selectedInstanceKey = useStore($selectedInstanceKey);
359+
// Memorizing recent properties by instance, so that when user switches between instances and comes back
360+
// they are still in-place
361+
const [recentPropertiesMap, setRecentPropertiesMap] = useState<
362+
Map<string, Array<StyleProperty>>
363+
>(new Map());
358364
const addPropertyInputRef = useRef<HTMLInputElement>(null);
359365
const recentValueInputRef = useRef<HTMLInputElement>(null);
360366
const searchInputRef = useRef<HTMLInputElement>(null);
@@ -369,19 +375,33 @@ export const Section = () => {
369375

370376
const currentProperties = searchProperties ?? advancedProperties;
371377

378+
const recentProperties = selectedInstanceKey
379+
? (recentPropertiesMap.get(selectedInstanceKey) ?? [])
380+
: [];
381+
372382
const showRecentProperties =
373383
recentProperties.length > 0 && searchProperties === undefined;
374384

375385
const memorizeMinHeight = () => {
376386
setMinHeight(containerRef.current?.getBoundingClientRect().height ?? 0);
377387
};
378388

389+
const updateRecentProperties = (properties: Array<StyleProperty>) => {
390+
if (selectedInstanceKey === undefined) {
391+
return;
392+
}
393+
const newRecentPropertiesMap = new Map(recentPropertiesMap);
394+
newRecentPropertiesMap.set(
395+
selectedInstanceKey,
396+
Array.from(new Set([...recentProperties, ...properties]))
397+
);
398+
setRecentPropertiesMap(newRecentPropertiesMap);
399+
};
400+
379401
const handleInsertStyles = (cssText: string) => {
380402
const styles = insertStyles(cssText);
381403
const insertedProperties = styles.map(({ property }) => property);
382-
setRecentProperties(
383-
Array.from(new Set([...recentProperties, ...insertedProperties]))
384-
);
404+
updateRecentProperties(insertedProperties);
385405
return styles;
386406
};
387407

@@ -445,7 +465,10 @@ export const Section = () => {
445465
properties={currentProperties}
446466
>
447467
<Flex gap="2" direction="column">
448-
<Box css={{ paddingInline: theme.panel.paddingInline }}>
468+
<Flex
469+
direction="column"
470+
css={{ paddingInline: theme.panel.paddingInline, gap: 2 }}
471+
>
449472
{showRecentProperties &&
450473
recentProperties.map((property, index, properties) => {
451474
const isLast = index === properties.length - 1;
@@ -461,11 +484,11 @@ export const Section = () => {
461484
}
462485
}}
463486
onReset={() => {
464-
setRecentProperties((properties) => {
465-
return properties.filter(
487+
updateRecentProperties(
488+
recentProperties.filter(
466489
(recentProperty) => recentProperty !== property
467-
);
468-
});
490+
)
491+
);
469492
}}
470493
/>
471494
);
@@ -499,10 +522,11 @@ export const Section = () => {
499522
/>
500523
</Box>
501524
)}
502-
</Box>
525+
</Flex>
503526
{showRecentProperties && <Separator />}
504-
<Box
505-
css={{ paddingInline: theme.panel.paddingInline }}
527+
<Flex
528+
direction="column"
529+
css={{ paddingInline: theme.panel.paddingInline, gap: 2 }}
506530
style={{ minHeight }}
507531
ref={containerRef}
508532
>
@@ -513,7 +537,7 @@ export const Section = () => {
513537
.map((property) => (
514538
<AdvancedProperty key={property} property={property} />
515539
))}
516-
</Box>
540+
</Flex>
517541
</Flex>
518542
</CopyPasteMenu>
519543
</AdvancedStyleSection>

apps/builder/app/builder/features/style-panel/sections/advanced/stores.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ export const $advancedStyles = computed(
6262
const { property, value, listed } = style;
6363
// When property is listed, it was added from advanced panel.
6464
// If we are in advanced mode, we show them all.
65-
if (listed || settings.stylePanelMode === "advanced") {
65+
if (
66+
visualProperties.has(property) === false ||
67+
listed ||
68+
settings.stylePanelMode === "advanced"
69+
) {
6670
advancedStyles.set(property, value);
6771
}
6872
}

apps/builder/app/builder/features/style-panel/style-panel.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const ModeMenu = () => {
6060
</DropdownMenuTrigger>
6161
<DropdownMenuContent
6262
sideOffset={Number.parseFloat(rawTheme.spacing[5])}
63-
css={{ width: theme.spacing[25] }}
63+
css={{ width: theme.spacing[26] }}
6464
>
6565
<DropdownMenuRadioGroup
6666
value={value}
@@ -91,7 +91,10 @@ export const ModeMenu = () => {
9191
icon={<MenuCheckedIcon />}
9292
onFocus={() => setFocusedValue("advanced")}
9393
>
94-
Advanced mode
94+
<Flex justify="between" grow>
95+
<Text variant="labelsTitleCase">Advanced mode</Text>
96+
<Kbd value={["alt", "shift", "a"]} />
97+
</Flex>
9598
</DropdownMenuRadioItem>
9699
)}
97100
</DropdownMenuRadioGroup>

apps/builder/app/builder/shared/commands.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,17 @@ export const { emitCommand, subscribeCommands } = createCommandsEmitter({
362362
},
363363
disableOnInputLikeControls: true,
364364
},
365+
{
366+
name: "toggleStylePanelAdvancedMode",
367+
defaultHotkeys: ["alt+shift+a"],
368+
handler: () => {
369+
setSetting(
370+
"stylePanelMode",
371+
getSetting("stylePanelMode") === "advanced" ? "default" : "advanced"
372+
);
373+
},
374+
disableOnInputLikeControls: true,
375+
},
365376
{
366377
name: "openSettingsPanel",
367378
defaultHotkeys: ["d"],

0 commit comments

Comments
 (0)