From ca753cd7106d4378e215d1c6bdf64ba6f74d76f4 Mon Sep 17 00:00:00 2001 From: Hiroki Isogai Date: Mon, 24 Jul 2023 10:40:53 +0900 Subject: [PATCH] chore(web): add popover contents to left panel and related modification (#581) --- .../components/ListItem/index.stories.tsx | 3 + web/src/beta/components/ListItem/index.tsx | 35 ++++++--- .../SidePanel/ContentPage/index.stories.tsx | 10 ++- .../story/SidePanel/ContentPage/index.tsx | 56 ++++++++++++-- .../SidePanel/ContentStory/index.stories.tsx | 10 ++- .../story/SidePanel/ContentStory/index.tsx | 76 +++++++++++++++---- .../Editor/tabs/story/SidePanel/index.tsx | 40 ++++++---- web/src/beta/features/Editor/useLeftPanel.tsx | 12 +-- web/src/services/i18n/translations/en.yml | 1 - web/src/services/i18n/translations/ja.yml | 1 - 10 files changed, 190 insertions(+), 54 deletions(-) diff --git a/web/src/beta/components/ListItem/index.stories.tsx b/web/src/beta/components/ListItem/index.stories.tsx index 7b868ff709..7dd20b61e9 100644 --- a/web/src/beta/components/ListItem/index.stories.tsx +++ b/web/src/beta/components/ListItem/index.stories.tsx @@ -10,6 +10,9 @@ type Story = StoryObj; export const Default: Story = { args: { + isSelected: false, + actionContent:
actionContent
, + isOpenAction: true, children: "long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text ", }, diff --git a/web/src/beta/components/ListItem/index.tsx b/web/src/beta/components/ListItem/index.tsx index 3c88c2968b..75eca9fee5 100644 --- a/web/src/beta/components/ListItem/index.tsx +++ b/web/src/beta/components/ListItem/index.tsx @@ -1,6 +1,7 @@ import { FC, ReactNode } from "react"; import Icon from "@reearth/beta/components/Icon"; +import * as Popover from "@reearth/beta/components/Popover"; import Text from "@reearth/beta/components/Text"; import { styled } from "@reearth/services/theme"; @@ -10,18 +11,35 @@ type Props = { isSelected?: boolean; onItemClick: (id: string) => void; onActionClick?: () => void; + actionContent?: ReactNode; + onOpenChange?: (isOpen: boolean) => void; + isOpenAction?: boolean; }; -const ListItem: FC = ({ children, border, isSelected, onItemClick, onActionClick }) => { +const ListItem: FC = ({ + children, + border, + isSelected, + onItemClick, + onActionClick, + actionContent, + onOpenChange, + isOpenAction, +}) => { return ( onItemClick("id")}> {children} - {onActionClick && ( - + {actionContent && ( + + + + + {actionContent} + )} ); @@ -46,13 +64,10 @@ const Inner = styled.button<{ border?: boolean; isSelected?: boolean }>` background: ${({ theme, isSelected }) => (isSelected ? theme.general.select : "inherit")}; transition: all 0.15s; - ${({ isSelected }) => - !isSelected && - ` + ${({ isSelected }) => isSelected && `background-color: #3B3CD0;`} :hover { - background: #232226; + ${({ isSelected }) => !isSelected && `background-color: #232226;`} } - `} `; const StyledText = styled(Text)` diff --git a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.stories.tsx b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.stories.tsx index 4dcbf440a3..4341dd90c9 100644 --- a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.stories.tsx +++ b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.stories.tsx @@ -8,4 +8,12 @@ export default { type Story = StoryObj; -export const Default: Story = {}; +export const Default: Story = { + render: args => { + return ( +
+ +
+ ); + }, +}; diff --git a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.tsx b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.tsx index 6270ab33ba..830872d0d2 100644 --- a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.tsx +++ b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentPage/index.tsx @@ -1,28 +1,68 @@ -import Item from "@reearth/beta/components/ListItem"; +import { useState } from "react"; + +import ListItem from "@reearth/beta/components/ListItem"; +import PopoverMenuContent from "@reearth/beta/components/PopoverMenuContent"; import Action from "@reearth/beta/features/Editor/tabs/story/SidePanel/Action"; import PageItemWrapper from "@reearth/beta/features/Editor/tabs/story/SidePanel/PageItemWrapper"; import { useT } from "@reearth/services/i18n"; import { styled } from "@reearth/services/theme"; type Props = { - onSelectPage: (id: string) => void; + onPageSelect: (id: string) => void; onPageAdd: () => void; + onPageDuplicate: (id: string) => void; + onPageDelete: (id: string) => void; }; -const ContentPage: React.FC = ({ onSelectPage, onPageAdd }) => { +const ContentPage: React.FC = ({ + onPageSelect, + onPageAdd, + onPageDuplicate, + onPageDelete, +}) => { const t = useT(); + const [openedPageId, setOpenedPageId] = useState(undefined); return ( - + setOpenedPageId(undefined) : undefined}> {[...Array(100)].map((_, i) => ( - onSelectPage(i.toString())} - onActionClick={() => console.log("onActionClick")}> + onItemClick={() => onPageSelect(i.toString())} + onActionClick={() => setOpenedPageId(old => (old ? undefined : i.toString()))} + onOpenChange={isOpen => { + setOpenedPageId(isOpen ? i.toString() : undefined); + }} + isSelected={i === 0} + isOpenAction={openedPageId === i.toString()} + actionContent={ + { + setOpenedPageId(undefined); + onPageDuplicate(i.toString()); + }, + }, + { + icon: "trash", + name: "Delete", + onClick: () => { + setOpenedPageId(undefined); + onPageDelete(i.toString()); + }, + }, + ]} + /> + }> Page - + ))} diff --git a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.stories.tsx b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.stories.tsx index 94e8d79792..0e2fdc6dfb 100644 --- a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.stories.tsx +++ b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.stories.tsx @@ -8,4 +8,12 @@ export default { type Story = StoryObj; -export const Default: Story = {}; +export const Default: Story = { + render: args => { + return ( +
+ +
+ ); + }, +}; diff --git a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.tsx b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.tsx index 858a100fed..fdee18dc63 100644 --- a/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.tsx +++ b/web/src/beta/features/Editor/tabs/story/SidePanel/ContentStory/index.tsx @@ -1,26 +1,76 @@ -import Item from "@reearth/beta/components/ListItem"; +import { useState } from "react"; + +import ListItem from "@reearth/beta/components/ListItem"; +import PopoverMenuContent from "@reearth/beta/components/PopoverMenuContent"; import Action from "@reearth/beta/features/Editor/tabs/story/SidePanel/Action"; -import { useT } from "@reearth/services/i18n"; import { styled } from "@reearth/services/theme"; type Props = { - onSelectStory: (id: string) => void; + onStorySelect: (id: string) => void; onStoryAdd: () => void; + onStoryDelete: (id: string) => void; + onStoryClickSettings: (id: string) => void; + onStoryRename: (id: string) => void; }; -const ContentStory: React.FC = ({ onStoryAdd, onSelectStory }) => { - const t = useT(); + +// This component is created for the multiple stories, currently this is hidden +// Need to replace text with i18n when use this +const ContentStory: React.FC = ({ + onStorySelect, + onStoryAdd, + onStoryDelete, + onStoryClickSettings, + onStoryRename, +}) => { + const [openedPageId, setOpenedPageId] = useState(undefined); return ( - + setOpenedPageId(undefined) : undefined}> {[...Array(100)].map((_, i) => ( - onSelectStory(i.toString())} - onActionClick={() => console.log("onActionClick")}> - Story{i} / Story{i} / Story{i} / Story{i} / Story{i} / Story{i} / Story{i} / Story{i} / - Story{i} - + onItemClick={() => onStorySelect(i.toString())} + onActionClick={() => setOpenedPageId(old => (old ? undefined : i.toString()))} + onOpenChange={isOpen => { + setOpenedPageId(isOpen ? i.toString() : undefined); + }} + isSelected={false} + isOpenAction={openedPageId === i.toString()} + actionContent={ + { + setOpenedPageId(undefined); + onStoryRename(i.toString()); + }, + }, + { + icon: "gearSix", + name: "Settings", + onClick: () => { + setOpenedPageId(undefined); + onStoryClickSettings(i.toString()); + }, + }, + { + icon: "trash", + name: "Delete Story", + onClick: () => { + setOpenedPageId(undefined); + onStoryDelete(i.toString()); + }, + }, + ]} + /> + }> + Story + ))} @@ -28,7 +78,7 @@ const ContentStory: React.FC = ({ onStoryAdd, onSelectStory }) => { icon="book" iconColor="#ffffff" iconSize={16} - title={`+ ${t("New Story")}`} + title={`+ New Story`} onClick={onStoryAdd} /> diff --git a/web/src/beta/features/Editor/tabs/story/SidePanel/index.tsx b/web/src/beta/features/Editor/tabs/story/SidePanel/index.tsx index 51a418ed43..7d6c877e43 100644 --- a/web/src/beta/features/Editor/tabs/story/SidePanel/index.tsx +++ b/web/src/beta/features/Editor/tabs/story/SidePanel/index.tsx @@ -1,36 +1,48 @@ import SidePanelCommon from "@reearth/beta/features/Editor/SidePanel"; import ContentPage from "@reearth/beta/features/Editor/tabs/story/SidePanel/ContentPage"; -import ContentStory from "@reearth/beta/features/Editor/tabs/story/SidePanel/ContentStory"; import { useT } from "@reearth/services/i18n"; // TODO: these are currently rough definition type Props = { - stories: any; - selectedStory: any; - onSelectStory: (id: string) => void; - onStoryAdd: () => void; + // story + // stories: any; + // selectedStory: any; + // onStorySelect: (id: string) => void; + // onStoryAdd: () => void; + + // page selectedPageId?: string; - onSelectPage: (id: string) => void; + onPageSelect: (id: string) => void; + onPageDuplicate: (id: string) => void; + onPageDelete: (id: string) => void; onPageAdd: () => void; }; -const SidePanel: React.FC = ({ onStoryAdd, onSelectStory, onPageAdd, onSelectPage }) => { +const SidePanel: React.FC = ({ onPageAdd, onPageSelect, onPageDuplicate, onPageDelete }) => { const t = useT(); return ( , - }, + // you can use this when get multiple story feature + // { + // id: "story", + // title: t("Story"), + // maxHeight: "33%", + // children: , + // }, { id: "page", title: t("Page"), - children: , + children: ( + + ), }, ]} /> diff --git a/web/src/beta/features/Editor/useLeftPanel.tsx b/web/src/beta/features/Editor/useLeftPanel.tsx index 89001ad6c5..2755e2b9eb 100644 --- a/web/src/beta/features/Editor/useLeftPanel.tsx +++ b/web/src/beta/features/Editor/useLeftPanel.tsx @@ -15,13 +15,15 @@ export default ({ tab }: Props) => { case "story": return ( console.log("onSelectStory")} - onStoryAdd={() => console.log("onStoryAdd")} + // stories={[]} + // selectedStory={undefined} + // onStorySelect={() => console.log("onSelectStory")} + // onStoryAdd={() => console.log("onStoryAdd")} selectedPageId={"1"} - onSelectPage={() => console.log("onSelectPage")} + onPageSelect={() => console.log("onSelectPage")} onPageAdd={() => console.log("onPageAdd")} + onPageDuplicate={() => console.log("onPageDuplicate")} + onPageDelete={() => console.log("onPageDelete")} /> ); case "widgets": diff --git a/web/src/services/i18n/translations/en.yml b/web/src/services/i18n/translations/en.yml index 7f811348b0..ea83c7a938 100644 --- a/web/src/services/i18n/translations/en.yml +++ b/web/src/services/i18n/translations/en.yml @@ -1,7 +1,6 @@ Not found: Not found New Page: New Page New Swipe: New Swipe -New Story: New Story Story: Story Page: Page Desktop: Desktop diff --git a/web/src/services/i18n/translations/ja.yml b/web/src/services/i18n/translations/ja.yml index 80f617af26..ae91968ffe 100644 --- a/web/src/services/i18n/translations/ja.yml +++ b/web/src/services/i18n/translations/ja.yml @@ -1,7 +1,6 @@ Not found: ページが見つかりません New Page: 新しいページ New Swipe: 新しいスワイプ -New Story: 新しいストーリー Story: ストーリー Page: ページ Desktop: デスクトップ