Skip to content

Commit

Permalink
chore(web): next page button story block (#846)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaWaite committed Dec 1, 2023
1 parent a69d813 commit 7aa3463
Show file tree
Hide file tree
Showing 25 changed files with 152 additions and 40 deletions.
6 changes: 5 additions & 1 deletion server/pkg/builtin/manifest.yml
Expand Up @@ -2575,4 +2575,8 @@ extensions:
- key: once
label: Once
- key: loop
label: Loop
label: Loop
- id: nextPageStoryBlock
name: Next Page Button
type: storyBlock
description: Down button that will skip to next page.
5 changes: 4 additions & 1 deletion server/pkg/builtin/manifest_ja.yml
Expand Up @@ -1282,4 +1282,7 @@ extensions:
bgColor:
title: 背景色
showLayers:
title: 見えるレイヤー
title: 見えるレイヤー
nextPageStoryBlock:
name: 次ページボタン
description: ストーリーテリングの次ページに移動するボタンブロック
3 changes: 3 additions & 0 deletions web/src/beta/components/Icon/Icons/nextPageStoryBlock.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions web/src/beta/components/Icon/icons.ts
Expand Up @@ -94,6 +94,7 @@ import CameraButtonStoryBlock from "./Icons/cameraButtonStoryBlock.svg";
import ShowLayersStoryBlock from "./Icons/showLayersStoryBlock.svg";
import TimelineStoryBlock from "./Icons/timelineStoryBlock.svg";
import TimelineStoryBlockSolid from "./Icons/timelineStoryBlockSolid.svg";
import NextPageStoryBlock from "./Icons/nextPageStoryBlock.svg";

// Widget tab
import Desktop from "./Icons/desktop.svg";
Expand Down Expand Up @@ -194,6 +195,7 @@ export default {
showLayersStoryBlock: ShowLayersStoryBlock,
timelineStoryBlock: TimelineStoryBlock,
timelineStoryBlockSolid: TimelineStoryBlockSolid,
nextPageStoryBlock: NextPageStoryBlock,
widget: Widgets,
widgets: Widgets,
menu: WidgetMenu,
Expand Down
16 changes: 13 additions & 3 deletions web/src/beta/features/Editor/Visualizer/convert-story.ts
@@ -1,21 +1,31 @@
import { Story, StoryBlock, StoryPage } from "@reearth/beta/lib/core/StoryPanel/types";
import { valueFromGQL, valueTypeFromGQL } from "@reearth/beta/utils/value";
import { toUi } from "@reearth/services/api/propertyApi/utils";
import { Scene } from "@reearth/services/api/sceneApi";
import {
PropertyFieldFragmentFragment,
PropertyFragmentFragment,
PropertyGroupFragmentFragment,
PropertyItemFragmentFragment,
PropertySchemaFieldFragmentFragment,
PropertySchemaGroupFragmentFragment,
Story as GqlStory,
StoryPage as GqlStoryPage,
StoryBlock as GqlStoryBlock,
} from "@reearth/services/gql";

import { DatasetMap, P, datasetValue } from "./convert";

export const convertStory = (story?: GqlStory): Story | undefined => {
export const convertStory = (scene?: Scene, storyId?: string): Story | undefined => {
const story = scene?.stories.find(s => s.id === storyId);
const installedBlockNames = (scene?.plugins ?? [])
.flatMap(p =>
(p.plugin?.extensions ?? [])
.filter(e => e.type === "StoryBlock")
.map(e => ({ [e.extensionId]: e.translatedName ?? e.name }))
.filter((e): e is { [key: string]: string } => !!e),
)
.reduce((result, obj) => ({ ...result, ...obj }), {});

if (!story) return undefined;

const storyPages = (pages: GqlStoryPage[]): StoryPage[] =>
Expand All @@ -32,7 +42,7 @@ export const convertStory = (story?: GqlStory): Story | undefined => {
id: b.id,
pluginId: b.pluginId,
extensionId: b.extensionId,
name: b.property?.schema?.groups.find(g => g.schemaGroupId === "default")?.translatedTitle,
name: installedBlockNames?.[b.extensionId] ?? "Story Block",
propertyId: b.property?.id,
property: processProperty(undefined, b.property),
}));
Expand Down
6 changes: 2 additions & 4 deletions web/src/beta/features/Editor/Visualizer/hooks.ts
Expand Up @@ -198,10 +198,8 @@ export default ({
};

// Story
const story = useMemo(
() => convertStory(scene?.stories.find(s => s.id === storyId)),
[storyId, scene?.stories],
);
const story = useMemo(() => convertStory(scene, storyId), [storyId, scene]);

const handleCurrentPageChange = useCallback(
(pageId?: string) => selectSelectedStoryPageId(pageId),
[selectSelectedStoryPageId],
Expand Down
11 changes: 6 additions & 5 deletions web/src/beta/lib/core/StoryPanel/ActionPanel/index.tsx
Expand Up @@ -85,13 +85,14 @@ const ActionPanel: React.FC<Props> = ({
const settingsTitle = useMemo(() => t("Spacing settings"), [t]);

const popoverContent = useMemo(() => {
const menuItems: { name: string; icon: Icons; onClick: () => void }[] = [
{
const menuItems: { name: string; icon: Icons; onClick: () => void }[] = [];
if (panelSettings) {
menuItems.push({
name: settingsTitle,
icon: "padding",
onClick: () => setShowPadding(true),
},
];
});
}
if (onRemove) {
menuItems.push({
name: t("Remove"),
Expand All @@ -100,7 +101,7 @@ const ActionPanel: React.FC<Props> = ({
});
}
return menuItems;
}, [settingsTitle, t, setShowPadding, onRemove, handleRemove]);
}, [settingsTitle, panelSettings, t, setShowPadding, onRemove, handleRemove]);
return (
<Wrapper isSelected={isSelected} position={position} onClick={stopClickPropagation}>
{dndEnabled && (
Expand Down
@@ -1,7 +1,7 @@
import { useMemo } from "react";

import type { CommonProps as BlockProps } from "@reearth//beta/lib/core/StoryPanel/Block/types";
import BlockWrapper from "@reearth/beta/lib/core/StoryPanel/Block/builtin/common/Wrapper";
import type { CommonProps as BlockProps } from "@reearth/beta/lib/core/StoryPanel/Block/types";
import type { ValueTypes } from "@reearth/beta/utils/value";
import { styled } from "@reearth/services/theme";

Expand Down
64 changes: 64 additions & 0 deletions web/src/beta/lib/core/StoryPanel/Block/builtin/NextPage/index.tsx
@@ -0,0 +1,64 @@
import { useCallback } from "react";

import Icon from "@reearth/beta/components/Icon";
import BlockWrapper from "@reearth/beta/lib/core/StoryPanel/Block/builtin/common/Wrapper";
import type { CommonProps as BlockProps } from "@reearth/beta/lib/core/StoryPanel/Block/types";
import { styled } from "@reearth/services/theme";

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

const NextPage: React.FC<BlockProps> = ({ block, pageId, isSelected, ...props }) => {
const { pageIds, onJumpToPage } = usePanelContext();

const handlePageChange = useCallback(() => {
if (!pageId) return;
const pageIndex = pageIds?.findIndex(id => id === pageId);
if (pageIndex === undefined) return;
onJumpToPage?.(pageIndex + 1);
}, [pageId, pageIds, onJumpToPage]);

return (
<BlockWrapper
name={block?.name}
icon={block?.extensionId}
isSelected={isSelected}
propertyId={block?.propertyId}
property={block?.property}
{...props}>
<Wrapper>
<Button onClick={handlePageChange}>
<StyledIcon icon={block?.extensionId} size={16} />
</Button>
</Wrapper>
</BlockWrapper>
);
};

export default NextPage;

const Wrapper = styled.div`
display: flex;
width: 100%;
justify-content: center;
`;

const StyledIcon = styled(Icon)`
transition: none;
`;

const Button = styled.div`
display: flex;
justify-content: center;
align-items: center;
padding: 4px 12px;
border: 1px solid #2c2c2c;
border-radius: 6px;
transition: none;
cursor: pointer;
:hover {
background: #8d8d8d;
border: 1px solid #8d8d8d;
color: ${({ theme }) => theme.content.strong};
}
`;
@@ -1,7 +1,7 @@
import { useMemo } from "react";

import type { CommonProps as BlockProps } from "@reearth//beta/lib/core/StoryPanel/Block/types";
import BlockWrapper from "@reearth/beta/lib/core/StoryPanel/Block/builtin/common/Wrapper";
import type { CommonProps as BlockProps } from "@reearth/beta/lib/core/StoryPanel/Block/types";

import TimelineEditor from "./Editor";

Expand Down
@@ -1,8 +1,8 @@
import { useMemo } from "react";

import type { CommonProps as BlockProps } from "@reearth//beta/lib/core/StoryPanel/Block/types";
import BlockWrapper from "@reearth/beta/lib/core/StoryPanel/Block/builtin/common/Wrapper";
import VideoPlayer from "@reearth/beta/lib/core/StoryPanel/Block/builtin/Video/VideoPlayer";
import type { CommonProps as BlockProps } from "@reearth/beta/lib/core/StoryPanel/Block/types";
import type { ValueTypes } from "@reearth/beta/utils/value";

const VideoBlock: React.FC<BlockProps> = ({ block, isSelected, ...props }) => {
Expand Down
Expand Up @@ -7,6 +7,7 @@ type Props = {
icon?: string;
isSelected?: boolean;
editMode?: boolean;
panelSettings?: any;
onEditModeToggle?: (e: MouseEvent<HTMLDivElement>) => void;
onSettingsToggle?: (e: MouseEvent<HTMLDivElement>) => void;
};
Expand All @@ -16,6 +17,7 @@ export default ({
icon,
isSelected,
editMode,
panelSettings,
onEditModeToggle,
onSettingsToggle,
}: Props) => {
Expand All @@ -27,7 +29,7 @@ export default ({
},
];

if (onEditModeToggle) {
if (onEditModeToggle && !!panelSettings) {
menuItems.push({
icon: editMode ? "exit" : "storyBlockEdit",
hide: !isSelected,
Expand All @@ -44,7 +46,7 @@ export default ({
}

return menuItems;
}, [title, icon, isSelected, editMode, onEditModeToggle, onSettingsToggle]);
}, [title, icon, isSelected, editMode, panelSettings, onEditModeToggle, onSettingsToggle]);
return {
actionItems,
};
Expand Down
Expand Up @@ -51,6 +51,7 @@ const BlockActionPanel: React.FC<Props> = ({
isSelected,
editMode,
dndEnabled,
panelSettings,
onEditModeToggle,
onSettingsToggle,
...actionProps
Expand All @@ -60,6 +61,7 @@ const BlockActionPanel: React.FC<Props> = ({
icon,
isSelected,
editMode,
panelSettings,
onEditModeToggle,
onSettingsToggle,
});
Expand All @@ -69,6 +71,7 @@ const BlockActionPanel: React.FC<Props> = ({
dndEnabled={dndEnabled}
isSelected={isSelected}
actionItems={actionItems}
panelSettings={panelSettings}
onSettingsToggle={onSettingsToggle}
{...actionProps}
/>
Expand Down
10 changes: 5 additions & 5 deletions web/src/beta/lib/core/StoryPanel/Block/builtin/common/hooks.ts
Expand Up @@ -51,8 +51,9 @@ export default ({
[property],
);

const panelSettings = useMemo(
() => ({
const panelSettings = useMemo(() => {
if (!property?.panel) return undefined;
return {
padding: {
...property?.panel?.padding,
value: calculatePaddingValue(
Expand All @@ -61,9 +62,8 @@ export default ({
isEditable,
),
},
}),
[property?.panel, isEditable],
);
};
}, [property?.panel, isEditable]);

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

Expand Down
6 changes: 5 additions & 1 deletion web/src/beta/lib/core/StoryPanel/Block/builtin/index.ts
Expand Up @@ -10,12 +10,14 @@ import {
TITLE_BUILTIN_STORY_BLOCK_ID,
VIDEO_BUILTIN_STORY_BLOCK_ID,
LAYER_BUILTIN_STORY_BLOCK_ID,
NEXT_PAGE_BUILTIN_STORY_BLOCK_ID,
} from "../../constants";

import CameraBlock from "./Camera";
import ImageBlock from "./Image";
import LayerBlock from "./Layer";
import MdBlock from "./Markdown";
import NextPageBlock from "./NextPage";
import TextBlock from "./Text";
import TimelineBlock from "./Timeline";
import TitleBlock from "./Title";
Expand All @@ -29,7 +31,8 @@ export type ReEarthBuiltinStoryBlocks<T = unknown> = Record<
| typeof MD_BUILTIN_STORY_BLOCK_ID
| typeof CAMERA_BUILTIN_STORY_BLOCK_ID
| typeof LAYER_BUILTIN_STORY_BLOCK_ID
| typeof TIMELINE_BUILTIN_STORY_BLOCK_ID,
| typeof TIMELINE_BUILTIN_STORY_BLOCK_ID
| typeof NEXT_PAGE_BUILTIN_STORY_BLOCK_ID,
T
>;

Expand All @@ -45,6 +48,7 @@ const reearthBuiltin: BuiltinStoryBlocks<Component> = {
[TIMELINE_BUILTIN_STORY_BLOCK_ID]: TimelineBlock,
[CAMERA_BUILTIN_STORY_BLOCK_ID]: CameraBlock,
[LAYER_BUILTIN_STORY_BLOCK_ID]: LayerBlock,
[NEXT_PAGE_BUILTIN_STORY_BLOCK_ID]: NextPageBlock,
};

const builtin = merge({}, reearthBuiltin);
Expand Down
1 change: 1 addition & 0 deletions web/src/beta/lib/core/StoryPanel/Block/index.tsx
Expand Up @@ -9,6 +9,7 @@ import type { CommonProps, BlockProps } from "./types";
export type Props = {
renderBlock?: (block: BlockProps) => ReactNode;
layer?: Layer;
pageId?: string;
} & CommonProps;

export type Component = ComponentType<CommonProps>;
Expand Down
1 change: 1 addition & 0 deletions web/src/beta/lib/core/StoryPanel/Block/types.ts
Expand Up @@ -14,6 +14,7 @@ export type BlockProps = {
};

export type CommonProps = {
pageId?: string;
isEditable?: boolean;
isBuilt?: boolean;
isSelected?: boolean;
Expand Down
1 change: 1 addition & 0 deletions web/src/beta/lib/core/StoryPanel/Page/index.tsx
Expand Up @@ -202,6 +202,7 @@ const StoryPanel: React.FC<Props> = ({
<Fragment key={idx}>
<StoryBlock
block={b}
pageId={page?.id}
isSelected={selectedStoryBlockId === b.id}
isEditable={isEditable}
onClick={() => onBlockSelect?.(b.id)}
Expand Down
2 changes: 2 additions & 0 deletions web/src/beta/lib/core/StoryPanel/constants.ts
Expand Up @@ -21,6 +21,7 @@ export const MD_BUILTIN_STORY_BLOCK_ID = "reearth/mdTextStoryBlock";
export const CAMERA_BUILTIN_STORY_BLOCK_ID = "reearth/cameraButtonStoryBlock";
export const LAYER_BUILTIN_STORY_BLOCK_ID = "reearth/showLayersStoryBlock";
export const TIMELINE_BUILTIN_STORY_BLOCK_ID = "reearth/timelineStoryBlock";
export const NEXT_PAGE_BUILTIN_STORY_BLOCK_ID = "reearth/nextPageStoryBlock";

export const AVAILABLE_STORY_BLOCK_IDS = [
IMAGE_BUILTIN_STORY_BLOCK_ID,
Expand All @@ -30,4 +31,5 @@ export const AVAILABLE_STORY_BLOCK_IDS = [
CAMERA_BUILTIN_STORY_BLOCK_ID,
LAYER_BUILTIN_STORY_BLOCK_ID,
TIMELINE_BUILTIN_STORY_BLOCK_ID,
NEXT_PAGE_BUILTIN_STORY_BLOCK_ID,
];
2 changes: 2 additions & 0 deletions web/src/beta/lib/core/StoryPanel/context.tsx
@@ -1,8 +1,10 @@
import { createContext, FC, PropsWithChildren, useContext } from "react";

export type StoryPanelContext = {
pageIds?: string[];
layerOverride?: { extensionId: string; layerIds?: string[] };
onLayerOverride?: (id?: string, layerIds?: string[]) => void;
onJumpToPage?: (newPageIndex: number) => void;
};

const PanelContext = createContext<StoryPanelContext | undefined>(undefined);
Expand Down
2 changes: 2 additions & 0 deletions web/src/beta/lib/core/StoryPanel/hooks.ts
Expand Up @@ -206,6 +206,8 @@ export default (
showPageSettings,
isAutoScrolling,
layerOverride,
setCurrentPageId,
setLayerOverride,
handleLayerOverride,
handlePageSettingsToggle,
handlePageSelect,
Expand Down

0 comments on commit 7aa3463

Please sign in to comment.