Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theming support #428 #1360

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions addons/options/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ import * as storybook from '@storybook/react';
import { setOptions } from '@storybook/addon-options';

setOptions({
name: 'My Storybook',
url: 'https://example.com',
goFullScreen: false,
showLeftPanel: false,
showDownPanel: false,
showSearchBox: false,
downPanelInRight: false,
sortStoriesByKind: false,
name: 'My Component', // change the name displayed in the left top portion
url: 'https://github.com/user/my-component', // change its URL
goFullScreen: false, // switch to fullscreen mode
showLeftPanel: false, // show the stories panel
showDownPanel: false, // show the addons panel
showSearchBox: false, // show the search box
downPanelInRight: false, // show the addons panel at the right side
sortStoriesByKind: true, // Sort the list of stories by their "kind"
currentTheme: 'default', // set theme of UI appearance ('default', 'dark')
});

storybook.configure(() => require('./stories'), module);
Expand Down
2 changes: 0 additions & 2 deletions examples/cra-kitchen-sink/src/base.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
:root {
background: rgba(232,232,232,1);
background: radial-gradient(ellipse at center, rgba(255,255,255,1) 11%,rgba(232,232,232,1) 100%);
height: 100%;
}
12 changes: 12 additions & 0 deletions examples/cra-kitchen-sink/src/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import EventEmiter from 'eventemitter3';

import { storiesOf } from '@storybook/react';
import { setOptions } from '@storybook/addon-options';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
import WithEvents from '@storybook/addon-events';
Expand Down Expand Up @@ -154,3 +155,14 @@ storiesOf('WithEvents', module)
</WithEvents>
)
.add('Logger', () => <Logger emiter={emiter} />);

storiesOf('Theming', module)
.addDecorator(centered)
.add('Default', () => {
setOptions({currentTheme: 'default'});
return <Button style={{backgroundColor: 'rgba(128,128,120,0.1)'}} >Default (white) Theme</Button>;
})
.add('Dark', () => {
setOptions({currentTheme: 'dark'});
return <Button style={{backgroundColor: 'rgba(128,128,120,0.5)'}} >Dark Theme</Button>;
})
12 changes: 11 additions & 1 deletion lib/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,13 @@ class ReactProvider extends Provider {
api.setOptions({
name: 'My Component', // change the name displayed in the left top portion
url: 'https://github.com/user/my-component', // change its URL
sortStoriesByKind: true // Sort the list of stories by their "kind"
goFullScreen: false, // switch to fullscreen mode
showLeftPanel: false, // show the stories panel
showDownPanel: false, // show the addons panel
showSearchBox: false, // show the search box
downPanelInRight: false, // show the addons panel at the right side
sortStoriesByKind: true, // Sort the list of stories by their "kind"
currentTheme: 'default', // set theme of UI appearance ('default', 'dark')
});
}
};
Expand Down Expand Up @@ -193,3 +199,7 @@ The above action(or the `handleShortcut` method) accepts events as a constant de
We are not using any routing library. That's because, we don't want to do routing, but wanted to add some query params and use them.

Routing logic is implemented in the `src/modules/ui/configs/handle_routing.js` configuration.

### Theming

Theming is implemented in the `theming` module (`src/modules/theming`). `genPoddaLoader` adds the current theme to the data passed to components and it's available as a `theme` prop. Themes are stored in `src/modules/theming/themes/*.js` files. We set the current theme by `uiOptions.currentTheme` prop. The default value is set to `default` in `src/modules/api/index.js` and could be overridden via `setOptions({ currentTheme: 'default' });` on the preview side.
3 changes: 3 additions & 0 deletions lib/ui/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import buildContext from './context';
import shortcutsModule from './modules/shortcuts';
import apiModule from './modules/api';
import uiModule from './modules/ui';
import themingModule from './modules/theming';
import { setContext, setActions } from './compose';

