Skip to content

Theme Configuration and custom branding

Overview

This guide provides instructions for modifying and creating themes, focusing on style for application and visual identity.

Contents

  1. Basic Theme and Functionality Overview
  2. Brand Assets Overview
  3. Client Theme Customization
  4. Theme Key Descriptions
  5. Custom Styles
  6. Credits
  7. Badges

Basic Theme and Functionality Overview

To automate the creation of CSS variables from a structured map of values, we use SASS mixins in our approach. Here's a detailed explanation of how it works:

  1. Defining Variables: Begin by creating a map of variables in SASS. This map contains all the CSS properties and values that you want to convert into CSS variables.

  2. Generating CSS Variables: The generate-css-vars mixin processes this map and generates the corresponding CSS variables with the specified prefix. This mixin ensures that all variables are properly formatted and nested.

  3. Setting Variables: The set-css-var mixin is responsible for setting the actual CSS variables in the generated CSS code. It ensures each variable is formatted correctly.

  4. Creating Prefixes: The build-prefix function helps create appropriate prefixes for the variables, ensuring they are unique and correctly placed.

With this foundation, we can now delve into the specifics of how to implement and configure this feature in your project.

Code Structure

  1. generate-css-vars($vars, $config):

  2. This mixin is the entry point that takes a variable map $vars and a configuration object $config.

  3. It creates a prefix from the configuration object and calls the parse-vars mixin.

  4. parse-vars($map, $prefix, $is-first-iteration: true):

  5. Recursively traverses the variable map.

  6. If a value in the map is another map, it calls itself recursively with an updated prefix.
  7. If a value is a simple type (e.g., string, number, boolean), it calls the set-css-var mixin.

  8. set-css-var($value, $prefix):

  9. Sets the CSS variable in the format --prefix: value;.

  10. build-prefix($prefix, $name, $is-first-iteration):

  11. A function to create the variable prefix.

  12. Uses __ as a separator for the first iteration.
  13. For subsequent iterations, it uses - or no separator if the name indicates a subcomponent.

Brand Assets Overview

Default brand files are stored in app/frontend/assets/images/brand/.

CSS variables that reference brand files are defined in app/frontend/src/shared/stylesheets/easy/themes/_brand-assets.scss. The file uses Vite alias (@assets) so assets are resolved and hashed by Vite.

CSS variable Default file Usage
--logo-url logo.svg Main color logo
--logo-url--black logo--bw.svg Black/white logo
--logo-url--inverted logo--inverted.svg Inverted/light logo
--logo-url--mark logo--mark.svg Symbol-only mark
--logo-url--mark-black logo--mark-bw.svg Symbol black/white
--logo-url--mark-inverted logo--mark-inverted.svg Symbol inverted
--logo-url--mutation logo--mutation.svg Alternate logo
--login-bg-url login-bg--default.svg Login background

In addition to CSS-driven assets, the backend also uses:

  • favicon.ico for browser tab icon
  • logo.png for mailer inline logo attachment

Client Theme Customization

Use this section to override brand assets for a client deployment without changing the default files.

Full rebrand checklist

A complete rebrand requires all of the following. Missing any item leaves that part of the UI using the default Easy brand.

  • [ ] app/frontend/assets/custom_brand/favicon.ico — browser tab icon (16, 32, 48 px sizes)
  • [ ] app/frontend/assets/custom_brand/logo.png — mailer inline logo (320 × 89 px recommended)
  • [ ] app/frontend/assets/custom_brand/logo.svg — main color logo
  • [ ] app/frontend/assets/custom_brand/logo--bw.svg — black/white logo
  • [ ] app/frontend/assets/custom_brand/logo--inverted.svg — inverted/light logo
  • [ ] app/frontend/assets/custom_brand/logo--mark.svg — symbol mark
  • [ ] app/frontend/assets/custom_brand/logo--mark-bw.svg — symbol mark black/white
  • [ ] app/frontend/assets/custom_brand/logo--mark-inverted.svg — symbol mark inverted
  • [ ] app/frontend/assets/custom_brand/logo--mutation.svg — alternate logo
  • [ ] app/frontend/assets/custom_brand/login-bg--default.svg — login background
  • [ ] brand-enabled: true set in _theme--brand.scssrequired to output any brand CSS variables
  • [ ] CSS asset variables overridden in _theme--brand.scss (SVG files only; raster files above are picked up automatically)
  • [ ] app/frontend/assets/custom_brand/<FontName>.ttf — brand font file (required by fallback source)
  • [ ] app/frontend/assets/custom_brand/<FontName>.woff2 — brand font file (recommended primary source)
  • [ ] Brand fonts loaded via typo.loadFontFace(..., true) in _theme--brand.scss
  • [ ] --easy__font-family--base and --easy__font-family--heading set in _theme--brand.scss
  • [ ] Brand color keys (-main, -front, -inverse) set in $theme__map--brand

