feat(theme): integrate bleu-theme repository for CLI tools
Replace hardcoded color configs with git-cloned bleu-theme repo during first boot. Applies consistent Bleu color palette to all CLI tools. Changes: - Clone https://github.com/bnema/bleu-theme.git to ~/.local/share/archup/themes/bleu - Create "current" theme symlink pattern for future theme switching - Apply themes to starship, eza, bat, fzf, btop, and yazi - Update BAT_THEME from "TwoDark" to "Bleu" - Source FZF Bleu theme in shell environment - Remove hardcoded starship.toml template (now from bleu-theme) Benefits: - Single source of truth for all CLI tool themes - Consistent color palette across shell environment - Easy theme updates via git pull - Foundation for theme switching in archup-cli
- commit
- 440f5c2df22938ceeea35794a890a126ef4963b9
- author
- bnema · · 2025-10-29 04:44 UTC
- parent
- c28bbce
- signature
- GPG Unverified
2B82207D370127A0The key is unknown
2 files · +103 -7
M install/configs/shell/envs +6 -1
| @@ -1,11 +1,16 @@ | |||
| 1 | 1 | # Bat configuration | |
| 2 | 2 | if command -v bat &> /dev/null; then | |
| 3 | - | export BAT_THEME="TwoDark" | |
| 3 | + | export BAT_THEME="Bleu" | |
| 4 | 4 | fi | |
| 5 | 5 | ||
| 6 | 6 | # FZF configuration | |
| 7 | 7 | # Note: Do NOT add --preview to FZF_DEFAULT_OPTS as it breaks non-file operations | |
| 8 | 8 | if command -v fzf &> /dev/null; then | |
| 9 | + | # Source FZF Bleu theme if available | |
| 10 | + | if [ -f "$HOME/.local/share/archup/current/theme/fzf/bleu.sh" ]; then | |
| 11 | + | source "$HOME/.local/share/archup/current/theme/fzf/bleu.sh" | |
| 12 | + | fi | |
| 13 | + | ||
| 9 | 14 | # CTRL-T file/directory picker options | |
| 10 | 15 | if command -v bat &> /dev/null; then | |
| 11 | 16 | export FZF_CTRL_T_OPTS="--preview 'bat -n --color=always {}' --preview-window right:60%:wrap" | |
| @@ -1,11 +1,16 @@ | |||||
| 1 | # Bat configuration | 1 | # Bat configuration | ||
| 2 | if command -v bat &> /dev/null; then | 2 | if command -v bat &> /dev/null; then | ||
| 3 | - | export BAT_THEME="TwoDark" | 3 | + | export BAT_THEME="Bleu" |
| 4 | fi | 4 | fi | ||
| 5 | 5 | ||||
| 6 | # FZF configuration | 6 | # FZF configuration | ||
| 7 | # Note: Do NOT add --preview to FZF_DEFAULT_OPTS as it breaks non-file operations | 7 | # Note: Do NOT add --preview to FZF_DEFAULT_OPTS as it breaks non-file operations | ||
| 8 | if command -v fzf &> /dev/null; then | 8 | if command -v fzf &> /dev/null; then | ||
| 9 | + | # Source FZF Bleu theme if available | |||
| 10 | + | if [ -f "$HOME/.local/share/archup/current/theme/fzf/bleu.sh" ]; then | |||
| 11 | + | source "$HOME/.local/share/archup/current/theme/fzf/bleu.sh" | |||
| 12 | + | fi | |||
| 13 | + | ||||
| 9 | # CTRL-T file/directory picker options | 14 | # CTRL-T file/directory picker options | ||
| 10 | if command -v bat &> /dev/null; then | 15 | if command -v bat &> /dev/null; then | ||
| 11 | export FZF_CTRL_T_OPTS="--preview 'bat -n --color=always {}' --preview-window right:60%:wrap" | 16 | export FZF_CTRL_T_OPTS="--preview 'bat -n --color=always {}' --preview-window right:60%:wrap" | ||
M internal/phases/postinstall.go +97 -6
| @@ -468,6 +468,37 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er | |||
| 468 | 468 | return fmt.Errorf("failed to set ownership: %w", err) | |
| 469 | 469 | } | |
| 470 | 470 | ||
| 471 | + | // Clone bleu-theme repository | |
| 472 | + | p.SendOutput(progressChan, "Cloning bleu-theme repository...") | |
| 473 | + | themesDir := filepath.Join(userHome, ".local", "share", "archup", "themes") | |
| 474 | + | bleuThemeDir := filepath.Join(themesDir, "bleu") | |
| 475 | + | currentDir := filepath.Join(userHome, ".local", "share", "archup", "current") | |
| 476 | + | ||
| 477 | + | cloneCmd := fmt.Sprintf("su - %s -c 'mkdir -p %s && git clone https://github.com/bnema/bleu-theme.git %s'", | |
| 478 | + | username, themesDir, bleuThemeDir) | |
| 479 | + | switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cloneCmd); { | |
| 480 | + | case err != nil: | |
| 481 | + | p.SendOutput(progressChan, "[WARN] Failed to clone bleu-theme repository") | |
| 482 | + | default: | |
| 483 | + | p.SendOutput(progressChan, "[OK] Bleu-theme repository cloned") | |
| 484 | + | } | |
| 485 | + | ||
| 486 | + | // Create current theme symlink | |
| 487 | + | symlinkCmd := fmt.Sprintf("su - %s -c 'mkdir -p %s && ln -snf %s %s/theme'", | |
| 488 | + | username, currentDir, bleuThemeDir, currentDir) | |
| 489 | + | switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, symlinkCmd); { | |
| 490 | + | case err != nil: | |
| 491 | + | p.SendOutput(progressChan, "[WARN] Failed to create theme symlink") | |
| 492 | + | } | |
| 493 | + | ||
| 494 | + | // Apply themes to CLI tools | |
| 495 | + | p.SendOutput(progressChan, "Applying themes to CLI tools...") | |
| 496 | + | switch err := p.applyThemes(progressChan, username, userHome); { | |
| 497 | + | case err != nil: | |
| 498 | + | // Non-fatal, log and continue | |
| 499 | + | p.SendOutput(progressChan, "[WARN] Some themes failed to apply") | |
| 500 | + | } | |
| 501 | + | ||
| 471 | 502 | // Configure git delta | |
| 472 | 503 | gitCommands := []string{ | |
| 473 | 504 | fmt.Sprintf("su - %s -c 'git config --global core.pager delta'", username), | |
| @@ -495,12 +526,12 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er | |||
| 495 | 526 | // copyShellTemplates copies shell config templates to user directory | |
| 496 | 527 | func (p *PostInstallPhase) copyShellTemplates(archupDefault, archupDefaultBash string) error { | |
| 497 | 528 | templates := map[string]string{ | |
| 498 | - | config.ShellConfigTemplate: filepath.Join(archupDefaultBash, "shell"), | |
| 499 | - | config.ShellInitTemplate: filepath.Join(archupDefaultBash, "init"), | |
| 500 | - | config.ShellAliasesTemplate: filepath.Join(archupDefaultBash, "aliases"), | |
| 501 | - | config.ShellEnvsTemplate: filepath.Join(archupDefaultBash, "envs"), | |
| 502 | - | config.ShellRcTemplate: filepath.Join(archupDefaultBash, "rc"), | |
| 503 | - | config.StarshipConfigTemplate: filepath.Join(archupDefault, "starship.toml"), | |
| 529 | + | config.ShellConfigTemplate: filepath.Join(archupDefaultBash, "shell"), | |
| 530 | + | config.ShellInitTemplate: filepath.Join(archupDefaultBash, "init"), | |
| 531 | + | config.ShellAliasesTemplate: filepath.Join(archupDefaultBash, "aliases"), | |
| 532 | + | config.ShellEnvsTemplate: filepath.Join(archupDefaultBash, "envs"), | |
| 533 | + | config.ShellRcTemplate: filepath.Join(archupDefaultBash, "rc"), | |
| 534 | + | // Note: starship.toml is now copied from bleu-theme in applyThemes() | |
| 504 | 535 | } | |
| 505 | 536 | ||
| 506 | 537 | for template, dest := range templates { | |
| @@ -535,6 +566,66 @@ func (p *PostInstallPhase) setShellOwnership(userHome, username string) error { | |||
| 535 | 566 | return p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, chownCmd) | |
| 536 | 567 | } | |
| 537 | 568 | ||
| 569 | + | // applyThemes applies bleu-theme to CLI tools | |
| 570 | + | func (p *PostInstallPhase) applyThemes(progressChan chan<- ProgressUpdate, username, userHome string) error { | |
| 571 | + | themeDir := filepath.Join(userHome, ".local", "share", "archup", "current", "theme") | |
| 572 | + | archupDefault := filepath.Join(userHome, ".local", "share", "archup", "default") | |
| 573 | + | ||
| 574 | + | // Starship theme - copy to archup default location | |
| 575 | + | p.SendOutput(progressChan, "Configuring starship theme...") | |
| 576 | + | starshipCmd := fmt.Sprintf("su - %s -c 'cp %s/starship/bleu.toml %s/starship.toml'", | |
| 577 | + | username, themeDir, archupDefault) | |
| 578 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, starshipCmd) | |
| 579 | + | ||
| 580 | + | // Eza theme | |
| 581 | + | p.SendOutput(progressChan, "Configuring eza theme...") | |
| 582 | + | ezaConfigDir := fmt.Sprintf("%s/.config/eza", userHome) | |
| 583 | + | ezaCommands := []string{ | |
| 584 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, ezaConfigDir), | |
| 585 | + | fmt.Sprintf("su - %s -c 'cp %s/eza/theme.yml %s/'", username, themeDir, ezaConfigDir), | |
| 586 | + | } | |
| 587 | + | for _, cmd := range ezaCommands { | |
| 588 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |
| 589 | + | } | |
| 590 | + | ||
| 591 | + | // Bat theme | |
| 592 | + | p.SendOutput(progressChan, "Configuring bat theme...") | |
| 593 | + | batThemeDir := fmt.Sprintf("%s/.config/bat/themes", userHome) | |
| 594 | + | batCommands := []string{ | |
| 595 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, batThemeDir), | |
| 596 | + | fmt.Sprintf("su - %s -c 'cp %s/bat/bleu.tmTheme %s/'", username, themeDir, batThemeDir), | |
| 597 | + | fmt.Sprintf("su - %s -c 'bat cache --build'", username), | |
| 598 | + | } | |
| 599 | + | for _, cmd := range batCommands { | |
| 600 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |
| 601 | + | } | |
| 602 | + | ||
| 603 | + | // Btop theme | |
| 604 | + | p.SendOutput(progressChan, "Configuring btop theme...") | |
| 605 | + | btopThemeDir := fmt.Sprintf("%s/.config/btop/themes", userHome) | |
| 606 | + | btopCommands := []string{ | |
| 607 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, btopThemeDir), | |
| 608 | + | fmt.Sprintf("su - %s -c 'cp %s/btop/bleu.theme %s/'", username, themeDir, btopThemeDir), | |
| 609 | + | } | |
| 610 | + | for _, cmd := range btopCommands { | |
| 611 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |
| 612 | + | } | |
| 613 | + | ||
| 614 | + | // Yazi theme | |
| 615 | + | p.SendOutput(progressChan, "Configuring yazi theme...") | |
| 616 | + | yaziFlavorDir := fmt.Sprintf("%s/.config/yazi/flavors/bleu", userHome) | |
| 617 | + | yaziCommands := []string{ | |
| 618 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, yaziFlavorDir), | |
| 619 | + | fmt.Sprintf("su - %s -c 'cp %s/yazi/bleu.toml %s/flavor.toml'", username, themeDir, yaziFlavorDir), | |
| 620 | + | } | |
| 621 | + | for _, cmd := range yaziCommands { | |
| 622 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |
| 623 | + | } | |
| 624 | + | ||
| 625 | + | p.SendOutput(progressChan, "[OK] CLI themes configured") | |
| 626 | + | return nil | |
| 627 | + | } | |
| 628 | + | ||
| 538 | 629 | // verifyInstallation performs comprehensive verification | |
| 539 | 630 | func (p *PostInstallPhase) verifyInstallation(progressChan chan<- ProgressUpdate) error { | |
| 540 | 631 | p.SendOutput(progressChan, "Verifying installation components...") | |
| @@ -468,6 +468,37 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er | |||||
| 468 | return fmt.Errorf("failed to set ownership: %w", err) | 468 | return fmt.Errorf("failed to set ownership: %w", err) | ||
| 469 | } | 469 | } | ||
| 470 | 470 | ||||
| 471 | + | // Clone bleu-theme repository | |||
| 472 | + | p.SendOutput(progressChan, "Cloning bleu-theme repository...") | |||
| 473 | + | themesDir := filepath.Join(userHome, ".local", "share", "archup", "themes") | |||
| 474 | + | bleuThemeDir := filepath.Join(themesDir, "bleu") | |||
| 475 | + | currentDir := filepath.Join(userHome, ".local", "share", "archup", "current") | |||
| 476 | + | ||||
| 477 | + | cloneCmd := fmt.Sprintf("su - %s -c 'mkdir -p %s && git clone https://github.com/bnema/bleu-theme.git %s'", | |||
| 478 | + | username, themesDir, bleuThemeDir) | |||
| 479 | + | switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cloneCmd); { | |||
| 480 | + | case err != nil: | |||
| 481 | + | p.SendOutput(progressChan, "[WARN] Failed to clone bleu-theme repository") | |||
| 482 | + | default: | |||
| 483 | + | p.SendOutput(progressChan, "[OK] Bleu-theme repository cloned") | |||
| 484 | + | } | |||
| 485 | + | ||||
| 486 | + | // Create current theme symlink | |||
| 487 | + | symlinkCmd := fmt.Sprintf("su - %s -c 'mkdir -p %s && ln -snf %s %s/theme'", | |||
| 488 | + | username, currentDir, bleuThemeDir, currentDir) | |||
| 489 | + | switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, symlinkCmd); { | |||
| 490 | + | case err != nil: | |||
| 491 | + | p.SendOutput(progressChan, "[WARN] Failed to create theme symlink") | |||
| 492 | + | } | |||
| 493 | + | ||||
| 494 | + | // Apply themes to CLI tools | |||
| 495 | + | p.SendOutput(progressChan, "Applying themes to CLI tools...") | |||
| 496 | + | switch err := p.applyThemes(progressChan, username, userHome); { | |||
| 497 | + | case err != nil: | |||
| 498 | + | // Non-fatal, log and continue | |||
| 499 | + | p.SendOutput(progressChan, "[WARN] Some themes failed to apply") | |||
| 500 | + | } | |||
| 501 | + | ||||
| 471 | // Configure git delta | 502 | // Configure git delta | ||
| 472 | gitCommands := []string{ | 503 | gitCommands := []string{ | ||
| 473 | fmt.Sprintf("su - %s -c 'git config --global core.pager delta'", username), | 504 | fmt.Sprintf("su - %s -c 'git config --global core.pager delta'", username), | ||
| @@ -495,12 +526,12 @@ func (p *PostInstallPhase) configureShell(progressChan chan<- ProgressUpdate) er | |||||
| 495 | // copyShellTemplates copies shell config templates to user directory | 526 | // copyShellTemplates copies shell config templates to user directory | ||
| 496 | func (p *PostInstallPhase) copyShellTemplates(archupDefault, archupDefaultBash string) error { | 527 | func (p *PostInstallPhase) copyShellTemplates(archupDefault, archupDefaultBash string) error { | ||
| 497 | templates := map[string]string{ | 528 | templates := map[string]string{ | ||
| 498 | - | config.ShellConfigTemplate: filepath.Join(archupDefaultBash, "shell"), | 529 | + | config.ShellConfigTemplate: filepath.Join(archupDefaultBash, "shell"), |
| 499 | - | config.ShellInitTemplate: filepath.Join(archupDefaultBash, "init"), | 530 | + | config.ShellInitTemplate: filepath.Join(archupDefaultBash, "init"), |
| 500 | - | config.ShellAliasesTemplate: filepath.Join(archupDefaultBash, "aliases"), | 531 | + | config.ShellAliasesTemplate: filepath.Join(archupDefaultBash, "aliases"), |
| 501 | - | config.ShellEnvsTemplate: filepath.Join(archupDefaultBash, "envs"), | 532 | + | config.ShellEnvsTemplate: filepath.Join(archupDefaultBash, "envs"), |
| 502 | - | config.ShellRcTemplate: filepath.Join(archupDefaultBash, "rc"), | 533 | + | config.ShellRcTemplate: filepath.Join(archupDefaultBash, "rc"), |
| 503 | - | config.StarshipConfigTemplate: filepath.Join(archupDefault, "starship.toml"), | 534 | + | // Note: starship.toml is now copied from bleu-theme in applyThemes() |
| 504 | } | 535 | } | ||
| 505 | 536 | ||||
| 506 | for template, dest := range templates { | 537 | for template, dest := range templates { | ||
| @@ -535,6 +566,66 @@ func (p *PostInstallPhase) setShellOwnership(userHome, username string) error { | |||||
| 535 | return p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, chownCmd) | 566 | return p.chrExec.ChrootExec(p.logger.LogPath(),config.PathMnt, chownCmd) | ||
| 536 | } | 567 | } | ||
| 537 | 568 | ||||
| 569 | + | // applyThemes applies bleu-theme to CLI tools | |||
| 570 | + | func (p *PostInstallPhase) applyThemes(progressChan chan<- ProgressUpdate, username, userHome string) error { | |||
| 571 | + | themeDir := filepath.Join(userHome, ".local", "share", "archup", "current", "theme") | |||
| 572 | + | archupDefault := filepath.Join(userHome, ".local", "share", "archup", "default") | |||
| 573 | + | ||||
| 574 | + | // Starship theme - copy to archup default location | |||
| 575 | + | p.SendOutput(progressChan, "Configuring starship theme...") | |||
| 576 | + | starshipCmd := fmt.Sprintf("su - %s -c 'cp %s/starship/bleu.toml %s/starship.toml'", | |||
| 577 | + | username, themeDir, archupDefault) | |||
| 578 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, starshipCmd) | |||
| 579 | + | ||||
| 580 | + | // Eza theme | |||
| 581 | + | p.SendOutput(progressChan, "Configuring eza theme...") | |||
| 582 | + | ezaConfigDir := fmt.Sprintf("%s/.config/eza", userHome) | |||
| 583 | + | ezaCommands := []string{ | |||
| 584 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, ezaConfigDir), | |||
| 585 | + | fmt.Sprintf("su - %s -c 'cp %s/eza/theme.yml %s/'", username, themeDir, ezaConfigDir), | |||
| 586 | + | } | |||
| 587 | + | for _, cmd := range ezaCommands { | |||
| 588 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |||
| 589 | + | } | |||
| 590 | + | ||||
| 591 | + | // Bat theme | |||
| 592 | + | p.SendOutput(progressChan, "Configuring bat theme...") | |||
| 593 | + | batThemeDir := fmt.Sprintf("%s/.config/bat/themes", userHome) | |||
| 594 | + | batCommands := []string{ | |||
| 595 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, batThemeDir), | |||
| 596 | + | fmt.Sprintf("su - %s -c 'cp %s/bat/bleu.tmTheme %s/'", username, themeDir, batThemeDir), | |||
| 597 | + | fmt.Sprintf("su - %s -c 'bat cache --build'", username), | |||
| 598 | + | } | |||
| 599 | + | for _, cmd := range batCommands { | |||
| 600 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |||
| 601 | + | } | |||
| 602 | + | ||||
| 603 | + | // Btop theme | |||
| 604 | + | p.SendOutput(progressChan, "Configuring btop theme...") | |||
| 605 | + | btopThemeDir := fmt.Sprintf("%s/.config/btop/themes", userHome) | |||
| 606 | + | btopCommands := []string{ | |||
| 607 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, btopThemeDir), | |||
| 608 | + | fmt.Sprintf("su - %s -c 'cp %s/btop/bleu.theme %s/'", username, themeDir, btopThemeDir), | |||
| 609 | + | } | |||
| 610 | + | for _, cmd := range btopCommands { | |||
| 611 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |||
| 612 | + | } | |||
| 613 | + | ||||
| 614 | + | // Yazi theme | |||
| 615 | + | p.SendOutput(progressChan, "Configuring yazi theme...") | |||
| 616 | + | yaziFlavorDir := fmt.Sprintf("%s/.config/yazi/flavors/bleu", userHome) | |||
| 617 | + | yaziCommands := []string{ | |||
| 618 | + | fmt.Sprintf("su - %s -c 'mkdir -p %s'", username, yaziFlavorDir), | |||
| 619 | + | fmt.Sprintf("su - %s -c 'cp %s/yazi/bleu.toml %s/flavor.toml'", username, themeDir, yaziFlavorDir), | |||
| 620 | + | } | |||
| 621 | + | for _, cmd := range yaziCommands { | |||
| 622 | + | p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cmd) | |||
| 623 | + | } | |||
| 624 | + | ||||
| 625 | + | p.SendOutput(progressChan, "[OK] CLI themes configured") | |||
| 626 | + | return nil | |||
| 627 | + | } | |||
| 628 | + | ||||
| 538 | // verifyInstallation performs comprehensive verification | 629 | // verifyInstallation performs comprehensive verification | ||
| 539 | func (p *PostInstallPhase) verifyInstallation(progressChan chan<- ProgressUpdate) error { | 630 | func (p *PostInstallPhase) verifyInstallation(progressChan chan<- ProgressUpdate) error { | ||
| 540 | p.SendOutput(progressChan, "Verifying installation components...") | 631 | p.SendOutput(progressChan, "Verifying installation components...") | ||