Skip to content

Commit

Permalink
chore(web): add property update support to story blocks (#629)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaWaite committed Aug 23, 2023
1 parent 958a1ce commit fdd4eeb
Show file tree
Hide file tree
Showing 22 changed files with 443 additions and 153 deletions.
Expand Up @@ -14,8 +14,9 @@ export default () => {
vt: ValueType,
itemId?: string,
) => {
return async (v?: ValueTypes[ValueType]) =>
return async (v?: ValueTypes[ValueType]) => {
await useUpdatePropertyValue(propertyId, schemaGroupId, itemId, fieldId, "en", v, vt);
};
},
[useUpdatePropertyValue],
);
Expand Down
51 changes: 51 additions & 0 deletions web/src/beta/components/fields/PropertyFields/index.tsx
@@ -0,0 +1,51 @@
import TextInput from "@reearth/beta/components/fields/TextInput";
import { type Item } from "@reearth/services/api/propertyApi/utils";

import ColorField from "../ColorField";

import useHooks from "./hooks";

type Props = {
propertyId: string;
item?: Item;
};

const PropertyFields: React.FC<Props> = ({ propertyId, item }) => {
const { handlePropertyValueUpdate } = useHooks();

return (
<>
{item?.schemaFields.map(sf => {
const isList = item && "items" in item;
const value = !isList ? item.fields.find(f => f.id === sf.id)?.value : sf.defaultValue;
return sf.type === "string" ? (
sf.ui === "color" ? (
<ColorField
key={sf.id}
name={sf.name}
value={(value as string) ?? ""}
description={sf.description}
onChange={handlePropertyValueUpdate(item.schemaGroup, propertyId, sf.id, sf.type)}
/>
) : sf.ui === "selection" || sf.choices ? (
<p key={sf.id}>Selection or choices field</p>
) : sf.ui === "buttons" ? (
<p key={sf.id}>Button radio field</p>
) : (
<TextInput
key={sf.id}
name={sf.name}
value={(value as string) ?? ""}
description={sf.description}
onChange={handlePropertyValueUpdate(item.schemaGroup, propertyId, sf.id, sf.type)}
/>
)
) : (
<p key={sf.id}>{sf.name} field</p>
);
})}
</>
);
};

export default PropertyFields;
1 change: 1 addition & 0 deletions web/src/beta/features/Editor/StoryPanel/Block/Template.tsx
Expand Up @@ -17,6 +17,7 @@ export default Template;

const Wrapper = styled.div`
display: flex;
height: 255px;
justify-content: center;
align-items: center;
flex: 1;
Expand Down
@@ -1,41 +1,26 @@
import { useCallback } from "react";
import { useMemo } from "react";

import { ValueTypes } from "@reearth/beta/utils/value";
import { styled } from "@reearth/services/theme";

import { CommonProps as BlockProps } from "../../types";
import BlockWrapper from "../Builtin/Wrapper";
import BlockWrapper from "../common/Wrapper";
import { getFieldValue } from "../utils";

export type Props = BlockProps<Property>;

type Spacing = {
top: number;
bottom: number;
left: number;
right: number;
};

export type Property = {
src?: string;
padding: Spacing;
};

const ImageBlock: React.FC<Props> = ({ block, isSelected, onClick, onRemove }) => {
const {
// src = "https://upload.wikimedia.org/wikipedia/en/a/a5/Pok%C3%A9mon_Charmander_art.png",
src,
padding = { top: 10, bottom: 20, left: 30, right: 10 },
} = block?.property ?? {};

const handleRemove = useCallback(() => onRemove?.(block?.id), [block?.id, onRemove]);
const ImageBlock: React.FC<BlockProps> = ({ block, isSelected, ...props }) => {
const src = useMemo(
() => getFieldValue(block?.property?.items ?? [], "src") as ValueTypes["string"],
[block?.property?.items],
);

return (
<BlockWrapper
title={block?.title}
icon={block?.extensionId}
padding={src ? padding : undefined}
isSelected={isSelected}
onClick={onClick}
onRemove={handleRemove}>
propertyId={block?.property?.id}
propertyItems={block?.property?.items}
{...props}>
{src && <Image src={src} />}
</BlockWrapper>
);
Expand Down
@@ -1,23 +1,34 @@
import { useCallback } from "react";
import { useMemo } from "react";

import { CommonProps as BlockProps } from "../../types";
import BlockWrapper from "../Builtin/Wrapper";
import Text from "@reearth/beta/components/Text";
import { ValueTypes } from "@reearth/beta/utils/value";

export type Props = BlockProps<Property>;
import { CommonProps as BlockProps } from "../../types";
import BlockWrapper from "../common/Wrapper";
import { getFieldValue } from "../utils";

export type Property = {};
export type Props = BlockProps;

const TextBlock: React.FC<Props> = ({ block, isSelected, onClick, onRemove }) => {
const handleRemove = useCallback(() => onRemove?.(block?.id), [block?.id, onRemove]);
const TextBlock: React.FC<Props> = ({ block, isSelected, ...props }) => {
const text = useMemo(
() => getFieldValue(block?.property?.items ?? [], "text") as ValueTypes["string"],
[block?.property?.items],
);

return (
<BlockWrapper
title={block?.title}
icon={block?.extensionId}
isSelected={isSelected}
onClick={onClick}
onRemove={handleRemove}
/>
propertyId={block?.property?.id}
propertyItems={block?.property?.items}
{...props}>
{text && (
<Text size="body" customColor>
{text}
</Text>
)}
</BlockWrapper>
);
};

Expand Down
@@ -1,9 +1,11 @@
import { Dispatch, Fragment, SetStateAction } from "react";

import FieldComponents from "@reearth/beta/components/fields/PropertyFields";
import Icon from "@reearth/beta/components/Icon";
import * as Popover from "@reearth/beta/components/Popover";
import PopoverMenuContent from "@reearth/beta/components/PopoverMenuContent";
import Text from "@reearth/beta/components/Text";
import { Item } from "@reearth/services/api/propertyApi/utils";
import { useT } from "@reearth/services/i18n";
import { styled } from "@reearth/services/theme";

Expand All @@ -16,6 +18,8 @@ type Props = {
showSettings?: boolean;
showPadding?: boolean;
editMode: boolean;
propertyId?: string;
panelSettings?: Item;
setShowPadding: Dispatch<SetStateAction<boolean>>;
onEditModeToggle: () => void;
onSettingsToggle: () => void;
Expand All @@ -29,6 +33,8 @@ const ActionPanel: React.FC<Props> = ({
showSettings,
showPadding,
editMode,
propertyId,
panelSettings,
setShowPadding,
onEditModeToggle,
onSettingsToggle,
Expand Down Expand Up @@ -75,11 +81,15 @@ const ActionPanel: React.FC<Props> = ({
<SettingsDropdown>
<SettingsHeading>
<Text size="footnote" customColor>
Padding settings
{panelSettings?.title}
</Text>
<CancelIcon icon="cancel" size={14} onClick={() => setShowPadding(false)} />
</SettingsHeading>
<SettingsContent>Padding</SettingsContent>
{propertyId && panelSettings && (
<SettingsContent>
<FieldComponents propertyId={propertyId} item={panelSettings} />
</SettingsContent>
)}
</SettingsDropdown>
) : (
<PopoverMenuContent
Expand Down Expand Up @@ -161,6 +171,8 @@ const SettingsHeading = styled.div`
const SettingsContent = styled.div`
height: 100px;
width: 200px;
padding: 8px;
box-sizing: border-box;
`;

