feat: common components
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
:local(.seal_custom_popover) {
|
||||
position: relative;
|
||||
padding-top: var(--ant-popover-inner-padding);
|
||||
border-radius: var(--ant-border-radius-lg);
|
||||
background-color: var(--color-white-1);
|
||||
box-shadow: var(--ant-box-shadow-secondary);
|
||||
overflow: hidden;
|
||||
padding-top: 80px;
|
||||
:global(.ant-popover-inner) {
|
||||
box-shadow: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
:global(.ant-popover-content) {
|
||||
position: static;
|
||||
}
|
||||
:global(.ant-popover-title) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding-block: var(--ant-popover-inner-padding)
|
||||
var(--ant-popover-title-margin-bottom);
|
||||
margin-bottom: 0;
|
||||
background: #fff;
|
||||
padding-left: var(--ant-popover-inner-padding);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Popover } from 'antd';
|
||||
import type { PopoverProps } from 'antd/lib/popover';
|
||||
import classNames from 'classnames';
|
||||
import styles from './index.less';
|
||||
|
||||
const SealPopover: React.FC<PopoverProps> = (props) => {
|
||||
const { className, children, style, ...restProps } = props;
|
||||
|
||||
return (
|
||||
<div className="popover-wrapper">
|
||||
<Popover
|
||||
{...restProps}
|
||||
style={{ ...style }}
|
||||
data-maxHeight="300px"
|
||||
overlayClassName={classNames(className, styles.seal_custom_popover)}
|
||||
>
|
||||
{children}
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SealPopover;
|
||||
@@ -0,0 +1,49 @@
|
||||
:local(.wrapper) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 54px;
|
||||
border-width: var(--ant-line-width);
|
||||
border-style: var(--ant-line-type);
|
||||
border-color: var(--ant-color-border);
|
||||
border-radius: 28px;
|
||||
padding-inline: 12px;
|
||||
padding-block: 20px 0;
|
||||
&:hover {
|
||||
border-color: var(--ant-input-hover-border-color);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
&:focus-within {
|
||||
border-color: var(--ant-input-active-border-color);
|
||||
box-shadow: var(--ant-input-active-shadow);
|
||||
outline: 0;
|
||||
background-color: var(--ant-input-active-bg);
|
||||
}
|
||||
.label {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: 1;
|
||||
pointer-events: all;
|
||||
z-index: 5;
|
||||
&.isfoucs-has-value {
|
||||
top: 8px;
|
||||
transition: all 0.2s var(--seal-transition-func);
|
||||
}
|
||||
&.blur-no-value {
|
||||
top: 21px;
|
||||
transition: all 0.2s var(--seal-transition-func);
|
||||
}
|
||||
}
|
||||
:global(.ant-input) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding-block: 5px;
|
||||
padding-inline: 12px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,34 @@
|
||||
import classNames from 'classnames';
|
||||
import wrapperStyle from './wrapper.less';
|
||||
interface WrapperProps {
|
||||
children: React.ReactNode;
|
||||
label: string;
|
||||
isFocus: boolean;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const Wrapper: React.FC<WrapperProps>= ({ children }) => {
|
||||
const Wrapper: React.FC<WrapperProps> = ({
|
||||
children,
|
||||
label,
|
||||
isFocus,
|
||||
onClick
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<div className={wrapperStyle.wrapper} onClick={onClick}>
|
||||
<label
|
||||
onClick={onClick}
|
||||
className={classNames(
|
||||
wrapperStyle['label'],
|
||||
isFocus
|
||||
? wrapperStyle['isfoucs-has-value']
|
||||
: wrapperStyle['blur-no-value']
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Wrapper;
|
||||
export default Wrapper;
|
||||
|
||||
@@ -1,24 +1,72 @@
|
||||
import { Input } from 'antd';
|
||||
import type { InputProps } from 'antd';
|
||||
import { Input } from 'antd';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import Wrapper from './components/wrapper';
|
||||
import { SealFormItemProps } from './types';
|
||||
import { SealFormItemProps } from './types';
|
||||
|
||||
const TextArea: React.FC<InputProps & SealFormItemProps> = (props) => {
|
||||
console.log('textarea=========', 121);
|
||||
return (
|
||||
<Wrapper label="input">
|
||||
<Input.TextArea placeholder='send your message' autoSize={{minRows: 1,maxRows: 6}} size="large" variant='borderless'></Input.TextArea>
|
||||
<Input.TextArea
|
||||
placeholder="send your message"
|
||||
autoSize={{ minRows: 1, maxRows: 6 }}
|
||||
size="large"
|
||||
variant="borderless"
|
||||
></Input.TextArea>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
|
||||
const {label, ...rest} = props;
|
||||
const { label, placeholder, ...rest } = props;
|
||||
const [isFocus, setIsFocus] = useState(false);
|
||||
const inputRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.value) {
|
||||
setIsFocus(true);
|
||||
}
|
||||
}, [props.value]);
|
||||
|
||||
const handleClickWrapper = () => {
|
||||
if (!props.disabled && !isFocus) {
|
||||
inputRef.current?.focus?.();
|
||||
setIsFocus(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e: any) => {
|
||||
props.onChange?.(e);
|
||||
};
|
||||
|
||||
const handleOnFocus = (e: any) => {
|
||||
setIsFocus(true);
|
||||
props.onFocus?.(e);
|
||||
};
|
||||
|
||||
const handleOnBlur = (e: any) => {
|
||||
if (!inputRef.current?.input?.value) {
|
||||
setIsFocus(false);
|
||||
props.onBlur?.(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper label="input">
|
||||
<Input {...rest} placeholder='send your message'></Input>
|
||||
<Wrapper
|
||||
label={label || (placeholder as string)}
|
||||
isFocus={isFocus}
|
||||
onClick={handleClickWrapper}
|
||||
>
|
||||
<Input
|
||||
{...rest}
|
||||
ref={inputRef}
|
||||
onFocus={handleOnFocus}
|
||||
onBlur={handleOnBlur}
|
||||
onChange={(e) => handleChange(e)}
|
||||
></Input>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default {TextArea,Input: SealInput};
|
||||
export default { TextArea, Input: SealInput };
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
export const DEFAULT_NAME = 'Umi Max';
|
||||
|
||||
export const INPUT_WIDTH = {
|
||||
default: 500,
|
||||
large: 600,
|
||||
small: 400
|
||||
};
|
||||
|
||||
+25
-12
@@ -1,4 +1,4 @@
|
||||
html{
|
||||
html {
|
||||
--color-fill-1: rgba(0, 0, 0, 0.04);
|
||||
--color-fill-2: #fff;
|
||||
--color-fill-3: #f3f6fa;
|
||||
@@ -10,23 +10,37 @@ html{
|
||||
--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;
|
||||
|
||||
|
||||
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
||||
// ======== input ============
|
||||
--ant-input-active-shadow: 0 0 0 2px rgba(5, 255, 105, 0.06);
|
||||
--ant-input-active-border-color: #2fbf85;
|
||||
--ant-input-hover-border-color: #54cc98;
|
||||
|
||||
.css-var-rf {
|
||||
--ant-font-size: var(--font-size-base);
|
||||
--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-sm: var(--font-size-base);
|
||||
--ant-font-size-lg: var(--font-size-base);
|
||||
--ant-font-size-xl: 20px;
|
||||
--ant-padding-sm: 14px;
|
||||
|
||||
&.ant-popover {
|
||||
--ant-popover-inner-padding: 26px;
|
||||
--ant-popover-title-margin-bottom: 22px;
|
||||
}
|
||||
|
||||
&.ant-btn {
|
||||
--ant-button-content-font-size-lg: 13px;
|
||||
--ant-button-content-font-size: 13px;
|
||||
--ant-button-content-font-size-sm: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.css-var-rf.ant-menu-css-var {
|
||||
--ant-menu-item-height: 46px;
|
||||
--ant-menu-item-selected-bg: var(--color-white-1);
|
||||
@@ -39,12 +53,12 @@ html{
|
||||
.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);
|
||||
--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 * {
|
||||
font-weight: var(--font-weight-normal);
|
||||
@@ -59,7 +73,6 @@ body * {
|
||||
}
|
||||
.ant-layout {
|
||||
min-height: 100vh;
|
||||
|
||||
}
|
||||
.ant-pro-layout-container {
|
||||
background-color: var(--color-fill-2);
|
||||
@@ -84,4 +97,4 @@ body * {
|
||||
}
|
||||
// ======== menu style end ============
|
||||
|
||||
@import url('src/assets/styles/menu.less');
|
||||
@import url('src/assets/styles/menu.less');
|
||||
|
||||
@@ -1,13 +1,142 @@
|
||||
import { Form } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import { INPUT_WIDTH } from '@/constants';
|
||||
import { Button, Form, Space } from 'antd';
|
||||
|
||||
type ParamsSettingsProps = {
|
||||
seed?: number;
|
||||
stopSequence?: number;
|
||||
temperature?: number;
|
||||
topK?: number;
|
||||
topP?: number;
|
||||
repeatPenalty?: number;
|
||||
repeatLastN?: number;
|
||||
tfsZ?: number;
|
||||
contextLength?: number;
|
||||
maxTokens?: number;
|
||||
};
|
||||
|
||||
const ParamsSettings: React.FC = () => {
|
||||
const [params, setParams] = useState({
|
||||
name: 'jack',
|
||||
age: 18,
|
||||
});
|
||||
const initialValues = {
|
||||
seed: 1,
|
||||
stopSequence: 1,
|
||||
temperature: 1,
|
||||
topK: 1,
|
||||
topP: 1,
|
||||
repeatPenalty: 1,
|
||||
repeatLastN: 1,
|
||||
tfsZ: 1,
|
||||
contextLength: 256,
|
||||
maxTokens: 256
|
||||
};
|
||||
const [form] = Form.useForm();
|
||||
|
||||
return <Form></Form>;
|
||||
const handleOnFinish = (values: any) => {
|
||||
console.log('handleOnFinish', values);
|
||||
};
|
||||
|
||||
const handleOnFinishFailed = (errorInfo: any) => {
|
||||
console.log('handleOnFinishFailed', errorInfo);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="modelparams"
|
||||
form={form}
|
||||
onFinish={handleOnFinish}
|
||||
onFinishFailed={handleOnFinishFailed}
|
||||
>
|
||||
<Form.Item<ParamsSettingsProps> name="seed" rules={[{ required: true }]}>
|
||||
<SealInput.Input
|
||||
label="Seed"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="stopSequence"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Stop Sequence"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="temperature"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Temperature"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps> name="topK" rules={[{ required: true }]}>
|
||||
<SealInput.Input
|
||||
label="TopK"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps> name="topP" rules={[{ required: true }]}>
|
||||
<SealInput.Input
|
||||
label="TopP"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="repeatPenalty"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Repeat Penalty"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="repeatLastN"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Repeat Last N"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps> name="tfsZ" rules={[{ required: true }]}>
|
||||
<SealInput.Input
|
||||
label="TFSZ"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="contextLength"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Context Length"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsProps>
|
||||
name="maxTokens"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label="Max Tokens"
|
||||
style={{ width: INPUT_WIDTH.default }}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item noStyle>
|
||||
<Space
|
||||
size={20}
|
||||
align="end"
|
||||
style={{ width: '100%', display: 'flex', justifyContent: 'end' }}
|
||||
>
|
||||
<Button>Cancel</Button>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ParamsSettings;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealPopover from '@/components/popover';
|
||||
import { ControlOutlined } from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { Button, Popover, Select, Space } from 'antd';
|
||||
import { Button, Select, Space } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ChatContent from './components/chatContent';
|
||||
import MessageInput from './components/messageInput';
|
||||
import ParamsSettings from './components/params-settings';
|
||||
|
||||
const dataList = [
|
||||
{ value: 'llama3:latest', label: 'llama3:latest' },
|
||||
@@ -23,6 +24,7 @@ const Playground: React.FC = () => {
|
||||
|
||||
const getMessageList = () => {
|
||||
// fetch message list from server
|
||||
console.log('getModelList');
|
||||
setMessageList(['1']);
|
||||
};
|
||||
|
||||
@@ -43,13 +45,21 @@ const Playground: React.FC = () => {
|
||||
onChange={handleSelectChange}
|
||||
variant="filled"
|
||||
></Select>
|
||||
<Popover content="ssd" title="Title" trigger="click">
|
||||
<SealPopover
|
||||
content={<ParamsSettings></ParamsSettings>}
|
||||
destroyTooltipOnHide={true}
|
||||
title="Params Settings"
|
||||
trigger="click"
|
||||
arrow={false}
|
||||
overlayInnerStyle={{ maxHeight: '500px', overflow: 'auto' }}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="circle"
|
||||
icon={<ControlOutlined />}
|
||||
></Button>
|
||||
</Popover>
|
||||
</SealPopover>
|
||||
</Space>
|
||||
]}
|
||||
footer={[<MessageInput />]}
|
||||
@@ -57,7 +67,6 @@ const Playground: React.FC = () => {
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<ChatContent messageList={messageList}></ChatContent>
|
||||
</div>
|
||||
<SealInput.Input label="test label"></SealInput.Input>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user