diff --git a/.bashrc b/.bashrc index df13140..4eca382 100644 --- a/.bashrc +++ b/.bashrc @@ -28,6 +28,13 @@ shopt -s nocaseglob # ghostty if [[ -n ${GHOSTTY_RESOURCES_DIR} ]]; then builtin source "${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash" + + # Auto-switch Ghostty theme based on time of day + if [[ -x "${HOME}/.dotfiles/bin/set-ghostty-theme" ]]; then + "${HOME}/.dotfiles/bin/set-ghostty-theme" 2>/dev/null || true + elif [[ -x "$(dirname "${BASH_SOURCE[0]}")/bin/set-ghostty-theme" ]]; then + "$(dirname "${BASH_SOURCE[0]}")/bin/set-ghostty-theme" 2>/dev/null || true + fi fi # starship @@ -144,6 +151,13 @@ fi # Auto start|attach zellij session if command -v zellij &>/dev/null; then + # Auto-switch Zellij theme based on time of day + if [[ -x "${HOME}/.dotfiles/bin/set-zellij-theme" ]]; then + "${HOME}/.dotfiles/bin/set-zellij-theme" 2>/dev/null || true + elif [[ -x "$(dirname "${BASH_SOURCE[0]}")/bin/set-zellij-theme" ]]; then + "$(dirname "${BASH_SOURCE[0]}")/bin/set-zellij-theme" 2>/dev/null || true + fi + if [ -z "$ZELLIJ" ]; then zellij attach -c 'BDS 🐑' fi diff --git a/.config/ghostty/config b/.config/ghostty/config index c76aebb..87e254e 100644 --- a/.config/ghostty/config +++ b/.config/ghostty/config @@ -1,2 +1,2 @@ -theme = "dracula" +theme = "GitHub-Light-High-Contrast" window-padding-x = 2,4 diff --git a/.config/nvim/lua/config/autocmds.lua b/.config/nvim/lua/config/autocmds.lua index b511e48..6ebbb0c 100644 --- a/.config/nvim/lua/config/autocmds.lua +++ b/.config/nvim/lua/config/autocmds.lua @@ -110,3 +110,63 @@ autocmd("FileType", { end, desc = "Disable backups for crontab editing", }) + +-- =================================================================== +-- TIME-BASED THEME SWITCHING +-- =================================================================== + +-- Auto-switch colorscheme based on time of day +local function switch_theme_by_time() + -- Function to get time-based colorscheme + local function get_time_based_colorscheme() + -- Try to use our theme-mode script if available + local theme_mode_paths = { + vim.fn.expand("~/.dotfiles/bin/theme-mode"), + vim.fn.expand("~/.config/nvim/../../bin/theme-mode"), + } + + for _, path in ipairs(theme_mode_paths) do + if vim.fn.executable(path) == 1 then + local handle = io.popen(path .. " 2>/dev/null") + if handle then + local mode = handle:read("*a"):gsub("%s+", "") + handle:close() + + if mode == "light" then + return "tokyonight-day" + else + return "tokyonight-night" + end + end + end + end + + -- Fallback: use system time directly + local hour = tonumber(os.date("%H")) + if hour >= 7 and hour < 19 then + return "tokyonight-day" + else + return "tokyonight-night" + end + end + + local new_colorscheme = get_time_based_colorscheme() + if vim.g.colors_name ~= new_colorscheme then + vim.cmd.colorscheme(new_colorscheme) + end +end + +-- Create augroup for theme switching +local themeGroup = augroup("TimeBasedTheme", { clear = true }) + +-- Switch theme on entering Neovim +autocmd("VimEnter", { + group = themeGroup, + callback = switch_theme_by_time, + desc = "Switch colorscheme based on time when entering Neovim", +}) + +-- Optionally switch theme periodically (every 30 minutes) +-- Uncomment the following to enable periodic theme switching: +-- local theme_timer = vim.loop.new_timer() +-- theme_timer:start(0, 30 * 60 * 1000, vim.schedule_wrap(switch_theme_by_time)) diff --git a/.config/nvim/lua/config/lazy.lua b/.config/nvim/lua/config/lazy.lua index f67a3a4..f2de297 100644 --- a/.config/nvim/lua/config/lazy.lua +++ b/.config/nvim/lua/config/lazy.lua @@ -45,7 +45,7 @@ require("lazy").setup({ version = false, -- always use the latest git commit -- version = "*", -- try installing the latest stable version for plugins that support semver }, - install = { colorscheme = { "dracula", "tokyonight", "habamax" } }, + install = { colorscheme = { "tokyonight-night", "tokyonight-day", "tokyonight", "habamax" } }, checker = { enabled = true }, -- automatically check for plugin updates performance = { rtp = { diff --git a/.config/nvim/lua/plugins/colorscheme.lua b/.config/nvim/lua/plugins/colorscheme.lua index 7f4847f..ad5270b 100644 --- a/.config/nvim/lua/plugins/colorscheme.lua +++ b/.config/nvim/lua/plugins/colorscheme.lua @@ -1,26 +1,86 @@ --- Dracula colorscheme configuration +-- Colorscheme configuration with automatic light/dark switching return { + -- Tokyo Night colorscheme (both light and dark modes) { - "Mofiqul/dracula.nvim", - lazy = false, -- Load immediately (colorscheme should be available early) - priority = 1000, -- High priority to load before other plugins + "folke/tokyonight.nvim", + lazy = false, + priority = 1000, config = function() - require("dracula").setup({ - -- Dracula theme customization - colors = {}, -- Use default dracula colors - show_end_of_buffer = true, -- Show '~' characters after buffer end - transparent_bg = false, -- Use dracula background color - lualine_bg_color = "#44475a", -- Custom lualine background - italic_comment = true, -- Italicize comments + require("tokyonight").setup({ + style = "night", -- The theme comes in three styles, `storm`, `moon`, a darker variant `night` and `day` + light_style = "day", -- The theme is used when the background is set to light + transparent = false, -- Enable this to disable setting the background color + terminal_colors = true, -- Configure the colors used when opening a `:terminal` in Neovim + styles = { + comments = { italic = true }, + keywords = { italic = true }, + functions = {}, + variables = {}, + -- Background styles. Can be "dark", "transparent" or "normal" + sidebars = "dark", -- style for sidebars, see below + floats = "dark", -- style for floating windows + }, + sidebars = { "qf", "help" }, -- Set a darker background on sidebar-like windows + day_brightness = 0.3, -- Adjusts the brightness of the colors of the **Day** style. Number between 0 and 1, from dull to vibrant colors + hide_inactive_statusline = false, -- Enabling this option, will hide inactive statuslines and replace them with a thin border instead + dim_inactive = false, -- dims inactive windows + lualine_bold = false, -- When `true`, section headers in the lualine theme will be bold }) end, }, - -- Configure LazyVim to use dracula as default colorscheme + -- Configure LazyVim with automatic theme detection { "LazyVim/LazyVim", - opts = { - colorscheme = "dracula", - }, + opts = function() + -- Function to detect and set theme based on time + local function get_time_based_colorscheme() + -- Try to use our theme-mode script if available + local theme_mode_paths = { + vim.fn.expand("~/.dotfiles/bin/theme-mode"), + vim.fn.expand("~/.config/nvim/../../bin/theme-mode"), + } + + for _, path in ipairs(theme_mode_paths) do + if vim.fn.executable(path) == 1 then + local handle = io.popen(path .. " nvim-light 2>/dev/null") + if handle then + local light_theme = handle:read("*a"):gsub("%s+", "") + handle:close() + + handle = io.popen(path .. " nvim-dark 2>/dev/null") + if handle then + local dark_theme = handle:read("*a"):gsub("%s+", "") + handle:close() + + handle = io.popen(path .. " 2>/dev/null") + if handle then + local mode = handle:read("*a"):gsub("%s+", "") + handle:close() + + if mode == "light" then + return "tokyonight-day" + else + return "tokyonight-night" + end + end + end + end + end + end + + -- Fallback: use system time directly + local hour = tonumber(os.date("%H")) + if hour >= 7 and hour < 19 then + return "tokyonight-day" + else + return "tokyonight-night" + end + end + + return { + colorscheme = get_time_based_colorscheme(), + } + end, }, } diff --git a/.config/zellij/config.kdl b/.config/zellij/config.kdl index fda9397..d39842d 100644 --- a/.config/zellij/config.kdl +++ b/.config/zellij/config.kdl @@ -60,5 +60,5 @@ keybinds { } pane_frames false -theme "dracula" +theme "default" mouse_mode true diff --git a/README.md b/README.md index e85182e..8308421 100644 --- a/README.md +++ b/README.md @@ -64,3 +64,51 @@ A few other notes: * Ensure that `~/.bash_login` does not exist. See also https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html + +## Automatic Light/Dark Mode Switching + +This dotfiles setup includes automatic light/dark mode switching for both Ghostty terminal and Neovim based on the time of day. + +### How it works + +- **Light Mode**: Active from 7:00 AM to 6:59 PM +- **Dark Mode**: Active from 7:00 PM to 6:59 AM +- **Ghostty**: Switches between `github-light` and `dracula` themes +- **Neovim**: Switches between `github_light_high_contrast` and `github_dark_high_contrast` colorschemes + +### Components + +1. **`bin/theme-mode`**: Core script that detects current time and returns appropriate theme +2. **`bin/set-ghostty-theme`**: Updates Ghostty configuration with time-appropriate theme +3. **Bash Integration**: Automatically runs theme switching on new shell launches +4. **Neovim Integration**: Automatically sets colorscheme when Neovim starts + +### Manual Theme Control + +You can manually test or force theme changes: + +```bash +# Check current theme mode +~/.dotfiles/bin/theme-mode + +# Manually switch Ghostty theme +~/.dotfiles/bin/set-ghostty-theme + +# Get theme names for different tools +~/.dotfiles/bin/theme-mode ghostty-light # Returns: github-light +~/.dotfiles/bin/theme-mode ghostty-dark # Returns: dracula +~/.dotfiles/bin/theme-mode nvim-light # Returns: github_light_high_contrast +~/.dotfiles/bin/theme-mode nvim-dark # Returns: dracula +``` + +### Requirements + +- **Ghostty**: Must have `github-light` and `dracula` themes available +- **Neovim**: Requires the github-nvim-theme plugin (installed automatically via LazyVim) +- **Portability**: Works on Linux and macOS systems + +The switching happens automatically on: +- New terminal/shell sessions (Ghostty) +- Neovim startup (colorscheme selection) + +For troubleshooting, check that the scripts in `bin/` are executable and that your system's `date` command works correctly. diff --git a/bin/set-ghostty-theme b/bin/set-ghostty-theme new file mode 100755 index 0000000..250e462 --- /dev/null +++ b/bin/set-ghostty-theme @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# set-ghostty-theme - Set Ghostty theme based on current time +# +# This script updates the Ghostty configuration to use light or dark theme +# based on the current hour of the day. +# + +set -euo pipefail + +# Get the directory where this script lives to find theme-mode +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +THEME_MODE_SCRIPT="${SCRIPT_DIR}/theme-mode" + +# Configuration file path - check both the dotfiles repo and installed location +DOTFILES_GHOSTTY_CONFIG="$(dirname "$SCRIPT_DIR")/.config/ghostty/config" +HOME_GHOSTTY_CONFIG="${HOME}/.config/ghostty/config" + +# Use the dotfiles repo config if it exists, otherwise use the home config +if [[ -f "$DOTFILES_GHOSTTY_CONFIG" ]]; then + GHOSTTY_CONFIG="$DOTFILES_GHOSTTY_CONFIG" +else + GHOSTTY_CONFIG="$HOME_GHOSTTY_CONFIG" +fi + +# Ensure the theme-mode script exists +if [[ ! -x "$THEME_MODE_SCRIPT" ]]; then + echo "Error: theme-mode script not found or not executable at $THEME_MODE_SCRIPT" >&2 + exit 1 +fi + +# Get current theme mode and corresponding Ghostty theme +MODE=$("$THEME_MODE_SCRIPT") +case "$MODE" in + "light") + THEME=$("$THEME_MODE_SCRIPT" ghostty-light) + ;; + "dark") + THEME=$("$THEME_MODE_SCRIPT" ghostty-dark) + ;; + *) + echo "Error: Unknown theme mode: $MODE" >&2 + exit 1 + ;; +esac + +# Update or create the Ghostty config file +if [[ -f "$GHOSTTY_CONFIG" ]]; then + # Create a temporary file to ensure atomic update + TEMP_CONFIG=$(mktemp) + + if grep -q "^theme = " "$GHOSTTY_CONFIG"; then + # Replace existing theme line, preserving other lines + sed "s/^theme = .*/theme = \"$THEME\"/" "$GHOSTTY_CONFIG" > "$TEMP_CONFIG" + else + # Append theme line if not found + cp "$GHOSTTY_CONFIG" "$TEMP_CONFIG" + echo "theme = \"$THEME\"" >> "$TEMP_CONFIG" + fi + + # Replace original with updated version + mv "$TEMP_CONFIG" "$GHOSTTY_CONFIG" +else + # Create config file with theme + mkdir -p "$(dirname "$GHOSTTY_CONFIG")" + echo "theme = \"$THEME\"" > "$GHOSTTY_CONFIG" +fi + +# Optional: print what we did (useful for debugging) +if [[ "${VERBOSE:-}" == "1" ]]; then + echo "Set Ghostty theme to '$THEME' (mode: $MODE)" +fi \ No newline at end of file diff --git a/bin/set-zellij-theme b/bin/set-zellij-theme new file mode 100755 index 0000000..ae25dbb --- /dev/null +++ b/bin/set-zellij-theme @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# set-zellij-theme - Set Zellij theme based on current time +# +# This script updates the Zellij configuration to use light or dark theme +# based on the current hour of the day. +# + +set -euo pipefail + +# Get the directory where this script lives to find theme-mode +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +THEME_MODE_SCRIPT="${SCRIPT_DIR}/theme-mode" + +# Configuration file path - check both the dotfiles repo and installed location +DOTFILES_ZELLIJ_CONFIG="$(dirname "$SCRIPT_DIR")/.config/zellij/config.kdl" +HOME_ZELLIJ_CONFIG="${HOME}/.config/zellij/config.kdl" + +# Use the dotfiles repo config if it exists, otherwise use the home config +if [[ -f "$DOTFILES_ZELLIJ_CONFIG" ]]; then + ZELLIJ_CONFIG="$DOTFILES_ZELLIJ_CONFIG" +else + ZELLIJ_CONFIG="$HOME_ZELLIJ_CONFIG" +fi + +# Ensure the theme-mode script exists +if [[ ! -x "$THEME_MODE_SCRIPT" ]]; then + echo "Error: theme-mode script not found or not executable at $THEME_MODE_SCRIPT" >&2 + exit 1 +fi + +# Get current theme mode and corresponding Zellij theme +MODE=$("$THEME_MODE_SCRIPT") +case "$MODE" in + "light") + THEME=$("$THEME_MODE_SCRIPT" zellij-light) + ;; + "dark") + THEME=$("$THEME_MODE_SCRIPT" zellij-dark) + ;; + *) + echo "Error: Unknown theme mode: $MODE" >&2 + exit 1 + ;; +esac + +# Update or create the Zellij config file +if [[ -f "$ZELLIJ_CONFIG" ]]; then + # Create a temporary file to ensure atomic update + TEMP_CONFIG=$(mktemp) + + if grep -q "^theme " "$ZELLIJ_CONFIG"; then + # Replace existing theme line, preserving other lines + sed "s/^theme .*/theme \"$THEME\"/" "$ZELLIJ_CONFIG" > "$TEMP_CONFIG" + else + # Append theme line if not found + cp "$ZELLIJ_CONFIG" "$TEMP_CONFIG" + echo "theme \"$THEME\"" >> "$TEMP_CONFIG" + fi + + # Replace original with updated version + mv "$TEMP_CONFIG" "$ZELLIJ_CONFIG" +else + # Create config file with theme + mkdir -p "$(dirname "$ZELLIJ_CONFIG")" + echo "theme \"$THEME\"" > "$ZELLIJ_CONFIG" +fi + +# Optional: print what we did (useful for debugging) +if [[ "${VERBOSE:-}" == "1" ]]; then + echo "Set Zellij theme to '$THEME' (mode: $MODE)" +fi \ No newline at end of file diff --git a/bin/theme-mode b/bin/theme-mode new file mode 100755 index 0000000..6e0a031 --- /dev/null +++ b/bin/theme-mode @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# +# theme-mode - Detect if current time should use light or dark theme +# +# Returns "light" for hours 7-18 (7:00 AM to 6:59 PM), "dark" otherwise +# This provides a natural light mode during typical daylight hours. +# + +set -euo pipefail + +get_theme_mode() { + local hour + hour=$(date +%H) + + # Convert to decimal to handle leading zeros + hour=$((10#$hour)) + + # Light mode from 7:00 AM to 6:59 PM (hours 7-18) + if [[ $hour -ge 7 && $hour -lt 19 ]]; then + echo "light" + else + echo "dark" + fi +} + +# Support different output formats +case "${1:-mode}" in + "mode"|"") + get_theme_mode + ;; + "ghostty-light") + echo "GitHub-Light-High-Contrast" + ;; + "ghostty-dark") + echo "dracula" + ;; + "nvim-light") + echo "tokyonight-day" + ;; + "nvim-dark") + echo "tokyonight-night" + ;; + "zellij-light") + echo "default" + ;; + "zellij-dark") + echo "dracula" + ;; + *) + echo "Usage: $0 [mode|ghostty-light|ghostty-dark|nvim-light|nvim-dark|zellij-light|zellij-dark]" >&2 + exit 1 + ;; +esac \ No newline at end of file