Skip to content

Commit 973d9df

Browse files
authored
feat: new resources dialog (#5383)
Ref #3691 - moved response preview into resource dialog - increased dialog size and centered it - added maximize button to resource dialog - removed inspect option from dropdown - refactored centering dialogs without transform to fix nested popovers positioning https://github.com/user-attachments/assets/901e086b-afcd-42e9-8866-d62d6cb662d2
1 parent f42488a commit 973d9df

File tree

9 files changed

+198
-220
lines changed

9 files changed

+198
-220
lines changed

apps/builder/app/builder/builder.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@ body {
2222
[data-radix-scroll-area-viewport]::-webkit-scrollbar {
2323
display: none;
2424
}
25+
26+
* {
27+
scrollbar-width: thin;
28+
scrollbar-color: var(--colors-foregroundScrollBar) transparent;
29+
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
List,
1212
ListItem,
1313
Text,
14+
rawTheme,
1415
} from "@webstudio-is/design-system";
1516
import {
1617
$openProjectSettings,
@@ -53,11 +54,11 @@ export const ProjectSettingsView = ({
5354
onOpenChange={onOpenChange}
5455
>
5556
<DialogContent
56-
css={{
57-
width: `calc(${leftPanelWidth} + ${rightPanelWidth})`,
58-
maxWidth: "none",
59-
height: theme.spacing[35],
60-
}}
57+
width={
58+
Number.parseInt(leftPanelWidth, 10) +
59+
Number.parseInt(rightPanelWidth, 10)
60+
}
61+
height={Number.parseInt(rawTheme.spacing[35], 10)}
6162
>
6263
<fieldset style={{ display: "contents" }} disabled={!isDesignMode}>
6364
<Flex grow>

apps/builder/app/builder/features/project-settings/utils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { theme, type CSS } from "@webstudio-is/design-system";
1+
import { rawTheme, theme, type CSS } from "@webstudio-is/design-system";
22
import { getPagePath, type Pages } from "@webstudio-is/sdk";
33

4-
export const leftPanelWidth = theme.spacing[26];
5-
export const rightPanelWidth = theme.spacing[35];
4+
export const leftPanelWidth = rawTheme.spacing[26];
5+
export const rightPanelWidth = rawTheme.spacing[35];
66
export const sectionSpacing: CSS = {
77
paddingInline: theme.panel.paddingInline,
88
};

apps/builder/app/builder/features/settings-panel/variable-popover.tsx

Lines changed: 98 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { z } from "zod";
22
import { nanoid } from "nanoid";
3+
import { computed } from "nanostores";
34
import { useStore } from "@nanostores/react";
5+
import { javascript } from "@codemirror/lang-javascript";
46
import {
57
type ReactNode,
68
type Ref,
@@ -13,13 +15,15 @@ import {
1315
createContext,
1416
useEffect,
1517
useCallback,
18+
useMemo,
1619
} from "react";
1720
import { CopyIcon, RefreshIcon, UpgradeIcon } from "@webstudio-is/icons";
1821
import {
1922
Box,
2023
Button,
2124
Combobox,
2225
DialogClose,
26+
DialogMaximize,
2327
DialogTitle,
2428
DialogTitleActions,
2529
Flex,
@@ -58,13 +62,19 @@ import {
5862
$userPlanFeatures,
5963
$instances,
6064
$props,
65+
$variableValuesByInstanceSelector,
6166
} from "~/shared/nano-states";
62-
import { $selectedInstance } from "~/shared/awareness";
67+
import {
68+
$selectedInstance,
69+
$selectedInstanceKeyWithRoot,
70+
} from "~/shared/awareness";
6371
import { BindingPopoverProvider } from "~/builder/shared/binding-popover";
6472
import {
73+
EditorContent,
6574
EditorDialog,
6675
EditorDialogButton,
6776
EditorDialogControl,
77+
foldGutterExtension,
6878
} from "~/builder/shared/code-editor-base";
6979
import { updateWebstudioData } from "~/shared/instance-utils";
7080
import {
@@ -666,8 +676,8 @@ const VariablePanel = forwardRef<
666676
direction="column"
667677
css={{
668678
overflow: "hidden",
679+
padding: theme.panel.padding,
669680
gap: theme.spacing[7],
670-
p: theme.panel.padding,
671681
}}
672682
>
673683
<NameField variable={variable} defaultValue={variable?.name ?? ""} />
@@ -707,6 +717,40 @@ const areAllFormErrorsVisible = (form: null | HTMLFormElement) => {
707717
return true;
708718
};
709719

720+
const $instanceVariableValues = computed(
721+
[$selectedInstanceKeyWithRoot, $variableValuesByInstanceSelector],
722+
(instanceKey, variableValuesByInstanceSelector) =>
723+
variableValuesByInstanceSelector.get(instanceKey ?? "") ??
724+
new Map<string, unknown>()
725+
);
726+
727+
const VariablePreview = ({ variable }: { variable: DataSource }) => {
728+
const variableValues = useStore($instanceVariableValues);
729+
const extensions = useMemo(() => [javascript({}), foldGutterExtension], []);
730+
const editorProps = {
731+
readOnly: true,
732+
extensions,
733+
// compute value as json lazily only when dialog is open
734+
// by spliting into separate component which is invoked
735+
// only when dialog content is rendered
736+
value: JSON.stringify(variableValues.get(variable.id), null, 2),
737+
onChange: () => {},
738+
onChangeComplete: () => {},
739+
};
740+
return (
741+
<Grid
742+
align="stretch"
743+
css={{
744+
height: "100%",
745+
overflow: "hidden",
746+
boxSizing: "content-box",
747+
}}
748+
>
749+
<EditorContent {...editorProps} />
750+
</Grid>
751+
);
752+
};
753+
710754
export const VariablePopoverTrigger = ({
711755
variable,
712756
children,
@@ -724,6 +768,9 @@ export const VariablePopoverTrigger = ({
724768

725769
return (
726770
<FloatingPanel
771+
placement="center"
772+
width={variable ? 740 : 320}
773+
height={480}
727774
open={isOpen}
728775
onOpenChange={(newOpen) => {
729776
if (newOpen) {
@@ -788,6 +835,7 @@ export const VariablePopoverTrigger = ({
788835
</Tooltip>
789836
</>
790837
)}
838+
<DialogMaximize />
791839
<DialogClose />
792840
</DialogTitleActions>
793841
}
@@ -797,57 +845,61 @@ export const VariablePopoverTrigger = ({
797845
)
798846
}
799847
content={
800-
<ScrollArea
848+
<Grid
801849
css={{
802-
// flex fixes content overflowing artificial scroll area
803-
display: "flex",
804-
flexDirection: "column",
805-
width: theme.spacing[30],
850+
height: "100%",
851+
gridTemplateColumns: "320px 1fr",
806852
}}
807853
>
808-
<form
809-
ref={formRef}
810-
noValidate={true}
811-
// exclude from the flow
812-
style={{ display: "contents" }}
813-
onSubmit={(event) => {
814-
event.preventDefault();
815-
if (isSystemVariable) {
816-
return;
817-
}
818-
const nameElement =
819-
event.currentTarget.elements.namedItem("name");
820-
// make sure only name is valid and allow to save everything else
821-
// to avoid loosing complex configuration when closed accidentally
822-
if (
823-
nameElement instanceof HTMLInputElement &&
824-
nameElement.checkValidity()
825-
) {
826-
const formData = new FormData(event.currentTarget);
827-
panelRef.current?.save(formData);
828-
// close popover whenever new variable is created
829-
// to prevent creating duplicated variable
830-
if (variable === undefined) {
831-
setOpen(false);
832-
}
833-
}
834-
}}
854+
<ScrollArea
855+
// flex fixes content overflowing artificial scroll area
856+
css={{ display: "flex", flexDirection: "column" }}
835857
>
836-
{/* submit is not triggered when press enter on input without submit button */}
837-
<button hidden></button>
838-
<fieldset
858+
<form
859+
ref={formRef}
860+
noValidate={true}
861+
// exclude from the flow
839862
style={{ display: "contents" }}
840-
// forbid editing system variable
841-
disabled={isSystemVariable}
863+
onSubmit={(event) => {
864+
event.preventDefault();
865+
if (isSystemVariable) {
866+
return;
867+
}
868+
const nameElement =
869+
event.currentTarget.elements.namedItem("name");
870+
// make sure only name is valid and allow to save everything else
871+
// to avoid loosing complex configuration when closed accidentally
872+
if (
873+
nameElement instanceof HTMLInputElement &&
874+
nameElement.checkValidity()
875+
) {
876+
const formData = new FormData(event.currentTarget);
877+
panelRef.current?.save(formData);
878+
// close popover whenever new variable is created
879+
// to prevent creating duplicated variable
880+
if (variable === undefined) {
881+
setOpen(false);
882+
}
883+
}
884+
}}
842885
>
843-
<BindingPopoverProvider
844-
value={{ containerRef: bindingPopoverContainerRef }}
886+
{/* submit is not triggered when press enter on input without submit button */}
887+
<button hidden></button>
888+
<fieldset
889+
style={{ display: "contents" }}
890+
// forbid editing system variable
891+
disabled={isSystemVariable}
845892
>
846-
<VariablePanel ref={panelRef} variable={variable} />
847-
</BindingPopoverProvider>
848-
</fieldset>
849-
</form>
850-
</ScrollArea>
893+
<BindingPopoverProvider
894+
value={{ containerRef: bindingPopoverContainerRef }}
895+
>
896+
<VariablePanel ref={panelRef} variable={variable} />
897+
</BindingPopoverProvider>
898+
</fieldset>
899+
</form>
900+
</ScrollArea>
901+
{variable && <VariablePreview variable={variable} />}
902+
</Grid>
851903
}
852904
>
853905
{children}

0 commit comments

Comments
 (0)