Commit 25dbd43c9d1f99bea1bfe5f00270864517b57ca4
1 parent
7b6a433f
refactor(core editor): render canvas、preview、props editor、plugin shortcuts in single file
Showing
6 changed files
with
270 additions
and
215 deletions
front-end/h5/src/components/core/editor/canvas/edit.js
0 → 100644
| 1 | +export default { | ||
| 2 | + props: ['elements', 'handleElementClick'], | ||
| 3 | + methods: { | ||
| 4 | + /** | ||
| 5 | + * #!zh: renderCanvas 渲染中间画布 | ||
| 6 | + * elements | ||
| 7 | + * @param {*} h | ||
| 8 | + * @param {*} elements | ||
| 9 | + * @returns | ||
| 10 | + */ | ||
| 11 | + renderCanvas (h, elements) { | ||
| 12 | + return ( | ||
| 13 | + <div style={{ height: '100%' }}> | ||
| 14 | + { | ||
| 15 | + elements.map((element, index) => { | ||
| 16 | + const data = { | ||
| 17 | + style: element.getStyle(), | ||
| 18 | + props: element.pluginProps, // #6 #3 | ||
| 19 | + nativeOn: { | ||
| 20 | + click: () => this.handleElementClick(element) | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | + return h(element.name, data) | ||
| 24 | + }) | ||
| 25 | + } | ||
| 26 | + </div> | ||
| 27 | + ) | ||
| 28 | + } | ||
| 29 | + }, | ||
| 30 | + render (h) { | ||
| 31 | + return this.renderCanvas(h, this.elements) | ||
| 32 | + } | ||
| 33 | +} |
front-end/h5/src/components/core/editor/canvas/preview.js
0 → 100644
| 1 | +export default { | ||
| 2 | + props: ['elements'], | ||
| 3 | + methods: { | ||
| 4 | + renderPreview (h, elements) { | ||
| 5 | + return ( | ||
| 6 | + <div style={{ height: '100%' }}> | ||
| 7 | + {elements.map((element, index) => { | ||
| 8 | + return (() => { | ||
| 9 | + const data = { | ||
| 10 | + style: element.getStyle(), | ||
| 11 | + props: element.pluginProps, // #6 #3 | ||
| 12 | + nativeOn: {} | ||
| 13 | + } | ||
| 14 | + return h(element.name, data) | ||
| 15 | + })() | ||
| 16 | + })} | ||
| 17 | + </div> | ||
| 18 | + ) | ||
| 19 | + } | ||
| 20 | + }, | ||
| 21 | + render (h) { | ||
| 22 | + return this.renderPreview(h, this.elements) | ||
| 23 | + } | ||
| 24 | +} |
front-end/h5/src/components/core/editor/edit-panel/props.js
0 → 100644
| 1 | +export default { | ||
| 2 | + props: ['editingElement'], | ||
| 3 | + methods: { | ||
| 4 | + /** | ||
| 5 | + * 将插件属性的 自定义增强编辑器注入 属性编辑面板中 | ||
| 6 | + */ | ||
| 7 | + mixinEnhancedPropsEditor (editingElement) { | ||
| 8 | + const { components } = editingElement.editorConfig | ||
| 9 | + for (const key in components) { | ||
| 10 | + if (this.$options.components[key]) return | ||
| 11 | + this.$options.components[key] = components[key] | ||
| 12 | + } | ||
| 13 | + }, | ||
| 14 | + renderPropsEditorPanel (h, editingElement) { | ||
| 15 | + const propsConfig = editingElement.editorConfig.propsConfig | ||
| 16 | + return ( | ||
| 17 | + <a-form ref="form" label-width="100px" size="mini" label-position="left"> | ||
| 18 | + { | ||
| 19 | + Object.keys(propsConfig).map(propKey => { | ||
| 20 | + const item = propsConfig[propKey] | ||
| 21 | + // https://vuejs.org/v2/guide/render-function.html | ||
| 22 | + const data = { | ||
| 23 | + props: { | ||
| 24 | + ...item.prop, | ||
| 25 | + // https://vuejs.org/v2/guide/render-function.html#v-model | ||
| 26 | + value: editingElement.pluginProps[propKey] || item.defaultPropValue | ||
| 27 | + }, | ||
| 28 | + on: { | ||
| 29 | + // https://vuejs.org/v2/guide/render-function.html#v-model | ||
| 30 | + // input (e) { | ||
| 31 | + // editingElement.pluginProps[propKey] = e.target ? e.target.value : e | ||
| 32 | + // } | ||
| 33 | + change (e) { | ||
| 34 | + // TODO fixme: update plugin props in vuex with dispatch | ||
| 35 | + editingElement.pluginProps[propKey] = e.target ? e.target.value : e | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + return ( | ||
| 40 | + <a-form-item label={item.label}> | ||
| 41 | + { h(item.type, data) } | ||
| 42 | + </a-form-item> | ||
| 43 | + ) | ||
| 44 | + }) | ||
| 45 | + } | ||
| 46 | + </a-form> | ||
| 47 | + ) | ||
| 48 | + } | ||
| 49 | + }, | ||
| 50 | + render (h) { | ||
| 51 | + const ele = this.editingElement | ||
| 52 | + if (!ele) return (<span>请先选择一个元素</span>) | ||
| 53 | + this.mixinEnhancedPropsEditor(ele) | ||
| 54 | + return this.renderPropsEditorPanel(h, ele) | ||
| 55 | + } | ||
| 56 | +} |
front-end/h5/src/components/core/editor/index.js
| @@ -2,42 +2,31 @@ import Vue from 'vue' | @@ -2,42 +2,31 @@ import Vue from 'vue' | ||
| 2 | import Element from '../models/element' | 2 | import Element from '../models/element' |
| 3 | import '../styles/index.scss' | 3 | import '../styles/index.scss' |
| 4 | 4 | ||
| 5 | +import RenderEditCanvas from './canvas/edit' | ||
| 6 | +import RenderPreviewCanvas from './canvas/preview' | ||
| 7 | +import RenderPropsEditor from './edit-panel/props' | ||
| 8 | +import RenderShortcutsPanel from './shortcuts-panel/index' | ||
| 9 | + | ||
| 10 | +const sidebarMenus = [ | ||
| 11 | + { | ||
| 12 | + label: '组件列表', | ||
| 13 | + value: 'pluginList', | ||
| 14 | + antIcon: 'user' | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + label: '页面管理', | ||
| 18 | + value: 'pageManagement', | ||
| 19 | + antIcon: 'copy' | ||
| 20 | + }, | ||
| 21 | + { | ||
| 22 | + label: '免费模板', | ||
| 23 | + value: 'freeTemplate', | ||
| 24 | + antIcon: 'appstore' | ||
| 25 | + } | ||
| 26 | +] | ||
| 5 | export default { | 27 | export default { |
| 6 | name: 'Editor', | 28 | name: 'Editor', |
| 7 | - components: { | ||
| 8 | - ShortcutButton: { | ||
| 9 | - functional: true, | ||
| 10 | - props: { | ||
| 11 | - faIcon: { | ||
| 12 | - required: true, | ||
| 13 | - type: String | ||
| 14 | - }, | ||
| 15 | - title: { | ||
| 16 | - required: true, | ||
| 17 | - type: String | ||
| 18 | - }, | ||
| 19 | - clickFn: { | ||
| 20 | - required: false, | ||
| 21 | - type: Function | ||
| 22 | - } | ||
| 23 | - }, | ||
| 24 | - render: (h, { props, listeners, slots }) => { | ||
| 25 | - const onClick = props.clickFn || function () {} | ||
| 26 | - return ( | ||
| 27 | - <a-button | ||
| 28 | - class="shortcut-button" | ||
| 29 | - onClick={onClick} | ||
| 30 | - > | ||
| 31 | - <i | ||
| 32 | - class={['shortcut-icon', 'fa', `fa-${props.faIcon}`]} | ||
| 33 | - aria-hidden='true' | ||
| 34 | - /> | ||
| 35 | - <span>{ props.title }</span> | ||
| 36 | - </a-button> | ||
| 37 | - ) | ||
| 38 | - } | ||
| 39 | - } | ||
| 40 | - }, | 29 | + components: {}, |
| 41 | data: () => ({ | 30 | data: () => ({ |
| 42 | activeMenuKey: 'pluginList', | 31 | activeMenuKey: 'pluginList', |
| 43 | pages: [], | 32 | pages: [], |
| @@ -63,159 +52,8 @@ export default { | @@ -63,159 +52,8 @@ export default { | ||
| 63 | const editorConfig = this.getEditorConfig(name) | 52 | const editorConfig = this.getEditorConfig(name) |
| 64 | this.elements.push(new Element({ name, zindex, editorConfig })) | 53 | this.elements.push(new Element({ name, zindex, editorConfig })) |
| 65 | }, | 54 | }, |
| 66 | - mixinPluginCustomComponents2Editor () { | ||
| 67 | - const { components } = this.editingElement.editorConfig | ||
| 68 | - for (const key in components) { | ||
| 69 | - if (this.$options.components[key]) return | ||
| 70 | - this.$options.components[key] = components[key] | ||
| 71 | - } | ||
| 72 | - }, | ||
| 73 | setCurrentEditingElement (element) { | 55 | setCurrentEditingElement (element) { |
| 74 | this.editingElement = element | 56 | this.editingElement = element |
| 75 | - this.mixinPluginCustomComponents2Editor() | ||
| 76 | - }, | ||
| 77 | - /** | ||
| 78 | - * #!zh: 在左侧或顶部导航上显示可用的组件快捷方式,用户点击之后,即可将其添加到中间画布上 | ||
| 79 | - * #!en: render shortcust at the sidebar or the header. if user click the shortcut, the related plugin will be added to the canvas | ||
| 80 | - * @param {Object} group: {children, title, icon} | ||
| 81 | - */ | ||
| 82 | - renderPluginShortcut (group) { | ||
| 83 | - return group.children.length === 1 | ||
| 84 | - ? this.renderSinglePluginShortcut(group) | ||
| 85 | - : this.renderMultiPluginShortcuts(group) | ||
| 86 | - }, | ||
| 87 | - /** | ||
| 88 | - * #!zh 渲染多个插件的快捷方式 | ||
| 89 | - * #!en render shortcuts for multi plugins | ||
| 90 | - * @param {Object} group: {children, title, icon} | ||
| 91 | - */ | ||
| 92 | - renderMultiPluginShortcuts (group) { | ||
| 93 | - const plugins = group.children | ||
| 94 | - return <a-popover | ||
| 95 | - placement="bottom" | ||
| 96 | - class="shortcust-button" | ||
| 97 | - trigger="hover"> | ||
| 98 | - <a-row slot="content" gutter={20} style={{ width: '400px' }}> | ||
| 99 | - { | ||
| 100 | - plugins.sort().map(item => ( | ||
| 101 | - <a-col span={6}> | ||
| 102 | - <ShortcutButton | ||
| 103 | - clickFn={this.clone.bind(this, item)} | ||
| 104 | - title={item.title} | ||
| 105 | - faIcon={item.icon} | ||
| 106 | - /> | ||
| 107 | - </a-col> | ||
| 108 | - )) | ||
| 109 | - } | ||
| 110 | - </a-row> | ||
| 111 | - <ShortcutButton | ||
| 112 | - title={group.title} | ||
| 113 | - faIcon={group.icon} | ||
| 114 | - /> | ||
| 115 | - </a-popover> | ||
| 116 | - }, | ||
| 117 | - /** | ||
| 118 | - * #!zh: 渲染单个插件的快捷方式 | ||
| 119 | - * #!en: render shortcut for single plugin | ||
| 120 | - * @param {Object} group: {children, title, icon} | ||
| 121 | - */ | ||
| 122 | - renderSinglePluginShortcut ({ children }) { | ||
| 123 | - const [plugin] = children | ||
| 124 | - return <ShortcutButton | ||
| 125 | - clickFn={this.clone.bind(this, plugin)} | ||
| 126 | - title={plugin.title} | ||
| 127 | - faIcon={plugin.icon} | ||
| 128 | - /> | ||
| 129 | - }, | ||
| 130 | - /** | ||
| 131 | - * #!zh: renderCanvas 渲染中间画布 | ||
| 132 | - * elements | ||
| 133 | - * @param {*} h | ||
| 134 | - * @param {*} elements | ||
| 135 | - * @returns | ||
| 136 | - */ | ||
| 137 | - renderCanvas (h, elements) { | ||
| 138 | - return ( | ||
| 139 | - <div style={{ height: '100%' }}> | ||
| 140 | - {elements.map((element, index) => { | ||
| 141 | - return (() => { | ||
| 142 | - const data = { | ||
| 143 | - style: element.getStyle(), | ||
| 144 | - props: element.pluginProps, // #6 #3 | ||
| 145 | - nativeOn: { | ||
| 146 | - click: this.setCurrentEditingElement.bind(this, element) | ||
| 147 | - } | ||
| 148 | - } | ||
| 149 | - return h(element.name, data) | ||
| 150 | - })() | ||
| 151 | - })} | ||
| 152 | - </div> | ||
| 153 | - ) | ||
| 154 | - }, | ||
| 155 | - renderPreview (h, elements) { | ||
| 156 | - return ( | ||
| 157 | - <div style={{ height: '100%' }}> | ||
| 158 | - {elements.map((element, index) => { | ||
| 159 | - return (() => { | ||
| 160 | - const data = { | ||
| 161 | - style: element.getStyle(), | ||
| 162 | - props: element.pluginProps, // #6 #3 | ||
| 163 | - nativeOn: {} | ||
| 164 | - } | ||
| 165 | - return h(element.name, data) | ||
| 166 | - })() | ||
| 167 | - })} | ||
| 168 | - </div> | ||
| 169 | - ) | ||
| 170 | - }, | ||
| 171 | - renderPluginListPanel () { | ||
| 172 | - return ( | ||
| 173 | - <a-row gutter={20}> | ||
| 174 | - { | ||
| 175 | - this.groups.sort().map(group => ( | ||
| 176 | - <a-col span={12} style={{ marginTop: '10px' }}> | ||
| 177 | - {this.renderPluginShortcut(group)} | ||
| 178 | - </a-col> | ||
| 179 | - )) | ||
| 180 | - } | ||
| 181 | - </a-row> | ||
| 182 | - ) | ||
| 183 | - }, | ||
| 184 | - renderPropsEditorPanel (h) { | ||
| 185 | - if (!this.editingElement) return (<span>请先选择一个元素</span>) | ||
| 186 | - const editingElement = this.editingElement | ||
| 187 | - const propsConfig = editingElement.editorConfig.propsConfig | ||
| 188 | - return ( | ||
| 189 | - <a-form ref="form" label-width="100px" size="mini" label-position="left"> | ||
| 190 | - { | ||
| 191 | - Object.keys(propsConfig).map(propKey => { | ||
| 192 | - const item = propsConfig[propKey] | ||
| 193 | - // https://vuejs.org/v2/guide/render-function.html | ||
| 194 | - const data = { | ||
| 195 | - props: { | ||
| 196 | - ...item.prop, | ||
| 197 | - // https://vuejs.org/v2/guide/render-function.html#v-model | ||
| 198 | - value: editingElement.pluginProps[propKey] || item.defaultPropValue | ||
| 199 | - }, | ||
| 200 | - on: { | ||
| 201 | - // https://vuejs.org/v2/guide/render-function.html#v-model | ||
| 202 | - // input (e) { | ||
| 203 | - // editingElement.pluginProps[propKey] = e.target ? e.target.value : e | ||
| 204 | - // } | ||
| 205 | - change (e) { | ||
| 206 | - editingElement.pluginProps[propKey] = e.target ? e.target.value : e | ||
| 207 | - } | ||
| 208 | - } | ||
| 209 | - } | ||
| 210 | - return ( | ||
| 211 | - <a-form-item label={item.label}> | ||
| 212 | - { h(item.type, data) } | ||
| 213 | - </a-form-item> | ||
| 214 | - ) | ||
| 215 | - }) | ||
| 216 | - } | ||
| 217 | - </a-form> | ||
| 218 | - ) | ||
| 219 | } | 57 | } |
| 220 | }, | 58 | }, |
| 221 | render (h) { | 59 | render (h) { |
| @@ -223,21 +61,7 @@ export default { | @@ -223,21 +61,7 @@ export default { | ||
| 223 | <a-layout id="luban-layout" style={{ height: '100vh' }}> | 61 | <a-layout id="luban-layout" style={{ height: '100vh' }}> |
| 224 | <a-layout-header class="header"> | 62 | <a-layout-header class="header"> |
| 225 | <div class="logo">鲁班 H5</div> | 63 | <div class="logo">鲁班 H5</div> |
| 226 | - {/* TODO we can show the plugins shortcuts here | ||
| 227 | - <a-menu | ||
| 228 | - theme="dark" | ||
| 229 | - mode="horizontal" | ||
| 230 | - defaultSelectedKeys={['2']} | ||
| 231 | - style={{ lineHeight: '64px', float: 'left', marginLeft: '30%', background: 'transparent' }} | ||
| 232 | - > | ||
| 233 | - { | ||
| 234 | - this.groups.sort().map((group, id) => ( | ||
| 235 | - <a-menu-item key={id} class="transparent-bg"> | ||
| 236 | - {this.renderPluginShortcut(group)} | ||
| 237 | - </a-menu-item> | ||
| 238 | - )) | ||
| 239 | - } | ||
| 240 | - </a-menu> */} | 64 | + {/* TODO we can show the plugins shortcuts here */} |
| 241 | <a-menu | 65 | <a-menu |
| 242 | theme="dark" | 66 | theme="dark" |
| 243 | mode="horizontal" | 67 | mode="horizontal" |
| @@ -252,22 +76,18 @@ export default { | @@ -252,22 +76,18 @@ export default { | ||
| 252 | <a-layout> | 76 | <a-layout> |
| 253 | <a-layout-sider width="160" style="background: #fff"> | 77 | <a-layout-sider width="160" style="background: #fff"> |
| 254 | <a-menu onSelect={val => { this.activeMenuKey = val }} mode="inline" defaultSelectedKeys={['pluginList']} style={{ height: '100%', borderRight: 1 }}> | 78 | <a-menu onSelect={val => { this.activeMenuKey = val }} mode="inline" defaultSelectedKeys={['pluginList']} style={{ height: '100%', borderRight: 1 }}> |
| 255 | - <a-menu-item key="pluginList"> | ||
| 256 | - <a-icon type="user" /> | ||
| 257 | - <span>组件列表</span> | ||
| 258 | - </a-menu-item> | ||
| 259 | - <a-menu-item key="2"> | ||
| 260 | - <a-icon type="video-camera" /> | ||
| 261 | - <span>页面管理</span> | ||
| 262 | - </a-menu-item> | ||
| 263 | - <a-menu-item key="3"> | ||
| 264 | - <a-icon type="upload" /> | ||
| 265 | - <span>更多模板</span> | ||
| 266 | - </a-menu-item> | 79 | + { |
| 80 | + sidebarMenus.map(menu => ( | ||
| 81 | + <a-menu-item key={menu.value}> | ||
| 82 | + <a-icon type={menu.antIcon} /> | ||
| 83 | + <span>{menu.label}</span> | ||
| 84 | + </a-menu-item> | ||
| 85 | + )) | ||
| 86 | + } | ||
| 267 | </a-menu> | 87 | </a-menu> |
| 268 | </a-layout-sider> | 88 | </a-layout-sider> |
| 269 | <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '0 12px' }}> | 89 | <a-layout-sider width="240" theme='light' style={{ background: '#fff', padding: '0 12px' }}> |
| 270 | - { this.renderPluginListPanel() } | 90 | + <RenderShortcutsPanel groups={this.groups} handleClickShortcut={this.clone} /> |
| 271 | </a-layout-sider> | 91 | </a-layout-sider> |
| 272 | <a-layout style="padding: 0 24px 24px"> | 92 | <a-layout style="padding: 0 24px 24px"> |
| 273 | <a-layout-content style={{ padding: '24px', margin: 0, minHeight: '280px' }}> | 93 | <a-layout-content style={{ padding: '24px', margin: 0, minHeight: '280px' }}> |
| @@ -283,7 +103,8 @@ export default { | @@ -283,7 +103,8 @@ export default { | ||
| 283 | </a-radio-group> | 103 | </a-radio-group> |
| 284 | </div> | 104 | </div> |
| 285 | <div class='canvas-wrapper'> | 105 | <div class='canvas-wrapper'> |
| 286 | - { this.isPreviewMode ? this.renderPreview(h, this.elements) : this.renderCanvas(h, this.elements) } | 106 | + {/* { this.isPreviewMode ? this.renderPreview(h, this.elements) : this.renderCanvas(h, this.elements) } */} |
| 107 | + { this.isPreviewMode ? <RenderPreviewCanvas elements={this.elements}/> : <RenderEditCanvas elements={this.elements} handleElementClick={this.setCurrentEditingElement} /> } | ||
| 287 | </div> | 108 | </div> |
| 288 | </a-layout-content> | 109 | </a-layout-content> |
| 289 | </a-layout> | 110 | </a-layout> |
| @@ -300,7 +121,8 @@ export default { | @@ -300,7 +121,8 @@ export default { | ||
| 300 | <a-icon type="apple" /> | 121 | <a-icon type="apple" /> |
| 301 | 属性 | 122 | 属性 |
| 302 | </span> | 123 | </span> |
| 303 | - { this.renderPropsEditorPanel(h) } | 124 | + {/* { this.renderPropsEditorPanel(h) } */} |
| 125 | + <RenderPropsEditor editingElement={this.editingElement} /> | ||
| 304 | </a-tab-pane> | 126 | </a-tab-pane> |
| 305 | <a-tab-pane label="动画" key='动画' tab='动画'>动画</a-tab-pane> | 127 | <a-tab-pane label="动画" key='动画' tab='动画'>动画</a-tab-pane> |
| 306 | <a-tab-pane label="动作" key='动作' tab='动作'>动作</a-tab-pane> | 128 | <a-tab-pane label="动作" key='动作' tab='动作'>动作</a-tab-pane> |
front-end/h5/src/components/core/editor/shortcuts-panel/index.js
0 → 100644
| 1 | +import ShortcutButton from './shortcut-button' | ||
| 2 | +export default { | ||
| 3 | + props: { | ||
| 4 | + groups: { | ||
| 5 | + required: false, | ||
| 6 | + type: Array, | ||
| 7 | + default: () => [] | ||
| 8 | + }, | ||
| 9 | + handleClickShortcut: { | ||
| 10 | + type: Function | ||
| 11 | + } | ||
| 12 | + }, | ||
| 13 | + methods: { | ||
| 14 | + onClickShortcut (item) { | ||
| 15 | + if (this.handleClickShortcut) { | ||
| 16 | + this.handleClickShortcut(item) | ||
| 17 | + } | ||
| 18 | + }, | ||
| 19 | + /** | ||
| 20 | + * #!zh 渲染多个插件的快捷方式 | ||
| 21 | + * #!en render shortcuts for multi plugins | ||
| 22 | + * @param {Object} group: {children, title, icon} | ||
| 23 | + */ | ||
| 24 | + renderMultiShortcuts (group) { | ||
| 25 | + const plugins = group.children | ||
| 26 | + return <a-popover | ||
| 27 | + placement="bottom" | ||
| 28 | + class="shortcust-button" | ||
| 29 | + trigger="hover"> | ||
| 30 | + <a-row slot="content" gutter={20} style={{ width: '400px' }}> | ||
| 31 | + { | ||
| 32 | + plugins.sort().map(item => ( | ||
| 33 | + <a-col span={6}> | ||
| 34 | + <ShortcutButton | ||
| 35 | + clickFn={this.onClickShortcut.bind(this, item)} | ||
| 36 | + title={item.title} | ||
| 37 | + faIcon={item.icon} | ||
| 38 | + /> | ||
| 39 | + </a-col> | ||
| 40 | + )) | ||
| 41 | + } | ||
| 42 | + </a-row> | ||
| 43 | + <ShortcutButton | ||
| 44 | + title={group.title} | ||
| 45 | + faIcon={group.icon} | ||
| 46 | + /> | ||
| 47 | + </a-popover> | ||
| 48 | + }, | ||
| 49 | + /** | ||
| 50 | + * #!zh: 渲染单个插件的快捷方式 | ||
| 51 | + * #!en: render shortcut for single plugin | ||
| 52 | + * @param {Object} group: {children, title, icon} | ||
| 53 | + */ | ||
| 54 | + renderSingleShortcut ({ children }) { | ||
| 55 | + const [plugin] = children | ||
| 56 | + return <ShortcutButton | ||
| 57 | + clickFn={this.onClickShortcut.bind(this, plugin)} | ||
| 58 | + title={plugin.title} | ||
| 59 | + faIcon={plugin.icon} | ||
| 60 | + /> | ||
| 61 | + }, | ||
| 62 | + /** | ||
| 63 | + * #!zh: 在左侧或顶部导航上显示可用的组件快捷方式,用户点击之后,即可将其添加到中间画布上 | ||
| 64 | + * #!en: render shortcust at the sidebar or the header. if user click the shortcut, the related plugin will be added to the canvas | ||
| 65 | + * @param {Object} group: {children, title, icon} | ||
| 66 | + */ | ||
| 67 | + renderShortCutsPanel (groups) { | ||
| 68 | + return ( | ||
| 69 | + <a-row gutter={20}> | ||
| 70 | + { | ||
| 71 | + groups.sort().map(group => ( | ||
| 72 | + <a-col span={12} style={{ marginTop: '10px' }}> | ||
| 73 | + { | ||
| 74 | + group.children.length === 1 | ||
| 75 | + ? this.renderSingleShortcut(group) | ||
| 76 | + : this.renderMultiShortcuts(group) | ||
| 77 | + } | ||
| 78 | + </a-col> | ||
| 79 | + )) | ||
| 80 | + } | ||
| 81 | + </a-row> | ||
| 82 | + ) | ||
| 83 | + } | ||
| 84 | + }, | ||
| 85 | + render (h) { | ||
| 86 | + return this.renderShortCutsPanel(this.groups) | ||
| 87 | + } | ||
| 88 | +} |
front-end/h5/src/components/core/editor/shortcuts-panel/shortcut-button.js
0 → 100644
| 1 | +export default { | ||
| 2 | + functional: true, | ||
| 3 | + props: { | ||
| 4 | + faIcon: { | ||
| 5 | + required: true, | ||
| 6 | + type: String | ||
| 7 | + }, | ||
| 8 | + title: { | ||
| 9 | + required: true, | ||
| 10 | + type: String | ||
| 11 | + }, | ||
| 12 | + clickFn: { | ||
| 13 | + required: false, | ||
| 14 | + type: Function | ||
| 15 | + } | ||
| 16 | + }, | ||
| 17 | + render: (h, { props, listeners, slots }) => { | ||
| 18 | + const onClick = props.clickFn || function () {} | ||
| 19 | + return ( | ||
| 20 | + <a-button | ||
| 21 | + class="shortcut-button" | ||
| 22 | + onClick={onClick} | ||
| 23 | + > | ||
| 24 | + <i | ||
| 25 | + class={['shortcut-icon', 'fa', `fa-${props.faIcon}`]} | ||
| 26 | + aria-hidden='true' | ||
| 27 | + /> | ||
| 28 | + <span>{ props.title }</span> | ||
| 29 | + </a-button> | ||
| 30 | + ) | ||
| 31 | + } | ||
| 32 | +} |