Skip to content

Commit b82fcd4

Browse files
authored
feat: Allow page clone in Content Edit mode (#4531)
## Description ref #3994 + disable edit project settings ## 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 1f09b0e commit b82fcd4

File tree

3 files changed

+86
-69
lines changed

3 files changed

+86
-69
lines changed

apps/builder/app/builder/features/pages/page-settings.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,17 +1679,16 @@ const PageSettingsView = ({
16791679
/>
16801680
</Tooltip>
16811681
)}
1682-
{isDesignMode && (
1683-
<Tooltip content="Duplicate page" side="bottom">
1684-
<Button
1685-
color="ghost"
1686-
prefix={<CopyIcon />}
1687-
onClick={onDuplicate}
1688-
aria-label="Duplicate page"
1689-
tabIndex={2}
1690-
/>
1691-
</Tooltip>
1692-
)}
1682+
1683+
<Tooltip content="Duplicate page" side="bottom">
1684+
<Button
1685+
color="ghost"
1686+
prefix={<CopyIcon />}
1687+
onClick={onDuplicate}
1688+
aria-label="Duplicate page"
1689+
tabIndex={2}
1690+
/>
1691+
</Tooltip>
16931692

16941693
<Tooltip content="Close page settings" side="bottom">
16951694
<Button

apps/builder/app/builder/features/project-settings/project-settings.tsx

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { SectionPublish } from "./section-publish";
1818
import { SectionMarketplace } from "./section-marketplace";
1919
import { leftPanelWidth, rightPanelWidth } from "./utils";
2020
import type { FunctionComponent } from "react";
21+
import { $isDesignMode } from "~/shared/nano-states";
2122

2223
type SectionName = "general" | "redirects" | "publish" | "marketplace";
2324

@@ -37,6 +38,8 @@ export const ProjectSettingsView = ({
3738
onSectionChange?: (section: SectionName) => void;
3839
onOpenChange?: (isOpen: boolean) => void;
3940
}) => {
41+
const isDesignMode = useStore($isDesignMode);
42+
4043
return (
4144
<Dialog open={sections.has(currentSection!)} onOpenChange={onOpenChange}>
4245
<DialogContent
@@ -46,66 +49,68 @@ export const ProjectSettingsView = ({
4649
height: theme.spacing[35],
4750
}}
4851
>
49-
<Flex grow>
50-
<List asChild>
51-
<Flex
52-
direction="column"
53-
shrink={false}
54-
css={{
55-
width: leftPanelWidth,
56-
borderRight: `1px solid ${theme.colors.borderMain}`,
57-
}}
58-
>
59-
{Array.from(sections.keys()).map((name, index) => {
60-
return (
61-
<ListItem
62-
current={currentSection === name}
63-
asChild
64-
index={index}
65-
key={name}
66-
onSelect={() => {
67-
onSectionChange?.(name);
68-
}}
69-
>
70-
<Flex
71-
css={{
72-
position: "relative",
73-
height: theme.spacing[13],
74-
paddingInline: theme.panel.paddingInline,
75-
outline: "none",
76-
"&:focus-visible, &:hover": {
77-
background: theme.colors.backgroundHover,
78-
},
79-
"&[aria-current=true]": {
80-
background: theme.colors.backgroundItemCurrent,
81-
color: theme.colors.foregroundMain,
82-
},
52+
<fieldset style={{ display: "contents" }} disabled={!isDesignMode}>
53+
<Flex grow>
54+
<List asChild>
55+
<Flex
56+
direction="column"
57+
shrink={false}
58+
css={{
59+
width: leftPanelWidth,
60+
borderRight: `1px solid ${theme.colors.borderMain}`,
61+
}}
62+
>
63+
{Array.from(sections.keys()).map((name, index) => {
64+
return (
65+
<ListItem
66+
current={currentSection === name}
67+
asChild
68+
index={index}
69+
key={name}
70+
onSelect={() => {
71+
onSectionChange?.(name);
8372
}}
84-
align="center"
8573
>
86-
<Text variant="labelsTitleCase" truncate>
87-
{name}
88-
</Text>
89-
</Flex>
90-
</ListItem>
91-
);
92-
})}
93-
</Flex>
94-
</List>
95-
<ScrollArea>
96-
<Grid gap={2} css={{ py: theme.spacing[5] }}>
97-
{currentSection === "general" && <SectionGeneral />}
98-
{currentSection === "redirects" && <SectionRedirects />}
99-
{currentSection === "publish" && <SectionPublish />}
100-
{currentSection === "marketplace" && <SectionMarketplace />}
101-
<div />
102-
</Grid>
103-
</ScrollArea>
104-
</Flex>
105-
{/* Title is at the end intentionally,
106-
* to make the close button last in the tab order
107-
*/}
108-
<DialogTitle>Project Settings</DialogTitle>
74+
<Flex
75+
css={{
76+
position: "relative",
77+
height: theme.spacing[13],
78+
paddingInline: theme.panel.paddingInline,
79+
outline: "none",
80+
"&:focus-visible, &:hover": {
81+
background: theme.colors.backgroundHover,
82+
},
83+
"&[aria-current=true]": {
84+
background: theme.colors.backgroundItemCurrent,
85+
color: theme.colors.foregroundMain,
86+
},
87+
}}
88+
align="center"
89+
>
90+
<Text variant="labelsTitleCase" truncate>
91+
{name}
92+
</Text>
93+
</Flex>
94+
</ListItem>
95+
);
96+
})}
97+
</Flex>
98+
</List>
99+
<ScrollArea>
100+
<Grid gap={2} css={{ py: theme.spacing[5] }}>
101+
{currentSection === "general" && <SectionGeneral />}
102+
{currentSection === "redirects" && <SectionRedirects />}
103+
{currentSection === "publish" && <SectionPublish />}
104+
{currentSection === "marketplace" && <SectionMarketplace />}
105+
<div />
106+
</Grid>
107+
</ScrollArea>
108+
</Flex>
109+
{/* Title is at the end intentionally,
110+
* to make the close button last in the tab order
111+
*/}
112+
<DialogTitle>Project Settings</DialogTitle>
113+
</fieldset>
109114
</DialogContent>
110115
</Dialog>
111116
);

apps/builder/app/builder/shared/code-editor-base.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
DialogClose,
4242
Flex,
4343
rawTheme,
44+
globalCss,
4445
} from "@webstudio-is/design-system";
4546
import { CrossIcon, MaximizeIcon, MinimizeIcon } from "@webstudio-is/icons";
4647
import { solarizedLight } from "./code-highlight";
@@ -67,6 +68,12 @@ export const getMinMaxHeightVars = ({
6768
[maxHeightVar]: maxHeight,
6869
});
6970

71+
const globalStyles = globalCss({
72+
"fieldset[disabled] .cm-editor": {
73+
opacity: 0.3,
74+
},
75+
});
76+
7077
const editorContentStyle = css({
7178
...textVariants.mono,
7279
// fit editor into parent if stretched
@@ -188,6 +195,8 @@ export const EditorContent = ({
188195
onChange,
189196
onBlur,
190197
}: EditorContentProps) => {
198+
globalStyles();
199+
191200
const editorRef = useRef<null | HTMLDivElement>(null);
192201
const viewRef = useRef<undefined | EditorView>();
193202

@@ -222,9 +231,13 @@ export const EditorContent = ({
222231
if (view === undefined) {
223232
return;
224233
}
234+
const hasDisabledFieldset =
235+
editorRef.current?.closest("fieldset[disabled]");
236+
225237
view.dispatch({
226238
effects: StateEffect.reconfigure.of([
227239
...extensions,
240+
...(hasDisabledFieldset ? [EditorView.editable.of(false)] : []),
228241
autocompletionTooltipTheme,
229242
history(),
230243
drawSelection(),

0 commit comments

Comments
 (0)