[Enhancement]: Add a text tint slider for font color in the ereader #1351

Open
opened 2026-04-24 23:57:45 +02:00 by adam · 2 comments
Owner

Originally created by @abouthillier on GitHub (Mar 12, 2026).

Describe the Feature/Enhancement

Libby, Kindle, and other ereader apps allow for additional customization of the text color, mainly in dark mode.

Why would this be helpful?

I'd like to see or implement these added features to aid in low-light reading comfort.

Future Implementation (Screenshot)

Image

Audiobookshelf App Version

Android App - 0.11.0

Current Implementation (Screenshot)

No response

Originally created by @abouthillier on GitHub (Mar 12, 2026). ### Describe the Feature/Enhancement Libby, Kindle, and other ereader apps allow for additional customization of the text color, mainly in dark mode. ### Why would this be helpful? I'd like to see or implement these added features to aid in low-light reading comfort. ### Future Implementation (Screenshot) <img width="295" height="604" alt="Image" src="https://github.com/user-attachments/assets/16aabbbb-feb9-449f-a2d6-e5d042382eb7" /> ### Audiobookshelf App Version Android App - 0.11.0 ### Current Implementation (Screenshot) _No response_
adam added the enhancement label 2026-04-24 23:57:45 +02:00
Author
Owner

@PandaUnit-TWL commented on GitHub (Mar 27, 2026):

abs-ereader-text-tint.patch

