feat: Implement dynamic style preview buttons

- Add JavaScript-based style copying from original elements to toolbar buttons
- Use getComputedStyle() to dynamically apply color, font-weight, text-decoration, text-transform
- Preserve button clickability with protected backgrounds and hover states
- Support any CSS framework/custom styles without hardcoded mappings
- Add comprehensive documentation to TODO.md for future enhancements

Examples:
- 'Emphasis' button now shows red bold text (from .emph class)
- 'Highlight' button displays with style preview while remaining clickable
- 'Brand' button demonstrates text-transform and color changes

This provides intuitive visual feedback so users immediately understand
what each formatting button will do to their content.
This commit is contained in:
2025-09-19 20:48:01 +02:00
parent d317e2e1d9
commit 01c8dcca76
4 changed files with 258 additions and 0 deletions

122
TODO.md
View File

@@ -535,3 +535,125 @@ The HTTP server has been successfully implemented and is production-ready:
**Priority**: Low - implement after core functionality is stable and enterprise customers request advanced permissions. **Priority**: Low - implement after core functionality is stable and enterprise customers request advanced permissions.
**Design Principle**: Keep simple `.insertr-gate` as default, add optional complexity only when needed. **Design Principle**: Keep simple `.insertr-gate` as default, add optional complexity only when needed.
## 🎨 **Style Preview Enhancement System** (Dec 2024)
### **✅ IMPLEMENTED: Basic Style Button Previews**
**Goal**: Make formatting buttons visually preview the styles they represent.
**Current Implementation**:
-**Dynamic Style Copying** - JavaScript reads computed styles from original elements
-**Selective Property Application** - Copies color, font-weight, text-decoration, text-transform
-**Button Structure Preservation** - Maintains clickable button appearance with backgrounds/borders
-**Cross-Platform Compatibility** - Uses `window.getComputedStyle()` for universal support
**Example Results**:
- "Emphasis" button displays with red bold text (from `.emph { color: #dc2626; font-weight: 700; }`)
- "Highlight" button shows preview styling while remaining clickable
- "Brand" button demonstrates text-transform and color changes
### **🔄 Future Style Preview Enhancements**
#### **🎯 Priority 1: Enhanced Style Support**
- [ ] **Background Colors** - Safe background preview with contrast protection
- [ ] **Border Styles** - Preview border styles while maintaining button structure
- [ ] **Typography Styles** - Font-family, font-size adjustments with readability limits
- [ ] **Advanced CSS Properties** - Text-shadow, letter-spacing, line-height previews
#### **🎯 Priority 2: Interactive Previews**
- [ ] **Hover State Previews** - Show hover effects in button previews
- [ ] **Animation Previews** - Preview CSS transitions and animations safely
- [ ] **Responsive Previews** - Show how styles adapt across screen sizes
- [ ] **Nested Style Previews** - Handle complex nested styling scenarios
#### **🎯 Priority 3: Advanced Preview Features**
- [ ] **Custom Style Creation** - Visual style picker with live preview
- [ ] **Style Inheritance Display** - Show which properties come from which classes
- [ ] **Accessibility Validation** - Ensure previews meet contrast and readability standards
- [ ] **Performance Optimization** - Cache computed styles, minimize recomputation
### **🔧 Technical Implementation Details**
**Current Approach** (JavaScript-based style copying):
```javascript
const computedStyle = window.getComputedStyle(styleInfo.element);
if (computedStyle.color && computedStyle.color !== 'rgb(0, 0, 0)') {
button.style.setProperty('color', computedStyle.color, 'important');
}
```
**Benefits**:
- ✅ Works with any CSS framework or custom styles
- ✅ No hardcoded style mappings required
- ✅ Automatically adapts to theme changes
- ✅ Handles complex CSS specificity scenarios
**Limitations**:
- ⚠️ Limited to properties safe for button elements
- ⚠️ Background colors skipped to maintain readability
- ⚠️ Some complex styles may not preview accurately
- ⚠️ Performance impact on large style sets
### **🎨 Design Considerations**
**Readability vs Accuracy Trade-offs**:
- **Button Backgrounds**: Always use safe background to ensure clickability
- **Text Contrast**: Ensure sufficient contrast between text and button background
- **Property Selection**: Only preview properties that don't break button functionality
- **Fallback Handling**: Graceful degradation when style copying fails
**User Experience Principles**:
- **Immediate Recognition**: Users should instantly understand what each button does
- **Consistent Interaction**: Buttons should always feel clickable regardless of style
- **Visual Hierarchy**: Style previews shouldn't overpower the editor interface
- **Accessibility**: Maintain WCAG compliance for all preview combinations
### **🧪 Testing Strategy for Style Previews**
**Cross-Browser Compatibility**:
- Test `getComputedStyle()` behavior across major browsers
- Validate CSS custom property support and inheritance
- Check for inconsistencies in color space handling
**Edge Case Handling**:
- Very long class names or deeply nested selectors
- Conflicting CSS properties from multiple stylesheets
- High contrast or accessibility mode compatibility
- Performance with large numbers of detected styles
**Real-World Style Testing**:
- Test with popular CSS frameworks (Tailwind, Bootstrap, Bulma)
- Validate with complex design systems and component libraries
- Check compatibility with CSS-in-JS solutions
- Test with user-defined custom properties and themes
### **📊 Future Metrics and Analytics**
**Style Preview Usage Analytics**:
- Track which style previews are most commonly used
- Measure user engagement with preview vs non-preview buttons
- Identify styles that cause preview rendering issues
- Monitor performance impact of style computation
**User Experience Improvements**:
- A/B test preview accuracy vs simplified representations
- Test user comprehension of style previews vs text labels
- Measure editing efficiency with vs without previews
- Gather feedback on preview helpfulness for different user types
### **Integration with Future Features**
**Style Management System**:
- Style preview integration with custom style creation tools
- Preview integration with theme switching and dark mode
- Connection to style documentation and design system integration
- Preview role in collaborative editing and style consistency
**Performance Optimization**:
- Style preview caching for frequently used styles
- Lazy loading of preview computation for off-screen elements
- Optimization for mobile devices and slower browsers
- Integration with build-time style optimization
**Note**: Current implementation provides solid foundation for all future enhancements while maintaining the zero-configuration philosophy.

