add prompt js page

This commit is contained in:
2024-09-25 08:56:20 +08:00
parent d53c18606e
commit 3da62fd254
26 changed files with 436 additions and 115 deletions

View File

@@ -1,4 +1,5 @@
import CodeEditor from '@uiw/react-textarea-code-editor';
import { useEffect, useState } from 'react';
import { clsx } from 'clsx';
@@ -7,29 +8,35 @@ type Props = {
onChange?: (data: string) => void;
readonly?: boolean;
className?: string;
style?: React.CSSProperties;
language?: string;
listen?: boolean;
};
export const TextArea = (props: Props) => {
const [code, setCode] = useState<string>('');
useEffect(() => {
setCode(props.value || '');
}, []);
}, [props.value]);
const _onChange = (value: string) => {
setCode(value);
props.onChange && props.onChange(value);
if (props.onChange) {
props.onChange(value);
}
};
return (
<div className={clsx('min-h-16 max-h-52 overflow-scroll p-1 ', props.className)}>
<div className={clsx('min-h-16 max-h-52 overflow-scroll scrollbar p-1 ', props.className)}>
<CodeEditor
value={code}
language='js'
className='border rounded-sm'
className='border rounded-sm '
readOnly={props.readonly}
placeholder='Please enter JS code.'
onChange={(evn) => _onChange(evn.target.value)}
padding={10}
style={{
backgroundColor: '#f5f5f5',
// backgroundColor: '#f5f5f5',
fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace',
...props.style,
}}
/>
</div>

View File

@@ -1,11 +1,13 @@
import { Button, Input, message, Modal, Table } from 'antd';
import { useEffect, useState } from 'react';
import { Fragment, useEffect, useMemo, useState } from 'react';
import { TextArea } from '../components/TextArea';
import { useContainerStore } from '../store';
import { useShallow } from 'zustand/react/shallow';
import { Form } from 'antd';
import copy from 'copy-to-clipboard';
import { useNavigate } from 'react-router';
import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlined, LeftOutlined } from '@ant-design/icons';
import clsx from 'clsx';
const FormModal = () => {
const [form] = Form.useForm();
const containerStore = useContainerStore(
@@ -22,8 +24,6 @@ const FormModal = () => {
const open = containerStore.showEdit;
if (open) {
form.setFieldsValue(containerStore.formData || {});
} else {
form.resetFields();
}
}, [containerStore.showEdit]);
const onFinish = async (values: any) => {
@@ -59,7 +59,12 @@ const FormModal = () => {
<Input />
</Form.Item>
<Form.Item name='code' label='code'>
<TextArea value={containerStore.formData.code} />
<TextArea
value={containerStore.formData.code}
style={{
height: '200px',
}}
/>
</Form.Item>
<Form.Item label=' ' colon={false}>
<Button type='primary' htmlType='submit'>
@@ -85,111 +90,122 @@ export const ContainerList = () => {
getList: state.getList,
loading: state.loading,
publishData: state.publishData,
updateData: state.updateData,
formData: state.formData,
};
}),
);
const [codeEdit, setCodeEdit] = useState(false);
const [code, setCode] = useState('');
useEffect(() => {
containerStore.getList();
}, []);
const columns = [
{
title: 'ID',
dataIndex: 'id',
render: (text: string) => {
return (
<div
className='w-40 truncate cursor-pointer'
title={text}
onClick={() => {
copy(text);
message.success('copy success');
}}>
{text}
</div>
);
},
},
{
title: 'Title',
dataIndex: 'title',
},
{
title: 'Code',
dataIndex: 'code',
width: '40%',
render: (text: string, record: any) => {
return <TextArea value={text} readonly />;
},
},
{
title: 'Source',
dataIndex: 'source',
},
{
title: 'Operation',
dataIndex: 'operation',
render: (text: string, record: any) => {
return (
<div className='flex gap-2'>
<Button
type='primary'
onClick={() => {
containerStore.setFormData(record);
containerStore.setShowEdit(true);
}}>
Edit
</Button>
<Button
onClick={() => {
navicate('/container/preview/' + record.id);
}}>
Preview
</Button>
<Button
onClick={() => {
containerStore.publishData(record);
}}>
Publish
</Button>
<Button
danger
onClick={() => {
containerStore.deleteData(record.id);
}}>
Delete
</Button>
</div>
);
},
},
];
const onAdd = () => {
containerStore.setFormData({});
containerStore.setShowEdit(true);
};
return (
<div className='w-full h-full flex flex-col'>
<div className='mb-2 w-full p-2 bg-white rounded-lg'>
<Button
className='w-20 '
type='primary'
onClick={() => {
containerStore.setFormData({});
containerStore.setShowEdit(true);
}}>
Add
</Button>
<div className='flex flex-grow overflow-hidden h-full'>
<div className='flex-grow overflow-auto scrollbar bg-gray-100'>
<div className='flex flex-wrap gap-x-10 gap-y-4 rounded pt-10 justify-center'>
{containerStore.list.length > 0 &&
containerStore.list.map((item) => {
return (
<Fragment key={item.id}>
<div
className='flex text-sm gap flex-col w-[400px] max-h-[400px] bg-white p-4 rounded-lg'
key={item.id}
onClick={() => {
setCode(item.code);
containerStore.setFormData(item);
setCodeEdit(true);
}}>
<div className='px-4 cursor-pointer'>
<div
className='font-bold'
onClick={(e) => {
copy(item.code);
e.stopPropagation();
message.success('copy code success');
}}>
{item.title || '-'}
</div>
<div className='font-light'>{item.description ? item.description : '-'}</div>
</div>
<div className='w-full text-xs'>
<TextArea className='max-h-[240px] scrollbar' value={item.code} readonly />
</div>
<div className='flex mt-2 '>
<Button.Group>
<Button onClick={() => containerStore.publishData(item)} icon={<SettingOutlined />}></Button>
<Button
onClick={(e) => {
containerStore.setFormData(item);
containerStore.setShowEdit(true);
setCodeEdit(false);
e.stopPropagation();
}}
icon={<EditOutlined />}></Button>
<Button
onClick={(e) => {
// navicate('/container/preview/' + item.id);
window.open('/container/preview/' + item.id);
e.stopPropagation();
}}
icon={<LinkOutlined />}></Button>
<Button
onClick={(e) => {
containerStore.deleteData(item.id);
e.stopPropagation();
}}
icon={<DeleteOutlined />}></Button>
</Button.Group>
</div>
</div>
</Fragment>
);
})}
{new Array(4).fill(0).map((_, index) => {
return <div key={index} className='w-[400px]'></div>;
})}
{containerStore.list.length == 0 && (
<div className='text-center' key={'no-data'}>
No Data
</div>
)}
</div>
</div>
<div className={clsx('bg-gray-100 border-l border-bg-slate-300 w-[600px] flex-shrink-0', !codeEdit && 'hidden')}>
<div className='bg-white p-2'>
<div className='mt-2 ml-2 flex gap-2'>
<Button
onClick={() => {
setCodeEdit(false);
containerStore.setFormData({});
}}
icon={<LeftOutlined />}></Button>
<Button
onClick={() => {
console.log('save', containerStore.formData);
containerStore.updateData({ ...containerStore.formData, code });
}}
icon={<SaveOutlined />}></Button>
</div>
</div>
<div className='h-[94%] p-2 rounded-2 shadow-sm'>
<TextArea
value={code}
onChange={(value) => {
setCode(value);
}}
className='h-full max-h-full scrollbar'
style={{ overflow: 'auto' }}
/>
</div>
</div>
</div>
<div className='flex-grow overflow-scroll'>
<Table
pagination={false}
scroll={{
y: 600,
}}
loading={containerStore.loading}
dataSource={containerStore.list}
rowKey='id'
columns={columns}
/>
</div>
<div className='h-2'></div>
<FormModal />
</div>
);