export class Provider {
Expand All @@ -26,6 +27,7 @@ export default function(domNode, provider) {
...shortcutsModule.defaultState,
...apiModule.defaultState,
...uiModule.defaultState,
...themingModule.defaultState,
};
const clientStore = new Podda(defaultState);
clientStore.registerAPI('toggle', (store, key) => store.set(key, !store.get(key)));
Expand All @@ -36,6 +38,7 @@ export default function(domNode, provider) {
app.loadModule(shortcutsModule);
app.loadModule(apiModule);
app.loadModule(uiModule);
app.loadModule(themingModule);

setContext(context);
setActions(app._bindContext(app.actions)); // eslint-disable-line
Expand Down
1 change: 1 addition & 0 deletions lib/ui/src/modules/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
name: 'STORYBOOK',
url: 'https://github.com/storybooks/storybook',
sortStoriesByKind: false,
currentTheme: 'default',
},
},
load({ clientStore, provider }, _actions) {
Expand Down
5 changes: 5 additions & 0 deletions lib/ui/src/modules/theming/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import theming from './theming';

export default {
theming,
};
86 changes: 86 additions & 0 deletions lib/ui/src/modules/theming/actions/theming.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Podda from 'podda';

const themesStore = new Podda({});

/**
* themesStore - simple podda store with all "build-in" themes (located in modules/theming/themes/*.js)
* we require them dynamically onLoad
*
* this module provides API:
*
* - selectTheme(themeName: string) selects the current theme
*
* - getTheme(): object returns current theme object
*
* - getThemesList(): arrayOf(strings) returns names of loaded themes
*
* - setTheme(theme: object) adds new or updates existing theme
*
* Usage:
*
* We don't store themes data in clientStore directly, we provide getTheme() API instead
* All containers (modules/ui/containers) passes current theme data to components automatically via `gen_podda_loader`
* it's available inside (root) components as `this.props.theme`
*
*/

const reqThemes = require.context('../themes/', true, /.js$/);
reqThemes.keys().forEach((filename) => {
const theme = reqThemes(filename).default;
themesStore.set(theme.name, theme);
});



themesStore.registerAPI('keys', (store) => {
const keys = Object.keys(store.getAll());
return keys;
});

themesStore.registerAPI('includes', (store, themeName) => {
if (store.keys().indexOf(themeName) > -1) {
return true;
}
return false;
});

export function updateThemesList(clientStore) {
const themingOptions = clientStore.get('themingOptions');
themingOptions.themesList = themesStore.keys();
clientStore.set('themingOptions', themingOptions);
}

function ensureTheme(currentTheme, themeName) {
if (themesStore.includes(themeName)) {
return themeName;
}
return currentTheme;
}

function setTheme(theme) {
const themeName = theme.name = theme.name || 'Theme ' + themesStore.keys.length;
themesStore.set(themeName, theme);
return theme;
}

export default {
selectTheme({ clientStore }, themeName) {
const uiOptions = clientStore.get('uiOptions');
uiOptions.currentTheme = ensureTheme(clientStore.get('currentTheme'), themeName);
clientStore.set('uiOptions', uiOptions);
},

getTheme({ clientStore }) {
var themeName = clientStore.get('uiOptions').currentTheme;
return themesStore.get(themeName);
},

getThemesList({ clientStore }) {
return clientStore.get('themingOptions').themesList;
},

setTheme({ clientStore }, theme) {
setTheme(theme);
updateThemesList(clientStore);
}
};
7 changes: 7 additions & 0 deletions lib/ui/src/modules/theming/configs/init_themes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { themesMap, updateThemesList } from '../actions/theming';


export default function(clientStore, actions) {
updateThemesList(clientStore);
}

39 changes: 39 additions & 0 deletions lib/ui/src/modules/theming/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import actions from './actions';
import init_themes from './configs/init_themes';

export default {
actions,
defaultState: {
themingOptions: {
themesList: [],
},
/**
* Also theming module depends on defaultState.uiOptions.currentTheme = 'default'
* see src/modules/api/index.js
*/
},
load({clientStore}, _actions) {
init_themes(clientStore, _actions);

/**
* Debug:
* uncomment the line below to get access to API via browser console
*/
// console.log('UI API:', _actions);
/**
* right click on 'UI API:' and 'Store as GlobalVariable'
* api = temp1;
* api.theming.getTheme();
* api.theming.selectTheme('dark');
* newTheme = api.theming.getTheme();
* newTheme.name = 'new';
* api.theming.setTheme(newTheme);
* api.theming.getThemesList();
* api.theming.selectTheme('new');
* newTheme.palette.canvas = 'green';
* newTheme.palette.background = 'darkgreen';
*
*/
}
};

25 changes: 25 additions & 0 deletions lib/ui/src/modules/theming/themes/dark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import white from './default';

export default {
...white,
name: 'dark',
palette: {
background: '#585858',
border: '#898989',
canvas: '#333333',
text: '#d6d6d6',


secondaryBorder: '#777777',
secondaryText: '#ffffff',
secondaryBackground: '#585858',

filterBackground: '#464646',

logoText: '#d2d2d2',
logoBorder: '#c1c1c1',

resizerColor: 'rgba(1, 1, 1, 0.0980392)',
resizerBackground: '#4a4a4a',
},
};
32 changes: 32 additions & 0 deletions lib/ui/src/modules/theming/themes/default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

export default {
name: 'default',
palette: {
/* Main color settings */
background: '#f7f7f7' /* background of panels */,
border: '#eeeeee' /* border like in the stories list */,
canvas: 'white' /* preview area */,
text: '#444444' /* active text in panels */,

secondaryBorder: '#eaeaea' /* border like in the addons panel */,
secondaryText: 'black',
secondaryBackground: 'white' /* addons area */,

logoText: '#828282' /* text in logo */,
logoBorder: '#c1c1c1' /* border of logo */,

filterBackground: 'white',

resizerColor: 'rgba(0, 0, 0, 0.0980392)' /* grips in resizers */,
resizerBackground: '#f7f7f7',
},
style: {
/* other styling settings */
inactiveOpacity: 0.5,
},
spacing: {
/* default spacing settings */
leftPanelSize: 100,
downPanelSize: 100,
},
};
13 changes: 7 additions & 6 deletions lib/ui/src/modules/ui/components/down_panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import style from './style';

class DownPanel extends Component {
renderTab(name, panel) {
let tabStyle = style.tablink;
let tabStyle = style(this.props.theme).tablink;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you'll define the style once, instead of creating it in each call ?
something like

import commonStyle from './style';
/**/
const style = commonStyle(this.props.theme); 
// in this case you will have less conflicts and irrelevant changes 
/**/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (this.props.selectedPanel === name) {
tabStyle = Object.assign({}, style.tablink, style.activetab);
tabStyle = Object.assign({}, style(this.props.theme).tablink, style(this.props.theme).activetab);
}

const onClick = () => e => {
Expand Down Expand Up @@ -46,7 +46,7 @@ class DownPanel extends Component {

renderEmpty() {
return (
<div style={style.empty}>
<div style={style(this.props.theme).empty}>
no panels available
</div>
);
Expand All @@ -57,9 +57,9 @@ class DownPanel extends Component {
return this.renderEmpty();
}
return (
<div style={style.wrapper}>
<div style={style.tabbar} role="tablist">{this.renderTabs()}</div>
<div style={style.content}>{this.renderPanels()}</div>
<div style={style(this.props.theme).wrapper}>
<div style={style(this.props.theme).tabbar} role="tablist">{this.renderTabs()}</div>
<div style={style(this.props.theme).content}>{this.renderPanels()}</div>
</div>
);
}
Expand All @@ -75,6 +75,7 @@ DownPanel.propTypes = {
panels: PropTypes.object, // eslint-disable-line react/forbid-prop-types
onPanelSelect: PropTypes.func,
selectedPanel: PropTypes.string,
theme: PropTypes.shape().isRequired,
};

export default DownPanel;
12 changes: 7 additions & 5 deletions lib/ui/src/modules/ui/components/down_panel/style.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { baseFonts } from '../theme';

export default {
export default theme => ({
empty: {
flex: 1,
display: 'flex',
...baseFonts,
Copy link
Member

@igor-dv igor-dv Jul 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't base font be in the theme ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

color: theme.palette.text,
fontSize: 11,
letterSpacing: '1px',
textTransform: 'uppercase',
Expand All @@ -16,9 +17,9 @@ export default {
flex: 1,
display: 'flex',
flexDirection: 'column',
background: 'white',
background: theme.palette.canvas,
borderRadius: 4,
border: 'solid 1px rgb(236, 236, 236)',
border: `solid 1px ${theme.palette.border}`,
marginTop: 5,
width: '100%',
},
Expand All @@ -29,7 +30,7 @@ export default {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
borderBottom: 'solid 1px #eaeaea',
borderBottom: `solid 1px ${theme.palette.secondaryBorder}`,
},

content: {
Expand All @@ -40,6 +41,7 @@ export default {

tablink: {
...baseFonts,
color: theme.palette.text,
fontSize: 11,
letterSpacing: '1px',
padding: '10px 15px',
Expand All @@ -55,4 +57,4 @@ export default {
activetab: {
opacity: 1,
},
};
});
Loading