-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(web): story page settings (#639)
- Loading branch information
Showing
53 changed files
with
836 additions
and
364 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
web/src/beta/features/Editor/StoryPanel/ActionPanel/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
import { Dispatch, Fragment, MouseEvent, SetStateAction, useMemo } from "react"; | ||
|
||
import FieldComponents from "@reearth/beta/components/fields/PropertyFields"; | ||
import Icon, { Icons } 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 { stopClickPropagation } from "@reearth/beta/utils/events"; | ||
import { Item } from "@reearth/services/api/propertyApi/utils"; | ||
import { useT } from "@reearth/services/i18n"; | ||
import { styled } from "@reearth/services/theme"; | ||
|
||
export type ActionItem = { | ||
icon: string; | ||
name?: string; | ||
hide?: boolean; | ||
onClick?: (e: MouseEvent<HTMLDivElement>) => void; | ||
}; | ||
|
||
export type ActionPosition = "left-top" | "left-bottom" | "right-top" | "right-bottom"; | ||
|
||
type Props = { | ||
isSelected?: boolean; | ||
showSettings?: boolean; | ||
showPadding?: boolean; | ||
propertyId?: string; | ||
panelSettings?: Item; | ||
actionItems: ActionItem[]; | ||
dndEnabled?: boolean; | ||
position?: ActionPosition; | ||
setShowPadding: Dispatch<SetStateAction<boolean>>; | ||
onSettingsToggle?: () => void; | ||
onRemove?: () => void; | ||
}; | ||
|
||
const ActionPanel: React.FC<Props> = ({ | ||
isSelected, | ||
showSettings, | ||
showPadding, | ||
propertyId, | ||
panelSettings, | ||
actionItems, | ||
dndEnabled, | ||
position, | ||
setShowPadding, | ||
onSettingsToggle, | ||
onRemove, | ||
}) => { | ||
const t = useT(); | ||
|
||
const popoverContent = useMemo(() => { | ||
const menuItems: { name: string; icon: Icons; onClick: () => void }[] = [ | ||
{ | ||
name: t("Padding settings"), | ||
icon: "padding", | ||
onClick: () => setShowPadding(true), | ||
}, | ||
]; | ||
if (onRemove) { | ||
menuItems.push({ | ||
name: t("Remove"), | ||
icon: "trash", | ||
onClick: onRemove, | ||
}); | ||
} | ||
return menuItems; | ||
}, [t, setShowPadding, onRemove]); | ||
|
||
return ( | ||
<Wrapper isSelected={isSelected} position={position} onClick={stopClickPropagation}> | ||
{dndEnabled && <DndHandle icon="dndHandle" size={16} />} | ||
<Popover.Provider | ||
open={showSettings} | ||
onOpenChange={() => onSettingsToggle?.()} | ||
placement="bottom-start"> | ||
<BlockOptions isSelected={isSelected}> | ||
{actionItems.map( | ||
(a, idx) => | ||
!a.hide && ( | ||
<Fragment key={idx}> | ||
<Popover.Trigger asChild> | ||
<OptionWrapper | ||
showPointer={!isSelected || !!a.onClick} | ||
onClick={a.onClick ?? stopClickPropagation}> | ||
<OptionIcon icon={a.icon} size={16} border={idx !== 0} /> | ||
{a.name && ( | ||
<OptionText size="footnote" customColor> | ||
{a.name} | ||
</OptionText> | ||
)} | ||
</OptionWrapper> | ||
</Popover.Trigger> | ||
</Fragment> | ||
), | ||
)} | ||
</BlockOptions> | ||
<Popover.Content> | ||
{showPadding ? ( | ||
<SettingsDropdown> | ||
<SettingsHeading> | ||
<Text size="footnote" customColor> | ||
{panelSettings?.title} | ||
</Text> | ||
<CancelIcon icon="cancel" size={14} onClick={() => setShowPadding(false)} /> | ||
</SettingsHeading> | ||
{propertyId && panelSettings && ( | ||
<SettingsContent> | ||
<FieldComponents propertyId={propertyId} item={panelSettings} /> | ||
</SettingsContent> | ||
)} | ||
</SettingsDropdown> | ||
) : ( | ||
<PopoverMenuContent size="sm" items={popoverContent} /> | ||
)} | ||
</Popover.Content> | ||
</Popover.Provider> | ||
</Wrapper> | ||
); | ||
}; | ||
|
||
export default ActionPanel; | ||
|
||
const Wrapper = styled.div<{ isSelected?: boolean; position?: ActionPosition }>` | ||
color: ${({ theme }) => theme.select.main}; | ||
display: flex; | ||
align-items: center; | ||
gap: 4px; | ||
height: 24px; | ||
position: absolute; | ||
${({ position }) => | ||
position === "left-top" | ||
? ` | ||
left: -1px; | ||
top: -25px; | ||
` | ||
: position === "left-bottom" | ||
? ` | ||
left: -1px; | ||
top: 0; | ||
` | ||
: position === "right-bottom" | ||
? ` | ||
top: 0; | ||
right: -1px; | ||
` | ||
: ` | ||
right: -1px; | ||
top: -25px; | ||
`} | ||
transition: all 0.2s; | ||
`; | ||
|
||
const BlockOptions = styled.div<{ isSelected?: boolean }>` | ||
background: ${({ isSelected, theme }) => (isSelected ? theme.select.main : "transparent")}; | ||
color: ${({ isSelected, theme }) => (isSelected ? theme.content.main : theme.select.main)}; | ||
display: flex; | ||
align-items: center; | ||
height: 24px; | ||
transition: all 0.2s; | ||
`; | ||
|
||
const OptionWrapper = styled.div<{ showPointer?: boolean }>` | ||
display: flex; | ||
align-items: center; | ||
cursor: ${({ showPointer }) => (showPointer ? "pointer" : "default")}; | ||
`; | ||
|
||
const OptionText = styled(Text)` | ||
padding-right: 4px; | ||
`; | ||
|
||
const OptionIcon = styled(Icon)<{ border?: boolean }>` | ||
padding: 4px; | ||
${({ border }) => border && "border-left: 1px solid #f1f1f1;"} | ||
`; | ||
|
||
const SettingsDropdown = styled.div` | ||
z-index: 999; | ||
background: ${({ theme }) => theme.bg[1]}; | ||
border-radius: 2px; | ||
border: 1px solid ${({ theme }) => theme.bg[3]}; | ||
`; | ||
|
||
const SettingsHeading = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
border-bottom: 1px solid ${({ theme }) => theme.outline.weak}; | ||
height: 28px; | ||
padding: 0 8px; | ||
`; | ||
|
||
const SettingsContent = styled.div` | ||
height: 100px; | ||
width: 200px; | ||
padding: 8px; | ||
box-sizing: border-box; | ||
`; | ||
|
||
const CancelIcon = styled(Icon)` | ||
cursor: pointer; | ||
`; | ||
|
||
const DndHandle = styled(Icon)` | ||
cursor: move; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
web/src/beta/features/Editor/StoryPanel/Block/builtin/Title/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { useMemo } from "react"; | ||
|
||
import Text from "@reearth/beta/components/Text"; | ||
import { ValueTypes } from "@reearth/beta/utils/value"; | ||
import { useT } from "@reearth/services/i18n"; | ||
import { styled } from "@reearth/services/theme"; | ||
|
||
import { getFieldValue } from "../../../utils"; | ||
import { CommonProps as BlockProps } from "../../types"; | ||
import BlockWrapper from "../common/Wrapper"; | ||
|
||
export type Props = BlockProps; | ||
|
||
const TitleBlock: React.FC<Props> = ({ block, isSelected, ...props }) => { | ||
const t = useT(); | ||
const text = useMemo( | ||
() => getFieldValue(block?.property?.items ?? [], "title") as ValueTypes["string"], | ||
[block?.property?.items], | ||
); | ||
|
||
const color = useMemo( | ||
() => getFieldValue(block?.property?.items ?? [], "color") as ValueTypes["string"], | ||
[block?.property?.items], | ||
); | ||
|
||
return ( | ||
<BlockWrapper | ||
title={block?.title} | ||
icon={block?.extensionId} | ||
isSelected={isSelected} | ||
propertyId={block?.property?.id} | ||
propertyItems={block?.property?.items} | ||
dndEnabled={false} | ||
{...props}> | ||
<Title size="h2" hasText={!!text} color={color} customColor> | ||
{text ?? t("Untitled")} | ||
</Title> | ||
</BlockWrapper> | ||
); | ||
}; | ||
|
||
export default TitleBlock; | ||
|
||
const Title = styled(Text)<{ hasText?: boolean; color?: string }>` | ||
color: ${({ color, hasText, theme }) => (hasText ? color ?? "black" : theme.content.weak)}; | ||
`; |
Oops, something went wrong.