View File

@@ -1,17 +1,17 @@
import { Navigate, Route, Routes } from 'react-router-dom';
import { ContainerList } from './edit/List';
import { Main } from './layouts';
import { Preview } from './preview';
import { Preview, PreviewWrapper } from './preview';
export const App = () => {
return (
<Routes>
<Route element={<Main />}>
<Route path='/' element={<Navigate to='/container/edit/list' />}></Route>
<Route path='edit/list' element={<ContainerList />} />
<Route path='preview/:id' element={<Preview />} />
<Route path='preview/:id/wrapper' element={<PreviewWrapper />} />
<Route path='/' element={<div>Home</div>} />
</Route>
<Route path='preview/:id' element={<Preview />} />
</Routes>
);
};

View File

@@ -1,15 +1,41 @@
import { Outlet } from 'react-router';
import { PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { Outlet, useLocation } from 'react-router';
import { useContainerStore } from '../store';
import { useEffect } from 'react';
import { useShallow } from 'zustand/react/shallow';
export const Main = () => {
const containerStore = useContainerStore(
useShallow((state) => {
return {
setFormData: state.setFormData,
setShowEdit: state.setShowEdit,
};
}),
);
const location = useLocation();
const isEdit = location.pathname.includes('edit/list');
return (
<div className='flex w-full h-full flex-col bg-gray-200'>
<div className='h-12 bg-white p-2 mb-2'>Container</div>
<div className='flex w-full h-full flex-col'>
<div className='layout-menu'>
Container
<Button
className={!isEdit ? 'hidden' : ''}
icon={<PlusOutlined />}
onClick={() => {
console.log('add');
containerStore.setFormData({});
containerStore.setShowEdit(true);
}}
/>
</div>
<div
className='flex'
style={{
height: 'calc(100vh - 4rem)',
height: 'calc(100vh - 3rem)',
}}>
<div className='flex-grow overflow-hidden mx-2'>
<div className='flex-grow overflow-hidden'>
<div className='w-full h-full rounded-lg'>
<Outlet />
</div>

View File

@@ -57,6 +57,75 @@ export const Preview = () => {
const containerRef = useRef<Container | null>(null);
const [data, setData] = useState<any>({});
useEffect(() => {
if (!id) return;
fetch();
}, []);
const fetch = async () => {
const res = await query.post({
path: 'container',
key: 'get',
id,
});
if (res.code === 200) {
const data = res.data;
// setData([data]);
console.log('data', data);
const code = {
id: data.id,
title: data.title,
codeId: data.id,
code: data.code,
data: data.data,
};
init([code]);
} else {
message.error(res.msg || 'Failed to fetch data');
}
};
const refresh = (data: any) => {
if (!data.id) return;
const code = {
id: data.id,
title: data.title,
codeId: data.id,
code: data.code,
data: data.data,
hash: '',
};
init([code], true);
};
useListener(id, { refresh: refresh });
const init = async (data: any[], replace: boolean = false) => {
// console.log('data', data, ref.current);
if (containerRef.current) {
const container = containerRef.current;
console.log('data', data, container.data);
container.updateData(data);
await new Promise((resolve) => {
setTimeout(resolve, 2000);
});
console.log('update---data', data, container.data);
container.destroy(id!);
container.renderId(id!);
return;
}
console.log('data', containerRef.current);
const container = new Container({
root: ref.current!,
data: data as any,
showChild: false,
});
container.renderId(id!);
containerRef.current = container;
};
return <div className='mx-auto border bg-gray-200 h-full w-full' ref={ref}></div>;
};
export const PreviewWrapper = () => {
const params = useParams<{ id: string }>();
const id = params.id;
const ref = useRef<HTMLDivElement>(null);
const containerRef = useRef<Container | null>(null);
useEffect(() => {
if (!id) return;
fetch();
@@ -121,13 +190,13 @@ export const Preview = () => {
};
return (
<div className='w-full h-full bg-gray-200'>
<div className='text-center mb-10 font-bold text-4xl mt-4 '>Preview</div>
<div className='text-center mb-4 pt-2 font-bold text-4xl '>Preview</div>
<div
className='flex '
style={{
height: 'calc(100% - 32px)',
}}>
<div className='mx-auto border bg-white h-h-full w-[80%] h-[80%]' ref={ref}></div>
<div className='mx-auto border bg-white h-h-full w-[80%] h-[80%] overflow-y-auto' ref={ref}></div>
</div>
</div>
);

16
src/pages/map/index.tsx Normal file
View File

@@ -0,0 +1,16 @@
export const App = () => {
const serverList = ['container', 'panel', 'publish', 'code-editor', 'map'];
return (
<div className='p-2 w-full h-full bg-gray-200'>
<div className='flex flex-col w-1/2 m-auto bg-white p-4 border rounded-md shadow-md'>
{serverList.map((item) => {
return (
<div key={item} className='flex flex-col'>
<div>{item}</div>
</div>
);
})}
</div>
</div>
);
};

View File

@@ -0,0 +1,57 @@
import { Button, Form, Input } from 'antd';
import { TextArea } from '../container/components/TextArea';
import clsx from 'clsx';
export const App = () => {
const [form] = Form.useForm();
const onFinish = (values: any) => {
console.log('Success:', values);
};
const onSave = () => {
//
};
const isEdit = form.getFieldValue('id');
return (
<div className='w-full h-full felx flex-col bg-gray-200'>
<h1 className='text-center py-4'>Prompt JS Code Generate</h1>
<div className='py-2 px-4 w-3/4 min-w-[600px] mx-auto border shadow rounded bg-white'>
<Form form={form} onFinish={onFinish} className='mt-4' labelCol={{ span: 4 }}>
<Form.Item name='id' hidden>
<Input />
</Form.Item>
<Form.Item name='title' label='Title'>
<Input />
</Form.Item>
<Form.Item name='description' label='Description'>
<Input.TextArea rows={4} />
</Form.Item>
<Form.Item name='code' label='Code'>
<TextArea className='max-h-full' style={{ minHeight: 300 }} />
</Form.Item>
<Form.Item label=' ' colon={false}>
<div className='flex gap-2'>
<Button type='primary' htmlType='submit'>
Generate
</Button>
<Button htmlType='reset'>Reset</Button>
<Button
type='primary'
onClick={() => {
//
}}>
Save
</Button>
<Button
className={clsx(isEdit ? 'block' : 'hidden')}
onClick={() => {
//
}}>
Preview
</Button>
</div>
</Form.Item>
</Form>
</div>
</div>
);
};