Skip to content

Commit

Permalink
chore(web): improve Story Panel UX (#856)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaWaite committed Dec 13, 2023
1 parent 8df7d07 commit d8d9f34
Show file tree
Hide file tree
Showing 17 changed files with 336 additions and 140 deletions.
18 changes: 9 additions & 9 deletions web/src/beta/lib/core/StoryPanel/ActionPanel/index.tsx
Expand Up @@ -15,7 +15,7 @@ export type ActionItem = {
icon: string;
name?: string;
hide?: boolean;
onClick?: (e: MouseEvent<HTMLDivElement>) => void;
onClick?: (e?: MouseEvent<HTMLDivElement>) => void;
};

export type ActionPosition = "left-top" | "left-bottom" | "right-top" | "right-bottom";
Expand All @@ -29,10 +29,10 @@ type Props = {
actionItems: ActionItem[];
dndEnabled?: boolean;
position?: ActionPosition;
isHovered?: boolean;
overrideGroupId?: string;
setShowPadding: Dispatch<SetStateAction<boolean>>;
onSettingsToggle?: () => void;
onClick?: (e: any) => void;
onRemove?: () => void;
onPropertyUpdate?: (
propertyId?: string,
Expand Down Expand Up @@ -69,6 +69,7 @@ const ActionPanel: React.FC<Props> = ({
overrideGroupId,
setShowPadding,
onSettingsToggle,
onClick,
onRemove,
onPropertyUpdate,
onPropertyItemAdd,
Expand Down Expand Up @@ -102,6 +103,7 @@ const ActionPanel: React.FC<Props> = ({
}
return menuItems;
}, [settingsTitle, panelSettings, t, setShowPadding, onRemove, handleRemove]);

return (
<Wrapper isSelected={isSelected} position={position} onClick={stopClickPropagation}>
{dndEnabled && (
Expand All @@ -113,15 +115,13 @@ const ActionPanel: React.FC<Props> = ({
open={showSettings && isSelected}
onOpenChange={() => onSettingsToggle?.()}
placement="bottom-start">
<BlockOptions isSelected={isSelected}>
<BlockOptions isSelected={isSelected} onClick={!isSelected ? onClick : undefined}>
{actionItems.map(
(a, idx) =>
!a.hide && (
<Fragment key={idx}>
<Popover.Trigger asChild>
<OptionWrapper
showPointer={!isSelected || !!a.onClick}
onClick={a.onClick ?? stopClickPropagation}>
<OptionWrapper showPointer={!isSelected || !!a.onClick} onClick={a.onClick}>
<OptionIcon icon={a.icon} size={16} border={idx !== 0} />
{a.name && (
<OptionText size="footnote" customColor>
Expand Down Expand Up @@ -192,14 +192,14 @@ const Wrapper = styled.div<{ isSelected?: boolean; position?: ActionPosition }>`
`
: position === "left-bottom"
? `
left: -1px;
left: 0;
top: 0;
`
: position === "right-bottom"
? `
top: 0;
right: -1px;
`
right: 0;
`
: `
right: -1px;
top: -25px;
Expand Down
Expand Up @@ -8,8 +8,8 @@ type Props = {
isSelected?: boolean;
editMode?: boolean;
panelSettings?: any;
onEditModeToggle?: (e: MouseEvent<HTMLDivElement>) => void;
onSettingsToggle?: (e: MouseEvent<HTMLDivElement>) => void;
onEditModeToggle?: (enable: boolean) => void;
onSettingsToggle?: (e?: MouseEvent<HTMLDivElement>) => void;
};

export default ({
Expand All @@ -33,7 +33,7 @@ export default ({
menuItems.push({
icon: editMode ? "exit" : "storyBlockEdit",
hide: !isSelected,
onClick: onEditModeToggle,
onClick: () => onEditModeToggle?.(!editMode),
});
}

Expand Down
@@ -1,4 +1,4 @@
import { Dispatch, SetStateAction } from "react";
import { Dispatch, MouseEvent, SetStateAction } from "react";

import ActionPanel, { type ActionPosition } from "../../../../ActionPanel";

Expand All @@ -19,8 +19,9 @@ type Props = {
position?: ActionPosition;
overrideGroupId?: string;
setShowPadding: Dispatch<SetStateAction<boolean>>;
onEditModeToggle?: () => void;
onEditModeToggle?: (enable: boolean) => void;
onSettingsToggle?: () => void;
onClick?: (e: MouseEvent<Element>) => void;
onRemove?: () => void;
onPropertyUpdate?: (
propertyId?: string,
Expand Down
31 changes: 23 additions & 8 deletions web/src/beta/lib/core/StoryPanel/Block/builtin/common/Wrapper.tsx
Expand Up @@ -29,6 +29,7 @@ type Props = {
dndEnabled?: boolean;
settingsEnabled?: boolean;
onClick?: () => void;
onClickAway?: () => void;
onRemove?: () => void;
onBlockDoubleClick?: () => void;
onPropertyUpdate?: (
Expand Down Expand Up @@ -65,6 +66,7 @@ const BlockWrapper: React.FC<Props> = ({
settingsEnabled = true,
onClick,
onBlockDoubleClick,
onClickAway,
onRemove,
onPropertyUpdate,
onPropertyItemAdd,
Expand All @@ -78,7 +80,7 @@ const BlockWrapper: React.FC<Props> = ({
showSettings,
defaultSettings,
panelSettings,
setEditMode,
disableSelection,
handleEditModeToggle,
handleSettingsToggle,
handleBlockClick,
Expand All @@ -97,15 +99,21 @@ const BlockWrapper: React.FC<Props> = ({
<SelectableArea
title={title}
icon={icon}
position="right-bottom"
isSelected={isSelected}
propertyId={propertyId}
dndEnabled={dndEnabled}
showSettings={showSettings}
panelSettings={panelSettings}
editMode={editMode}
isEditable={isEditable}
hideHoverUI={disableSelection}
overrideGroupId={groupId === "title" ? groupId : undefined}
setEditMode={setEditMode}
onClick={e => {
handleBlockClick(e);
}}
onDoubleClick={handleDoubleClick}
onClickAway={onClickAway}
onEditModeToggle={handleEditModeToggle}
onSettingsToggle={handleSettingsToggle}
onRemove={onRemove}
Expand All @@ -116,11 +124,9 @@ const BlockWrapper: React.FC<Props> = ({
<Block
padding={panelSettings?.padding?.value}
isEditable={isEditable}
onClick={e => {
handleBlockClick(e);
}}
onDoubleClick={handleDoubleClick}>
disableSelection={disableSelection}>
{children ?? (isEditable && <Template icon={icon} />)}
{!editMode && isEditable && <Overlay disableSelection={disableSelection} />}
</Block>
{editMode && groupId && propertyId && settingsEnabled && (
<EditorPanel onClick={stopClickPropagation}>
Expand Down Expand Up @@ -149,18 +155,27 @@ const BlockWrapper: React.FC<Props> = ({

export default BlockWrapper;

const Block = styled.div<{ padding?: Spacing; isEditable?: boolean }>`
const Block = styled.div<{ padding?: Spacing; isEditable?: boolean; disableSelection?: boolean }>`
display: flex;
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: ${({ isEditable }) => (isEditable ? "pointer" : "default")};
cursor: ${({ isEditable, disableSelection }) =>
isEditable && !disableSelection ? "pointer" : "default"};
color: black;
position: relative;
`;

const EditorPanel = styled.div`
background: ${({ theme }) => theme.bg[1]};
color: ${({ theme }) => theme.content.main};
padding: 12px;
`;

const Overlay = styled.div<{ disableSelection?: boolean }>`
position: absolute;
height: 100%;
width: 100%;
${({ disableSelection }) => !disableSelection && "cursor: pointer;"}
`;
33 changes: 25 additions & 8 deletions web/src/beta/lib/core/StoryPanel/Block/builtin/common/hooks.ts
Expand Up @@ -3,6 +3,7 @@ import { useCallback, useMemo, useState, MouseEvent } from "react";
import { Spacing } from "@reearth/beta/lib/core/mantle";
import useDoubleClick from "@reearth/beta/utils/use-double-click";

import { usePanelContext } from "../../../context";
import { calculatePaddingValue } from "../../../utils";

export const DEFAULT_BLOCK_PADDING: Spacing = { top: 0, bottom: 0, left: 0, right: 0 };
Expand All @@ -22,21 +23,41 @@ export default ({
onClick: (() => void) | undefined;
onBlockDoubleClick: (() => void) | undefined;
}) => {
const storyPanelContext = usePanelContext();
const [editMode, setEditMode] = useState(false);
const [showSettings, setShowSettings] = useState(false);

const disableSelection = useMemo(
() => storyPanelContext?.disableSelection,
[storyPanelContext?.disableSelection],
);

const handleEditModeToggle = useCallback(
(enable: boolean) => {
storyPanelContext?.onSelectionDisable?.(enable);
setEditMode?.(enable);
},
[storyPanelContext],
);

const handleSettingsToggle = useCallback(() => setShowSettings?.(s => !s), []);

const title = useMemo(() => name ?? property?.title, [name, property?.title]);

const handleBlockDoubleClick = useCallback(() => {
if (isEditable) onBlockDoubleClick?.(), setEditMode(true);
}, [isEditable, onBlockDoubleClick]);
if (isEditable && !storyPanelContext.disableSelection) {
onBlockDoubleClick?.();
handleEditModeToggle(true);
}
}, [isEditable, storyPanelContext, onBlockDoubleClick, handleEditModeToggle]);

const [handleSingleClick, handleDoubleClick] = useDoubleClick(
() => onClick?.(),
() => handleBlockDoubleClick?.(),
);

const handleBlockClick = useCallback(
(e: MouseEvent<HTMLDivElement>) => {
(e: MouseEvent<Element>) => {
e.stopPropagation();
if ((showSettings && isSelected) || editMode) return;
handleSingleClick();
Expand Down Expand Up @@ -65,18 +86,14 @@ export default ({
};
}, [property?.panel, isEditable]);

const handleEditModeToggle = useCallback(() => setEditMode?.(em => !em), []);

const handleSettingsToggle = useCallback(() => setShowSettings?.(s => !s), []);

return {
title,
groupId,
editMode,
showSettings,
defaultSettings,
panelSettings,
setEditMode,
disableSelection,
handleEditModeToggle,
handleSettingsToggle,
handleBlockClick,
Expand Down

0 comments on commit d8d9f34

Please sign in to comment.