Skip to content
esr360 edited this page Feb 14, 2020 · 13 revisions

One of the most powerful features of Synergy is the ability to create themes. Themes are used to create distinctly separate UI's using a combination of modules and custom configuration, without modifying any source code.

A theme is a JavaScript/JSON object that should contain things like:

  • Reusable colors
  • Reusable font-sizes, font-styles etc.
  • Style patterns (vertical-rhythm, positioning etc.)
Page Index

Creating a Theme

Themes can exist either as JSON or JavaScript files. If your theme exists as a JavaScript file, it must export an object.

Synergy recommends keeping your themes inside a themes directory that exists alongside the modules directory.

|-- modules
|   |   ...
|-- themes
|   |-- myTheme.js
|   |   ...

Core Theme

A Core Theme is a base theme on which subsequent themes are built. Subsequently, a theme utilising a Core Theme may resemble:

import deepextend from 'deep-extend';
import core from './core';

export default deepextend(core, {
  ...
});

deep-extend is a dependency of Synergy so can be freely imported

As you can see, there is no special functionality around using a Core Theme; it is merely merged with a new theme that wishes to use it.

Core Themes are useful when your different themes would other duplicate several/many values. A Core Theme can also serve as a default theme if no other themes can be found/are used.

Accessing Theme Properties From Within the Theme

Sometimes you may wish to access values of the theme from witin the theme itself. This is possible by passing the value as a function with a theme parameter (which can be destructrued as in the below example):

export default {
  spacing: '1em',
  colors: {
    primary: '#1E90FF',
    secondary: '#00FFB2',
    tertiary: '#01BFFF'
  },
  typography: {
    primaryFont: 'sans-serif',
    textColor: '#444444'
  },
  tokens: {
    background: ({ colors }) => colors.primary,
    margin: theme => theme.gutter
  },
  modules: {
    Accordion: {
      title: {
        background: ({ colors }) => colors.tertiary
      }
    }
  }
}

All values will be evaluated by the time you use them in your Modules

Using a Theme

Passing Via <Provider>/<Container>

A theme can be provided to your Modules using either the <Provider> or <Container> Components, by passing the theme to the theme prop:

import React from 'react';
import { Provider } from '@onenexus/synergy';
import theme from './themes/myTheme.js';
import MyModule from './modules/MyModule';

const App = () => (
  <Provider theme={theme}>
    <MyModule />
  </Provider>
);

Passing Manually

If a theme already exists, the theme you pass here will be merged with the existing theme

import React from 'react';
import { Module } from '@onenexus/synergy';
import theme from '../../themes/myTheme';
import config from './config';
import layout from './layout';

export default (props) => (
  <Module name='MyModule' theme={theme} styles={styles} config={config} {...props}>
    {props.children}
  </Module>
);

Accessing In Module Styles/Layout

/modules/MyModule/layout.js

Note that you can also expose some other useful objects to the Module's styles

export default ({ theme }) => ({
  ...
});

Accessing In Module Config (Learn More)

/modules/MyModule/config.js
export default (theme) => ({
  ...
});

Accessing in Module's JSX

This requires the theme to have been provided by either the <Provider> or <Container> Component

/modules/MyModule/index.js
import React from 'react';
import { Module, useTheme } from '@onenexus/synergy';
import config from './config';
import layout from './layout';

export default (props) => {
  const theme = useTheme();

  // do something with `theme`

  return (
    <Module name='MyModule' styles={styles} config={config} {...props}>
      {props.children}
    </Module>
  );
}
/modules/MyModule/index.js

Note that using a render function with <Module> also exposes some other useful objects

import React from 'react';
import { Module } from '@onenexus/synergy';
import config from './config';
import layout from './layout';

export default (props) => (
  <Module name='MyModule' styles={styles} config={config} {...props}>
    {({ theme }) => {
    // do something with `theme`

      return props.children;
    }}
  </Module>
);

Overriding Module Configuration

You can override a module's default configuration by creating a modules object within the theme object.

You must pass a name prop when using <Module> to utilise this feature

/themes/myTheme.js
const theme = {
  colors: {
    primary: 'red',
    secondary: 'blue'
  }
  modules: {
    MyModule: {
      // You can access the theme's properties by using a function
      // with a `theme` parameter, they will be evaluated before being
      // exposed to your styles (so no need to manually evaluate)
      someProp: (theme) => theme.colors.secondary,

      MyComponent: {
        fontFamily: 'Comic Sans MS'
      }
    }
  }
}
/modules/MyModule/config.js
export default {
  someProp: 'purple'
}
/modules/MyModule/styles.js
export default ({ config }) => ({
  color: config.someProp // will be 'blue' (theme.colors.secondary)
});
/modules/MyModule/index.js
import React from 'react';
import { Module, Component } from '@onenexus/synergy';
import theme from '../../themes/myTheme';
import config from './config';
import styles from './styles';

const MyModule = () => (
  <Module name='MyModule' styles={styles} config={config} theme={theme}>
    <Component name='MyComponent'>
      This Component will be 'Comic Sans MS'
    </Component>
    ...
  </Module>
);

Combined with the dynamic cosmetic properties feature, this allows you to create distinctly different versions of the same Module without changing the source code.