diff --git a/package.json b/package.json index ffffc99..4ad072e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.8", - "@zsviczian/excalidraw": "0.18.0-8", + "@zsviczian/excalidraw": "0.18.0-9", "chroma-js": "^2.4.2", "clsx": "^2.0.0", "@zsviczian/colormaster": "^1.2.2", diff --git a/src/core/settings.ts b/src/core/settings.ts index 4c3a550..666e308 100644 --- a/src/core/settings.ts +++ b/src/core/settings.ts @@ -46,6 +46,7 @@ import { PDFExportSettingsComponent, PDFExportSettings } from "src/shared/Dialog import de from "src/lang/locale/de"; export interface ExcalidrawSettings { + disableDoubleClickTextEditing: boolean; folder: string; cropFolder: string; annotateFolder: string; @@ -228,6 +229,7 @@ export interface ExcalidrawSettings { declare const PLUGIN_VERSION:string; export const DEFAULT_SETTINGS: ExcalidrawSettings = { + disableDoubleClickTextEditing: false, folder: "Excalidraw", cropFolder: "", annotateFolder: "", @@ -684,6 +686,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab { }), ); + new Setting(detailsEl) + .setName(t("TOGGLE_SPLASHSCREEN")) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.showSplashscreen) + .onChange((value)=> { + this.plugin.settings.showSplashscreen = value; + this.applySettingsUpdate(); + }) + ) + new Setting(detailsEl) .setName(t("FOLDER_NAME")) .setDesc(fragWithHTML(t("FOLDER_DESC"))) @@ -1094,6 +1107,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab { cls: "excalidraw-setting-h1", }); + new Setting(detailsEl) + .setName(t("ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME")) + .addToggle((toggle) => + toggle + .setValue(!this.plugin.settings.disableDoubleClickTextEditing) + .onChange(async (value) => { + this.plugin.settings.disableDoubleClickTextEditing = !value; + this.applySettingsUpdate(); + }), + ); + const readingModeEl = new Setting(detailsEl) .setName(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_NAME")) .setDesc(fragWithHTML(t("SHOW_DRAWING_OR_MD_IN_READING_MODE_DESC"))) @@ -1136,17 +1160,6 @@ export class ExcalidrawSettingTab extends PluginSettingTab { ); addIframe(detailsEl, "H8Njp7ZXYag",999); - new Setting(detailsEl) - .setName(t("TOGGLE_SPLASHSCREEN")) - .addToggle((toggle) => - toggle - .setValue(this.plugin.settings.showSplashscreen) - .onChange((value)=> { - this.plugin.settings.showSplashscreen = value; - this.applySettingsUpdate(); - }) - ) - detailsEl = displayDetailsEl.createEl("details"); detailsEl.createEl("summary", { text: t("HOTKEY_OVERRIDE_HEAD"), diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 2607d00..9d4070a 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -371,6 +371,7 @@ FILENAME_HEAD: "Filename", DEFAULT_PEN_MODE_NAME: "Pen mode", DEFAULT_PEN_MODE_DESC: "Should pen mode be automatically enabled when opening Excalidraw?", + ENABLE_DOUBLE_CLICK_TEXT_EDITING_NAME: "Enable double-click text create", DISABLE_DOUBLE_TAP_ERASER_NAME: "Enable double-tap eraser in pen mode", DISABLE_SINGLE_FINGER_PANNING_NAME: "Enable single-finger panning in pen mode", SHOW_PEN_MODE_FREEDRAW_CROSSHAIR_NAME: "Show (+) crosshair in pen mode", diff --git a/src/shared/Dialogs/ExportDialog.ts b/src/shared/Dialogs/ExportDialog.ts index a4f5f31..52a6d7b 100644 --- a/src/shared/Dialogs/ExportDialog.ts +++ b/src/shared/Dialogs/ExportDialog.ts @@ -43,6 +43,7 @@ export class ExportDialog extends Modal { public customPaperColor: string = "#ffffff"; public alignment: PDFPageAlignment = "center"; public margin: PDFPageMarginString = "normal"; + private scaleSetting:Setting; constructor( private plugin: ExcalidrawPlugin, @@ -85,6 +86,17 @@ export class ExportDialog extends Modal { this.selectedOnlySetting = null; this.containerEl.remove(); } + + updateBoundingBox() { + if(this.hasSelectedElements && this.exportSelectedOnly) { + this.boundingBox = this.ea.getBoundingBox(this.view.getViewSelectedElements()); + } else { + this.boundingBox = this.ea.getBoundingBox(this.ea.getViewElements()); + } + if(this.scaleSetting) { + this.scaleSetting.setDesc(this.size()); + } + } onOpen(): void { this.containerEl.classList.add("excalidraw-release"); @@ -92,6 +104,7 @@ export class ExportDialog extends Modal { this.hasSelectedElements = this.view.getViewSelectedElements().length > 0; //@ts-ignore this.selectedOnlySetting.setVisibility(this.hasSelectedElements); + this.updateBoundingBox(); } async onClose() { @@ -167,9 +180,14 @@ export class ExportDialog extends Modal { this.createPDFButton(); } } + + private size ():DocumentFragment { + const width = Math.round(this.scale*this.boundingBox.width + this.padding*2); + const height = Math.round(this.scale*this.boundingBox.height + this.padding*2); + return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}
${t("EXPORTDIALOG_SCALE_VALUE")} ${this.scale}
${t("EXPORTDIALOG_IMAGE_SIZE")} ${width}x${height}`); + } private createImageSettings() { - let scaleSetting:Setting; let paddingSetting: Setting; this.contentContainer.createEl("h1",{text: t("EXPORTDIALOG_IMAGE_SETTINGS")}); @@ -177,12 +195,6 @@ export class ExportDialog extends Modal { this.createSaveSettingsDropdown(); - const size = ():DocumentFragment => { - const width = Math.round(this.scale*this.boundingBox.width + this.padding*2); - const height = Math.round(this.scale*this.boundingBox.height + this.padding*2); - return fragWithHTML(`${t("EXPORTDIALOG_SIZE_DESC")}
${t("EXPORTDIALOG_SCALE_VALUE")} ${this.scale}
${t("EXPORTDIALOG_IMAGE_SIZE")} ${width}x${height}`); - } - const padding = ():DocumentFragment => { return fragWithHTML(`${t("EXPORTDIALOG_CURRENT_PADDING")} ${this.padding}`); } @@ -196,21 +208,21 @@ export class ExportDialog extends Modal { .setValue(this.padding) .onChange(value => { this.padding = value; - scaleSetting.setDesc(size()); + this.scaleSetting.setDesc(this.size()); paddingSetting.setDesc(padding()); }) }) - scaleSetting = new Setting(this.contentContainer) + this.scaleSetting = new Setting(this.contentContainer) .setName(t("EXPORTDIALOG_SCALE")) - .setDesc(size()) + .setDesc(this.size()) .addSlider(slider => slider .setLimits(0.2,7,0.1) .setValue(this.scale) .onChange(value => { this.scale = value; - scaleSetting.setDesc(size()); + this.scaleSetting.setDesc(this.size()); }) ) @@ -247,6 +259,7 @@ export class ExportDialog extends Modal { .setValue(this.exportSelectedOnly?"selected":"all") .onChange(value => { this.exportSelectedOnly = value === "selected"; + this.updateBoundingBox(); }) ); } diff --git a/src/shared/Dialogs/InsertPDFModal.ts b/src/shared/Dialogs/InsertPDFModal.ts index d2f024f..13f1826 100644 --- a/src/shared/Dialogs/InsertPDFModal.ts +++ b/src/shared/Dialogs/InsertPDFModal.ts @@ -70,7 +70,7 @@ export class InsertPDFModal extends Modal { this.setImageSizeMessage = null; } - private async getPageDimensions (pdfDoc: any) { + private async getPDFPageDimensions (pdfDoc: any) { try { const scale = this.plugin.settings.pdfScale; const canvas = createEl("canvas"); @@ -197,7 +197,7 @@ export class InsertPDFModal extends Modal { rangeOnChange(`1-${numPages}`); importButtonMessages(); numPagesMessages(); - this.getPageDimensions(this.pdfDoc); + this.getPDFPageDimensions(this.pdfDoc); } else { importButton.setDisabled(true); } diff --git a/src/shared/Dialogs/Messages.ts b/src/shared/Dialogs/Messages.ts index 02968e9..5eca86c 100644 --- a/src/shared/Dialogs/Messages.ts +++ b/src/shared/Dialogs/Messages.ts @@ -23,6 +23,8 @@ I build this plugin in my free time, as a labor of love. Curious about the philo ## New - Expose parameter in plugin settings to disable AI functionality [#2325](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2325) +- Enable double-click text editing option in Excalidraw appearance and behavior (based on request on Discord) +- Added two new PDF export sizes: "Match image", "HD Screen". ## Fixed in the plugin - Scaling multiple embeddables at once did not work. [#2276](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2276) diff --git a/src/shared/Dialogs/PDFExportSettingsComponent.ts b/src/shared/Dialogs/PDFExportSettingsComponent.ts index 2c2f833..7a9463d 100644 --- a/src/shared/Dialogs/PDFExportSettingsComponent.ts +++ b/src/shared/Dialogs/PDFExportSettingsComponent.ts @@ -21,6 +21,10 @@ export class PDFExportSettingsComponent { if (!update) this.update = () => {}; } + isOrientationAndTilingVisible() { + return !(this.settings.pageSize === "HD Screen" || this.settings.pageSize === "MATCH IMAGE"); + } + render() { const pageSizeOptions: Record = Object.keys(STANDARD_PAGE_SIZES) .reduce((acc, key) => ({ @@ -28,6 +32,8 @@ export class PDFExportSettingsComponent { [key]: key }), {}); + let div: HTMLDivElement; + new Setting(this.contentEl) .setName(t("EXPORTDIALOG_PAGE_SIZE")) .addDropdown(dropdown => @@ -36,11 +42,15 @@ export class PDFExportSettingsComponent { .setValue(this.settings.pageSize) .onChange(value => { this.settings.pageSize = value as PageSize; + div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none"; this.update(); }) ); - new Setting(this.contentEl) + div = this.contentEl.createDiv(); + div.style.display = this.isOrientationAndTilingVisible() ? "block" : "none"; + + new Setting(div) .setName(t("EXPORTDIALOG_PAGE_ORIENTATION")) .addDropdown(dropdown => dropdown @@ -55,7 +65,7 @@ export class PDFExportSettingsComponent { }) ); - new Setting(this.contentEl) + new Setting(div) .setName(t("EXPORTDIALOG_PDF_FIT_TO_PAGE")) .addDropdown(dropdown => dropdown diff --git a/src/utils/exportUtils.ts b/src/utils/exportUtils.ts index ae40297..f421f00 100644 --- a/src/utils/exportUtils.ts +++ b/src/utils/exportUtils.ts @@ -54,7 +54,9 @@ export const STANDARD_PAGE_SIZES = { Legal: { width: 816, height: 1344 }, // 8.5 × 14 inches Letter: { width: 816, height: 1056 }, // 8.5 × 11 inches Tabloid: { width: 1056, height: 1632 }, // 11 × 17 inches - Ledger: { width: 1632, height: 1056 } // 17 × 11 inches + Ledger: { width: 1632, height: 1056 }, // 17 × 11 inches + "HD Screen": { width: 1920, height: 1080 },// 16:9 aspect ratio + "MATCH IMAGE": { width: 0, height: 0 }, // 0 means use the current screen size } as const; export type PageSize = keyof typeof STANDARD_PAGE_SIZES; @@ -69,9 +71,15 @@ export function getMarginValue(margin:PDFPageMarginString): PDFMargin { } } -export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation): PageDimensions { - const dimensions = STANDARD_PAGE_SIZES[pageSize]; - return orientation === "portrait" +export function getPageDimensions(pageSize: PageSize, orientation: PageOrientation, dims?: {width: number, height: number}): PageDimensions { + let dimensions:{width: number, height: number}; + dimensions = STANDARD_PAGE_SIZES[pageSize]; + + if (dims && dimensions.width === 0 && dimensions.height === 0) { + dimensions = { width: dims.width, height: dims.height }; + } + + return orientation === "portrait" || pageSize === "MATCH IMAGE" || pageSize === "HD Screen" ? { width: dimensions.width, height: dimensions.height } : { width: dimensions.height, height: dimensions.width }; } diff --git a/src/view/ExcalidrawView.ts b/src/view/ExcalidrawView.ts index 78ee4f4..c0895c1 100644 --- a/src/view/ExcalidrawView.ts +++ b/src/view/ExcalidrawView.ts @@ -77,7 +77,6 @@ import { getExcalidrawMarkdownHeaderSection, } from "../shared/ExcalidrawData"; import { - arrayBufferToBase64, checkAndCreateFolder, createOrOverwriteFile, download, @@ -155,7 +154,6 @@ import { ImageInfo } from "src/types/excalidrawAutomateTypes"; import { exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils"; import { FrameRenderingOptions } from "src/types/utilTypes"; import { CaptureUpdateAction } from "src/constants/constants"; -import { FlipHorizontal } from "lucide-react"; const EMBEDDABLE_SEMAPHORE_TIMEOUT = 2000; const PREVENT_RELOAD_TIMEOUT = 2000; @@ -612,8 +610,10 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{ return; } + const scene = this.getScene(selectedOnly); + const svg = await this.svg( - this.getScene(selectedOnly), + scene, undefined, false, true @@ -622,20 +622,26 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{ if (!svg) { return; } - + + const boundingBox = this.plugin.ea.getBoundingBox(scene.elements); + const margin = getMarginValue(this.exportDialog.margin); + const [width, height] = [boundingBox.width, boundingBox.height]; + exportToPDF({ SVG: [svg], scale: { zoom: this.exportDialog.scale, - fitToPage: this.exportDialog.fitToPage + fitToPage: pageSize === "MATCH IMAGE" || pageSize === "HD Screen" + ? 1 + : this.exportDialog.fitToPage }, pageProps: { - dimensions: getPageDimensions(pageSize, orientation), + dimensions: getPageDimensions(pageSize, orientation, {width, height}), backgroundColor: this.exportDialog.getPaperColor(), - margin: getMarginValue(this.exportDialog.margin), + margin, alignment: this.exportDialog.alignment, }, - filename: this.file.basename, + filename: this.file.basename+".pdf", }); }