Skip to content

Commit fadaf44

Browse files
authored
1 parent 8af687b commit fadaf44

File tree

10 files changed

+746
-61
lines changed

10 files changed

+746
-61
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
- [Users having "Team" plan or above may now access shared directories in Cloud
2020
File Browser][12208]
2121
- [Added support for rendering numbered and nested lists][12190].
22+
- [Added buttons for editing top-level markdown elements in the documentation
23+
panel][12217].
2224
- [Removed `#` from default colum name][12222]
2325

2426
[11889]: https://github.com/enso-org/enso/pull/11889
@@ -34,6 +36,7 @@
3436
[12208]: https://github.com/enso-org/enso/pull/12208
3537
[12190]: https://github.com/enso-org/enso/pull/12190
3638
[12222]: https://github.com/enso-org/enso/pull/12222
39+
[12217]: https://github.com/enso-org/enso/pull/12217
3740

3841
#### Enso Standard Library
3942

app/gui/src/project-view/components/DocumentationEditor.vue

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const emit = defineEmits<{
2121
'update:fullscreen': [boolean]
2222
}>()
2323
24-
const toolbarElement = ref<HTMLElement>()
2524
const markdownEditor = ref<ComponentInstance<typeof MarkdownEditor>>()
2625
2726
const graphStore = useGraphStore()
@@ -72,25 +71,23 @@ const handler = documentationEditorBindings.handler({
7271

7372
<template>
7473
<WithFullscreenMode :fullscreen="fullscreen" @update:animating="fullscreenAnimating = $event">
75-
<div class="DocumentationEditor">
76-
<div ref="toolbarElement" class="toolbar">
77-
<FullscreenButton v-model="fullscreen" />
78-
<SvgButton name="image" title="Insert image" @click.stop="tryUploadImageFile()" />
79-
</div>
80-
<slot name="belowToolbar" />
81-
<div
82-
class="scrollArea"
83-
@keydown="handler"
84-
@dragover.prevent
85-
@drop.prevent="tryUploadDroppedImage($event)"
86-
>
87-
<MarkdownEditor
88-
ref="markdownEditor"
89-
:content="yText"
90-
:transformImageUrl="transformImageUrl"
91-
:toolbarContainer="toolbarElement"
92-
/>
93-
</div>
74+
<div
75+
class="DocumentationEditor"
76+
@keydown="handler"
77+
@dragover.prevent
78+
@drop.prevent="tryUploadDroppedImage($event)"
79+
>
80+
<MarkdownEditor ref="markdownEditor" :content="yText" :transformImageUrl="transformImageUrl">
81+
<template #toolbarLeft>
82+
<FullscreenButton v-model="fullscreen" />
83+
</template>
84+
<template #toolbarRight>
85+
<SvgButton name="image" title="Insert image" @click.stop="tryUploadImageFile()" />
86+
</template>
87+
<template #belowToolbar>
88+
<slot name="belowToolbar" />
89+
</template>
90+
</MarkdownEditor>
9491
</div>
9592
</WithFullscreenMode>
9693
</template>
@@ -103,24 +100,4 @@ const handler = documentationEditorBindings.handler({
103100
height: 100%;
104101
width: 100%;
105102
}
106-
107-
.scrollArea {
108-
width: 100%;
109-
overflow-y: auto;
110-
padding-left: 10px;
111-
/* Prevent touchpad back gesture, which can be triggered while panning. */
112-
overscroll-behavior-x: none;
113-
flex-grow: 1;
114-
}
115-
116-
.toolbar {
117-
height: 48px;
118-
padding-left: 16px;
119-
flex-shrink: 0;
120-
121-
display: flex;
122-
align-items: center;
123-
flex-direction: row;
124-
gap: 8px;
125-
}
126103
</style>

app/gui/src/project-view/components/MarkdownEditor.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import * as Y from 'yjs'
1010
const props = defineProps<{
1111
content: Y.Text | string
1212
transformImageUrl?: UrlTransformer
13-
toolbarContainer: HTMLElement | undefined
1413
}>()
1514
1615
const inner = ref<ComponentInstance<typeof LazyMarkdownEditor>>()
@@ -34,6 +33,16 @@ defineExpose({
3433

3534
<template>
3635
<Suspense>
37-
<LazyMarkdownEditor ref="inner" v-bind="props" class="MarkdownEditor" />
36+
<LazyMarkdownEditor ref="inner" v-bind="props">
37+
<template #toolbarLeft>
38+
<slot name="toolbarLeft" />
39+
</template>
40+
<template #toolbarRight>
41+
<slot name="toolbarRight" />
42+
</template>
43+
<template #belowToolbar>
44+
<slot name="belowToolbar" />
45+
</template>
46+
</LazyMarkdownEditor>
3847
</Suspense>
3948
</template>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script setup lang="ts">
2+
import DropdownMenu from '@/components/DropdownMenu.vue'
3+
import MenuButton from '@/components/MenuButton.vue'
4+
import MenuPanel from '@/components/MenuPanel.vue'
5+
import SvgIcon from '@/components/SvgIcon.vue'
6+
import { HeaderLevel, ListType } from '@/util/codemirror/markdownEditing'
7+
import { Icon } from '@/util/iconMetadata/iconName'
8+
import { ref } from 'vue'
9+
10+
const emit = defineEmits<{
11+
toggleHeader: [HeaderLevel]
12+
toggleQuote: []
13+
toggleList: [ListType]
14+
}>()
15+
16+
interface MenuItem {
17+
name: string
18+
icon: Icon
19+
action: () => void
20+
}
21+
const menuItems: MenuItem[] = [
22+
{ name: 'Header 1', icon: 'header1', action: () => emit('toggleHeader', 1) },
23+
{ name: 'Header 2', icon: 'header2', action: () => emit('toggleHeader', 2) },
24+
{ name: 'Header 3', icon: 'header3', action: () => emit('toggleHeader', 3) },
25+
{ name: 'Quote', icon: 'quote', action: () => emit('toggleQuote') },
26+
{ name: 'Bullet list', icon: 'bullet-list', action: () => emit('toggleList', 'unordered') },
27+
{ name: 'Numbered list', icon: 'numbered-list', action: () => emit('toggleList', 'ordered') },
28+
]
29+
30+
const open = ref(false)
31+
</script>
32+
33+
<template>
34+
<DropdownMenu v-model:open="open" title="Block type">
35+
<template #button>
36+
<SvgIcon name="text3" />
37+
</template>
38+
<template #menu>
39+
<MenuPanel>
40+
<template v-for="item in menuItems" :key="item.name">
41+
<MenuButton @click="(item.action(), (open = false))">
42+
<SvgIcon :name="item.icon" />
43+
<div class="iconLabel" v-text="item.name" />
44+
</MenuButton>
45+
</template>
46+
</MenuPanel>
47+
</template>
48+
</DropdownMenu>
49+
</template>
50+
51+
<style scoped>
52+
.MenuPanel {
53+
box-shadow: 0 0 1px rgba(0, 0, 0, 0.2);
54+
}
55+
56+
.MenuButton {
57+
margin: -4px;
58+
justify-content: unset;
59+
}
60+
61+
.iconLabel {
62+
margin-left: 4px;
63+
padding-right: 4px;
64+
}
65+
</style>

app/gui/src/project-view/components/MarkdownEditor/MarkdownEditorImpl.vue

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import CodeMirrorRoot from '@/components/CodeMirrorRoot.vue'
33
import { transformPastedText } from '@/components/DocumentationEditor/textPaste'
4+
import BlockTypeDropdown from '@/components/MarkdownEditor/BlockTypeDropdown.vue'
45
import { ensoMarkdown } from '@/components/MarkdownEditor/markdown'
56
import VueHostRender, { VueHostInstance } from '@/components/VueHostRender.vue'
67
import { useCodeMirror } from '@/util/codemirror'
@@ -22,17 +23,20 @@ const editing = computed(() => !readonly.value && focused.value)
2223
2324
const vueHost = new VueHostInstance()
2425
const editorRoot = useTemplateRef<ComponentInstance<typeof CodeMirrorRoot>>('editorRoot')
25-
const { editorView, readonly, putTextAt } = useCodeMirror(editorRoot, {
26-
content: () => content,
27-
extensions: [
28-
minimalSetup,
29-
EditorView.lineWrapping,
30-
highlightStyle(useCssModule()),
31-
EditorView.clipboardInputFilter.of(transformPastedText),
32-
ensoMarkdown(),
33-
],
34-
vueHost: () => vueHost,
35-
})
26+
const { editorView, readonly, putTextAt, toggleHeader, toggleQuote, toggleList } = useCodeMirror(
27+
editorRoot,
28+
{
29+
content: () => content,
30+
extensions: [
31+
minimalSetup,
32+
EditorView.lineWrapping,
33+
highlightStyle(useCssModule()),
34+
EditorView.clipboardInputFilter.of(transformPastedText),
35+
ensoMarkdown(),
36+
],
37+
vueHost: () => vueHost,
38+
},
39+
)
3640
3741
useLinkTitles(editorView, { readonly })
3842
@@ -59,16 +63,57 @@ defineExpose({
5963
</script>
6064

6165
<template>
62-
<CodeMirrorRoot
63-
ref="editorRoot"
64-
v-bind="$attrs"
65-
:class="{ editing }"
66-
@focusout="focused = false"
67-
/>
68-
<VueHostRender :host="vueHost" />
66+
<div class="MarkdownEditorRoot">
67+
<div class="toolbar">
68+
<slot name="toolbarLeft" />
69+
<BlockTypeDropdown
70+
@toggleHeader="toggleHeader($event)"
71+
@toggleQuote="toggleQuote()"
72+
@toggleList="toggleList($event)"
73+
/>
74+
<slot name="toolbarRight" />
75+
</div>
76+
<slot name="belowToolbar" />
77+
<div class="scrollArea">
78+
<CodeMirrorRoot
79+
ref="editorRoot"
80+
v-bind="$attrs"
81+
:class="{ MarkdownEditor: true, editing }"
82+
@focusout="focused = false"
83+
/>
84+
<VueHostRender :host="vueHost" />
85+
</div>
86+
</div>
6987
</template>
7088

7189
<style scoped>
90+
.MarkdownEditorRoot {
91+
display: flex;
92+
flex-direction: column;
93+
height: 100%;
94+
width: 100%;
95+
}
96+
97+
.toolbar {
98+
height: 48px;
99+
padding-left: 18px;
100+
flex-shrink: 0;
101+
display: flex;
102+
align-items: center;
103+
flex-direction: row;
104+
gap: 8px;
105+
z-index: 250;
106+
}
107+
108+
.scrollArea {
109+
width: 100%;
110+
overflow-y: auto;
111+
padding-left: 10px;
112+
/* Prevent touchpad back gesture, which can be triggered while panning. */
113+
overscroll-behavior-x: none;
114+
flex-grow: 1;
115+
}
116+
72117
:deep(.cm-content) {
73118
/*noinspection CssUnresolvedCustomProperty,CssNoGenericFontName*/
74119
font-family: var(--font-sans);

0 commit comments

Comments
 (0)