Compare commits
2 commits
5c261b35f2
...
56cf62f1eb
Author | SHA1 | Date | |
---|---|---|---|
56cf62f1eb | |||
8d1438de33 |
5 changed files with 253 additions and 34 deletions
29
README.md
29
README.md
|
@ -4,26 +4,23 @@
|
||||||
This plugin allows you to embed js-draw whiteboards anywhere in your SiYuan documents.
|
This plugin allows you to embed js-draw whiteboards anywhere in your SiYuan documents.
|
||||||
|
|
||||||
## Usage instructions
|
## Usage instructions
|
||||||
1. Install the plugin
|
- Install the plugin from the marketplace. You can find it by searching for `js-draw`.
|
||||||
- Grab a release from the [Releases page](https://git.massive.box/massivebox/siyuan-jsdraw-plugin/releases)
|
- To edit an SVG image that is already embedded in your document:
|
||||||
- Unzip it in the folder `./data/plugins`, relatively to your SiYuan workspace.
|
1. Right-click on the image, select "Plugin" > "Edit with js-draw" in the menu
|
||||||
> The plugin is not yet available in the official marketplace. I will try to publish it there soon!
|
2. The editor tab will open, edit your file as you like, then click the Save button and close the tab.
|
||||||
2. Insert a drawing in your documents by typing `/Insert Drawing` in your document, and selecting the correct menu entry
|
3. The image is updated, but SiYuan will still show the cached (old) image. This will be fixed in future releases,
|
||||||
3. The whiteboard editor will open in a new tab. Draw as you like, then click the Save button. It will also add a
|
please be patient. Until them, you can refresh the editor or change the image path.
|
||||||
drawing block to your document.
|
- To add a new drawing to your document:
|
||||||
4. Click the Gear icon > Refresh to refresh the drawing block, if it's still displaying the old drawing.
|
1. Type `/Insert Drawing` in your document, and select the correct menu entry
|
||||||
5. Click the drawing block to open the editor again.
|
2. The whiteboard editor will open in a new tab. Draw as you like, then click the Save button and close the tab.
|
||||||
|
3. Click the Gear icon > Refresh to refresh the drawing block.
|
||||||
|
4. Click the drawing block to open the editor again.
|
||||||
|
|
||||||
## Planned features
|
## Planned features
|
||||||
- [ ] Auto-reload drawing blocks on drawing change
|
Check out the [Projects](https://git.massive.box/massivebox/siyuan-jsdraw-plugin/projects) tab!
|
||||||
- [ ] Rename whiteboards
|
|
||||||
- [ ] Improve internationalization framework
|
|
||||||
- [ ] Default background color and grid options
|
|
||||||
- [ ] Respecting user theme for the editor
|
|
||||||
- And more!
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Contributions are always welcome! Right now, I'm working on the core functionality and fixing bugs.
|
Contributions are always welcome! Right now, I'm working on the core functionality and fixing bugs.
|
||||||
After that is done, I will need help with the internationalization, as, unfortunately, I don't speak Chinese.
|
After that is done, I will need help with the internationalization, as, unfortunately, I don't speak Chinese.
|
||||||
Please [contact me](mailto:box@massive.box) if you'd like to help!
|
Please [contact me](mailto:box@massive.box) if you'd like to help!
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
function copyEditLink(fileID) {
|
function copyEditLink(fileID) {
|
||||||
navigator.clipboard.writeText(getEditLink(fileID));
|
navigator.clipboard.writeText(getEditLink(fileID));
|
||||||
}
|
}
|
||||||
|
function copyImageLink(fileID) {
|
||||||
|
navigator.clipboard.writeText(``);
|
||||||
|
}
|
||||||
|
|
||||||
function refreshPage() {
|
function refreshPage() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
@ -20,7 +23,7 @@ function addButton(document, fileID) {
|
||||||
popupMenu.innerHTML = `
|
popupMenu.innerHTML = `
|
||||||
<button onclick="refreshPage()">Refresh</button>
|
<button onclick="refreshPage()">Refresh</button>
|
||||||
<button onclick="copyEditLink('${fileID}')">Copy Direct Edit Link</button>
|
<button onclick="copyEditLink('${fileID}')">Copy Direct Edit Link</button>
|
||||||
|
<button onclick="copyImageLink('${fileID}')">Copy Image Link</button>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(popupMenu);
|
document.body.appendChild(popupMenu);
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ function addButton(document, fileID) {
|
||||||
|
|
||||||
document.body.addEventListener('mouseleave', () => {
|
document.body.addEventListener('mouseleave', () => {
|
||||||
floatingButton.style.display = 'none';
|
floatingButton.style.display = 'none';
|
||||||
|
popupMenu.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle popup menu on button click
|
// Toggle popup menu on button click
|
||||||
|
|
|
@ -54,4 +54,37 @@ export function getPreviewHTML(id: string): string {
|
||||||
return `
|
return `
|
||||||
<iframe src="${EMBED_PATH + id}&antiCache=0"></iframe>
|
<iframe src="${EMBED_PATH + id}&antiCache=0"></iframe>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// given a tag (such as a div) containing an image as a child at any level, return the src of the image
|
||||||
|
export function findImgSrc(element: HTMLElement): string | null {
|
||||||
|
// Base case: if current element is an image
|
||||||
|
if (element.tagName === 'IMG') {
|
||||||
|
const fullSrc = (element as HTMLImageElement).src;
|
||||||
|
// Extract the path after host:port using URL API
|
||||||
|
const url = new URL(fullSrc);
|
||||||
|
return url.pathname.startsWith('/assets/')
|
||||||
|
? url.pathname.substring(1) // Remove leading slash
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively check children
|
||||||
|
if (element.children) {
|
||||||
|
for (const child of Array.from(element.children)) {
|
||||||
|
const src = findImgSrc(child as HTMLElement);
|
||||||
|
if (src) return src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractFileID(imgSrc: string | null): string | null {
|
||||||
|
if (!imgSrc) return null;
|
||||||
|
|
||||||
|
const [pathPart] = imgSrc.split('?');
|
||||||
|
// Match pattern: assets/{fileID}.svg
|
||||||
|
const match = pathPart.match(/^assets\/([^\/]+)\.svg$/i);
|
||||||
|
|
||||||
|
return match?.[1] || null;
|
||||||
|
}
|
||||||
|
|
32
src/index.ts
32
src/index.ts
|
@ -1,12 +1,11 @@
|
||||||
import {Plugin, Protyle} from 'siyuan';
|
import {Plugin, Protyle} from 'siyuan';
|
||||||
import {getPreviewHTML, loadIcons, getMenuHTML, generateSiyuanId} from "@/helper";
|
import {getPreviewHTML, loadIcons, getMenuHTML, generateSiyuanId, findImgSrc, extractFileID} from "@/helper";
|
||||||
import {createEditor, openEditorTab} from "@/editorTab";
|
import {createEditor, openEditorTab} from "@/editorTab";
|
||||||
|
|
||||||
export default class DrawJSPlugin extends Plugin {
|
export default class DrawJSPlugin extends Plugin {
|
||||||
onload() {
|
onload() {
|
||||||
|
|
||||||
loadIcons(this);
|
loadIcons(this);
|
||||||
//const id = Math.random().toString(36).substring(7);
|
|
||||||
this.addTab({
|
this.addTab({
|
||||||
'type': "whiteboard",
|
'type': "whiteboard",
|
||||||
init() {
|
init() {
|
||||||
|
@ -25,20 +24,21 @@ export default class DrawJSPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
this.eventBus.on("open-menu-image", (e: any) => {
|
||||||
|
const fileID = extractFileID(findImgSrc(e.detail.element));
|
||||||
|
if(fileID === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("got ID" + fileID);
|
||||||
|
e.detail.menu.addItem({
|
||||||
|
icon: "iconDraw",
|
||||||
|
label: "Edit with js-draw",
|
||||||
|
click: () => {
|
||||||
|
openEditorTab(this, fileID);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onLayoutReady() {
|
|
||||||
// This function is automatically called when the layout is loaded.
|
|
||||||
}
|
|
||||||
|
|
||||||
onunload() {
|
|
||||||
// This function is automatically called when the plugin is disabled.
|
|
||||||
}
|
|
||||||
|
|
||||||
uninstall() {
|
|
||||||
// This function is automatically called when the plugin is uninstalled.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
185
vite.config.ts.timestamp-1743541342564-d66840ad6dd8b.mjs
Normal file
185
vite.config.ts.timestamp-1743541342564-d66840ad6dd8b.mjs
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue