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:
122
TODO.md
122
TODO.md
@@ -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.
|
||||
|
||||
**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.
|
||||
|
||||
@@ -380,6 +380,56 @@ body:not(.insertr-edit-mode) .insertr-editing-hover::after {
|
||||
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 */
|
||||
.insertr-simple-editor,
|
||||
.insertr-rich-editor,
|
||||
|
||||
@@ -380,6 +380,56 @@ body:not(.insertr-edit-mode) .insertr-editing-hover::after {
|
||||
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 */
|
||||
.insertr-simple-editor,
|
||||
.insertr-rich-editor,
|
||||
|
||||
@@ -246,6 +246,42 @@ export class StyleAwareEditor {
|
||||
button.title = `Apply ${styleInfo.name} style`;
|
||||
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
|
||||
button.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user