diff --git a/src/editor-extension/RatingWidget.ts b/src/editor-extension/RatingWidget.ts index ddaa0cb..725838f 100644 --- a/src/editor-extension/RatingWidget.ts +++ b/src/editor-extension/RatingWidget.ts @@ -49,8 +49,7 @@ export class RatingWidget extends WidgetType { for (let i = 0; i < displaySymbolCount; i++) { const span = document.createElement('span'); span.textContent = this.symbolSet.full; - span.style.cursor = 'pointer'; - span.style.position = 'relative'; + span.className = 'interactive-rating-symbol'; span.setAttribute('data-symbol-index', i.toString()); // Add click handler with full-only validation @@ -156,6 +155,17 @@ export class RatingWidget extends WidgetType { } } + /** + * Apply the appropriate CSS class to a symbol based on its state + */ + private applySymbolState(span: HTMLElement, state: 'rated' | 'unrated' | 'normal'): void { + // Remove all state classes + span.classList.remove('interactive-rating-symbol--rated', 'interactive-rating-symbol--unrated', 'interactive-rating-symbol--normal'); + + // Add the appropriate state class + span.classList.add(`interactive-rating-symbol--${state}`); + } + /** * Preview rating with proper half-symbol rendering and full-only symbol support */ @@ -175,29 +185,24 @@ export class RatingWidget extends WidgetType { // For full-only symbols: show full symbol for rated, grey for unrated span.textContent = this.symbolSet.full; if (symbolRating <= newRating) { - span.style.opacity = '1'; - span.style.filter = 'none'; + this.applySymbolState(span, 'rated'); } else { - span.style.opacity = '0.5'; - span.style.filter = 'grayscale(100%)'; + this.applySymbolState(span, 'unrated'); } } else { // Regular symbol behavior if (symbolRating <= newRating) { // Full symbol span.textContent = this.symbolSet.full; - span.style.opacity = '1'; - span.style.filter = 'none'; + this.applySymbolState(span, 'normal'); } else if (this.symbolSet.half && halfRating <= newRating && halfRating > newRating - 0.5) { // Half symbol span.textContent = this.symbolSet.half; - span.style.opacity = '1'; - span.style.filter = 'none'; + this.applySymbolState(span, 'normal'); } else { // Empty symbol span.textContent = this.symbolSet.empty; - span.style.opacity = '1'; - span.style.filter = 'none'; + this.applySymbolState(span, 'normal'); } } }); @@ -250,11 +255,9 @@ export class RatingWidget extends WidgetType { // For full-only symbols: show full symbol for rated, grey for unrated span.textContent = this.symbolSet.full; if (symbolRating <= rating) { - span.style.opacity = '1'; - span.style.filter = 'none'; + this.applySymbolState(span, 'rated'); } else { - span.style.opacity = '0.5'; - span.style.filter = 'grayscale(100%)'; + this.applySymbolState(span, 'unrated'); } } else { // Regular symbol behavior @@ -268,9 +271,8 @@ export class RatingWidget extends WidgetType { // Empty symbol span.textContent = this.symbolSet.empty; } - // Reset any styling for regular symbols - span.style.opacity = '1'; - span.style.filter = 'none'; + // Apply normal state for regular symbols + this.applySymbolState(span, 'normal'); } }); diff --git a/styles.css b/styles.css index d082c68..2cde63b 100644 --- a/styles.css +++ b/styles.css @@ -38,6 +38,32 @@ color: inherit; } +/* Base symbol styling */ +.interactive-rating-symbol { + position: relative; + cursor: pointer; + display: inline-block; + transition: opacity 0.2s ease, filter 0.2s ease; +} + +/* Active/rated symbol state */ +.interactive-rating-symbol--rated { + opacity: 1; + filter: none; +} + +/* Inactive/unrated symbol state (for full-only symbols) */ +.interactive-rating-symbol--unrated { + opacity: 0.5; + filter: grayscale(100%); +} + +/* Normal symbol state (for regular symbols) */ +.interactive-rating-symbol--normal { + opacity: 1; + filter: none; +} + /* Individual symbol spans in editor widget with half-symbol support */ .interactive-rating-editor-widget .interactive-rating-symbols span { position: relative; @@ -80,14 +106,14 @@ transition: opacity 0.2s ease, filter 0.2s ease; } -/* Ensure full-only unrated symbols are properly grayed out */ -.interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbols span[style*="opacity: 0.5"] { +/* Ensure full-only unrated symbols are properly grayed out - using class-based approach */ +.interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbol--unrated { opacity: 0.5 !important; filter: grayscale(100%) !important; } -/* Ensure full-only rated symbols are fully visible */ -.interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbols span[style*="opacity: 1"] { +/* Ensure full-only rated symbols are fully visible - using class-based approach */ +.interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbol--rated { opacity: 1 !important; filter: none !important; } @@ -120,8 +146,8 @@ /* No visual elements */ } - /* Enhanced contrast for full-only symbols */ - .interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbols span[style*="opacity: 0.5"] { + /* Enhanced contrast for full-only symbols using class-based approach */ + .interactive-rating-editor-widget[data-full-only="true"] .interactive-rating-symbol--unrated { opacity: 0.3 !important; filter: grayscale(100%) contrast(0.7) !important; } @@ -132,7 +158,8 @@ .interactive-rating-editor-widget, .interactive-rating-editor-widget .interactive-rating-symbols span, .interactive-rating-editor-widget .interactive-rating-symbols span::before, - .interactive-rating-editor-widget .interactive-rating-symbols span::after { + .interactive-rating-editor-widget .interactive-rating-symbols span::after, + .interactive-rating-symbol { transition: none; } }