diff --git a/packages/builtinComponent/index.js b/packages/builtinComponent/index.js
index 99242b77a..d9976790d 100644
--- a/packages/builtinComponent/index.js
+++ b/packages/builtinComponent/index.js
@@ -1,4 +1,6 @@
export { default as CanvasCol } from './src/components/CanvasCol.vue'
export { default as CanvasRow } from './src/components/CanvasRow.vue'
export { default as CanvasRowColContainer } from './src/components/CanvasRowColContainer.vue'
+export { default as CanvasFlexBox } from './src/components/CanvasFlexBox.vue'
+export { default as CanvasSection } from './src/components/CanvasSection.vue'
export { default as meta } from './src/meta'
diff --git a/packages/builtinComponent/src/components/CanvasFlexBox.vue b/packages/builtinComponent/src/components/CanvasFlexBox.vue
new file mode 100644
index 000000000..593443dc6
--- /dev/null
+++ b/packages/builtinComponent/src/components/CanvasFlexBox.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
diff --git a/packages/builtinComponent/src/components/CanvasSection.vue b/packages/builtinComponent/src/components/CanvasSection.vue
new file mode 100644
index 000000000..2d2994fa3
--- /dev/null
+++ b/packages/builtinComponent/src/components/CanvasSection.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/packages/builtinComponent/src/meta/CanvasFlexBox.json b/packages/builtinComponent/src/meta/CanvasFlexBox.json
new file mode 100644
index 000000000..625a3ac67
--- /dev/null
+++ b/packages/builtinComponent/src/meta/CanvasFlexBox.json
@@ -0,0 +1,221 @@
+{
+ "component": {
+ "icon": "Box",
+ "name": {
+ "zh_CN": "弹性容器"
+ },
+ "component": "CanvasFlexBox",
+ "schema": {
+ "slots": {},
+ "properties": [
+ {
+ "label": {
+ "zh_CN": "基础信息"
+ },
+ "description": {
+ "zh_CN": "基础信息"
+ },
+ "collapse": {
+ "number": 6,
+ "text": {
+ "zh_CN": "显示更多"
+ }
+ },
+ "content": [
+ {
+ "property": "flexDirection",
+ "type": "String",
+ "defaultValue": "row",
+ "bindState": true,
+ "label": {
+ "text": {
+ "zh_CN": "排列方向"
+ }
+ },
+ "cols": 12,
+ "rules": [],
+ "widget": {
+ "component": "SelectConfigurator",
+ "props": {
+ "options": [
+ {
+ "label": "水平,起点在左端",
+ "value": "row"
+ },
+ {
+ "label": "水平,起点在右端",
+ "value": "row-reverse"
+ },
+ {
+ "label": "垂直,起点在上沿",
+ "value": "column"
+ },
+ {
+ "label": "垂直,起点在下沿",
+ "value": "column-reverse"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "property": "gap",
+ "defaultValue": "8px",
+ "label": {
+ "text": {
+ "zh_CN": "间距"
+ }
+ },
+ "widget": {
+ "component": "InputConfigurator"
+ },
+ "description": {
+ "zh_CN": "控制容器内水平和垂直的间距"
+ },
+ "labelPosition": "left"
+ },
+ {
+ "property": "padding",
+ "defaultValue": "8px",
+ "label": {
+ "text": {
+ "zh_CN": "内边距"
+ }
+ },
+ "widget": {
+ "component": "InputConfigurator"
+ },
+ "labelPosition": "left"
+ },
+ {
+ "property": "justifyContent",
+ "type": "String",
+ "defaultValue": "flex-start",
+ "bindState": true,
+ "label": {
+ "text": {
+ "zh_CN": "水平对齐方式"
+ }
+ },
+ "cols": 12,
+ "rules": [],
+ "widget": {
+ "component": "SelectConfigurator",
+ "props": {
+ "options": [
+ {
+ "label": "左对齐",
+ "value": "flex-start"
+ },
+ {
+ "label": "右对齐",
+ "value": "flex-end"
+ },
+ {
+ "label": "居中",
+ "value": "center"
+ },
+ {
+ "label": "两端对齐,子元素间隔相等",
+ "value": "space-between"
+ },
+ {
+ "label": "子元素两侧间隔相等",
+ "value": "space-around"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "property": "alignItems",
+ "type": "String",
+ "defaultValue": "center",
+ "bindState": true,
+ "label": {
+ "text": {
+ "zh_CN": "垂直对齐方式"
+ }
+ },
+ "cols": 12,
+ "rules": [],
+ "widget": {
+ "component": "SelectConfigurator",
+ "props": {
+ "options": [
+ {
+ "label": "交叉轴的中点对齐",
+ "value": "center"
+ },
+ {
+ "label": "交叉轴的起点对齐",
+ "value": "flex-start"
+ },
+ {
+ "label": "交叉轴的终点对齐",
+ "value": "flex-end"
+ },
+ {
+ "label": "以子元素第一行文字的基线对齐",
+ "value": "baseline"
+ },
+ {
+ "label": "占满容器高度",
+ "value": "stretch"
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "events": {
+ "onClick": {
+ "label": {
+ "zh_CN": "点击事件"
+ },
+ "description": {
+ "zh_CN": "点击时触发的回调函数"
+ },
+ "type": "event",
+ "functionInfo": {
+ "params": [],
+ "returns": {}
+ },
+ "defaultValue": ""
+ }
+ },
+ "shortcuts": {
+ "properties": []
+ },
+ "contentMenu": {
+ "actions": []
+ }
+ },
+ "configure": {
+ "loop": true,
+ "isContainer": true,
+ "nestingRule": {
+ "childWhitelist": [],
+ "descendantBlacklist": []
+ }
+ }
+ },
+ "snippet": {
+ "name": {
+ "zh_CN": "弹性容器"
+ },
+ "screenshot": "",
+ "snippetName": "CanvasFlexBox",
+ "icon": "Box",
+ "schema": {
+ "componentName": "CanvasFlexBox",
+ "props": {
+ "flexDirection": "row",
+ "gap": "8px",
+ "padding": "8px"
+ }
+ }
+ }
+}
diff --git a/packages/builtinComponent/src/meta/CanvasRowColContainer.json b/packages/builtinComponent/src/meta/CanvasRowColContainer.json
index 3281b14a0..4609c76b2 100644
--- a/packages/builtinComponent/src/meta/CanvasRowColContainer.json
+++ b/packages/builtinComponent/src/meta/CanvasRowColContainer.json
@@ -68,21 +68,21 @@
"schema": {
"componentName": "CanvasRowColContainer",
"props": {
- "rowGap": "20px"
+ "rowGap": "16px"
},
"children": [
{
"componentName": "CanvasRow",
"props": {
- "rowGap": "20px",
- "colGap": "20px"
+ "rowGap": "16px",
+ "colGap": "16px"
},
"children": [
{
"componentName": "CanvasCol",
"props": {
- "rowGap": "20px",
- "colGap": "20px",
+ "rowGap": "16px",
+ "colGap": "16px",
"grow": true,
"shrink": true,
"widthType": "auto"
diff --git a/packages/builtinComponent/src/meta/CanvasSection.json b/packages/builtinComponent/src/meta/CanvasSection.json
new file mode 100644
index 000000000..44c2ffd83
--- /dev/null
+++ b/packages/builtinComponent/src/meta/CanvasSection.json
@@ -0,0 +1,71 @@
+{
+ "component": {
+ "icon": "Box",
+ "name": {
+ "zh_CN": "全宽居中布局"
+ },
+ "component": "CanvasSection",
+ "schema": {
+ "slots": {},
+ "properties": [
+ {
+ "label": {
+ "zh_CN": "基础信息"
+ },
+ "description": {
+ "zh_CN": "基础信息"
+ },
+ "collapse": {
+ "number": 6,
+ "text": {
+ "zh_CN": "显示更多"
+ }
+ },
+ "content": []
+ }
+ ],
+ "events": {
+ "onClick": {
+ "label": {
+ "zh_CN": "点击事件"
+ },
+ "description": {
+ "zh_CN": "点击时触发的回调函数"
+ },
+ "type": "event",
+ "functionInfo": {
+ "params": [],
+ "returns": {}
+ },
+ "defaultValue": ""
+ }
+ },
+ "shortcuts": {
+ "properties": []
+ },
+ "contentMenu": {
+ "actions": []
+ }
+ },
+ "configure": {
+ "loop": true,
+ "isContainer": true,
+ "nestingRule": {
+ "childWhitelist": [],
+ "descendantBlacklist": []
+ }
+ }
+ },
+ "snippet": {
+ "name": {
+ "zh_CN": "全宽居中布局"
+ },
+ "screenshot": "",
+ "snippetName": "CanvasSection",
+ "icon": "Box",
+ "schema": {
+ "componentName": "CanvasSection",
+ "props": {}
+ }
+ }
+}
diff --git a/packages/builtinComponent/src/meta/index.js b/packages/builtinComponent/src/meta/index.js
index 2480e7051..7521af69a 100644
--- a/packages/builtinComponent/src/meta/index.js
+++ b/packages/builtinComponent/src/meta/index.js
@@ -1,16 +1,24 @@
import CanvasCol from './CanvasCol.json'
import CanvasRow from './CanvasRow.json'
import CanvasRowColContainer from './CanvasRowColContainer.json'
+import CanvasFlexBox from './CanvasFlexBox.json'
+import CanvasSection from './CanvasSection.json'
export default {
- components: [CanvasCol.component, CanvasRow.component, CanvasRowColContainer.component],
+ components: [
+ CanvasCol.component,
+ CanvasRow.component,
+ CanvasRowColContainer.component,
+ CanvasFlexBox.component,
+ CanvasSection.component
+ ],
snippets: [
{
group: 'layout',
label: {
zh_CN: '布局与容器'
},
- children: [CanvasRowColContainer.snippet]
+ children: [CanvasRowColContainer.snippet, CanvasFlexBox.snippet, CanvasSection.snippet]
}
]
}
diff --git a/packages/canvas/DesignCanvas/src/api/useCanvas.js b/packages/canvas/DesignCanvas/src/api/useCanvas.js
index 2be05169b..a43b8c400 100644
--- a/packages/canvas/DesignCanvas/src/api/useCanvas.js
+++ b/packages/canvas/DesignCanvas/src/api/useCanvas.js
@@ -13,7 +13,7 @@
/* eslint-disable no-new-func */
import { reactive, ref } from 'vue'
import { constants } from '@opentiny/tiny-engine-utils'
-import { useHistory } from '@opentiny/tiny-engine-meta-register'
+import { useHistory, getMetaApi } from '@opentiny/tiny-engine-meta-register'
const { COMPONENT_NAME } = constants
@@ -80,11 +80,17 @@ const resetBlockCanvasState = async (state = {}) => {
await resetCanvasState(state)
}
-const getDefaultSchema = (componentName = 'Page', fileName = '') => ({
- ...defaultSchema,
- componentName,
- fileName
-})
+const getDefaultSchema = (componentName = 'Page', fileName = '') => {
+ const DEFAULT_PAGE = getMetaApi('engine.service.page')?.getDefaultPage() || { page_content: { props: {}, css: '' } }
+
+ return {
+ ...defaultSchema,
+ props: DEFAULT_PAGE.page_content?.props || {},
+ css: DEFAULT_PAGE.page_content?.css || '',
+ componentName,
+ fileName
+ }
+}
const setSaved = (flag = false) => {
pageState.isSaved = flag
diff --git a/packages/canvas/render/src/builtin/builtin.json b/packages/canvas/render/src/builtin/builtin.json
index ad56e67ab..924f197cf 100644
--- a/packages/canvas/render/src/builtin/builtin.json
+++ b/packages/canvas/render/src/builtin/builtin.json
@@ -468,6 +468,7 @@
"schema": {
"componentName": "Text",
"props": {
+ "style": "display: inline-block;",
"text": "TinyEngine 前端可视化设计器,为设计器开发者提供定制服务,在线构建出自己专属的设计器。"
}
}
diff --git a/packages/canvas/render/src/render.js b/packages/canvas/render/src/render.js
index 1c5c4a36c..9a7b32a93 100644
--- a/packages/canvas/render/src/render.js
+++ b/packages/canvas/render/src/render.js
@@ -17,7 +17,13 @@ import { constants, utils } from '@opentiny/tiny-engine-utils'
import babelPluginJSX from '@vue/babel-plugin-jsx'
import { transformSync } from '@babel/core'
import i18nHost from '@opentiny/tiny-engine-i18n-host'
-import { CanvasRow, CanvasCol, CanvasRowColContainer } from '@opentiny/tiny-engine-builtin-component'
+import {
+ CanvasRow,
+ CanvasCol,
+ CanvasRowColContainer,
+ CanvasFlexBox,
+ CanvasSection
+} from '@opentiny/tiny-engine-builtin-component'
import { NODE_UID as DESIGN_UIDKEY, NODE_TAG as DESIGN_TAGKEY, NODE_LOOP as DESIGN_LOOPID } from '../../common'
import { context, conditions, setNode, getDesignMode, DESIGN_MODE } from './context'
@@ -66,6 +72,8 @@ const Mapper = {
slot: CanvasSlot,
Template: CanvasBox,
Img: CanvasImg,
+ CanvasSection,
+ CanvasFlexBox,
CanvasRow,
CanvasCol,
CanvasRowColContainer,
diff --git a/packages/plugins/materials/index.js b/packages/plugins/materials/index.js
index dc6136c03..95ae843fa 100644
--- a/packages/plugins/materials/index.js
+++ b/packages/plugins/materials/index.js
@@ -26,7 +26,16 @@ export default {
options: {
defaultTabId: 'engine.plugins.materials.component',
displayComponentIds: ['engine.plugins.materials.component', 'engine.plugins.materials.block'],
- basePropertyOptions
+ basePropertyOptions,
+ useBaseStyle: true,
+ blockBaseStyle: {
+ className: 'block-base-style',
+ style: 'margin: 16px;'
+ },
+ componentBaseStyle: {
+ className: 'component-base-style',
+ style: 'margin: 8px;'
+ }
},
components: {
header: MaterialHeader
diff --git a/packages/plugins/materials/src/composable/useMaterial.js b/packages/plugins/materials/src/composable/useMaterial.js
index 91365bfea..8e371085f 100644
--- a/packages/plugins/materials/src/composable/useMaterial.js
+++ b/packages/plugins/materials/src/composable/useMaterial.js
@@ -58,14 +58,19 @@ const getSnippet = (component) => {
const generateNode = ({ type, component }) => {
const snippet = getSnippet(component) || {}
+
const schema = {
componentName: component,
- props: {},
- ...snippet
+ ...snippet,
+ props: {
+ ...snippet.props,
+ className: getOptions(meta.id).useBaseStyle ? getOptions(meta.id).componentBaseStyle.className : ''
+ }
}
if (type === 'block') {
schema.componentType = 'Block'
+ schema.props.className = getOptions(meta.id).useBaseStyle ? getOptions(meta.id).blockBaseStyle.className : ''
}
return schema
diff --git a/packages/plugins/page/index.js b/packages/plugins/page/index.js
index b9b07781b..de0203d4c 100644
--- a/packages/plugins/page/index.js
+++ b/packages/plugins/page/index.js
@@ -19,6 +19,12 @@ export default {
...metaData,
apis: api,
entry,
+ options: {
+ pageBaseStyle: {
+ className: 'page-base-style',
+ style: 'padding: 24px;background: #FFFFFF;'
+ }
+ },
components: {
PageGeneral
},
diff --git a/packages/plugins/page/src/Main.vue b/packages/plugins/page/src/Main.vue
index 2101637cf..4305c78bf 100644
--- a/packages/plugins/page/src/Main.vue
+++ b/packages/plugins/page/src/Main.vue
@@ -69,7 +69,7 @@ export default {
},
setup() {
const { pageState } = useCanvas()
- const { pageSettingState, DEFAULT_PAGE, isTemporaryPage, initCurrentPageData } = usePage()
+ const { pageSettingState, getDefaultPage, isTemporaryPage, initCurrentPageData } = usePage()
const pageTreeRef = ref(null)
const ROOT_ID = pageSettingState.ROOT_ID
@@ -82,15 +82,24 @@ export default {
const createNewPage = (group) => {
closeFolderSettingPanel()
pageSettingState.isNew = true
- pageSettingState.currentPageData = {
- ...DEFAULT_PAGE,
- parentId: ROOT_ID,
- route: '',
- name: 'Untitled',
- page_content: {
- lifeCycles: {}
- },
- group
+ try {
+ const defaultPage = getDefaultPage()
+ if (!defaultPage) {
+ throw new Error('Failed to get default page configuration')
+ }
+ pageSettingState.currentPageData = {
+ ...getDefaultPage(),
+ ...defaultPage,
+ parentId: ROOT_ID,
+ route: '',
+ name: 'Untitled',
+ page_content: {
+ lifeCycles: {}
+ },
+ group
+ }
+ } catch (error) {
+ // console.error('Failed to create new page:', error)
}
pageSettingState.currentPageDataCopy = extend(true, {}, pageSettingState.currentPageData)
state.isFolder = false
diff --git a/packages/plugins/page/src/PageSetting.vue b/packages/plugins/page/src/PageSetting.vue
index 4558d2274..8c9e6dc08 100644
--- a/packages/plugins/page/src/PageSetting.vue
+++ b/packages/plugins/page/src/PageSetting.vue
@@ -121,7 +121,7 @@ export default {
setup(props, { emit }) {
const { requestCreatePage, requestDeletePage } = http
const {
- DEFAULT_PAGE,
+ getDefaultPage,
pageSettingState,
changeTreeData,
isCurrentDataSame,
@@ -161,7 +161,7 @@ export default {
}
const createPage = async () => {
- const { page_content, ...other } = DEFAULT_PAGE
+ const { page_content, ...other } = getDefaultPage()
const { page_content: page_content_state, ...pageSettingStateOther } = pageSettingState.currentPageData
const createParams = {
...other,
diff --git a/packages/plugins/page/src/composable/usePage.js b/packages/plugins/page/src/composable/usePage.js
index c99072cc4..ef8b1da8a 100644
--- a/packages/plugins/page/src/composable/usePage.js
+++ b/packages/plugins/page/src/composable/usePage.js
@@ -12,6 +12,7 @@
import { reactive, ref } from 'vue'
import { extend, isEqual } from '@opentiny/vue-renderless/common/object'
+import { getOptions } from '@opentiny/tiny-engine-meta-register'
const DEFAULT_PAGE = {
app: '',
@@ -56,6 +57,47 @@ const pageSettingState = reactive({
const isTemporaryPage = reactive({
saved: false
})
+
+const generateCssString = (pageOptions, materialsOptions) => {
+ if (!pageOptions?.pageBaseStyle?.className || !pageOptions?.pageBaseStyle?.style) {
+ return ''
+ }
+
+ const formatCssRule = (className, style) => `.${className} {\n ${style.trim()}\n}\n`
+ const baseStyle = `.${pageOptions.pageBaseStyle.className}{\r\n ${pageOptions.pageBaseStyle.style}\r\n}\r\n`
+
+ if (!materialsOptions.useBaseStyle) {
+ return baseStyle
+ }
+
+ return [
+ formatCssRule(pageOptions.pageBaseStyle.className, pageOptions.pageBaseStyle.style),
+ formatCssRule(materialsOptions.blockBaseStyle.className, materialsOptions.blockBaseStyle.style),
+ formatCssRule(materialsOptions.componentBaseStyle.className, materialsOptions.componentBaseStyle.style)
+ ].join('\n')
+}
+
+const getDefaultPage = () => {
+ const materialsOptions = getOptions('engine.plugins.materials')
+ const pageOptions = getOptions('engine.plugins.appmanage')
+
+ if (!materialsOptions || !pageOptions || !pageOptions.pageBaseStyle) {
+ return { ...DEFAULT_PAGE }
+ }
+
+ return {
+ ...DEFAULT_PAGE,
+ page_content: {
+ ...DEFAULT_PAGE.page_content,
+ props: {
+ ...DEFAULT_PAGE.page_content.props,
+ className: pageOptions.pageBaseStyle.className
+ },
+ css: generateCssString(pageOptions, materialsOptions)
+ }
+ }
+}
+
const isCurrentDataSame = () => {
const data = pageSettingState.currentPageData || {}
const dataCopy = pageSettingState.currentPageDataCopy || {}
@@ -134,7 +176,7 @@ const COMMON_PAGE_GROUP_ID = 1
export default () => {
return {
- DEFAULT_PAGE,
+ getDefaultPage,
selectedTemplateCard,
pageSettingState,
isTemporaryPage,
diff --git a/packages/plugins/robot/src/Main.vue b/packages/plugins/robot/src/Main.vue
index 9efd418bd..89d82b461 100644
--- a/packages/plugins/robot/src/Main.vue
+++ b/packages/plugins/robot/src/Main.vue
@@ -146,7 +146,7 @@ export default {
const selectedModel = ref(AIModelOptions[0])
const { confirm } = useModal()
- const { pageSettingState, DEFAULT_PAGE } = usePage()
+ const { pageSettingState, getDefaultPage } = usePage()
const ROOT_ID = pageSettingState.ROOT_ID
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))
watchEffect(() => {
@@ -174,7 +174,7 @@ export default {
pageSettingState.isNew = true
pageSettingState.isAIPage = true
pageSettingState.currentPageData = {
- ...DEFAULT_PAGE,
+ ...getDefaultPage(),
parentId: ROOT_ID,
route: 'temporaryPage',
name: 'TemporaryPage',
diff --git a/packages/settings/styles/src/components/spacing/SpacingSetting.vue b/packages/settings/styles/src/components/spacing/SpacingSetting.vue
index c906e2dba..d33a6c36e 100644
--- a/packages/settings/styles/src/components/spacing/SpacingSetting.vue
+++ b/packages/settings/styles/src/components/spacing/SpacingSetting.vue
@@ -45,7 +45,7 @@ export default {
emits: useEvent(),
setup(props, { emit }) {
let sliderFlag = true
- const options = [0, 10, 20, 40, 60, 100, 140, 220]
+ const options = [0, 4, 8, 12, 16, 20, 24, 32]
const isReset = computed(() => Boolean(props.property.value))
const isMargin = computed(
() => props.property.type === SPACING_PROPERTY.Margin || props.property.type === POSITION_PROPERTY.Position
diff --git a/packages/settings/styles/src/components/typography/TypographyGroup.vue b/packages/settings/styles/src/components/typography/TypographyGroup.vue
index 9d6c5ac13..92c431c9e 100644
--- a/packages/settings/styles/src/components/typography/TypographyGroup.vue
+++ b/packages/settings/styles/src/components/typography/TypographyGroup.vue
@@ -38,7 +38,7 @@
-
+
@@ -182,6 +187,22 @@ export default {
const { setPosition } = useModal()
const fontFamilyOptions = [
+ {
+ label: '微软雅黑',
+ value: '"Microsoft YaHei", "微软雅黑", sans-serif'
+ },
+ {
+ label: '苹方',
+ value: 'PingFang SC'
+ },
+ {
+ label: '黑体',
+ value: 'SimHei'
+ },
+ {
+ label: '宋体',
+ value: 'SimSun'
+ },
{
label: 'Arial',
value: 'Arial, "Helvetica Neue", Helvetica'
@@ -312,6 +333,9 @@ export default {
}
]
+ const sizes = ['9', '10', '11', '12', '14', '16', '18', '20', '24']
+ const sizeOptions = sizes.map((size) => ({ label: size, value: size }))
+
const alignOptions = [
{
icon: 'text-align-left',
@@ -389,7 +413,8 @@ export default {
const state = reactive({
value: '400',
- fontFamilyValue: 'Arial, "Helvetica Neue", Helvetica'
+ fontFamilyValue: '"Microsoft YaHei", "微软雅黑", sans-serif',
+ sizeValue: ''
})
const selectedAlign = ref('')
@@ -460,6 +485,12 @@ export default {
}
}
+ const selectFontSize = (type) => {
+ if (type) {
+ updateStyle({ 'font-size': type + 'px' })
+ }
+ }
+
const selectFontFamily = (type) => {
if (type) {
updateStyle({ [TYPO_PROPERTY.FontFamily]: type })
@@ -480,8 +511,10 @@ export default {
selectFontStyle,
selectedTextDecoration,
selectTextDecoration,
+ selectFontSize,
openSetting,
selectOptions,
+ sizeOptions,
state,
selectFontWeight,
fontFamilyOptions,
@@ -513,6 +546,11 @@ export default {
grid-template-columns: 45% auto;
}
+ &.font-split {
+ gap: 4px 8px;
+ grid-template-columns: 56% auto;
+ }
+
&.more {
grid-template-columns: 1fr;
}
@@ -609,6 +647,13 @@ export default {
.color-wrap {
width: 210px;
}
+ .font-size {
+ display: flex;
+ font-size: 12px;
+ color: var(--te-common-text-weaken);
+ align-items: center;
+ gap: 4px;
+ }
}
.typography-font-row {
diff --git a/packages/settings/styles/src/js/useStyle.js b/packages/settings/styles/src/js/useStyle.js
index cf93da8f5..f705aec27 100644
--- a/packages/settings/styles/src/js/useStyle.js
+++ b/packages/settings/styles/src/js/useStyle.js
@@ -12,7 +12,7 @@
import { computed, reactive, watch } from 'vue'
import { useBroadcastChannel } from '@vueuse/core'
-import { useCanvas, useHistory, useProperties as useProps } from '@opentiny/tiny-engine-meta-register'
+import { useCanvas, useHistory, useProperties as useProps, getOptions } from '@opentiny/tiny-engine-meta-register'
import { formatString } from '@opentiny/tiny-engine-common/js/ast'
import { constants, utils } from '@opentiny/tiny-engine-utils'
import { parser, stringify, getSelectorArr } from './parser'
@@ -255,7 +255,7 @@ watch(
(value) => value.pureSelector === classNameList && value.mouseState === mouseState
)
const style = matchStyles.length ? matchStyles[0].rules : {}
- state.style = style
+ state.style = { ...style }
},
{
deep: true
@@ -288,7 +288,7 @@ const updateGlobalStyle = (newSelector) => {
state.styleObject[currentSelector] = {
...(state.styleObject[currentSelector] || {}),
- rules: state.style
+ rules: { ...state.style }
}
if (!Object.keys(state.style).length) {
@@ -307,6 +307,13 @@ const updateStyle = (properties) => {
const { addHistory } = useHistory()
const { getSchema: getCanvasPageSchema, updateRect } = canvasApi.value
const schema = getSchema() || getCanvasPageSchema()
+ const pageOptions = getOptions('engine.plugins.appmanage')
+ const materialsOptions = getOptions('engine.plugins.materials')
+ const baseClassGroup = [
+ `.${pageOptions.pageBaseStyle.className}`,
+ `.${materialsOptions.blockBaseStyle.className}`,
+ `.${materialsOptions.componentBaseStyle.className}`
+ ]
schema.props = schema.props || {}
if (properties) {
@@ -321,7 +328,7 @@ const updateStyle = (properties) => {
const classNames = schema.props.className || ''
// 不存在选择器,需要生成一个随机类名,添加到当前选中组件中,然后写入到全局样式
- if (!currentSelector && typeof classNames === 'string') {
+ if ((!currentSelector || baseClassGroup.includes(currentSelector)) && typeof classNames === 'string') {
randomClassName = genRandomClassNames(schema?.componentName || 'component')
let newClassNames = randomClassName.slice(1)
diff --git a/packages/utils/src/utils/index.js b/packages/utils/src/utils/index.js
index d7f16ddf2..5e570f1a5 100644
--- a/packages/utils/src/utils/index.js
+++ b/packages/utils/src/utils/index.js
@@ -381,3 +381,68 @@ export const string2Obj = (string) => {
return obj
}
+
+/**
+ * 指定-转化为驼峰命名
+ * @param {*} string
+ * @returns
+ */
+
+export const toCamelCase = (str) => {
+ return str.replace(/[-\s]+(.)?/g, (match, group1) => (group1 ? group1.toUpperCase() : ''))
+}
+
+/**
+ * 驼峰转化为连字符形式
+ * @param {*} string
+ * @returns
+ */
+
+export const convertCamelToKebab = (string) => {
+ return string
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
+ .toLowerCase()
+}
+
+/**
+ * 样式字符串转对象
+ * @param {*} string
+ * @returns
+ */
+
+export const styleString2Obj = (styleString) => {
+ if (!styleString || typeof styleString !== 'string') {
+ return {}
+ }
+
+ const styles = styleString.trim().split(';')
+ const styleObject = styles.reduce((obj, pair) => {
+ const colonIndex = pair.indexOf(':')
+ if (colonIndex === -1) return obj
+ const key = pair.slice(0, colonIndex)
+ const value = pair.slice(colonIndex + 1)
+ if (key && value) {
+ obj[toCamelCase(key.trim())] = value.trim()
+ }
+ return obj
+ }, {})
+ return styleObject
+}
+
+/**
+ * 对象转样式字符串
+ * @param {*} string
+ * @returns
+ */
+
+export const obj2StyleString = (obj) => {
+ if (!obj || typeof obj !== 'object') {
+ return ''
+ }
+
+ return Object.entries(obj)
+ .filter(([, value]) => value != null)
+ .map(([key, value]) => `${convertCamelToKebab(key)}: ${value}`)
+ .join('; ')
+}
diff --git a/packages/vue-generator/src/constant/index.js b/packages/vue-generator/src/constant/index.js
index b45bf828c..eb0d9c719 100644
--- a/packages/vue-generator/src/constant/index.js
+++ b/packages/vue-generator/src/constant/index.js
@@ -2195,6 +2195,20 @@ export const BUILTIN_COMPONENTS_MAP = [
package: '@opentiny/tiny-engine-builtin-component',
version: '^1.0.1',
destructuring: true
+ },
+ {
+ componentName: 'CanvasFlexBox',
+ exportName: 'CanvasFlexBox',
+ package: '@opentiny/tiny-engine-builtin-component',
+ version: '^1.0.1',
+ destructuring: true
+ },
+ {
+ componentName: 'CanvasSection',
+ exportName: 'CanvasSection',
+ package: '@opentiny/tiny-engine-builtin-component',
+ version: '^1.0.1',
+ destructuring: true
}
]