179 lines
5.0 KiB
TypeScript
179 lines
5.0 KiB
TypeScript
/**
|
|
* Editor Styles Configuration
|
|
* 编辑器样式配置
|
|
*/
|
|
|
|
import { type EditorStyleConfig } from '../types';
|
|
|
|
export const defaultStyleConfig: EditorStyleConfig = {
|
|
hover: {
|
|
outline: '1px dashed var(--editor-accent)',
|
|
outlineOffset: '0px',
|
|
cursor: 'pointer',
|
|
},
|
|
selected: {
|
|
outline: '1px solid var(--editor-accent)',
|
|
outlineOffset: '2px',
|
|
cursor: 'pointer',
|
|
},
|
|
badge: {
|
|
enabled: true,
|
|
position: 'top-left',
|
|
offset: {
|
|
top: '-24px',
|
|
left: '0',
|
|
},
|
|
background: 'var(--editor-accent)',
|
|
color: 'white',
|
|
padding: '2px 8px',
|
|
borderRadius: '3px',
|
|
fontSize: '12px',
|
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
zIndex: 10000,
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Generate CSS from style configuration
|
|
* 从样式配置生成CSS
|
|
*/
|
|
export function generateEditorCSS(config: EditorStyleConfig = defaultStyleConfig, enableMoveable: boolean | undefined, helperBox: boolean | undefined): string {
|
|
const { hover, selected, badge } = config;
|
|
const scope = '.html-visual-editor';
|
|
|
|
let css = `
|
|
${scope} {
|
|
position: relative;
|
|
}
|
|
|
|
${scope} .hover-highlight {
|
|
outline: ${helperBox ? 'none' : hover.outline} !important;
|
|
outline-offset: ${hover.outlineOffset};
|
|
// position: relative;
|
|
cursor: ${hover.cursor};
|
|
${hover.backgroundColor ? `background-color: ${hover.backgroundColor} !important;` : ''}
|
|
}
|
|
|
|
${scope} .selected-element {
|
|
outline: ${enableMoveable || helperBox ? 'none' : selected.outline} !important;
|
|
outline-offset: ${selected.outlineOffset};
|
|
cursor: ${selected.cursor};
|
|
// position: relative;
|
|
${selected.backgroundColor ? `background-color: ${selected.backgroundColor} !important;` : ''}
|
|
}
|
|
|
|
${scope} [contenteditable="true"] {
|
|
user-select: text;
|
|
-webkit-font-smoothing: inherit !important;
|
|
-moz-osx-font-smoothing: inherit !important;
|
|
text-rendering: inherit !important;
|
|
}
|
|
|
|
${scope} [contenteditable="true"]:focus {
|
|
outline: ${enableMoveable || helperBox ? 'none' : selected.outline} !important;
|
|
outline-offset: ${selected.outlineOffset};
|
|
cursor: text !important;
|
|
}
|
|
|
|
${scope} [contenteditable="true"]:empty:not(:focus)::before {
|
|
content: attr(data-placeholder);
|
|
color: var(--muted-foreground);
|
|
}
|
|
|
|
.moveable-control-box>.moveable-line{
|
|
background: var(--editor-accent) !important;
|
|
height: 2px !important;
|
|
}
|
|
|
|
.moveable-control-box>.moveable-control:not(.moveable-e):not(.moveable-w){
|
|
border: 2px solid var(--editor-accent) !important;
|
|
background: var(--editor-surface) !important;
|
|
}
|
|
|
|
.moveable-control-box>.moveable-control.moveable-e{
|
|
width: 10px !important;
|
|
height: 22px !important;
|
|
border-radius: 10px !important;
|
|
margin-top: -11px !important;
|
|
margin-left: -5px !important;
|
|
border: 2px solid var(--editor-accent) !important;
|
|
background: var(--editor-surface) !important;
|
|
}
|
|
.moveable-control-box>.moveable-control.moveable-w{
|
|
width: 10px !important;
|
|
height: 22px !important;
|
|
border-radius: 7px !important;
|
|
border: 2px solid var(--editor-accent) !important;
|
|
background: var(--editor-surface) !important;
|
|
margin-top: -11px !important;
|
|
margin-left: -5px !important;
|
|
}
|
|
`;
|
|
|
|
// 如果启用角标,添加 ::before 伪元素样式
|
|
if (badge.enabled) {
|
|
const badgePosition = getBadgePositionCSS(badge.position || 'top-left', badge.offset);
|
|
css += `
|
|
${scope} #html-editor-helper-box::before {
|
|
content: attr(data-element-type);
|
|
position: absolute;
|
|
${badgePosition}
|
|
background: ${badge.background};
|
|
color: ${badge.color};
|
|
padding: ${badge.padding};
|
|
border-radius: ${badge.borderRadius};
|
|
font-size: ${badge.fontSize};
|
|
font-family: ${badge.fontFamily};
|
|
white-space: nowrap;
|
|
z-index: ${badge.zIndex};
|
|
}}
|
|
`;
|
|
}
|
|
|
|
return css;
|
|
}
|
|
|
|
/**
|
|
* Get badge position CSS based on position type
|
|
* 根据位置类型获取角标位置CSS
|
|
*/
|
|
function getBadgePositionCSS(
|
|
position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right',
|
|
offset?: { top?: string; left?: string; right?: string; bottom?: string }
|
|
): string {
|
|
const defaultOffset = offset || {};
|
|
|
|
switch (position) {
|
|
case 'top-left':
|
|
return `
|
|
top: ${defaultOffset.top || '-24px'};
|
|
left: ${defaultOffset.left || '0'};
|
|
`;
|
|
case 'top-right':
|
|
return `
|
|
top: ${defaultOffset.top || '-24px'};
|
|
right: ${defaultOffset.right || '0'};
|
|
`;
|
|
case 'bottom-left':
|
|
return `
|
|
bottom: ${defaultOffset.bottom || '-24px'};
|
|
left: ${defaultOffset.left || '0'};
|
|
`;
|
|
case 'bottom-right':
|
|
return `
|
|
bottom: ${defaultOffset.bottom || '-24px'};
|
|
right: ${defaultOffset.right || '0'};
|
|
`;
|
|
default:
|
|
return `
|
|
top: ${defaultOffset.top || '-24px'};
|
|
left: ${defaultOffset.left || '0'};
|
|
`;
|
|
}
|
|
}
|
|
|
|
export default {
|
|
defaultStyleConfig,
|
|
generateEditorCSS,
|
|
};
|