diff --git a/package-lock.json b/package-lock.json
index afda2f55..42843d06 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"nanoid": "^4.0.0",
"pinia": "^2.0.32",
"pptxgenjs": "^3.11.0",
+ "pptxtojson": "^0.0.8",
"prosemirror-commands": "^1.3.0",
"prosemirror-dropcursor": "^1.6.0",
"prosemirror-gapcursor": "^1.3.1",
@@ -40,8 +41,7 @@
"svg-arc-to-cubic-bezier": "^3.2.0",
"svg-pathdata": "^6.0.0",
"tinycolor2": "^1.6.0",
- "vue": "^3.2.47",
- "vuedraggable": "^4.1.0"
+ "vue": "^3.2.47"
},
"devDependencies": {
"@commitlint/cli": "^17.4.4",
@@ -11734,6 +11734,16 @@
"node": ">=14.0.0"
}
},
+ "node_modules/pptxtojson": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/pptxtojson/-/pptxtojson-0.0.8.tgz",
+ "integrity": "sha512-9RDoPhTF9Nq7xlJbzmi05lfLV4TVa7sATX5uUmzWEj5mZyQ1SymIU8e6E1/h86/4BUVB0DbM9blwjCBXjiVlpw==",
+ "dependencies": {
+ "jszip": "^3.10.1",
+ "tinycolor2": "1.6.0",
+ "txml": "^5.1.1"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -12278,7 +12288,6 @@
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
"integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -12689,7 +12698,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -13338,7 +13346,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dev": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
@@ -14395,6 +14402,23 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
+ "node_modules/txml": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/txml/-/txml-5.1.1.tgz",
+ "integrity": "sha512-TwMDLnXQ09enNaxybLVvKZU7rqog8LgnuAs4ZYXM0nV0eu10iLsSFwlX3AEknAXXtH1wT3CYfoiXAjyBexcmuw==",
+ "dependencies": {
+ "through2": "^3.0.1"
+ }
+ },
+ "node_modules/txml/node_modules/through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmmirror.com/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -14887,22 +14911,6 @@
"vue": "^3.0.0"
}
},
- "node_modules/vuedraggable": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
- "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
- "dependencies": {
- "sortablejs": "1.14.0"
- },
- "peerDependencies": {
- "vue": "^3.0.1"
- }
- },
- "node_modules/vuedraggable/node_modules/sortablejs": {
- "version": "1.14.0",
- "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
- "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
- },
"node_modules/w3c-keyname": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
@@ -24667,6 +24675,16 @@
}
}
},
+ "pptxtojson": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/pptxtojson/-/pptxtojson-0.0.8.tgz",
+ "integrity": "sha512-9RDoPhTF9Nq7xlJbzmi05lfLV4TVa7sATX5uUmzWEj5mZyQ1SymIU8e6E1/h86/4BUVB0DbM9blwjCBXjiVlpw==",
+ "requires": {
+ "jszip": "^3.10.1",
+ "tinycolor2": "1.6.0",
+ "txml": "^5.1.1"
+ }
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -25104,7 +25122,6 @@
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
"integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
- "dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -25406,8 +25423,7 @@
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safe-regex-test": {
"version": "1.0.0",
@@ -25928,7 +25944,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dev": true,
"requires": {
"safe-buffer": "~5.2.0"
}
@@ -26708,6 +26723,25 @@
}
}
},
+ "txml": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/txml/-/txml-5.1.1.tgz",
+ "integrity": "sha512-TwMDLnXQ09enNaxybLVvKZU7rqog8LgnuAs4ZYXM0nV0eu10iLsSFwlX3AEknAXXtH1wT3CYfoiXAjyBexcmuw==",
+ "requires": {
+ "through2": "^3.0.1"
+ },
+ "dependencies": {
+ "through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmmirror.com/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "requires": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ }
+ }
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -27071,21 +27105,6 @@
"is-plain-object": "3.0.1"
}
},
- "vuedraggable": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
- "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
- "requires": {
- "sortablejs": "1.14.0"
- },
- "dependencies": {
- "sortablejs": {
- "version": "1.14.0",
- "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
- "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
- }
- }
- },
"w3c-keyname": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
diff --git a/package.json b/package.json
index 416e4d56..20d59b35 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"nanoid": "^4.0.0",
"pinia": "^2.0.32",
"pptxgenjs": "^3.11.0",
+ "pptxtojson": "^0.0.8",
"prosemirror-commands": "^1.3.0",
"prosemirror-dropcursor": "^1.6.0",
"prosemirror-gapcursor": "^1.3.1",
diff --git a/src/configs/shapes.ts b/src/configs/shapes.ts
index 8439c40d..622e64f0 100644
--- a/src/configs/shapes.ts
+++ b/src/configs/shapes.ts
@@ -10,6 +10,7 @@ export interface ShapePoolItem {
special?: boolean
pathFormula?: ShapePathFormulasKeys
outlined?: boolean
+ pptxShapeType?: string
}
interface ShapeListItem {
@@ -228,47 +229,56 @@ export const SHAPE_LIST: ShapeListItem[] = [
children: [
{
viewBox: [200, 200],
- path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z'
+ path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z',
+ pptxShapeType: 'rect',
},
{
viewBox: [200, 200],
path: 'M 50 0 L 150 0 Q 200 0 200 50 L 200 150 Q 200 200 150 200 L 50 200 Q 0 200 0 150 L 0 50 Q 0 0 50 0 Z',
pathFormula: ShapePathFormulasKeys.ROUND_RECT,
+ pptxShapeType: 'roundRect',
},
{
viewBox: [200, 200],
path: 'M 0 200 L 0 0 L 150 0 L 200 50 L 200 200 Z',
pathFormula: ShapePathFormulasKeys.CUT_RECT_SINGLE,
+ pptxShapeType: 'snip1Rect',
},
{
viewBox: [200, 200],
path: 'M 0 50 L 50 0 L 150 0 L 200 50 L 200 200 L 0 200 Z',
pathFormula: ShapePathFormulasKeys.CUT_RECT_SAMESIDE,
+ pptxShapeType: 'snip2SameRect',
},
{
viewBox: [200, 200],
path: 'M 0 150 L 0 0 L 150 0 L 200 50 L 200 200 L 50 200 Z',
pathFormula: ShapePathFormulasKeys.CUT_RECT_DIAGONAL,
+ pptxShapeType: 'snip2DiagRect',
},
{
viewBox: [200, 200],
path: 'M 50 0 L 150 0 L 200 50 L 200 200 L 0 200 L 0 50 Q 0 0 50 0 Z',
pathFormula: ShapePathFormulasKeys.CUT_ROUND_RECT,
+ pptxShapeType: 'snipRoundRect',
},
{
viewBox: [200, 200],
path: 'M 0 0 L 150 0 Q 200 0 200 50 L 200 200 L 0 200 L 0 0 Z',
pathFormula: ShapePathFormulasKeys.ROUND_RECT_SINGLE,
+ pptxShapeType: 'round1Rect',
},
{
viewBox: [200, 200],
path: 'M 0 50 Q 0 0 50 0 L 150 0 Q 200 0 200 50 L 200 200 L 0 200 Z',
pathFormula: ShapePathFormulasKeys.ROUND_RECT_SAMESIDE,
+ pptxShapeType: 'round2SameRect',
},
{
viewBox: [200, 200],
path: 'M 50 0 L 200 0 L 200 150 Q 200 200 150 200 L 0 200 L 0 50 Q 0 0 50 0 Z',
pathFormula: ShapePathFormulasKeys.ROUND_RECT_DIAGONAL,
+ pptxShapeType: 'round2DiagRect',
},
]
},
@@ -278,12 +288,14 @@ export const SHAPE_LIST: ShapeListItem[] = [
children: [
{
viewBox: [200, 200],
- path: 'M 100 0 A 50 50 0 1 1 100 200 A 50 50 0 1 1 100 0 Z'
+ path: 'M 100 0 A 50 50 0 1 1 100 200 A 50 50 0 1 1 100 0 Z',
+ pptxShapeType: 'ellipse',
},
{
viewBox: [200, 200],
path: 'M 100 0 L 0 200 L 200 200 L 100 0 Z',
pathFormula: ShapePathFormulasKeys.TRIANGLE,
+ pptxShapeType: 'triangle',
},
{
viewBox: [200, 200],
@@ -297,6 +309,7 @@ export const SHAPE_LIST: ShapeListItem[] = [
viewBox: [200, 200],
path: 'M 50 0 L 200 0 L 150 200 L 0 200 L 50 0 Z',
pathFormula: ShapePathFormulasKeys.PARALLELOGRAM_LEFT,
+ pptxShapeType: 'parallelogram',
},
{
viewBox: [200, 200],
@@ -307,10 +320,12 @@ export const SHAPE_LIST: ShapeListItem[] = [
viewBox: [200, 200],
path: 'M 50 0 L 150 0 L 200 200 L 0 200 L 50 0 Z',
pathFormula: ShapePathFormulasKeys.TRAPEZOID,
+ pptxShapeType: 'trapezoid',
},
{
viewBox: [200, 200],
- path: 'M 100 0 L 0 100 L 100 200 L 200 100 L 100 0 Z'
+ path: 'M 100 0 L 0 100 L 100 200 L 200 100 L 100 0 Z',
+ pptxShapeType: 'diamond',
},
{
viewBox: [200, 200],
@@ -340,7 +355,8 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 100 0 A 100 100 102 1 0 200 100 L 100 100 L 100 0 Z'
+ path: 'M 100 0 A 100 100 102 1 0 200 100 L 100 100 L 100 0 Z',
+ pptxShapeType: 'pie',
},
{
viewBox: [200, 200],
@@ -348,11 +364,13 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 100 0 A 100 100 102 1 0 200 100 L 100 0 Z'
+ path: 'M 100 0 A 100 100 102 1 0 200 100 L 100 0 Z',
+ pptxShapeType: 'chord',
},
{
viewBox: [200, 200],
- path: 'M 100 0 A 100 100 102 1 0 200 100 L 200 0 L 100 0 Z'
+ path: 'M 100 0 A 100 100 102 1 0 200 100 L 200 0 L 100 0 Z',
+ pptxShapeType: 'teardrop',
},
{
viewBox: [200, 200],
@@ -360,7 +378,13 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 100 0 L 0 90 L 50 200 L 150 200 L 200 90 L 100 0 Z'
+ path: 'M 100 0 L 0 90 L 50 200 L 150 200 L 200 90 L 100 0 Z',
+ pptxShapeType: 'pentagon',
+ },
+ {
+ viewBox: [200, 200],
+ path: 'M 40 0 L 160 0 L 200 100 L 160 200 L 40 200 L 0 100 Z',
+ pptxShapeType: 'hexagon',
},
{
viewBox: [200, 200],
@@ -368,7 +392,8 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 60 0 L 140 0 L 200 60 L 200 140 L 140 200 L 60 200 L 0 140 L 0 60 L 60 0 Z'
+ path: 'M 60 0 L 140 0 L 200 60 L 200 140 L 140 200 L 60 200 L 0 140 L 0 60 L 60 0 Z',
+ pptxShapeType: 'octagon',
},
{
viewBox: [200, 200],
@@ -462,6 +487,13 @@ export const SHAPE_LIST: ShapeListItem[] = [
{
viewBox: [200, 200],
path: 'M 100 0 L 120 80 L 200 100 L 120 120 L 100 200 L 80 120 L 0 100 L 80 80 L 100 0 Z',
+ pptxShapeType: 'star4',
+ },
+ {
+ viewBox: [1024, 1024],
+ path: 'M1018.67652554 400.05983681l-382.95318779-5.89158658L512 34.78141155 388.27666225 394.16825023l-382.95318779 5.89158658L311.68602415 629.83174977l-117.83174978 365.27842665 312.25413766-223.88032637 312.25413904 223.88032637-117.83175116-365.27842665 318.14572563-229.77191296z',
+ pptxShapeType: 'star5',
+ special: true,
},
{
viewBox: [200, 200],
@@ -470,6 +502,7 @@ export const SHAPE_LIST: ShapeListItem[] = [
{
viewBox: [200, 200],
path: 'M 100 0 L 140 60 L 200 60 L 160 100 L 200 140 L 140 140 L 100 200 L 60 140 L 0 140 L 40 100 L 0 60 L 60 60 L 100 0 Z',
+ pptxShapeType: 'star6',
},
{
viewBox: [200, 200],
@@ -487,27 +520,33 @@ export const SHAPE_LIST: ShapeListItem[] = [
children: [
{
viewBox: [200, 200],
- path: 'M 100 0 L 0 100 L 50 100 L 50 200 L 150 200 L 150 100 L 200 100 L 100 0 Z'
+ path: 'M 100 0 L 0 100 L 50 100 L 50 200 L 150 200 L 150 100 L 200 100 L 100 0 Z',
+ pptxShapeType: 'upArrow',
},
{
viewBox: [200, 200],
- path: 'M 100 200 L 200 100 L 150 100 L 150 0 L 50 0 L 50 100 L 0 100 L 100 200 Z'
+ path: 'M 100 200 L 200 100 L 150 100 L 150 0 L 50 0 L 50 100 L 0 100 L 100 200 Z',
+ pptxShapeType: 'downArrow',
},
{
viewBox: [200, 200],
- path: 'M 0 100 L 100 0 L 100 50 L 200 50 L 200 150 L 100 150 L 100 200 L 0 100 Z'
+ path: 'M 0 100 L 100 0 L 100 50 L 200 50 L 200 150 L 100 150 L 100 200 L 0 100 Z',
+ pptxShapeType: 'leftArrow',
},
{
viewBox: [200, 200],
- path: 'M 200 100 L 100 0 L 100 50 L 0 50 L 0 150 L 100 150 L 100 200 L 200 100 Z'
+ path: 'M 200 100 L 100 0 L 100 50 L 0 50 L 0 150 L 100 150 L 100 200 L 200 100 Z',
+ pptxShapeType: 'rightArrow',
},
{
viewBox: [200, 200],
- path: 'M 100 0 L 0 60 L 60 60 L 60 140 L 0 140 L 100 200 L 200 140 L 140 140 L 140 60 L 200 60 L 100 0 Z'
+ path: 'M 100 0 L 0 60 L 60 60 L 60 140 L 0 140 L 100 200 L 200 140 L 140 140 L 140 60 L 200 60 L 100 0 Z',
+ pptxShapeType: 'upDownArrow',
},
{
viewBox: [200, 200],
- path: 'M 0 100 L 60 0 L 60 60 L 140 60 L 140 0 L 200 100 L 140 200 L 140 140 L 60 140 L 60 200 L 0 100 Z'
+ path: 'M 0 100 L 60 0 L 60 60 L 140 60 L 140 0 L 200 100 L 140 200 L 140 140 L 60 140 L 60 200 L 0 100 Z',
+ pptxShapeType: 'leftRightArrow',
},
{
viewBox: [200, 200],
@@ -515,11 +554,12 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 0 100 L 100 0 L 100 50 L 200 50 L 150 100 L 200 150 L 100 150 L 100 200 L 0 100 Z'
+ path: 'M 0 100 L 100 0 L 100 50 L 200 50 L 150 100 L 200 150 L 100 150 L 100 200 L 0 100 Z',
},
{
viewBox: [200, 200],
- path: 'M 200 100 L 100 0 L 100 50 L 0 50 L 50 100 L 0 150 L 100 150 L 100 200 L 200 100 Z'
+ path: 'M 200 100 L 100 0 L 100 50 L 0 50 L 50 100 L 0 150 L 100 150 L 100 200 L 200 100 Z',
+ pptxShapeType: 'notchedRightArrow',
},
{
viewBox: [200, 200],
@@ -527,19 +567,21 @@ export const SHAPE_LIST: ShapeListItem[] = [
},
{
viewBox: [200, 200],
- path: 'M 200 100 L 120 20 L 120 80 L 80 80 L 80 0 L 0 0 L 0 200 L 80 200 L 80 120 L 120 120 L 120 180 L 200 100 Z'
+ path: 'M 200 100 L 120 20 L 120 80 L 80 80 L 80 0 L 0 0 L 0 200 L 80 200 L 80 120 L 120 120 L 120 180 L 200 100 Z',
},
{
viewBox: [200, 200],
- path: 'M 0 0 L 120 0 L 200 100 L 120 200 L 0 200 L 80 100 L 0 0 Z'
+ path: 'M 0 0 L 120 0 L 200 100 L 120 200 L 0 200 L 80 100 L 0 0 Z',
+ pptxShapeType: 'chevron',
},
{
viewBox: [200, 200],
- path: 'M 80 0 L 200 0 L 120 100 L 200 200 L 80 200 L 0 100 L 80 0 Z'
+ path: 'M 80 0 L 200 0 L 120 100 L 200 200 L 80 200 L 0 100 L 80 0 Z',
},
{
viewBox: [200, 200],
- path: 'M 0 0 L 140 0 L 200 100 L 140 200 L 0 200 L 0 100 L 0 0 Z'
+ path: 'M 0 0 L 140 0 L 200 100 L 140 200 L 0 200 L 0 100 L 0 0 Z',
+ pptxShapeType: 'homePlate',
},
{
viewBox: [200, 200],
diff --git a/src/hooks/useExport.ts b/src/hooks/useExport.ts
index 212da26d..8c25baf5 100644
--- a/src/hooks/useExport.ts
+++ b/src/hooks/useExport.ts
@@ -10,10 +10,9 @@ import { PPTElementOutline, PPTElementShadow, PPTElementLink, Slide } from '@/ty
import { getElementRange, getLineElementPath, getTableSubThemeColor } from '@/utils/element'
import { AST, toAST } from '@/utils/htmlParser'
import { SvgPoints, toPoints } from '@/utils/svgPathParser'
-import { decrypt, encrypt } from '@/utils/crypto'
+import { encrypt } from '@/utils/crypto'
import { svg2Base64 } from '@/utils/svg2Base64'
import { message } from 'ant-design-vue'
-import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements'
const INCH_PX_RATIO = 100
const PT_PX_RATIO = 0.75
@@ -28,8 +27,6 @@ export default () => {
const slidesStore = useSlidesStore()
const { slides, theme, viewportRatio } = storeToRefs(slidesStore)
- const { addSlidesFromData } = useAddSlidesOrElements()
-
const exporting = ref(false)
// 导出图片
@@ -64,24 +61,6 @@ export default () => {
saveAs(blob, 'pptist_slides.pptist')
}
- // 导入pptist文件
- const importSpecificFile = (files: FileList, cover = false) => {
- const file = files[0]
-
- const reader = new FileReader()
- reader.addEventListener('load', () => {
- try {
- const slides = JSON.parse(decrypt(reader.result as string))
- if (cover) slidesStore.setSlides(slides)
- else addSlidesFromData(slides)
- }
- catch {
- message.error('无法正确读取 / 解析该文件')
- }
- })
- reader.readAsText(file)
- }
-
// 导出JSON文件
const exportJSON = () => {
const blob = new Blob([JSON.stringify(slides.value)], { type: '' })
@@ -778,7 +757,6 @@ export default () => {
exporting,
exportImage,
exportJSON,
- importSpecificFile,
exportSpecificFile,
exportPPTX,
}
diff --git a/src/hooks/useImport.ts b/src/hooks/useImport.ts
new file mode 100644
index 00000000..af589777
--- /dev/null
+++ b/src/hooks/useImport.ts
@@ -0,0 +1,266 @@
+import { storeToRefs } from 'pinia'
+import { parse } from 'pptxtojson'
+import { nanoid } from 'nanoid'
+import { Slide, TableCellStyle, TableCell, ChartType, ChartOptions, SlideBackground, PPTShapeElement } from '@/types/slides'
+import { useSlidesStore } from '@/store'
+import { decrypt } from '@/utils/crypto'
+import { ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
+import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements'
+
+import { message } from 'ant-design-vue'
+
+export default () => {
+ const slidesStore = useSlidesStore()
+ const { theme } = storeToRefs(useSlidesStore())
+
+ const { addSlidesFromData } = useAddSlidesOrElements()
+
+ // 导入pptist文件
+ const importSpecificFile = (files: FileList, cover = false) => {
+ const file = files[0]
+
+ const reader = new FileReader()
+ reader.addEventListener('load', () => {
+ try {
+ const slides = JSON.parse(decrypt(reader.result as string))
+ if (cover) slidesStore.setSlides(slides)
+ else addSlidesFromData(slides)
+ }
+ catch {
+ message.error('无法正确读取 / 解析该文件')
+ }
+ })
+ reader.readAsText(file)
+ }
+
+ // 导入PPTX文件
+ const importPPTXFile = (files: FileList) => {
+ const file = files[0]
+ if (!file) return
+
+ const shapeList: ShapePoolItem[] = []
+ for (const item of SHAPE_LIST) {
+ shapeList.push(...item.children)
+ }
+
+ const reader = new FileReader()
+ reader.onload = async e => {
+ const json = await parse(e.target!.result as ArrayBuffer)
+ const slides: Slide[] = []
+ for (const item of json.slides) {
+ const { type, value } = item.fill
+ let background: SlideBackground
+ if (type === 'image') {
+ background = {
+ type: 'image',
+ image: value.picBase64,
+ imageSize: 'cover',
+ }
+ }
+ else {
+ background = {
+ type: 'solid',
+ color: value,
+ }
+ }
+
+ const slide: Slide = {
+ id: nanoid(10),
+ elements: [],
+ background,
+ }
+ for (const el of item.elements) {
+ if (el.type === 'text') {
+ slide.elements.push({
+ type: 'text',
+ id: nanoid(10),
+ width: el.width,
+ height: el.height,
+ left: el.left,
+ top: el.top,
+ rotate: el.rotate,
+ defaultFontName: theme.value.fontName,
+ defaultColor: theme.value.fontColor,
+ content: el.content,
+ lineHeight: 1,
+ outline: {
+ color: el.borderColor,
+ width: el.borderWidth,
+ style: el.borderType,
+ },
+ fill: el.fillColor,
+ })
+ }
+ else if (el.type === 'image') {
+ slide.elements.push({
+ type: 'image',
+ id: nanoid(10),
+ src: el.src,
+ width: el.width,
+ height: el.height,
+ left: el.left,
+ top: el.top,
+ fixedRatio: true,
+ rotate: el.rotate,
+ })
+ }
+ else if (el.type === 'shape') {
+ const shape = shapeList.find(item => item.pptxShapeType === el.shapType)
+
+ const element: PPTShapeElement = {
+ type: 'shape',
+ id: nanoid(10),
+ width: el.width,
+ height: el.height,
+ left: el.left,
+ top: el.top,
+ viewBox: [200, 200],
+ path: 'M 0 0 L 200 0 L 200 200 L 0 200 Z',
+ fill: el.fillColor,
+ fixedRatio: false,
+ rotate: el.rotate,
+ outline: {
+ color: el.borderColor,
+ width: el.borderWidth,
+ style: el.borderType,
+ },
+ text: {
+ content: el.content,
+ defaultFontName: theme.value.fontName,
+ defaultColor: theme.value.fontColor,
+ align: 'middle',
+ }
+ }
+
+ if (shape) {
+ element.path = shape.path
+ element.viewBox = shape.viewBox
+
+ if (shape.pathFormula) {
+ element.pathFormula = shape.pathFormula
+ element.viewBox = [el.width, el.height]
+
+ const pathFormula = SHAPE_PATH_FORMULAS[shape.pathFormula]
+ if ('editable' in pathFormula) {
+ element.path = pathFormula.formula(el.width, el.height, pathFormula.defaultValue)
+ element.keypoint = pathFormula.defaultValue
+ }
+ else element.path = pathFormula.formula(el.width, el.height)
+ }
+ }
+
+ slide.elements.push(element)
+ }
+ else if (el.type === 'table') {
+ const row = el.data.length
+ const col = el.data[0].length
+
+ const style: TableCellStyle = {
+ fontname: theme.value.fontName,
+ color: theme.value.fontColor,
+ }
+ const data: TableCell[][] = []
+ for (let i = 0; i < row; i++) {
+ const rowCells: TableCell[] = []
+ for (let j = 0; j < col; j++) {
+ const cellData = el.data[i][j]
+ rowCells.push({
+ id: nanoid(10),
+ colspan: 1,
+ rowspan: cellData.rowSpan || 1,
+ text: cellData.text,
+ style,
+ })
+ }
+ data.push(rowCells)
+ }
+
+ const colWidths: number[] = new Array(col).fill(1 / col)
+
+ slide.elements.push({
+ type: 'table',
+ id: nanoid(10),
+ width: el.width,
+ height: el.height,
+ left: el.left,
+ top: el.top,
+ colWidths,
+ rotate: 0,
+ data,
+ outline: {
+ width: 2,
+ style: 'solid',
+ color: '#eeece1',
+ },
+ theme: {
+ color: theme.value.themeColor,
+ rowHeader: true,
+ rowFooter: false,
+ colHeader: false,
+ colFooter: false,
+ },
+ cellMinHeight: 36,
+ })
+ }
+ else if (el.type === 'chart') {
+ const labels = Object.values(el.data[0].xlabels)
+ const legends = el.data.map(item => item.key)
+ const series = el.data.map(item => item.values.map(v => v.y))
+ let options: ChartOptions = {}
+
+ let chartType: ChartType = 'bar'
+ if (el.chartType === 'barChart') {
+ chartType = 'bar'
+ }
+ if (el.chartType === 'stackedBarChart') {
+ chartType = 'bar'
+ options = { stackBars: true }
+ }
+ else if (el.chartType === 'lineChart') {
+ chartType = 'line'
+ }
+ else if (el.chartType === 'areaChart') {
+ chartType = 'line'
+ options = { showArea: true }
+ }
+ else if (el.chartType === 'scatterChart') {
+ chartType = 'line'
+ options = { showLine: false }
+ }
+ else if (el.chartType === 'pieChart' || el.chartType === 'pie3DChart') {
+ chartType = 'pie'
+ }
+
+ slide.elements.push({
+ type: 'chart',
+ id: nanoid(10),
+ chartType: chartType,
+ width: el.width,
+ height: el.height,
+ left: el.left,
+ top: el.top,
+ rotate: 0,
+ themeColor: [theme.value.themeColor],
+ gridColor: theme.value.fontColor,
+ data: {
+ labels,
+ legends,
+ series,
+ },
+ options,
+ })
+ }
+ // else if (el.type === 'group') {}
+ }
+ slides.push(slide)
+ }
+ addSlidesFromData(slides)
+ }
+ reader.readAsArrayBuffer(file)
+ }
+
+ return {
+ importSpecificFile,
+ importPPTXFile,
+ }
+}
\ No newline at end of file
diff --git a/src/views/Editor/EditorHeader/index.vue b/src/views/Editor/EditorHeader/index.vue
index 8afc5fbe..f0b39530 100644
--- a/src/views/Editor/EditorHeader/index.vue
+++ b/src/views/Editor/EditorHeader/index.vue
@@ -8,6 +8,9 @@
importSpecificFile(files)">
+ importPPTXFile(files)">
+
+
@@ -83,7 +86,7 @@ import { useMainStore } from '@/store'
import useScreening from '@/hooks/useScreening'
import useSlideHandler from '@/hooks/useSlideHandler'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
-import useExport from '@/hooks/useExport'
+import useImport from '@/hooks/useImport'
import HotkeyDoc from './HotkeyDoc.vue'
import FileInput from '@/components/FileInput.vue'
@@ -101,7 +104,7 @@ const { gridLineSize, showRuler, showSelectPanel } = storeToRefs(mainStore)
const { enterScreening, enterScreeningFromStart } = useScreening()
const { createSlide, deleteSlide, resetSlides } = useSlideHandler()
const { redo, undo } = useHistorySnapshot()
-const { importSpecificFile } = useExport()
+const { importSpecificFile, importPPTXFile } = useImport()
const setDialogForExport = mainStore.setDialogForExport