diff --git a/apps/server/src/integrations/import/services/import-attachment.service.ts b/apps/server/src/integrations/import/services/import-attachment.service.ts
index bba517d0..a797ecc6 100644
--- a/apps/server/src/integrations/import/services/import-attachment.service.ts
+++ b/apps/server/src/integrations/import/services/import-attachment.service.ts
@@ -14,6 +14,7 @@ import { getAttachmentFolderPath } from '../../../core/attachment/attachment.uti
import { AttachmentType } from '../../../core/attachment/attachment.constants';
import { unwrapFromParagraph } from '../utils/import-formatter';
import { resolveRelativeAttachmentPath } from '../utils/import.utils';
+import { imageDimensionsFromData } from 'image-dimensions';
import { load } from 'cheerio';
import pLimit from 'p-limit';
import { InjectQueue } from '@nestjs/bullmq';
@@ -271,15 +272,37 @@ export class ImportAttachmentService {
continue;
}
- const { attachmentId, apiFilePath } = processFile(relPath);
+ const { attachmentId, apiFilePath, abs } = processFile(relPath);
- const width = $img.attr('width') ?? '100%';
+ let width = $img.attr('width');
+ const height = $img.attr('height');
const align = $img.attr('data-align') ?? 'center';
+ if (!width) {
+ try {
+ const buf = await fs.readFile(abs);
+ const natural = imageDimensionsFromData(new Uint8Array(buf));
+ if (natural) {
+ width = height
+ ? String(
+ Math.round((natural.width / natural.height) * Number(height)),
+ )
+ : String(natural.width);
+ }
+ } catch {
+ /* empty */
+ }
+
+ if (!width) {
+ width = '600';
+ }
+ }
+
$img
.attr('src', apiFilePath)
.attr('data-attachment-id', attachmentId)
.attr('width', width)
+ .attr('height', height)
.attr('data-align', align);
unwrapFromParagraph($, $img);
@@ -420,7 +443,7 @@ export class ImportAttachmentService {
const { attachmentId, apiFilePath, abs } = processFile(relPath);
const fileName = path.basename(abs);
- const width = $oldDiv.attr('data-width') || '100%';
+ const width = $oldDiv.attr('data-width') || '600';
const align = $oldDiv.attr('data-align') || 'center';
const $newDiv = $('
')
@@ -460,7 +483,7 @@ export class ImportAttachmentService {
.attr('data-type', 'drawio')
.attr('data-src', drawioSvg.apiFilePath)
.attr('data-title', 'diagram')
- .attr('data-width', '100%')
+ .attr('data-width', '600')
.attr('data-align', 'center')
.attr('data-attachment-id', drawioSvg.attachmentId);
@@ -531,7 +554,9 @@ export class ImportAttachmentService {
// Post-process DOM elements to add file sizes after uploads complete
// This avoids blocking file operations during initial DOM processing
- const elementsNeedingSize = $('[data-attachment-id]:not([data-attachment-size])');
+ const elementsNeedingSize = $(
+ '[data-attachment-id]:not([data-attachment-size])',
+ );
for (const element of elementsNeedingSize.toArray()) {
const $el = $(element);
const attachmentId = $el.attr('data-attachment-id');
diff --git a/apps/server/src/integrations/import/utils/import-formatter.ts b/apps/server/src/integrations/import/utils/import-formatter.ts
index 360e22de..4f6a1a80 100644
--- a/apps/server/src/integrations/import/utils/import-formatter.ts
+++ b/apps/server/src/integrations/import/utils/import-formatter.ts
@@ -99,6 +99,15 @@ export function defaultHtmlFormatter($: CheerioAPI, $root: Cheerio
) {
});
}
+const COLUMN_LAYOUTS = [
+ '',
+ '',
+ 'two_equal',
+ 'three_equal',
+ 'four_equal',
+ 'five_equal',
+] as const;
+
export function notionFormatter($: CheerioAPI, $root: Cheerio) {
// remove page header icon and cover image
$root.find('.page-header-icon').remove();
@@ -109,6 +118,31 @@ export function notionFormatter($: CheerioAPI, $root: Cheerio) {
if (!$(el).text().trim()) $(el).remove();
});
+ // columns
+ $root.find('div.column-list').each((_, el) => {
+ const $list = $(el);
+ const $cols = $list.find('div.column');
+
+ if ($cols.length <= 1) {
+ $list.replaceWith($cols.html() || '');
+ return;
+ }
+
+ const layout = COLUMN_LAYOUTS[$cols.length] ?? 'two_equal';
+ let cells = '';
+ $cols.each((_, col) => {
+ const $col = $(col);
+ $col.children('div[style*="display:contents"]').each((_, wrapper) => {
+ $(wrapper).replaceWith($(wrapper).html() || '');
+ });
+ cells += `${$col.html()}
`;
+ });
+
+ $list.replaceWith(
+ `${cells}
`,
+ );
+ });
+
// block math → mathBlock
$root.find('figure.equation').each((_: any, fig: any) => {
const $fig = $(fig);