From 44c50904f06b4032ddeb51064dffb2d4e4f78ed9 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Thu, 30 Oct 2025 16:16:38 +0100 Subject: [PATCH 1/8] fix: preserve sections order and remove encoded `*` --- package.json | 2 +- pnpm-lock.yaml | 57 ++++++++++++++++++++++++++++++++++-- src/app/src/utils/content.ts | 4 ++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index aed1b4e0..24d83840 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "dependencies": { "@iconify-json/lucide": "^1.2.71", - "@nuxtjs/mdc": "0.18.0", + "@nuxtjs/mdc": "https://pkg.pr.new/@nuxtjs/mdc@bf09212", "defu": "^6.1.4", "destr": "^2.0.5", "unstorage": "^1.17.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 677fdc8e..4a078a04 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.2.71 version: 1.2.71 '@nuxtjs/mdc': - specifier: 0.18.0 - version: 0.18.0(magicast@0.3.5) + specifier: https://pkg.pr.new/@nuxtjs/mdc@bf09212 + version: https://pkg.pr.new/@nuxtjs/mdc@bf09212(magicast@0.3.5) defu: specifier: ^6.1.4 version: 6.1.4 @@ -921,6 +921,10 @@ packages: '@nuxtjs/mdc@0.18.0': resolution: {integrity: sha512-/rWEOiLpD6oNx2FC/UsYxLn1pP31pvRmaX5y8GurBOogATKDWd3jlfKCGgshLnsWM6dCKgNkF0mCZQCMZMfpIQ==} + '@nuxtjs/mdc@https://pkg.pr.new/@nuxtjs/mdc@bf09212': + resolution: {tarball: https://pkg.pr.new/@nuxtjs/mdc@bf09212} + version: 0.18.0 + '@nuxtjs/robots@5.5.6': resolution: {integrity: sha512-PFp0sSaQs2ceEubvkiUPrWQ0GYTTu5bDH0lGVmJlm0h/Dqmt/e9TziXNKahL8HUV3VG22YzRyuyjd7p8+BaNgw==} @@ -8054,6 +8058,55 @@ snapshots: - magicast - supports-color + '@nuxtjs/mdc@https://pkg.pr.new/@nuxtjs/mdc@bf09212(magicast@0.3.5)': + dependencies: + '@nuxt/kit': 4.2.0(magicast@0.3.5) + '@shikijs/core': 3.14.0 + '@shikijs/langs': 3.14.0 + '@shikijs/themes': 3.14.0 + '@shikijs/transformers': 3.14.0 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@vue/compiler-core': 3.5.22 + consola: 3.4.2 + debug: 4.4.3 + defu: 6.1.4 + destr: 2.0.5 + detab: 3.0.2 + github-slugger: 2.0.0 + hast-util-format: 1.1.0 + hast-util-to-mdast: 10.1.2 + hast-util-to-string: 3.0.1 + mdast-util-to-hast: 13.2.0 + micromark-util-sanitize-uri: 2.0.1 + parse5: 8.0.0 + pathe: 2.0.3 + property-information: 7.1.0 + rehype-external-links: 3.0.0 + rehype-minify-whitespace: 6.0.2 + rehype-raw: 7.0.0 + rehype-remark: 10.0.1 + rehype-slug: 6.0.0 + rehype-sort-attribute-values: 5.0.1 + rehype-sort-attributes: 5.0.1 + remark-emoji: 5.0.2 + remark-gfm: 4.0.1 + remark-mdc: remark-mdc-edge@3.6.0-29333381.8558577 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-stringify: 11.0.0 + scule: 1.3.0 + shiki: 3.14.0 + ufo: 1.6.1 + unified: 11.0.5 + unist-builder: 4.0.0 + unist-util-visit: 5.0.0 + unwasm: 0.3.11 + vfile: 6.0.3 + transitivePeerDependencies: + - magicast + - supports-color + '@nuxtjs/robots@5.5.6(h3@1.15.4)(magicast@0.5.0)(vue@3.5.22(typescript@5.9.3))': dependencies: '@fingerprintjs/botd': 1.9.1 diff --git a/src/app/src/utils/content.ts b/src/app/src/utils/content.ts index 3e44db9d..d08851b6 100644 --- a/src/app/src/utils/content.ts +++ b/src/app/src/utils/content.ts @@ -197,7 +197,7 @@ export async function generateContentFromMarkdownDocument(document: DatabasePage } }) - return await stringifyMarkdown(body, removeReservedKeysFromDocument(document), { + const markdown = await stringifyMarkdown(body, removeReservedKeysFromDocument(document), { plugins: { remarkMDC: { options: { @@ -206,4 +206,6 @@ export async function generateContentFromMarkdownDocument(document: DatabasePage }, }, }) + + return typeof markdown === 'string' ? markdown.replace(/*/g, '*') : markdown } From a02c6bec5eb91828f2505900b6569136c9703398 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Thu, 30 Oct 2025 17:07:03 +0100 Subject: [PATCH 2/8] fix(host): remove unneccessary seo fields --- src/module/src/runtime/utils/collection.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/module/src/runtime/utils/collection.ts b/src/module/src/runtime/utils/collection.ts index 18df26fd..5017bd40 100644 --- a/src/module/src/runtime/utils/collection.ts +++ b/src/module/src/runtime/utils/collection.ts @@ -143,10 +143,19 @@ export function normalizeDocument(document: DatabaseItem) { // we can remove it to avoid duplication if (document.seo) { const seo = document.seo as Record - if ((!seo.title || seo.title === document.title) && (!seo.description || seo.description === document.description)) { + + if (!seo.title || seo.title === document.title) { + Reflect.deleteProperty(document.seo, 'title') + } + if (!seo.description || seo.description === document.description) { + Reflect.deleteProperty(document.seo, 'description') + } + + if (Object.keys(seo).length === 0) { Reflect.deleteProperty(document, 'seo') } } + console.log({document}) return document } From 13f59906e4c617537265b346b8e4147d12487a24 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Thu, 30 Oct 2025 17:09:04 +0100 Subject: [PATCH 3/8] chore: remove log --- src/module/src/runtime/utils/collection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/src/runtime/utils/collection.ts b/src/module/src/runtime/utils/collection.ts index 5017bd40..fe6aa2d3 100644 --- a/src/module/src/runtime/utils/collection.ts +++ b/src/module/src/runtime/utils/collection.ts @@ -155,7 +155,7 @@ export function normalizeDocument(document: DatabaseItem) { Reflect.deleteProperty(document, 'seo') } } - console.log({document}) + return document } From a18b9a08531fca8077b12e83604db28b5a45240c Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Thu, 30 Oct 2025 17:55:49 +0100 Subject: [PATCH 4/8] fix: content comparison --- src/app/src/utils/database.ts | 33 ++++++++++++++++++++++++++++++++- src/app/src/utils/draft.ts | 7 ++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/app/src/utils/database.ts b/src/app/src/utils/database.ts index 3a2fbd16..b0fd20a7 100644 --- a/src/app/src/utils/database.ts +++ b/src/app/src/utils/database.ts @@ -35,7 +35,7 @@ export function isEqual(document1: DatabasePageItem, document2: DatabasePageItem } } - if (JSON.stringify(documentData1) !== JSON.stringify(documentData2)) { + if (!isDeepEqual(refineDocumentData(documentData1), refineDocumentData(documentData2))) { return false } @@ -49,3 +49,34 @@ export function isEqual(document1: DatabasePageItem, document2: DatabasePageItem return true } + +function refineDocumentData(doc: Record) { + if (doc.seo) { + const seo = doc.seo as Record + doc.seo = { + ...seo, + title: seo.title || doc.title, + description: seo.description || doc.description, + } + } + // documents with same id are being compared, so it is safe to remove `path` and `__hash__` + Reflect.deleteProperty(doc, '__hash__') + Reflect.deleteProperty(doc, 'path') + return doc +} + +function isDeepEqual(obj1: Record, obj2: Record) { + if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2 + + const keys1 = Object.keys(obj1).filter(k => obj1[k] != null) + const keys2 = Object.keys(obj2).filter(k => obj2[k] != null) + + if (keys1.length !== keys2.length) return false + + for (const key of keys1) { + if (!keys2.includes(key)) continue // Ignore missing null/undefined fields + if (!isDeepEqual(obj1[key] as Record, obj2[key] as Record)) return false + } + + return true +} diff --git a/src/app/src/utils/draft.ts b/src/app/src/utils/draft.ts index 0d7232ad..33b92066 100644 --- a/src/app/src/utils/draft.ts +++ b/src/app/src/utils/draft.ts @@ -2,7 +2,7 @@ import type { DatabaseItem, MediaItem, DatabasePageItem, DraftItem, BaseItem, Co import { DraftStatus, ContentFileExtension, TreeRootId } from '../types' import { isEqual } from './database' import { studioFlags } from '../composables/useStudio' -import { generateContentFromDocument } from './content' +import { generateContentFromDocument, generateDocumentFromContent } from './content' import { fromBase64ToUTF8 } from '../utils/string' export async function checkConflict(draftItem: DraftItem): Promise { @@ -28,6 +28,11 @@ export async function checkConflict(draftItem: DraftItem Date: Fri, 31 Oct 2025 09:24:49 +0100 Subject: [PATCH 5/8] up --- src/app/src/utils/database.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/src/utils/database.ts b/src/app/src/utils/database.ts index b0fd20a7..a95b8524 100644 --- a/src/app/src/utils/database.ts +++ b/src/app/src/utils/database.ts @@ -74,7 +74,6 @@ function isDeepEqual(obj1: Record, obj2: Record, obj2[key] as Record)) return false } From f2f852715f340481a4b294d33e6f8653fdf2bad9 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Fri, 31 Oct 2025 10:00:38 +0100 Subject: [PATCH 6/8] fix: monaco model uri error --- src/app/src/components/content/ContentEditorCode.vue | 1 + src/app/src/composables/useMonaco.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/src/components/content/ContentEditorCode.vue b/src/app/src/components/content/ContentEditorCode.vue index 30672ae9..b8dea35a 100644 --- a/src/app/src/components/content/ContentEditorCode.vue +++ b/src/app/src/components/content/ContentEditorCode.vue @@ -42,6 +42,7 @@ const language = computed(() => { }) const { editor, setContent: setEditorContent } = useMonaco(editorRef, { + uri: 'file://' + document.value?.id || '', language, readOnly: props.readOnly, colorMode: ui.colorMode, diff --git a/src/app/src/composables/useMonaco.ts b/src/app/src/composables/useMonaco.ts index 3aae3aab..6320879f 100644 --- a/src/app/src/composables/useMonaco.ts +++ b/src/app/src/composables/useMonaco.ts @@ -3,6 +3,7 @@ import type { editor as Editor } from 'modern-monaco/editor-core' import { setupMonaco } from '../utils/monaco' export interface UseMonacoOptions { + uri?: string language: Ref | string initialContent?: string readOnly?: boolean @@ -60,7 +61,8 @@ export function useMonaco(target: Ref, options: UseMona // Create and attach model const language = unref(options.language) - editor.value.setModel(monaco.editor.createModel(initialContent, language)) + const model = (options.uri && monaco.editor.getModel(options.uri)) || monaco.editor.createModel(initialContent, language, options.uri) + editor.value.setModel(model) // Watch for color mode changes watch(options.colorMode, (newMode) => { From 35f70f10d011b457a5ab7bea4dc9a345864e88c2 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Fri, 31 Oct 2025 10:14:50 +0100 Subject: [PATCH 7/8] Apply suggestion from @vercel[bot] Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> --- src/app/src/components/content/ContentEditorCode.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/src/components/content/ContentEditorCode.vue b/src/app/src/components/content/ContentEditorCode.vue index b8dea35a..6ab3feb7 100644 --- a/src/app/src/components/content/ContentEditorCode.vue +++ b/src/app/src/components/content/ContentEditorCode.vue @@ -42,7 +42,7 @@ const language = computed(() => { }) const { editor, setContent: setEditorContent } = useMonaco(editorRef, { - uri: 'file://' + document.value?.id || '', + uri: 'file://' + (document.value?.id || ''), language, readOnly: props.readOnly, colorMode: ui.colorMode, From 4450198e8691527d5c1089360d599862bc85f458 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Fri, 31 Oct 2025 10:24:24 +0100 Subject: [PATCH 8/8] up --- src/app/src/composables/useMonaco.ts | 3 ++- src/app/src/utils/database.ts | 16 +--------------- src/app/src/utils/object.ts | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/app/src/composables/useMonaco.ts b/src/app/src/composables/useMonaco.ts index 6320879f..6c1bbfd7 100644 --- a/src/app/src/composables/useMonaco.ts +++ b/src/app/src/composables/useMonaco.ts @@ -61,7 +61,8 @@ export function useMonaco(target: Ref, options: UseMona // Create and attach model const language = unref(options.language) - const model = (options.uri && monaco.editor.getModel(options.uri)) || monaco.editor.createModel(initialContent, language, options.uri) + const existingModel = options.uri && monaco.editor.getModel(options.uri) + const model = existingModel || monaco.editor.createModel(initialContent, language, options.uri) editor.value.setModel(model) // Watch for color mode changes diff --git a/src/app/src/utils/database.ts b/src/app/src/utils/database.ts index a95b8524..c113ab53 100644 --- a/src/app/src/utils/database.ts +++ b/src/app/src/utils/database.ts @@ -3,6 +3,7 @@ import { type DatabasePageItem, ContentFileExtension } from '../types' import { stringify } from 'minimark/stringify' import type { MDCRoot } from '@nuxtjs/mdc' import type { MarkdownRoot } from '@nuxt/content' +import { isDeepEqual } from './object' export function isEqual(document1: DatabasePageItem, document2: DatabasePageItem) { function withoutLastStyles(body: MarkdownRoot) { @@ -64,18 +65,3 @@ function refineDocumentData(doc: Record) { Reflect.deleteProperty(doc, 'path') return doc } - -function isDeepEqual(obj1: Record, obj2: Record) { - if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2 - - const keys1 = Object.keys(obj1).filter(k => obj1[k] != null) - const keys2 = Object.keys(obj2).filter(k => obj2[k] != null) - - if (keys1.length !== keys2.length) return false - - for (const key of keys1) { - if (!isDeepEqual(obj1[key] as Record, obj2[key] as Record)) return false - } - - return true -} diff --git a/src/app/src/utils/object.ts b/src/app/src/utils/object.ts index 4016b563..d5c5c9be 100644 --- a/src/app/src/utils/object.ts +++ b/src/app/src/utils/object.ts @@ -7,3 +7,18 @@ export const pick = (obj: Record, keys: string | string[]) => { return Object.fromEntries(Object.entries(obj) .filter(([key]) => keys.includes(key))) } + +export function isDeepEqual(obj1: Record, obj2: Record) { + if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2 + + const keys1 = Object.keys(obj1).filter(k => obj1[k] != null) + const keys2 = Object.keys(obj2).filter(k => obj2[k] != null) + + if (keys1.length !== keys2.length) return false + + for (const key of keys1) { + if (!isDeepEqual(obj1[key] as Record, obj2[key] as Record)) return false + } + + return true +}