Adapted global css for dark mode and better automatic color scaling

This commit is contained in:
Kevin Veen-Birkenbach 2025-02-17 13:51:22 +01:00
parent 326f048639
commit f7953f74bd
3 changed files with 170 additions and 124 deletions

View File

@ -5,7 +5,7 @@ global_theming:
# General Colors # General Colors
base: "#001f3f" base: "#001f3f"
# Special Action Colors lightness_change:
# Sucess Color # Sucess Color
success: "#B2D3B2" success: "#B2D3B2"

View File

@ -1,18 +1,18 @@
import colorsys import colorsys
def adjust_color(hex_color, lightness_change=0, hue_shift=0, saturation_change=0): def adjust_color(hex_color, target_lightness=None, lightness_change=0, hue_shift=0, saturation_change=0):
""" """
Adjust a HEX color in HSL space. Adjust a HEX color in HSL space.
@See https://chatgpt.com/c/67b08ad4-eb58-800f-80cc-f1b22d8c64f3
- lightness_change: Percentage points to add or subtract from lightness (0-100 => 0-1 in HSL). - target_lightness: If provided (0 to 1), the lightness is set absolutely to this value.
Otherwise, lightness_change is applied additively (in percentage points, where 100 => 1 in HSL).
- lightness_change: Percentage points to add or subtract from lightness (if target_lightness is None).
- hue_shift: Degrees to shift hue (e.g., +180 for complementary). - hue_shift: Degrees to shift hue (e.g., +180 for complementary).
- saturation_change: Percentage points to add or subtract from saturation (0-100 => 0-1 in HSL). - saturation_change: Percentage points to add or subtract from saturation.
Uses a 'cyclical' approach for lightness and saturation: Uses a 'cyclical' approach for lightness and saturation if no target_lightness is provided:
If the new value goes above 1, it wraps around (subtract 1). If the new value goes above 1, it wraps around (subtract 1).
If it goes below 0, it wraps around (add 1). If it goes below 0, it wraps around (add 1).
This creates strong contrast when crossing boundaries.
""" """
# Strip leading '#' if present # Strip leading '#' if present
@ -28,24 +28,23 @@ def adjust_color(hex_color, lightness_change=0, hue_shift=0, saturation_change=0
g /= 255.0 g /= 255.0
b /= 255.0 b /= 255.0
# Convert RGB -> HLS (note: in Python, it's Hue, Lightness, Saturation) # Convert RGB -> HLS (colorsys uses HLS, also hier: Hue, Lightness, Saturation)
# Hue, Lightness, Saturation are each in [0..1]
h, l, s = colorsys.rgb_to_hls(r, g, b) h, l, s = colorsys.rgb_to_hls(r, g, b)
# Shift hue by (hue_shift / 360) # Shift hue by (hue_shift / 360)
# e.g., hue_shift=180 => shift by 0.5 in HLS space
h = (h + (hue_shift / 360.0)) % 1.0 h = (h + (hue_shift / 360.0)) % 1.0
# Shift saturation (cyc wrap) # Adjust saturation (cyclically)
# saturation_change is e.g. +20 => +0.20 in HLS
s_new = s + (saturation_change / 100.0) s_new = s + (saturation_change / 100.0)
if s_new > 1: if s_new > 1:
s_new -= 1 s_new -= 1
elif s_new < 0: elif s_new < 0:
s_new += 1 s_new += 1
# Shift lightness (cyc wrap) # Adjust lightness: either set to a target or change it additively (cyclically)
# lightness_change is e.g. +30 => +0.30 in HLS if target_lightness is not None:
l_new = target_lightness
else:
l_new = l + (lightness_change / 100.0) l_new = l + (lightness_change / 100.0)
if l_new > 1: if l_new > 1:
l_new -= 1 l_new -= 1
@ -55,7 +54,7 @@ def adjust_color(hex_color, lightness_change=0, hue_shift=0, saturation_change=0
# Convert back to RGB # Convert back to RGB
new_r, new_g, new_b = colorsys.hls_to_rgb(h, l_new, s_new) new_r, new_g, new_b = colorsys.hls_to_rgb(h, l_new, s_new)
# Scale back to [0..255] # Scale back to [0..255] and format as HEX
new_r = int(new_r * 255) new_r = int(new_r * 255)
new_g = int(new_g * 255) new_g = int(new_g * 255)
new_b = int(new_b * 255) new_b = int(new_b * 255)

View File

@ -8,30 +8,9 @@ HINT: Better overwritte CSS variables instead of individual elements.
:root { :root {
/** Derived Colors from the Base Color **/ /** Derived Colors from the Base Color **/
{% for i in range(1, 100) %}
/* Primary Color: the base color itself */ --color-{{ "%02d"|format(i) }}: {{ global_theming.css.colors.base | adjust_color(target_lightness=(i / 100)) }};
--primary-color: {{ global_theming.css.colors.base }}; {% endfor %}
/* Secondary Color: slightly lightened */
--secondary-color: {{ global_theming.css.colors.base | adjust_color(15) }};
/* Complementary Color: moderately lightened to fall within a mid-brightness range */
--complementary-color: {{ global_theming.css.colors.base | adjust_color(30) }};
/* Bright Background: significantly lightened */
--bright-color: {{ global_theming.css.colors.base | adjust_color(45) }};
/* Brightest Tone (e.g., for button text or accents): nearly white */
--brightest-color: {{ global_theming.css.colors.base | adjust_color(60) }};
/* Dark Background: a darker variant of the base color */
--dark-color: {{ global_theming.css.colors.base | adjust_color(-30) }};
/* Border Color: slightly offset with a light adjustment */
--border-color: {{ global_theming.css.colors.base | adjust_color(10) }};
/* Button Background: a gentle lightening for soft contrast */
--button-bg-color: {{ global_theming.css.colors.base | adjust_color(20) }};
/** Special Action Colors **/ /** Special Action Colors **/
--success-color: {{ global_theming.css.colors.success }}; --success-color: {{ global_theming.css.colors.success }};
@ -41,81 +20,147 @@ HINT: Better overwritte CSS variables instead of individual elements.
} }
@media (prefers-color-scheme: dark) {
:root {
/** Dark Mode Derived Colors from the Base Color **/
{% for i in range(1, 100) %}
--color-{{ "%02d"|format(i) }}: {{ global_theming.css.colors.base | adjust_color(target_lightness=(1 - (i / 100))) }};
{% endfor %}
/** Special Action Colors **/
--success-color: {{ global_theming.css.colors.success | adjust_color(target_lightness=(1 - 0.2)) }};
--warning-color: {{ global_theming.css.colors.warning | adjust_color(target_lightness=(1 - 0.3)) }};
--error-color: {{ global_theming.css.colors.error | adjust_color(target_lightness=(1 - 0.3)) }};
--info-color: {{ global_theming.css.colors.info | adjust_color(target_lightness=(1 - 0.2)) }};
}
}
:root, ::after, ::before, ::backdrop {
/* For Dark Mode Plugin
* @See https://chromewebstore.google.com/detail/dark-mode/dmghijelimhndkbmpgbldicpogfkceaj
*/
--native-dark-accent-color: var(--color-60); /* was #a9a9a9 */
--native-dark-bg-blend-mode: multiply;
--native-dark-bg-color: var(--color-10); /* was #292929 */
--native-dark-bg-image-color: rgba(0, 0, 0, 0.10); /* remains the same, or adjust if needed */
--native-dark-bg-image-filter: brightness(50%) contrast(200%);
--native-dark-border-color: var(--color-40); /* was #555555 */
--native-dark-box-shadow: 0 0 0 1px rgb(255 255 255 / 10%);
--native-dark-brightness: 0.85;
--native-dark-cite-color: var(--color-70); /* was #92de92 you might adjust if a green tone is needed */
--native-dark-fill-color: var(--color-50); /* was #7d7d7d */
--native-dark-font-color: var(--color-95); /* was #dcdcdc */
--native-dark-link-color: var(--color-80); /* was #8db2e5 */
--native-dark-opacity: 0.85;
--native-dark-text-shadow: none;
--native-dark-transparent-color: transparent;
--native-dark-visited-link-color: var(--color-85); /* was #c76ed7 */
}
/* Bootstrap Overrides (Color/Shadow Variables Only) */ /* Bootstrap Overrides (Color/Shadow Variables Only) */
:root { :root {
--bs-primary: var(--primary-color); --bs-primary: var(--color-50);
--bs-secondary: var(--secondary-color); --bs-secondary: var(--color-65);
--bs-body-bg: var(--bright-color); --bs-body-bg: var(--color-90);
--bs-body-color: var(--dark-color); --bs-body-color: var(--color-40);
--bs-danger: var(--error-color); --bs-danger: var(--error-color);
--bs-warning: var(--warning-color); --bs-warning: var(--warning-color);
--bs-success: var(--success-color); --bs-success: var(--success-color);
--bs-info: var(--info-color); --bs-info: var(--info-color);
--bs-link-color: var(--primary-color); --bs-link-color: var(--color-50);
--bs-btn-color: var(--dark-color); --bs-btn-color: var(--color-40);
} }
/** Keycloak Overrides **/ /** Keycloak Overrides **/
:root{ :root{
--pf-v5-global--Color--100: {{ global_theming.css.colors.base | adjust_color(-30) }}; --pf-v5-global--Color--100: var(--color-40);
--pf-v5-global--Color--200: {{ global_theming.css.colors.base | adjust_color(-10) }}; --pf-v5-global--Color--200: var(--color-60);
--pf-v5-global--Color--light-100: {{ global_theming.css.colors.base | adjust_color(-30) }}; --pf-v5-global--Color--light-100: var(--color-40);
--pf-v5-global--Color--light-200: {{ global_theming.css.colors.base | adjust_color(-10) }}; --pf-v5-global--Color--light-200: var(--color-60);
--pf-v5-global--Color--light-300: {{ global_theming.css.colors.base | adjust_color(10) }}; --pf-v5-global--Color--light-300: var(--color-70);
} }
/** Mastodon Overrides **/ /** Mastodon Overrides **/
:root{ :root{
--surface-variant-background-color: var(--button-bg-color); --surface-variant-background-color: var(--color-80);
} }
/** Nextcloud Specific**/ /** Nextcloud Specific**/
:root{ :root{
--color-main-background: var(--bright-color); --color-main-background: None;
--color-main-background-rgb: var(--bright-color); --color-main-background-rgb: None;
--color-primary-element: var(--button-bg-color); --color-primary-element: var(--color-80);
--color-main-text: var(--dark-color); --color-main-text: var(--color-40);
--color-background-hover: var(--secondary-color); --color-background-hover: var(--color-65);
/** Calendar **/ /** Calendar **/
--color-background-dark: var(--info-color); /** Days which aren't in the current month **/ --color-background-dark: var(--info-color); /** Days which aren't in the current month **/
--color-primary-element-light: var(--secondary-color); --color-primary-element-light: var(--color-65);
} }
/** Peertube **/ /** Peertube **/
:root { :root {
--mainColor: var(--primary-color); --mainColor: var(--color-50);
} }
/** Pixelfed **/ /** Pixelfed **/
:root {
--card-bg: var(--complementary-color);
--light-gray: var(--complementary-color);
}
:root {
/* Base Colors */
--light: var(--color-05); /* Very dark (was #000) */
--dark: var(--color-100); /* Very light (was #fff) */
/* Backgrounds */
--body-bg: var(--color-05); /* Main background: very dark */
--nav-bg: var(--color-05); /* Navigation background: very dark */
/* Text Colors */
--body-color: var(--color-70); /* Main text mid brightness */
--text-lighter: var(--color-60); /* Lighter text for less prominent elements */
/* Section Backgrounds and Cards */
--bg-light: var(--color-95); /* Lighter background areas */
--card-bg: var(--color-90); /* Card background */
--light-gray: var(--color-75); /* For less dominant elements */
--light-hover-bg: var(--color-85); /* Slightly lighter hover background */
/* Borders and Input Fields */
--btn-light-border: var(--color-10); /* Dark border for buttons */
--input-border: var(--color-10); /* Border color for inputs */
--border-color: var(--color-85); /* General border: slightly lighter than background */
/* Other Areas */
--comment-bg: var(--color-85); /* Background for comments */
--card-header-accent: var(--color-85); /* Accent color in card headers */
/* Dropdown Menus */
--dropdown-item-hover-bg: var(--color-05); /* Hover background: very dark */
--dropdown-item-hover-color: var(--color-60); /* Hover text: a bit lighter */
--dropdown-item-color: var(--color-70); /* Regular dropdown item text */
--dropdown-item-active-color: var(--color-99);/* Active state: very light (white) */
}
/* Global Defaults (Colors Only) */ /* Global Defaults (Colors Only) */
body { body {
background-color: var(--bright-color) !important; background-color: var(--color-93) !important;
background-image: none !important; background-image: none !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
/* Use the corporate-design font family */ /* Use the corporate-design font family */
font-family: "Liberation Sans", Arial, sans-serif; font-family: "Liberation Sans", Arial, sans-serif;
} }
/* Links (Color Only) */ /* Links (Color Only) */
a { a {
color: var(--primary-color) !important; color: var(--color-50) !important;
} }
/* Buttons (Background, Text, Border, and Shadow) /* Buttons (Background, Text, Border, and Shadow)
Now using a button background that is only slightly darker than the overall background */ Now using a button background that is only slightly darker than the overall background */
button, .btn { button, .btn {
background-color: var(--button-bg-color) !important; background-color: var(--color-87) !important;
color: var(--primary-color) !important; color: var(--color-50) !important;
border-color: var(--border-color) !important; border-color: var(--color-80) !important;
cursor: pointer; cursor: pointer;
} }
@ -126,107 +171,107 @@ button:hover, .btn:hover {
/* States: Success, Warning, Error, Info (Background and Text Colors) */ /* States: Success, Warning, Error, Info (Background and Text Colors) */
.success, .alert-success { .success, .alert-success {
background-color: var(--success-color) !important; background-color: var(--success-color) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
.warning, .alert-warning { .warning, .alert-warning {
background-color: var(--warning-color) !important; background-color: var(--warning-color) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
.error, .alert-danger { .error, .alert-danger {
background-color: var(--error-color) !important; background-color: var(--error-color) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
.info, .alert-info { .info, .alert-info {
background-color: var(--info-color) !important; background-color: var(--info-color) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/* Inputs & Forms in Light Mode (Using a Light Tone from the Corporate Design) */ /* Inputs & Forms in Light Mode (Using a Light Tone from the Corporate Design) */
input, textarea, select { input, textarea, select {
background-color: var(--info-color) !important; /* Instead of var(--bright-color) */ background-color: var(--info-color) !important; /* Instead of var(--color-90) */
color: var(--dark-color) !important; color: var(--color-40) !important;
border-color: var(--border-color) !important; border-color: var(--color-70) !important;
} }
input:focus, textarea:focus, select:focus { input:focus, textarea:focus, select:focus {
border-color: var(--primary-color) !important; border-color: var(--color-50) !important;
} }
/* Navigation (Background and Text Colors) */ /* Navigation (Background and Text Colors) */
.navbar, .navbar-light, .navbar-dark { .navbar, .navbar-light, .navbar-dark {
background-color: var(--bright-color) !important; background-color: var(--color-90) !important;
color: var(--primary-color) !important; color: var(--color-50) !important;
border-color: var(--color-85) !important;
} }
.navbar a { .navbar a {
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
.navbar a.dropdown-item { .navbar a.dropdown-item {
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
.card-body { .card-body {
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/* Tables (Borders and Header Colors) */ /* Tables (Borders and Header Colors) */
th, td { th, td {
border-color: var(--border-color) !important; border-color: var(--color-70) !important;
} }
thead { thead {
background-color: var(--button-bg-color) !important; background-color: var(--color-80) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/* Cards / Containers (Background, Border, and Shadow) /* Cards / Containers (Background, Border, and Shadow)
Cards now use a slightly lighter background and a bold, clear shadow */ Cards now use a slightly lighter background and a bold, clear shadow */
.card { .card {
background-color: var(--complementary-color) !important; background-color: var(--color-90) !important;
border-color: var(--border-color) !important; border-color: var(--color-85) !important;
} }
/* Headings (Text Color) */ /* Headings (Text Color) */
h1, h2, h3, h4, h5, h6, p{ h1, h2, h3, h4, h5, h6, p{
color: var(--dark-color) !important; color: var(--color-10) !important;
} }
/* Dropdown Menu and Submenu (Background, Text, and Shadow) */ /* Dropdown Menu and Submenu (Background, Text, and Shadow) */
.navbar .dropdown-menu, .navbar .dropdown-menu,
.nav-item .dropdown-menu { .nav-item .dropdown-menu {
background-color: var(--bright-color) !important; background-color: var(--color-80) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
/**box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);**/
} }
.dropdown-item { .dropdown-item {
color: var(--dark-color) !important; color: var(--color-40) !important;
background-color: var(--bright-color) !important; background-color: var(--color-80) !important;
} }
.dropdown-item:hover, .dropdown-item:hover,
.dropdown-item:focus { .dropdown-item:focus {
background-color: var(--secondary-color) !important; background-color: var(--color-65) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/* Ensure the button itself uses the light text color. Occurred in Mastodon */ /* Ensure the button itself uses the light text color. Occurred in Mastodon */
button.icon-button { button.icon-button {
color: var(--most-bright) !important; color: var(--color-99) !important;
} }
/** Keycloak **/ /** Keycloak **/
body#keycloak-bg main{ body#keycloak-bg main{
background-color: var(--complementary-color) !important; background-color: var(--color-75) !important;
} }
div#app header, div#app header *{ div#app header, div#app header *{
background-color: var(--primary-color) !important; background-color: var(--color-50) !important;
color: var(--brightest-color); color: var(--color-98);
} }
div#app div#page-sidebar, div#app main#kc-main-content-page-container{ div#app div#page-sidebar, div#app main#kc-main-content-page-container{
background-color: var(--complementary-color) !important; background-color: var(--color-75) !important;
} }
div#app main#kc-main-content-page-container section, div#app main#kc-main-content-page-container section,
@ -234,7 +279,7 @@ div#app main#kc-main-content-page-container section *,
div#app main#kc-main-content-page-container section a div#app main#kc-main-content-page-container section a
{ {
background-color: transparent !important; background-color: transparent !important;
color: var(--dark-color); color: var(--color-40);
} }
/** LAM Specific **/ /** LAM Specific **/
@ -245,28 +290,28 @@ div#app main#kc-main-content-page-container section a
/** Mailu **/ /** Mailu **/
[class*=sidebar-dark-], .bg-mailu-logo { [class*=sidebar-dark-], .bg-mailu-logo {
background-color: var(--bright-color) !important; background-color: var(--color-90) !important;
} }
/** Mastodon Specific **/ /** Mastodon Specific **/
div#mastodon div.compose-panel div.compose-form__highlightable{ div#mastodon div.compose-panel div.compose-form__highlightable{
background-color: var(--bright-color) !important; background-color: var(--color-90) !important;
} }
div#mastodon strong{ div#mastodon strong{
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/** Nextcloud specific **/ /** Nextcloud specific **/
html.ng-csp header#header{ html.ng-csp header#header{
color: var(--bright-color) !important; color: var(--color-90) !important;
background-color: var(--button-bg-color) !important; background-color: var(--color-80) !important;
} }
html.ng-csp button.files-list__row-name-link, html.ng-csp button.button-vue{ html.ng-csp button.files-list__row-name-link, html.ng-csp button.button-vue{
background-color: transparent !important; background-color: transparent !important;
color: background-color: var(--button-bg-color) !important; color: background-color: var(--color-80) !important;
} }
html.ng-csp div#postsetupchecks ul.warnings{ html.ng-csp div#postsetupchecks ul.warnings{
@ -278,13 +323,13 @@ html.ng-csp div#postsetupchecks ul.info{
} }
div#content-vue p, div#content-vue span{ div#content-vue p, div#content-vue span{
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/** OpenProject **/ /** OpenProject **/
header.op-app-header{ header.op-app-header{
background-color: var(--dark-color) !important; background-color: var(--color-40) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
/** Open Project **/ /** Open Project **/
@ -292,15 +337,17 @@ div#wrapper button, div#wrapper input, button.top-menu-search-button, div.menu-s
background-color: transparent !important; background-color: transparent !important;
} }
main-menu-toggle button{
border: 0px none !important;
}
/* Peertube specific configuration */ /* Peertube specific configuration */
.peertube-container button { .peertube-container button {
background-color: transparent !important; background-color: transparent !important;
} }
/* Pixelfed */
div.page-wrapper{
background: none !important;
background-color: none !important;
}
/** Taiga specific configuration **/ /** Taiga specific configuration **/
section.main.kanban{ section.main.kanban{
@ -309,9 +356,9 @@ section.main.kanban{
div.master, div.kanban-header, div.kanban-table-inner, section.kanban button,a.dropdown-project-list-projects{ div.master, div.kanban-header, div.kanban-table-inner, section.kanban button,a.dropdown-project-list-projects{
background-color: var(--info-color) !important; background-color: var(--info-color) !important;
color: var(--dark-color) !important; color: var(--color-40) !important;
} }
section.kanban h1, section.kanban h2{ section.kanban h1, section.kanban h2{
color: var(--dark-color) !important; color: var(--color-40) !important;
} }