Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ All notable changes to `markdown-tui-explorer` are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added — Gaia Aether theme

A ninth built-in palette: Gruvbox warmth (cream `#f2e5bc` text, moss and
amber hues) on a blue-grey `#181c22` surface, with a dusty-mauve accent.
Select it in the settings modal under **Theme** or with
`theme = "gaia_aether"` in `config.toml`.

Three slots deliberately depart from the source palette, because its literal
values fail the contrast audit in `src/theme/mod.rs::tests`:

- `accent.primary` uses the source magenta `#c98fa0` rather than the source
accent `#a0607a`. No foreground colour reaches WCAG AA (4.5:1) on
`#a0607a` — its ceiling is 3.76:1 — so it cannot carry the `on_accent`
text drawn by the status bar and tab bar. `#a0607a` remains available as
`accent.alt`.
- `state.selection_bg` is a lightened `#503a4a`. The source selection
`#261a28` sits 0.16 luminance units from the background surface, below the
`MIN_SELECTION_DELTA` of 3.0, so a selection highlight would be invisible.
- `state.focus` is the magenta accent, 6.45:1 against the base surface.

The existing audit tests cover the new variant automatically, so the palette
is pinned to the same AA floor as every other theme.

## [1.35.1] — 2026-08-31

### Fixed — Mermaid quoted and delimiter-containing labels (#40)
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ a 500-file cap with a truncation footer.

