Skip to content

Commit 5f0d9fe

Browse files
committed
Update custom node example
1 parent 0c81f8e commit 5f0d9fe

15 files changed

Lines changed: 242 additions & 333 deletions

File tree

examples/shared/css/style.css

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
:root {
2+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3+
line-height: 1.5;
4+
font-weight: 400;
5+
6+
color: rgba(0, 0, 0, 0.87);
7+
8+
font-synthesis: none;
9+
text-rendering: optimizeLegibility;
10+
-webkit-font-smoothing: antialiased;
11+
-moz-osx-font-smoothing: grayscale;
12+
}
13+
14+
a {
15+
font-weight: 500;
16+
color: #646cff;
17+
text-decoration: inherit;
18+
}
19+
a:hover {
20+
color: #535bf2;
21+
}
22+
23+
body {
24+
margin: 0;
25+
display: flex;
26+
min-width: 320px;
27+
min-height: 100vh;
28+
}
29+
30+
h1 {
31+
font-size: 2.2em;
32+
line-height: 1.1;
33+
}
34+
35+
#app {
36+
max-width: 1280px;
37+
margin: 0 auto;
38+
padding: 2rem;
39+
}
40+
41+
.my-custom-mark-class {
42+
border-bottom: 1px solid #646cff;
43+
}
44+
45+
.example-container {
46+
display: flex;
47+
flex-direction: column;
48+
align-items: center;
49+
justify-content: center;
50+
}
51+
.editor-and-button {
52+
display: flex;
53+
flex-direction: row;
54+
align-items: flex-start;
55+
justify-content: center;
56+
}
57+
.editor-buttons {
58+
display: flex;
59+
flex-direction: column;
60+
}
61+
.editor-buttons button {
62+
margin-bottom: 10px;
63+
}
64+
.custom-button {
65+
padding: 8px 12px;
66+
border-radius: 8px;
67+
margin-left: 10px;
68+
outline: none;
69+
border: none;
70+
background-color: #AECEE6;
71+
}
72+
.hidden {
73+
display: none;
74+
}
454 KB
Binary file not shown.

examples/shared/images/logo.webp

283 KB
Loading
836 KB
Loading
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,13 @@
1-
# Custom Nodes in SuperDoc
1+
# SuperDoc
2+
## SuperDoc: Creating a custom mark
23

3-
You can create custom nodes (or extensions/plugins). For this example we'll create a simple custom node and pass it to the editor.
4+
An example of creating a custom Mark to use with SuperDoc.
5+
Note: Requires `SuperDoc 0.10.15` or later
46

