app/javascript/panda/cms/editor/editor_js_config.js in panda-cms-0.7.0 vs app/javascript/panda/cms/editor/editor_js_config.js in panda-cms-0.7.2

- old
+ new

@@ -13,134 +13,263 @@ if (window.PANDA_CMS_EDITOR_JS_RESOURCES) { EDITOR_JS_RESOURCES.push(...window.PANDA_CMS_EDITOR_JS_RESOURCES) } export const EDITOR_JS_CSS = ` -/* Editor layout styles */ -.ce-toolbar__content { - margin: 0 !important; - margin-left: 40px; - max-width: 100% !important; - width: 100% !important; -} + .codex-editor { + position: relative; + } + .codex-editor::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 65px; + margin-right: 5px; + background-color: #f9fafb; + border-right: 2px dashed #e5e7eb; + z-index: 0; + } + .ce-block { + padding-left: 70px; + position: relative; + min-height: 40px; + margin: 0; + padding-bottom: 1em; + } + .ce-block__content { + position: relative; + max-width: none; + margin: 0; + } + .ce-paragraph { + padding: 0; + line-height: 1.6; + min-height: 1.6em; + margin: 0; + } + /* Override inherited heading styles */ + .ce-header h1, + .ce-header h2, + .ce-header h3, + .ce-header h4, + .ce-header h5, + .ce-header h6 { + margin: 0; + padding: 0; + line-height: 1.6; + font-weight: 600; + } + .ce-header h1 { font-size: 2em; } + .ce-header h2 { font-size: 1.5em; } + .ce-header h3 { font-size: 1.17em; } + .ce-header h4 { font-size: 1em; } + .ce-header h5 { font-size: 0.83em; } + .ce-header h6 { font-size: 0.67em; } -.ce-block__content { - max-width: 100%; - margin: 0 !important; - margin-left: 10px !important; -} + .codex-editor__redactor { + padding-bottom: 150px !important; + min-height: 100px !important; + } + /* Base toolbar styles */ + .ce-toolbar { + left: 0 !important; + right: auto !important; + background: none !important; + position: absolute !important; + width: 65px !important; + height: 40px !important; + display: flex !important; + align-items: center !important; + justify-content: flex-start !important; + padding: 0 !important; + margin-left: -70px !important; + margin-top: -5px !important; + opacity: 1 !important; + visibility: visible !important; + pointer-events: all !important; + z-index: 2 !important; + } + /* Ensure toolbar is visible for all blocks */ + .ce-block .ce-toolbar { + display: flex !important; + opacity: 1 !important; + visibility: visible !important; + } + .ce-toolbar__content { + max-width: none; + left: 70px !important; + display: flex !important; + position: relative !important; + } + .ce-toolbar__actions { + position: relative !important; + left: 5px !important; + opacity: 1 !important; + visibility: visible !important; + background: transparent !important; + z-index: 2; + display: flex !important; + align-items: center !important; + gap: 5px !important; + height: 40px !important; + padding: 0 !important; + } + .ce-toolbar__plus { + position: relative !important; + left: 0px !important; + opacity: 1 !important; + visibility: visible !important; + background: transparent !important; + border: none !important; + z-index: 2; + display: block !important; + } + .ce-toolbar__settings-btn { + position: relative !important; + left: -10px !important; + opacity: 1 !important; + visibility: visible !important; + background: transparent !important; + border: none !important; + z-index: 2; + display: block !important; + } + /* Style the search input */ + .ce-popover__search { + padding-left: 3px !important; + } + .ce-popover__search input { + outline: none !important; + box-shadow: none !important; + border: none !important; + } + .ce-popover__search input::placeholder { + content: 'Search'; + } + /* Ensure popups still work */ + .ce-popover { + z-index: 4; + } + .ce-inline-toolbar { + z-index: 3; + } + /* Override any hiding behavior */ + .ce-toolbar--closed, + .ce-toolbar--opened, + .ce-toolbar--showed { + display: flex !important; + opacity: 1 !important; + visibility: visible !important; + } + /* Force toolbar to show on every block */ + .ce-block:not(:focus):not(:hover) .ce-toolbar, + .ce-block--selected .ce-toolbar, + .ce-block--focused .ce-toolbar, + .ce-block--hover .ce-toolbar { + opacity: 1 !important; + visibility: visible !important; + display: flex !important; + } -/* Ensure proper nesting for content styles to apply */ -.codex-editor .codex-editor__redactor { - position: relative; -} + /* Ensure last block has bottom spacing */ + .ce-block:last-child { + padding-bottom: 2em; + } -.codex-editor .codex-editor__redactor .ce-block { - position: relative; -} + /* Reset all block type margins */ + .ce-header, + .ce-paragraph, + .ce-quote, + .ce-list { + margin: 0 !important; + padding: 0 !important; + } +` -.codex-editor .codex-editor__redactor .ce-block .ce-block__content { - position: relative; -} - -/* Remove default editor styles that might interfere */ -.ce-header { - padding: 0 !important; - margin: 0 !important; - background: none !important; - border: none !important; -} - -.ce-paragraph { - padding: 0 !important; - margin: 0 !important; - line-height: inherit !important; -} - -/* Lists */ -.ce-block--list ul, -.ce-block--list ol { - margin: 0; - padding-left: inherit; -} - -.ce-block--list li { - margin: 0; - padding-left: inherit; -} - -/* Ensure editor toolbar is above content */ -.ce-toolbar { - z-index: 100; -} - -/* Style the block selection */ -.ce-block--selected { - background-color: rgba(16, 64, 113, 0.05); - border-radius: 4px; -}` - export const getEditorConfig = (elementId, previousData, doc = document) => { // Validate holder element exists const holder = doc.getElementById(elementId) if (!holder) { throw new Error(`Editor holder element ${elementId} not found`) } + // Get the correct window context + const win = doc.defaultView || window + + // Ensure we have a clean holder element + holder.innerHTML = "" + const config = { holder: elementId, data: previousData || {}, placeholder: 'Click the + button to add content...', inlineToolbar: true, + onChange: () => { + // Ensure the editor is properly initialized before handling changes + if (holder && holder.querySelector('.codex-editor')) { + const event = new Event('editor:change', { bubbles: true }) + holder.dispatchEvent(event) + } + }, + i18n: { + toolbar: { + filter: { + placeholder: 'Search' + } + } + }, tools: { header: { - class: window.Header, + class: win.Header, inlineToolbar: true, config: { placeholder: 'Enter a header', levels: [1, 2, 3, 4, 5, 6], defaultLevel: 2 } }, paragraph: { - class: window.Paragraph, + class: win.Paragraph, inlineToolbar: true, config: { placeholder: 'Start writing or press Tab to add content...' } }, list: { - class: window.NestedList, + class: win.NestedList, inlineToolbar: true, config: { - defaultStyle: 'unordered' + defaultStyle: 'unordered', + enableLineBreaks: true } }, quote: { - class: window.Quote, + class: win.Quote, inlineToolbar: true, config: { quotePlaceholder: 'Enter a quote', captionPlaceholder: 'Quote\'s author' } }, - table: { - class: window.Table, + image: { + class: win.SimpleImage, inlineToolbar: true, config: { - rows: 2, - cols: 2 + placeholder: 'Paste an image URL...' } }, - image: { - class: window.SimpleImage, + table: { + class: win.Table, inlineToolbar: true, config: { - placeholder: 'Paste an image URL...' + rows: 2, + cols: 2 } }, embed: { - class: window.Embed, + class: win.Embed, inlineToolbar: true, config: { services: { youtube: true, vimeo: true