Override brand files

Upload custom brand files to:

app/frontend/assets/custom_brand/

Automatically reused files

If the following files exist in app/frontend/assets/custom_brand/, they are used automatically:

  • favicon.ico — browser tab icon
  • logo.png — mailer inline logo attachment

These filenames must remain unchanged. If either file is not present, the application uses the default version from:

app/frontend/assets/images/brand/

Frontend brand assets (SVG / login background)

Other frontend brand assets, such as SVG logos or the login background, must be mapped manually through CSS variables in:

app/frontend/src/shared/stylesheets/easy/themes/_theme--brand.scss

Note: The CSS variable overrides only take effect when brand-enabled: true is set in $theme__map--brand. Without it the :root block inside generate-brand-themes() is never emitted and all logo/background variables remain at their defaults.

Process:

  1. Upload the new files to app/frontend/assets/custom_brand/
  2. Set brand-enabled: true in $theme__map--brand
  3. Override the asset variables in _theme--brand.scss

Example:

// app/frontend/src/shared/stylesheets/easy/themes/_theme--brand.scss
:root {
  --logo-url: url('@assets/custom_brand/logo.svg');
  --logo-url--black: url('@assets/custom_brand/logo--bw.svg');
  --logo-url--inverted: url('@assets/custom_brand/logo--inverted.svg');
  --logo-url--mark: url('@assets/custom_brand/logo--mark.svg');
  --logo-url--mark-black: url('@assets/custom_brand/logo--mark-bw.svg');
  --logo-url--mark-inverted: url('@assets/custom_brand/logo--mark-inverted.svg');
  --logo-url--mutation: url('@assets/custom_brand/logo--mutation.svg');
  --login-bg-url: url('@assets/custom_brand/login-bg--default.svg');
}

Override brand fonts

To use a client-specific font family, place font files in:

app/frontend/assets/custom_brand/

Then wire them in:

app/frontend/src/shared/stylesheets/easy/themes/_theme--brand.scss

Process:

  1. Upload font files to app/frontend/assets/custom_brand/ (keep filenames aligned with the mixin calls, for example ComicRelief-Regular.ttf).
  2. Import typography mixins:
@use "../../../../design_system/shared/stylesheets/foundations/typography/_abstracts/_typography.mixins" as typo;
  1. Inside @if map.get($theme__map--brand, brand-enabled), load all required font faces using typo.loadFontFace(..., true).
  2. Apply the font family globally and set font CSS variables used by the theme.

Example:

@mixin generate-brand-themes() {
  @if map.get($theme__map--brand, brand-enabled) {
    @include typo.loadFontFace('Comic Relief', 'ComicRelief-Regular', 400, normal, true);
    @include typo.loadFontFace('Comic Relief', 'ComicRelief-Bold', 700, normal, true);

    html {
      font-family: 'Comic Relief', sans-serif !important;
    }

    :root {
      --easy__font-family--base: 'Comic Relief', sans-serif;
      --easy__font-family--heading: 'Comic Relief', sans-serif;
    }
  }
}

Note: loadFontFace points to both woff2 and ttf sources under @assets/custom_brand. Keep both formats when possible for best compatibility and loading performance.

Override theme color variables

Modify app/frontend/src/shared/stylesheets/easy/themes/_theme--brand.scss:

  1. Keep map name $theme__map--brand (required by theme generation).
  2. Set brand-enabled: true to output brand CSS variables.
  3. Override color keys (-main, -front, -inverse) as needed.
