Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(web): add property update support to story blocks #629

Merged
merged 18 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading