feat: Table support in article editor (#13974)

This commit is contained in:
Sivin Varghese
2026-04-16 11:23:10 +05:30
committed by GitHub
parent cc008951db
commit edd0fc98db
7 changed files with 60 additions and 16 deletions

View File

@@ -161,8 +161,12 @@ const handleCreateArticle = event => {
}
.editor-root .has-selection {
.ProseMirror-menubar:not(:has(*)) {
display: none !important;
}
.ProseMirror-menubar {
@apply h-8 rounded-lg !px-2 z-50 bg-n-solid-3 items-center gap-4 ml-0 mb-0 shadow-md outline outline-1 outline-n-weak;
@apply rounded-lg !px-3 !py-1.5 z-50 bg-n-background items-center gap-4 ml-0 mb-0 shadow-md outline outline-1 outline-n-weak;
display: flex;
top: var(--selection-top, auto) !important;
left: var(--selection-left, 0) !important;
@@ -170,15 +174,10 @@ const handleCreateArticle = event => {
position: absolute !important;
.ProseMirror-menuitem {
@apply mr-0;
@apply ltr:mr-0 rtl:ml-0 size-4 flex items-center;
.ProseMirror-icon {
@apply p-0 mt-0 !mr-0;
svg {
width: 20px !important;
height: 20px !important;
}
@apply p-0.5 flex-shrink-0 ltr:mr-2 rtl:ml-2;
}
}

View File

@@ -262,7 +262,8 @@ export default {
// Get the editor's width
const editorWidth = editor.offsetWidth;
const menubarWidth = 480; // Menubar width (adjust as needed (px))
const menubar = editor.querySelector('.ProseMirror-menubar');
const menubarWidth = menubar ? menubar.scrollWidth : 480;
// Get the end position of the selection
const { bottom: endBottom, right: endRight } = editorView.coordsAtPos(to);

View File

@@ -182,6 +182,7 @@ export const ARTICLE_EDITOR_MENU_OPTIONS = [
'h3',
'imageUpload',
'code',
'insertTable',
];
/**

View File

@@ -36,7 +36,7 @@
<% end %>
<div class="flex max-w-5xl w-full px-4 md:px-8 mx-auto">
<article id="cw-article-content" class="article-content flex-grow flex-2 mx-auto text-slate-800 dark:text-slate-50 text-lg max-w-3xl prose-h1:text-2xl prose-h2:text-xl prose-h2:mt-0 prose-h3:text-lg prose-code:[&>p]:p-1 prose-code:[&>p]:rounded-sm prose-code:[&>p]:bg-black-100 dark:prose-code:[&>p]:bg-black-600 prose-code:after:content-none prose-code:before:content-none prose dark:prose-invert break-words w-full <%= @is_plain_layout_enabled ? 'py-4' : 'pt-8 pb-12' %>">
<article id="cw-article-content" class="article-content flex-grow flex-2 mx-auto text-slate-800 dark:text-slate-50 text-lg max-w-3xl prose-h1:text-2xl prose-h2:text-xl prose-h2:mt-0 prose-h3:text-lg prose-code:[&>p]:p-1 prose-code:[&>p]:rounded-sm prose-code:[&>p]:bg-black-100 dark:prose-code:[&>p]:bg-black-600 prose-code:after:content-none prose-code:before:content-none prose dark:prose-invert break-words w-full [&_table]:!border-slate-200 dark:[&_table]:!border-slate-800 [&_th]:!border-slate-200 dark:[&_th]:!border-slate-800 [&_td]:!border-slate-200 dark:[&_td]:!border-slate-800 [&_th]:!bg-slate-50 dark:[&_th]:!bg-slate-800/50 <%= @is_plain_layout_enabled ? 'py-4' : 'pt-8 pb-12' %>">
<%= @parsed_content %>
</article>
<div class="flex-1" id="cw-hc-toc"></div>
@@ -45,4 +45,41 @@
.article-content li > p {
margin: 0;
}
.article-content .tableWrapper {
overflow-x: auto;
margin-bottom: 1rem;
}
.article-content table {
min-width: 100%;
border: 1px solid;
border-radius: 8px;
border-spacing: 0;
border-collapse: separate;
margin: 0;
}
.article-content th,
.article-content td {
border-bottom: 1px solid;
border-inline-end: 1px solid;
border-color: inherit;
padding: 0.5rem 0.75rem;
text-align: start;
vertical-align: top;
}
.article-content th:last-child,
.article-content td:last-child {
border-inline-end: none;
}
.article-content th {
font-weight: 600;
}
.article-content th:first-child {
border-start-start-radius: 7px;
}
.article-content th:last-child {
border-start-end-radius: 7px;
}
.article-content tr:last-child td {
border-bottom: none;
}
</style>

View File

@@ -9,6 +9,12 @@ class CustomMarkdownRenderer < CommonMarker::HtmlRenderer
@embed_regexes ||= config.transform_values { |embed_config| Regexp.new(embed_config['regex']) }
end
def table(node)
out('<div class="tableWrapper">')
super
out('</div>')
end
def text(node)
content = node.string_content

View File

@@ -34,7 +34,7 @@
"@amplitude/analytics-browser": "^2.11.10",
"@breezystack/lamejs": "^1.2.7",
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.3.9",
"@chatwoot/prosemirror-schema": "1.3.10",
"@chatwoot/utils": "^0.0.52",
"@formkit/core": "^1.7.2",
"@formkit/vue": "^1.7.2",

10
pnpm-lock.yaml generated
View File

@@ -26,8 +26,8 @@ importers:
specifier: 1.2.3
version: 1.2.3
'@chatwoot/prosemirror-schema':
specifier: 1.3.9
version: 1.3.9
specifier: 1.3.10
version: 1.3.10
'@chatwoot/utils':
specifier: ^0.0.52
version: 0.0.52
@@ -454,8 +454,8 @@ packages:
'@chatwoot/ninja-keys@1.2.3':
resolution: {integrity: sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g==}
'@chatwoot/prosemirror-schema@1.3.9':
resolution: {integrity: sha512-nbzvW4Rfe7EC+tHF/wWJK5pIxRzfQj/DDAtZI7pwM9uJfv9yQz6bAUCA7kz7Vq1NF29XOisZaT5W0005ygk1pg==}
'@chatwoot/prosemirror-schema@1.3.10':
resolution: {integrity: sha512-MtOXqFPHptFHu/AoIPhQ9TskVXOxOXCgBY/tgAtCAQRut978F7I3QxozQBECBz83ubsoXnBecpNjGNq0OPgONw==}
'@chatwoot/utils@0.0.52':
resolution: {integrity: sha512-e57uVqyVW4tj1gql4YJPNMykqMJPkETn5Y9AmHdhc6Y7oxDXfRXBq27fZrrDadLkZdn5RYVCZjfIhXOumyYv2Q==}
@@ -4967,7 +4967,7 @@ snapshots:
hotkeys-js: 3.8.7
lit: 2.2.6
'@chatwoot/prosemirror-schema@1.3.9':
'@chatwoot/prosemirror-schema@1.3.10':
dependencies:
markdown-it-sup: 2.0.0
prosemirror-commands: 1.6.0