From 38af9e19437e5388578e0b19c90e4f935731f1e0 Mon Sep 17 00:00:00 2001 From: Hsu Zhong Jun <27919917+dcshzj@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:13:44 +0800 Subject: [PATCH 1/2] feat: introduce link custom renderer (#292) * feat: introduce link custom renderer * chore: perform string type check * chore: fix prettier formatting * chore: rename uri to link to differentiate * fix: use radio instead of tabs * chore: add return type and use rem for padding --- apps/studio/src/constants/formBuilder.ts | 1 + .../components/form-builder/FormBuilder.tsx | 3 + .../controls/JsonFormsLinkControl.tsx | 198 ++++++++++++++++++ .../form-builder/renderers/controls/index.ts | 4 + .../src/interfaces/complex/Button.ts | 1 + .../src/interfaces/complex/Infobar.ts | 2 + .../src/interfaces/complex/Infopic.ts | 1 + .../interfaces/internal/ContentPageHeader.ts | 1 + 8 files changed, 211 insertions(+) create mode 100644 apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/JsonFormsLinkControl.tsx diff --git a/apps/studio/src/constants/formBuilder.ts b/apps/studio/src/constants/formBuilder.ts index b38aaa31a..98409e334 100644 --- a/apps/studio/src/constants/formBuilder.ts +++ b/apps/studio/src/constants/formBuilder.ts @@ -10,6 +10,7 @@ export const JSON_FORMS_RANKING = { AnyOfControl: 3, ProseControl: 2, RadioControl: 3, + LinkControl: 3, GroupLayoutRenderer: 1, VerticalLayoutRenderer: 1, } diff --git a/apps/studio/src/features/editing-experience/components/form-builder/FormBuilder.tsx b/apps/studio/src/features/editing-experience/components/form-builder/FormBuilder.tsx index 0f7ba0b87..01a40d8c5 100644 --- a/apps/studio/src/features/editing-experience/components/form-builder/FormBuilder.tsx +++ b/apps/studio/src/features/editing-experience/components/form-builder/FormBuilder.tsx @@ -20,6 +20,8 @@ import { jsonFormsGroupLayoutTester, JsonFormsIntegerControl, jsonFormsIntegerControlTester, + JsonFormsLinkControl, + jsonFormsLinkControlTester, JsonFormsObjectControl, jsonFormsObjectControlTester, JsonFormsProseControl, @@ -41,6 +43,7 @@ const renderers: JsonFormsRendererRegistryEntry[] = [ renderer: JsonFormsDropdownControl, }, { tester: jsonFormsIntegerControlTester, renderer: JsonFormsIntegerControl }, + { tester: jsonFormsLinkControlTester, renderer: JsonFormsLinkControl }, { tester: jsonFormsTextControlTester, renderer: JsonFormsTextControl }, { tester: jsonFormsAllOfControlTester, renderer: JsonFormsAllOfControl }, { tester: jsonFormsAnyOfControlTester, renderer: JsonFormsAnyOfControl }, diff --git a/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/JsonFormsLinkControl.tsx b/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/JsonFormsLinkControl.tsx new file mode 100644 index 000000000..b396d478a --- /dev/null +++ b/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/JsonFormsLinkControl.tsx @@ -0,0 +1,198 @@ +import type { UseRadioProps } from "@chakra-ui/react" +import type { ControlProps, RankedTester } from "@jsonforms/core" +import type { PropsWithChildren } from "react" +import { useState } from "react" +import { + Box, + FormControl, + HStack, + Icon, + Text, + useRadio, + useRadioGroup, +} from "@chakra-ui/react" +import { and, isStringControl, rankWith, schemaMatches } from "@jsonforms/core" +import { withJsonFormsControlProps } from "@jsonforms/react" +import { FormLabel, Input } from "@opengovsg/design-system-react" +import { BiEnvelopeOpen, BiFile, BiFileBlank, BiLink } from "react-icons/bi" + +import { JSON_FORMS_RANKING } from "~/constants/formBuilder" + +const LINK_TYPES = { + page: { + icon: BiFileBlank, + label: "Page", + }, + external: { + icon: BiLink, + label: "External link", + }, + file: { + icon: BiFile, + label: "File", + }, + email: { + icon: BiEnvelopeOpen, + label: "Email", + }, +} as const + +export const jsonFormsLinkControlTester: RankedTester = rankWith( + JSON_FORMS_RANKING.LinkControl, + and( + isStringControl, + schemaMatches((schema) => schema.format === "link"), + ), +) + +const RadioCard = ({ children, ...rest }: PropsWithChildren) => { + const { getInputProps, getRadioProps } = useRadio(rest) + + return ( + div": { + borderLeftRadius: "base", + }, + }} + _last={{ + "> div": { + borderRightRadius: "base", + }, + }} + > + + + {children} + + + ) +} + +interface RadioContentProps { + selectedLinkType: string + data: string + handleChange: (value: string) => void +} + +const RadioContent = ({ + selectedLinkType, + data, + handleChange, +}: RadioContentProps): JSX.Element => { + switch (selectedLinkType) { + case "page": + return ( + handleChange(e.target.value)} + placeholder="Page permalink" + /> + ) + case "external": + return ( + handleChange(e.target.value)} + placeholder="https://www.isomer.gov.sg" + /> + ) + case "file": + return ( + handleChange(e.target.value)} + placeholder="File link" + /> + ) + case "email": + return ( + handleChange(`mailto:${e.target.value}`)} + placeholder="test@example.com" + /> + ) + default: + return <> + } +} + +export function JsonFormsLinkControl({ + data, + label, + handleChange, + path, + description, + required, +}: ControlProps) { + const [selectedLinkType, setSelectedLinkType] = useState("page") + + const handleLinkTypeChange = (value: string) => { + setSelectedLinkType(value) + handleChange(path, "") + } + + const { getRootProps, getRadioProps } = useRadioGroup({ + name: "link-type", + defaultValue: "page", + onChange: handleLinkTypeChange, + }) + + const dataString = data && typeof data === "string" ? data : "" + + return ( + + + {label} + + + {Object.entries(LINK_TYPES).map(([key, { icon, label }]) => { + const radio = getRadioProps({ value: key }) + + return ( + + + + {label} + + + ) + })} + + + + handleChange(path, value)} + /> + + + + ) +} + +export default withJsonFormsControlProps(JsonFormsLinkControl) diff --git a/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/index.ts b/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/index.ts index b01b7fb55..491d18181 100644 --- a/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/index.ts +++ b/apps/studio/src/features/editing-experience/components/form-builder/renderers/controls/index.ts @@ -34,6 +34,10 @@ export { default as JsonFormsRadioControl, jsonFormsRadioControlTester, } from "./JsonFormsRadioControl" +export { + default as JsonFormsLinkControl, + jsonFormsLinkControlTester, +} from "./JsonFormsLinkControl" export { default as JsonFormsTextControl, jsonFormsTextControlTester, diff --git a/packages/components/src/interfaces/complex/Button.ts b/packages/components/src/interfaces/complex/Button.ts index 4228be6b5..80d4fea12 100644 --- a/packages/components/src/interfaces/complex/Button.ts +++ b/packages/components/src/interfaces/complex/Button.ts @@ -18,6 +18,7 @@ export const ButtonSchema = Type.Object( href: Type.String({ title: "Button URL", description: "The URL to navigate to when the button is clicked", + format: "link", }), colorScheme: Type.Optional( Type.Union( diff --git a/packages/components/src/interfaces/complex/Infobar.ts b/packages/components/src/interfaces/complex/Infobar.ts index 95e52c45d..6c2e4a003 100644 --- a/packages/components/src/interfaces/complex/Infobar.ts +++ b/packages/components/src/interfaces/complex/Infobar.ts @@ -23,6 +23,7 @@ export const InfobarSchema = Type.Object( Type.String({ title: "Button destination", description: "When this is clicked, open:", + format: "link", }), ), secondaryButtonLabel: Type.Optional( @@ -36,6 +37,7 @@ export const InfobarSchema = Type.Object( Type.String({ title: "Secondary button destination", description: "When this is clicked, open:", + format: "link", }), ), }, diff --git a/packages/components/src/interfaces/complex/Infopic.ts b/packages/components/src/interfaces/complex/Infopic.ts index 43545391b..85c300c75 100644 --- a/packages/components/src/interfaces/complex/Infopic.ts +++ b/packages/components/src/interfaces/complex/Infopic.ts @@ -34,6 +34,7 @@ export const InfopicSchema = Type.Object( Type.String({ title: "Button destination", description: "When this is clicked, open:", + format: "link", }), ), }, diff --git a/packages/components/src/interfaces/internal/ContentPageHeader.ts b/packages/components/src/interfaces/internal/ContentPageHeader.ts index 3184d7d4e..fd8b08900 100644 --- a/packages/components/src/interfaces/internal/ContentPageHeader.ts +++ b/packages/components/src/interfaces/internal/ContentPageHeader.ts @@ -19,6 +19,7 @@ export const ContentPageHeaderSchema = Type.Object( Type.String({ title: "Button URL", description: "The URL the button should link to", + format: "link", }), ), }, From 8f9e4d3980ebd3a77a6484479f09d026b2dd7964 Mon Sep 17 00:00:00 2001 From: seaerchin <44049504+seaerchin@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:51:58 +0800 Subject: [PATCH 2/2] chore: style fixes for save button (#362) * chore: style fixes for save button * chore: remove TODO * chore; update to sticky idk why it wasn't previously and is now tbh --- .../components/ComplexEditorStateDrawer.tsx | 21 +++++++++++++++---- .../components/RootStateDrawer.tsx | 12 +++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/studio/src/features/editing-experience/components/ComplexEditorStateDrawer.tsx b/apps/studio/src/features/editing-experience/components/ComplexEditorStateDrawer.tsx index 749c5161a..82b00cb4c 100644 --- a/apps/studio/src/features/editing-experience/components/ComplexEditorStateDrawer.tsx +++ b/apps/studio/src/features/editing-experience/components/ComplexEditorStateDrawer.tsx @@ -1,4 +1,4 @@ -import { Box, Heading, HStack, Icon } from "@chakra-ui/react" +import { Box, Flex, Heading, HStack, Icon } from "@chakra-ui/react" import { Button, IconButton } from "@opengovsg/design-system-react" import { getComponentSchema } from "@opengovsg/isomer-components" import { BiDollar, BiX } from "react-icons/bi" @@ -29,7 +29,13 @@ export default function ComplexEditorStateDrawer(): JSX.Element { const { title } = getComponentSchema(component.type) return ( - + - + - + ) } diff --git a/apps/studio/src/features/editing-experience/components/RootStateDrawer.tsx b/apps/studio/src/features/editing-experience/components/RootStateDrawer.tsx index 4c66f189d..81be2ea18 100644 --- a/apps/studio/src/features/editing-experience/components/RootStateDrawer.tsx +++ b/apps/studio/src/features/editing-experience/components/RootStateDrawer.tsx @@ -5,7 +5,6 @@ import { Divider, HStack, Icon, - Spacer, Text, VStack, } from "@chakra-ui/react" @@ -148,13 +147,14 @@ export default function RootStateDrawer() { - - {/* TODO: Add New Block Section */}