Blog Editor UX Enhancements
Status: Production Ready
Version: 1.0.0
Last Updated: January 2025
Overview
The blog editor has been redesigned with improved UX patterns including horizontal tabs, an external toolbar, and WYSIWYG styling that matches the live site. These changes provide a more intuitive editing experience while maximizing content area space.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Horizontal Tab Navigation (Bootstrap 5) │
│ [Summary] [Content] [Tagging] [Status] [Related] [Advanced] │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ External Toolbar Container (#redactor-blog-toolbar) │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Bold | Italic | ... | WY Image | WY Video | WY FAQ | AI... ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Redactor Content Area │
│ (Full width, WWW styles injected) │
│ │
└─────────────────────────────────────────────────────────────────┘
Features
Horizontal Tabs
The post form uses Bootstrap 5 horizontal tabs instead of vertical navigation:
- Summary - Title, description, author, dates
- Content - Redactor editor (full width)
- Tagging - Tags and categories
- Status - Publication state, scheduling
- Related - Related articles
- Advanced - Content processing, TOC, schema markup
Tab state persists across form submissions via tab_persist_controller.js.
External Toolbar
The Redactor toolbar is rendered outside the editor in a dedicated container:
<%# app/views/crm/posts/_form.html.erb %>
<div id="redactor-blog-toolbar" class="mb-3"></div>
Benefits:
- Stays visible when scrolling
- Doesn't interfere with content area
- Consistent positioning
WYSIWYG CSS Injection
The editor content area is styled to match the live blog:
// redactor4_init_controller.js
if (isBlogEditor && editor.id === 'redactor-blog') {
// Fetch WWW CSS and inject into Redactor content area
const cssUrls = JSON.parse(editor.dataset.wwwCss || '[]')
cssUrls.forEach(url => {
fetch(url)
.then(response => response.text())
.then(css => {
const style = document.createElement('style')
style.textContent = css
rxContent.appendChild(style)
})
})
}
Full Width Content
CSS ensures the editor uses all available space:
// _general.scss
.rx-container {
max-width: 100% !important;
width: 100% !important;
}
.rx-editor,
.rx-content {
max-width: 100% !important;
}
Configuration
Blog Mode vs Other Modes
The Redactor initializer detects blog mode via editor.id === 'redactor-blog':
| Feature | Blog Mode | Other Modes |
|---|---|---|
| External Toolbar | ✅ | ❌ |
| CSS Injection | ✅ WWW styles | ❌ |
| Min Height | 2000px | 300-500px |
| AI Tools | ✅ | Varies |
| WY Plugins | ✅ All | Varies |
Data Attributes
<%= f.input_field :solution, as: :redactor4, id: 'redactor-blog',
data: { www_css: webpack_css_url('www').to_json } %>
| Attribute | Purpose |
|---|---|
id="redactor-blog" |
Identifies blog editor mode |
data-www-css |
JSON array of CSS URLs to inject |
Files
| File | Purpose |
|---|---|
app/views/crm/posts/_form.html.erb |
Post form with horizontal tabs |
app/views/crm/posts/_content.html.erb |
Redactor input configuration |
app/javascript/controllers/redactor4_init_controller.js |
Editor initialization |
app/javascript/controllers/tab_persist_controller.js |
Tab state persistence |
client/stylesheets/crm/partials/_general.scss |
Editor styling |
client/js/crm/editors/redactor4.js |
Redactor base configuration |
Tab Persistence
The tab_persist_controller saves and restores active tab across page loads:
// Supports both <a href="#id"> and <button data-bs-target="#id">
const activeTabId = activeTab.getAttribute('href')?.replace('#', '') ||
activeTab.getAttribute('data-bs-target')?.replace('#', '')
sessionStorage.setItem('activePostTab', activeTabId)
Troubleshooting
Toolbar Not Visible
Cause: External toolbar container missing
Fix: Ensure #redactor-blog-toolbar div exists before the editor
Styles Not Matching WWW
Cause: CSS injection failed or wrong URLs
Fix: Check webpack_css_url('www') returns valid URLs
Tab State Not Persisting
Cause: Bootstrap Tab API not loaded
Fix: Ensure Bootstrap JS is loaded before form submission
Related Documentation
- Redactor Configuration - All editor modes
- WY Image Plugin - Rich image insertion
- UI Conventions - Bootstrap patterns