diff --git a/bin/omarchy-theme-set-obsidian b/bin/omarchy-theme-set-obsidian index 5bb1b7b8..4ff70d4c 100755 --- a/bin/omarchy-theme-set-obsidian +++ b/bin/omarchy-theme-set-obsidian @@ -87,6 +87,35 @@ calculate_brightness() { echo $(((r * 299 + g * 587 + b * 114) / 1000)) } +# Calculate approximate contrast ratio between two colors +# Returns ratio scaled by 100 (e.g., 450 = 4.5:1 ratio) +# (this is due to bash not supporting decimal math) +calculate_contrast_ratio() { + local hex1="$1" hex2="$2" + local br1=$(calculate_brightness "$hex1") # 0-255 range + local br2=$(calculate_brightness "$hex2") # 0-255 range + + # Ensure br1 is the lighter color (higher brightness) + if [ $br1 -lt $br2 ]; then + local temp=$br1 + br1=$br2 + br2=$temp + fi + + # Approximate contrast ratio scaled by 100 + # Add offset to avoid division by zero and approximate WCAG +0.05 behavior + echo $(((br1 + 13) * 100 / (br2 + 13))) +} + +# Check if two colors meet minimum contrast threshold +# Usage: meets_contrast_threshold +# Both ratio and threshold should be scaled by 100 (e.g., 300 = 3:1) +meets_contrast_threshold() { + local ratio="$1" # Ratio scaled by 100 (from calculate_contrast_ratio) + local threshold="$2" # Threshold scaled by 100 (300=3:1, 450=4.5:1, 700=7:1) + [ $ratio -ge $threshold ] +} + # Calculate color distance (euclidean in RGB space) color_distance() { local hex1="$1" @@ -229,38 +258,30 @@ extract_theme_data() { fi done - # Sort by distance and get the closest color for code background - local -a closest_to_bg - readarray -t closest_to_bg < <(printf '%s\n' "${bg_distances[@]}" | sort -n | head -1 | cut -d: -f2) - # All background variations use the same as primary background local bg_primary_alt="$bg_color" local bg_secondary="$bg_color" local bg_secondary_alt="$bg_color" - # Code block background uses the closest different color - local code_bg="${closest_to_bg[0]}" - - # If no different color available, create a subtle variant for code blocks - if [ -z "$code_bg" ]; then - read -r r g b <<<"$(hex_to_rgb "$bg_color")" - if [ $bg_brightness -gt 127 ]; then - r=$((r - 10)) - g=$((g - 10)) - b=$((b - 10)) - else - r=$((r + 15)) - g=$((g + 15)) - b=$((b + 15)) - fi - [ $r -lt 0 ] && r=0 - [ $r -gt 255 ] && r=255 - [ $g -lt 0 ] && g=0 - [ $g -gt 255 ] && g=255 - [ $b -lt 0 ] && b=0 - [ $b -gt 255 ] && b=255 - code_bg=$(printf "#%02x%02x%02x" "$r" "$g" "$b") + # Generate code background color that will contrast with foreground text + read -r r g b <<<"$(hex_to_rgb "$bg_color")" + if [ $bg_brightness -gt 127 ]; then + r=$((r - 10)) + g=$((g - 10)) + b=$((b - 10)) + else + r=$((r + 15)) + g=$((g + 15)) + b=$((b + 15)) fi + [ $r -lt 0 ] && r=0 + [ $r -gt 255 ] && r=255 + [ $g -lt 0 ] && g=0 + [ $g -gt 255 ] && g=255 + [ $b -lt 0 ] && b=0 + [ $b -gt 255 ] && b=255 + code_bg=$(printf "#%02x%02x%02x" "$r" "$g" "$b") + # Find closest color to foreground for code block text local code_fg="" @@ -345,6 +366,22 @@ extract_theme_data() { border_color=$(printf "#%02x%02x%02x" "$r" "$g" "$b") fi + # Set text colors for muted/faint based on contrast + local text_muted_color="$border_color" + local text_faint_color="$border_color" + + # Validate border color contrast against background + + # Represents a 3:1 WCAG contrast ratio + local ideal_contrast_ratio=300 + + local border_contrast=$(calculate_contrast_ratio "$border_color" "$bg_color") + if ! meets_contrast_threshold "$border_contrast" "$ideal_contrast_ratio"; then + # Override text colors for readability, keep border color for visibility + text_muted_color="$fg_color" + text_faint_color="$fg_color" + fi + # Get unique colors array (without bg/fg) sorted by frequency local -a unique_colors readarray -t unique_colors < <(echo "$filtered_data" | sort_colors_by_frequency) @@ -409,8 +446,8 @@ extract_theme_data() { --text-mark: ${color_slots[7]}; --interactive-accent: ${color_slots[8]}; --blockquote-border: ${color_slots[9]}; - --text-muted: $border_color; /* Use border color for muted text */ - --text-faint: $border_color; /* Use border color for faint text */ + --text-muted: $text_muted_color; /* Use text-specific color for muted text */ + --text-faint: $text_faint_color; /* Use text-specific color for faint text */ /* Additional mappings */ --text-accent: var(--interactive-accent);