![Global search modal](https://raw.githubusercontent.com/leboiko/markdown-reader/master/docs/screenshots/global-search.png)

Eight themes ship built-in, including light variants. Settings modal
Nine themes ship built-in, including light variants. Settings modal
reached via `c`.

![GitHub Light theme with settings open](https://raw.githubusercontent.com/leboiko/markdown-reader/master/docs/screenshots/settings-github-light.png)
Expand Down Expand Up @@ -166,8 +166,9 @@ drawn on the left of the viewer content when enabled.
The modal supports column-boundary panning (`h`/`l` snap to the next
column, `H`/`L` half-page pan), mouse scroll wheel (plain for rows,
`Shift`+wheel for columns), and click-outside-to-close.
- **Themes** — eight built-in palettes (Default, Dracula, Solarized Dark,
Solarized Light, Nord, Gruvbox Dark, Gruvbox Light, GitHub Light).
- **Themes** — nine built-in palettes (Default, Dracula, Solarized Dark,
Solarized Light, Nord, Gruvbox Dark, Gruvbox Light, GitHub Light,
Gaia Aether).
Switch live from the settings modal; every open document re-renders
with the new colors.
- **Session resume** — per-project: the last open tabs, active tab, and
Expand Down Expand Up @@ -710,7 +711,7 @@ it past the viewport and press `Enter` again for the next.

## Themes

Eight built-in themes (five dark, three light), switchable live from
Nine built-in themes (six dark, three light), switchable live from
the settings modal (`c`):

- **Default** — balanced palette that works on dark terminals.
Expand All @@ -721,6 +722,8 @@ the settings modal (`c`):
- **Gruvbox Dark** — warm retro groove.
- **Gruvbox Light** — warm retro light variant.
- **GitHub Light** — bright palette for light terminals.
- **Gaia Aether** — Gruvbox warmth (cream text, moss and amber hues) on a
blue-grey surface, with a dusty-mauve accent.

Theme changes re-render every open tab immediately, so switching feels
instantaneous. The choice is persisted and restored on next launch.
Expand All @@ -740,7 +743,7 @@ app starts with defaults rather than refusing to launch.
Fields:

```toml
theme = "dracula" # default | dracula | solarized_dark | solarized_light | nord | gruvbox_dark | gruvbox_light | github_light
theme = "dracula" # default | dracula | solarized_dark | solarized_light | nord | gruvbox_dark | gruvbox_light | github_light | gaia_aether
show_line_numbers = true
show_file_tree = true # true | false; false starts hidden (H still toggles)
tree_position = "left" # left | right
Expand Down
4 changes: 4 additions & 0 deletions src/theme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub enum Theme {
GruvboxDark,
GruvboxLight,
GithubLight,
GaiaAether,
}

impl Theme {
Expand All @@ -63,6 +64,7 @@ impl Theme {
Theme::GruvboxDark,
Theme::GruvboxLight,
Theme::GithubLight,
Theme::GaiaAether,
];

/// Human-readable display name for the theme.
Expand All @@ -76,6 +78,7 @@ impl Theme {
Theme::GruvboxDark => "Gruvbox Dark",
Theme::GruvboxLight => "Gruvbox Light",
Theme::GithubLight => "GitHub Light",
Theme::GaiaAether => "Gaia Aether",
}
}

Expand All @@ -95,6 +98,7 @@ impl Theme {
Theme::Default | Theme::SolarizedDark | Theme::Nord => "base16-ocean.dark",
Theme::Dracula | Theme::GruvboxDark => "base16-eighties.dark",
Theme::SolarizedLight | Theme::GruvboxLight | Theme::GithubLight => "InspiredGitHub",
Theme::GaiaAether => "base16-eighties.dark",
}
}
}
Expand Down
99 changes: 99 additions & 0 deletions src/theme/themes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,102 @@ pub(super) fn github_light() -> Tokens {
},
}
}

/// Gaia Aether — the dark Gruvbox/terracotta palette used across the author's
/// desktop theme ("AETHER / G.A.I.A v2": Gruvbox, terracotta, and dusty mauve).
///
/// Slots carry the source-palette names from that theme's `colors.toml`:
/// `background` `#181c22`, `lighter_background` `#1e2228`, `foreground`
/// `#f2e5bc`, `dark_foreground` `#8a7e70`, `accent` `#a0607a`, `selection`
/// `#261a28`, plus the Gruvbox-derived hue slots.
///
/// Three slots deviate from the source palette because its literal values
/// fail this crate's own contrast audit:
///
/// * `accent.primary` is the theme's dusty-mauve/tan `magenta` `#c98fa0`
/// rather than `accent` `#a0607a`. No foreground reaches WCAG AA (4.5:1)
/// on `#a0607a` — its ceiling is 3.76:1 — so it cannot carry the
/// `on_accent` text drawn by the status bar and tab bar. `#a0607a` stays
/// in the palette as `accent.alt`.
/// * `state.selection_bg` `#503a4a` is a lightened `selection` — the
/// source `#261a28` sits only 0.16 luminance units from `background`,
/// below the `MIN_SELECTION_DELTA` of 3.0, and would render invisible.
/// * `state.focus` is the magenta accent, 6.45:1 on `background`.
pub(super) fn gaia_aether() -> Tokens {
// AETHER / G.A.I.A v2 base surfaces and reading text.
let bg = Color::Rgb(24, 28, 34); // background #181c22
let raised = Color::Rgb(30, 34, 40); // lighter_background #1e2228
let brown = Color::Rgb(60, 56, 54); // brown #3c3836
let fg = Color::Rgb(242, 229, 188); // foreground #f2e5bc
let gray = Color::Rgb(168, 153, 132); // gruvbox fg4 #a89984
let dark_fg = Color::Rgb(138, 126, 112); // dark_foreground #8a7e70
// Hue slots, Gruvbox-derived in the source theme.
let orange = Color::Rgb(208, 128, 80); // orange #d08050
let yellow = Color::Rgb(184, 151, 90); // yellow #b8975a
let bright_yellow = Color::Rgb(212, 176, 122); // bright_yellow #d4b07a
let green = Color::Rgb(122, 158, 126); // green #7a9e7e
let cyan = Color::Rgb(131, 165, 152); // cyan #83a598
let mauve = Color::Rgb(201, 143, 160); // magenta #c98fa0
let deep_mauve = Color::Rgb(160, 96, 122); // accent #a0607a
let selection = Color::Rgb(80, 58, 74); // selection, lightened #261a28
Tokens {
surface: Surface {
base: bg,
raised,
border: brown,
},
text: Text {
primary: fg,
muted: gray,
// Dark base on the bright mauve accent: 6.45:1.
on_accent: bg,
title: fg,
},
state: State {
selection_bg: selection,
selection_fg: fg,
focus: mauve,
search_bg: bright_yellow,
current_match_bg: orange,
// Dark base reads 8.38:1 on bright_yellow and 5.61:1 on orange.
match_fg: bg,
},
accent: Accent {
primary: mauve,
alt: deep_mauve,
link: cyan,
},
syntax: Syntax {
inline_code: green,
code_fg: fg,
code_border: brown,
},
heading: Heading {
h1: green,
h2: cyan,
h3: mauve,
other: fg,
},
status: Status {
// Darker than `raised`: the source theme's `dark_background`.
bg: Color::Rgb(22, 26, 31), // #161a1f
fg: gray,
help_bg: bg,
gutter: dark_fg,
},
list: List {
marker: bright_yellow,
task_marker: green,
block_quote_fg: gray,
block_quote_border: dark_fg,
},
table: Table {
header: cyan,
border: brown,
},
git: Git {
new: green,
modified: yellow,
},
}
}
1 change: 1 addition & 0 deletions src/theme/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl Tokens {
Theme::GruvboxDark => super::themes::gruvbox_dark(),
Theme::GruvboxLight => super::themes::gruvbox_light(),
Theme::GithubLight => super::themes::github_light(),
Theme::GaiaAether => super::themes::gaia_aether(),
}
}
}
Expand Down