mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 18:01:38 +03:00
Heading levels (#10078)
Larger h1 to enable three levels of headings. <img width="508" alt="Screenshot 2024-05-24 at 07 38 31" src="https://github.com/enso-org/enso/assets/1047859/53e77040-30c2-4ed0-bfb5-81d4a703a565"> Fixes #10051. # Important Notes Refactored Lexical styling.
This commit is contained in:
parent
ac5fbbcd17
commit
ca53b69dfb
@ -22,7 +22,7 @@ const textSync: LexicalPlugin = {
|
||||
},
|
||||
}
|
||||
|
||||
useLexical(contentElement, 'PlainTextEditor', [plainText, textSync])
|
||||
useLexical(contentElement, 'PlainTextEditor', {}, [plainText, textSync])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useLexical, type LexicalPlugin } from '@/components/lexical'
|
||||
import { lexicalTheme, useLexical, type LexicalPlugin } from '@/components/lexical'
|
||||
import FloatingSelectionMenu from '@/components/lexical/FloatingSelectionMenu.vue'
|
||||
import LexicalContent from '@/components/lexical/LexicalContent.vue'
|
||||
import SelectionFormattingToolbar from '@/components/lexical/SelectionFormattingToolbar.vue'
|
||||
@ -18,7 +18,7 @@ import {
|
||||
import { HeadingNode, QuoteNode, registerRichText } from '@lexical/rich-text'
|
||||
import { TableCellNode, TableNode, TableRowNode } from '@lexical/table'
|
||||
import { syncRef } from '@vueuse/core'
|
||||
import { shallowRef, type ComponentInstance } from 'vue'
|
||||
import { shallowRef, useCssModule, type ComponentInstance } from 'vue'
|
||||
|
||||
const markdown = defineModel<string>({ required: true })
|
||||
|
||||
@ -56,7 +56,8 @@ const markdownSyncPlugin: LexicalPlugin = {
|
||||
},
|
||||
}
|
||||
|
||||
const { editor } = useLexical(contentElement, 'MarkdownEditor', [
|
||||
const theme = lexicalTheme(useCssModule('lexicalTheme'))
|
||||
const { editor } = useLexical(contentElement, 'MarkdownEditor', theme, [
|
||||
listPlugin,
|
||||
markdownPlugin,
|
||||
markdownSyncPlugin,
|
||||
@ -77,43 +78,6 @@ const formatting = useFormatting(editor)
|
||||
.fullHeight {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(h1) {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(h2, h3, h4, h5, h6) {
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(p + p) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(ol) {
|
||||
list-style-type: decimal;
|
||||
list-style-position: outside;
|
||||
padding-left: 1.6em;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(ul) {
|
||||
list-style-type: disc;
|
||||
list-style-position: outside;
|
||||
padding-left: 1.6em;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(strong) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(.lexical-strikethrough) {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.LexicalContent :deep(.lexical-italic) {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style module="lexicalTheme" src="@/components/lexical/theme.css" />
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { unrefElement, type MaybeElement } from '@vueuse/core'
|
||||
import {
|
||||
createEditor,
|
||||
type EditorThemeClasses,
|
||||
type KlassConstructor,
|
||||
type LexicalEditor,
|
||||
type LexicalNode,
|
||||
type LexicalNodeReplacement,
|
||||
} from 'lexical'
|
||||
import { assertDefined } from 'shared/util/assert'
|
||||
import { markRaw, onMounted, type Ref } from 'vue'
|
||||
|
||||
type NodeDefinition = KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement
|
||||
@ -15,9 +17,34 @@ export interface LexicalPlugin {
|
||||
register: (editor: LexicalEditor) => void
|
||||
}
|
||||
|
||||
export function lexicalTheme(theme: Record<string, string>): EditorThemeClasses {
|
||||
interface EditorThemeShape extends Record<string, EditorThemeShape | string> {}
|
||||
const editorClasses: EditorThemeShape = {}
|
||||
for (const [classPath, className] of Object.entries(theme)) {
|
||||
const path = classPath.split('_')
|
||||
const leaf = path.pop()
|
||||
// `split` will always return at least one value
|
||||
assertDefined(leaf)
|
||||
let obj = editorClasses
|
||||
for (const section of path) {
|
||||
const nextObj = (obj[section] ??= {})
|
||||
if (typeof nextObj === 'string') {
|
||||
console.warn(
|
||||
`Lexical theme contained path '${classPath}', but path component '${section}' is a leaf.`,
|
||||
)
|
||||
continue
|
||||
}
|
||||
obj = nextObj
|
||||
}
|
||||
obj[leaf] = className
|
||||
}
|
||||
return editorClasses
|
||||
}
|
||||
|
||||
export function useLexical(
|
||||
contentElement: Ref<MaybeElement>,
|
||||
namespace: string,
|
||||
theme: EditorThemeClasses,
|
||||
plugins: LexicalPlugin[],
|
||||
) {
|
||||
const nodes = new Set<NodeDefinition>()
|
||||
@ -27,12 +54,7 @@ export function useLexical(
|
||||
createEditor({
|
||||
editable: true,
|
||||
namespace,
|
||||
theme: {
|
||||
text: {
|
||||
strikethrough: 'lexical-strikethrough',
|
||||
italic: 'lexical-italic',
|
||||
},
|
||||
},
|
||||
theme,
|
||||
nodes: [...nodes],
|
||||
onError: console.error,
|
||||
}),
|
||||
|
52
app/gui2/src/components/lexical/theme.css
Normal file
52
app/gui2/src/components/lexical/theme.css
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Lexical theme. Class names are derived from the `LexicalThemeClasses` type from `lexical`, with the hierarchy flattened
|
||||
using `_` to separate levels. See the `lexicalTheme` function in `lexical/formatting.ts`.
|
||||
*/
|
||||
|
||||
.heading_h1 {
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
.heading_h2 {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
.heading_h3,
|
||||
.heading_h4,
|
||||
.heading_h5,
|
||||
.heading_h6 {
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.text_strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.text_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.text_quote {
|
||||
margin-left: 0.2em;
|
||||
border-left: 0.3em solid #ccc;
|
||||
padding-left: 1.6em;
|
||||
}
|
||||
.text_bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.paragraph {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.list_ol {
|
||||
list-style-type: decimal;
|
||||
list-style-position: outside;
|
||||
padding-left: 1.6em;
|
||||
}
|
||||
.list_ul {
|
||||
list-style-type: disc;
|
||||
list-style-position: outside;
|
||||
padding-left: 1.6em;
|
||||
}
|
Loading…
Reference in New Issue
Block a user