diff --git a/bin/omarchy-theme-set-obsidian b/bin/omarchy-theme-set-obsidian
index 6906b28d..f86cea1d 100755
--- a/bin/omarchy-theme-set-obsidian
+++ b/bin/omarchy-theme-set-obsidian
@@ -1,52 +1,18 @@
#!/bin/bash
-# omarchy-theme-set-obsidian: Bootstrap and update Omarchy theme for Obsidian
-#
-# - Ensures registry at ~/.local/state/omarchy/obsidian-vaults
-# - Populates by extracting vault paths from ~/.config/obsidian/obsidian.json
-# - For each valid vault:
-# - Ensures .obsidian/themes/Omarchy/{manifest.json, theme.css}
-# - Updates theme.css (uses current theme’s obsidian.css if present; otherwise generates -- see below)
+# Sync Omarchy theme to all Obsidian vaults
-# Theme automagic generation logic:
-#
-# - Background/foreground: read from ~/.config/omarchy/current/theme/alacritty.toml [colors.primary]
-# (background/foreground). Fallbacks: bg=#1a1b26, fg=#a9b1d6. Compute bg brightness for light/dark handling.
-# - Palette extraction: collect colors from Alacritty (primary/normal/bright/dim/selection), Waybar (@define-color),
-# and Hyprland (col.*_border; rgba->hex). Normalize, dedupe, and count frequencies.
-# - Slot ordering: remove bg/fg, sort remaining colors by frequency, then fill 13 slots by cycling. Map slots to:
-# h1–h6, links, inline code, marks, interactive accent, blockquote border; muted/faint use border color.
-# - Code colors: code background = closest color to bg (Euclidean RGB); if none, make a subtle bg variant (+/− RGB).
-# code foreground = closest color to fg; fallback #e0e0e0.
-# - Border color: from btop.theme theme[div_line]; else blended mix biased toward bg (≈ (bg+fg)/3).
-# - Selection: from Alacritty [colors.selection] (background/text), honoring CellForeground/Background.
-# If missing, background = 75% bg + 25% fg; text chosen for contrast vs selection background.
-# - Fonts: monospace from Alacritty [font] or fontconfig monospace; UI font from fontconfig sans-serif.
-
-VAULTS_FILE="$HOME/.local/state/omarchy/obsidian-vaults"
CURRENT_THEME_DIR="$HOME/.config/omarchy/current/theme"
-ensure_vaults_file() {
- mkdir -p "$(dirname "$VAULTS_FILE")"
- local tmpfile
- tmpfile="$(mktemp)"
- # Extract the Obsidian vault location from config file //.obsidian
- jq -r '.vaults | values[].path' ~/.config/obsidian/obsidian.json 2>/dev/null >>"$tmpfile"
- if [ -s "$tmpfile" ]; then
- sort -u "$tmpfile" >"$VAULTS_FILE"
- else
- : >"$VAULTS_FILE"
- fi
- rm "$tmpfile"
-}
+[ -f "$CURRENT_THEME_DIR/obsidian.css" ] || exit 0
-# Ensure theme directory and minimal manifest exist in a vault
-ensure_theme_scaffold() {
- local vault_path="$1"
- local theme_dir="$vault_path/.obsidian/themes/Omarchy"
+jq -r '.vaults | values[].path' ~/.config/obsidian/obsidian.json 2>/dev/null | while read -r vault_path; do
+ [ -d "$vault_path/.obsidian" ] || continue
+
+ theme_dir="$vault_path/.obsidian/themes/Omarchy"
mkdir -p "$theme_dir"
- if [ ! -f "$theme_dir/manifest.json" ]; then
- cat >"$theme_dir/manifest.json" <<'EOF'
+
+ [ -f "$theme_dir/manifest.json" ] || cat >"$theme_dir/manifest.json" <<'EOF'
{
"name": "Omarchy",
"version": "1.0.0",
@@ -56,624 +22,6 @@ ensure_theme_scaffold() {
"authorUrl": "https://omarchy.org"
}
EOF
- fi
- [ -f "$theme_dir/theme.css" ] || : >"$theme_dir/theme.css"
-}
-# Function to extract hex color from string
-extract_hex_color() {
- echo "$1" | grep -oE '#[0-9a-fA-F]{6}' | head -1
-}
-
-# Function to convert RGB/RGBA to hex
-rgb_to_hex() {
- local rgb_string="$1"
- if [[ $rgb_string =~ rgba?\(([0-9]+),\s*([0-9]+),\s*([0-9]+) ]]; then
- printf "#%02x%02x%02x\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
- fi
-}
-
-# Convert hex to RGB components
-hex_to_rgb() {
- local hex="${1#\#}"
- printf "%d %d %d\n" "0x${hex:0:2}" "0x${hex:2:2}" "0x${hex:4:2}"
-}
-
-# Calculate perceived brightness (0-255)
-calculate_brightness() {
- local hex="$1"
- read -r r g b <<<"$(hex_to_rgb "$hex")"
- # Use perceived brightness formula
- 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"
- local hex2="$2"
- read -r r1 g1 b1 <<<"$(hex_to_rgb "$hex1")"
- read -r r2 g2 b2 <<<"$(hex_to_rgb "$hex2")"
- echo $(((r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2)))
-}
-
-# Extract all colors with frequency count
-extract_all_colors_with_count() {
- local -A color_counts
- local color
-
- # Extract from Alacritty config
- if [ -f "$CURRENT_THEME_DIR/alacritty.toml" ]; then
- # Primary colors
- while IFS= read -r color; do
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [ -n "$color" ] && ((color_counts["$color"]++))
- done < <(grep -E "(background|foreground|cursor|text)" "$CURRENT_THEME_DIR/alacritty.toml" | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | grep "^#")
-
- # Normal colors
- while IFS= read -r color; do
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [ -n "$color" ] && ((color_counts["$color"]++))
- done < <(grep -A 20 "\[colors.normal\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep -E "(black|red|green|yellow|blue|magenta|cyan|white)" | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | grep "^#")
-
- # Bright colors
- while IFS= read -r color; do
- # Add # if missing
- [[ "$color" =~ ^[0-9a-fA-F]{6}$ ]] && color="#$color"
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [[ "$color" =~ ^#[0-9a-f]{6}$ ]] && ((color_counts["$color"]++))
- done < <(grep -A 20 "\[colors.bright\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep -E "(black|red|green|yellow|blue|magenta|cyan|white)" | sed "s/.*[\"']//;s/[\"'].*//")
-
- # Dim colors if present
- while IFS= read -r color; do
- # Add # if missing
- [[ "$color" =~ ^[0-9a-fA-F]{6}$ ]] && color="#$color"
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [[ "$color" =~ ^#[0-9a-f]{6}$ ]] && ((color_counts["$color"]++))
- done < <(grep -A 20 "\[colors.dim\]" "$CURRENT_THEME_DIR/alacritty.toml" 2>/dev/null | grep -E "(black|red|green|yellow|blue|magenta|cyan|white)" | sed "s/.*[\"']//;s/[\"'].*//")
-
- # Selection colors
- while IFS= read -r color; do
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [ -n "$color" ] && ((color_counts["$color"]++))
- done < <(grep -A 5 "\[colors.selection\]" "$CURRENT_THEME_DIR/alacritty.toml" 2>/dev/null | grep -E "(background|text)" | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | grep "^#")
- fi
-
- # Extract from Waybar CSS
- if [ -f "$CURRENT_THEME_DIR/waybar.css" ]; then
- while IFS= read -r color; do
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [ -n "$color" ] && ((color_counts["$color"]++))
- done < <(grep -oE '@define-color [a-z_-]+ #[0-9a-fA-F]{6}' "$CURRENT_THEME_DIR/waybar.css" | grep -oE '#[0-9a-fA-F]{6}')
- fi
-
- # Extract from Hyprland config
- if [ -f "$CURRENT_THEME_DIR/hyprland.conf" ]; then
- while IFS= read -r color; do
- if [[ $color == rgba* ]] || [[ $color == rgb* ]]; then
- color=$(rgb_to_hex "$color")
- fi
- color=$(echo "$color" | tr '[:upper:]' '[:lower:]') # Lowercase for consistency
- [ -n "$color" ] && ((color_counts["$color"]++))
- done < <(grep -E "col\.(active|inactive)_border" "$CURRENT_THEME_DIR/hyprland.conf" | grep -oE 'rgba?\([^)]+\)|#[0-9a-fA-F]{6,8}' | sed 's/ff$//')
- fi
-
- # Output colors with their counts
- for color in "${!color_counts[@]}"; do
- echo "${color_counts[$color]} $color"
- done
-}
-
-# Sort colors by frequency
-sort_colors_by_frequency() {
- # Input is already "count color" format
- sort -rn | cut -d' ' -f2
-}
-
-# Fill color slots with cycling if needed
-fill_color_slots() {
- local -a colors=("$@")
- local -a slots
- local num_colors=${#colors[@]}
-
- # Need 13 slots total (code colors are handled separately)
- local slots_needed=13
-
- if [ $num_colors -eq 0 ]; then
- # No colors available, use defaults
- colors=("#3d3d3d" "#5d5d5d" "#7d7d7d" "#9d9d9d" "#bd93f9" "#50fa7b")
- num_colors=6
- fi
-
- # Fill slots, cycling if necessary
- for ((i = 0; i < slots_needed; i++)); do
- slots[$i]="${colors[$((i % num_colors))]}"
- done
-
- echo "${slots[@]}"
-}
-
-# Main color extraction and theme generation
-extract_theme_data() {
- # Get primary colors from Alacritty
- local bg_color="#1a1b26"
- local fg_color="#a9b1d6"
-
- if [ -f "$CURRENT_THEME_DIR/alacritty.toml" ]; then
- local extracted_bg=$(grep -A 5 "\[colors.primary\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^background = " | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | head -1 | tr '[:upper:]' '[:lower:]')
- local extracted_fg=$(grep -A 5 "\[colors.primary\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^foreground = " | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | head -1 | tr '[:upper:]' '[:lower:]')
- [ -n "$extracted_bg" ] && bg_color="$extracted_bg"
- [ -n "$extracted_fg" ] && fg_color="$extracted_fg"
- fi
-
- # Determine if light or dark theme
- local bg_brightness=$(calculate_brightness "$bg_color")
- local is_light_theme=false
- [ $bg_brightness -gt 127 ] && is_light_theme=true
-
- # Extract all colors with counts
- local color_data=$(extract_all_colors_with_count)
-
- # Filter out background and foreground colors for the main array
- local filtered_data=$(echo "$color_data" | grep -v "$bg_color" | grep -v "$fg_color")
-
- # Get all unique colors (including bg/fg) for distance calculations
- local -a all_unique_colors
- readarray -t all_unique_colors < <(echo "$color_data" | cut -d' ' -f2 | sort -u)
-
- # Find the 3 closest colors to background for background variations
- local -a bg_distances
- for color in "${all_unique_colors[@]}"; do
- if [ "$color" != "$bg_color" ]; then
- distance=$(color_distance "$color" "$bg_color")
- bg_distances+=("$distance:$color")
- fi
- done
-
- # 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"
-
- # 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=""
- min_distance=999999999
- for color in "${all_unique_colors[@]}"; do
- if [ "$color" != "$fg_color" ]; then
- distance=$(color_distance "$color" "$fg_color")
- if [ $distance -lt $min_distance ]; then
- min_distance=$distance
- code_fg="$color"
- fi
- fi
- done
- [ -z "$code_fg" ] && code_fg="#e0e0e0" # Fallback
-
- # Extract text selection colors from Alacritty
- local selection_bg=""
- local selection_fg=""
- if [ -f "$CURRENT_THEME_DIR/alacritty.toml" ]; then
- selection_bg=$(grep -A 5 "\[colors.selection\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^background = " | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | head -1 | tr '[:upper:]' '[:lower:]')
- local selection_text=$(grep -A 5 "\[colors.selection\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^text = " | sed "s/.*[\"']0x/#/;s/.*[\"']#/#/;s/[\"'].*//;s/.*#\([0-9a-fA-F]\{6\}\).*/\#\1/" | head -1 | tr '[:upper:]' '[:lower:]')
-
- # If text is set to CellForeground/CellBackground, use the appropriate color
- if [ -z "$selection_text" ] || [[ "$(grep -A 5 "\[colors.selection\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^text = ")" == *"CellForeground"* ]]; then
- selection_fg="$fg_color"
- elif [[ "$(grep -A 5 "\[colors.selection\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep "^text = ")" == *"CellBackground"* ]]; then
- selection_fg="$bg_color"
- else
- selection_fg="$selection_text"
- fi
- fi
-
- # Fallback if no selection colors found
- if [ -z "$selection_bg" ]; then
- read -r r1 g1 b1 <<<"$(hex_to_rgb "$bg_color")"
- read -r r2 g2 b2 <<<"$(hex_to_rgb "$fg_color")"
- local r=$(((r1 * 3 + r2) / 4)) # 75% background, 25% foreground
- local g=$(((g1 * 3 + g2) / 4))
- local b=$(((b1 * 3 + b2) / 4))
- selection_bg=$(printf "#%02x%02x%02x" "$r" "$g" "$b")
- fi
-
- # Use contrasting color for selection text if not defined
- if [ -z "$selection_fg" ]; then
- # Calculate brightness of selection background
- local sel_brightness=$(calculate_brightness "$selection_bg")
- if [ $sel_brightness -gt 127 ]; then
- selection_fg="$bg_color" # Dark text on light selection
- else
- selection_fg="$fg_color" # Light text on dark selection
- fi
- fi
-
- # Extract border color from btop theme
- local border_color=""
- if [ -f "$CURRENT_THEME_DIR/btop.theme" ]; then
- # Look for theme[div_line] in btop theme
- local btop_divline=$(grep 'theme\[div_line\]' "$CURRENT_THEME_DIR/btop.theme" | head -1)
-
- if [ -n "$btop_divline" ]; then
- # Extract the color value after the = sign
- local extracted=$(echo "$btop_divline" | sed 's/.*=//' | xargs)
-
- # Check if it's a hex color and lowercase it
- if [[ $extracted =~ ^#[0-9a-fA-F]{6}$ ]]; then
- border_color=$(echo "$extracted" | tr '[:upper:]' '[:lower:]')
- elif [[ $extracted =~ ^[0-9a-fA-F]{6}$ ]]; then
- # Add # if missing and lowercase
- border_color=$(echo "#$extracted" | tr '[:upper:]' '[:lower:]')
- fi
- fi
- fi
-
- # Fallback if no border color found
- if [ -z "$border_color" ]; then
- # Use a color between bg and fg
- read -r r1 g1 b1 <<<"$(hex_to_rgb "$bg_color")"
- read -r r2 g2 b2 <<<"$(hex_to_rgb "$fg_color")"
- local r=$(((r1 + r2) / 3)) # Closer to background
- local g=$(((g1 + g2) / 3))
- local b=$(((b1 + b2) / 3))
- 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)
-
- # Fill the 13 color slots (code colors handled separately)
- local -a color_slots
- readarray -t color_slots < <(fill_color_slots "${unique_colors[@]}" | tr ' ' '\n')
-
- # Extract fonts
- local monospace_font="JetBrainsMono Nerd Font"
- local ui_font="Liberation Sans"
-
- if [ -f "$CURRENT_THEME_DIR/alacritty.toml" ]; then
- local alacritty_font=$(grep -A 5 "\[font\]" "$CURRENT_THEME_DIR/alacritty.toml" | grep 'family = ' | head -1 | cut -d'"' -f2)
- [ -n "$alacritty_font" ] && monospace_font="$alacritty_font"
- fi
-
- if [ -f "$HOME/.config/fontconfig/fonts.conf" ]; then
- local fontconfig_mono=$(xmlstarlet sel -t -v '//match[@target="pattern"][test/string="monospace"]/edit[@name="family"]/string' "$HOME/.config/fontconfig/fonts.conf" 2>/dev/null || true)
- [ -n "$fontconfig_mono" ] && monospace_font="$fontconfig_mono"
-
- local fontconfig_sans=$(xmlstarlet sel -t -v '//match[@target="pattern"][test/string="sans-serif"]/edit[@name="family"]/string' "$HOME/.config/fontconfig/fonts.conf" 2>/dev/null || true)
- [ -n "$fontconfig_sans" ] && ui_font="$fontconfig_sans"
- fi
-
- # Generate CSS with 14-slot system
- cat </dev/null || echo "unknown")") */
-/* Colors sorted by frequency, backgrounds by distance */
-
-.theme-dark, .theme-light {
- /* Core colors */
- --background-primary: $bg_color;
- --text-normal: $fg_color;
-
- /* Background variations (always distance-based) */
- --background-primary-alt: $bg_primary_alt;
- --background-secondary: $bg_secondary;
- --background-secondary-alt: $bg_secondary_alt;
-
- /* Code block colors (always distance-based) */
- --code-background: $code_bg;
- --code-foreground: $code_fg;
-
- /* Border color from btop theme */
- --border-color: $border_color;
-
- /* Selection colors from Alacritty */
- --text-selection: $selection_bg;
- --text-selection-fg: $selection_fg;
-
- /* 13-slot color system for remaining elements */
- --text-title-h1: ${color_slots[0]};
- --text-title-h2: ${color_slots[1]};
- --text-title-h3: ${color_slots[2]};
- --text-title-h4: ${color_slots[3]};
- --text-title-h5: ${color_slots[4]};
- --text-title-h6: ${color_slots[4]}; /* Same as h5 */
- --text-link: ${color_slots[5]};
- --markup-code: ${color_slots[6]};
- --text-mark: ${color_slots[7]};
- --interactive-accent: ${color_slots[8]};
- --blockquote-border: ${color_slots[9]};
- --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);
- --text-accent-hover: var(--interactive-accent);
- --text-error: var(--text-title-h1);
- --text-error-hover: var(--text-title-h1);
- --text-highlight-bg: $fg_color; /* Use text color as highlight background */
- --text-on-accent: $bg_color;
-
- --interactive-normal: var(--code-background);
- --interactive-hover: var(--interactive-accent);
- --interactive-accent-hover: var(--interactive-accent);
- --interactive-success: var(--text-title-h2);
-
- --scrollbar-bg: var(--background-primary);
- --scrollbar-thumb-bg: var(--code-background);
- --scrollbar-active-thumb-bg: var(--interactive-accent);
-
- --background-modifier-border: var(--border-color);
- --background-modifier-form-field: var(--code-background);
- --background-modifier-form-field-highlighted: var(--code-background);
- --background-modifier-box-shadow: rgba(0, 0, 0, 0.3);
- --background-modifier-success: var(--interactive-success);
- --background-modifier-error: var(--text-error);
- --background-modifier-error-hover: var(--text-error);
- --background-modifier-cover: rgba(0, 0, 0, 0.8);
-
- --link-color: var(--text-link);
- --link-color-hover: var(--text-link);
- --link-unresolved-color: var(--text-muted);
- --link-unresolved-opacity: 0.7;
-
- --tag-color: var(--text-title-h3);
- --tag-background: var(--code-background);
-
- --graph-line: var(--text-muted);
- --graph-node: var(--interactive-accent);
- --graph-node-unresolved: var(--text-muted);
- --graph-node-focused: var(--text-link);
- --graph-node-tag: var(--text-title-h3);
- --graph-node-attachment: var(--text-title-h2);
-
- /* Fonts */
- --font-interface-theme: "$ui_font";
- --font-text-theme: "$ui_font";
- --font-monospace-theme: "$monospace_font";
-}
-
-/* Headers */
-.cm-header-1, .markdown-rendered h1 { color: var(--text-title-h1); }
-.cm-header-2, .markdown-rendered h2 { color: var(--text-title-h2); }
-.cm-header-3, .markdown-rendered h3 { color: var(--text-title-h3); }
-.cm-header-4, .markdown-rendered h4 { color: var(--text-title-h4); }
-.cm-header-5, .markdown-rendered h5 { color: var(--text-title-h5); }
-.cm-header-6, .markdown-rendered h6 { color: var(--text-title-h6); }
-
-/* Code blocks */
-.markdown-rendered code {
- font-family: var(--font-monospace-theme);
- background-color: var(--code-background);
- color: var(--markup-code);
- padding: 2px 4px;
- border-radius: 3px;
-}
-
-.markdown-rendered pre {
- background-color: var(--code-background);
- border: 1px solid var(--background-modifier-border);
- border-radius: 5px;
-}
-
-.markdown-rendered pre code {
- background-color: transparent;
- color: var(--code-foreground);
-}
-
-/* Syntax highlighting */
-.cm-s-obsidian span.cm-keyword { color: var(--text-title-h1); }
-.cm-s-obsidian span.cm-string { color: var(--text-title-h2); }
-.cm-s-obsidian span.cm-number { color: var(--text-title-h3); }
-.cm-s-obsidian span.cm-comment { color: var(--text-muted); }
-.cm-s-obsidian span.cm-operator { color: var(--text-link); }
-.cm-s-obsidian span.cm-variable { color: var(--text-normal); }
-.cm-s-obsidian span.cm-def { color: var(--text-link); }
-
-/* Highlighted text */
-.markdown-rendered mark,
-.cm-s-obsidian span.cm-highlight,
-mark {
- background-color: var(--text-highlight-bg) !important;
- color: var(--code-background) !important;
-}
-
-/* Links */
-.markdown-rendered a {
- color: var(--text-link);
-}
-
-/* Blockquotes */
-.markdown-rendered blockquote {
- border-left: 4px solid var(--blockquote-border);
- padding-left: 1em;
-}
-
-/* Status bar */
-.status-bar {
- background-color: var(--code-background);
- border-top: 1px solid var(--background-modifier-border);
-}
-
-/* Active file */
-.workspace-leaf.mod-active .workspace-leaf-header-title {
- color: var(--interactive-accent);
-}
-
-.nav-file-title.is-active {
- background-color: var(--code-background);
- color: var(--interactive-accent);
-}
-
-/* Text selection */
-::selection {
- background-color: var(--text-selection);
- color: var(--text-selection-fg);
-}
-
-/* Search results */
-.search-result-file-title {
- color: var(--interactive-accent);
-}
-
-.search-result-file-match {
- background-color: var(--code-background);
- color: var(--text-normal);
- border-left: 3px solid var(--interactive-accent);
-}
-
-.search-result-file-matched-text {
- color: var(--code-background);
-}
-
-/* Tables */
-.markdown-rendered table {
- border: 1px solid var(--background-modifier-border);
-}
-
-.markdown-rendered th {
- background-color: var(--code-background);
- color: var(--text-accent);
-}
-
-.markdown-rendered td {
- border: 1px solid var(--background-modifier-border);
-}
-
-/* Callouts */
-.callout {
- border-left: 4px solid var(--interactive-accent);
- background-color: var(--code-background);
-}
-.callout * {
- color: var(--text-normal);
-}
-
-/* Modal dialogs */
-.modal {
- background-color: var(--background-primary);
- border: 2px solid var(--background-modifier-border);
-}
-
-/* Settings */
-.vertical-tab-header-group-title {
- color: var(--interactive-accent);
-}
-
-.vertical-tab-nav-item.is-active {
- background-color: var(--code-background);
- color: var(--interactive-accent);
-}
-EOF
-}
-
-# Option handling
-if [ "${1:-}" = "--reset" ]; then
- echo "♻️ Resetting Omarchy themes and registry..."
- if [ -f "$VAULTS_FILE" ] && [ -s "$VAULTS_FILE" ]; then
- while IFS= read -r vault_path || [ -n "$vault_path" ]; do
- case "$vault_path" in ""|\#*) continue ;; esac
- vault_path="${vault_path%/}"
- vault_name=$(basename "$vault_path")
- theme_dir="$vault_path/.obsidian/themes/Omarchy"
- if [ -d "$theme_dir" ]; then
- rm -rf "$theme_dir"
- echo " ✅ $vault_name (theme removed)"
- else
- echo " ℹ️ $vault_name (no theme present)"
- fi
- done <"$VAULTS_FILE"
- fi
- rm -f "$VAULTS_FILE"
- echo "✅ Registry removed"
- exit 0
-fi
-
-# Step 1: ensure registry exists (bootstrap if needed)
-ensure_vaults_file
-
-while IFS= read -r vault_path || [ -n "$vault_path" ]; do
- case "$vault_path" in "" | \#*) continue ;; esac
- vault_path="${vault_path%/}"
- vault_name=$(basename "$vault_path")
-
- # Step 2: verify path exists; log/skip gracefully if invalid
- if [ ! -d "$vault_path" ] || [ ! -d "$vault_path/.obsidian" ]; then
- echo " ❌ $vault_name (invalid entry: missing directory or .obsidian)"
- continue
- fi
-
- # Ensure theme files exist for this vault
- ensure_theme_scaffold "$vault_path"
- THEME_DIR="$vault_path/.obsidian/themes/Omarchy"
-
- # Step 3: update theme.css
- if [ -f "$CURRENT_THEME_DIR/obsidian.css" ]; then
- cp "$CURRENT_THEME_DIR/obsidian.css" "$THEME_DIR/theme.css"
- else
- extract_theme_data >"$THEME_DIR/theme.css"
- fi
-done <"$VAULTS_FILE"
+ cp "$CURRENT_THEME_DIR/obsidian.css" "$theme_dir/theme.css"
+done
diff --git a/default/themed/obsidian.css.tpl b/default/themed/obsidian.css.tpl
new file mode 100644
index 00000000..90b86244
--- /dev/null
+++ b/default/themed/obsidian.css.tpl
@@ -0,0 +1,99 @@
+/* Omarchy Theme for Obsidian */
+
+.theme-dark, .theme-light {
+ /* Core colors */
+ --background-primary: {{ background }};
+ --background-primary-alt: {{ background }};
+ --background-secondary: {{ background }};
+ --background-secondary-alt: {{ background }};
+ --text-normal: {{ foreground }};
+
+ /* Selection colors */
+ --text-selection: {{ selection_background }};
+
+ /* Border color */
+ --background-modifier-border: {{ color8 }};
+
+ /* Semantic heading colors */
+ --text-title-h1: {{ color1 }};
+ --text-title-h2: {{ color2 }};
+ --text-title-h3: {{ color3 }};
+ --text-title-h4: {{ color4 }};
+ --text-title-h5: {{ color5 }};
+ --text-title-h6: {{ color5 }};
+
+ /* Links and accents */
+ --text-link: {{ color4 }};
+ --text-accent: {{ accent }};
+ --text-accent-hover: {{ accent }};
+ --interactive-accent: {{ accent }};
+ --interactive-accent-hover: {{ accent }};
+
+ /* Muted text */
+ --text-muted: {{ color8 }};
+ --text-faint: {{ color8 }};
+
+ /* Code */
+ --code-normal: {{ color6 }};
+
+ /* Errors and success */
+ --text-error: {{ color1 }};
+ --text-error-hover: {{ color1 }};
+ --text-success: {{ color2 }};
+
+ /* Tags */
+ --tag-color: {{ color6 }};
+ --tag-background: {{ color8 }};
+
+ /* Graph */
+ --graph-line: {{ color8 }};
+ --graph-node: {{ accent }};
+ --graph-node-focused: {{ color4 }};
+ --graph-node-tag: {{ color6 }};
+ --graph-node-attachment: {{ color2 }};
+}
+
+/* Headers */
+.cm-header-1, .markdown-rendered h1 { color: var(--text-title-h1); }
+.cm-header-2, .markdown-rendered h2 { color: var(--text-title-h2); }
+.cm-header-3, .markdown-rendered h3 { color: var(--text-title-h3); }
+.cm-header-4, .markdown-rendered h4 { color: var(--text-title-h4); }
+.cm-header-5, .markdown-rendered h5 { color: var(--text-title-h5); }
+.cm-header-6, .markdown-rendered h6 { color: var(--text-title-h6); }
+
+/* Code blocks */
+.markdown-rendered code {
+ color: {{ color6 }};
+}
+
+/* Syntax highlighting */
+.cm-s-obsidian span.cm-keyword { color: {{ color1 }}; }
+.cm-s-obsidian span.cm-string { color: {{ color2 }}; }
+.cm-s-obsidian span.cm-number { color: {{ color3 }}; }
+.cm-s-obsidian span.cm-comment { color: {{ color8 }}; }
+.cm-s-obsidian span.cm-operator { color: {{ color4 }}; }
+.cm-s-obsidian span.cm-def { color: {{ color4 }}; }
+
+/* Links */
+.markdown-rendered a {
+ color: var(--text-link);
+}
+
+/* Blockquotes */
+.markdown-rendered blockquote {
+ border-left-color: {{ accent }};
+}
+
+/* Active elements */
+.workspace-leaf.mod-active .workspace-leaf-header-title {
+ color: var(--interactive-accent);
+}
+
+.nav-file-title.is-active {
+ color: var(--interactive-accent);
+}
+
+/* Search results */
+.search-result-file-title {
+ color: var(--interactive-accent);
+}