diff --git a/package.json b/package.json index c37c3a2..4a2f879 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@kevisual/codemirror": "^0.0.2", "@kevisual/query": "^0.0.6", "@kevisual/ui": "^0.0.2", + "@monaco-editor/react": "^4.6.0", "@uiw/react-textarea-code-editor": "^3.0.2", "@xyflow/react": "^12.3.1", "antd": "^5.21.1", @@ -34,6 +35,7 @@ "nanoid": "^5.0.7", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-resizable-panels": "^2.1.4", "react-router": "^6.26.2", "react-router-dom": "^6.26.2", "react-toastify": "^10.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bb9148..1c3e6a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: '@kevisual/ui': specifier: ^0.0.2 version: 0.0.2 + '@monaco-editor/react': + specifier: ^4.6.0 + version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@uiw/react-textarea-code-editor': specifier: ^3.0.2 version: 3.0.2(@babel/runtime@7.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -74,6 +77,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-resizable-panels: + specifier: ^2.1.4 + version: 2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-router: specifier: ^6.26.2 version: 6.26.2(react@18.3.1) @@ -577,6 +583,18 @@ packages: '@kevisual/ui@0.0.2': resolution: {integrity: sha512-MDZDQTrYToLyj3WhiVJQLJ0PUHiN4D0Z5yJIyGzzPewPGpP2xwNgKO1BFX37J95cGZckzCdZwTKP0XKAOq0QtA==} + '@monaco-editor/loader@1.4.0': + resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==} + peerDependencies: + monaco-editor: '>= 0.21.0 < 1' + + '@monaco-editor/react@4.6.0': + resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1773,6 +1791,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + monaco-editor@0.52.0: + resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2185,6 +2206,12 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-resizable-panels@2.1.4: + resolution: {integrity: sha512-kzue8lsoSBdyyd2IfXLQMMhNujOxRoGVus+63K95fQqleGxTfvgYLTzbwYMOODeAHqnkjb3WV/Ks7f5+gDYZuQ==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 + react-router-dom@6.26.2: resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==} engines: {node: '>=14.0.0'} @@ -2312,6 +2339,9 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} @@ -3037,6 +3067,18 @@ snapshots: lodash-es: 4.17.21 style-to-object: 1.0.8 + '@monaco-editor/loader@1.4.0(monaco-editor@0.52.0)': + dependencies: + monaco-editor: 0.52.0 + state-local: 1.0.7 + + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) + monaco-editor: 0.52.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4373,6 +4415,8 @@ snapshots: minipass@7.1.2: {} + monaco-editor@0.52.0: {} + ms@2.1.3: {} mz@2.7.0: @@ -4853,6 +4897,11 @@ snapshots: react-refresh@0.14.2: {} + react-resizable-panels@2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@remix-run/router': 1.19.2 @@ -5004,6 +5053,8 @@ snapshots: space-separated-tokens@2.0.2: {} + state-local@1.0.7: {} + string-convert@0.2.1: {} string-width@4.2.3: diff --git a/src/pages/ai-chat/AiModule.tsx b/src/pages/ai-chat/AiModule.tsx index 4c82f95..a4462e5 100644 --- a/src/pages/ai-chat/AiModule.tsx +++ b/src/pages/ai-chat/AiModule.tsx @@ -2,7 +2,7 @@ import { useShallow } from 'zustand/react/shallow'; import { useAiStore } from './store/ai-store'; import { CloseOutlined, HistoryOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Dropdown, Form, Input, message, Modal, Tooltip } from 'antd'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { TextArea } from '../container/components/TextArea'; import clsx from 'clsx'; import { query } from '@/modules'; @@ -221,7 +221,11 @@ export const AiMoudle = () => { const onSendNoPrompt = (value) => { send({ type: 'messages', data: { message: value, root: true } }); }; - const inputs = form.getFieldValue('inputs'); + const inputs = useMemo(() => { + if (!aiStore.open) return []; + const inputs = form.getFieldValue('inputs'); + return inputs; + }, [aiStore.open]); const isNotShow = inputs?.length === 0 || !inputs; const OnlyNormalMessage = ( diff --git a/src/pages/panel/app/edit/Editor.tsx b/src/pages/panel/app/edit/Editor.tsx new file mode 100644 index 0000000..2ad6f91 --- /dev/null +++ b/src/pages/panel/app/edit/Editor.tsx @@ -0,0 +1,26 @@ +import Editor from '@monaco-editor/react'; +import { useState } from 'react'; + +export const AppEditor = () => { + const [code, setCode] = useState(''); + const [language, setLanguage] = useState('javascript'); + return ( +
+ { + setCode(value || ''); + }} + options={{ + minimap: { enabled: false }, + }} + defaultLanguage='javascript' + defaultValue='// some comment' + /> +
+ ); +}; + +export default AppEditor; diff --git a/src/pages/panel/app/index.tsx b/src/pages/panel/app/index.tsx new file mode 100644 index 0000000..daf42b0 --- /dev/null +++ b/src/pages/panel/app/index.tsx @@ -0,0 +1,36 @@ +import { useParams } from 'react-router'; +import { useAppStore } from './store'; +import { lazy, useEffect } from 'react'; +import { Left } from './panel/Left'; +import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; +import { EditorHeader } from './panel/EditorHeader'; + +// import AppEditor from './edit/Editor'; +const AppEditor = lazy(() => import('./edit/Editor')); + +export const App = () => { + const appStore = useAppStore(); + const param = useParams(); + const id = param.id as string; + useEffect(() => { + if (!id) return; + appStore.getData(id); + }, []); + if (!id) return
Not Found
; + return ( +
+ + + + + + +
+ + +
+
+
+
+ ); +}; diff --git a/src/pages/panel/app/panel/EditorHeader.tsx b/src/pages/panel/app/panel/EditorHeader.tsx new file mode 100644 index 0000000..c8497ed --- /dev/null +++ b/src/pages/panel/app/panel/EditorHeader.tsx @@ -0,0 +1,22 @@ +import { useState } from 'react'; +import { useAppStore } from '../store'; + +export const EditorHeader = () => { + const appStore = useAppStore(); + const [headerList, setHeaderList] = useState([]); + return ( +
+
+
+
+
Header
+
({headerList.length})
+
+
+ +
+
+
+
+ ); +}; diff --git a/src/pages/panel/app/panel/Left.tsx b/src/pages/panel/app/panel/Left.tsx new file mode 100644 index 0000000..07a5119 --- /dev/null +++ b/src/pages/panel/app/panel/Left.tsx @@ -0,0 +1,36 @@ +import { useAppStore } from '../store'; + +type LabelProps = { + title: string; + children?: any; +}; +export const Label = (props: LabelProps) => { + const { title } = props; + return ( +
+
{title}:
+
{props.children}
+
+ ); +}; +export const Left = () => { + const appStore = useAppStore(); + return ( +
+
+ + +
+
+
+ {appStore.nodes?.map?.((node, index) => { + return ( +
+ {node.id} +
+ ); + })} +
+
+ ); +}; diff --git a/src/pages/panel/app/store/index.ts b/src/pages/panel/app/store/index.ts new file mode 100644 index 0000000..2dd6300 --- /dev/null +++ b/src/pages/panel/app/store/index.ts @@ -0,0 +1,45 @@ +import { query } from '@/modules'; +import { message } from 'antd'; +import { create } from 'zustand'; + +type Node = { + id: string; + type: string; + data: { + cid: string; + }; +}; +type AppStore = { + id: string; + setId: (id: string) => void; + getData: (id: string) => Promise; + nodes: Node[]; + data: any; +}; +export const useAppStore = create((set, get) => ({ + id: '', + setId: (id: string) => set({ id }), + data: {}, + nodes: [], + getData: async (id: string) => { + console.log('getData'); + if (!id) { + message.error('Invalid id'); + return; + } + set({ id }); + const loaded = message.loading('Loading...', 0); + const res = await query.post({ + path: 'page', + key: 'get', + id, + }); + loaded(); + if (res.code === 200) { + console.log(res.data); + const data = res.data; + const nodes = data?.data?.nodes; + set({ data: data, nodes }); + } + }, +})); diff --git a/src/pages/panel/index.tsx b/src/pages/panel/index.tsx index 0831c30..e3a3d57 100644 --- a/src/pages/panel/index.tsx +++ b/src/pages/panel/index.tsx @@ -3,6 +3,8 @@ import { List } from './edit/List'; import { Main } from './layouts'; import { App as FlowApp } from './flow'; import { Deck } from './deck'; +import { App as PanelApp } from './app'; + export const App = () => { return ( @@ -11,6 +13,7 @@ export const App = () => { } /> } /> } /> + } />