mirror of
https://github.com/ethanolivertroy/obsidian-markitdown.git
synced 2026-07-22 05:41:54 +00:00
Merge branch 'worktree-agent-af6650b1'
# Conflicts: # src/modals/FileConvertModal.ts # styles.css
This commit is contained in:
commit
733e4dca8f
4 changed files with 198 additions and 10 deletions
30
main.ts
30
main.ts
|
|
@ -25,6 +25,7 @@ import { FileConvertModal } from './src/modals/FileConvertModal';
|
|||
import { FolderConvertModal } from './src/modals/FolderConvertModal';
|
||||
import { UrlConvertModal } from './src/modals/UrlConvertModal';
|
||||
import { SetupModal } from './src/modals/SetupModal';
|
||||
import { PreviewModal } from './src/modals/PreviewModal';
|
||||
|
||||
export default class MarkitdownPlugin extends Plugin {
|
||||
settings: MarkitdownSettings = DEFAULT_SETTINGS;
|
||||
|
|
@ -245,11 +246,30 @@ export default class MarkitdownPlugin extends Plugin {
|
|||
const result = await this.converter.convert(inputPath, outputPath, options);
|
||||
|
||||
if (result.success) {
|
||||
const msg = result.imagesExtracted
|
||||
? `Converted successfully (${result.imagesExtracted} images extracted)`
|
||||
: 'Converted successfully';
|
||||
new Notice(msg);
|
||||
await this.openConvertedFile(outputPath, vaultPath);
|
||||
let content: string;
|
||||
try {
|
||||
content = await fs.promises.readFile(outputPath, 'utf-8');
|
||||
} catch {
|
||||
new Notice('Conversion succeeded but could not read output file');
|
||||
return;
|
||||
}
|
||||
|
||||
new PreviewModal(this.app, {
|
||||
content,
|
||||
outputPath,
|
||||
processingTime: result.processingTime ?? 0,
|
||||
onSave: async () => {
|
||||
const msg = result.imagesExtracted
|
||||
? `Converted successfully (${result.imagesExtracted} images extracted)`
|
||||
: 'Converted successfully';
|
||||
new Notice(msg);
|
||||
await this.openConvertedFile(outputPath, vaultPath);
|
||||
},
|
||||
onCancel: async () => {
|
||||
await fs.promises.unlink(outputPath).catch(() => {});
|
||||
new Notice('Conversion discarded');
|
||||
},
|
||||
}).open();
|
||||
} else {
|
||||
new Notice(`Conversion failed: ${result.error}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import * as fs from 'fs';
|
|||
import type MarkitdownPlugin from '../../main';
|
||||
import { FILE_INPUT_ACCEPT } from '../utils/fileTypes';
|
||||
import { getVaultBasePath, resolveOutputFolder, resolveFilenameTemplate, toVaultRelative } from '../utils/paths';
|
||||
import { PreviewModal } from './PreviewModal';
|
||||
|
||||
export class FileConvertModal extends Modal {
|
||||
private plugin: MarkitdownPlugin;
|
||||
|
|
@ -67,12 +68,36 @@ export class FileConvertModal extends Modal {
|
|||
const result = await this.plugin.convertExternalFile(tempFilePath, outputPath);
|
||||
|
||||
if (result.success) {
|
||||
const msg = result.imagesExtracted
|
||||
? `Converted successfully (${result.imagesExtracted} images extracted)`
|
||||
: 'Converted successfully';
|
||||
new Notice(msg);
|
||||
// Read the converted output for preview
|
||||
let content: string;
|
||||
try {
|
||||
content = await fs.promises.readFile(outputPath, 'utf-8');
|
||||
} catch {
|
||||
new Notice('Conversion succeeded but could not read output file');
|
||||
convertButton.disabled = false;
|
||||
convertButton.setText('Convert');
|
||||
return;
|
||||
}
|
||||
|
||||
this.close();
|
||||
await this.plugin.openConvertedFile(outputPath, vaultPath);
|
||||
|
||||
new PreviewModal(this.app, {
|
||||
content,
|
||||
outputPath,
|
||||
processingTime: result.processingTime ?? 0,
|
||||
onSave: async () => {
|
||||
const msg = result.imagesExtracted
|
||||
? `Converted successfully (${result.imagesExtracted} images extracted)`
|
||||
: 'Converted successfully';
|
||||
new Notice(msg);
|
||||
await this.plugin.openConvertedFile(outputPath, vaultPath);
|
||||
},
|
||||
onCancel: async () => {
|
||||
// Discard the converted output file
|
||||
await fs.promises.unlink(outputPath).catch(() => {});
|
||||
new Notice('Conversion discarded');
|
||||
},
|
||||
}).open();
|
||||
} else {
|
||||
new Notice(`Conversion failed: ${result.error}`);
|
||||
convertButton.disabled = false;
|
||||
|
|
|
|||
97
src/modals/PreviewModal.ts
Normal file
97
src/modals/PreviewModal.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { App, Modal } from 'obsidian';
|
||||
|
||||
const MAX_PREVIEW_LINES = 500;
|
||||
|
||||
export class PreviewModal extends Modal {
|
||||
private content: string;
|
||||
private outputPath: string;
|
||||
private processingTime: number;
|
||||
private onSave: () => Promise<void> | void;
|
||||
private onCancel: () => Promise<void> | void;
|
||||
|
||||
constructor(
|
||||
app: App,
|
||||
opts: {
|
||||
content: string;
|
||||
outputPath: string;
|
||||
processingTime: number;
|
||||
onSave: () => Promise<void> | void;
|
||||
onCancel: () => Promise<void> | void;
|
||||
}
|
||||
) {
|
||||
super(app);
|
||||
this.content = opts.content;
|
||||
this.outputPath = opts.outputPath;
|
||||
this.processingTime = opts.processingTime;
|
||||
this.onSave = opts.onSave;
|
||||
this.onCancel = opts.onCancel;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
contentEl.addClass('markitdown-modal');
|
||||
contentEl.addClass('markitdown-preview-modal');
|
||||
contentEl.createEl('h2', { text: 'Conversion preview' });
|
||||
|
||||
// Metadata section
|
||||
const metaEl = contentEl.createDiv('markitdown-preview-meta');
|
||||
metaEl.createEl('div', {
|
||||
text: `Output: ${this.outputPath}`,
|
||||
cls: 'markitdown-preview-meta-item',
|
||||
});
|
||||
metaEl.createEl('div', {
|
||||
text: `Processing time: ${(this.processingTime / 1000).toFixed(1)}s`,
|
||||
cls: 'markitdown-preview-meta-item',
|
||||
});
|
||||
metaEl.createEl('div', {
|
||||
text: `Content length: ${this.content.length.toLocaleString()} characters`,
|
||||
cls: 'markitdown-preview-meta-item',
|
||||
});
|
||||
|
||||
// Determine if content should be truncated
|
||||
const lines = this.content.split('\n');
|
||||
const truncated = lines.length > MAX_PREVIEW_LINES;
|
||||
const displayContent = truncated
|
||||
? lines.slice(0, MAX_PREVIEW_LINES).join('\n')
|
||||
: this.content;
|
||||
|
||||
if (truncated) {
|
||||
contentEl.createEl('div', {
|
||||
text: `Showing first ${MAX_PREVIEW_LINES} of ${lines.length} lines`,
|
||||
cls: 'markitdown-preview-truncation-note',
|
||||
});
|
||||
}
|
||||
|
||||
// Scrollable preview area
|
||||
const previewContainer = contentEl.createDiv('markitdown-preview-content');
|
||||
previewContainer.createEl('pre', { text: displayContent });
|
||||
|
||||
// Buttons
|
||||
const buttonContainer = contentEl.createDiv('markitdown-button-container');
|
||||
|
||||
const cancelBtn = buttonContainer.createEl('button', { text: 'Cancel' });
|
||||
cancelBtn.addEventListener('click', async () => {
|
||||
await this.onCancel();
|
||||
this.close();
|
||||
});
|
||||
|
||||
const saveBtn = buttonContainer.createEl('button', {
|
||||
text: 'Save',
|
||||
cls: 'mod-cta',
|
||||
});
|
||||
saveBtn.addEventListener('click', async () => {
|
||||
saveBtn.disabled = true;
|
||||
saveBtn.setText('Saving...');
|
||||
cancelBtn.disabled = true;
|
||||
try {
|
||||
await this.onSave();
|
||||
} finally {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.contentEl.empty();
|
||||
}
|
||||
}
|
||||
46
styles.css
46
styles.css
|
|
@ -176,6 +176,7 @@ Styles for the Markitdown Obsidian plugin
|
|||
font-weight: 500;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
/* Resolved path hint */
|
||||
.markitdown-resolved-path-hint {
|
||||
font-size: 0.85em;
|
||||
|
|
@ -285,6 +286,51 @@ Styles for the Markitdown Obsidian plugin
|
|||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
/* Preview modal */
|
||||
.markitdown-preview-modal {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.markitdown-preview-meta {
|
||||
background-color: var(--background-secondary);
|
||||
padding: 10px 14px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.markitdown-preview-meta-item {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-muted);
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.markitdown-preview-truncation-note {
|
||||
font-size: 0.85em;
|
||||
color: var(--text-accent);
|
||||
margin-bottom: 8px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.markitdown-preview-content {
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px;
|
||||
background-color: var(--background-primary-alt);
|
||||
padding: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markitdown-preview-content pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 0.85em;
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
/* Plugin args editor */
|
||||
.markitdown-plugin-args-container {
|
||||
margin: 8px 0 16px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue