Skip to content

Instantly share code, notes, and snippets.

@gmac
Last active December 21, 2018 20:13
Show Gist options
  • Save gmac/852b8d8c6b1f086323876239abd90faa to your computer and use it in GitHub Desktop.
Save gmac/852b8d8c6b1f086323876239abd90faa to your computer and use it in GitHub Desktop.

First, the design system gets broken down into three parts: palette, theme, and config.

Palette

A palette is a set of values that admins can manage directly. Palette fields accept raw input (numbers, hex codes, etc). A palette would look like this:

palette = {
  "color1-faded": "#xxx",
  "color1-light": "#xxx",
  "color1-bright": "#xxx",
  "color1-main": "#xxx",
  "color1-dark": "#xxx",

  "color2-faded": "#xxx",
  "color2-light": "#xxx",
  "color2-bright": "#xxx",
  "color2-main": "#xxx",
  "color2-dark": "#xxx",

  "color3-faded": "#xxx",
  "color3-light": "#xxx",
  "color3-bright": "#xxx",
  "color3-main": "#xxx",
  "color3-dark": "#xxx",

  "color4-faded": "#xxx",
  "color4-light": "#xxx",
  "color4-bright": "#xxx",
  "color4-main": "#xxx",
  "color4-dark": "#xxx",

  "neutral-white": "#xxx",
  "neutral-gray05": "#xxx",
  "neutral-gray10": "#xxx",
  "neutral-gray30": "#xxx",
  "neutral-gray40": "#xxx",
  "neutral-gray60": "#xxx",
  "neutral-gray70": "#xxx",
  "neutral-gray80": "#xxx",
  "neutral-gray90": "#xxx",
  "neutral-black": "#xxx",
}

Theme

The second half of the design system is a theme. Theme is a schema that holds keys of palette values. A theme value never holds a raw value, it always references a field out of the palette.

theme = {
  "brand-color": <palette.keys>,
  "brand-color-tint": <palette.keys>,

  "white-mode-primary-foreground": <palette.keys>,
  "white-mode-secondary-foreground": <palette.keys>,
  "white-mode-accent": <palette.keys>,
  "white-mode-hover": <palette.keys>,
  "white-mode-ui": <palette.keys>,
  "white-mode-button": <palette.keys>,
  "white-mode-background": <palette.keys>,

  "black-mode-primary-foreground": <palette.keys>,
  "black-mode-secondary-foreground": <palette.keys>,
  "black-mode-accent": <palette.keys>,
  "black-mode-hover": <palette.keys>,
  "black-mode-ui": <palette.keys>,
  "black-mode-button": <palette.keys>,
  "black-mode-background": <palette.keys>,

  "light-mode-primary-foreground": <palette.keys>,
  "light-mode-secondary-foreground": <palette.keys>,
  "light-mode-accent": <palette.keys>,
  "light-mode-hover": <palette.keys>,
  "light-mode-ui": <palette.keys>,
  "light-mode-button": <palette.keys>,
  "light-mode-background": <palette.keys>,

  "dark-mode-primary-foreground": <palette.keys>,
  "dark-mode-secondary-foreground": <palette.keys>,
  "dark-mode-accent": <palette.keys>,
  "dark-mode-hover": <palette.keys>,
  "dark-mode-ui": <palette.keys>,
  "dark-mode-button": <palette.keys>,
  "dark-mode-background": <palette.keys>,
}

With this breakdown, it becomes relatively straight forward to render a hash of theme values populated with palette fields.

Config

Lastly, we get to configuration. This is where theme settings are mapped to actual frontend components. This looks a lot like site config settings as they exist now. Style config settings can select from characteristics of the theme schema. For example:

config = {
  "sidebar-widget-theme-mode": <"light-mode", "dark-mode", ...>,
  "breaker-bar-theme-mode": "dark-mode"
}

Implementation

Now the implementation will need to be managed at several levels.

SASS

In SCSS, variables would need to be defined as composite fields. These would accept config references and other partial namespace references.

background-color: composite-var(--sidebar-widget-theme-mode, "background");

CSS

When rendered as CSS, these composite values simply get a recognizable token format that would allow for post-processing.

background-color: COMPOSITE____sidebar_widget_theme_mode____background;

ERB

Now when our proprietary Webpack plugin runs to transform the CSS into ERB, we'd simply recognize these larger token patterns and write them as template functions into the ERB markup.

background-color: <%= composite_var(@theme[:sidebar_widget_theme_mode], "background") %>

Ruby

Finally, Ruby render context adds corresponding view helper methods that would allow variables to be assembled into dynamic references at runtime. This would allow for, say, "light-mode" to be read from component config, namespaced as "light-mode-background" by the template function, and then reference the precompiled value from theme data.

def composite_var(prefix, namespace)
  @theme["#{prefix}_#{namespace}"]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment