improved designable styling

This commit is contained in:
chenos 2021-08-17 14:40:38 +08:00
parent da418720aa
commit 2ba5e6f76f
13 changed files with 967 additions and 842 deletions

View File

@ -349,7 +349,6 @@ const schema: ISchema = {
'x-component-props': { 'x-component-props': {
className: 'nb-table-operation', className: 'nb-table-operation',
}, },
'x-designable-bar': 'Table.Operation.DesignableBar',
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',

View File

@ -1,5 +1,5 @@
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { Button, Dropdown, Menu } from 'antd'; import { Button, Dropdown, Menu, Spin } from 'antd';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { request } from '../../schemas'; import { request } from '../../schemas';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
@ -25,7 +25,7 @@ export function SystemSettingsProvider(props) {
); );
return ( return (
<SystemSettingsContext.Provider value={{ service, resource }}> <SystemSettingsContext.Provider value={{ service, resource }}>
{props.children} {service.loading ? <Spin /> : props.children}
</SystemSettingsContext.Provider> </SystemSettingsContext.Provider>
); );
} }

View File

@ -89,7 +89,7 @@ function LayoutWithMenu(props: LayoutWithMenuProps) {
}; };
return ( return (
<Layout> <Layout>
<Layout.Header style={{ display: 'flex' }}> <Layout.Header className={'site-header'} style={{ display: 'flex' }}>
<SiteTitle /> <SiteTitle />
<SchemaRenderer <SchemaRenderer
schema={schema} schema={schema}

View File

@ -50,8 +50,9 @@
.nb-designable-toggle { .nb-designable-toggle {
background: none !important; background: none !important;
border-radius: 0 !important;
&.active { &.active {
background: #1890ff !important; // background: #faad14 !important;
} }
} }
@ -76,3 +77,23 @@
padding-right: 8px; padding-right: 8px;
} }
} }
.site-header {
.ant-menu.ant-menu-dark .ant-menu-item-selected, .ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected {
background-color: rgba(255, 255, 255, 0.1);
}
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.ant-btn {
color: rgba(255, 255, 255, 0.65) !important;
&.nb-designable-toggle:hover {
color: #fff !important;
background-color: #F18B62 !important
}
}
.ant-btn:hover {
color: #fff !important;
background-color: rgba(255, 255, 255, 0.1) !important;
}
}

View File

@ -214,7 +214,7 @@ function AddActionButton() {
</Menu> </Menu>
} }
> >
<Button style={{ marginLeft: 8 }} type={'dashed'} icon={<PlusOutlined />}> <Button className={'designable-btn designable-btn-dash'} style={{ marginLeft: 8 }} type={'dashed'} icon={<PlusOutlined />}>
</Button> </Button>
</Dropdown> </Dropdown>

View File

@ -339,6 +339,7 @@ Action.DesignableBar = (props: any) => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space size={2}>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -405,8 +406,12 @@ Action.DesignableBar = (props: any) => {
updateSchema(s); updateSchema(s);
}} }}
> >
<Select.Option value={'Action.Modal'}></Select.Option> <Select.Option value={'Action.Modal'}>
<Select.Option value={'Action.Drawer'}></Select.Option>
</Select.Option>
<Select.Option value={'Action.Drawer'}>
</Select.Option>
<Select.Option value={'Action.Window'}> <Select.Option value={'Action.Window'}>
</Select.Option> </Select.Option>
@ -434,6 +439,7 @@ Action.DesignableBar = (props: any) => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</Space>
</span> </span>
</div> </div>
); );

View File

