diff --git a/package.json b/package.json index 004b134..ad2ab8e 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "clsx": "^2.1.1", "copy-to-clipboard": "^3.3.3", "d3": "^7.9.0", + "eventemitter3": "^5.0.1", "immer": "^10.1.1", "lodash-es": "^4.17.21", "marked": "^14.1.2", @@ -42,8 +43,10 @@ "devDependencies": { "@eslint/js": "^9.11.0", "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/line-clamp": "^0.4.4", "@tailwindcss/typography": "^0.5.15", "@types/d3": "^7.4.3", + "@types/lodash-es": "^4.17.12", "@types/node": "^22.5.5", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", @@ -53,6 +56,7 @@ "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", "globals": "^15.9.0", + "postcss-import": "^16.1.0", "react-is": "^18.3.1", "tailwind-merge": "^2.5.2", "tailwindcss": "^3.4.13", diff --git a/plugins/flex.js b/plugins/flex.js new file mode 100644 index 0000000..ad53cd5 --- /dev/null +++ b/plugins/flex.js @@ -0,0 +1,25 @@ +const plugin = require('tailwindcss/plugin'); + +const flexCenterBaseStyles = { + display: 'flex', + 'justify-content': 'center', + 'align-items': 'center', +}; + +/** flex 居中 */ +const flexCenter = plugin(function ({ addUtilities }) { + addUtilities({ + /** flex 居中 */ + '.flex-row-center': flexCenterBaseStyles, + '.flex-col-center': { ...flexCenterBaseStyles, 'flex-direction': 'column' }, + '.layout-menu': {}, + '.scrollbar': {}, + '.card': {}, + '.card-title': {}, + '.card-subtitle': {}, + '.card-body': {}, + '.card-footer': {}, + }); +}); + +module.exports = flexCenter; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ebd977f..3928fbc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: d3: specifier: ^7.9.0 version: 7.9.0 + eventemitter3: + specifier: ^5.0.1 + version: 5.0.1 immer: specifier: ^10.1.1 version: 10.1.1 @@ -93,12 +96,18 @@ importers: '@tailwindcss/aspect-ratio': specifier: ^0.4.2 version: 0.4.2(tailwindcss@3.4.13) + '@tailwindcss/line-clamp': + specifier: ^0.4.4 + version: 0.4.4(tailwindcss@3.4.13) '@tailwindcss/typography': specifier: ^0.5.15 version: 0.5.15(tailwindcss@3.4.13) '@types/d3': specifier: ^7.4.3 version: 7.4.3 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 '@types/node': specifier: ^22.5.5 version: 22.5.5 @@ -126,6 +135,9 @@ importers: globals: specifier: ^15.9.0 version: 15.9.0 + postcss-import: + specifier: ^16.1.0 + version: 16.1.0(postcss@8.4.47) react-is: specifier: ^18.3.1 version: 18.3.1 @@ -733,6 +745,11 @@ packages: peerDependencies: tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' + '@tailwindcss/line-clamp@0.4.4': + resolution: {integrity: sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==} + peerDependencies: + tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' + '@tailwindcss/typography@0.5.15': resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==} peerDependencies: @@ -855,6 +872,12 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.9': + resolution: {integrity: sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -1861,6 +1884,12 @@ packages: peerDependencies: postcss: ^8.0.0 + postcss-import@16.1.0: + resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==} + engines: {node: '>=18.0.0'} + peerDependencies: + postcss: ^8.0.0 + postcss-js@4.0.1: resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} engines: {node: ^12 || ^14 || >= 16} @@ -3142,6 +3171,10 @@ snapshots: dependencies: tailwindcss: 3.4.13 + '@tailwindcss/line-clamp@0.4.4(tailwindcss@3.4.13)': + dependencies: + tailwindcss: 3.4.13 + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.13)': dependencies: lodash.castarray: 4.4.0 @@ -3300,6 +3333,12 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.9 + + '@types/lodash@4.17.9': {} + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -4428,6 +4467,13 @@ snapshots: read-cache: 1.0.0 resolve: 1.22.8 + postcss-import@16.1.0(postcss@8.4.47): + dependencies: + postcss: 8.4.47 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + postcss-js@4.0.1(postcss@8.4.47): dependencies: camelcase-css: 2.0.1 diff --git a/src/App.tsx b/src/App.tsx index 76b6cc0..1e929a3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; -import { ConfigProvider } from 'antd'; +import { ConfigProvider, App as AntApp } from 'antd'; import { App as ContainerApp } from './pages/container'; import { App as PanelApp } from './pages/panel'; import { App as PublishApp } from './pages/publish'; diff --git a/src/components/card/CardBlank.tsx b/src/components/card/CardBlank.tsx new file mode 100644 index 0000000..332cf2e --- /dev/null +++ b/src/components/card/CardBlank.tsx @@ -0,0 +1,17 @@ +import clsx from 'clsx'; +import twMerge from 'tailwind-merge'; + +type CardBlankProps = { + number?: number; + className?: string; +}; +export const CardBlank = (props: CardBlankProps) => { + const { number = 4, className } = props; + return ( + <> + {new Array(number).fill(0).map((_, index) => { + return
; + })} + + ); +}; diff --git a/src/globals.css b/src/globals.css index 1ad8d9b..51fd0b6 100644 --- a/src/globals.css +++ b/src/globals.css @@ -3,6 +3,13 @@ @tailwind utilities; @layer base { + html, + body { + width: 100%; + height: 100%; + font-size: 16px; + font-family: 'Montserrat', sans-serif; + } h1 { @apply text-2xl font-bold; } @@ -12,7 +19,40 @@ h3 { @apply text-lg font-bold; } +} + +@layer components { + .btn { + @apply bg-blue-500 text-white font-bold py-2 px-4 rounded; + } + .card { + @apply bg-white shadow-md rounded-lg p-4; + .card-title { + @apply text-lg font-bold; + } + .card-subtitle { + @apply text-sm text-gray-500; + } + .card-description { + @apply text-gray-700 break-words; + } + .card-code { + @apply bg-gray-100 p-2; + } + .card-body { + @apply text-gray-700; + } + .card-footer { + @apply text-sm text-gray-500; + } + } +} + +@layer utilities { .layout-menu { @apply bg-gray-900 p-2 text-white flex justify-between h-12; } + .bg-custom-blue { + background-color: #3490dc; + } } diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..f545587 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1 @@ +export * from './message'; diff --git a/src/hooks/message.tsx b/src/hooks/message.tsx new file mode 100644 index 0000000..57af24a --- /dev/null +++ b/src/hooks/message.tsx @@ -0,0 +1,22 @@ +import { App } from 'antd'; + +export const useMessage = () => { + const { message: antMessage, modal, notification } = App.useApp(); + return { + success: antMessage.success, + error: antMessage.error, + warning: antMessage.warning, + info: antMessage.info, + loading: antMessage.loading, + open: antMessage.open, + destroy: antMessage.destroy, + modal: modal, + notification: notification, + message: antMessage, + com: ( + <> + + + ), + }; +}; diff --git a/src/pages/ai-chat/AiModule.tsx b/src/pages/ai-chat/AiModule.tsx index 3e3854c..3026ced 100644 --- a/src/pages/ai-chat/AiModule.tsx +++ b/src/pages/ai-chat/AiModule.tsx @@ -1,36 +1,110 @@ import { useShallow } from 'zustand/react/shallow'; import { useAiStore } from './store/ai-store'; import { CloseOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; +import { Button, Form, Input } from 'antd'; +import { useEffect } from 'react'; +import { TextArea } from '../container/components/TextArea'; +import clsx from 'clsx'; +import { marked } from 'marked'; export const AiMoudle = () => { + const [form] = Form.useForm(); const aiStore = useAiStore( useShallow((state) => { return { open: state.open, setOpen: state.setOpen, runAi: state.runAi, + formData: state.formData, + setFormData: state.setFormData, + messages: state.messages, + setMessages: state.setMessage, }; }), ); - if (!aiStore.open) { - return null; - } + + useEffect(() => { + if (!aiStore.open) { + return; + } + const isNull = JSON.stringify(aiStore.formData) === '{}'; + if (!isNull) { + form.setFieldsValue(aiStore.formData); + } else { + form.setFieldsValue({ inputs: [] }); + } + }, [aiStore.open, aiStore.formData]); + useEffect(() => { + if (!aiStore.open) { + aiStore.setMessages([]); + } + }, [aiStore.open]); + const onSend = () => { + const data = form.getFieldsValue(); + aiStore.setFormData(data); + aiStore.runAi(); + }; return ( -
+

Ai Moudle

-
-
chat message
-
- +
+
+
chat message
+ {aiStore?.messages?.map((message, index) => { + const html = marked.parse(message?.content); + return ( +
+
{message?.role}
+
+
+
+ ); + })} +
+
+
+ + + + + {(fields, { add, remove }) => { + return ( + <> + {fields.map((field, index) => { + const key = form.getFieldValue(['inputs', index, 'key']); + console.log('key', key); + const isTitle = key === 'title'; + + return ( +
+ + +