5-
First, [we've created a basic example of a custom node here](https://github.com/Harbour-Enterprises/SuperDoc/blob/main/examples/vue-custom-node-example/src/plugins/MyCustomNodePlugin.js) showing __some__ of the API we have access to.
7+
[We create a custom mark here](https://github.com/Harbour-Enterprises/SuperDoc/blob/main/examples/vue-custom-mark/src/custom-mark.js)
8+
Note that we added a custom command to the mark, called setMyCustomMark. We can now insert this mark by calling this command from `superdoc.activeEditor.commands`
69

7-
We simply import it into our document editor, using:
8-
```
9-
import { myCustomNode } from '../plugins/MyCustomNodePlugin';
10-
```
10+
[Then we can pass it into the editor via the `editorExtensions` key](https://github.com/Harbour-Enterprises/SuperDoc/blob/e724d31eaba50a423ed0d73a4264a09b33d06eaa/examples/vue-custom-mark/src/App.vue#L20)
1111

12-
And pass it to the editor via our config:
13-
```
14-
const config = {
15-
// Our config...
16-
editorExtensions: [myCustomNode],
17-
}
18-
```
19-
20-
And that's it! Our editor now can use our custom node.
21-
22-
## Custom commands
23-
Since our custom node creates a custom command `insertCustomNode` that takes an **object** as a param with keys `content` and `id`, we can use it via:
24-
```
25-
activeEditor.commands.insertCustomNode({ content, id })
26-
```
27-
28-
## Running the example
29-
```
30-
npm install && npm run dev
31-
```
32-
33-
The example inserts two instances of our custom node - once using a generic editor `insertContent` command and some HTML, and the second time using our newly-created custom command `insertCustomNode`
12+
## Exporting the docx
13+
This example also shows one way to export the docx to a blob whenever the content changes in the editor
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
4-
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>SuperDoc Vue Example</title>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/png" href="/logo.webp" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>SuperDoc Examples</title>
78
</head>
89
<body>
910
<div id="app"></div>
1011
<script type="module" src="/src/main.js"></script>
1112
</body>
12-
</html>
13+
</html>
Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
{
2-
"name": "vue-superdoc-example",
3-
"private": true,
4-
"version": "0.0.1",
5-
"type": "module",
6-
"scripts": {
7-
"dev": "vite"
8-
},
9-
"dependencies": {
10-
"@harbour-enterprises/superdoc": "^0.9.7",
11-
"vue": "^3.5.13"
12-
},
13-
"devDependencies": {
14-
"@vitejs/plugin-vue": "^4.2.3",
15-
"vite": "^4.4.6"
16-
}
2+
"name": "vue-html-editor",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@harbour-enterprises/superdoc": "^0.10.8",
13+
"vue": "^3.5.13"
14+
},
15+
"devDependencies": {
16+
"@vitejs/plugin-vue": "^5.2.2",
17+
"vite": "^6.3.1"
18+
}
1719
}
283 KB
Loading
Lines changed: 74 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,86 @@
1-
<template>
2-
<div class="app">
3-
<header>
4-
<h1>SuperDoc Example</h1>
5-
<button @click="fileInput?.click()">Load Document</button>
6-
<input
7-
type="file"
8-
ref="fileInput"
9-
accept=".docx,.pdf"
10-
class="hidden"
11-
@change="handleFileChange"
12-
>
13-
</header>
14-
15-
<main>
16-
<DocumentEditor
17-
:document-id="documentId"
18-
:initial-data="documentFile"
19-
@editor-ready="handleEditorReady"
20-
/>
21-
</main>
22-
</div>
23-
</template>
24-
251
<script setup>
26-
import { ref } from 'vue';
27-
import DocumentEditor from './components/DocumentEditor.vue';
28-
29-
const documentId = ref('example-doc');
30-
const documentFile = ref(null);
31-
const fileInput = ref(null);
32-
33-
const handleFileChange = (event) => {
34-
const file = event.target.files?.[0];
35-
if (file) {
36-
documentFile.value = file;
37-
documentId.value = `doc-${Date.now()}`;
38-
}
39-
};
2+
import '@harbour-enterprises/superdoc/style.css';
3+
import { onMounted, shallowRef } from 'vue';
4+
import { SuperDoc } from '@harbour-enterprises/superdoc';
5+
import UploadFile from './components/UploadFile.vue';
6+
7+
// Default document
8+
import sampleDocument from '../../shared/data/sample-document.docx?url';
9+
10+
// This is our custom node that we are creating for this example
11+
import { myCustomNode } from './custom-node';
12+
13+
const superdoc = shallowRef(null);
14+
const editor = shallowRef(null);
4015
41-
const handleEditorReady = (editor) => {
42-
console.log('SuperDoc editor is ready', editor);
16+
const init = (fileToLoad) => {
17+
superdoc.value = new SuperDoc({
18+
// Can also be a class ie: .main-editor
19+
selector: '#editor',
20+
21+
// Enable pagination
22+
pagination: true,
23+
24+
document: fileToLoad ? { data: fileToLoad } : sampleDocument,
25+
26+
// Initialize the toolbar
27+
toolbar: '#toolbar',
28+
toolbarGroups: ['center'],
29+
30+
// Pass in custom extensions
31+
editorExtensions: [myCustomNode],
32+
33+
// Listen for ready event
34+
onReady,
35+
});
4336
};
44-
</script>
4537
46-
<style>
47-
.app {
48-
height: 100vh;
49-
display: flex;
50-
flex-direction: column;
51-
}
38+
const handleFileUpdate = (file) => {
39+
// Handle file update logic here
40+
console.log('File updated:', file);
41+
superdoc.value?.destroy();
5242
53-
header {
54-
padding: 1rem;
55-
background: #f5f5f5;
56-
display: flex;
57-
align-items: center;
58-
gap: 1rem;
43+
init(file);
5944
}
6045
61-
header button {
62-
padding: 0.5rem 1rem;
63-
background: #1355ff;
64-
color: white;
65-
border: none;
66-
border-radius: 4px;
67-
cursor: pointer;
46+
/* When SuperDoc is ready, we can store a reference to the editor instance */
47+
const onReady = () => {
48+
superdoc.value?.activeEditor?.on('create', ({ editor: activeEditor }) => {
49+
editor.value = activeEditor;
50+
});
6851
}
6952
70-
header button:hover {
71-
background: #0044ff;
72-
}
53+
onMounted(() => init());
54+
</script>
7355
74-
.hidden {
75-
display: none;
76-
}
56+
<template>
57+
<div class="example-container">
58+
<h1>SuperDoc: Create a custom node with custom command</h1>
59+
60+
<p>In this example, we create a simple custom node to pass into SuperDoc.</p>
7761
78-
main {
79-
flex: 1;
80-
padding: 1rem;
62+
<div id="toolbar" class="my-custom-toolbar"></div>
63+
<div class="editor-and-button">
64+
<div id="editor" class="main-editor"></div>
65+
<div class="editor-buttons">
66+
<UploadFile :update-file="handleFileUpdate" />
67+
<button class="custom-button" @click="editor?.commands.insertCustomNode">Insert custom node</button>
68+
</div>
69+
</div>
70+
</div>
71+
</template>
72+
73+
<style>
74+
.my-custom-node-default-class {
75+
background-color: #1355FF;
76+
border-radius: 8px;
77+
cursor: pointer;
78+
color: white;
79+
display: inline-block;
80+
padding: 2px 8px;
81+
font-size: 12px;
82+
}
83+
.my-custom-node-default-class:hover {
84+
background-color: #0a3dff;
8185
}
82-
</style>
86+
</style>

0 commit comments

Comments
 (0)