parent
84bed59f21
commit
2b1f5d38e1
@ -1,7 +1,7 @@
|
||||
import { createFromIconfontCN } from '@ant-design/icons';
|
||||
|
||||
const IconFont = createFromIconfontCN({
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_m179wc500g.js'
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_3n3aubqzylv.js'
|
||||
});
|
||||
|
||||
export default IconFont;
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
.short-cuts {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.ant-table-container .ant-table-content table tr > td {
|
||||
height: auto;
|
||||
border-bottom: var(--ant-line-width) var(--ant-line-type)
|
||||
var(--ant-table-border-color);
|
||||
}
|
||||
|
||||
.ant-table-container .ant-table-content table {
|
||||
border-spacing: 0;
|
||||
|
||||
.ant-table-tbody .ant-table-row {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
tr > td:first-child {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
tr > td:last-child {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ant-table-thead > tr > th {
|
||||
background-color: var(--color-fill-sider);
|
||||
height: 36px;
|
||||
padding-block: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-fixed-header {
|
||||
// .ant-table-body {
|
||||
// overflow-y: auto !important;
|
||||
// }
|
||||
.ant-table-thead > tr > th {
|
||||
background-color: var(--color-fill-sider);
|
||||
height: 36px;
|
||||
padding-block: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
import { platformCall } from '@/utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { Input, Table, Tag } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import IconFont from '../icon-font';
|
||||
import './index.less';
|
||||
|
||||
const dataSource = [
|
||||
{
|
||||
scope: 'playground',
|
||||
command: 'New Message',
|
||||
keybindingWin: 'Ctrl + N',
|
||||
keybindingMac: 'N'
|
||||
},
|
||||
{
|
||||
scope: 'models',
|
||||
span: {
|
||||
rowSpan: 3,
|
||||
colSpan: 1
|
||||
},
|
||||
command: 'deploy model from Hugging Face',
|
||||
keybindingWin: 'Ctrl + 1',
|
||||
keybindingMac: '1'
|
||||
},
|
||||
{
|
||||
scope: 'models',
|
||||
command: 'deploy model from Ollama Library',
|
||||
keybindingWin: 'Ctrl + 2',
|
||||
keybindingMac: '2',
|
||||
span: {
|
||||
rowSpan: 0,
|
||||
colSpan: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
scope: 'models',
|
||||
command: '从 Hugging Face 搜索模型',
|
||||
keybindingWin: 'Ctrl + K',
|
||||
keybindingMac: 'K',
|
||||
span: {
|
||||
rowSpan: 0,
|
||||
colSpan: 0
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
||||
const platform = platformCall();
|
||||
|
||||
const [dataList, setDataList] = React.useState<any[]>(dataSource);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Scope',
|
||||
dataIndex: 'scope',
|
||||
key: 'scope',
|
||||
width: 120,
|
||||
onCell: (row: any, index: number) => {
|
||||
if (row.span) {
|
||||
return row.span;
|
||||
}
|
||||
return {
|
||||
rowSpan: 1,
|
||||
colSpan: 1
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Command',
|
||||
dataIndex: 'command',
|
||||
key: 'command'
|
||||
},
|
||||
{
|
||||
title: 'Keybinding',
|
||||
dataIndex: 'keybinding',
|
||||
key: 'keybinding',
|
||||
width: 180,
|
||||
render: (text: string, row: any) => {
|
||||
if (platform.isMac) {
|
||||
return (
|
||||
<Tag>
|
||||
<IconFont type="icon-command"></IconFont> + {row.keybindingMac}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return <Tag>{row.keybindingWin}</Tag>;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const handleInputChange = (e: any) => {
|
||||
const value = e.target.value;
|
||||
const list = _.filter(dataSource, (item: any) => {
|
||||
return (
|
||||
item.command.toLowerCase().includes(value.toLowerCase()) ||
|
||||
item.scope.toLowerCase().includes(value.toLowerCase())
|
||||
);
|
||||
});
|
||||
setDataList(list);
|
||||
};
|
||||
|
||||
const debounceHandleInputChange = _.debounce(handleInputChange, 300);
|
||||
return (
|
||||
<div className="short-cuts">
|
||||
<h3 style={{ marginBottom: 20 }}>GPUStack 快捷方式</h3>
|
||||
<Input
|
||||
allowClear
|
||||
placeholder="Search keybindings"
|
||||
style={{ marginBottom: 16 }}
|
||||
onChange={debounceHandleInputChange}
|
||||
prefix={
|
||||
<>
|
||||
<SearchOutlined
|
||||
style={{
|
||||
fontSize: '16px',
|
||||
color: 'var(--ant-color-text-quaternary)'
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
></Input>
|
||||
<Table
|
||||
rowKey={(record) => record.command}
|
||||
columns={columns}
|
||||
dataSource={dataList}
|
||||
pagination={false}
|
||||
></Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const modalConfig = {
|
||||
icon: null,
|
||||
centered: false,
|
||||
maskClosable: true,
|
||||
footer: null,
|
||||
style: {
|
||||
top: '10%'
|
||||
},
|
||||
width: 660
|
||||
};
|
||||
|
||||
export default React.memo(ShortCuts);
|
||||
@ -0,0 +1,18 @@
|
||||
import { Divider } from 'antd';
|
||||
import React from 'react';
|
||||
import '../style/separator.less';
|
||||
|
||||
const Separator: React.FC = () => {
|
||||
return (
|
||||
<div className="separator">
|
||||
<Divider
|
||||
type="vertical"
|
||||
style={{ height: 'calc(100vh - 89px)', marginInline: '0px' }}
|
||||
></Divider>
|
||||
<span className="shape"></span>
|
||||
{/* <span className="shape-s"></span> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Separator;
|
||||
@ -0,0 +1,28 @@
|
||||
.separator {
|
||||
position: relative;
|
||||
|
||||
.shape {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: -10px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 2px solid var(--ant-color-split);
|
||||
transform: rotate(45deg);
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
background-color: var(--color-white-1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.shape-s {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 16px solid transparent;
|
||||
border-left: 16px solid var(--color-fill-sider);
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue