jvs-ppt-ui 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/lib/jvs-ppt-ui.es.js +22611 -21764
- package/dist/lib/jvs-ppt-ui.umd.js +102 -101
- package/dist/lib/style.css +1 -1
- package/package.json +7 -7
- package/scripts/check_connectors.cjs +25 -0
- package/scripts/check_slide1.cjs +11 -0
- package/scripts/check_slide123.cjs +25 -0
- package/scripts/convert-fonts-to-woff2.cjs +97 -0
- package/scripts/extract-slides.ts +149 -0
- package/scripts/find_candidate_pptx.cjs +34 -0
- package/scripts/find_orange_slide.cjs +29 -0
- package/scripts/generate-complete-ppt-preview.js +385 -0
- package/scripts/inspect_315_327.cjs +19 -0
- package/scripts/mcp-smoke-test.js +568 -0
- package/scripts/patch-pptxtojson.cjs +81 -0
- package/scripts/verify-fonts.cjs +20 -0
- package/src/App.vue +53 -53
- package/src/components/AIPptDialog.vue +2 -0
- package/src/components/CanvasArea.vue +124 -62
- package/src/components/Header.vue +364 -142
- package/src/components/PptEditor.vue +26 -15
- package/src/components/PresentationMode.vue +24 -4
- package/src/components/SidebarRight.vue +8 -1
- package/src/components/SvgChart.vue +5 -2
- package/src/components/TemplateGallery.vue +1321 -866
- package/src/components/Toolbar.vue +243 -22
- package/src/components/canvas/CanvasTransformHandles.vue +5 -1
- package/src/components/canvas/elements/CanvasShapeElement.vue +98 -19
- package/src/components/canvas/elements/CanvasTextElement.vue +39 -9
- package/src/components/canvas/textSelectionOverlay.ts +305 -0
- package/src/composables/canvas/useCanvasAlignment.ts +286 -238
- package/src/composables/canvas/useCanvasContextMenu.ts +53 -22
- package/src/composables/canvas/useCanvasFormatting.ts +35 -12
- package/src/composables/canvas/useCanvasTable.ts +52 -24
- package/src/composables/canvas/useCanvasText.ts +12 -0
- package/src/composables/canvas/useCanvasTransform.ts +2 -2
- package/src/composables/sidebar/useSidebarElementTransform.ts +5 -5
- package/src/composables/sidebar/useSidebarShapeFormat.ts +2 -2
- package/src/composables/useSlides.ts +482 -127
- package/src/style.css +88 -0
- package/src/types/index.ts +4 -0
- package/src/utils/pptxShapes.ts +1 -1
- package/src/utils/pptxShapesLazy.ts +39 -0
- package/src/utils/svgPathParser.ts +12 -1
package/src/style.css
CHANGED
|
@@ -50,6 +50,68 @@
|
|
|
50
50
|
padding: 0;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* -------------------------------------------------------------
|
|
54
|
+
* 🛡️ [CSS Defensive Shield] 容器级样式防御屏障
|
|
55
|
+
* 彻底切断外部宿主全局样式(如 button, svg, *, line-height 等)的侵入
|
|
56
|
+
* ------------------------------------------------------------- */
|
|
57
|
+
.jvs-ppt-editor-root {
|
|
58
|
+
font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif) !important;
|
|
59
|
+
font-size: 14px !important;
|
|
60
|
+
line-height: 1.5 !important;
|
|
61
|
+
color: #0f172a !important;
|
|
62
|
+
text-align: left !important;
|
|
63
|
+
letter-spacing: normal !important;
|
|
64
|
+
word-spacing: normal !important;
|
|
65
|
+
box-sizing: border-box !important;
|
|
66
|
+
-webkit-font-smoothing: antialiased !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.jvs-ppt-editor-root *,
|
|
70
|
+
.jvs-ppt-editor-root *::before,
|
|
71
|
+
.jvs-ppt-editor-root *::after {
|
|
72
|
+
box-sizing: border-box;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* 强行重置外部宿主全局 button 样式侵入 */
|
|
76
|
+
.jvs-ppt-editor-root button {
|
|
77
|
+
font-family: inherit;
|
|
78
|
+
font-size: inherit;
|
|
79
|
+
line-height: normal;
|
|
80
|
+
text-transform: none;
|
|
81
|
+
margin: 0;
|
|
82
|
+
border: none;
|
|
83
|
+
background: transparent;
|
|
84
|
+
outline: none;
|
|
85
|
+
box-shadow: none;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
-webkit-appearance: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* 强行重置外部宿主全局 svg 样式侵入 */
|
|
91
|
+
.jvs-ppt-editor-root svg {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
vertical-align: middle;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* 强行重置外部宿主全局 a 标签样式侵入 */
|
|
97
|
+
.jvs-ppt-editor-root a {
|
|
98
|
+
color: inherit;
|
|
99
|
+
text-decoration: none;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* 强行重置外部宿主全局 button 样式侵入(防 text-indent, line-height, text-transform, pseudo elements) */
|
|
103
|
+
.jvs-ppt-editor-root button {
|
|
104
|
+
box-sizing: border-box !important;
|
|
105
|
+
text-transform: none !important;
|
|
106
|
+
text-indent: 0 !important;
|
|
107
|
+
letter-spacing: normal !important;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.jvs-ppt-editor-root button::before,
|
|
111
|
+
.jvs-ppt-editor-root button::after {
|
|
112
|
+
content: none !important;
|
|
113
|
+
}
|
|
114
|
+
|
|
53
115
|
button,
|
|
54
116
|
select,
|
|
55
117
|
input,
|
|
@@ -1024,6 +1086,12 @@ td.selected-cell,
|
|
|
1024
1086
|
outline: none !important;
|
|
1025
1087
|
}
|
|
1026
1088
|
|
|
1089
|
+
/* 焦点(光标)所在的唯一选中格:不显示选中蒙层,避免"光标在单元格里还显示选中效果" */
|
|
1090
|
+
td.selected-cell.focused-cell,
|
|
1091
|
+
.canvas-element td.selected-cell.focused-cell {
|
|
1092
|
+
background-image: none !important;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1027
1095
|
.table-tick-dot {
|
|
1028
1096
|
width: 6px !important;
|
|
1029
1097
|
height: 6px !important;
|
|
@@ -4013,6 +4081,26 @@ td.selected-cell,
|
|
|
4013
4081
|
background-color: rgba(100, 116, 139, 0.45) !important;
|
|
4014
4082
|
}
|
|
4015
4083
|
|
|
4084
|
+
/* 画布编辑态自绘选区高亮:原生 ::selection 的几何跟随行盒/字体度量
|
|
4085
|
+
(CJK 回退字体 ascent 偏大 → 高亮条顶空白过多、行间空白带宽),
|
|
4086
|
+
CSS 无法控制其几何,故编辑态改用 overlay 绘制并隐藏原生高亮。
|
|
4087
|
+
.text-selection-overlay-active 挂在与 editable 同坐标系的宿主上,
|
|
4088
|
+
只有 overlay 成功画出条时才添加,失败自动回落原生表现。 */
|
|
4089
|
+
.text-selection-overlay-active ::selection {
|
|
4090
|
+
background-color: transparent !important;
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
.text-selection-overlay {
|
|
4094
|
+
pointer-events: none;
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
.text-selection-bar {
|
|
4098
|
+
position: absolute;
|
|
4099
|
+
background-color: rgba(100, 116, 139, 0.45);
|
|
4100
|
+
border-radius: 2px;
|
|
4101
|
+
box-sizing: border-box;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4016
4104
|
/* Custom cursor for format painter mode */
|
|
4017
4105
|
.main-slide.format-painting-mode,
|
|
4018
4106
|
.main-slide.format-painting-mode * {
|
package/src/types/index.ts
CHANGED
|
@@ -94,6 +94,8 @@ export interface PptEditorConfig {
|
|
|
94
94
|
title?: string
|
|
95
95
|
/** 是否显示左上角主菜单按钮(导入/导出/快捷键等弹窗菜单),默认为 true */
|
|
96
96
|
showMenu?: boolean
|
|
97
|
+
/** 工具栏布局模式:'auto' (自适应折叠)、'more' (收纳更多功能模式,适合弹窗/小屏)、'full' (全展开),默认为 'auto' */
|
|
98
|
+
toolbarMode?: 'auto' | 'more' | 'full'
|
|
97
99
|
/** 是否启用 AI PPT 智能生成与一键美化功能。未配置或为 false 时不显示一键美化功能 */
|
|
98
100
|
enableAi?: boolean
|
|
99
101
|
/** AI 一键美化请求接口地址。如果未配置或未开启,则不显示一键美化功能 */
|
|
@@ -142,6 +144,8 @@ export interface PptEditorProps {
|
|
|
142
144
|
showHeader?: boolean
|
|
143
145
|
/** 是否显示左上角主菜单按钮(导入/导出/快捷键等弹窗菜单),默认为 true */
|
|
144
146
|
showMenu?: boolean
|
|
147
|
+
/** 工具栏布局模式:'auto' (自适应折叠)、'more' (收纳更多功能模式,适合弹窗/小屏)、'full' (全展开),默认为 'auto' */
|
|
148
|
+
toolbarMode?: 'auto' | 'more' | 'full'
|
|
145
149
|
/** 是否显示左侧缩略图导航栏 */
|
|
146
150
|
showSidebarLeft?: boolean
|
|
147
151
|
/** 是否显示右侧属性面板 */
|
package/src/utils/pptxShapes.ts
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { shallowRef } from 'vue'
|
|
2
|
+
import type { ShapeListItem, ShapePathFormula } from './pptxShapes'
|
|
3
|
+
|
|
4
|
+
type PptxShapesModule = typeof import('./pptxShapes')
|
|
5
|
+
|
|
6
|
+
// 98KB 形状公式/预设表从启动 chunk 拆出:本模块求值时即后台加载(不阻塞首屏),
|
|
7
|
+
// 表就绪后写入 shallowRef,依赖它的 computed(如形状调整点 keypoints)会自动重算。
|
|
8
|
+
export const pptxShapeFormulas = shallowRef<Record<string, ShapePathFormula> | null>(null)
|
|
9
|
+
export const pptxShapeList = shallowRef<ShapeListItem[] | null>(null)
|
|
10
|
+
|
|
11
|
+
const EMPTY_FORMULAS: Record<string, ShapePathFormula> = {}
|
|
12
|
+
const EMPTY_LIST: ShapeListItem[] = []
|
|
13
|
+
|
|
14
|
+
/** 同步读取形状公式表;未就绪时返回空表(调用点均有 if (formulaObj) 守卫,安全降级) */
|
|
15
|
+
export function shapeFormulas(): Record<string, ShapePathFormula> {
|
|
16
|
+
return pptxShapeFormulas.value ?? EMPTY_FORMULAS
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 同步读取形状预设列表;未就绪时返回空数组 */
|
|
20
|
+
export function shapeList(): ShapeListItem[] {
|
|
21
|
+
return pptxShapeList.value ?? EMPTY_LIST
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let loadPromise: Promise<PptxShapesModule> | null = null
|
|
25
|
+
|
|
26
|
+
/** 确保形状表已加载;文件导入/DSL 编译等异步解析路径在调用解析器前 await 一次 */
|
|
27
|
+
export function ensurePptxShapes(): Promise<PptxShapesModule> {
|
|
28
|
+
if (!loadPromise) {
|
|
29
|
+
loadPromise = import('./pptxShapes').then(mod => {
|
|
30
|
+
pptxShapeFormulas.value = mod.SHAPE_PATH_FORMULAS
|
|
31
|
+
pptxShapeList.value = mod.SHAPE_LIST
|
|
32
|
+
return mod
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
return loadPromise
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 启动即后台预载:与首屏渲染并行,用户首次交互(插形状/拖调整点/导文件)前早已就绪
|
|
39
|
+
ensurePptxShapes()
|
|
@@ -71,6 +71,13 @@ export const getSvgPathRange = (path: string) => {
|
|
|
71
71
|
for (const item of pathData.commands) {
|
|
72
72
|
if ('x' in item) xList.push(item.x)
|
|
73
73
|
if ('y' in item) yList.push(item.y)
|
|
74
|
+
// 贝塞尔控制点也纳入边界:曲线的实际极值可能只出现在控制点上
|
|
75
|
+
// (端点算出的范围会偏小,导致 viewBox 被错误收窄、形状被拉伸),
|
|
76
|
+
// 与 normalizeSvgPath 的边界口径保持一致。
|
|
77
|
+
if ('x1' in item) xList.push(item.x1)
|
|
78
|
+
if ('y1' in item) yList.push(item.y1)
|
|
79
|
+
if ('x2' in item) xList.push(item.x2)
|
|
80
|
+
if ('y2' in item) yList.push(item.y2)
|
|
74
81
|
}
|
|
75
82
|
return {
|
|
76
83
|
minX: Math.min(...xList),
|
|
@@ -102,9 +109,13 @@ export const normalizeSvgPath = (path: string) => {
|
|
|
102
109
|
|
|
103
110
|
const xList: number[] = []
|
|
104
111
|
const yList: number[] = []
|
|
105
|
-
for (const item of pathData.commands) {
|
|
112
|
+
for (const item of pathData.commands as any[]) {
|
|
106
113
|
if ('x' in item) xList.push(item.x)
|
|
107
114
|
if ('y' in item) yList.push(item.y)
|
|
115
|
+
if ('x1' in item) xList.push(item.x1)
|
|
116
|
+
if ('y1' in item) yList.push(item.y1)
|
|
117
|
+
if ('x2' in item) xList.push(item.x2)
|
|
118
|
+
if ('y2' in item) yList.push(item.y2)
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
if (xList.length === 0 || yList.length === 0) {
|