features and bug fixes (#322)

* fix page import title bug

* fix youtube embed in markdown export

* add link to rendered file html

* fix: markdown callout import

* update local generateJSON

* feat: switch spaces from sidebar

* remove unused package

* feat: editor date menu command

* fix date description

* update default locale code

* feat: add more code highlight languages
This commit is contained in:
Philip Okugbe
2024-09-17 15:40:49 +01:00
committed by GitHub
parent fb27282886
commit 6a3a7721be
20 changed files with 296 additions and 234 deletions

View File

@ -1,7 +1,9 @@
import { Extensions, getSchema } from '@tiptap/core';
import { DOMParser, ParseOptions } from '@tiptap/pm/model';
import { Window, DOMParser as HappyDomParser } from 'happy-dom';
import { Window } from 'happy-dom';
// this function does not work as intended
// it has issues with closing tags
export function generateJSON(
html: string,
extensions: Extensions,
@ -10,8 +12,10 @@ export function generateJSON(
const schema = getSchema(extensions);
const window = new Window();
const dom = new HappyDomParser().parseFromString(html, 'text/html').body;
const document = window.document;
document.body.innerHTML = html;
// @ts-ignore
return DOMParser.fromSchema(schema).parse(dom, options).toJSON();
return DOMParser.fromSchema(schema)
.parse(document as never, options)
.toJSON();
}

View File

@ -102,7 +102,7 @@ export class UserRepo {
name: insertableUser.name || insertableUser.email.toLowerCase(),
email: insertableUser.email.toLowerCase(),
password: await hashPassword(insertableUser.password),
locale: 'en',
locale: 'en-US',
role: insertableUser?.role,
lastLoginAt: new Date(),
};

View File

@ -22,6 +22,7 @@ export function turndown(html: string): string {
listParagraph,
mathInline,
mathBlock,
iframeEmbed,
]);
return turndownService.turndown(html).replaceAll('<br>', ' ');
}
@ -120,3 +121,15 @@ function mathBlock(turndownService: TurndownService) {
},
});
}
function iframeEmbed(turndownService: TurndownService) {
turndownService.addRule('iframeEmbed', {
filter: function (node: HTMLInputElement) {
return node.nodeName === 'IFRAME';
},
replacement: function (content: any, node: HTMLInputElement) {
const src = node.getAttribute('src');
return '[' + src + '](' + src + ')';
},
});
}

View File

@ -32,8 +32,10 @@ export class ImportService {
): Promise<void> {
const file = await filePromise;
const fileBuffer = await file.toBuffer();
const fileName = sanitize(file.filename).slice(0, 255).split('.')[0];
const fileExtension = path.extname(file.filename).toLowerCase();
const fileName = sanitize(
path.basename(file.filename, fileExtension).slice(0, 255),
);
const fileContent = fileBuffer.toString();
let prosemirrorState = null;

View File

@ -0,0 +1,41 @@
import { Token, marked } from 'marked';
interface CalloutToken {
type: 'callout';
calloutType: string;
text: string;
raw: string;
}
export const calloutExtension = {
name: 'callout',
level: 'block',
start(src: string) {
return src.match(/:::/)?.index ?? -1;
},
tokenizer(src: string): CalloutToken | undefined {
const rule = /^:::([a-zA-Z0-9]+)\s+([\s\S]+?):::/;
const match = rule.exec(src);
const validCalloutTypes = ['info', 'success', 'warning', 'danger'];
if (match) {
let type = match[1];
if (!validCalloutTypes.includes(type)) {
type = 'info';
}
return {
type: 'callout',
calloutType: type,
raw: match[0],
text: match[2].trim(),
};
}
},
renderer(token: Token) {
const calloutToken = token as CalloutToken;
const body = marked.parse(calloutToken.text);
return `<div data-type="callout" data-callout-type="${calloutToken.calloutType}">${body}</div>`;
},
};

View File

@ -1,4 +1,5 @@
import { marked } from 'marked';
import { calloutExtension } from './callout.marked';
marked.use({
renderer: {
@ -25,6 +26,8 @@ marked.use({
},
});
marked.use({ extensions: [calloutExtension] });
export async function markdownToHtml(markdownInput: string): Promise<string> {
const YAML_FONT_MATTER_REGEX = /^\s*---[\s\S]*?---\s*/;