Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ff2c33c
chore: use mdc nightly
farnabaz Nov 10, 2025
0e83b97
chore: use mdc nightly
farnabaz Nov 10, 2025
c8cce12
fix: drop auto generated title and description from documents
farnabaz Nov 11, 2025
1b13df6
Merge branch 'main' into fix/content-parsing-improvement
farnabaz Nov 11, 2025
35643a0
Merge branch 'fix/content-parsing-improvement' of github.com:nuxtlabs…
farnabaz Nov 11, 2025
42f4557
fix(editor): prevent keeping invalid fields in front-matter
farnabaz Nov 11, 2025
4d96e73
Update src/module/src/runtime/utils/collection.ts
farnabaz Nov 11, 2025
8ab69b1
lint: fix
farnabaz Nov 11, 2025
6764de8
Merge branch 'main' into fix/content-parsing-improvement
farnabaz Nov 12, 2025
4f2369e
fix: update document normalize
farnabaz Nov 12, 2025
f2a21d3
fix: content matching
farnabaz Nov 12, 2025
0c7d09b
Merge branch 'main' into fix/content-parsing-improvement
farnabaz Nov 12, 2025
b1444a5
fix: transform with path-meta
farnabaz Nov 12, 2025
f10738b
expose all document related method from host
larbish Nov 12, 2025
f53c6be
fix tests
larbish Nov 12, 2025
b69f2ba
feat: show diff when auto parsing applies
larbish Nov 13, 2025
965131f
refactor getDraftStatus
larbish Nov 13, 2025
59d087b
refactor getDraftStatus
larbish Nov 13, 2025
7a520cf
remove fsPath before storing file
larbish Nov 13, 2025
02d91d4
up
larbish Nov 13, 2025
6728f78
update mdc
larbish Nov 13, 2025
90b5d41
fix: better match for markdown files
farnabaz Nov 13, 2025
92979d6
types: fix
farnabaz Nov 13, 2025
cd2f0ec
fix regression
larbish Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"dependencies": {
"@iconify-json/lucide": "^1.2.72",
"@nuxtjs/mdc": "^0.18.2",
"@nuxtjs/mdc": "^0.18.3",
"@vueuse/core": "^13.9.0",
"defu": "^6.1.4",
"destr": "^2.0.5",
Expand All @@ -55,7 +55,7 @@
"@iconify-json/simple-icons": "^1.2.57",
"@nuxt/content": "^3.8.0",
"@nuxt/eslint-config": "^1.10.0",
"@nuxt/kit": "^4.2.0",
"@nuxt/kit": "^4.2.1",
"@nuxt/module-builder": "^1.0.2",
"@nuxt/ui": "^4.1.0",
"@octokit/types": "^15.0.1",
Expand Down Expand Up @@ -85,7 +85,7 @@
"resolutions": {
"remark-mdc": "3.8.1"
},
"packageManager": "pnpm@10.20.0",
"packageManager": "pnpm@10.21.0",
"keywords": [
"nuxt",
"content",
Expand Down
2 changes: 1 addition & 1 deletion playground/docus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dependencies": {
"docus": "^5.2.1",
"better-sqlite3": "^12.4.1",
"nuxt": "latest",
"nuxt": "^4.2.1",
"@nuxt/content": "latest",
"@nuxt/ui": "4.1.0",
"nuxt-studio": "workspace:*"
Expand Down
4,157 changes: 1,930 additions & 2,227 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/app/src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const appPortal = ref<HTMLElement>()
const activeDocuments = ref<{ fsPath: string, title: string }[]>([])
function detectActiveDocuments() {
activeDocuments.value = host.document.detectActives().map((content) => {
activeDocuments.value = host.document.utils.detectActives().map((content) => {
return {
fsPath: content.fsPath,
title: content.title,
Expand Down
7 changes: 4 additions & 3 deletions src/app/src/components/content/ContentCardReview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import type { PropType } from 'vue'
import { ref, computed, nextTick, watch, onMounted, onUnmounted } from 'vue'
import { DraftStatus, ContentFileExtension } from '../../types'
import { getFileExtension } from '../../utils/file'
import { generateContentFromDocument, isEqual } from '../../utils/content'
import { useMonacoDiff } from '../../composables/useMonacoDiff'
import { useMonaco } from '../../composables/useMonaco'
import { useStudio } from '../../composables/useStudio'
import { fromBase64ToUTF8 } from '../../utils/string'
import { areContentEqual } from '../../utils/content'

const { ui } = useStudio()
const { ui, host } = useStudio()

const props = defineProps({
draftItem: {
Expand Down Expand Up @@ -89,11 +89,12 @@ watch(isOpen, () => {
async function initializeEditor() {
isLoadingContent.value = true

const generateContentFromDocument = host.document.generate.contentFromDocument
const localOriginal = props.draftItem.original ? await generateContentFromDocument(props.draftItem.original as DatabaseItem) : null
const gitHubOriginal = props.draftItem.githubFile?.content ? fromBase64ToUTF8(props.draftItem.githubFile.content) : null
const modified = props.draftItem.modified ? await generateContentFromDocument(props.draftItem.modified as DatabasePageItem) : null

isAutomaticFormattingDetected.value = !isEqual(localOriginal, gitHubOriginal)
isAutomaticFormattingDetected.value = !areContentEqual(localOriginal, gitHubOriginal)

// Wait for DOM to update before initializing Monaco
await nextTick()
Expand Down
7 changes: 2 additions & 5 deletions src/app/src/components/content/ContentEditor.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, type PropType, toRaw } from 'vue'
import { computed, type PropType } from 'vue'
import { decompressTree } from '@nuxt/content/runtime'
import type { MarkdownRoot } from '@nuxt/content'
import { DraftStatus, type DatabasePageItem, type DraftItem } from '../../types'
Expand Down Expand Up @@ -50,10 +50,7 @@ const document = computed<DatabasePageItem>({
return
}

context.activeTree.value.draft.update(props.draftItem.fsPath, {
...toRaw(document.value as DatabasePageItem),
...toRaw(value),
})
context.activeTree.value.draft.update(props.draftItem.fsPath, value)
},
})
</script>
Expand Down
48 changes: 42 additions & 6 deletions src/app/src/components/content/ContentEditorCode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
import { computed, ref, watch } from 'vue'
import { ContentFileExtension, type DatabasePageItem, type DraftItem, DraftStatus, type DatabaseItem } from '../../types'
import type { PropType } from 'vue'
import { generateContentFromDocument, generateDocumentFromContent, isEqual, pickReservedKeysFromDocument } from '../../utils/content'
import { setupSuggestion } from '../../utils/monaco'
import { useStudio } from '../../composables/useStudio'
import { useMonaco } from '../../composables/useMonaco'
import { useMonacoDiff } from '../../composables/useMonacoDiff'
import { fromBase64ToUTF8 } from '../../utils/string'
import { areContentEqual } from '../../utils/content'

const props = defineProps({
draftItem: {
Expand All @@ -24,10 +25,13 @@ const document = defineModel<DatabasePageItem>()
const { mediaTree, host, ui } = useStudio()

const editorRef = ref<HTMLElement>()
const diffEditorRef = ref<HTMLElement>()

const content = ref<string>('')
const currentDocumentId = ref<string | null>(null)
const localStatus = ref<DraftStatus>(props.draftItem.status)
const isAutomaticFormattingDetected = ref(false)
const showAutomaticFormattingDiff = ref(false)

const language = computed(() => {
switch (document.value?.extension) {
Expand Down Expand Up @@ -67,11 +71,11 @@ const { editor, setContent: setEditorContent } = useMonaco(editorRef, {

content.value = newContent

generateDocumentFromContent(document.value!.id, content.value).then((doc) => {
host.document.generate.documentFromContent(document.value!.id, content.value).then((doc) => {
localStatus.value = DraftStatus.Updated

document.value = {
...pickReservedKeysFromDocument(props.draftItem.modified as DatabasePageItem || document.value!),
...host.document.utils.pickReservedKeys(props.draftItem.modified as DatabasePageItem || document.value!),
...doc,
} as DatabasePageItem
})
Expand Down Expand Up @@ -102,6 +106,19 @@ watch(() => props.readOnly, (newReadOnly) => {
}
})

const originalContent = ref<string>('')
const formattedContent = ref<string>('')
watch(showAutomaticFormattingDiff, async (show) => {
if (show && diffEditorRef.value) {
useMonacoDiff(diffEditorRef, {
original: originalContent.value,
modified: formattedContent.value,
language: language.value,
colorMode: ui.colorMode,
})
}
})

// Trigger on document changes
watch(() => document.value?.id + '-' + props.draftItem.version, async () => {
if (document.value?.body) {
Expand All @@ -110,30 +127,49 @@ watch(() => document.value?.id + '-' + props.draftItem.version, async () => {
}, { immediate: true })

async function setContent(document: DatabasePageItem) {
const md = await generateContentFromDocument(document) || ''
const contentFromDocument = host.document.generate.contentFromDocument
const md = await contentFromDocument(document) || ''
content.value = md
setEditorContent(md, true)
currentDocumentId.value = document.id

isAutomaticFormattingDetected.value = false
if (props.draftItem.original && props.draftItem.githubFile?.content) {
const localOriginal = await generateContentFromDocument(props.draftItem.original as DatabaseItem)
const localOriginal = await contentFromDocument(props.draftItem.original as DatabaseItem) as string
const gitHubOriginal = fromBase64ToUTF8(props.draftItem.githubFile.content)

isAutomaticFormattingDetected.value = !isEqual(localOriginal, gitHubOriginal)
isAutomaticFormattingDetected.value = !areContentEqual(localOriginal, gitHubOriginal)
if (isAutomaticFormattingDetected.value) {
originalContent.value = gitHubOriginal
formattedContent.value = localOriginal
}
}
}

function toggleDiffView() {
showAutomaticFormattingDiff.value = !showAutomaticFormattingDiff.value
}
</script>

<template>
<div class="relative h-full flex flex-col">
<AlertMDCFormatting
v-if="isAutomaticFormattingDetected"
show-action
:is-diff-shown="showAutomaticFormattingDiff"
class="flex-none"
@show-diff="toggleDiffView"
/>
<div
v-show="!showAutomaticFormattingDiff"
ref="editorRef"
class="flex-1"
/>
<div
v-if="isAutomaticFormattingDetected"
v-show="showAutomaticFormattingDiff"
ref="diffEditorRef"
class="flex-1"
/>
</div>
</template>
5 changes: 3 additions & 2 deletions src/app/src/components/content/ContentEditorText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import { parseMarkdown, stringifyMarkdown } from '@nuxtjs/mdc/runtime'
import { decompressTree, compressTree } from '@nuxt/content/runtime'
import type { MDCRoot } from '@nuxtjs/mdc'
import type { MarkdownRoot } from '@nuxt/content'
import { removeReservedKeysFromDocument } from '../../utils/content'
import { useStudio } from '../../composables/useStudio'
const { host } = useStudio()
const document = defineModel<DatabasePageItem>()
const content = ref('')
watch(() => document.value?.id, async () => {
if (document.value?.body) {
// @ts-expect-error todo fix MarkdownRoot/MDCRoot conversion in MDC module
const tree = document.value.body.type === 'minimark' ? decompressTree(document.value.body) : (document.value.body as MDCRoot)
const data = removeReservedKeysFromDocument(document.value)
const data = host.document.utils.removeReservedKeys(document.value)
stringifyMarkdown(tree, data).then((md) => {
content.value = md || ''
})
Expand Down
38 changes: 37 additions & 1 deletion src/app/src/components/shared/AlertMDCFormatting.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
<script setup lang="ts">
import { ref } from 'vue'

defineProps({
showAction: {
type: Boolean,
default: false,
},
})

const emit = defineEmits(['showDiff'])

const isDiffShown = ref(false)

function toggleAction() {
isDiffShown.value = !isDiffShown.value
emit('showDiff', isDiffShown.value)
}
</script>

<template>
<UAlert
title="Formatting applied to align with MDC syntax standard."
color="info"
variant="soft"
orientation="horizontal"
:ui="{ title: 'text-xs', root: 'rounded-none py-2 border-b border-default' }"
/>
>
<template
v-if="showAction"
#actions
>
<UButton
variant="soft"
color="secondary"
size="xs"
class="bg-white hover:bg-muted dark:bg-accented dark:hover:bg-elevated"
@click="toggleAction"
>
{{ isDiffShown ? 'Back to code' : "See what's changed" }}
</UButton>
</template>
</UAlert>
</template>
6 changes: 3 additions & 3 deletions src/app/src/composables/useContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ export const useContext = createSharedComposable((
const rootDocumentFsPath = joinURL(fsPath, 'index.md')
const navigationDocumentFsPath = joinURL(fsPath, '.navigation.yml')

const navigationDocument = await host.document.create(navigationDocumentFsPath, `title: ${folderName}`)
const rootDocument = await host.document.create(rootDocumentFsPath, `# ${upperFirst(folderName)} root file`)
const navigationDocument = await host.document.db.create(navigationDocumentFsPath, `title: ${folderName}`)
const rootDocument = await host.document.db.create(rootDocumentFsPath, `# ${upperFirst(folderName)} root file`)

await activeTree.value.draft.create(navigationDocumentFsPath, navigationDocument)
const rootDocumentDraftItem = await activeTree.value.draft.create(rootDocumentFsPath, rootDocument)
Expand Down Expand Up @@ -136,7 +136,7 @@ export const useContext = createSharedComposable((
},
[StudioItemActionId.CreateDocument]: async (params: CreateFileParams) => {
const { fsPath, content } = params
const document = await host.document.create(fsPath, content)
const document = await host.document.db.create(fsPath, content)
const draftItem = await activeTree.value.draft.create(fsPath, document as DatabaseItem)
await activeTree.value.selectItemByFsPath(draftItem.fsPath)
},
Expand Down
Loading
Loading