Compare commits

...

2 commits

Author SHA1 Message Date
56cf62f1eb
Improve docs 2025-04-01 23:24:17 +02:00
8d1438de33
Offer to edit images
Any SVG image in assets/ can now be edited with js-draw. It won't reload automatically (yet)
2025-04-01 23:03:22 +02:00
5 changed files with 253 additions and 34 deletions

View file

@ -4,23 +4,20 @@
This plugin allows you to embed js-draw whiteboards anywhere in your SiYuan documents.
## Usage instructions
1. Install the plugin
- Grab a release from the [Releases page](https://git.massive.box/massivebox/siyuan-jsdraw-plugin/releases)
- Unzip it in the folder `./data/plugins`, relatively to your SiYuan workspace.
> The plugin is not yet available in the official marketplace. I will try to publish it there soon!
2. Insert a drawing in your documents by typing `/Insert Drawing` in your document, and selecting the correct menu entry
3. The whiteboard editor will open in a new tab. Draw as you like, then click the Save button. It will also add a
drawing block to your document.
4. Click the Gear icon > Refresh to refresh the drawing block, if it's still displaying the old drawing.
5. Click the drawing block to open the editor again.
- Install the plugin from the marketplace. You can find it by searching for `js-draw`.
- To edit an SVG image that is already embedded in your document:
1. Right-click on the image, select "Plugin" > "Edit with js-draw" in the menu
2. The editor tab will open, edit your file as you like, then click the Save button and close the tab.
3. The image is updated, but SiYuan will still show the cached (old) image. This will be fixed in future releases,
please be patient. Until them, you can refresh the editor or change the image path.
- To add a new drawing to your document:
1. Type `/Insert Drawing` in your document, and select the correct menu entry
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
- [ ] Auto-reload drawing blocks on drawing change
- [ ] Rename whiteboards
- [ ] Improve internationalization framework
- [ ] Default background color and grid options
- [ ] Respecting user theme for the editor
- And more!
Check out the [Projects](https://git.massive.box/massivebox/siyuan-jsdraw-plugin/projects) tab!
## Contributing
Contributions are always welcome! Right now, I'm working on the core functionality and fixing bugs.

View file

@ -1,6 +1,9 @@
function copyEditLink(fileID) {
navigator.clipboard.writeText(getEditLink(fileID));
}
function copyImageLink(fileID) {
navigator.clipboard.writeText(`![Drawing](assets/${fileID}.svg)`);
}
function refreshPage() {
window.location.reload();
@ -20,7 +23,7 @@ function addButton(document, fileID) {
popupMenu.innerHTML = `
<button onclick="refreshPage()">Refresh</button>
<button onclick="copyEditLink('${fileID}')">Copy Direct Edit Link</button>
<button onclick="copyImageLink('${fileID}')">Copy Image Link</button>
`;
document.body.appendChild(popupMenu);
@ -31,6 +34,7 @@ function addButton(document, fileID) {
document.body.addEventListener('mouseleave', () => {
floatingButton.style.display = 'none';
popupMenu.style.display = 'none';
});
// Toggle popup menu on button click

View file

@ -55,3 +55,36 @@ export function getPreviewHTML(id: string): string {
<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;
}

View file

@ -1,12 +1,11 @@
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";
export default class DrawJSPlugin extends Plugin {
onload() {
loadIcons(this);
//const id = Math.random().toString(36).substring(7);
this.addTab({
'type': "whiteboard",
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.
}
}

File diff suppressed because one or more lines are too long