From 9dd1c319e05a5c83ebc13daaa80d635450dacb36 Mon Sep 17 00:00:00 2001 From: Jonas H Date: Fri, 24 Apr 2026 14:20:32 +0200 Subject: [PATCH] nvim light theme --- nvim/.config/nvim/init.lua | 4 +- nvim/.config/nvim/lua/bearded-arc/init.lua | 266 +++++++++++++++ nvim/.config/nvim/lua/bearded-arc/watcher.lua | 50 +++ nvim/.config/nvim/lua/configs/lualine.lua | 323 ++++++++++-------- 4 files changed, 494 insertions(+), 149 deletions(-) create mode 100644 nvim/.config/nvim/lua/bearded-arc/init.lua create mode 100644 nvim/.config/nvim/lua/bearded-arc/watcher.lua diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index bc0d526..8d16ade 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -17,8 +17,8 @@ require("lazy").setup({ { import = "plugins" }, }, lazy_config) --- load theme -vim.cmd.colorscheme("bearded-arc") +-- load theme (watches ~/.config/theme-state for dark/light toggle) +require("bearded-arc.watcher").setup() -- Load standalone config (migrated from NvChad) require "options" diff --git a/nvim/.config/nvim/lua/bearded-arc/init.lua b/nvim/.config/nvim/lua/bearded-arc/init.lua new file mode 100644 index 0000000..93ab8df --- /dev/null +++ b/nvim/.config/nvim/lua/bearded-arc/init.lua @@ -0,0 +1,266 @@ +-- Bearded Arc highlight engine +-- Shared logic for dark and light variants + +local M = {} + +-- Helper function to set highlights +local function hi(group, opts) + local cmd = "hi " .. group + if opts.fg then cmd = cmd .. " guifg=" .. opts.fg end + if opts.bg then cmd = cmd .. " guibg=" .. opts.bg end + if opts.sp then cmd = cmd .. " guisp=" .. opts.sp end + if opts.style then cmd = cmd .. " gui=" .. opts.style end + vim.cmd(cmd) +end + +function M.apply(base_30, base_16) + -- === UI ELEMENTS === + + hi("LineNr", { fg = base_30.grey }) + hi("CursorLineNr", { fg = base_30.white }) + hi("SignColumn", { fg = base_16.base03 }) + hi("FoldColumn", { fg = base_30.grey, bg = base_16.base00 }) + hi("Folded", { fg = base_30.light_grey, bg = base_16.base01 }) + + hi("Normal", { fg = base_16.base05, bg = base_16.base00 }) + hi("NormalFloat", { bg = base_30.darker_black }) + hi("FloatBorder", { fg = base_30.blue }) + hi("FloatTitle", { fg = base_30.white, bg = base_30.grey }) + + hi("Cursor", { fg = base_16.base00, bg = base_16.base05 }) + hi("CursorLine", { bg = base_30.black2 }) + hi("CursorColumn", { bg = base_16.base01 }) + hi("ColorColumn", { bg = base_16.base01 }) + + hi("Visual", { bg = base_30.one_bg2 }) + hi("VisualNOS", { bg = base_30.one_bg2 }) + + hi("Search", { fg = base_16.base00, bg = base_16.base0A }) + hi("IncSearch", { fg = base_16.base01, bg = base_16.base09 }) + hi("Substitute", { fg = base_16.base01, bg = base_16.base0A }) + + hi("WinSeparator", { fg = base_30.line }) + hi("WinBar", { bg = base_30.statusline_bg }) + hi("WinBarNC", { bg = base_30.statusline_bg }) + + hi("Pmenu", { bg = base_30.one_bg }) + hi("PmenuSbar", { bg = base_30.one_bg }) + hi("PmenuSel", { bg = base_30.pmenu_bg, fg = base_30.black }) + hi("PmenuThumb", { bg = base_30.grey }) + + hi("StatusLine", { bg = base_30.statusline_bg }) + hi("StatusLineNC", { bg = base_30.statusline_bg }) + hi("TabLine", { fg = base_30.light_grey, bg = base_30.black2 }) + hi("TabLineSel", { fg = base_30.white, bg = base_30.black }) + hi("TabLineFill", { bg = base_30.black2 }) + + hi("ErrorMsg", { fg = base_16.base08, bg = base_16.base00 }) + hi("WarningMsg", { fg = base_16.base0A }) + hi("MoreMsg", { fg = base_16.base0B }) + hi("ModeMsg", { fg = base_16.base0B }) + hi("Question", { fg = base_16.base0D }) + + hi("MatchParen", { bg = base_30.grey, fg = base_30.white }) + hi("NonText", { fg = base_16.base03 }) + hi("SpecialKey", { fg = base_16.base03 }) + hi("Conceal", { fg = base_16.base0D, bg = base_16.base00 }) + hi("Directory", { fg = base_16.base0D }) + hi("Title", { fg = base_16.base0D }) + + -- === SYNTAX HIGHLIGHTING === + + hi("Comment", { fg = base_30.grey_fg, style = "italic" }) + + hi("Constant", { fg = base_16.base09 }) + hi("String", { fg = base_16.base0B }) + hi("Character", { fg = base_16.base08 }) + hi("Number", { fg = base_16.base09 }) + hi("Boolean", { fg = base_16.base09 }) + hi("Float", { fg = base_16.base09 }) + + hi("Identifier", { fg = base_16.base08 }) + hi("Function", { fg = base_16.base0D }) + + hi("Statement", { fg = base_16.base0E }) + hi("Conditional", { fg = base_16.base0E }) + hi("Repeat", { fg = base_16.base0E }) + hi("Label", { fg = base_16.base0A }) + hi("Operator", { fg = base_16.base05 }) + hi("Keyword", { fg = base_16.base0E }) + hi("Exception", { fg = base_16.base08 }) + + hi("PreProc", { fg = base_16.base0A }) + hi("Include", { fg = base_16.base0D }) + hi("Define", { fg = base_16.base0E }) + hi("Macro", { fg = base_16.base08 }) + hi("PreCondit", { fg = base_16.base0A }) + + hi("Type", { fg = base_16.base0A }) + hi("StorageClass", { fg = base_16.base0A }) + hi("Structure", { fg = base_16.base0E }) + hi("Typedef", { fg = base_16.base0A }) + + hi("Special", { fg = base_16.base0C }) + hi("SpecialChar", { fg = base_16.base0F }) + hi("Tag", { fg = base_16.base0A }) + hi("Delimiter", { fg = base_16.base0F }) + hi("SpecialComment", { fg = base_16.base0C }) + hi("Debug", { fg = base_16.base08 }) + + hi("Error", { fg = base_16.base00, bg = base_16.base08 }) + hi("Todo", { fg = base_16.base0A, bg = base_16.base01 }) + + hi("Underlined", { fg = base_16.base0B, style = "underline" }) + hi("Ignore", { fg = base_16.base0C }) + + -- === DIFF === + + hi("DiffAdd", { fg = base_16.base0B, bg = base_16.base00 }) + hi("DiffChange", { fg = base_16.base0E, bg = base_16.base00 }) + hi("DiffDelete", { fg = base_16.base08, bg = base_16.base00 }) + hi("DiffText", { fg = base_16.base0D, bg = base_16.base01 }) + + hi("Added", { fg = base_30.green }) + hi("Changed", { fg = base_30.yellow }) + hi("Removed", { fg = base_30.red }) + + -- === GIT SIGNS === + + hi("GitSignsAdd", { fg = base_30.green }) + hi("GitSignsChange", { fg = base_30.yellow }) + hi("GitSignsDelete", { fg = base_30.red }) + + -- === LSP DIAGNOSTICS === + + hi("DiagnosticError", { fg = base_30.red }) + hi("DiagnosticWarn", { fg = base_30.yellow }) + hi("DiagnosticInfo", { fg = base_30.green }) + hi("DiagnosticHint", { fg = base_30.purple }) + + hi("DiagnosticUnderlineError", { sp = base_30.red, style = "underline" }) + hi("DiagnosticUnderlineWarn", { sp = base_30.yellow, style = "underline" }) + hi("DiagnosticUnderlineInfo", { sp = base_30.green, style = "underline" }) + hi("DiagnosticUnderlineHint", { sp = base_30.purple, style = "underline" }) + + hi("LspReferenceText", { bg = base_30.one_bg3 }) + hi("LspReferenceRead", { bg = base_30.one_bg3 }) + hi("LspReferenceWrite", { bg = base_30.one_bg3 }) + + hi("LspInlayHint", { fg = base_30.light_grey, bg = base_30.black2 }) + hi("LspSignatureActiveParameter", { fg = base_30.black, bg = base_30.green }) + + -- === TELESCOPE === + + hi("TelescopeBorder", { fg = base_30.grey, bg = base_30.darker_black }) + hi("TelescopePromptBorder", { fg = base_30.grey, bg = base_30.darker_black }) + hi("TelescopePromptNormal", { fg = base_16.base05, bg = base_30.darker_black }) + hi("TelescopeResultsBorder", { fg = base_30.grey, bg = base_30.darker_black }) + hi("TelescopeResultsNormal", { bg = base_30.darker_black }) + hi("TelescopePreviewBorder", { fg = base_30.grey, bg = base_30.darker_black }) + hi("TelescopePreviewNormal", { bg = base_30.darker_black }) + hi("TelescopeSelection", { bg = base_30.one_bg2, fg = base_30.white }) + hi("TelescopeSelectionCaret", { fg = base_30.cyan, bg = base_30.one_bg2 }) + hi("TelescopeMatching", { fg = base_30.blue, style = "bold" }) + + -- === TREESITTER === + + hi("@variable", { fg = base_16.base05 }) + hi("@variable.builtin", { fg = base_16.base09 }) + hi("@variable.parameter", { fg = base_16.base08 }) + hi("@variable.member", { fg = base_16.base08 }) + + hi("@constant", { fg = base_16.base08 }) + hi("@constant.builtin", { fg = base_16.base09 }) + hi("@constant.macro", { fg = base_16.base08 }) + + hi("@string", { fg = base_16.base0B }) + hi("@string.regex", { fg = base_16.base0C }) + hi("@string.escape", { fg = base_16.base0C }) + hi("@character", { fg = base_16.base08 }) + hi("@number", { fg = base_16.base09 }) + hi("@boolean", { fg = base_16.base09 }) + hi("@float", { fg = base_16.base09 }) + + hi("@function", { fg = base_16.base0D }) + hi("@function.builtin", { fg = base_16.base0D }) + hi("@function.macro", { fg = base_16.base08 }) + hi("@function.method", { fg = base_16.base0D }) + + hi("@constructor", { fg = base_16.base0C }) + hi("@parameter", { fg = base_16.base08 }) + + hi("@keyword", { fg = base_16.base0E }) + hi("@keyword.function", { fg = base_16.base0E }) + hi("@keyword.return", { fg = base_16.base0E }) + hi("@keyword.operator", { fg = base_16.base0E }) + + hi("@conditional", { fg = base_16.base0E }) + hi("@repeat", { fg = base_16.base0E }) + hi("@label", { fg = base_16.base0A }) + hi("@operator", { fg = base_16.base05 }) + hi("@exception", { fg = base_16.base08 }) + + hi("@type", { fg = base_16.base0A }) + hi("@type.builtin", { fg = base_16.base0A }) + hi("@type.qualifier", { fg = base_16.base0E }) + + hi("@structure", { fg = base_16.base0E }) + hi("@include", { fg = base_16.base0D }) + + hi("@property", { fg = base_16.base08 }) + hi("@field", { fg = base_16.base08 }) + + hi("@punctuation.delimiter", { fg = base_16.base0F }) + hi("@punctuation.bracket", { fg = base_16.base05 }) + hi("@punctuation.special", { fg = base_16.base08 }) + + hi("@comment", { fg = base_30.grey_fg, style = "italic" }) + hi("@comment.todo", { fg = base_30.grey, bg = base_30.white }) + hi("@comment.note", { fg = base_30.white, bg = base_30.blue }) + hi("@comment.warning", { fg = base_30.black, bg = base_30.yellow }) + hi("@comment.error", { fg = base_30.white, bg = base_30.red }) + + hi("@tag", { fg = base_16.base08 }) + hi("@tag.attribute", { fg = base_16.base0A }) + hi("@tag.delimiter", { fg = base_16.base0F }) + + hi("@markup.strong", { style = "bold" }) + hi("@markup.italic", { style = "italic" }) + hi("@markup.underline", { style = "underline" }) + hi("@markup.strike", { style = "strikethrough" }) + hi("@markup.heading", { fg = base_16.base0D, style = "bold" }) + hi("@markup.link", { fg = base_16.base08, style = "underline" }) + hi("@markup.link.url", { fg = base_16.base0B, style = "underline" }) + hi("@markup.list", { fg = base_16.base08 }) + + -- === NVIM-TREE === + + hi("NvimTreeNormal", { bg = base_30.darker_black }) + hi("NvimTreeNormalNC", { bg = base_30.darker_black }) + hi("NvimTreeRootFolder", { fg = base_30.red, style = "bold" }) + hi("NvimTreeGitDirty", { fg = base_30.yellow }) + hi("NvimTreeGitNew", { fg = base_30.green }) + hi("NvimTreeGitDeleted", { fg = base_30.red }) + hi("NvimTreeSpecialFile", { fg = base_30.yellow, style = "underline" }) + hi("NvimTreeIndentMarker", { fg = base_30.grey }) + hi("NvimTreeImageFile", { fg = base_30.dark_purple }) + hi("NvimTreeSymlink", { fg = base_30.cyan }) + hi("NvimTreeFolderName", { fg = base_30.blue }) + hi("NvimTreeFolderIcon", { fg = base_30.folder_bg }) + hi("NvimTreeOpenedFolderName", { fg = base_30.blue }) + + -- === WHICH-KEY === + + hi("WhichKey", { fg = base_30.blue }) + hi("WhichKeyGroup", { fg = base_30.green }) + hi("WhichKeyDesc", { fg = base_16.base05 }) + hi("WhichKeySeparator", { fg = base_30.grey }) + hi("WhichKeyFloat", { bg = base_30.darker_black }) + hi("WhichKeyBorder", { fg = base_30.blue, bg = base_30.darker_black }) + + -- === HEALTH CHECK === + + hi("healthSuccess", { fg = base_30.green, bg = base_30.black }) +end + +return M diff --git a/nvim/.config/nvim/lua/bearded-arc/watcher.lua b/nvim/.config/nvim/lua/bearded-arc/watcher.lua new file mode 100644 index 0000000..983ffdc --- /dev/null +++ b/nvim/.config/nvim/lua/bearded-arc/watcher.lua @@ -0,0 +1,50 @@ +-- Theme state file watcher +-- Watches ~/.config/theme-state and switches between bearded-arc / bearded-arc-light + +local M = {} + +local state_file = vim.fn.expand("~/.config/theme-state") +local current_theme = nil + +local function apply_theme(name) + if name == current_theme then return end + current_theme = name + if name == "light" then + vim.cmd("colorscheme bearded-arc-light") + else + vim.cmd("colorscheme bearded-arc") + end + -- Re-setup lualine with the new palette + if package.loaded["configs.lualine"] then + require("configs.lualine").setup() + end +end + +local function read_state() + local f = io.open(state_file, "r") + if f then + local state = f:read("*a"):gsub("%s+", "") + f:close() + return state == "light" and "light" or "dark" + end + return "dark" +end + +function M.setup() + -- Apply initial theme on startup + apply_theme(read_state()) + + -- Watch for changes + local uv = vim.uv or vim.loop + local watcher = uv.new_fs_event() + if watcher then + watcher:start(state_file, {}, function(err, filename, events) + if err then return end + vim.schedule(function() + apply_theme(read_state()) + end) + end) + end +end + +return M diff --git a/nvim/.config/nvim/lua/configs/lualine.lua b/nvim/.config/nvim/lua/configs/lualine.lua index 850504d..32ee829 100644 --- a/nvim/.config/nvim/lua/configs/lualine.lua +++ b/nvim/.config/nvim/lua/configs/lualine.lua @@ -1,59 +1,77 @@ -- Lualine configuration with bearded-arc theme colors -local colors = { - bg = "#232b3a", -- statusline_bg - fg = "#c3cfd9", -- base05 - white = "#ABB7C1", -- white - black = "#1c2433", -- black - grey = "#444c5b", -- grey - light_grey = "#626a79", -- light_grey +-- Supports dark and light variants - -- Mode colors - nord_blue = "#6da4cd", -- normal mode - cyan = "#22ECDB", -- visual mode - dark_purple = "#B78AFF", -- insert mode - green = "#3CEC85", -- success/terminal - red = "#FF738A", -- errors/replace - yellow = "#EACD61", -- warnings - orange = "#FF955C", -- command - blue = "#69C3FF", -- info - - -- Section backgrounds - lightbg = "#303847", -- file section bg +local palettes = { + dark = { + bg = "#232b3a", + fg = "#c3cfd9", + white = "#ABB7C1", + black = "#1c2433", + grey = "#444c5b", + light_grey = "#626a79", + nord_blue = "#6da4cd", + cyan = "#22ECDB", + dark_purple = "#B78AFF", + green = "#3CEC85", + red = "#FF738A", + yellow = "#EACD61", + orange = "#FF955C", + blue = "#69C3FF", + lightbg = "#303847", + }, + light = { + bg = "#f0e8df", + fg = "#3a3228", + white = "#2a2a2a", + black = "#faf4ed", + grey = "#b0a89c", + light_grey = "#6a6258", + nord_blue = "#2a6a9a", + cyan = "#147a8a", + dark_purple = "#7b4fc4", + green = "#1e9b52", + red = "#d1344f", + yellow = "#b8890f", + orange = "#c45a1c", + blue = "#1a7db5", + lightbg = "#e8e0d4", + }, } --- Custom theme based on bearded-arc -local bearded_arc_theme = { - normal = { - a = { bg = colors.nord_blue, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - c = { bg = colors.bg, fg = colors.fg }, - }, - insert = { - a = { bg = colors.dark_purple, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - }, - visual = { - a = { bg = colors.cyan, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - }, - replace = { - a = { bg = colors.red, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - }, - command = { - a = { bg = colors.orange, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - }, - terminal = { - a = { bg = colors.green, fg = colors.black, gui = "bold" }, - b = { bg = colors.lightbg, fg = colors.white }, - }, - inactive = { - a = { bg = colors.bg, fg = colors.grey }, - b = { bg = colors.bg, fg = colors.grey }, - c = { bg = colors.bg, fg = colors.grey }, - }, -} +local function build_theme(colors) + return { + normal = { + a = { bg = colors.nord_blue, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + c = { bg = colors.bg, fg = colors.fg }, + }, + insert = { + a = { bg = colors.dark_purple, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + }, + visual = { + a = { bg = colors.cyan, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + }, + replace = { + a = { bg = colors.red, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + }, + command = { + a = { bg = colors.orange, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + }, + terminal = { + a = { bg = colors.green, fg = colors.black, gui = "bold" }, + b = { bg = colors.lightbg, fg = colors.white }, + }, + inactive = { + a = { bg = colors.bg, fg = colors.grey }, + b = { bg = colors.bg, fg = colors.grey }, + c = { bg = colors.bg, fg = colors.grey }, + }, + } +end -- Custom component for LSP status local function lsp_status() @@ -115,106 +133,117 @@ local function git_status() return table.concat(parts, " ") end -require("lualine").setup({ - options = { - theme = bearded_arc_theme, - component_separators = { left = "", right = "" }, - section_separators = { left = "", right = "" }, - disabled_filetypes = { - statusline = { "alpha", "dashboard", "NvimTree", "neo-tree" }, - winbar = {}, - }, - ignore_focus = {}, - always_divide_middle = true, - globalstatus = true, - refresh = { - statusline = 1000, - tabline = 1000, - winbar = 1000, - }, - }, - sections = { - lualine_a = { - { - "mode", - fmt = function(str) - return str:sub(1, 1) -- Show only first letter (N, I, V, etc.) - end, +local M = {} + +function M.setup() + local colors = palettes[vim.o.background] or palettes.dark + local theme = build_theme(colors) + + require("lualine").setup({ + options = { + theme = theme, + component_separators = { left = "", right = "" }, + section_separators = { left = "", right = "" }, + disabled_filetypes = { + statusline = { "alpha", "dashboard", "NvimTree", "neo-tree" }, + winbar = {}, + }, + ignore_focus = {}, + always_divide_middle = true, + globalstatus = true, + refresh = { + statusline = 1000, + tabline = 1000, + winbar = 1000, }, }, - lualine_b = { - { - "branch", - icon = "", - color = { fg = colors.light_grey }, - }, - { - git_status, - color = { bg = colors.lightbg }, - }, - }, - lualine_c = { - { - "filename", - path = 1, -- Relative path - symbols = { - modified = " ", - readonly = " ", - unnamed = "[No Name]", - newfile = " ", + sections = { + lualine_a = { + { + "mode", + fmt = function(str) + return str:sub(1, 1) + end, }, - color = { bg = colors.lightbg, fg = colors.white }, }, - { - function() - return require("nvim-navic").get_location() - end, - cond = function() - return package.loaded["nvim-navic"] and require("nvim-navic").is_available() - end, - color = { bg = colors.bg, fg = colors.light_grey }, + lualine_b = { + { + "branch", + icon = "", + color = { fg = colors.light_grey }, + }, + { + git_status, + color = { bg = colors.lightbg }, + }, }, - { - lsp_diagnostics, - color = { bg = colors.bg }, + lualine_c = { + { + "filename", + path = 1, + symbols = { + modified = " ", + readonly = " ", + unnamed = "[No Name]", + newfile = " ", + }, + color = { bg = colors.lightbg, fg = colors.white }, + }, + { + function() + return require("nvim-navic").get_location() + end, + cond = function() + return package.loaded["nvim-navic"] and require("nvim-navic").is_available() + end, + color = { bg = colors.bg, fg = colors.light_grey }, + }, + { + lsp_diagnostics, + color = { bg = colors.bg }, + }, + }, + lualine_x = { + { + lsp_status, + color = { fg = colors.nord_blue, bg = colors.bg }, + }, + { + "filetype", + colored = true, + icon_only = false, + icon = { align = "right" }, + }, + }, + lualine_y = { + { + "progress", + color = { bg = colors.lightbg, fg = colors.white }, + }, + }, + lualine_z = { + { + "location", + icon = "", + color = { bg = colors.green, fg = colors.black }, + }, }, }, - lualine_x = { - { - lsp_status, - color = { fg = colors.nord_blue, bg = colors.bg }, - }, - { - "filetype", - colored = true, - icon_only = false, - icon = { align = "right" }, - }, + inactive_sections = { + lualine_a = {}, + lualine_b = {}, + lualine_c = { "filename" }, + lualine_x = { "location" }, + lualine_y = {}, + lualine_z = {}, }, - lualine_y = { - { - "progress", - color = { bg = colors.lightbg, fg = colors.white }, - }, - }, - lualine_z = { - { - "location", - icon = "", - color = { bg = colors.green, fg = colors.black }, - }, - }, - }, - inactive_sections = { - lualine_a = {}, - lualine_b = {}, - lualine_c = { "filename" }, - lualine_x = { "location" }, - lualine_y = {}, - lualine_z = {}, - }, - tabline = {}, - winbar = {}, - inactive_winbar = {}, - extensions = { "lazy", "mason" }, -}) + tabline = {}, + winbar = {}, + inactive_winbar = {}, + extensions = { "lazy", "mason" }, + }) +end + +M.setup() + +return M