lib/clacky/ui2/themes/base_theme.rb
# frozen_string_literal: true require "pastel" module Clacky module UI2 module Themes # BaseTheme defines the abstract interface for all themes # Subclasses MUST define SYMBOLS and COLORS constants class BaseTheme def initialize @pastel = Pastel.new @is_dark_background = nil # Will be set by ThemeManager validate_theme_definition! end # Set background mode (called by ThemeManager after detection) # @param is_dark [Boolean] true if dark background, false if light def set_background_mode(is_dark) @is_dark_background = is_dark end # Get all symbols defined by this theme # @return [Hash] Symbol definitions def symbols self.class::SYMBOLS end # Get all colors defined by this theme # @return [Hash] Color definitions def colors self.class::COLORS end # Get symbol for a specific key # @param key [Symbol] Symbol key # @return [String] Symbol string def symbol(key) symbols[key] || "[??]" end # Get symbol color for a specific key # @param key [Symbol] Color key # @return [Symbol] Pastel color method name def symbol_color(key) colors.dig(key, 0) || :white end # Get text color for a specific key # Automatically selects appropriate color based on terminal background # Color format: [symbol_color, dark_bg_text_color, light_bg_text_color] # @param key [Symbol] Color key # @return [Symbol] Pastel color method name def text_color(key) color_def = colors[key] return :white unless color_def # Use index 1 for dark background, index 2 for light background dark_background? ? color_def[1] : color_def[2] end # Format symbol with its color # @param key [Symbol] Symbol key (e.g., :user, :assistant) # @return [String] Colored symbol def format_symbol(key) @pastel.public_send(symbol_color(key), symbol(key)) end # Format text with color for given key # @param text [String] Text to format # @param key [Symbol] Color key (e.g., :user, :assistant) # @return [String] Colored text def format_text(text, key) @pastel.public_send(text_color(key), text) end # Theme name for display (subclasses should override) # @return [String] Theme name def name raise NotImplementedError, "Subclass must implement #name method" end # Check if terminal has dark background # Uses pre-detected value from ThemeManager, or defaults to true # @return [Boolean] true if dark background, false if light background def dark_background? # Use pre-detected value if available, otherwise default to dark @is_dark_background.nil? ? true : @is_dark_background end # Validate that subclass has defined required constants def validate_theme_definition! unless self.class.const_defined?(:SYMBOLS) raise NotImplementedError, "Theme #{self.class.name} must define SYMBOLS constant" end unless self.class.const_defined?(:COLORS) raise NotImplementedError, "Theme #{self.class.name} must define COLORS constant" end end end end end end