Skip to content

Commit

Permalink
refactor(web): link block (#1096)
Browse files Browse the repository at this point in the history
Co-authored-by: airslice <[email protected]>
  • Loading branch information
mkumbobeaty and airslice authored Aug 9, 2024
1 parent ab9db9a commit b46698f
Show file tree
Hide file tree
Showing 13 changed files with 781 additions and 358 deletions.
5 changes: 5 additions & 0 deletions web/src/beta/components/Icon/Icons/linkStoryBlockButton.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions web/src/beta/components/Icon/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ import ShowLayersStoryBlock from "./Icons/showLayersStoryBlock.svg?react";
import TimelineStoryBlock from "./Icons/timelineStoryBlock.svg?react";
import TimelineStoryBlockSolid from "./Icons/timelineStoryBlockSolid.svg?react";
import NextPageStoryBlock from "./Icons/nextPageStoryBlock.svg?react";
//TODO: will be not be use in future
import LinkButtonStoryBlock from "./Icons/linkStoryBlockButton.svg?react";

// Widget tab
import Desktop from "./Icons/desktop.svg?react";
Expand Down Expand Up @@ -204,6 +206,7 @@ export default {
timelineStoryBlock: TimelineStoryBlock,
timelineStoryBlockSolid: TimelineStoryBlockSolid,
nextPageStoryBlock: NextPageStoryBlock,
linkButtonStoryBlock: LinkButtonStoryBlock,
widget: Widgets,
widgets: Widgets,
menu: WidgetMenu,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,15 @@ const ButtonWrapper = styled("div")(({ theme }) => ({
maxWidth: "400px",
}));

const StyledButton = styled(Button)<{ color?: string; bgColor?: string }>(({ color, bgColor }) => ({
color: color || color,
background: bgColor || bgColor,
borderColor: color || color,
["&:hover"]: {
color: bgColor || bgColor,
background: color ? color : "inherit",
},
}));
const StyledButton = styled(Button)<{ color?: string; bgColor?: string; userSelected?: boolean }>(
({ color, bgColor, userSelected, theme }) => ({
color: userSelected ? bgColor ?? theme.content.strong : color,
backgroundColor: userSelected ? color ?? theme.primary.main : bgColor,
borderColor: color,

":hover": {
color: bgColor,
backgroundColor: color ?? theme.primary.main,
},
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { FC, useCallback, useContext, useState } from "react";

import Button from "@reearth/beta/components/Button";
import { BlockContext } from "@reearth/beta/features/Visualizer/shared/components/BlockWrapper";
import { useT } from "@reearth/services/i18n";
import { styled } from "@reearth/services/theme";

import LinkEditor, { type LinkBlock as LinkBlockType } from "./Editor";

type Props = {
propertyId?: string;
linkButtons: LinkBlockType[];
isEditable?: boolean;
onPropertyUpdate?: (
propertyId?: string,
schemaItemId?: string,
fieldId?: string,
itemId?: string,
vt?: any,
v?: any,
) => Promise<void>;
onPropertyItemAdd?: (propertyId?: string, schemaGroupId?: string) => Promise<void>;
onPropertyItemMove?: (
propertyId?: string,
schemaGroupId?: string,
itemId?: string,
index?: number,
) => Promise<void>;
onPropertyItemDelete?: (
propertyId?: string,
schemaGroupId?: string,
itemId?: string,
) => Promise<void>;
};

const Content: FC<Props> = ({
propertyId,
linkButtons,
isEditable,
onPropertyUpdate,
onPropertyItemAdd,
onPropertyItemDelete,
onPropertyItemMove,
}) => {
const t = useT();
const blockContext = useContext(BlockContext);
const [selected, setSelected] = useState<string>(linkButtons[0]?.id);

const handleClick = useCallback(
(itemId: string) => {
if (isEditable) {
setSelected(itemId);
return;
}
const item = linkButtons.find(i => i.id === itemId);

if (!item?.url?.value) return;
window.open(item.url.value, "_blank");
},
[isEditable, linkButtons],
);

return (
<Wrapper>
<ButtonWrapper>
{linkButtons.map(({ title, color, bgColor, id }) => {
return (
//The button will be updated in future
<StyledButton
key={id}
color={color?.value}
bgColor={bgColor?.value}
icon="linkButtonStoryBlock"
buttonType="primary"
text={title?.value ?? t("New Link Button")}
size="small"
onClick={() => handleClick(id)}
/>
);
})}
</ButtonWrapper>
{blockContext?.editMode && (
<LinkEditor
items={linkButtons}
propertyId={propertyId}
selected={selected}
setSelected={setSelected}
onPropertyUpdate={onPropertyUpdate}
onPropertyItemAdd={onPropertyItemAdd}
onPropertyItemMove={onPropertyItemMove}
onPropertyItemDelete={onPropertyItemDelete}
/>
)}
</Wrapper>
);
};

export default Content;

const Wrapper = styled("div")(() => ({
width: "100%",
}));

const ButtonWrapper = styled("div")(({ theme }) => ({
width: "100%",
display: "flex",
flexWrap: "wrap",
gap: theme.spacing.smallest,
maxWidth: "400px",
}));

const StyledButton = styled(Button)<{ color?: string; bgColor?: string; userSelected?: boolean }>(
({ color, bgColor, userSelected, theme }) => ({
color: userSelected ? bgColor ?? theme.content.strong : color,
backgroundColor: userSelected ? color ?? theme.primary.main : bgColor,
borderColor: color,

":hover": {
color: bgColor,
backgroundColor: color ?? theme.primary.main,
},
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { debounce } from "lodash-es";
import { useCallback, useMemo } from "react";

import { ValueTypes } from "@reearth/beta/utils/value";
import { useT } from "@reearth/services/i18n";

import type { Field } from "../../../../types";

export type LinkBlock = {
id: string;
title?: Field<string>;
color?: Field<string>;
bgColor?: Field<string>;
url?: Field<URL>;
};

export default ({
items,
propertyId,
selected,
onPropertyUpdate,
onPropertyItemAdd,
onPropertyItemDelete,
onPropertyItemMove,
}: {
items: LinkBlock[];
propertyId?: string;
selected?: string;
onPropertyUpdate?: (
propertyId?: string,
schemaItemId?: string,
fieldId?: string,
itemId?: string,
vt?: any,
v?: any,
) => Promise<void>;
onPropertyItemAdd?: (propertyId?: string, schemaGroupId?: string) => Promise<void>;
onPropertyItemMove?: (
propertyId?: string,
schemaGroupId?: string,
itemId?: string,
index?: number,
) => Promise<void>;
onPropertyItemDelete?: (
propertyId?: string,
schemaGroupId?: string,
itemId?: string,
) => Promise<void>;
}) => {
const t = useT();

const editorProperties = useMemo(() => items.find(i => i.id === selected), [items, selected]);

const handlePropertyValueUpdate = useCallback(
(schemaGroupId: string, propertyId: string, fieldId: string, vt: any, itemId?: string) => {
return async (v?: any) => {
await onPropertyUpdate?.(propertyId, schemaGroupId, fieldId, itemId, vt, v);
};
},
[onPropertyUpdate],
);

const handleUpdate = useCallback(
(
itemId: string,
fieldId: string,
fieldType: keyof ValueTypes,
updatedValue?: ValueTypes[keyof ValueTypes],
) => {
if (!propertyId || !itemId) return;

handlePropertyValueUpdate("default", propertyId, fieldId, fieldType, itemId)(updatedValue);
},
[propertyId, handlePropertyValueUpdate],
);

const debounceOnUpdate = useMemo(() => debounce(handleUpdate, 500), [handleUpdate]);

const listItems = useMemo(
() => items.map(({ id, title }) => ({ id, title: title?.value ?? t("New Link Button") })),
[items, t],
);

const handleItemAdd = useCallback(() => {
if (!propertyId) return;
onPropertyItemAdd?.(propertyId, "default");
}, [propertyId, onPropertyItemAdd]);

const handleItemRemove = useCallback(
(itemId: string) => {
if (!propertyId || !itemId) return;

onPropertyItemDelete?.(propertyId, "default", itemId);
},
[propertyId, onPropertyItemDelete],
);

const handleItemMove = useCallback(
(id: string, index: number) => {
if (!propertyId || !id) return;

onPropertyItemMove?.(propertyId, "default", id, index);
},
[propertyId, onPropertyItemMove],
);

return {
editorProperties,
debounceOnUpdate,
listItems,
handleUpdate,
handleItemAdd,
handleItemRemove,
handleItemMove,
};
};
Loading

0 comments on commit b46698f

Please sign in to comment.