diff --git a/modelina-website/src/components/contexts/PlaygroundLayoutContext.tsx b/modelina-website/src/components/contexts/PlaygroundLayoutContext.tsx index ab35e8e2e5..58398df04b 100644 --- a/modelina-website/src/components/contexts/PlaygroundLayoutContext.tsx +++ b/modelina-website/src/components/contexts/PlaygroundLayoutContext.tsx @@ -1,133 +1,17 @@ 'use client'; import { useMeasure } from '@uidotdev/usehooks'; -import type { Draft, Immutable } from 'immer'; -import { enableMapSet, produce } from 'immer'; import { createContext, useContext, useEffect, useReducer } from 'react'; -import { IoOptionsOutline } from 'react-icons/io5'; -import { LuFileInput, LuFileOutput } from 'react-icons/lu'; -import { VscListSelection } from 'react-icons/vsc'; -interface ISidebarItem { - name: string; - title: string; - isOpen: boolean; - devices: 'mobile' | 'tablet' | 'desktop' | 'all' ; - icon: React.ReactNode; - tooltip: string; -} - -const sidebarItems: Map = new Map([ - [ - 'input-editor', { - name: 'input-editor', - title: 'Input Editor', - isOpen: true, - devices: 'mobile', - icon: , - tooltip: 'Show Input Editor' - } - ], - [ - 'output-editor', { - name: 'output-editor', - title: 'Output Editor', - isOpen: false, - devices: 'mobile', - icon: , - tooltip: 'Show Output Editor' - } - ], - [ - 'general-options', { - name: 'general-options', - title: 'Options', - isOpen: true, - devices: 'all', - icon: , - tooltip: 'Show or hide all the options' - } - ], - [ - 'output-options', { - name: 'output-options', - title: 'Output', - isOpen: false, - devices: 'all', - icon: , - tooltip: 'Show or hide the list of output models' - } - ] -]); - -type IDeviceType = 'mobile' | 'tablet' | 'notebook' | 'desktop'; +import type { Dispatch, State } from '@/store/useLayoutStore'; +import { initialState, playgroundLayoutReducer } from '@/store/useLayoutStore'; -type ActionType = { type: 'open-option', name: string } | { type: 'update-device', payload: IDeviceType } | { type: '' }; -type Dispatch = (action: ActionType) => void; -type State = Immutable<{ open: string, device: IDeviceType, sidebarItems: typeof sidebarItems }>; type PlaygroundtProviderProps = { children: React.ReactNode }; -const initialState: State = { open: 'general-options', device: 'desktop', sidebarItems }; - const PlaygroundtLayoutContext = createContext< { state: State; dispatch: Dispatch } | undefined >(undefined); -const playgroundLayoutReducer = produce((draft: Draft, action) => { - enableMapSet(); - - switch (action.type) { - case 'update-device': { - // eslint-disable-next-line no-param-reassign - draft.device = action.payload; - break; - } - case 'open-option': { - const findOpts = draft.sidebarItems.get(action.name); - - const alwaysOpen = ['input-editor', 'output-editor', 'general-options']; - const isMobile = draft.device === 'mobile'; - - if (!findOpts) { - break; - } - - if (alwaysOpen.includes(action.name) && isMobile) { - if (draft.open === action.name) { - // eslint-disable-next-line no-param-reassign - draft.open = findOpts.name ?? draft.open; - break; - } - } - - draft.sidebarItems.set(action.name, { - ...findOpts, - isOpen: !findOpts.isOpen - }); - - if (draft.open !== findOpts.name) { - const findOne = draft.sidebarItems.get(draft.open); - - if (findOne) { - draft.sidebarItems.set(draft.open, { - ...findOne, - isOpen: false - } - ); - } - } - - // eslint-disable-next-line no-param-reassign - draft.open = findOpts.name ?? draft.open; - - break; - } - default: { - throw new Error(`Unhandled action type: ${action.type}`); - } - } -}); - /** * This component to consume Plaground Layout State. * @@ -170,7 +54,7 @@ function PlaygroundLayoutProvider({ children }: PlaygroundtProviderProps) { }, [width]); return ( - +
{children}
diff --git a/modelina-website/src/components/playground/Resizable.tsx b/modelina-website/src/components/playground/Resizable.tsx index 3381984bc5..98f36e1dcc 100644 --- a/modelina-website/src/components/playground/Resizable.tsx +++ b/modelina-website/src/components/playground/Resizable.tsx @@ -3,6 +3,8 @@ import { useMeasure } from '@uidotdev/usehooks'; import { motion, useMotionValue, useTransform } from 'framer-motion'; import { memo, type ReactNode, useEffect } from 'react'; +import { usePlaygroundLayout } from '../contexts/PlaygroundLayoutContext'; + interface ResizableComponentProps { leftComponent?: ReactNode; rightComponent?: ReactNode; @@ -15,20 +17,37 @@ interface ResizableComponentProps { * @property {React.ReactElement} rightComponent The right element which will be stretch. */ function Resizable({ leftComponent, rightComponent }: ResizableComponentProps) { + const { state, dispatch } = usePlaygroundLayout(); + const [ref, { width: containerWidth }] = useMeasure(); const DefaultWidth = 640; const dragableX = useMotionValue(DefaultWidth); - const width = useTransform(dragableX, (value) => `${value + 0.5 * 4}px`); + const width = useTransform(dragableX, (value) => { + if (containerWidth !== null) { + const visibleView = value / containerWidth; + + dispatch({ type: 'resizable-size', total: visibleView }); + } + + return `${value + 0.5 * 4}px`; + }); useEffect(() => { - if (containerWidth !== null && containerWidth >= 640) { - dragableX.set(Math.round(containerWidth / 2)); + if (containerWidth !== null) { + dragableX.set(Math.round(containerWidth * state.editorSize)); } }, [containerWidth]); + if (state.device === 'mobile') { + return
+ {leftComponent} + {rightComponent} +
; + } + return ( -
+
diff --git a/modelina-website/src/components/playground/Sidebar.tsx b/modelina-website/src/components/playground/Sidebar.tsx index 048588f8c3..73ff0959a6 100644 --- a/modelina-website/src/components/playground/Sidebar.tsx +++ b/modelina-website/src/components/playground/Sidebar.tsx @@ -19,14 +19,14 @@ export const Sidebar: React.FunctionComponent = () => {