Skip to content

Commit 8a69b92

Browse files
authored
Merge pull request #473 from cozy/feat/custom-theme
feat: Allow custom overrides in the theme
2 parents c05eec6 + c1d36af commit 8a69b92

File tree

8 files changed

+129
-23
lines changed

8 files changed

+129
-23
lines changed

src/components/Bar.jsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class Bar extends Component {
180180
} = this.state
181181
const {
182182
theme,
183+
themeOverrides,
183184
barLeft,
184185
barRight,
185186
barCenter,
@@ -189,8 +190,17 @@ class Bar extends Component {
189190
onLogOut,
190191
userActionRequired
191192
} = this.props
193+
194+
const {
195+
primaryColor: pColor,
196+
primaryContrastTextColor: pctColor
197+
} = themeOverrides
198+
const pStyle = pColor ? { '--cozBarThemePrimaryColor': pColor } : { }
199+
const pctStyle = pctColor ? { '--cozBarThemePrimaryContrastTextColor': pctColor } : { }
200+
const themeStyle = { ...pStyle, ...pctStyle }
201+
192202
return (
193-
<div className={`coz-bar-wrapper coz-theme-${theme}`}>
203+
<div className={`coz-bar-wrapper coz-theme-${theme}`} style={themeStyle}>
194204
<div id="cozy-bar-modal-dom-place" />
195205
<div className="coz-bar-container">
196206
{barLeft || this.renderLeft()}
@@ -229,7 +239,8 @@ class Bar extends Component {
229239
}
230240

231241
const mapStateToProps = state => ({
232-
theme: getTheme(state),
242+
theme: getTheme(state).name,
243+
themeOverrides: getTheme(state).overrides,
233244
barLeft: getContent(state, 'left'),
234245
barRight: getContent(state, 'right'),
235246
barCenter: getContent(state, 'center'),

src/index.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,18 +252,18 @@ APILocations.forEach(location => {
252252
})
253253

254254
// setLocale API
255-
apiReferences.setLocale = lang => {
255+
apiReferences.setLocale = (...args) => {
256256
if (exposedAPI.setLocale) {
257-
return exposedAPI.setLocale(lang)
257+
return exposedAPI.setLocale(...args)
258258
} else {
259259
showAPIError('setLocale')
260260
}
261261
}
262262

263263
// setTheme API
264-
apiReferences.setTheme = theme => {
264+
apiReferences.setTheme = (...args) => {
265265
if (exposedAPI.setTheme) {
266-
return exposedAPI.setTheme(theme)
266+
return exposedAPI.setTheme(...args)
267267
} else {
268268
showAPIError('setTheme')
269269
}

src/lib/api/index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ export default store => {
8282
methods[getReactApiName(location)] = barContentComponent(store, location)
8383
})
8484

85-
methods.setLocale = lang => {
86-
store.dispatch(setLocale(lang))
85+
methods.setLocale = (...args) => {
86+
store.dispatch(setLocale(...args))
8787
}
8888

89-
methods.setTheme = theme => {
90-
store.dispatch(setTheme(theme))
89+
methods.setTheme = (...args) => {
90+
store.dispatch(setTheme(...args))
9191
}
9292

9393
return methods

src/lib/reducers/theme.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,43 @@ const SET_THEME = 'SET_THEME'
22
const DEFAULT_THEME = 'default'
33
const PRIMARY_THEME = 'primary'
44
const THEMES = [DEFAULT_THEME, PRIMARY_THEME]
5+
const EMPTY_OVERRIDES = {}
56

6-
// action creator
7-
export const setTheme = theme => ({
7+
// Theme state is { name, overrides }
8+
// where both have the form described in `setTheme`
9+
const DEFAULT_STATE = {name: DEFAULT_THEME, overrides: EMPTY_OVERRIDES}
10+
11+
/**
12+
* Change the cozy-bar theme
13+
*
14+
* Today, the value 'primary' will change the background color
15+
* of the bar in the mobile view. It will then use the
16+
* `--primaryColor` CSS variable and the `--primaryContrastTextColor`
17+
* for the text.
18+
*
19+
* @function
20+
* @param {String} name - either 'default' or 'primary'
21+
* @param {Object} overrides - overrides of default values for the theme
22+
* default to an empty object (no overrides)
23+
* It will only overrides the values for the
24+
* 'primary' specific theme/view
25+
* @param {Object} overrides.primaryColor - the background color
26+
* @param {Object} overrides.primaryContrastTextColor - the text color
27+
* @returns {Object} action `{ type: SET_THEME, theme: {name, overrides} }
28+
*/
29+
export const setTheme = (name, overrides=EMPTY_OVERRIDES) => ({
830
type: SET_THEME,
9-
theme
31+
theme: { name, overrides }
1032
})
1133

12-
// reducer
13-
export const getDefaultTheme = () => DEFAULT_THEME
14-
34+
export const getDefaultTheme = () => DEFAULT_STATE
35+
1536
export const reducer = (state = getDefaultTheme(), action) => {
1637
if (action.type === SET_THEME) {
17-
if (THEMES.includes(action.theme)) {
38+
if (THEMES.includes(action.theme.name)) {
1839
return action.theme
1940
}
20-
return DEFAULT_THEME
41+
return {...action.theme, name: DEFAULT_THEME }
2142
} else {
2243
return state
2344
}

src/styles/theme.styl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
12
[role=banner] .coz-bar-wrapper
23
box-shadow inset 0 -1px 0 0 var(--silver)
4+
--cozBarThemePrimaryColor var(--primaryColor)
5+
--cozBarThemePrimaryContrastTextColor var(--primaryContrastTextColor)
36

47
.coz-nav-apps-btns
58
color var(--slateGrey)
@@ -15,8 +18,8 @@
1518
[role=banner] .coz-bar-wrapper
1619
&.coz-theme-primary
1720
box-shadow inherit
18-
background-color var(--primaryColor)
21+
background-color var(--cozBarThemePrimaryColor)
1922

2023
.coz-nav-apps-btns,
2124
.coz-bar-burger
22-
color var(--primaryContrastTextColor)
25+
color var(--cozBarThemePrimaryContrastTextColor)

test/components/Bar.spec.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('Bar', () => {
1717
fetchApps: jest.fn().mockResolvedValue([]),
1818
fetchSettingsData: jest.fn().mockResolvedValue({}),
1919
theme: 'default',
20+
themeOverrides: {},
2021
t: x => x
2122
}
2223
})
@@ -56,6 +57,13 @@ describe('Bar', () => {
5657
expect(toJson(root)).toMatchSnapshot()
5758
})
5859

60+
it('should change allow theme overrides', () => {
61+
const root = shallow(
62+
<Bar {...props} theme="primary" themeOverrides={{primaryColor: 'red'}} />
63+
)
64+
expect(toJson(root)).toMatchSnapshot()
65+
})
66+
5967
it('should display the Searchbar', () => {
6068
const root = shallow(
6169
<Bar {...props} currentApp="Cozy Drive" isPublic={false} />

test/components/__snapshots__/Bar.spec.jsx.snap

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,61 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`Bar should change allow theme overrides 1`] = `
4+
<div
5+
className="coz-bar-wrapper coz-theme-primary"
6+
style={
7+
Object {
8+
"--cozBarThemePrimaryColor": "red",
9+
}
10+
}
11+
>
12+
<div
13+
id="cozy-bar-modal-dom-place"
14+
/>
15+
<div
16+
className="coz-bar-container"
17+
>
18+
<button
19+
className="coz-bar-btn coz-bar-burger"
20+
data-tutorial="apps-mobile"
21+
onClick={[Function]}
22+
type="button"
23+
>
24+
<Icon
25+
height={16}
26+
icon="test-file-stub"
27+
spin={false}
28+
width={16}
29+
/>
30+
<span
31+
className="coz-bar-hidden"
32+
>
33+
drawer
34+
</span>
35+
</button>
36+
<Apps />
37+
<div
38+
className="u-flex-grow"
39+
/>
40+
<Wrapper
41+
toggleSupport={[Function]}
42+
/>
43+
<Connect(Drawer)
44+
drawerListener={[Function]}
45+
isClaudyLoading={false}
46+
onClaudy={false}
47+
onClose={[Function]}
48+
toggleSupport={[Function]}
49+
visible={false}
50+
/>
51+
</div>
52+
</div>
53+
`;
54+
355
exports[`Bar should change theme 1`] = `
456
<div
557
className="coz-bar-wrapper coz-theme-primary"
58+
style={Object {}}
659
>
760
<div
861
id="cozy-bar-modal-dom-place"
@@ -50,6 +103,7 @@ exports[`Bar should change theme 1`] = `
50103
exports[`Bar should display the Searchbar 1`] = `
51104
<div
52105
className="coz-bar-wrapper coz-theme-default"
106+
style={Object {}}
53107
>
54108
<div
55109
id="cozy-bar-modal-dom-place"
@@ -101,6 +155,7 @@ exports[`Bar should display the Searchbar 1`] = `
101155
exports[`Bar should not display searchbar if we are not on a public page 1`] = `
102156
<div
103157
className="coz-bar-wrapper coz-theme-default"
158+
style={Object {}}
104159
>
105160
<div
106161
id="cozy-bar-modal-dom-place"
@@ -121,6 +176,7 @@ exports[`Bar should not display searchbar if we are not on a public page 1`] =
121176
exports[`Bar should not display searchbar if we are not on Cozy Drive 1`] = `
122177
<div
123178
className="coz-bar-wrapper coz-theme-default"
179+
style={Object {}}
124180
>
125181
<div
126182
id="cozy-bar-modal-dom-place"
@@ -170,6 +226,7 @@ exports[`Bar should not display searchbar if we are not on Cozy Drive 1`] = `
170226
exports[`Bar should not display searchbar if we are on mobile 1`] = `
171227
<div
172228
className="coz-bar-wrapper coz-theme-default"
229+
style={Object {}}
173230
>
174231
<div
175232
id="cozy-bar-modal-dom-place"

test/lib/api.spec.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,16 @@ describe('api spec', function() {
114114
it('should set theme', function() {
115115
const { setTheme } = api
116116
// default theme is `default`
117-
expect(store.getState().theme).toBe('default')
117+
expect(store.getState().theme.name).toBe('default')
118+
expect(store.getState().theme.overrides).toEqual({})
118119
setTheme('primary')
119-
expect(store.getState().theme).toBe('primary')
120+
expect(store.getState().theme.name).toBe('primary')
121+
expect(store.getState().theme.overrides).toEqual({})
122+
setTheme('primary', { primaryColor: 'red' })
123+
expect(store.getState().theme.name).toBe('primary')
124+
expect(store.getState().theme.overrides).toEqual({ primaryColor: 'red' })
120125
setTheme('wrongTheme')
121-
expect(store.getState().theme).toBe('default')
126+
expect(store.getState().theme.name).toBe('default')
127+
expect(store.getState().theme.overrides).toEqual({})
122128
})
123129
})

0 commit comments

Comments
 (0)