diff --git a/group_vars/all/13_theming.yml b/group_vars/all/13_theming.yml index fa8584b4..00f1a832 100644 --- a/group_vars/all/13_theming.yml +++ b/group_vars/all/13_theming.yml @@ -2,19 +2,12 @@ global_theming: enabled: true css: colors: - # For buttons and highlights – symbolizes the sea (slate blue) - primary: "#4F6D7A" - # For navigation, footers, etc. – a subtly light brown with a grayish tint (earth) - secondary: "#C8A28F" - # For the general (light mode) background – an azul, blue–gray tone - background: "#DCE6F2" - # For dark mode: a dark, blue–gray background - background_dark: "#2E3B4E" - # For the text – true black - text: "#2E3B4E" - # Accent color (e.g., for links or buttons) – a golden tone symbolizing the sun - accent: "#FFD700" - # As the positive/success color – a light, slightly grayish green (forest) + # General Colors + base: "#001f3f" + + # Special Action Colors + + # Sucess Color success: "#B2D3B2" # As the warning color – a light brown (earth) warning: "#D2B48C" @@ -22,20 +15,4 @@ global_theming: error: "#DC3545" # As the info color – a very light blue (symbolizing the sky) info: "#F0F8FF" - # Links – in this case, identical to primary (sea) - link: "#4F6D7A" - # Button text – white - button_text: "#FFFFFF" - # Shadows & borders (unchanged) - shadow: "rgba(0, 0, 0, 0.1)" - border: "#DDDDDD" - # New settings for cards and buttons: - # Cards: a slightly lighter tone than the background for subtle differentiation - card_bg_color: "#E6EFF9" - # Buttons: a background that is only a bit darker than the main background and in a blue tone - button_bg_color: "#C6D7E6" - # Bold, larger shadow for containers (cards, dropdowns, etc.) - large_shadow: "4px 4px 15px rgba(0, 0, 0, 0.2)" - # Reduced shadow for buttons - small_shadow: "1px 1px 3px rgba(0, 0, 0, 0.1)" global_theming_enabled: true diff --git a/roles/nginx-global-css/filter_plugins/color_filters.py b/roles/nginx-global-css/filter_plugins/color_filters.py index 957a8aea..c883ee2d 100644 --- a/roles/nginx-global-css/filter_plugins/color_filters.py +++ b/roles/nginx-global-css/filter_plugins/color_filters.py @@ -1,19 +1,66 @@ -def adjust_color(hex_color, amount): - # Remove the leading '#' if present +import colorsys + +def adjust_color(hex_color, lightness_change=0, hue_shift=0, saturation_change=0): + """ + 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). + - 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). + + Uses a 'cyclical' approach for lightness and saturation: + If the new value goes above 1, it wraps around (subtract 1). + If it goes below 0, it wraps around (add 1). + This creates strong contrast when crossing boundaries. + """ + + # Strip leading '#' if present hex_color = hex_color.lstrip('#') - # Extract the RGB components + # Parse the original RGB values r = int(hex_color[0:2], 16) g = int(hex_color[2:4], 16) b = int(hex_color[4:6], 16) - # Adjust the values, ensuring they remain within the range 0-255 - r = max(0, min(255, r + amount)) - g = max(0, min(255, g + amount)) - b = max(0, min(255, b + amount)) + # Convert from [0..255] range to [0..1] for colorsys + r /= 255.0 + g /= 255.0 + b /= 255.0 - # Convert the values back into a hexadecimal string - return '#{0:02x}{1:02x}{2:02x}'.format(r, g, b) + # Convert RGB -> HLS (note: in Python, it's Hue, Lightness, Saturation) + # Hue, Lightness, Saturation are each in [0..1] + h, l, s = colorsys.rgb_to_hls(r, g, b) + + # 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 + + # Shift saturation (cyc wrap) + # saturation_change is e.g. +20 => +0.20 in HLS + s_new = s + (saturation_change / 100.0) + if s_new > 1: + s_new -= 1 + elif s_new < 0: + s_new += 1 + + # Shift lightness (cyc wrap) + # lightness_change is e.g. +30 => +0.30 in HLS + l_new = l + (lightness_change / 100.0) + if l_new > 1: + l_new -= 1 + elif l_new < 0: + l_new += 1 + + # Convert back to RGB + new_r, new_g, new_b = colorsys.hls_to_rgb(h, l_new, s_new) + + # Scale back to [0..255] + new_r = int(new_r * 255) + new_g = int(new_g * 255) + new_b = int(new_b * 255) + + return '#{:02x}{:02x}{:02x}'.format(new_r, new_g, new_b) class FilterModule(object): '''Custom filters for Ansible''' diff --git a/roles/nginx-global-css/templates/global.css.j2 b/roles/nginx-global-css/templates/global.css.j2 index e947708d..ce368efc 100644 --- a/roles/nginx-global-css/templates/global.css.j2 +++ b/roles/nginx-global-css/templates/global.css.j2 @@ -7,25 +7,42 @@ HINT: Better overwritte CSS variables instead of individual elements. */ :root { - --primary-color: {{ global_theming.css.colors.primary }}; - --secondary-color: {{ global_theming.css.colors.secondary }}; - --brightest-color: {{ global_theming.css.colors.button_text }}; - --bright-color: {{ global_theming.css.colors.background }}; - --dark-color: {{ global_theming.css.colors.background_dark }}; + /** Derived Colors from the Base Color **/ + + /* Primary Color: the base color itself */ + --primary-color: {{ global_theming.css.colors.base }}; + + /* 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 **/ --success-color: {{ global_theming.css.colors.success }}; --warning-color: {{ global_theming.css.colors.warning }}; --error-color: {{ global_theming.css.colors.error }}; --info-color: {{ global_theming.css.colors.info }}; - --shadow-color: {{ global_theming.css.colors.shadow }}; - --border-color: {{ global_theming.css.colors.border }}; - - /* New variables for cards and buttons */ - --card-bg-color: {{ global_theming.css.colors.card_bg_color }}; - --large-shadow: {{ global_theming.css.colors.large_shadow }}; - --button-bg-color: {{ global_theming.css.colors.button_bg_color }}; - --small-shadow: {{ global_theming.css.colors.small_shadow }}; + } + + /* Bootstrap Overrides (Color/Shadow Variables Only) */ :root { --bs-primary: var(--primary-color); @@ -42,11 +59,11 @@ HINT: Better overwritte CSS variables instead of individual elements. /** Keycloak Overrides **/ :root{ - --pf-v5-global--Color--100: {{global_theming.css.colors.background_dark | adjust_color(10) }}; - --pf-v5-global--Color--200: {{global_theming.css.colors.background_dark | adjust_color(30) }}; - --pf-v5-global--Color--light-100: {{global_theming.css.colors.background_dark | adjust_color(0) }}; - --pf-v5-global--Color--light-200: {{global_theming.css.colors.background_dark | adjust_color(20) }}; - --pf-v5-global--Color--light-300: {{global_theming.css.colors.background_dark | adjust_color(40) }}; + --pf-v5-global--Color--100: {{ global_theming.css.colors.base | adjust_color(-30) }}; + --pf-v5-global--Color--200: {{ global_theming.css.colors.base | adjust_color(-10) }}; + --pf-v5-global--Color--light-100: {{ global_theming.css.colors.base | adjust_color(-30) }}; + --pf-v5-global--Color--light-200: {{ global_theming.css.colors.base | adjust_color(-10) }}; + --pf-v5-global--Color--light-300: {{ global_theming.css.colors.base | adjust_color(10) }}; } /** Mastodon Overrides **/ @@ -67,11 +84,18 @@ HINT: Better overwritte CSS variables instead of individual elements. --color-primary-element-light: var(--secondary-color); } -/* Peertube Overrides */ +/** Peertube **/ :root { --mainColor: var(--primary-color); } +/** Pixelfed **/ +:root { + --card-bg: var(--complementary-color); + --light-gray: var(--complementary-color); +} + + /* Global Defaults (Colors Only) */ body { background-color: var(--bright-color) !important; @@ -125,7 +149,6 @@ input, textarea, select { } input:focus, textarea:focus, select:focus { border-color: var(--primary-color) !important; - /** box-shadow: 0 0 5px var(--shadow-color);**/ } /* Navigation (Background and Text Colors) */ @@ -159,8 +182,7 @@ thead { /* Cards / Containers (Background, Border, and Shadow) Cards now use a slightly lighter background and a bold, clear shadow */ .card { - background-color: var(--card-bg-color) !important; - /** box-shadow: var(--large-shadow) !important;**/ + background-color: var(--complementary-color) !important; border-color: var(--border-color) !important; } @@ -195,7 +217,7 @@ button.icon-button { /** Keycloak **/ body#keycloak-bg main{ - background-color: var(--card-bg-color) !important; + background-color: var(--complementary-color) !important; } div#app header, div#app header *{ @@ -204,7 +226,7 @@ div#app header, div#app header *{ } div#app div#page-sidebar, div#app main#kc-main-content-page-container{ - background-color: var(--card-bg-color) !important; + background-color: var(--complementary-color) !important; } div#app main#kc-main-content-page-container section,