<template>
<plugin-panel
title="样式"
:fixed-panels="fixedPanels"
:fixed-name="PLUGIN_NAME.Styles"
:is-show-collapse-icon="true"
:show-bottom-border="true"
@updateCollapseStatus="updateCollapseStatus"
@close="$emit('close')"
>
<template #content>
<div class="style-editor">
<div class="line-style">
<span class="line-text"> 行内样式 </span>
<div class="inline-style">
<component
:is="CodeConfigurator"
v-if="state.lineStyleDisable"
:buttonShowContent="true"
:modelValue="state.styleContent"
title="编辑行内样式"
:button-text="state.inlineBtnText"
language="css"
single
@save="save"
></component>
<div v-if="!state.lineStyleDisable">
<tiny-input v-model="state.propertiesList" class="inline-bind-style"> </tiny-input>
</div>
<component
:is="VariableConfigurator"
ref="bindVariable"
:model-value="state.bindModelValue"
name="advance"
@update:modelValue="setConfig"
>
</component>
</div>
</div>
</div>
<class-names-container></class-names-container>
<tiny-collapse v-model="activeNames" @change="handoverGroup">
<tiny-collapse-item title="布局" name="layout">
<layout-group :display="state.style.display" @update="updateStyle" />
<flex-box v-if="state.style.display === 'flex'" :style="state.style" @update="updateStyle"></flex-box>
<grid-box v-if="state.style.display === 'grid'" :style="state.style" @update="updateStyle"></grid-box>
</tiny-collapse-item>
<tiny-collapse-item title="间距" name="spacing">
<spacing-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="尺寸" name="size">
<size-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="定位" name="position">
<position-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="文本" name="typography">
<typography-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="背景" name="backgrounds">
<background-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="边框" name="borders">
<border-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
<tiny-collapse-item title="效果" name="effects" class="effects-style">
<effect-group :style="state.style" @update="updateStyle" />
</tiny-collapse-item>
</tiny-collapse>
</template>
</plugin-panel>
</template>
<script>
/* metaService: engine.setting.styles.Main */
import { watch, ref, reactive, provide } from 'vue'
import { Collapse, CollapseItem, Input } from '@opentiny/vue'
import { useLayout, useHistory, useCanvas, useProperties, getConfigurator } from '@opentiny/tiny-engine-meta-register'
import {
SizeGroup,
LayoutGroup,
FlexBox,
GridBox,
PositionGroup,
BorderGroup,
SpacingGroup,
BackgroundGroup,
EffectGroup,
TypographyGroup,
ClassNamesContainer
} from './components'
import { CSS_TYPE } from './js/cssType'
import useStyle from './js/useStyle'
import { PluginPanel } from '@opentiny/tiny-engine-common'
import { styleStrRemoveRoot } from './js/cssConvert'
export default {
components: {
PluginPanel,
SizeGroup,
LayoutGroup,
FlexBox,
GridBox,
PositionGroup,
BorderGroup,
SpacingGroup,
BackgroundGroup,
TypographyGroup,
EffectGroup,
ClassNamesContainer,
TinyCollapse: Collapse,
TinyCollapseItem: CollapseItem,
TinyInput: Input
},
props: {
fixedPanels: {
type: Array
}
},
setup(props, { emit }) {
const CodeConfigurator = getConfigurator('CodeConfigurator')
const VariableConfigurator = getConfigurator('VariableConfigurator')
const styleCategoryGroup = [
'layout',
'spacing',
'size',
'position',
'typography',
'backgrounds',
'borders',
'effects'
]
const isCollapsed = ref(false)
const activeNames = ref(styleCategoryGroup)
const { getCurrentSchema } = useCanvas()
// 获取当前节点 style 对象
const { state, updateStyle } = useStyle() // updateStyle
const { addHistory } = useHistory()
const { getSchema, setProp } = useProperties()
const { PLUGIN_NAME } = useLayout()
const panelState = reactive({
emitEvent: emit
})
provide('panelState', panelState)
const handoverGroup = (actives) => {
if (isCollapsed.value) {
activeNames.value = actives.length > 1 ? actives.shift() : actives
}
}
const updateStyleToSchema = (value) => {
const schema = getSchema()
if (schema) {
setProp('style', value)
return
}
const { getSchema: getCanvasPageSchema, updateSchema } = useCanvas()
const pageSchema = getCanvasPageSchema()
// TODO: 当 style 为空时,支持移除 style key
updateSchema({ props: { ...(pageSchema.props || {}), style: value } })
}
// 保存编辑器内容,并回写到 schema
const save = ({ content }) => {
const { updateRect } = useCanvas().canvasApi.value
const styleString = styleStrRemoveRoot(content)
state.styleContent = content
updateStyleToSchema(styleString)
addHistory()
updateRect()
}
const setConfig = (value) => {
const { updateRect } = useCanvas().canvasApi.value
if (value !== '') {
updateStyleToSchema(value)
state.propertiesList = `已绑定:${value.value}`
state.lineStyleDisable = false
addHistory()
} else {
updateStyleToSchema('')
state.propertiesList = '编辑行内样式'
state.lineStyleDisable = true
addHistory()
}
updateRect()
}
watch(
() => getCurrentSchema(),
(val) => {
if (val?.props?.style?.value) {
state.lineStyleDisable = false
state.propertiesList = `已绑定:${val.props.style?.value}`
state.bindModelValue = val.props.style
} else {
state.lineStyleDisable = true
state.propertiesList = '编辑行内样式'
state.bindModelValue = null
}
},
{
deep: true
}
)
const updateCollapseStatus = (val) => {
isCollapsed.value = val
}
watch(
() => isCollapsed.value,
() => {
if (isCollapsed.value) {
activeNames.value = []
} else {
activeNames.value = styleCategoryGroup
}
}
)
return {
updateCollapseStatus,
PLUGIN_NAME,
CodeConfigurator,
VariableConfigurator,
state,
activeNames,
CSS_TYPE,
open,
handoverGroup,
save,
close,
updateStyle,
setConfig,
isCollapsed
}
}
}
</script>
<style lang="less" scoped>
.style-editor {
justify-content: space-around;
margin-top: 12px;
column-gap: 8px;
.line-style {
padding: 0 8px 0 12px;
display: block;
font-size: 12px;
.line-text {
display: block;
margin-bottom: 8px;
font-size: 12px;
color: var(--te-styles-common-text-color-secondary);
}
}
.inline-style {
display: flex;
align-items: center;
:deep(.editor-wrap) {
display: flex;
.tiny-button {
padding: 0 16px;
border-radius: 8px;
width: 216px;
text-align: left;
color: var(--te-styles-common-text-color-primary);
}
.tiny-button:hover {
background: none;
border-color: var(--te-styles-common-border-color);
}
}
.inline-bind-style {
:deep(.tiny-input__inner) {
width: 216px;
pointer-events: none;
background: var(--te-styles-editor-bg-color);
color: var(--te-styles-editor-font-text-color);
border-color: var(--te-styles-editor-border-color);
}
}
}
}
.dots {
display: inline-block;
margin-left: 4px;
vertical-align: middle;
border: 2px solid var(--te-styles-editor-border-color);
border-radius: 2px;
}
</style>