View File

@@ -380,6 +380,56 @@ body:not(.insertr-edit-mode) .insertr-editing-hover::after {
transform: translateY(1px); transform: translateY(1px);
} }
/* Style preview buttons - styled dynamically via JavaScript */
.insertr-style-btn.insertr-style-preview {
/* Preserve button structure */
background: var(--insertr-bg-primary) !important;
border: 1px solid var(--insertr-border-color) !important;
border-radius: var(--insertr-border-radius) !important;
padding: var(--insertr-spacing-xs) var(--insertr-spacing-sm) !important;
font-size: var(--insertr-font-size-sm) !important;
cursor: pointer !important;
transition: var(--insertr-transition) !important;
/* Button layout */
min-height: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
/* Ensure button remains clickable */
position: relative;
/* Styles will be applied dynamically via JavaScript */
}
/* Add subtle background to preview buttons to ensure they remain clickable-looking */
.insertr-style-btn.insertr-style-preview::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--insertr-bg-primary);
opacity: 0.9;
border-radius: inherit;
z-index: -1;
}
/* Hover state for preview buttons */
.insertr-style-btn.insertr-style-preview:hover {
background: var(--insertr-bg-secondary) !important;
border-color: var(--insertr-text-muted) !important;
transform: none !important;
}
/* Active state for preview buttons */
.insertr-style-btn.insertr-style-preview:active {
background: var(--insertr-border-color) !important;
transform: translateY(1px) !important;
}
/* Editor components */ /* Editor components */
.insertr-simple-editor, .insertr-simple-editor,
.insertr-rich-editor, .insertr-rich-editor,

View File

@@ -380,6 +380,56 @@ body:not(.insertr-edit-mode) .insertr-editing-hover::after {
transform: translateY(1px); transform: translateY(1px);
} }
/* Style preview buttons - styled dynamically via JavaScript */
.insertr-style-btn.insertr-style-preview {
/* Preserve button structure */
background: var(--insertr-bg-primary) !important;
border: 1px solid var(--insertr-border-color) !important;
border-radius: var(--insertr-border-radius) !important;
padding: var(--insertr-spacing-xs) var(--insertr-spacing-sm) !important;
font-size: var(--insertr-font-size-sm) !important;
cursor: pointer !important;
transition: var(--insertr-transition) !important;
/* Button layout */
min-height: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
/* Ensure button remains clickable */
position: relative;
/* Styles will be applied dynamically via JavaScript */
}
/* Add subtle background to preview buttons to ensure they remain clickable-looking */
.insertr-style-btn.insertr-style-preview::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--insertr-bg-primary);
opacity: 0.9;
border-radius: inherit;
z-index: -1;
}
/* Hover state for preview buttons */
.insertr-style-btn.insertr-style-preview:hover {
background: var(--insertr-bg-secondary) !important;
border-color: var(--insertr-text-muted) !important;
transform: none !important;
}
/* Active state for preview buttons */
.insertr-style-btn.insertr-style-preview:active {
background: var(--insertr-border-color) !important;
transform: translateY(1px) !important;
}
/* Editor components */ /* Editor components */
.insertr-simple-editor, .insertr-simple-editor,
.insertr-rich-editor, .insertr-rich-editor,

View File

@@ -246,6 +246,42 @@ export class StyleAwareEditor {
button.title = `Apply ${styleInfo.name} style`; button.title = `Apply ${styleInfo.name} style`;
button.dataset.styleId = styleId; button.dataset.styleId = styleId;
// Apply preview styling by copying computed styles from the original element
if (styleInfo.element && styleInfo.classes && styleInfo.classes.length > 0) {
// Add the detected classes first
styleInfo.classes.forEach(className => {
button.classList.add(className);
});
// Add special button class
button.classList.add('insertr-style-preview');
// Copy specific style properties from the original element to ensure they show
const computedStyle = window.getComputedStyle(styleInfo.element);
// Copy color (most important for visual preview)
if (computedStyle.color && computedStyle.color !== 'rgb(0, 0, 0)') {
button.style.setProperty('color', computedStyle.color, 'important');
}
// Copy font-weight
if (computedStyle.fontWeight && computedStyle.fontWeight !== '400') {
button.style.setProperty('font-weight', computedStyle.fontWeight, 'important');
}
// Copy text-decoration (for underlines, etc.)
if (computedStyle.textDecoration && computedStyle.textDecoration !== 'none') {
button.style.setProperty('text-decoration', computedStyle.textDecoration, 'important');
}
// Copy text-transform (for uppercase, etc.)
if (computedStyle.textTransform && computedStyle.textTransform !== 'none') {
button.style.setProperty('text-transform', computedStyle.textTransform, 'important');
}
// Don't copy background-color to keep button appearance
}
// Add click handler for style application // Add click handler for style application
button.addEventListener('click', (e) => { button.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();