@PandaUnit-TWL commented on GitHub (Mar 27, 2026): [abs-ereader-text-tint.patch](https://github.com/user-attachments/files/26297388/abs-ereader-text-tint.patch)
Author
Owner

@PandaUnit-TWL commented on GitHub (Mar 27, 2026):

Implementation: Text Color slider for ereader (#1821)

Adds a "Text Color" slider to the ereader settings panel, positioned after "Font Boldness". This lets users dim the text for comfortable low-light reading — a common feature in Libby, Kindle, and other ereader apps.

How it works

The slider ranges from 20 (dim) to 100 (full contrast), defaulting to 100 so existing behavior is unchanged.

  • Dark/Black themes: 100 = #ffffff, 50 = #808080, 20 = #333333
  • Light theme: 100 = #000000 (inverted — 50 = #808080, 20 = #cccccc)

The tint value also flows through to -webkit-text-stroke so font boldness rendering stays consistent with the dimmed color.

The setting persists to localStorage through the existing settingsUpdated()loadEreaderSettings() flow, same as all other ereader settings. Older stored settings without textTint default to 100 via nullish coalescing (??), so no migration is needed.

Not changed

  • MobiReader — does not use the same themeRules CSS injection system
  • ComicReader — not applicable (image-based rendering)
  • Bottom status bar — keeps its existing Tailwind opacity classes, unaffected by the slider

Changes

3 files changed, 23 insertions, 2 deletions


strings/en-us.json

Added one string:

  "LabelFontBoldness": "Font Boldness",
  "LabelFontColor": "Text Color",       // ← new
  "LabelFontFamily": "Font family",

components/readers/Reader.vue

Added textTint: 100 to ereaderSettings defaults:

ereaderSettings: {
  theme: 'dark',
  font: 'serif',
  fontScale: 100,
  lineSpacing: 115,
  spread: 'auto',
  textStroke: 0,
  textTint: 100,              // ← new
  navigateWithVolume: 'enabled',
  navigateWithVolumeWhilePlaying: false,
  keepScreenAwake: false
}

Added slider UI in the settings modal, after Font Boldness:

<div class="flex items-center mb-6">
  <div class="w-32">
    <p class="text-sm">{{ $strings.LabelFontColor }}</p>
  </div>
  <ui-range-input v-model="ereaderSettings.textTint" :min="20" :max="100" :step="1" input-width="180px" @input="settingsUpdated" />
</div>

components/readers/EpubReader.vue

Added textTint: 100 to ereaderSettings defaults:

ereaderSettings: {
  theme: 'dark',
  font: 'serif',
  fontScale: 100,
  lineSpacing: 115,
  textStroke: 0,
  textTint: 100               // ← new
}

Replaced the hardcoded font color in themeRules computed property.

Before:

themeRules() {
  const isDark = this.ereaderSettings.theme === 'dark'
  const isBlack = this.ereaderSettings.theme === 'black'
  const fontColor = isDark ? '#fff' : isBlack ? '#fff' : '#000'
  const backgroundColor = isDark ? 'rgb(35 35 35)' : isBlack ? 'rgb(0 0 0)' : 'rgb(255, 255, 255)'
  // ...
}

After:

themeRules() {
  const isDark = this.ereaderSettings.theme === 'dark'
  const isBlack = this.ereaderSettings.theme === 'black'
  const tint = this.ereaderSettings.textTint ?? 100

  let fontColor
  if (isDark || isBlack) {
    // Dark/black: tint 100 = #ffffff, tint 20 = #333333
    const g = Math.round((tint / 100) * 255)
    fontColor = '#' + g.toString(16).padStart(2, '0').repeat(3)
  } else {
    // Light: tint 100 = #000000, tint 20 = #cccccc
    const g = Math.round(255 - (tint / 100) * 255)
    fontColor = '#' + g.toString(16).padStart(2, '0').repeat(3)
  }

  const backgroundColor = isDark ? 'rgb(35 35 35)' : isBlack ? 'rgb(0 0 0)' : 'rgb(255, 255, 255)'

  return {
    '*': {
      color: `${fontColor}!important`,
      'background-color': `${backgroundColor}!important`,
      'line-height': this.ereaderSettings.lineSpacing + '%!important',
      '-webkit-text-stroke': this.ereaderSettings.textStroke / 100 + 'px ' + fontColor + '!important'
    },
    a: {
      color: `${fontColor}!important`
    }
  }
}

The -webkit-text-stroke color (used by Font Boldness) automatically uses the tinted fontColor, so stroke and text stay matched at any brightness level.

@PandaUnit-TWL commented on GitHub (Mar 27, 2026): ## Implementation: Text Color slider for ereader (#1821) Adds a "Text Color" slider to the ereader settings panel, positioned after "Font Boldness". This lets users dim the text for comfortable low-light reading — a common feature in Libby, Kindle, and other ereader apps. ### How it works The slider ranges from 20 (dim) to 100 (full contrast), defaulting to 100 so existing behavior is unchanged. - **Dark/Black themes:** 100 = `#ffffff`, 50 = `#808080`, 20 = `#333333` - **Light theme:** 100 = `#000000` (inverted — 50 = `#808080`, 20 = `#cccccc`) The tint value also flows through to `-webkit-text-stroke` so font boldness rendering stays consistent with the dimmed color. The setting persists to `localStorage` through the existing `settingsUpdated()` → `loadEreaderSettings()` flow, same as all other ereader settings. Older stored settings without `textTint` default to 100 via nullish coalescing (`??`), so no migration is needed. ### Not changed - **MobiReader** — does not use the same `themeRules` CSS injection system - **ComicReader** — not applicable (image-based rendering) - **Bottom status bar** — keeps its existing Tailwind opacity classes, unaffected by the slider --- ### Changes **3 files changed, 23 insertions, 2 deletions** --- #### `strings/en-us.json` Added one string: ```json "LabelFontBoldness": "Font Boldness", "LabelFontColor": "Text Color", // ← new "LabelFontFamily": "Font family", ``` --- #### `components/readers/Reader.vue` Added `textTint: 100` to `ereaderSettings` defaults: ```js ereaderSettings: { theme: 'dark', font: 'serif', fontScale: 100, lineSpacing: 115, spread: 'auto', textStroke: 0, textTint: 100, // ← new navigateWithVolume: 'enabled', navigateWithVolumeWhilePlaying: false, keepScreenAwake: false } ``` Added slider UI in the settings modal, after Font Boldness: ```html <div class="flex items-center mb-6"> <div class="w-32"> <p class="text-sm">{{ $strings.LabelFontColor }}</p> </div> <ui-range-input v-model="ereaderSettings.textTint" :min="20" :max="100" :step="1" input-width="180px" @input="settingsUpdated" /> </div> ``` --- #### `components/readers/EpubReader.vue` Added `textTint: 100` to `ereaderSettings` defaults: ```js ereaderSettings: { theme: 'dark', font: 'serif', fontScale: 100, lineSpacing: 115, textStroke: 0, textTint: 100 // ← new } ``` Replaced the hardcoded font color in `themeRules` computed property. Before: ```js themeRules() { const isDark = this.ereaderSettings.theme === 'dark' const isBlack = this.ereaderSettings.theme === 'black' const fontColor = isDark ? '#fff' : isBlack ? '#fff' : '#000' const backgroundColor = isDark ? 'rgb(35 35 35)' : isBlack ? 'rgb(0 0 0)' : 'rgb(255, 255, 255)' // ... } ``` After: ```js themeRules() { const isDark = this.ereaderSettings.theme === 'dark' const isBlack = this.ereaderSettings.theme === 'black' const tint = this.ereaderSettings.textTint ?? 100 let fontColor if (isDark || isBlack) { // Dark/black: tint 100 = #ffffff, tint 20 = #333333 const g = Math.round((tint / 100) * 255) fontColor = '#' + g.toString(16).padStart(2, '0').repeat(3) } else { // Light: tint 100 = #000000, tint 20 = #cccccc const g = Math.round(255 - (tint / 100) * 255) fontColor = '#' + g.toString(16).padStart(2, '0').repeat(3) } const backgroundColor = isDark ? 'rgb(35 35 35)' : isBlack ? 'rgb(0 0 0)' : 'rgb(255, 255, 255)' return { '*': { color: `${fontColor}!important`, 'background-color': `${backgroundColor}!important`, 'line-height': this.ereaderSettings.lineSpacing + '%!important', '-webkit-text-stroke': this.ereaderSettings.textStroke / 100 + 'px ' + fontColor + '!important' }, a: { color: `${fontColor}!important` } } } ``` The `-webkit-text-stroke` color (used by Font Boldness) automatically uses the tinted `fontColor`, so stroke and text stay matched at any brightness level.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf-app#1351