Fix PDF export with Tauri native dialogs and proper margins
- Installed @tauri-apps/plugin-dialog for native dialogs - Added tauri-plugin-dialog to Rust dependencies - Registered dialog plugin in Tauri app initialization - Replaced web alert() with Tauri message() dialog - Success dialog shows filename and download location - Error dialog shows if export fails - Added 20mm margins on all sides of PDF pages - Content width adjusted to 170mm (210mm - 40mm margins) - Multi-page support respects margins on all pages - Native dialogs work properly in Tauri app
This commit is contained in:
10
package-lock.json
generated
10
package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
|
"@tauri-apps/plugin-dialog": "^2.6.0",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
"@tiptap/extension-strike": "^2.27.2",
|
"@tiptap/extension-strike": "^2.27.2",
|
||||||
"@tiptap/extension-underline": "^2.27.2",
|
"@tiptap/extension-underline": "^2.27.2",
|
||||||
@@ -1489,6 +1490,15 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tauri-apps/plugin-dialog": {
|
||||||
|
"version": "2.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.6.0.tgz",
|
||||||
|
"integrity": "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==",
|
||||||
|
"license": "MIT OR Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^2.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tauri-apps/plugin-opener": {
|
"node_modules/@tauri-apps/plugin-opener": {
|
||||||
"version": "2.5.3",
|
"version": "2.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.3.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
|
"@tauri-apps/plugin-dialog": "^2.6.0",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
"@tiptap/extension-strike": "^2.27.2",
|
"@tiptap/extension-strike": "^2.27.2",
|
||||||
"@tiptap/extension-underline": "^2.27.2",
|
"@tiptap/extension-underline": "^2.27.2",
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ tauri = { version = "2", features = [] }
|
|||||||
tauri-plugin-opener = "2"
|
tauri-plugin-opener = "2"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
tauri-plugin-dialog = "2.6.0"
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ fn greet(name: &str) -> String {
|
|||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.invoke_handler(tauri::generate_handler![greet])
|
.invoke_handler(tauri::generate_handler![greet])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import TurndownService from 'turndown';
|
|||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import jsPDF from 'jspdf';
|
import jsPDF from 'jspdf';
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
|
import { message } from '@tauri-apps/plugin-dialog';
|
||||||
import { Note } from '../types';
|
import { Note } from '../types';
|
||||||
|
|
||||||
interface NoteEditorProps {
|
interface NoteEditorProps {
|
||||||
@@ -154,8 +155,9 @@ export function NoteEditor({ note, onUpdateNote, fontSize, onUnsavedChanges }: N
|
|||||||
|
|
||||||
// Create a temporary container with better styling for PDF
|
// Create a temporary container with better styling for PDF
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.style.width = '210mm'; // A4 width
|
const contentWidth = 170; // A4 width (210mm) - margins (20mm each side)
|
||||||
container.style.padding = '20mm';
|
container.style.width = `${contentWidth}mm`;
|
||||||
|
container.style.padding = '0';
|
||||||
container.style.backgroundColor = 'white';
|
container.style.backgroundColor = 'white';
|
||||||
container.style.position = 'absolute';
|
container.style.position = 'absolute';
|
||||||
container.style.left = '-9999px';
|
container.style.left = '-9999px';
|
||||||
@@ -188,7 +190,7 @@ export function NoteEditor({ note, onUpdateNote, fontSize, onUnsavedChanges }: N
|
|||||||
// Remove temporary container
|
// Remove temporary container
|
||||||
document.body.removeChild(container);
|
document.body.removeChild(container);
|
||||||
|
|
||||||
// Create PDF with multi-page support
|
// Create PDF with multi-page support and margins
|
||||||
const pdf = new jsPDF({
|
const pdf = new jsPDF({
|
||||||
orientation: 'portrait',
|
orientation: 'portrait',
|
||||||
unit: 'mm',
|
unit: 'mm',
|
||||||
@@ -197,36 +199,54 @@ export function NoteEditor({ note, onUpdateNote, fontSize, onUnsavedChanges }: N
|
|||||||
|
|
||||||
const pageWidth = 210; // A4 width in mm
|
const pageWidth = 210; // A4 width in mm
|
||||||
const pageHeight = 297; // A4 height in mm
|
const pageHeight = 297; // A4 height in mm
|
||||||
const imgWidth = pageWidth;
|
const margin = 20; // 20mm margins on all sides
|
||||||
|
const contentWidthMm = pageWidth - (2 * margin);
|
||||||
|
const contentHeightMm = pageHeight - (2 * margin);
|
||||||
|
|
||||||
|
const imgWidth = contentWidthMm;
|
||||||
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||||
|
|
||||||
let heightLeft = imgHeight;
|
let heightLeft = imgHeight;
|
||||||
let position = 0;
|
let position = 0;
|
||||||
|
|
||||||
// Add first page
|
// Add first page with margins
|
||||||
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
|
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', margin, margin + position, imgWidth, imgHeight);
|
||||||
heightLeft -= pageHeight;
|
heightLeft -= contentHeightMm;
|
||||||
|
|
||||||
// Add additional pages if needed
|
// Add additional pages if needed
|
||||||
while (heightLeft > 0) {
|
while (heightLeft > 0) {
|
||||||
position = heightLeft - imgHeight;
|
position = heightLeft - imgHeight;
|
||||||
pdf.addPage();
|
pdf.addPage();
|
||||||
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
|
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', margin, margin + position, imgWidth, imgHeight);
|
||||||
heightLeft -= pageHeight;
|
heightLeft -= contentHeightMm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the PDF
|
// Save the PDF
|
||||||
const fileName = `${localTitle || 'note'}.pdf`;
|
const fileName = `${localTitle || 'note'}.pdf`;
|
||||||
pdf.save(fileName);
|
pdf.save(fileName);
|
||||||
|
|
||||||
// Show success message
|
// Show success message using Tauri dialog
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
alert(`PDF exported successfully!\n\nFile: ${fileName}\nLocation: Downloads folder`);
|
try {
|
||||||
|
await message(`PDF exported successfully!\n\nFile: ${fileName}\nLocation: Downloads folder`, {
|
||||||
|
title: 'Export Complete',
|
||||||
|
kind: 'info',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Dialog shown successfully or not available');
|
||||||
|
}
|
||||||
setIsExportingPDF(false);
|
setIsExportingPDF(false);
|
||||||
}, 500);
|
}, 500);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('PDF export failed:', error);
|
console.error('PDF export failed:', error);
|
||||||
alert('Failed to export PDF. Please try again.');
|
try {
|
||||||
|
await message('Failed to export PDF. Please try again.', {
|
||||||
|
title: 'Export Failed',
|
||||||
|
kind: 'error',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Could not show error dialog');
|
||||||
|
}
|
||||||
setIsExportingPDF(false);
|
setIsExportingPDF(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user