@ -935,7 +935,7 @@ AddNew.CardItem = observer((props: any) => {
{ghost ? ( {ghost ? (
<PlusOutlined /> <PlusOutlined />
) : ( ) : (
<Button type={'dashed'} icon={<PlusOutlined />}> <Button type={'dashed'} className={'designable-btn designable-btn-dash'} icon={<PlusOutlined />}>
</Button> </Button>
)} )}
@ -1122,7 +1122,7 @@ AddNew.FormItem = observer((props: any) => {
{ghost ? ( {ghost ? (
<PlusOutlined /> <PlusOutlined />
) : ( ) : (
<Button type={'dashed'} icon={<SettingOutlined />}> <Button type={'dashed'} className={'designable-btn designable-btn-dash'} icon={<SettingOutlined />}>
</Button> </Button>
)} )}
@ -1326,7 +1326,7 @@ AddNew.PaneItem = observer((props: any) => {
{ghost ? ( {ghost ? (
<PlusOutlined /> <PlusOutlined />
) : ( ) : (
<Button block type={'dashed'} icon={<PlusOutlined />}> <Button block className={'designable-btn designable-btn-dash'} type={'dashed'} icon={<PlusOutlined />}>
</Button> </Button>
)} )}

View File

@ -27,9 +27,6 @@
color: #fff; color: #fff;
z-index: 10; z-index: 10;
padding: 0 3px; padding: 0 3px;
.ant-space {
gap: 1px !important;
}
.anticon { .anticon {
width: 16px; width: 16px;
height: 16px; height: 16px;

View File

@ -1,8 +1,71 @@
@bgcolor: #F18B62;
.designable-info { .designable-info {
position: absolute; position: absolute;
font-size: 12px; font-size: 12px;
background: #1890ff; background: @bgcolor;
color: #fff; color: #fff;
padding: 0 5px; padding: 0 5px;
line-height: 16px;
height: 16px;
border-bottom-right-radius: 2px; border-bottom-right-radius: 2px;
} }
.designable-bar {
border-radius: 1px !important;
border: 2px solid @bgcolor !important;
.designable-bar-actions {
padding: 0 !important;
background: none !important;
display: flex !important;
right: 2px !important;
// .ant-space-item {
// margin: 0 !important;
// }
.ant-space {
gap: 2px !important;
}
.anticon {
width: 16px !important;
height: 16px !important;
vertical-align: top;
line-height: 16px !important;
// font-size: 10px;
// display: inline-flex;
background-color: @bgcolor !important;
border-bottom-left-radius: 1px;
border-bottom-right-radius: 1px;
// margin-left: 0 !important;
// margin-right: 2px !important;
}
}
}
.designable-btn-dash {
border-color: @bgcolor !important;
color: @bgcolor !important;
}
.nb-add-new-menu-item.menu-mode-horizontal.designable {
color: @bgcolor !important;
border: 1px dashed !important;
height: 32px !important;
// &:hover {
// color: #fff !important;
// background: @bgcolor !important;
// }
// &:active {
// color: #fff !important;
// background: @bgcolor !important;
// }
}
.ant-menu-item-group.nb-menu-add-new {
.menu-mode-horizontal {
margin-left: 8px;
}
}
.nb-designable-toggle.active {
background: @bgcolor !important;
}

View File

@ -62,7 +62,7 @@ export const FieldDesignableBar = observer((props) => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space size={'small'}> <Space size={2}>
<AddNew.FormItem defaultAction={'insertAfter'} ghost /> <AddNew.FormItem defaultAction={'insertAfter'} ghost />
{dragRef && <DragOutlined ref={dragRef} />} {dragRef && <DragOutlined ref={dragRef} />}
<Dropdown <Dropdown

View File

@ -29,6 +29,7 @@ import {
Dropdown, Dropdown,
Modal, Modal,
Button, Button,
Space,
} from 'antd'; } from 'antd';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import cls from 'classnames'; import cls from 'classnames';
@ -97,7 +98,7 @@ const SideMenu = (props: any) => {
<Button <Button
block block
type={'dashed'} type={'dashed'}
className={`nb-add-new-menu-item menu-mode-inline`} className={`nb-add-new-menu-item menu-mode-inline designable-btn designable-btn-dash`}
> >
<PlusOutlined /> <PlusOutlined />
</Button> </Button>
@ -207,7 +208,7 @@ export const Menu: any = observer((props: any) => {
<Menu.AddNew key={uid()} path={path}> <Menu.AddNew key={uid()} path={path}>
{/* <PlusOutlined className={'nb-add-new-icon'} /> */} {/* <PlusOutlined className={'nb-add-new-icon'} /> */}
<Button <Button
className={`nb-add-new-menu-item menu-mode-${ className={`designable-btn designable-btn-dash nb-add-new-menu-item designable menu-mode-${
mode === 'mix' ? 'horizontal' : mode mode === 'mix' ? 'horizontal' : mode
}`} }`}
block block
@ -660,6 +661,7 @@ Menu.DesignableBar = (props) => {
}} }}
className={'designable-bar-actions'} className={'designable-bar-actions'}
> >
<Space size={2}>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
overlayStyle={{ overlayStyle={{
@ -708,9 +710,11 @@ Menu.DesignableBar = (props) => {
key={'update'} key={'update'}
onClick={async () => { onClick={async () => {
const initialValues = {}; const initialValues = {};
Object.keys(formConfig.schema.properties).forEach((name) => { Object.keys(formConfig.schema.properties).forEach(
(name) => {
_.set(initialValues, name, get(schema, name)); _.set(initialValues, name, get(schema, name));
}); },
);
const values = await FormDialog( const values = await FormDialog(
`修改${formConfig.title}`, `修改${formConfig.title}`,
() => { () => {
@ -726,7 +730,8 @@ Menu.DesignableBar = (props) => {
if (values.title) { if (values.title) {
schema.title = values.title; schema.title = values.title;
} }
const icon = _.get(values, 'x-component-props.icon') || null; const icon =
_.get(values, 'x-component-props.icon') || null;
schema['x-component-props'] = schema['x-component-props'] =
schema['x-component-props'] || {}; schema['x-component-props'] || {};
schema['x-component-props']['icon'] = icon; schema['x-component-props']['icon'] = icon;
@ -757,7 +762,9 @@ Menu.DesignableBar = (props) => {
Object.keys(s.properties || {}).forEach((name) => { Object.keys(s.properties || {}).forEach((name) => {
const current = s.properties[name]; const current = s.properties[name];
if ( if (
!(current['x-component'] as string).startsWith('Menu.') !(current['x-component'] as string).startsWith(
'Menu.',
)
) { ) {
return; return;
} }
@ -1004,6 +1011,7 @@ Menu.DesignableBar = (props) => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</Space>
</div> </div>
</div> </div>
); );

View File

@ -510,7 +510,11 @@ function AddColumn() {
</Menu> </Menu>
} }
> >
<Button type={'dashed'} icon={<SettingOutlined />}> <Button
type={'dashed'}
className={'designable-btn designable-btn-dash'}
icon={<SettingOutlined />}
>
</Button> </Button>
</Dropdown> </Dropdown>
@ -1089,7 +1093,12 @@ function AddActionButton() {
</Menu> </Menu>
} }
> >
<Button style={{ marginLeft: 8 }} type={'dashed'} icon={<PlusOutlined />}> <Button
className={'designable-btn designable-btn-dash'}
style={{ marginLeft: 8 }}
type={'dashed'}
icon={<PlusOutlined />}
>
</Button> </Button>
</Dropdown> </Dropdown>
@ -1350,6 +1359,7 @@ Table.Filter.DesignableBar = () => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -1366,6 +1376,129 @@ Table.Filter.DesignableBar = () => {
return option.operations?.length; return option.operations?.length;
}) })
.map((collectionField) => ( .map((collectionField) => (
<SwitchMenuItem
title={collectionField?.uiSchema?.title}
checked={fieldNames.includes(collectionField.name)}
onChange={async (checked) => {
if (checked) {
fieldNames.push(collectionField.name);
} else {
const index = fieldNames.indexOf(
collectionField.name,
);
if (index > -1) {
fieldNames.splice(index, 1);
}
}
console.log({ fieldNames, field });
schema['x-component-props']['fieldNames'] =
fieldNames;
field.componentProps.fieldNames = fieldNames;
updateSchema(schema);
}}
/>
))}
</Menu.ItemGroup>
<Menu.Divider />
<Menu.Item
onClick={async (e) => {
const values = await FormDialog('修改名称和图标', () => {
return (
<FormLayout layout={'vertical'}>
<SchemaField
schema={{
type: 'object',
properties: {
title: {
type: 'string',
title: '按钮名称',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
icon: {
type: 'string',
title: '按钮图标',
'x-decorator': 'FormItem',
'x-component': 'IconPicker',
},
},
}}
/>
</FormLayout>
);
}).open({
initialValues: {
title: schema['title'],
icon: schema['x-component-props']?.['icon'],
},
});
schema['title'] = values.title;
schema['x-component-props']['icon'] = values.icon;
field.componentProps.icon = values.icon;
field.title = values.title;
updateSchema(schema);
refresh();
}}
>
</Menu.Item>
<Menu.Divider />
<Menu.Item
onClick={async () => {
const displayName =
schema?.['x-decorator-props']?.['displayName'];
const data = remove();
await removeSchema(data);
if (displayName) {
displayed.remove(displayName);
}
setVisible(false);
}}
>
</Menu.Item>
</Menu>
}
>
<MenuOutlined />
</Dropdown>
</Space>
</span>
</div>
);
};
Table.ExportActionDesignableBar = () => {
const { schema, remove, refresh, insertAfter } = useDesignable();
const [visible, setVisible] = useState(false);
const displayed = useDisplayedMapContext();
const { fields } = useCollectionContext();
const field = useField();
let fieldNames = field.componentProps.fieldNames || [];
if (fieldNames.length === 0) {
fieldNames = fields.map((field) => field.name);
}
return (
<div className={cls('designable-bar', { active: visible })}>
<span
onClick={(e) => {
e.stopPropagation();
}}
className={cls('designable-bar-actions', { active: visible })}
>
<Space>
<DragHandle />
<Dropdown
trigger={['click']}
visible={visible}
onVisibleChange={(visible) => {
setVisible(visible);
}}
overlay={
<Menu>
<Menu.ItemGroup title={'导出字段'}>
{fields.map((collectionField) => (
<SwitchMenuItem <SwitchMenuItem
title={collectionField?.uiSchema?.title} title={collectionField?.uiSchema?.title}
checked={fieldNames.includes(collectionField.name)} checked={fieldNames.includes(collectionField.name)}
@ -1452,124 +1585,7 @@ Table.Filter.DesignableBar = () => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</span> </Space>
</div>
);
};
Table.ExportActionDesignableBar = () => {
const { schema, remove, refresh, insertAfter } = useDesignable();
const [visible, setVisible] = useState(false);
const displayed = useDisplayedMapContext();
const { fields } = useCollectionContext();
const field = useField();
let fieldNames = field.componentProps.fieldNames || [];
if (fieldNames.length === 0) {
fieldNames = fields.map((field) => field.name);
}
return (
<div className={cls('designable-bar', { active: visible })}>
<span
onClick={(e) => {
e.stopPropagation();
}}
className={cls('designable-bar-actions', { active: visible })}
>
<DragHandle />
<Dropdown
trigger={['click']}
visible={visible}
onVisibleChange={(visible) => {
setVisible(visible);
}}
overlay={
<Menu>
<Menu.ItemGroup title={'导出字段'}>
{fields.map((collectionField) => (
<SwitchMenuItem
title={collectionField?.uiSchema?.title}
checked={fieldNames.includes(collectionField.name)}
onChange={async (checked) => {
if (checked) {
fieldNames.push(collectionField.name);
} else {
const index = fieldNames.indexOf(collectionField.name);
if (index > -1) {
fieldNames.splice(index, 1);
}
}
console.log({ fieldNames, field });
schema['x-component-props']['fieldNames'] = fieldNames;
field.componentProps.fieldNames = fieldNames;
updateSchema(schema);
}}
/>
))}
</Menu.ItemGroup>
<Menu.Divider />
<Menu.Item
onClick={async (e) => {
const values = await FormDialog('修改名称和图标', () => {
return (
<FormLayout layout={'vertical'}>
<SchemaField
schema={{
type: 'object',
properties: {
title: {
type: 'string',
title: '按钮名称',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
icon: {
type: 'string',
title: '按钮图标',
'x-decorator': 'FormItem',
'x-component': 'IconPicker',
},
},
}}
/>
</FormLayout>
);
}).open({
initialValues: {
title: schema['title'],
icon: schema['x-component-props']?.['icon'],
},
});
schema['title'] = values.title;
schema['x-component-props']['icon'] = values.icon;
field.componentProps.icon = values.icon;
field.title = values.title;
updateSchema(schema);
refresh();
}}
>
</Menu.Item>
<Menu.Divider />
<Menu.Item
onClick={async () => {
const displayName =
schema?.['x-decorator-props']?.['displayName'];
const data = remove();
await removeSchema(data);
if (displayName) {
displayed.remove(displayName);
}
setVisible(false);
}}
>
</Menu.Item>
</Menu>
}
>
<MenuOutlined />
</Dropdown>
</span> </span>
</div> </div>
); );
@ -1580,9 +1596,7 @@ Table.Operation = observer((props: any) => {
return ( return (
<div className={'nb-table-column'}> <div className={'nb-table-column'}>
{designable && schema['x-designable-bar'] && (
<Table.Operation.DesignableBar path={props.path} /> <Table.Operation.DesignableBar path={props.path} />
)}
</div> </div>
); );
}); });
@ -1600,9 +1614,10 @@ Table.Operation.Cell = observer((props: any) => {
Table.Operation.DesignableBar = (props) => { Table.Operation.DesignableBar = (props) => {
const { schema, remove, refresh, appendChild } = useDesignable(props.path); const { schema, remove, refresh, appendChild } = useDesignable(props.path);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
if (!schema['x-designable-bar']) { if (!schema?.parent?.parent['x-designable-bar']) {
return null; return null;
} }
console.log('Table.Operation.DesignableBar', schema?.parent?.parent);
const map = new Map(); const map = new Map();
schema.mapProperties((s) => { schema.mapProperties((s) => {
if (!s['x-action-type']) { if (!s['x-action-type']) {
@ -1618,6 +1633,7 @@ Table.Operation.DesignableBar = (props) => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -1664,6 +1680,7 @@ Table.Operation.DesignableBar = (props) => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</Space>
</span> </span>
</div> </div>
); );
@ -1686,6 +1703,7 @@ Table.Action.DesignableBar = () => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -1754,8 +1772,12 @@ Table.Action.DesignableBar = () => {
// console.log('fffffff', { schema, f }); // console.log('fffffff', { schema, f });
}} }}
> >
<Select.Option value={'Action.Modal'}></Select.Option> <Select.Option value={'Action.Modal'}>
<Select.Option value={'Action.Drawer'}></Select.Option>
</Select.Option>
<Select.Option value={'Action.Drawer'}>
</Select.Option>
<Select.Option value={'Action.Window'}> <Select.Option value={'Action.Window'}>
</Select.Option> </Select.Option>
@ -1789,6 +1811,7 @@ Table.Action.DesignableBar = () => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</Space>
</span> </span>
</div> </div>
); );
@ -1860,6 +1883,7 @@ Table.Column.DesignableBar = () => {
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space>
<DragHandle /> <DragHandle />
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -1919,7 +1943,8 @@ Table.Column.DesignableBar = () => {
<Menu.Item <Menu.Item
onClick={async () => { onClick={async () => {
const s = remove(); const s = remove();
const fieldName = schema['x-component-props']?.['fieldName']; const fieldName =
schema['x-component-props']?.['fieldName'];
displayed.remove(fieldName); displayed.remove(fieldName);
await removeSchema(s); await removeSchema(s);
}} }}
@ -1931,6 +1956,7 @@ Table.Column.DesignableBar = () => {
> >
<MenuOutlined /> <MenuOutlined />
</Dropdown> </Dropdown>
</Space>
</span> </span>
</div> </div>
); );
@ -1957,14 +1983,16 @@ Table.DesignableBar = observer((props) => {
console.log({ collectionName }); console.log({ collectionName });
return ( return (
<div className={cls('designable-bar', { active: visible })}> <div className={cls('designable-bar', { active: visible })}>
<div className={'designable-info'}>{collection?.title || collection?.name}</div> <div className={'designable-info'}>
{collection?.title || collection?.name}
</div>
<span <span
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
}} }}
className={cls('designable-bar-actions', { active: visible })} className={cls('designable-bar-actions', { active: visible })}
> >
<Space size={'small'}> <Space size={2}>
<AddNew.CardItem defaultAction={'insertAfter'} ghost /> <AddNew.CardItem defaultAction={'insertAfter'} ghost />
{dragRef && <DragOutlined ref={dragRef} />} {dragRef && <DragOutlined ref={dragRef} />}
<Dropdown <Dropdown
@ -2245,7 +2273,10 @@ Table.useActionLogDetailsResource = ({ onSuccess }) => {
}); });
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {
return resource.get({ ...params, appends: ['changes', 'user', 'collection'] }); return resource.get({
...params,
appends: ['changes', 'user', 'collection'],
});
}, },
{ {
formatResult: (result) => result?.data, formatResult: (result) => result?.data,