mirror of
https://github.com/MrXujiang/h5-Dooring.git
synced 2025-12-16 21:52:49 +00:00
🆕 添加icon组件库 📦 添加package.json说明日志
This commit is contained in:
parent
f4f2a2ebaa
commit
b89af1975b
23
package.json
23
package.json
@ -1,9 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "h5-Dooring",
|
"name": "h5-dooring",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"description": "H5-Dooring是一款功能强大,开源免费的H5可视化页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react为主, 后台采用nodejs开发。",
|
"description": "H5-Dooring是一款功能强大,开源免费的H5可视化页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react为主, 后台采用nodejs开发。",
|
||||||
"private": false,
|
"private": false,
|
||||||
"license": "MIT",
|
"author": {
|
||||||
|
"name": "徐小夕",
|
||||||
|
"email": "xujiang156@qq.com",
|
||||||
|
"url": "http://io.nainor.com/h5_visible"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"h5 editor",
|
||||||
|
"h5",
|
||||||
|
"react",
|
||||||
|
"antd",
|
||||||
|
"react-dnd",
|
||||||
|
"web visible"
|
||||||
|
],
|
||||||
|
"contributors": ["yehuozhili <yehuozhili@outlook.com> (https://github.com/yehuozhili))"],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "umi dev",
|
"start": "umi dev",
|
||||||
"build": "umi build",
|
"build": "umi build",
|
||||||
@ -23,6 +36,7 @@
|
|||||||
"prettier --parser=typescript --write"
|
"prettier --parser=typescript --write"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"homepage": "http://io.nainor.com/h5_visible",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/MrXujiang/h5-Dooring.git"
|
"url": "git+https://github.com/MrXujiang/h5-Dooring.git"
|
||||||
@ -58,5 +72,6 @@
|
|||||||
"video-react": "^0.14.1",
|
"video-react": "^0.14.1",
|
||||||
"yorkie": "^2.0.0",
|
"yorkie": "^2.0.0",
|
||||||
"zarm": "^2.5.1"
|
"zarm": "^2.5.1"
|
||||||
}
|
},
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/components/CardPicker/index.js
Normal file
38
src/components/CardPicker/index.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { useState, useEffect, memo } from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import Icon from '../Icon';
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
export default memo(props => {
|
||||||
|
const { type, icons, onChange } = props;
|
||||||
|
|
||||||
|
const [selected, setSelected] = useState(type);
|
||||||
|
|
||||||
|
const handlePicker = v => {
|
||||||
|
if (onChange) {
|
||||||
|
onChange(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelected(v);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelected(type);
|
||||||
|
}, [type]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.pickerWrap}>
|
||||||
|
{icons.map((item, i) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={classnames(styles.picker, selected === item ? styles.selected : '')}
|
||||||
|
onClick={handlePicker.bind(this, item)}
|
||||||
|
key={i}
|
||||||
|
>
|
||||||
|
<Icon type={item} size={20} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
16
src/components/CardPicker/index.less
Normal file
16
src/components/CardPicker/index.less
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.pickerWrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
.picker {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
border-color: #4091f7;
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
border-color: #4091f7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -145,6 +145,8 @@ export default {
|
|||||||
key: 'imgSize',
|
key: 'imgSize',
|
||||||
name: '图片大小',
|
name: '图片大小',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
|
isCrop: true,
|
||||||
|
cropRate: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'sourceData',
|
key: 'sourceData',
|
||||||
@ -271,6 +273,8 @@ export default {
|
|||||||
key: 'qrcode',
|
key: 'qrcode',
|
||||||
name: '二维码',
|
name: '二维码',
|
||||||
type: 'Upload',
|
type: 'Upload',
|
||||||
|
isCrop: true,
|
||||||
|
cropRate: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'text',
|
key: 'text',
|
||||||
@ -364,6 +368,7 @@ export default {
|
|||||||
key: 'imgUrl',
|
key: 'imgUrl',
|
||||||
name: '上传',
|
name: '上传',
|
||||||
type: 'Upload',
|
type: 'Upload',
|
||||||
|
isCrop: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'round',
|
key: 'round',
|
||||||
@ -399,6 +404,8 @@ export default {
|
|||||||
key: 'logo',
|
key: 'logo',
|
||||||
name: 'logo',
|
name: 'logo',
|
||||||
type: 'Upload',
|
type: 'Upload',
|
||||||
|
isCrop: true,
|
||||||
|
cropRate: 1000 / 618,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'logoText',
|
key: 'logoText',
|
||||||
@ -519,6 +526,79 @@ export default {
|
|||||||
color: 'rgba(153,153,153,1)',
|
color: 'rgba(153,153,153,1)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Icon: {
|
||||||
|
editData: [
|
||||||
|
{
|
||||||
|
key: 'color',
|
||||||
|
name: '颜色',
|
||||||
|
type: 'Color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'size',
|
||||||
|
name: '大小',
|
||||||
|
type: 'Number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'spin',
|
||||||
|
name: '旋转动画',
|
||||||
|
type: 'Switch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'type',
|
||||||
|
name: '图标类型',
|
||||||
|
type: 'CardPicker',
|
||||||
|
icons: [
|
||||||
|
'AccountBookTwoTone',
|
||||||
|
'AlertTwoTone',
|
||||||
|
'ApiTwoTone',
|
||||||
|
'AppstoreTwoTone',
|
||||||
|
'AudioTwoTone',
|
||||||
|
'BankTwoTone',
|
||||||
|
'BellTwoTone',
|
||||||
|
'BookTwoTone',
|
||||||
|
'BugTwoTone',
|
||||||
|
'BuildTwoTone',
|
||||||
|
'BulbTwoTone',
|
||||||
|
'CalculatorTwoTone',
|
||||||
|
'CalendarTwoTone',
|
||||||
|
'CameraTwoTone',
|
||||||
|
'CarTwoTone',
|
||||||
|
'CarryOutTwoTone',
|
||||||
|
'CiCircleTwoTone',
|
||||||
|
'CloudTwoTone',
|
||||||
|
'CodeTwoTone',
|
||||||
|
'CrownTwoTone',
|
||||||
|
'CustomerServiceTwoTone',
|
||||||
|
'DollarCircleTwoTone',
|
||||||
|
'EnvironmentTwoTone',
|
||||||
|
'ExperimentTwoTone',
|
||||||
|
'FireTwoTone',
|
||||||
|
'GiftTwoTone',
|
||||||
|
'InsuranceTwoTone',
|
||||||
|
'LikeTwoTone',
|
||||||
|
'LockTwoTone',
|
||||||
|
'MailTwoTone',
|
||||||
|
'MessageTwoTone',
|
||||||
|
'PhoneTwoTone',
|
||||||
|
'PictureTwoTone',
|
||||||
|
'PlaySquareTwoTone',
|
||||||
|
'RedEnvelopeTwoTone',
|
||||||
|
'ShopTwoTone',
|
||||||
|
'TrademarkCircleTwoTone',
|
||||||
|
'StarTwoTone',
|
||||||
|
'SafetyCertificateTwoTone',
|
||||||
|
'SettingTwoTone',
|
||||||
|
'RocketTwoTone',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
color: '',
|
||||||
|
size: 36,
|
||||||
|
spin: false,
|
||||||
|
type: 'CarTwoTone',
|
||||||
|
},
|
||||||
|
},
|
||||||
Video: {
|
Video: {
|
||||||
editData: [
|
editData: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,40 +1,44 @@
|
|||||||
const template = [
|
const template = [
|
||||||
{
|
{
|
||||||
type:'Text',
|
type: 'Text',
|
||||||
h: 20
|
h: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Carousel',
|
type: 'Carousel',
|
||||||
h: 82
|
h: 82,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Tab',
|
type: 'Tab',
|
||||||
h: 130
|
h: 130,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Notice',
|
type: 'Notice',
|
||||||
h: 20
|
h: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Qrcode',
|
type: 'Qrcode',
|
||||||
h: 150
|
h: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Footer',
|
type: 'Icon',
|
||||||
h: 24
|
h: 23,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Image',
|
type: 'Image',
|
||||||
h: 188
|
h: 188,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'Header',
|
type: 'Header',
|
||||||
h: 28
|
h: 28,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type:'List',
|
type: 'List',
|
||||||
h: 110
|
h: 110,
|
||||||
}
|
},
|
||||||
]
|
{
|
||||||
|
type: 'Footer',
|
||||||
|
h: 24,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default template
|
export default template;
|
||||||
|
|||||||
@ -1,17 +1,10 @@
|
|||||||
import React, { memo, useState, useEffect } from 'react';
|
import React, { memo, useState, useEffect } from 'react';
|
||||||
import {
|
import { Form, Select, InputNumber, Input, Switch, Radio, Button } from 'antd';
|
||||||
Form,
|
|
||||||
Select,
|
|
||||||
InputNumber,
|
|
||||||
Input,
|
|
||||||
Switch,
|
|
||||||
Radio,
|
|
||||||
Button
|
|
||||||
} from 'antd';
|
|
||||||
import Upload from '@/components/Upload';
|
import Upload from '@/components/Upload';
|
||||||
import DataList from '@/components/DataList';
|
import DataList from '@/components/DataList';
|
||||||
import MutiText from '@/components/MutiText';
|
import MutiText from '@/components/MutiText';
|
||||||
import Color from '@/components/Color';
|
import Color from '@/components/Color';
|
||||||
|
import CardPicker from '@/components/CardPicker';
|
||||||
|
|
||||||
// import styles from './index.less';
|
// import styles from './index.less';
|
||||||
const normFile = e => {
|
const normFile = e => {
|
||||||
@ -29,32 +22,24 @@ const formItemLayout = {
|
|||||||
wrapperCol: { span: 16 },
|
wrapperCol: { span: 16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultConfig = [
|
const FormEditor = props => {
|
||||||
{
|
const { config, defaultValue, onSave, onDel, uid } = props;
|
||||||
"key": "tabs",
|
|
||||||
"name": "项目类别",
|
|
||||||
"type": "mutiText",
|
|
||||||
"defaultValue": ["类别一", "类别二"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const FormEditor = (props) => {
|
|
||||||
const { config = defaultConfig, defaultValue, onSave, onDel, uid } = props
|
|
||||||
const onFinish = values => {
|
const onFinish = values => {
|
||||||
onSave && onSave(values)
|
onSave && onSave(values);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleDel = () => {
|
const handleDel = () => {
|
||||||
onDel && onDel(uid)
|
onDel && onDel(uid);
|
||||||
}
|
};
|
||||||
|
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
form.resetFields()
|
form.resetFields();
|
||||||
}
|
};
|
||||||
}, [defaultValue])
|
}, [defaultValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
@ -64,83 +49,88 @@ const FormEditor = (props) => {
|
|||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
initialValues={defaultValue}
|
initialValues={defaultValue}
|
||||||
>
|
>
|
||||||
{
|
{config.map((item, i) => {
|
||||||
config.map((item, i) => {
|
return (
|
||||||
return <React.Fragment key={i}>
|
<React.Fragment key={i}>
|
||||||
{
|
{item.type === 'Number' && (
|
||||||
item.type === 'Number' &&
|
<Form.Item label={item.name} name={item.key}>
|
||||||
<Form.Item label={item.name} name={item.key}>
|
<InputNumber min={1} max={item.range && item.range[1]} />
|
||||||
<InputNumber min={1} />
|
</Form.Item>
|
||||||
</Form.Item>
|
)}
|
||||||
}
|
{item.type === 'Text' && (
|
||||||
{
|
<Form.Item label={item.name} name={item.key}>
|
||||||
item.type === 'Text' &&
|
<Input />
|
||||||
<Form.Item label={item.name} name={item.key}>
|
</Form.Item>
|
||||||
<Input />
|
)}
|
||||||
</Form.Item>
|
{item.type === 'DataList' && (
|
||||||
}
|
<Form.Item label={item.name} name={item.key}>
|
||||||
{
|
<DataList />
|
||||||
item.type === 'DataList' &&
|
</Form.Item>
|
||||||
<Form.Item label={item.name} name={item.key}>
|
)}
|
||||||
<DataList />
|
{item.type === 'Color' && (
|
||||||
</Form.Item>
|
<Form.Item label={item.name} name={item.key}>
|
||||||
}
|
<Color />
|
||||||
{
|
</Form.Item>
|
||||||
item.type === 'Color' &&
|
)}
|
||||||
<Form.Item label={item.name} name={item.key}>
|
{item.type === 'MutiText' && (
|
||||||
<Color />
|
<Form.Item label={item.name} name={item.key}>
|
||||||
</Form.Item>
|
<MutiText />
|
||||||
}
|
</Form.Item>
|
||||||
{
|
)}
|
||||||
item.type === 'MutiText' &&
|
{item.type === 'Select' && (
|
||||||
<Form.Item label={item.name} name={item.key}>
|
<Form.Item label={item.name} name={item.key}>
|
||||||
<MutiText />
|
<Select placeholder="请选择">
|
||||||
</Form.Item>
|
{item.range.map((v, i) => {
|
||||||
}
|
return (
|
||||||
{
|
<Option value={v.key} key={i}>
|
||||||
item.type === 'Select' &&
|
{v.text}
|
||||||
<Form.Item label={item.name} name={item.key}>
|
</Option>
|
||||||
<Select placeholder="请选择">
|
);
|
||||||
{
|
})}
|
||||||
item.range.map((v, i) => {
|
</Select>
|
||||||
return <Option value={v.key} key={i}>{ v.text }</Option>
|
</Form.Item>
|
||||||
})
|
)}
|
||||||
}
|
{item.type === 'Radio' && (
|
||||||
</Select>
|
<Form.Item label={item.name} name={item.key}>
|
||||||
</Form.Item>
|
<Radio.Group>
|
||||||
}
|
{item.range.map((v, i) => {
|
||||||
{
|
return (
|
||||||
item.type === 'Radio' &&
|
<Radio value={v.key} key={i}>
|
||||||
<Form.Item label={item.name} name={item.key}>
|
{v.text}
|
||||||
<Radio.Group>
|
</Radio>
|
||||||
{
|
);
|
||||||
item.range.map((v, i) => {
|
})}
|
||||||
return <Radio value={v.key} key={i}>{ v.text }</Radio>
|
</Radio.Group>
|
||||||
})
|
</Form.Item>
|
||||||
}
|
)}
|
||||||
</Radio.Group>
|
{item.type === 'Switch' && (
|
||||||
</Form.Item>
|
<Form.Item label={item.name} name={item.key} valuePropName="checked">
|
||||||
}
|
<Switch />
|
||||||
{
|
</Form.Item>
|
||||||
item.type === 'Switch' &&
|
)}
|
||||||
<Form.Item label={item.name} name={item.key} valuePropName="checked">
|
{item.type === 'Upload' && (
|
||||||
<Switch />
|
<Form.Item
|
||||||
</Form.Item>
|
label={item.name}
|
||||||
}
|
name={item.key}
|
||||||
{
|
valuePropName="fileList"
|
||||||
item.type === 'Upload' &&
|
getValueFromEvent={normFile}
|
||||||
<Form.Item label={item.name} name={item.key} valuePropName="fileList" getValueFromEvent={normFile}>
|
>
|
||||||
<Upload />
|
<Upload cropRate={item.cropRate} isCrop={item.isCrop} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
)}
|
||||||
|
{item.type === 'CardPicker' && (
|
||||||
|
<Form.Item label={item.name} name={item.key} valuePropName="type">
|
||||||
|
<CardPicker icons={item.icons} />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
})
|
);
|
||||||
}
|
})}
|
||||||
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
|
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
|
||||||
<Button type="primary" htmlType="submit">
|
<Button type="primary" htmlType="submit">
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="danger" style={{marginLeft: '20px'}} onClick={handleDel}>
|
<Button type="danger" style={{ marginLeft: '20px' }} onClick={handleDel}>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -148,4 +138,4 @@ const FormEditor = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(FormEditor)
|
export default memo(FormEditor);
|
||||||
|
|||||||
20
src/components/Icon/index.js
Normal file
20
src/components/Icon/index.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import * as Icon from '@ant-design/icons';
|
||||||
|
import IconImg from 'assets/icon.png';
|
||||||
|
|
||||||
|
const XIcon = memo(props => {
|
||||||
|
const { color, size, type, spin, isTpl } = props;
|
||||||
|
|
||||||
|
const MyIcon = Icon[type];
|
||||||
|
|
||||||
|
return isTpl ? (
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<img style={{ verticalAlign: '-20px', width: '82px' }} src={IconImg} alt={type} />
|
||||||
|
图标
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<MyIcon twoToneColor={color} style={{ fontSize: size }} spin={spin} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default XIcon;
|
||||||
@ -20,7 +20,8 @@ const SourceBox = memo(props => {
|
|||||||
pointEnd = monitor.getSourceClientOffset(),
|
pointEnd = monitor.getSourceClientOffset(),
|
||||||
y = pointEnd.y < top ? 0 : pointEnd.y - top,
|
y = pointEnd.y < top ? 0 : pointEnd.y - top,
|
||||||
col = 24, // 网格列数
|
col = 24, // 网格列数
|
||||||
cellHeight = 2;
|
cellHeight = 2,
|
||||||
|
w = item.type === 'Icon' ? 3 : col;
|
||||||
// 转换成网格规则的坐标和大小
|
// 转换成网格规则的坐标和大小
|
||||||
let gridY = Math.ceil(y / cellHeight);
|
let gridY = Math.ceil(y / cellHeight);
|
||||||
dispatch({
|
dispatch({
|
||||||
@ -28,7 +29,7 @@ const SourceBox = memo(props => {
|
|||||||
payload: {
|
payload: {
|
||||||
id: uuid(6, 10),
|
id: uuid(6, 10),
|
||||||
item,
|
item,
|
||||||
point: { i: `x-${pointData.length}`, x: 0, y: gridY, w: col, h: item.h, isBounded: true },
|
point: { i: `x-${pointData.length}`, x: 0, y: gridY, w, h: item.h, isBounded: true },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import schema from 'components/DynamicEngine/schema';
|
|||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const TargetBox = memo(props => {
|
const TargetBox = memo(props => {
|
||||||
const { item, dispatch, canvasId, pointData } = props;
|
const { item, dispatch, pointData } = props;
|
||||||
const [{ isDragging }, drag, preview] = useDrag({
|
const [{ isDragging }, drag, preview] = useDrag({
|
||||||
item: {
|
item: {
|
||||||
type: item.type,
|
type: item.type,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user