mirror of
https://github.com/baptisteArno/typebot.io.git
synced 2026-06-19 21:04:33 +08:00
♻️ Lift right side bar state to the URL
This commit is contained in:
parent
fb3eda4e87
commit
07e1eb41c3
@ -8,6 +8,7 @@ import {
|
||||
} from "@/components/icons";
|
||||
import { ParentModalProvider } from "@/features/graph/providers/ParentModalProvider";
|
||||
import { parseDefaultPublicId } from "@/features/publish/helpers/parseDefaultPublicId";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
HStack,
|
||||
IconButton,
|
||||
@ -21,7 +22,6 @@ import {
|
||||
} from "@chakra-ui/react";
|
||||
import { useTranslate } from "@tolgee/react";
|
||||
import React, { useState } from "react";
|
||||
import { RightPanel, useEditor } from "../providers/EditorProvider";
|
||||
import { useTypebot } from "../providers/TypebotProvider";
|
||||
import { EditorSettingsModal } from "./EditorSettingsModal";
|
||||
|
||||
@ -30,7 +30,7 @@ export const BoardMenuButton = (props: StackProps) => {
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { t } = useTranslate();
|
||||
const { setRightPanel } = useEditor();
|
||||
const [, setRightPanel] = useRightPanel();
|
||||
|
||||
const downloadFlow = () => {
|
||||
assert(typebot);
|
||||
@ -60,7 +60,7 @@ export const BoardMenuButton = (props: StackProps) => {
|
||||
size="sm"
|
||||
shadow="md"
|
||||
bgColor={useColorModeValue("white", undefined)}
|
||||
onClick={() => setRightPanel(RightPanel.VARIABLES)}
|
||||
onClick={() => setRightPanel("variables")}
|
||||
/>
|
||||
<Menu>
|
||||
<MenuButton
|
||||
|
||||
@ -6,12 +6,9 @@ import { VideoOnboardingFloatingWindow } from "@/features/onboarding/components/
|
||||
import { PreviewDrawer } from "@/features/preview/components/PreviewDrawer";
|
||||
import { VariablesDrawer } from "@/features/preview/components/VariablesDrawer";
|
||||
import { useWorkspace } from "@/features/workspace/WorkspaceProvider";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import { Flex, Spinner, useColorModeValue } from "@chakra-ui/react";
|
||||
import {
|
||||
EditorProvider,
|
||||
RightPanel as RightPanelEnum,
|
||||
useEditor,
|
||||
} from "../providers/EditorProvider";
|
||||
import { EditorProvider } from "../providers/EditorProvider";
|
||||
import { useTypebot } from "../providers/TypebotProvider";
|
||||
import { BlocksSideBar } from "./BlocksSideBar";
|
||||
import { BoardMenuButton } from "./BoardMenuButton";
|
||||
@ -77,14 +74,14 @@ export const EditorPage = () => {
|
||||
};
|
||||
|
||||
const RightPanel = () => {
|
||||
const { rightPanel, setRightPanel } = useEditor();
|
||||
const [rightPanel, setRightPanel] = useRightPanel();
|
||||
|
||||
switch (rightPanel) {
|
||||
case RightPanelEnum.PREVIEW:
|
||||
case "preview":
|
||||
return <PreviewDrawer />;
|
||||
case RightPanelEnum.VARIABLES:
|
||||
return <VariablesDrawer onClose={() => setRightPanel(undefined)} />;
|
||||
case undefined:
|
||||
case "variables":
|
||||
return <VariablesDrawer onClose={() => setRightPanel(null)} />;
|
||||
case null:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@ import { ShareTypebotButton } from "@/features/share/components/ShareTypebotButt
|
||||
import { useWorkspace } from "@/features/workspace/WorkspaceProvider";
|
||||
import { isCloudProdInstance } from "@/helpers/isCloudProdInstance";
|
||||
import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
@ -34,7 +35,7 @@ import { useRouter } from "next/router";
|
||||
import React, { useState } from "react";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { headerHeight } from "../constants";
|
||||
import { RightPanel, useEditor } from "../providers/EditorProvider";
|
||||
import { useEditor } from "../providers/EditorProvider";
|
||||
import { useTypebot } from "../providers/TypebotProvider";
|
||||
import { EditableTypebotName } from "./EditableTypebotName";
|
||||
import { GuestTypebotHeader } from "./UnauthenticatedTypebotHeader";
|
||||
@ -42,7 +43,6 @@ import { GuestTypebotHeader } from "./UnauthenticatedTypebotHeader";
|
||||
export const TypebotHeader = () => {
|
||||
const { typebot, publishedTypebot, currentUserMode } = useTypebot();
|
||||
const { workspace } = useWorkspace();
|
||||
|
||||
const { isOpen, onOpen } = useDisclosure();
|
||||
const headerBgColor = useColorModeValue("white", "gray.950");
|
||||
|
||||
@ -254,12 +254,13 @@ const RightElements = ({
|
||||
const router = useRouter();
|
||||
const { t } = useTranslate();
|
||||
const { typebot, currentUserMode, save, isSavingLoading } = useTypebot();
|
||||
const { setRightPanel, rightPanel, setStartPreviewFrom } = useEditor();
|
||||
const { setStartPreviewFrom } = useEditor();
|
||||
const [rightPanel, setRightPanel] = useRightPanel();
|
||||
|
||||
const handlePreviewClick = async () => {
|
||||
setStartPreviewFrom(undefined);
|
||||
await save();
|
||||
setRightPanel(RightPanel.PREVIEW);
|
||||
setRightPanel("preview");
|
||||
};
|
||||
|
||||
return (
|
||||
@ -272,21 +273,20 @@ const RightElements = ({
|
||||
<Flex pos="relative">
|
||||
<ShareTypebotButton isLoading={isNotDefined(typebot)} />
|
||||
</Flex>
|
||||
{router.pathname.includes("/edit") &&
|
||||
rightPanel !== RightPanel.PREVIEW && (
|
||||
<Button
|
||||
colorScheme="gray"
|
||||
onClick={handlePreviewClick}
|
||||
isLoading={isNotDefined(typebot) || isSavingLoading}
|
||||
leftIcon={<PlayIcon />}
|
||||
size="sm"
|
||||
iconSpacing={{ base: 0, xl: 2 }}
|
||||
>
|
||||
<chakra.span display={{ base: "none", xl: "inline" }}>
|
||||
{t("editor.header.previewButton.label")}
|
||||
</chakra.span>
|
||||
</Button>
|
||||
)}
|
||||
{router.pathname.includes("/edit") && rightPanel !== "preview" && (
|
||||
<Button
|
||||
colorScheme="gray"
|
||||
onClick={handlePreviewClick}
|
||||
isLoading={isNotDefined(typebot) || isSavingLoading}
|
||||
leftIcon={<PlayIcon />}
|
||||
size="sm"
|
||||
iconSpacing={{ base: 0, xl: 2 }}
|
||||
>
|
||||
<chakra.span display={{ base: "none", xl: "inline" }}>
|
||||
{t("editor.header.previewButton.label")}
|
||||
</chakra.span>
|
||||
</Button>
|
||||
)}
|
||||
{currentUserMode === "guest" && (
|
||||
<Button
|
||||
as={Link}
|
||||
|
||||
@ -2,6 +2,7 @@ import { EmojiOrImageIcon } from "@/components/EmojiOrImageIcon";
|
||||
import { TypebotLogo } from "@/components/TypebotLogo";
|
||||
import { CopyIcon, PlayIcon } from "@/components/icons";
|
||||
import { useUser } from "@/features/user/hooks/useUser";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
Button,
|
||||
Divider,
|
||||
@ -16,7 +17,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
import { headerHeight } from "../constants";
|
||||
import { RightPanel, useEditor } from "../providers/EditorProvider";
|
||||
import { useEditor } from "../providers/EditorProvider";
|
||||
import { useTypebot } from "../providers/TypebotProvider";
|
||||
|
||||
export const GuestTypebotHeader = () => {
|
||||
@ -24,12 +25,13 @@ export const GuestTypebotHeader = () => {
|
||||
const router = useRouter();
|
||||
const { user } = useUser();
|
||||
const { typebot, save } = useTypebot();
|
||||
const { setRightPanel, rightPanel, setStartPreviewFrom } = useEditor();
|
||||
const { setStartPreviewFrom } = useEditor();
|
||||
const [rightPanel, setRightPanel] = useRightPanel();
|
||||
|
||||
const handlePreviewClick = async () => {
|
||||
setStartPreviewFrom(undefined);
|
||||
save().then();
|
||||
setRightPanel(RightPanel.PREVIEW);
|
||||
setRightPanel("preview");
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -7,14 +7,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
export enum RightPanel {
|
||||
PREVIEW = 0,
|
||||
VARIABLES = 1,
|
||||
}
|
||||
|
||||
const editorContext = createContext<{
|
||||
rightPanel?: RightPanel;
|
||||
setRightPanel: Dispatch<SetStateAction<RightPanel | undefined>>;
|
||||
startPreviewFrom:
|
||||
| {
|
||||
type: "group" | "event";
|
||||
@ -34,7 +27,6 @@ const editorContext = createContext<{
|
||||
}>({});
|
||||
|
||||
export const EditorProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [rightPanel, setRightPanel] = useState<RightPanel>();
|
||||
const [startPreviewFrom, setStartPreviewFrom] = useState<
|
||||
| {
|
||||
type: "group" | "event";
|
||||
@ -46,8 +38,6 @@ export const EditorProvider = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<editorContext.Provider
|
||||
value={{
|
||||
rightPanel,
|
||||
setRightPanel,
|
||||
startPreviewFrom,
|
||||
setStartPreviewFrom,
|
||||
}}
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import { ContextMenu } from "@/components/ContextMenu";
|
||||
import {
|
||||
RightPanel,
|
||||
useEditor,
|
||||
} from "@/features/editor/providers/EditorProvider";
|
||||
import { useEditor } from "@/features/editor/providers/EditorProvider";
|
||||
import { useTypebot } from "@/features/editor/providers/TypebotProvider";
|
||||
import { SettingsModal } from "@/features/graph/components/nodes/block/SettingsModal";
|
||||
import {
|
||||
@ -14,6 +11,7 @@ import { useSelectionStore } from "@/features/graph/hooks/useSelectionStore";
|
||||
import { useGraph } from "@/features/graph/providers/GraphProvider";
|
||||
import { ParentModalProvider } from "@/features/graph/providers/ParentModalProvider";
|
||||
import { setMultipleRefs } from "@/helpers/setMultipleRefs";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
Popover,
|
||||
PopoverTrigger,
|
||||
@ -43,8 +41,9 @@ export const EventNode = ({ event, eventIndex }: Props) => {
|
||||
const elementBgColor = useColorModeValue("white", "gray.950");
|
||||
const previewingBorderColor = useColorModeValue("orange.400", "orange.300");
|
||||
const { previewingEdge, isReadOnly, graphPosition } = useGraph();
|
||||
const { updateEvent, deleteEvent, updateEventsCoordinates } = useTypebot();
|
||||
const { setRightPanel, setStartPreviewFrom } = useEditor();
|
||||
const { updateEvent, updateEventsCoordinates } = useTypebot();
|
||||
const { setStartPreviewFrom } = useEditor();
|
||||
const [, setRightPanel] = useRightPanel();
|
||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||
|
||||
const focusedElements = useSelectionStore(
|
||||
@ -88,7 +87,7 @@ export const EventNode = ({ event, eventIndex }: Props) => {
|
||||
|
||||
const startPreviewAtThisEvent = () => {
|
||||
setStartPreviewFrom({ type: "event", id: event.id });
|
||||
setRightPanel(RightPanel.PREVIEW);
|
||||
setRightPanel("preview");
|
||||
};
|
||||
|
||||
const handleOnNodeChange = (
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import { ContextMenu } from "@/components/ContextMenu";
|
||||
import {
|
||||
RightPanel,
|
||||
useEditor,
|
||||
} from "@/features/editor/providers/EditorProvider";
|
||||
import { useEditor } from "@/features/editor/providers/EditorProvider";
|
||||
import { useTypebot } from "@/features/editor/providers/TypebotProvider";
|
||||
import { groupWidth } from "@/features/graph/constants";
|
||||
import { useSelectionStore } from "@/features/graph/hooks/useSelectionStore";
|
||||
import { useBlockDnd } from "@/features/graph/providers/GraphDndProvider";
|
||||
import { useGraph } from "@/features/graph/providers/GraphProvider";
|
||||
import { setMultipleRefs } from "@/helpers/setMultipleRefs";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
Editable,
|
||||
EditableInput,
|
||||
@ -25,7 +23,6 @@ import { useShallow } from "zustand/react/shallow";
|
||||
import { BlockNodesList } from "../block/BlockNodesList";
|
||||
import { GroupFocusToolbar } from "./GroupFocusToolbar";
|
||||
import { GroupNodeContextMenu } from "./GroupNodeContextMenu";
|
||||
|
||||
type Props = {
|
||||
group: GroupV6;
|
||||
groupIndex: number;
|
||||
@ -45,7 +42,8 @@ export const GroupNode = ({ group, groupIndex }: Props) => {
|
||||
} = useGraph();
|
||||
const { typebot, updateGroup, updateGroupsCoordinates } = useTypebot();
|
||||
const { setMouseOverGroup, mouseOverGroup } = useBlockDnd();
|
||||
const { setRightPanel, setStartPreviewFrom } = useEditor();
|
||||
const { setStartPreviewFrom } = useEditor();
|
||||
const [, setRightPanel] = useRightPanel();
|
||||
|
||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
@ -111,7 +109,7 @@ export const GroupNode = ({ group, groupIndex }: Props) => {
|
||||
|
||||
const startPreviewAtThisGroup = () => {
|
||||
setStartPreviewFrom({ type: "group", id: group.id });
|
||||
setRightPanel(RightPanel.PREVIEW);
|
||||
setRightPanel("preview");
|
||||
};
|
||||
|
||||
useDrag(
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useGraph } from "@/features/graph/providers/GraphProvider";
|
||||
import { useRightPanel } from "@/hooks/useRightPanel";
|
||||
import {
|
||||
Button,
|
||||
CloseButton,
|
||||
@ -12,7 +13,6 @@ import { useTranslate } from "@tolgee/react";
|
||||
import { useDrag } from "@use-gesture/react";
|
||||
import React, { useState } from "react";
|
||||
import { headerHeight } from "../../editor/constants";
|
||||
import { useEditor } from "../../editor/providers/EditorProvider";
|
||||
import { useTypebot } from "../../editor/providers/TypebotProvider";
|
||||
import { runtimes } from "../data";
|
||||
import { PreviewDrawerBody } from "./PreviewDrawerBody";
|
||||
@ -32,7 +32,6 @@ const getDefaultRuntime = (typebotId?: string) => {
|
||||
export const PreviewDrawer = () => {
|
||||
const { typebot, save, isSavingLoading } = useTypebot();
|
||||
const { t } = useTranslate();
|
||||
const { setRightPanel } = useEditor();
|
||||
const { setPreviewingBlock } = useGraph();
|
||||
const [width, setWidth] = useState(500);
|
||||
const [isResizeHandleVisible, setIsResizeHandleVisible] = useState(false);
|
||||
@ -40,6 +39,7 @@ export const PreviewDrawer = () => {
|
||||
const [selectedRuntime, setSelectedRuntime] = useState<
|
||||
(typeof runtimes)[number]
|
||||
>(getDefaultRuntime(typebot?.id));
|
||||
const [, setRightPanel] = useRightPanel();
|
||||
|
||||
const handleRestartClick = async () => {
|
||||
await save();
|
||||
@ -48,7 +48,7 @@ export const PreviewDrawer = () => {
|
||||
|
||||
const handleCloseClick = () => {
|
||||
setPreviewingBlock(undefined);
|
||||
setRightPanel(undefined);
|
||||
setRightPanel(null);
|
||||
};
|
||||
|
||||
const useResizeHandleDrag = useDrag(
|
||||
|
||||
9
apps/builder/src/hooks/useRightPanel.ts
Normal file
9
apps/builder/src/hooks/useRightPanel.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { parseAsStringLiteral, useQueryState } from "nuqs";
|
||||
|
||||
const rightPanels = ["preview", "variables"] as const;
|
||||
|
||||
export const useRightPanel = () =>
|
||||
useQueryState<(typeof rightPanels)[number]>(
|
||||
"rightPanel",
|
||||
parseAsStringLiteral(rightPanels),
|
||||
);
|
||||
@ -2,7 +2,11 @@ import Router from "next/router";
|
||||
import NProgress from "nprogress";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const progressStarted = () => NProgress.start();
|
||||
const progressStarted = (url: string) => {
|
||||
if (Router.asPath.split("?")[0] === url.split("?")[0]) return;
|
||||
NProgress.start();
|
||||
};
|
||||
|
||||
const progressComplete = () => NProgress.done();
|
||||
|
||||
export const useRouterProgressBar = () =>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user