mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-11 07:51:20 +00:00
000 📚: Fix rendering diffs in grid view for the rich text field
This commit is contained in:
parent
3fd4b604fb
commit
4bfe3ae299
8 changed files with 145 additions and 200 deletions
premium/web-frontend/modules/baserow_premium/assets/scss/components
web-frontend/modules
core
assets/scss/components
components/editor
editor
database/components
|
@ -20,60 +20,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.rich-text-editor__content--scaled {
|
||||
overflow: hidden;
|
||||
|
||||
h1, h2, h3, p, a, ul, ol, li, blockquote, pre, code {
|
||||
|
||||
@include fixed-height(32px, 13px);
|
||||
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: revert;
|
||||
}
|
||||
|
||||
h1, h2, h3, p, a, blockquote, pre, code {
|
||||
@extend %ellipsis;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
ul[data-type='taskList'] li {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding: 0 2px;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding-left: 6px;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.rich-text-editor__content-blockquote {
|
||||
padding-left: 1rem;
|
||||
color: $color-neutral-700;
|
||||
border-left: 4px solid $color-neutral-300;
|
||||
}
|
||||
|
||||
.rich-text-editor__content {
|
||||
width: 100%;
|
||||
|
@ -112,10 +63,9 @@
|
|||
}
|
||||
|
||||
blockquote {
|
||||
@extend .rich-text-editor__content-blockquote;
|
||||
|
||||
margin: 1rem;
|
||||
padding-left: 1rem;
|
||||
color: $color-neutral-700;
|
||||
border-left: 4px solid $color-neutral-300;
|
||||
}
|
||||
|
||||
pre {
|
||||
|
@ -144,63 +94,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.rich-text-editor__content.rich-text-editor__content--scaled {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
h1, h2, h3, p, a, ul, ol, li, blockquote, pre, code {
|
||||
|
||||
@include fixed-height(32px, 13px);
|
||||
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: revert;
|
||||
}
|
||||
|
||||
h1, h2, h3, p, a, blockquote, pre, code {
|
||||
@extend %ellipsis;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
ul[data-type='taskList'] li {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding: 0 2px;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding-left: 6px;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.rich-text-editor__content--comment {
|
||||
max-height: 50vh;
|
||||
overflow: auto;
|
||||
|
|
|
@ -11,3 +11,89 @@
|
|||
background-color: $palette-neutral-700;
|
||||
}
|
||||
}
|
||||
|
||||
.field-rich-text--preview {
|
||||
overflow: hidden;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
a,
|
||||
ul,
|
||||
ol,
|
||||
li,
|
||||
blockquote,
|
||||
pre,
|
||||
code {
|
||||
@include fixed-height(32px, 13px);
|
||||
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: revert;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
a,
|
||||
blockquote,
|
||||
pre,
|
||||
code {
|
||||
@extend %ellipsis;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
@extend .rich-text-editor__content-blockquote;
|
||||
|
||||
margin: 5px 0 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding-left: 6px;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: $color-neutral-100;
|
||||
border-radius: $rounded;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding: 0 2px;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ul.contains-task-list {
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin-left: 0;
|
||||
|
||||
label {
|
||||
@extend %ellipsis;
|
||||
@include fixed-height(32px, 13px);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,7 @@
|
|||
.grid-field-rich-text__cell {
|
||||
@extend .grid-field-long-text__cell;
|
||||
|
||||
&.grid-field-rich-text__cell--preview {
|
||||
@extend .rich-text-editor__content.rich-text-editor__content--scaled;
|
||||
|
||||
padding: 0 10px;
|
||||
|
||||
pre {
|
||||
background-color: $color-neutral-100;
|
||||
border-radius: $rounded;
|
||||
}
|
||||
|
||||
ul.contains-task-list {
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin-left: 0;
|
||||
|
||||
label {
|
||||
@extend %ellipsis;
|
||||
@include fixed-height(32px, 13px);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.grid-field-rich-text {
|
||||
|
|
|
@ -24,12 +24,7 @@
|
|||
</div>
|
||||
<EditorContent
|
||||
class="rich-text-editor__content"
|
||||
:class="[
|
||||
{
|
||||
'rich-text-editor__content--scaled': contentScaled,
|
||||
},
|
||||
editorClass,
|
||||
]"
|
||||
:class="editorClass"
|
||||
:editor="editor"
|
||||
/>
|
||||
</div>
|
||||
|
@ -120,10 +115,6 @@ export default {
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
contentScaled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
enableMentions: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
|
|
8
web-frontend/modules/core/editor/markdown.js
Normal file
8
web-frontend/modules/core/editor/markdown.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import Markdown from 'markdown-it'
|
||||
import taskLists from 'markdown-it-task-lists'
|
||||
|
||||
const md = new Markdown({ html: false })
|
||||
md.use(taskLists, { label: true, enabled: true })
|
||||
|
||||
export const defaultMarkdownParser = md
|
||||
export const parseMarkdown = (markdown) => md.render(markdown)
|
|
@ -1,19 +1,15 @@
|
|||
<template>
|
||||
<div class="card-rich-text">
|
||||
<RichTextEditor
|
||||
:content-scaled="true"
|
||||
:editable="false"
|
||||
:enable-rich-text-formatting="true"
|
||||
:value="value"
|
||||
></RichTextEditor>
|
||||
</div>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div
|
||||
class="card-rich-text field-rich-text--preview"
|
||||
v-html="formattedValue"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RichTextEditor from '@baserow/modules/core/components/editor/RichTextEditor.vue'
|
||||
import { parseMarkdown } from '@baserow/modules/core/editor/markdown'
|
||||
|
||||
export default {
|
||||
components: { RichTextEditor },
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
|
@ -22,8 +18,8 @@ export default {
|
|||
},
|
||||
height: 32,
|
||||
computed: {
|
||||
richValue() {
|
||||
return this.value || ''
|
||||
formattedValue() {
|
||||
return parseMarkdown(this.value || '')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,34 +1,29 @@
|
|||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template functional>
|
||||
<div
|
||||
class="field-rich-text--preview grid-view__cell grid-field-rich-text__cell"
|
||||
v-html="$options.methods.renderFormattedValue(props.value)"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Markdown from 'markdown-it'
|
||||
import taskLists from 'markdown-it-task-lists'
|
||||
import { parseMarkdown } from '@baserow/modules/core/editor/markdown'
|
||||
|
||||
export default {
|
||||
functional: true,
|
||||
render(createElement, context) {
|
||||
const { props } = context
|
||||
const md = new Markdown({ html: false })
|
||||
|
||||
function parseMarkdown(value) {
|
||||
return md.use(taskLists, { label: true, enabled: true }).render(value)
|
||||
}
|
||||
|
||||
// Take only a part of the text as a preview to avoid rendering a huge amount of
|
||||
// HTML that could slow down the page and won't be visible anyway
|
||||
let preview = ''
|
||||
if (props.value) {
|
||||
preview = props.value.substring(0, 200)
|
||||
if (props.value.length > 200) {
|
||||
preview += '...'
|
||||
name: 'FunctionalGridViewFieldRichText',
|
||||
methods: {
|
||||
renderFormattedValue(value) {
|
||||
// Take only a part of the text as a preview to avoid rendering a huge amount of
|
||||
// HTML that could slow down the page and won't be visible anyway
|
||||
let preview = ''
|
||||
if (value) {
|
||||
preview = value.substring(0, 200)
|
||||
if (value.length > 200) {
|
||||
preview += '...'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createElement('div', {
|
||||
class:
|
||||
'grid-view__cell grid-field-rich-text__cell grid-field-rich-text__cell--preview',
|
||||
domProps: {
|
||||
innerHTML: parseMarkdown(preview),
|
||||
},
|
||||
})
|
||||
return parseMarkdown(preview)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,14 +2,21 @@
|
|||
<div
|
||||
ref="cell"
|
||||
class="grid-view__cell grid-field-rich-text__cell active"
|
||||
:class="{ editing: opened && !isModalOpen() }"
|
||||
:class="{
|
||||
editing: opened && !isModalOpen(),
|
||||
'field-rich-text--preview': !opened || isModalOpen(),
|
||||
}"
|
||||
@contextmenu="stopContextIfEditing($event)"
|
||||
>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-if="!opened || isModalOpen()" v-html="formattedValue"></div>
|
||||
<RichTextEditor
|
||||
v-else
|
||||
ref="input"
|
||||
v-model="richCopy"
|
||||
v-prevent-parent-scroll="editing"
|
||||
:class="classNames"
|
||||
class="grid-field-rich-text__textarea"
|
||||
:class="{ 'grid-field-rich-text__textarea--resizable': editing }"
|
||||
:editable="editing && !isModalOpen()"
|
||||
:content-scaled="!opened || isModalOpen()"
|
||||
:enable-rich-text-formatting="true"
|
||||
|
@ -37,6 +44,7 @@ import RichTextEditor from '@baserow/modules/core/components/editor/RichTextEdit
|
|||
import gridField from '@baserow/modules/database/mixins/gridField'
|
||||
import gridFieldInput from '@baserow/modules/database/mixins/gridFieldInput'
|
||||
import FieldRichTextModal from '@baserow/modules/database/components/view/FieldRichTextModal'
|
||||
import { parseMarkdown } from '@baserow/modules/core/editor/markdown'
|
||||
|
||||
export default {
|
||||
components: { RichTextEditor, FieldRichTextModal },
|
||||
|
@ -48,14 +56,8 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
classNames() {
|
||||
if (!this.opened || this.isModalOpen()) {
|
||||
return 'grid-field-rich-text'
|
||||
} else if (this.editing) {
|
||||
return 'grid-field-rich-text__textarea grid-field-rich-text__textarea--resizable'
|
||||
} else {
|
||||
return 'grid-field-rich-text__textarea'
|
||||
}
|
||||
formattedValue() {
|
||||
return parseMarkdown(this.value)
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
Loading…
Add table
Reference in a new issue