Skip to content

Commit 5a75858

Browse files
committed
feat(app): add delete block button
1 parent 59253dd commit 5a75858

File tree

12 files changed

+150
-140
lines changed

12 files changed

+150
-140
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/auto-import.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ declare global {
4545
const toRaw: typeof import('vue')['toRaw']
4646
const toRef: typeof import('vue')['toRef']
4747
const toRefs: typeof import('vue')['toRefs']
48+
const toValue: typeof import('vue')['toValue']
4849
const triggerRef: typeof import('vue')['triggerRef']
4950
const unref: typeof import('vue')['unref']
5051
const useAttrs: typeof import('vue')['useAttrs']

packages/app/modules/evaluation/composables/use-evaluation.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ describe('useEvaluation', () => {
99
})
1010

1111
it.each([
12-
['import lodash from "lodash"', `const lodash = ${composable.importIdentifier}("lodash");`],
12+
[
13+
'import lodash from "lodash"',
14+
`const lodash = ${composable.importIdentifier}("lodash").default;`,
15+
],
1316
[
1417
'import { camelCase } from "lodash"',
1518
`const { camelCase } = ${composable.importIdentifier}("lodash");`,

packages/app/modules/evaluation/resolvers/npm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ export default defineResolver({
77
const version = 'latest'
88
const url = `https://unpkg.com/${name}@${version}?module`
99

10-
return import(url)
10+
return import(/* @vite-ignore */ url)
1111
},
1212
})

packages/app/modules/markdown-editor/components/MBlock.vue

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1-
<script setup lang="ts"></script>
1+
<script setup lang="ts">
2+
import { Node } from '@language-kit/markdown'
3+
import { useManger } from '../composable/nodes-manager'
4+
5+
const props = defineProps({
6+
node: {
7+
type: Object as () => Node,
8+
required: true,
9+
},
10+
})
11+
12+
const manager = useManger()
13+
14+
function deleteBlock() {
15+
manager.removeNode(props.node)
16+
}
17+
</script>
218

319
<template>
420
<div class="flex min-h-[30px] items-center group">
521
<div class="w-[50px] flex justify-center">
6-
<v-menu offset-y offset-x close-on-content-click>
22+
<v-menu offset-y close-on-content-click>
723
<template #activator="{ attrs }">
824
<v-btn
925
v-bind="attrs"
@@ -16,6 +32,11 @@
1632
</template>
1733

1834
<v-card color="b-secondary">
35+
<v-list-item @click="deleteBlock">
36+
<v-icon name="trash" class="mr-2" />
37+
38+
{{ $t('delete') }}
39+
</v-list-item>
1940
<slot name="menu" />
2041
</v-card>
2142
</v-menu>

packages/app/modules/markdown-editor/components/MComponent.vue

Lines changed: 37 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -30,106 +30,11 @@ const loading = ref(false)
3030
const componentData = shallowRef({
3131
template: null as null | string,
3232
components: createComponentObject(),
33-
props: {
34-
context: {
35-
type: Object,
36-
required: true,
37-
},
33+
setup() {
34+
return context
3835
},
3936
})
4037
41-
function findAttrsRange() {
42-
const startIndex = 4
43-
const endIndex = model.value.tokens.findIndex((t, index) => {
44-
const prev = model.value.tokens[index - 1]
45-
46-
if (t.type === TokenType.BreakLine && prev?.type === TokenType.WhiteSpace) {
47-
return true
48-
}
49-
50-
return false
51-
})
52-
53-
return [startIndex, endIndex]
54-
}
55-
56-
function findAttrs() {
57-
const [startIndex, endIndex] = findAttrsRange()
58-
const lines: string[] = []
59-
const attrs: string[] = []
60-
61-
let current = 0
62-
63-
model.value.tokens.slice(startIndex, endIndex).forEach((t) => {
64-
if (t.type === TokenType.BreakLine) {
65-
current++
66-
return
67-
}
68-
69-
if (!lines[current]) {
70-
lines[current] = ''
71-
}
72-
73-
lines[current] += t.value
74-
})
75-
76-
lines.forEach((line) => {
77-
// split first =
78-
let [name, value] = line.split(/=(.+)/)
79-
80-
name = name.trim()
81-
82-
if (!name) return
83-
84-
if (name[0] === ':' && value[1] === '`') {
85-
// replace ${variable} to ${context.variable}
86-
value = value.replace(/\$\{([a-zA-Z0-9_]+)\}/g, (_, name) => {
87-
return `\${context.${name}}`
88-
})
89-
}
90-
91-
if (name[0] === '@' && !value.includes('(')) {
92-
// replace method to context.method
93-
value = value.replace(/([a-zA-Z0-9_]+)/g, (_, name) => {
94-
return `context.${name}`
95-
})
96-
}
97-
98-
if (name[0] === '@' && value.includes('(')) {
99-
// replace method(..args) to context.method(..args)
100-
value = value.replace(/([a-zA-Z0-9_]+)\(/g, (_, name) => {
101-
return `context.${name}(`
102-
})
103-
}
104-
105-
attrs.push(`${name}=${value}`)
106-
})
107-
108-
return attrs
109-
}
110-
111-
function findContent() {
112-
const [, endAttrIndex] = findAttrsRange()
113-
114-
const tokens = model.value.tokens.slice(endAttrIndex + 1)
115-
116-
let content = tokens.map((t) => t.value).join('')
117-
118-
// replace {{variable}} to {{context.variable}}
119-
content = content.replace(/\{\{([a-zA-Z0-9_]+)\}\}/g, (_, name) => {
120-
return `{{context.${name}}}`
121-
})
122-
123-
// replace {{ `...${variable}...` }} to {{ `...${context.variable}...` }}
124-
content = content.replace(/\{\{ `(.+)` \}\}/g, (_, content) => {
125-
return `{{ \`${content.replace(/\$\{([a-zA-Z0-9_]+)\}/g, (_, name) => {
126-
return `\${context.${name}}`
127-
})}\` }}`
128-
})
129-
130-
return content.trim()
131-
}
132-
13338
function load() {
13439
loading.value = true
13540
@@ -138,14 +43,28 @@ function load() {
13843
}
13944
14045
let name = model.value.tokens[3].value
141-
const attrs: string[] = findAttrs()
142-
const content = findContent()
46+
47+
if (!model.value.isComponent()) {
48+
return
49+
}
50+
51+
const attrs = Object.entries(model.value.attrs)
52+
.map(([key, value]) => `${key}="${value}"`)
53+
.join(' ')
54+
55+
const props = Object.entries(model.value.props)
56+
.map(([key, value]) => `:${key}="${value}"`)
57+
.join(' ')
58+
59+
const events = Object.entries(model.value.events)
60+
.map(([key, value]) => `@${key}="${value}"`)
61+
.join(' ')
14362
14463
if (globalComponents[name]) {
14564
name = globalComponents[name]
14665
}
14766
148-
const template = `<${name} ${attrs.join(' ')}>${content}</${name}>`
67+
const template = `<${name} ${props} ${attrs} ${events} >${model.value.body}</${name}>`
14968
15069
componentData.value.template = template
15170
@@ -157,10 +76,27 @@ function load() {
15776
watch(model, load)
15877
15978
onMounted(load)
79+
80+
// destroy
81+
82+
const destroy = ref(false)
83+
84+
watch(loading, (value) => {
85+
if (value) {
86+
destroy.value = true
87+
return
88+
}
89+
90+
destroy.value = false
91+
})
92+
93+
onUnmounted(() => {
94+
destroy.value = true
95+
})
16096
</script>
16197

16298
<template>
163-
<m-block class="my-2">
99+
<m-block v-if="!destroy" :node="model">
164100
<div v-if="loading" class="text-t-secondary text-sm">Loading...</div>
165101
<component
166102
:is="componentData as any"

packages/app/modules/markdown-editor/components/MEditor.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
import MonacoEditor from '../../monaco/components/MEditor.vue'
33
import { Parser, Node as MarkdownNode, NodeType } from '@language-kit/markdown'
44
5+
import uniqueId from 'lodash/uniqueId'
6+
57
import MHeading from './MHeading.vue'
68
import MParagraph from './MParagraph.vue'
79
import MSetup from './MSetup.vue'
810
import MComponent from './MComponent.vue'
911
import { provideContext } from '../composable/context'
12+
import { provideManager } from '../composable/nodes-manager'
1013
1114
const props = defineProps({
1215
modelValue: {
@@ -19,28 +22,28 @@ const emit = defineEmits(['update:modelValue'])
1922
2023
const parser = new Parser()
2124
22-
const nodes = ref<MarkdownNode[]>([])
25+
const manager = provideManager()
2326
2427
const text = ref('')
2528
2629
function load() {
27-
nodes.value = parser.toNodes(props.modelValue)
30+
manager.nodes = parser.toNodes(props.modelValue)
2831
2932
text.value = props.modelValue
3033
}
3134
3235
function updateNode(index: number, node: MarkdownNode) {
33-
nodes.value.splice(index, 1, node)
36+
manager.nodes.splice(index, 1, node)
3437
35-
text.value = nodes.value.map((n) => n.toText()).join('')
38+
text.value = manager.nodes.map((n) => n.toText()).join('')
3639
3740
emit('update:modelValue', text.value)
3841
}
3942
4043
function updateText(value: string) {
4144
text.value = value
4245
43-
nodes.value = parser.toNodes(value)
46+
manager.nodes = parser.toNodes(value)
4447
4548
emit('update:modelValue', value)
4649
}
@@ -49,6 +52,10 @@ watch(() => props.modelValue, load, {
4952
immediate: true,
5053
})
5154
55+
manager.on('remove', () => {
56+
text.value = manager.nodes.map((n) => n.toText()).join('')
57+
})
58+
5259
// context
5360
5461
provideContext()
@@ -68,7 +75,7 @@ function isSetup(node: MarkdownNode) {
6875
</div>
6976

7077
<div class="h-full w-6/12 overflow-auto">
71-
<template v-for="(node, index) in nodes" :key="index">
78+
<template v-for="(node, index) in manager.nodes" :key="index">
7279
<MSetup
7380
v-if="isSetup(node)"
7481
:model-value="node"

packages/app/modules/markdown-editor/components/MHtml.vue

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,10 @@ const onInput = debounce((event: InputEvent) => {
4444
4545
const loading = ref(false)
4646
47-
const componentData = shallowRef({
47+
const componentData = shallowRef<any>({
4848
template: '<div></div>',
49-
props: {
50-
context: {
51-
type: Object,
52-
required: true,
53-
},
49+
setup() {
50+
return context
5451
},
5552
})
5653
@@ -61,16 +58,6 @@ function setComponentData() {
6158
6259
let text = props.modelValue
6360
64-
// replace any {{ variable }} with {{ context[variable] }}
65-
text = text.replaceAll(/{{ ([a-zA-Z0-9]+) }}/g, (match, p1) => {
66-
return `{{ context.${p1} }}`
67-
})
68-
69-
// replace any {{ method(arg1, arg2) }} with {{ context.method(arg1, arg2) }}
70-
text = text.replaceAll(/{{ ([a-zA-Z0-9]+)\((.*)\) }}/g, (match, p1, p2) => {
71-
return `{{ context.${p1}(${p2}) }}`
72-
})
73-
7461
componentData.value.template = `<div>${text}</div>`
7562
7663
setTimeout(() => {
@@ -86,7 +73,7 @@ watch(() => props.modelValue, setComponentData, {
8673
<template>
8774
<div v-if="loading" class="text-t-secondary text-sm">Loading...</div>
8875

89-
<component :is="componentData as any" v-else-if="textHaveVariable" :context="context" />
76+
<component :is="componentData" v-else-if="textHaveVariable" :context="context" />
9077

9178
<div
9279
v-else

0 commit comments

Comments
 (0)