diff --git a/.prettierrc b/.prettierrc index ea9f5baa..55206551 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,9 @@ { "printWidth": 80, "singleQuote": true, - "trailingComma": "all", + "tabWidth": 2, + "trailingComma": "none", + "htmlWhitespaceSensitivity": "strict", "proseWrap": "never", "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }], "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson","unused-imports"], diff --git a/config/config.ts b/config/config.ts index 28cfda82..ebf665f8 100644 --- a/config/config.ts +++ b/config/config.ts @@ -6,17 +6,20 @@ export default defineConfig({ antd: { style: 'less', configProvider: { + componentSize: 'large', theme:{ 'root-entry-name': 'variable', cssVar: true, hashed: false, - token: { - colorPrimary: '#2fbf85', - motion: true, - } + token: { + colorPrimary: '#2fbf85', + borderRadius:'20px', + motion: true, + }, }, } }, + hash: true, access: {}, model: {}, initialState: {}, diff --git a/config/routes.ts b/config/routes.ts index 2243ff39..8840531d 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -15,6 +15,7 @@ export default [ }, { name: 'Playground', + title: 'Playground', path: '/playground', key: 'playground', icon: 'Comment', diff --git a/src/assets/images/avatar.png b/src/assets/images/avatar.png new file mode 100644 index 00000000..a53d4c02 Binary files /dev/null and b/src/assets/images/avatar.png differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 00000000..22cccba8 Binary files /dev/null and b/src/assets/images/logo.png differ diff --git a/src/assets/menu.less b/src/assets/styles/menu.less similarity index 100% rename from src/assets/menu.less rename to src/assets/styles/menu.less diff --git a/src/components/seal-form/components/wrapper.tsx b/src/components/seal-form/components/wrapper.tsx new file mode 100644 index 00000000..6b88ca78 --- /dev/null +++ b/src/components/seal-form/components/wrapper.tsx @@ -0,0 +1,14 @@ +interface WrapperProps { + children: React.ReactNode; + label: string; +} + +const Wrapper: React.FC= ({ children }) => { + return ( +
+ {children} +
+ ); +} + +export default Wrapper; \ No newline at end of file diff --git a/src/components/seal-form/seal-input.tsx b/src/components/seal-form/seal-input.tsx new file mode 100644 index 00000000..9e8de926 --- /dev/null +++ b/src/components/seal-form/seal-input.tsx @@ -0,0 +1,24 @@ +import { Input } from 'antd'; +import type { InputProps } from 'antd'; +import Wrapper from './components/wrapper'; +import { SealFormItemProps } from './types'; + +const TextArea: React.FC = (props) => { + return ( + + + + ); +} + +const SealInput: React.FC = (props) => { + const {label, ...rest} = props; + return ( + + + + ); +} + + +export default {TextArea,Input: SealInput}; \ No newline at end of file diff --git a/src/components/seal-form/types.ts b/src/components/seal-form/types.ts new file mode 100644 index 00000000..886c92fb --- /dev/null +++ b/src/components/seal-form/types.ts @@ -0,0 +1,3 @@ +export interface SealFormItemProps { + label?: string; +} \ No newline at end of file diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/global.less b/src/global.less index faf6b225..66365653 100644 --- a/src/global.less +++ b/src/global.less @@ -1,14 +1,30 @@ html{ - --color-fill-1: #f3f6fa; + --color-fill-1: rgba(0, 0, 0, 0.04); --color-fill-2: #fff; + --color-fill-3: #f3f6fa; --menu-border-radius-base: 32px; + --border-radius-base: 16px; --color-white-1: #fff; --font-weight-normal: 500; --font-weight-bold: 700; --color-text-1: #1d2129; + --color-bg-light-1: #f0fff6; + --font-size-base: 12px; + --ant-input-active-shadow: 0 0 0 2px rgba(5, 255, 105, 0.06); + --ant-input-active-border-color: #2fbf85; + --ant-color-fill-secondary: rgba(0, 0, 0, 0.06); + // --color-text-1: #000; + .css-var-rf { - --ant-font-size: 12px; + --ant-font-size: var(--font-size-base); + } + .css-var-r0 { + // --ant-control-height: 36px; + --ant-font-size-sm: var(--font-size-base); + --ant-font-size-lg: var(--font-size-base); + --ant-font-size-xl: 20px; + --ant-padding-sm: 14px; } .css-var-rf.ant-menu-css-var { @@ -20,8 +36,17 @@ html{ --ant-menu-item-color: var(--color-text-1); --ant-menu-item-active-bg: var(--color-white-1); } + .css-var-r0.ant-input-css-var { + --ant-input-input-font-size: var(--font-size-base); + --ant-input-input-font-size-lg: var(--font-size-base); + --ant-input-input-font-size-sm:var(--font-size-base); + } + .css-var-r0.ant-select-css-var { + --ant-select-option-active-bg: var(--color-fill-1); + --ant-select-option-font-size: var(--font-size-base); + } } -body { +body * { font-weight: var(--font-weight-normal); } @@ -29,6 +54,7 @@ body { .ant-pro-layout { height: 100vh; .ant-pro-sider-logo { + padding-left: 22px; border-block-end: none; } .ant-layout { @@ -58,4 +84,4 @@ body { } // ======== menu style end ============ -@import url('src/assets/menu.less'); \ No newline at end of file +@import url('src/assets/styles/menu.less'); \ No newline at end of file diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index c9f98b31..6e6a6d0a 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -7,9 +7,7 @@ const Dashboard: React.FC = () => { return ( diff --git a/src/pages/playground/components/chat-style.less b/src/pages/playground/components/chat-style.less new file mode 100644 index 00000000..1b4daa09 --- /dev/null +++ b/src/pages/playground/components/chat-style.less @@ -0,0 +1,68 @@ +.chatEmpty { + display: flex; + justify-content: center; + align-items: center; + margin-top: 200px; + flex-direction: column; + .logo { + height: 60px; + width: 60px; + margin-block: 20px; + img { + width: 100%; + height: 100%; + } + } + .tips { + margin-top: 20px; + } +} + +.chatContent { + width: max(50%, 500px); +} +.chatMessageItem { + margin-bottom: 12px; + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + padding-inline: 44px 16px; + .name { + padding-block: 8px 16px; + } + .content { + padding: 8px 12px; + border-radius: var(--border-radius-base); + background-color: var(--color-fill-3); + font-size: var(--font-size-base); + } + .contentWrap { + position: relative; + padding-right: 45px; + &:hover .edit { + display: block; + } + .edit { + display: none; + position: absolute; + top: -10px; + right: 0; + padding: 8px; + } + } + .img { + position: absolute; + top: 0; + left: 0; + width: 32px; + height: 32px; + border-radius: 50%; + img { + width: 100%; + height: 100%; + border-radius: 50%; + } + } +} diff --git a/src/pages/playground/components/chatContent.tsx b/src/pages/playground/components/chatContent.tsx new file mode 100644 index 00000000..4e05f1c2 --- /dev/null +++ b/src/pages/playground/components/chatContent.tsx @@ -0,0 +1,61 @@ +import { Button,Space,Tooltip} from "antd"; +import { EditOutlined, CopyOutlined,DislikeOutlined,SyncOutlined} from '@ant-design/icons'; +import ChatEmpty from "./chatEmpty"; +import chatStyle from './chat-style.less' +import avatar from '@/assets/images/avatar.png' +import logo from '@/assets/images/logo.png' + +export type ChatContentProps = { + messageList: any[]; +} + +const QuestionMessage:React.FC<{content: string;}> = ({content}) => { + return ( +
+ + + + + YOU +
+ +

{content}

+
+
+ ) +} + +const AnswerMessage:React.FC<{content: string;}> = ({content}) => { + return ( +
+ + + + AI +

{content}

+ + + + + + + + + + + +
+ ) +} + +const ChatContent:React.FC = ({ messageList }) => { + if (messageList.length === 0) { + return + } + return (
+ + +
) +} + +export default ChatContent; \ No newline at end of file diff --git a/src/pages/playground/components/chatEmpty.tsx b/src/pages/playground/components/chatEmpty.tsx new file mode 100644 index 00000000..ed977dfc --- /dev/null +++ b/src/pages/playground/components/chatEmpty.tsx @@ -0,0 +1,15 @@ +import Logo from '@/assets/images/logo.png'; +import chatStyle from './chat-style.less' + +const ChatEmpty:React.FC = () => { + return ( +
+
+ chat empty +
+

How can I help you today?

+
+ ); +} + +export default ChatEmpty; \ No newline at end of file diff --git a/src/pages/playground/components/message-input.less b/src/pages/playground/components/message-input.less new file mode 100644 index 00000000..77c32034 --- /dev/null +++ b/src/pages/playground/components/message-input.less @@ -0,0 +1,63 @@ +.ant-pro-footer-bar { + padding-block: 20px; + padding-bottom: 30px; + border:none; + .ant-pro-footer-bar-right { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + } +} +.messageInput{ + position:relative; + display: flex; + align-items: center; + justify-content: center; + width: max(50%, 500px); + background-color: var(--color-fill-1); + border-radius: 30px; + padding-right: 50px; + border: 1px solid transparent; + transition: all 0.2s ease; + &:focus-within { + border-color: var(--ant-input-active-border-color); + box-shadow: var(--ant-input-active-shadow); + background-color: var(--color-white-1); + transition: all 0.2s ease; + &:hover { + background-color: var(--color-white-1); + } + } + + &:hover { + background: var(--ant-color-fill-secondary); + transition: background 0.2s ease; + } + textarea { + padding: 16px; + border-radius: 30px; + background-color:transparent; + } + textarea::-webkit-scrollbar { + width: 8px; +} + +textarea::-webkit-scrollbar-track { + background-color: #f1f1f1; +} + +textarea::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + border-radius: 6px; +} + .send-btn { + position: absolute; + right: 10px; + bottom: 11px; + display: flex; + justify-content: center; + align-items: center; + transform: rotate(-30deg); + } +} \ No newline at end of file diff --git a/src/pages/playground/components/messageInput.tsx b/src/pages/playground/components/messageInput.tsx new file mode 100644 index 00000000..e50d1515 --- /dev/null +++ b/src/pages/playground/components/messageInput.tsx @@ -0,0 +1,26 @@ +import { Input,Button} from 'antd'; +import { useState } from 'react'; +import { SendOutlined } from '@ant-design/icons'; +import './message-input.less' + +const MessageInput: React.FC = () => { + const { TextArea } = Input; + const [message, setMessage] = useState('') + const handleInputChange = (value:string) => { + setMessage(value) + } + const handleSendMessage = () => { + console.log('send message:', message) + } + const SendButton: React.FC = () => { + return + } + return ( +
+ + +
+ ); +}; + +export default MessageInput; \ No newline at end of file diff --git a/src/pages/playground/components/params-settings.tsx b/src/pages/playground/components/params-settings.tsx new file mode 100644 index 00000000..b6a6036a --- /dev/null +++ b/src/pages/playground/components/params-settings.tsx @@ -0,0 +1,13 @@ +import { Form } from "antd"; +import { useState } from "react"; + +const ParamsSettings:React.FC = () => { + const [params, setParams] = useState({ + name: 'jack', + age: 18 + }); + + return (
) +}; + +export default ParamsSettings; \ No newline at end of file diff --git a/src/pages/playground/index.tsx b/src/pages/playground/index.tsx index 3cc675f8..4e54554b 100644 --- a/src/pages/playground/index.tsx +++ b/src/pages/playground/index.tsx @@ -1,16 +1,59 @@ +import { useState,useEffect} from 'react'; +import { Button, Select,Space,Input,Popover } from 'antd'; +import { ControlOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; +import SealInput from '@/components/seal-form/seal-input'; +import MessageInput from './components/messageInput'; +import ChatContent from './components/chatContent'; + +const dataList = [ + {value: 'llama3:latest', label: 'llama3:latest'}, + {value: 'wangfuyun/AnimateLCM', label: 'wangfuyun/AnimateLCM'}, + {value: 'Revanthraja/Text_to_Vision', label: 'Revanthraja/Text_to_Vision'}, +] +const Playground: React.FC = () => { + const [ModelList, setModelList] = useState(dataList) + const [messageList, setMessageList] = useState([]) + const [selectedModel, setSelectedModel] = useState('llama3:latest') + + const handleSelectChange = (value: string) => { + setSelectedModel(value) + } + + const getMessageList = () => { + // fetch message list from server + setMessageList(['1']) + } + + useEffect(() => { + getMessageList() + }, [selectedModel]) -const Dashboard: React.FC = () => { return ( -
Playground
+ + title={false} + extra={[ + + + + + + + + ]} + footer={[ + + ]} + > + +
+ +
+
); }; -export default Dashboard; \ No newline at end of file +export default Playground; \ No newline at end of file