From 799d1004cb355064351363aad1dd182d389a6802 Mon Sep 17 00:00:00 2001 From: Ole Eskild Steensen Date: Mon, 14 Mar 2022 16:30:44 +0100 Subject: [PATCH 1/4] Added support for excalidraw --- Publisher.ts | 50 +++++++++++++++++++++++++++------------- icons.ts => constants.ts | 9 ++++++++ main.ts | 2 +- 3 files changed, 44 insertions(+), 17 deletions(-) rename icons.ts => constants.ts (50%) diff --git a/Publisher.ts b/Publisher.ts index 93f66e98..97159527 100644 --- a/Publisher.ts +++ b/Publisher.ts @@ -6,9 +6,11 @@ import { arrayBufferToBase64, generateUrlPath } from "utils"; import { vallidatePublishFrontmatter } from "Validator"; import slugify from "@sindresorhus/slugify"; import { title } from "process"; +import { excaliDrawBundle } from "constants"; +import { excalidraw } from "constants"; -export interface IPublisher{ +export interface IPublisher { publish(file: TFile): Promise; getFilesMarkedForPublishing(): Promise; generateMarkdown(file: TFile): Promise; @@ -192,6 +194,7 @@ export default class Publisher { let transcludedText = text; const transcludedRegex = /!\[\[(.*?)\]\]/g; const transclusionMatches = text.match(transcludedRegex); + let numberOfExcaliDraws = 0; if (transclusionMatches) { for (let i = 0; i < transclusionMatches.length; i++) { try { @@ -200,22 +203,37 @@ export default class Publisher { const tranclusionFilePath = getLinkpath(tranclusionFileName); const linkedFile = this.metadataCache.getFirstLinkpathDest(tranclusionFilePath, filePath); - if (linkedFile.extension !== "md") { - continue; - } + if (linkedFile.name.endsWith(".excalidraw.md")) { + let fileText = await this.vault.cachedRead(linkedFile); + const start = fileText.indexOf('```json') + "```json".length; + const end = fileText.lastIndexOf('```') + const excaliDrawJson = JSON.parse(fileText.slice(start, end)); + + const drawingId = linkedFile.name; + let excaliDrawCode = ""; + if(++numberOfExcaliDraws === 1){ + excaliDrawCode += excaliDrawBundle; + } + excaliDrawCode += + + `${excalidraw(JSON.stringify(excaliDrawJson), drawingId)}`; + + transcludedText = transcludedText.replace(transclusionMatch, excaliDrawCode); + + }else if (linkedFile.extension === "md") { - let fileText = await this.vault.cachedRead(linkedFile); + let fileText = await this.vault.cachedRead(linkedFile); - //Remove frontmatter from transclusion - fileText = fileText.replace(/^---\n([\s\S]*?)\n---/g, ""); + //Remove frontmatter from transclusion + fileText = fileText.replace(/^---\n([\s\S]*?)\n---/g, ""); - const header = this.generateTransclusionHeader(headerName, linkedFile); + const header = this.generateTransclusionHeader(headerName, linkedFile); - const headerSection = header ? `${header}\n` : ''; + const headerSection = header ? `${header}\n` : ''; - fileText = `\n
\n\n` + headerSection + fileText + '\n
\n' - //This should be recursive up to a certain depth - transcludedText = transcludedText.replace(transclusionMatch, fileText); + fileText = `\n
\n\n` + headerSection + fileText + '\n
\n' + //This should be recursive up to a certain depth + transcludedText = transcludedText.replace(transclusionMatch, fileText); + } } catch { continue; } @@ -251,15 +269,15 @@ export default class Publisher { } generateTransclusionHeader(headerName: string, transcludedFile: TFile) { - if(!headerName) { + if (!headerName) { return headerName; } - + const titleVariable = "{{title}}"; if (headerName && headerName.indexOf(titleVariable) > -1) { headerName = headerName.replace(titleVariable, transcludedFile.basename); } - + //Defaults to h1 if (headerName && !headerName.startsWith("#")) { headerName = "# " + headerName; @@ -269,7 +287,7 @@ export default class Publisher { if (!headerParts.last().startsWith(" ")) { headerName = headerName.replace(headerParts.last(), " " + headerParts.last()); } - + } return headerName; } diff --git a/icons.ts b/constants.ts similarity index 50% rename from icons.ts rename to constants.ts index 71b4a935..73288134 100644 --- a/icons.ts +++ b/constants.ts @@ -1 +1,10 @@ export const seedling = `Layer 1` +export const excaliDrawBundle = ``; + +export let excalidraw = (excaliDrawJson:string , drawingId:string) => `
`; \ No newline at end of file diff --git a/main.ts b/main.ts index b89b072d..e06859ba 100644 --- a/main.ts +++ b/main.ts @@ -4,7 +4,7 @@ import DigitalGardenSettings from 'DigitalGardenSettings'; import DigitalGardenSiteManager from 'DigitalGardenSiteManager'; import SettingView from 'SettingView'; import { PublishStatusBar } from 'PublishStatusBar'; -import { seedling } from 'icons'; +import { seedling } from './constants'; import { PublishModal } from 'PublishModal'; const DEFAULT_SETTINGS: DigitalGardenSettings = { From 60461d9a76c2a57cec4399f2dbf18c18e99ad461 Mon Sep 17 00:00:00 2001 From: Ole Eskild Steensen Date: Mon, 14 Mar 2022 18:56:52 +0100 Subject: [PATCH 2/4] Support multiple excalidrawing in same document --- Publisher.ts | 19 +++++++++---------- constants.ts | 2 +- main.ts | 2 +- manifest.json | 2 +- versions.json | 1 + 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Publisher.ts b/Publisher.ts index 97159527..0f503d91 100644 --- a/Publisher.ts +++ b/Publisher.ts @@ -4,10 +4,7 @@ import { Base64 } from "js-base64"; import { Octokit } from "@octokit/core"; import { arrayBufferToBase64, generateUrlPath } from "utils"; import { vallidatePublishFrontmatter } from "Validator"; -import slugify from "@sindresorhus/slugify"; -import { title } from "process"; -import { excaliDrawBundle } from "constants"; -import { excalidraw } from "constants"; +import { excaliDrawBundle, excalidraw } from "./constants"; export interface IPublisher { @@ -209,13 +206,13 @@ export default class Publisher { const end = fileText.lastIndexOf('```') const excaliDrawJson = JSON.parse(fileText.slice(start, end)); - const drawingId = linkedFile.name; + const drawingId = linkedFile.name.split(" ").join("_").replace(".", "") + numberOfExcaliDraws; let excaliDrawCode = ""; if(++numberOfExcaliDraws === 1){ excaliDrawCode += excaliDrawBundle; } - excaliDrawCode += + - `${excalidraw(JSON.stringify(excaliDrawJson), drawingId)}`; + + excaliDrawCode += excalidraw(JSON.stringify(excaliDrawJson), drawingId); transcludedText = transcludedText.replace(transclusionMatch, excaliDrawCode); @@ -246,18 +243,20 @@ export default class Publisher { async createBase64Images(text: string, filePath: string): Promise { let imageText = text; - const imageRegex = /!\[\[(.*?)(\.(png|jpg|jpeg|gif))\]\]/g; + const imageRegex = /!\[\[(.*?)(\.(png|jpg|jpeg|gif))\|(.*?)\]\]|!\[\[(.*?)(\.(png|jpg|jpeg|gif))\]\]/g; const imageMatches = text.match(imageRegex); if (imageMatches) { for (let i = 0; i < imageMatches.length; i++) { try { const imageMatch = imageMatches[i]; - const imageName = imageMatch.substring(imageMatch.indexOf('[') + 2, imageMatch.indexOf(']')); + + let [imageName, size] = imageMatch.substring(imageMatch.indexOf('[') + 2, imageMatch.indexOf(']')).split("|"); const imagePath = getLinkpath(imageName); const linkedFile = this.metadataCache.getFirstLinkpathDest(imagePath, filePath); const image = await this.vault.readBinary(linkedFile); const imageBase64 = arrayBufferToBase64(image) - const imageMarkdown = `![${imageName}](data:image/${linkedFile.extension};base64,${imageBase64})`; + const name = size ? `${imageName}|${size}` : imageName; + const imageMarkdown = `![${name}](data:image/${linkedFile.extension};base64,${imageBase64})`; imageText = imageText.replace(imageMatch, imageMarkdown); } catch { continue; diff --git a/constants.ts b/constants.ts index 73288134..770e8750 100644 --- a/constants.ts +++ b/constants.ts @@ -7,4 +7,4 @@ export const excaliDrawBundle = ``; -export let excalidraw = (excaliDrawJson:string , drawingId:string) => `
`; \ No newline at end of file +export let excalidraw = (excaliDrawJson:string , drawingId:string):string => `
`; \ No newline at end of file diff --git a/main.ts b/main.ts index e06859ba..bb62748b 100644 --- a/main.ts +++ b/main.ts @@ -22,7 +22,7 @@ export default class DigitalGarden extends Plugin { publishModal: PublishModal; async onload() { - this.appVersion = "2.4.0"; + this.appVersion = "2.5.0"; console.log("Initializing DigitalGarden plugin v" + this.appVersion); await this.loadSettings(); diff --git a/manifest.json b/manifest.json index b0c11162..db14aa6e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "digitalgarden", "name": "Digital Garden", - "version": "2.4.0", + "version": "2.5.0", "minAppVersion": "0.12.0", "description": "Publish your notes to a digital garden for others to enjoy.", "author": "Ole Eskild Steensen", diff --git a/versions.json b/versions.json index 24965ae9..4a1ea20f 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ { + "2.5.0": "0.12.0", "2.4.0": "0.12.0", "2.3.1": "0.12.0", "2.3.0": "0.12.0", From 620fcd21c5273aeac6b45989794883491b852918 Mon Sep 17 00:00:00 2001 From: Ole Eskild Steensen Date: Mon, 14 Mar 2022 18:57:30 +0100 Subject: [PATCH 3/4] Fix bug where modal could contain duplicates --- PublishModal.ts | 73 +++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/PublishModal.ts b/PublishModal.ts index 69912fae..e339ad26 100644 --- a/PublishModal.ts +++ b/PublishModal.ts @@ -15,7 +15,7 @@ export class PublishModal { deletedContainer: HTMLElement; unpublishedContainer: HTMLElement; - constructor(app: App, siteManager: IDigitalGardenSiteManager, publisher: IPublisher, + constructor(app: App, siteManager: IDigitalGardenSiteManager, publisher: IPublisher, settings: DigitalGardenSettings) { this.modal = new Modal(app) this.siteManager = siteManager; @@ -25,19 +25,19 @@ export class PublishModal { this.initialize(); } - createCollapsable(title:string): HTMLElement{ - const toggleHeader = this.modal.contentEl.createEl("h3", { text: `➡️️ ${title}`, attr:{class:"collapsable collapsed"} }); + createCollapsable(title: string): HTMLElement { + const toggleHeader = this.modal.contentEl.createEl("h3", { text: `➕️ ${title}`, attr: { class: "collapsable collapsed" } }); const toggledList = this.modal.contentEl.createEl("ul"); toggledList.hide(); toggleHeader.onClickEvent(() => { - if(toggledList.isShown()){ - toggleHeader.textContent = `➡️️ ${title}`; + if (toggledList.isShown()) { + toggleHeader.textContent = `➕️ ${title}`; toggledList.hide(); toggleHeader.removeClass("open"); toggleHeader.addClass("collapsed"); - }else{ - toggleHeader.textContent = `⬇️ ${title}`; + } else { + toggleHeader.textContent = `➖ ${title}`; toggledList.show() toggleHeader.removeClass("collapsed"); toggleHeader.addClass("open"); @@ -54,29 +54,37 @@ export class PublishModal { this.modal.contentEl.createEl("h2", { text: "Publication Status" }); this.publishedContainer = this.createCollapsable("Published"); - this.changedContainer= this.createCollapsable("Changed"); + this.changedContainer = this.createCollapsable("Changed"); this.deletedContainer = this.createCollapsable("Deleted from vault"); this.unpublishedContainer = this.createCollapsable("Unpublished"); - - this.modal.onOpen = ()=>this.populateWithNotes(); - this.modal.onClose = ()=>this.clearView(); + + this.modal.onOpen = () => this.populateWithNotes(); + this.modal.onClose = () => this.clearView(); } - async clearView(){ - this.publishedContainer.childNodes.forEach(node=>node.remove()); - this.changedContainer.childNodes.forEach(node=>node.remove()); - this.deletedContainer.childNodes.forEach(node=>node.remove()); - this.unpublishedContainer.childNodes.forEach(node=>node.remove()); + async clearView() { + while (this.publishedContainer.lastElementChild) { + this.publishedContainer.removeChild(this.publishedContainer.lastElementChild); + } + while (this.changedContainer.lastElementChild) { + this.changedContainer.removeChild(this.changedContainer.lastElementChild); + } + while (this.deletedContainer.lastElementChild) { + this.deletedContainer.removeChild(this.deletedContainer.lastElementChild); + } + while (this.unpublishedContainer.lastElementChild) { + this.unpublishedContainer.removeChild(this.unpublishedContainer.lastElementChild); + } } - async populateWithNotes(){ + async populateWithNotes() { const publishStatus = await this.buildPublishStatus(); - publishStatus.publishedNotes.map(file=>this.publishedContainer.createEl("li", { text: file.path})); - publishStatus.unpublishedNotes.map(file=>this.unpublishedContainer.createEl("li", { text: file.path})); - publishStatus.changedNotes.map(file=>this.changedContainer.createEl("li", { text: file.path})); - publishStatus.deletedNotePaths.map(path=>this.deletedContainer.createEl("li", { text: path})); + publishStatus.publishedNotes.map(file => this.publishedContainer.createEl("li", { text: file.path })); + publishStatus.unpublishedNotes.map(file => this.unpublishedContainer.createEl("li", { text: file.path })); + publishStatus.changedNotes.map(file => this.changedContainer.createEl("li", { text: file.path })); + publishStatus.deletedNotePaths.map(path => this.deletedContainer.createEl("li", { text: path })); } - async buildPublishStatus(){ + async buildPublishStatus(): Promise { const unpublishedNotes: Array = []; const publishedNotes: Array = []; const changedNotes: Array = []; @@ -91,27 +99,38 @@ export class PublishModal { const localHash = generateBlobHash(content); const remoteHash = remoteNoteHashes[file.path]; - if(!remoteHash) { + if (!remoteHash) { unpublishedNotes.push(file); } - else if(remoteHash === localHash) { + else if (remoteHash === localHash) { publishedNotes.push(file); } - else{ + else { changedNotes.push(file); } } Object.keys(remoteNoteHashes).forEach(key => { - if(!marked.find(f => f.path === key)) { + if (!marked.find(f => f.path === key)) { deletedNotePaths.push(key); } }); - return {unpublishedNotes, publishedNotes, changedNotes, deletedNotePaths}; + unpublishedNotes.sort((a, b) => a.path > b.path ? 1 : -1); + publishedNotes.sort((a, b) => a.path > b.path ? 1 : -1); + changedNotes.sort((a, b) => a.path > b.path ? 1 : -1); + deletedNotePaths.sort((a, b) => a > b ? 1 : -1); + return { unpublishedNotes, publishedNotes, changedNotes, deletedNotePaths }; } open() { this.modal.open(); } +} + +interface PublishStatus{ + unpublishedNotes: Array; + publishedNotes: Array; + changedNotes: Array; + deletedNotePaths: Array; } \ No newline at end of file From 4b24d09dc2ae25af63930dcbbaeb355e0de6fde1 Mon Sep 17 00:00:00 2001 From: Ole Eskild Steensen Date: Mon, 14 Mar 2022 18:59:34 +0100 Subject: [PATCH 4/4] Add excalidraw as supported content --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ac60ca79..3ea13b56 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ In the future you will be notified with a visual cue whenever there is an update The plugin currently supports rendering of these types of note contents: * Basic Markdown Syntax * Links to other notes +* Embedded/Transcluded Excalidraw drawings * Code Blocks * Admonitions * MathJax