const CancelIcon = styled(Icon)`
Expand Down
@@ -1,10 +1,13 @@
import { ReactNode } from "react";

import FieldComponents from "@reearth/beta/components/fields/PropertyFields";
import { type Item } from "@reearth/services/api/propertyApi/utils";
import { styled } from "@reearth/services/theme";

import Template from "../../Template";

import ActionPanel from "./ActionPanel";
import ClickAwayListener from "./click-away";
import useHooks from "./hooks";

type Spacing = {
Expand All @@ -17,27 +20,34 @@ type Spacing = {
type Props = {
title?: string;
icon?: string;
padding?: Spacing;
isSelected?: boolean;
children?: ReactNode;
onClick: (() => void) | undefined;
propertyId?: string;
propertyItems?: Item[];
onClick?: () => void;
onClickAway?: () => void;
onRemove?: () => void;
};

const BlockWrapper: React.FC<Props> = ({
title,
icon,
padding,
isSelected,
children,
propertyId,
propertyItems,
onClick,
onClickAway,
onRemove,
}) => {
const {
isHovered,
editMode,
showSettings,
showPadding,
defaultSettings,
panelSettings,
padding,
setShowPadding,
handleMouseEnter,
handleMouseLeave,
Expand All @@ -46,37 +56,42 @@ const BlockWrapper: React.FC<Props> = ({
handleSettingsToggle,
} = useHooks({
isSelected,
propertyItems,
onClick,
});

return (
<Wrapper
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
isSelected={isSelected}>
{(isHovered || isSelected) && (
<ActionPanel
title={title}
icon={icon}
isSelected={isSelected}
showSettings={showSettings}
showPadding={showPadding}
editMode={editMode}
setShowPadding={setShowPadding}
onEditModeToggle={handleEditModeToggle}
onSettingsToggle={handleSettingsToggle}
onRemove={onRemove}
/>
)}
<Block padding={padding} onClick={handleBlockClick}>
{children ?? <Template icon={icon} />}
</Block>
{editMode && (
<EditorPanel>
<p>Block editing</p>
</EditorPanel>
)}
</Wrapper>
<ClickAwayListener enabled={isSelected} onClickAway={onClickAway}>
<Wrapper
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
isSelected={isSelected}>
{(isHovered || isSelected) && (
<ActionPanel
title={title}
icon={icon}
isSelected={isSelected}
showSettings={showSettings}
showPadding={showPadding}
editMode={editMode}
propertyId={propertyId}
panelSettings={panelSettings}
setShowPadding={setShowPadding}
onEditModeToggle={handleEditModeToggle}
onSettingsToggle={handleSettingsToggle}
onRemove={onRemove}
/>
)}
<Block padding={padding} onClick={handleBlockClick}>
{children ?? <Template icon={icon} />}
</Block>
{editMode && propertyId && defaultSettings && (
<EditorPanel>
<FieldComponents propertyId={propertyId} item={defaultSettings} />
</EditorPanel>
)}
</Wrapper>
</ClickAwayListener>
);
};

Expand All @@ -97,12 +112,12 @@ const Wrapper = styled.div<{ isSelected?: boolean }>`

const Block = styled.div<{ padding?: Spacing }>`
display: flex;
min-height: 255px;
padding-top: ${({ padding }) => padding?.top + "px" ?? 0};
padding-bottom: ${({ padding }) => padding?.bottom + "px" ?? 0};
padding-left: ${({ padding }) => padding?.left + "px" ?? 0};
padding-right: ${({ padding }) => padding?.right + "px" ?? 0};
cursor: pointer;
color: black;
`;

const EditorPanel = styled.div`
Expand Down

0 comments on commit fdd4eeb

Please sign in to comment.