// app/frontend/src/shared/stylesheets/easy/themes/_theme--brand.scss
@use '../utils/helpers/functions' as *;
@use '../utils/helpers/variables/config' as *;
@use '../utils/abstracts/css-variables/create' as *;
@use 'sass:map';

// This one needs to exist as it is used in the mailer theme
$theme__map--brand: (
  brand-enabled: true,
  color: (
    -main: (
        '': prep-color-tints(#75b849),
      ),
    -front: (
        '': prep-color-tints(#ffffff),
      ),
    -inverse: (
        '': prep-color-tints(#1f2937),
      ),
  ),
);

$theme__map--brand-dark: (
  color: (
    -main: (
        '': prep-color-tints(#5f38c3),
      ),
  ),
);

@mixin generate-brand-themes() {
  @if map.get($theme__map--brand, brand-enabled) {
    :root {
      @include generate-css-vars($theme__map--brand, map.get($config, global));
    }
  }

  :root[data-theme*='theme-dark'] {
    @include generate-css-vars($theme__map--brand-dark, map.get($config, global));
  }
}

Dark Theme

To specify settings for the Dark theme, create a map named $theme__map--brand-dark in _theme--brand.scss and place it under the default brand map.

Note: Changes will not be reflected in the contrast theme _theme--contrast.scss, which is specially designed for visually impaired users. This theme is optimized for maximum contrast and readability.

Customizing Account Submenu (Optional)

If you need to adjust account submenu, add or remove buttons, you can do so in menus.rb

```ruby menus.rb

plugins/easyproject/easy_plugins/modification_client/lib/modification_client/menus.rb`

Redmine::MenuManager.map :account_menu do |menu| menu.delete :theme_dark_toggle menu.delete :theme_contrast_toggle end

Then require the `menus.rb` in initializers.

```ruby 02_menu_manager.rb
# plugins/easyproject/easy_plugins/modification_client/config/initializers/02_menu_manager.rb`
Rails.application.config.after_initialize do
  require "modification_client/menus"
end

Theme Key Descriptions

Here are detailed descriptions of the keys in the $theme__map--default map, which influence various aspects of the application's appearance:

Key Elements:

The paths to logos are already defined in the default theme, so there is no need to redefine them.

Font

The font style is defined in the map. Changing the base font size (key font-size) can affect various dimensions across the application, such as spacing, heights, and widths of individual elements.

Colors

Includes basic colors and their shades for text, background, and other elements.

  • Key -main: The main color affects the color scheme of buttons, action elements, hover effects, links, menus, notifications, active elements, the main top bar, and borders of various elements, such as secondary buttons.

  • Key -front: The color of white backgrounds, module backgrounds, and form elements' backgrounds. This color often mixes with other colors, such as background colors for menus.

  • Key -inverse: Used for reverse color logic. It is light for the default theme and dark for the Dark theme. It is used in elements where the color needs to be adjusted based on the background color.

  • Key -mixed: Mixes the -front and -background keys, used in specific application parts such as mind maps, sidebars, and tables.

  • Key -text: Influences text throughout the application and contains text categories such as:

muted: Affects the color of text in disabled form elements, various inactive elements, separators, and some links.\ inverted: Applied in reverse color logic, similar to inverse, but for text.\ light: Uses the color from inverted.\ dark: Basic text color.

Color Palette

Key palette: Contains the base palette -base and other color palettes. The values inside influence multicolored components and are interconnected. They can affect elements like trend cards, charts, tables, mind maps, and WBS.

Other Elements

All components already have all parameters set, such as colors, etc. If you want to further customize the components, you can use additional keys from the default map and adjust them as needed.

When adjusting various sizes, spacings, and areas around elements, it's important to focus on functions that convert units from px to rem, so components adapt correctly based on font size. These functions include:

ms(): This function defines basic spacing sizes. The most commonly used values are ms(0) for basic spacing, ms(2) for medium spacing, and ms(-2) for small spacing. The basic scale ranges from -6 to 12.

px(): This function converts the specified number of pixels to rem and can include negative numbers.

Custom Styles

If you want to add your own styles, always place them in the same file where you define the maps and place them at the end of page.