Skip to content

Commit 5ad5a71

Browse files
authored
experimental: Focus mode for style panel (#4827)
#4816 ## Description Still behind a flag, so on dev only, but now style panel is in accordion mode. Switch will come next. Testing: In this mode only one section at a time will be open and Layout is the initial one. ## 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 e8de913 commit 5ad5a71

File tree

5 files changed

+52
-14
lines changed

5 files changed

+52
-14
lines changed

apps/builder/app/builder/features/settings-panel/variables-section.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,7 @@ const VariablesList = () => {
315315

316316
export const VariablesSection = () => {
317317
const containerRef = useRef<HTMLDivElement>(null);
318-
const [isOpen, setIsOpen] = useOpenState({
319-
label: "variables",
320-
isOpenDefault: true,
321-
});
318+
const [isOpen, setIsOpen] = useOpenState({ label: "variables" });
322319
return (
323320
<VariablePopoverProvider value={{ containerRef }}>
324321
<CollapsibleSectionRoot

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

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export const StyleSection = (props: {
4141
// @todo remove to keep sections consistent
4242
fullWidth?: boolean;
4343
children: ReactNode;
44+
accordion?: string;
45+
initialOpen?: string;
4446
}) => {
4547
const { label, children, properties, fullWidth } = props;
4648
const [isOpen, setIsOpen] = useOpenState(props);

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { sections } from "./sections";
1414
import { toValue } from "@webstudio-is/css-engine";
1515
import { $instanceTags, useParentComputedStyleDecl } from "./shared/model";
1616
import { $selectedInstance } from "~/shared/awareness";
17+
import { CollapsibleSectionContext } from "~/builder/shared/collapsible-section";
18+
import { isFeatureEnabled } from "@webstudio-is/feature-flags";
1719

1820
const $selectedInstanceTag = computed(
1921
[$selectedInstance, $instanceTags],
@@ -72,7 +74,16 @@ export const StylePanel = () => {
7274
<StyleSourcesSection />
7375
</Box>
7476
<Separator />
75-
<ScrollArea>{all}</ScrollArea>
77+
<ScrollArea>
78+
<CollapsibleSectionContext.Provider
79+
value={{
80+
accordion: isFeatureEnabled("stylePanelModes"),
81+
initialOpen: "Layout",
82+
}}
83+
>
84+
{all}
85+
</CollapsibleSectionContext.Provider>
86+
</ScrollArea>
7687
</>
7788
);
7889
};

apps/builder/app/builder/shared/collapsible-section.tsx

+36-9
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,57 @@ import {
99
Separator,
1010
theme,
1111
} from "@webstudio-is/design-system";
12-
import type { ComponentProps, ReactNode } from "react";
12+
import {
13+
createContext,
14+
useContext,
15+
type ComponentProps,
16+
type ReactNode,
17+
} from "react";
1318
import { PlusIcon } from "@webstudio-is/icons";
1419
import type { Simplify } from "type-fest";
1520

21+
type Label = string;
22+
1623
type UseOpenStateProps = {
17-
label: string;
18-
isOpenDefault?: boolean;
24+
label: Label;
1925
isOpen?: boolean;
2026
};
2127

22-
const stateContainer = atom<{ [label: string]: boolean }>({});
28+
export const CollapsibleSectionContext = createContext<{
29+
accordion?: boolean;
30+
initialOpen?: Label;
31+
}>({});
32+
33+
const $stateContainer = atom<{
34+
[label: string]: boolean;
35+
}>({});
2336

2437
// Preserves the open/close state even when component gets unmounted
2538
export const useOpenState = ({
2639
label,
27-
isOpenDefault = true,
2840
isOpen: isOpenForced,
2941
}: UseOpenStateProps): [boolean, (value: boolean) => void] => {
30-
const state = useStore(stateContainer);
31-
const isOpen = label in state ? state[label] : isOpenDefault;
42+
const state = useStore($stateContainer);
43+
const { accordion, initialOpen } = useContext(CollapsibleSectionContext);
3244
const setIsOpen = (isOpen: boolean) => {
33-
stateContainer.set({ ...state, [label]: isOpen });
45+
const update = { ...state };
46+
if (isOpen && accordion) {
47+
// In accordion mode we close everything else within that accordion.
48+
for (const key in update) {
49+
update[key] = false;
50+
}
51+
}
52+
update[label] = isOpen;
53+
$stateContainer.set(update);
3454
};
35-
return [isOpenForced === undefined ? isOpen : isOpenForced, setIsOpen];
55+
56+
// Set initial value for accordion mode.
57+
if (accordion && state[label] === undefined) {
58+
state[label] = initialOpen === label;
59+
}
60+
61+
const isOpenCurrent = state[label];
62+
return [isOpenForced ?? isOpenCurrent ?? true, setIsOpen];
3663
};
3764

3865
type CollapsibleSectionBaseProps = {

packages/feature-flags/src/flags.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export const staticExport = false;
99
export const contentEditableMode = false;
1010
export const command = false;
1111
export const headSlotComponent = false;
12+
export const stylePanelModes = false;

0 commit comments

Comments
 (0)