diff --git a/package.json b/package.json index a4d1e7a..4dc5c75 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,22 @@ { - "name": "h5-Dooring", - "version": "1.2.0", + "name": "h5-dooring", + "version": "1.3.0", "description": "H5-Dooring是一款功能强大,开源免费的H5可视化页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react为主, 后台采用nodejs开发。", "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 (https://github.com/yehuozhili))"], "scripts": { "start": "umi dev", "build": "umi build", @@ -23,6 +36,7 @@ "prettier --parser=typescript --write" ] }, + "homepage": "http://io.nainor.com/h5_visible", "repository": { "type": "git", "url": "git+https://github.com/MrXujiang/h5-Dooring.git" @@ -58,5 +72,6 @@ "video-react": "^0.14.1", "yorkie": "^2.0.0", "zarm": "^2.5.1" - } + }, + "license": "MIT" } diff --git a/src/components/CardPicker/index.js b/src/components/CardPicker/index.js new file mode 100644 index 0000000..f0c4c0d --- /dev/null +++ b/src/components/CardPicker/index.js @@ -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 ( +
+ {icons.map((item, i) => { + return ( + + + + ); + })} +
+ ); +}); diff --git a/src/components/CardPicker/index.less b/src/components/CardPicker/index.less new file mode 100644 index 0000000..c67b749 --- /dev/null +++ b/src/components/CardPicker/index.less @@ -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; + } + } +} diff --git a/src/components/DynamicEngine/schema.js b/src/components/DynamicEngine/schema.js index 65d059b..58b7589 100644 --- a/src/components/DynamicEngine/schema.js +++ b/src/components/DynamicEngine/schema.js @@ -145,6 +145,8 @@ export default { key: 'imgSize', name: '图片大小', type: 'Number', + isCrop: true, + cropRate: 1, }, { key: 'sourceData', @@ -271,6 +273,8 @@ export default { key: 'qrcode', name: '二维码', type: 'Upload', + isCrop: true, + cropRate: 1, }, { key: 'text', @@ -364,6 +368,7 @@ export default { key: 'imgUrl', name: '上传', type: 'Upload', + isCrop: false, }, { key: 'round', @@ -399,6 +404,8 @@ export default { key: 'logo', name: 'logo', type: 'Upload', + isCrop: true, + cropRate: 1000 / 618, }, { key: 'logoText', @@ -519,6 +526,79 @@ export default { 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: { editData: [ { diff --git a/src/components/DynamicEngine/template.js b/src/components/DynamicEngine/template.js index de41fb7..d59f3fd 100644 --- a/src/components/DynamicEngine/template.js +++ b/src/components/DynamicEngine/template.js @@ -1,40 +1,44 @@ const template = [ - { - type:'Text', - h: 20 + { + type: 'Text', + h: 20, }, - { - type:'Carousel', - h: 82 + { + type: 'Carousel', + h: 82, }, - { - type:'Tab', - h: 130 + { + type: 'Tab', + h: 130, }, - { - type:'Notice', - h: 20 + { + type: 'Notice', + h: 20, }, - { - type:'Qrcode', - h: 150 + { + type: 'Qrcode', + h: 150, }, - { - type:'Footer', - h: 24 + { + type: 'Icon', + h: 23, }, - { - type:'Image', - h: 188 + { + type: 'Image', + h: 188, }, - { - type:'Header', - h: 28 + { + type: 'Header', + h: 28, }, - { - type:'List', - h: 110 - } -] + { + type: 'List', + h: 110, + }, + { + type: 'Footer', + h: 24, + }, +]; -export default template \ No newline at end of file +export default template; diff --git a/src/components/FormEditor/index.js b/src/components/FormEditor/index.js index cdae705..3ba70dc 100644 --- a/src/components/FormEditor/index.js +++ b/src/components/FormEditor/index.js @@ -1,17 +1,10 @@ import React, { memo, useState, useEffect } from 'react'; -import { - Form, - Select, - InputNumber, - Input, - Switch, - Radio, - Button -} from 'antd'; +import { Form, Select, InputNumber, Input, Switch, Radio, Button } from 'antd'; import Upload from '@/components/Upload'; import DataList from '@/components/DataList'; import MutiText from '@/components/MutiText'; import Color from '@/components/Color'; +import CardPicker from '@/components/CardPicker'; // import styles from './index.less'; const normFile = e => { @@ -29,32 +22,24 @@ const formItemLayout = { wrapperCol: { span: 16 }, }; -const defaultConfig = [ - { - "key": "tabs", - "name": "项目类别", - "type": "mutiText", - "defaultValue": ["类别一", "类别二"] - } -] +const FormEditor = props => { + const { config, defaultValue, onSave, onDel, uid } = props; -const FormEditor = (props) => { - const { config = defaultConfig, defaultValue, onSave, onDel, uid } = props const onFinish = values => { - onSave && onSave(values) - } + onSave && onSave(values); + }; const handleDel = () => { - onDel && onDel(uid) - } + onDel && onDel(uid); + }; - const [form] = Form.useForm() + const [form] = Form.useForm(); useEffect(() => { return () => { - form.resetFields() - } - }, [defaultValue]) + form.resetFields(); + }; + }, [defaultValue]); return (
{ onFinish={onFinish} initialValues={defaultValue} > - { - config.map((item, i) => { - return - { - item.type === 'Number' && - - - - } - { - item.type === 'Text' && - - - - } - { - item.type === 'DataList' && - - - - } - { - item.type === 'Color' && - - - - } - { - item.type === 'MutiText' && - - - - } - { - item.type === 'Select' && - - - - } - { - item.type === 'Radio' && - - - { - item.range.map((v, i) => { - return { v.text } - }) - } - - - } - { - item.type === 'Switch' && - - - - } - { - item.type === 'Upload' && - - - - } + {config.map((item, i) => { + return ( + + {item.type === 'Number' && ( + + + + )} + {item.type === 'Text' && ( + + + + )} + {item.type === 'DataList' && ( + + + + )} + {item.type === 'Color' && ( + + + + )} + {item.type === 'MutiText' && ( + + + + )} + {item.type === 'Select' && ( + + + + )} + {item.type === 'Radio' && ( + + + {item.range.map((v, i) => { + return ( + + {v.text} + + ); + })} + + + )} + {item.type === 'Switch' && ( + + + + )} + {item.type === 'Upload' && ( + + + + )} + {item.type === 'CardPicker' && ( + + + + )} - }) - } + ); + })} - @@ -148,4 +138,4 @@ const FormEditor = (props) => { ); }; -export default memo(FormEditor) \ No newline at end of file +export default memo(FormEditor); diff --git a/src/components/Icon/index.js b/src/components/Icon/index.js new file mode 100644 index 0000000..8fcd47d --- /dev/null +++ b/src/components/Icon/index.js @@ -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 ? ( +
+ {type} + 图标 +
+ ) : ( + + ); +}); + +export default XIcon; diff --git a/src/pages/editor/SourceBox.js b/src/pages/editor/SourceBox.js index f217946..be25e02 100644 --- a/src/pages/editor/SourceBox.js +++ b/src/pages/editor/SourceBox.js @@ -20,7 +20,8 @@ const SourceBox = memo(props => { pointEnd = monitor.getSourceClientOffset(), y = pointEnd.y < top ? 0 : pointEnd.y - top, col = 24, // 网格列数 - cellHeight = 2; + cellHeight = 2, + w = item.type === 'Icon' ? 3 : col; // 转换成网格规则的坐标和大小 let gridY = Math.ceil(y / cellHeight); dispatch({ @@ -28,7 +29,7 @@ const SourceBox = memo(props => { payload: { id: uuid(6, 10), 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 }, }, }); }, diff --git a/src/pages/editor/TargetBox.js b/src/pages/editor/TargetBox.js index 4666be3..876766d 100644 --- a/src/pages/editor/TargetBox.js +++ b/src/pages/editor/TargetBox.js @@ -6,7 +6,7 @@ import schema from 'components/DynamicEngine/schema'; import styles from './index.less'; const TargetBox = memo(props => { - const { item, dispatch, canvasId, pointData } = props; + const { item, dispatch, pointData } = props; const [{ isDragging }, drag, preview] = useDrag({ item: { type: item.type,