diff --git a/apps/poc-state-plugin/src/app/app.component.ts b/apps/poc-state-plugin/src/app/app.component.ts
index 2e9bc85..64300c4 100644
--- a/apps/poc-state-plugin/src/app/app.component.ts
+++ b/apps/poc-state-plugin/src/app/app.component.ts
@@ -90,6 +90,28 @@ import type { Shape } from '@penpot/plugin-types';
>
Rotate
+
+
+
+
@@ -146,6 +168,8 @@ export class AppComponent {
this.theme.set(event.data.content);
} else if (event.data.type === 'update-counter') {
this.counter.set(event.data.content.counter);
+ } else if (event.data.type === 'start-download') {
+ this.#startDownload(event.data.content);
}
});
@@ -218,6 +242,18 @@ export class AppComponent {
this.#sendMessage({ content: 'rotate-selection' });
}
+ createMargins() {
+ this.#sendMessage({ content: 'create-margins' });
+ }
+
+ addComment() {
+ this.#sendMessage({ content: 'add-comment' });
+ }
+
+ exportFile() {
+ this.#sendMessage({ content: 'export-file' });
+ }
+
async uploadImage(event: Event) {
const input = event.target as HTMLInputElement;
if (input?.files?.length) {
@@ -253,4 +289,22 @@ export class AppComponent {
this.form.get('name')?.setValue('');
}
}
+
+ #startDownload(data: Uint8Array) {
+ const blob = new Blob([data], { type: 'application/octet-stream' });
+
+ // We need to start a download with this URL
+ const downloadURL = URL.createObjectURL(blob);
+
+ // Download
+ var a = document.createElement('a');
+ document.body.appendChild(a);
+ a.href = downloadURL;
+ a.download = 'Export.penpot';
+ a.click();
+
+ // Remove temporary
+ URL.revokeObjectURL(a.href);
+ a.remove();
+ }
}
diff --git a/apps/poc-state-plugin/src/assets/manifest.json b/apps/poc-state-plugin/src/assets/manifest.json
index ce29e9c..5a2ba40 100644
--- a/apps/poc-state-plugin/src/assets/manifest.json
+++ b/apps/poc-state-plugin/src/assets/manifest.json
@@ -3,10 +3,10 @@
"description": "Sandbox plugin for plugins development",
"code": "/assets/plugin.js",
"permissions": [
- "content:read",
"content:write",
- "library:read",
"library:write",
- "user:read"
+ "comment:write",
+ "user:read",
+ "allow:downloads"
]
}
diff --git a/apps/poc-state-plugin/src/plugin.ts b/apps/poc-state-plugin/src/plugin.ts
index d8b704b..ed8e315 100644
--- a/apps/poc-state-plugin/src/plugin.ts
+++ b/apps/poc-state-plugin/src/plugin.ts
@@ -5,7 +5,7 @@ penpot.ui.open('Plugin name', '', {
height: 600,
});
-penpot.ui.onMessage<{ content: string; data: unknown }>((message) => {
+penpot.ui.onMessage<{ content: string; data: unknown }>(async (message) => {
if (message.content === 'close') {
penpot.closePlugin();
} else if (message.content === 'ready') {
@@ -42,6 +42,12 @@ penpot.ui.onMessage<{ content: string; data: unknown }>((message) => {
mimeType: string;
};
createImage(data, mimeType);
+ } else if (message.content === 'create-margins') {
+ createMargins();
+ } else if (message.content === 'add-comment') {
+ addComment();
+ } else if (message.content === 'export-file') {
+ exportFile();
}
});
@@ -432,3 +438,56 @@ function createImage(data: Uint8Array, mimeType: string) {
})
.catch((err) => console.error(err));
}
+
+function createMargins() {
+ const page = penpot.currentPage;
+ const selected = penpot.selection && penpot.selection[0];
+
+ if (selected && penpot.utils.types.isBoard(selected)) {
+ const { width, height } = selected;
+ selected.addRulerGuide('vertical', 10);
+ selected.addRulerGuide('vertical', width - 10);
+ selected.addRulerGuide('horizontal', 10);
+ selected.addRulerGuide('horizontal', height - 10);
+ } else {
+ console.log('bound', penpot.viewport.bounds);
+ const { x, y, width, height } = penpot.viewport.bounds;
+ page.addRulerGuide('vertical', x + 100);
+ page.addRulerGuide('vertical', x + width - 50);
+ page.addRulerGuide('horizontal', y + 100);
+ page.addRulerGuide('horizontal', y + height - 50);
+ }
+}
+
+async function addComment() {
+ const shape = penpot.selection[0];
+
+ if (shape) {
+ const content = shape.name + ' - ' + Date.now();
+ const cthr = await penpot.currentPage.findCommentThreads();
+ const th = cthr && cthr[0];
+
+ if (th) {
+ const comms = await th.findComments();
+ const first = comms && comms[0];
+ if (first) {
+ console.log('Reply to thread', content);
+ th.reply(content);
+ }
+ } else {
+ console.log('Create new thread', content);
+ await penpot.currentPage.addCommentThread(content, shape.center);
+ }
+ }
+}
+
+async function exportFile() {
+ const data = await penpot.getFile()?.export('penpot');
+
+ if (data) {
+ penpot.ui.sendMessage({
+ type: 'start-download',
+ content: data,
+ });
+ }
+}
diff --git a/libs/plugin-types/index.d.ts b/libs/plugin-types/index.d.ts
index 4396672..f6b6ed4 100644
--- a/libs/plugin-types/index.d.ts
+++ b/libs/plugin-types/index.d.ts
@@ -2850,7 +2850,7 @@ export interface Page extends PluginData {
/**
* Removes the comment thread.
- * Requires the `comment:read` or `comment:write` permission.
+ * Requires the `comment:write` permission.
*/
removeCommentThread(commentThread: CommentThread): Promise;
diff --git a/libs/plugins-runtime/src/lib/plugin-manager.spec.ts b/libs/plugins-runtime/src/lib/plugin-manager.spec.ts
index f9ae229..18c5a5a 100644
--- a/libs/plugins-runtime/src/lib/plugin-manager.spec.ts
+++ b/libs/plugins-runtime/src/lib/plugin-manager.spec.ts
@@ -114,7 +114,8 @@ describe('createPluginManager', () => {
'Test Modal',
'https://example.com/plugin',
'light',
- { width: 400, height: 300 }
+ { width: 400, height: 300 },
+ true
);
expect(mockModal.setTheme).toHaveBeenCalledWith('light');
expect(mockModal.addEventListener).toHaveBeenCalledWith(