Skip to content

Commit

Permalink
feat #92 - Theming (#97)
Browse files Browse the repository at this point in the history
* feat #92 - Theming

* fix #104 - Fix exported types for table and form
  • Loading branch information
sam-dassana authored Oct 9, 2020
1 parent cca500d commit 0f81ad2
Show file tree
Hide file tree
Showing 28 changed files with 2,230 additions and 1,440 deletions.
38 changes: 38 additions & 0 deletions .storybook/Decorator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { FC, ReactNode } from 'react'
import { createUseStyles } from 'react-jss'
import { ThemeType, themes } from '../src/components/assets/styles/themes'
import cn from 'classnames'
const { dark } = ThemeType

const useStyles = createUseStyles({
'@global': {
[`.${dark} .decorator`]: {
backgroundColor: themes[dark].background.secondary
}
},
decorator: {
padding: '1rem'
}
})

export interface DecoratorProps {
children: ReactNode
classes?: string[]
}

const Decorator: FC<DecoratorProps> = ({
children,
classes = []
}: DecoratorProps) => {
const decoratorClasses = useStyles()

return (
<div
className={cn(decoratorClasses.decorator, 'decorator', ...classes)}
>
{children}
</div>
)
}

export default Decorator
13 changes: 13 additions & 0 deletions .storybook/__tests__/Decorator.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import Decorator, { DecoratorProps } from '../Decorator'
import { shallow, ShallowWrapper } from 'enzyme'

let wrapper: ShallowWrapper<DecoratorProps>

describe('Decorator', () => {
it('renders', () => {
wrapper = shallow(<Decorator>Decorator</Decorator>)

expect(wrapper).toHaveLength(1)
})
})
18 changes: 14 additions & 4 deletions .storybook/index.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
/* This is the global dassana stylesheet. It should match the global stylesheet in web-orchestrator. */

@import '~normalize.css';
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');

body {
font-family: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
html,
body,
#root,
.App {
font-family: 'Inter', sans-serif;
height: 100%;
}

/* Storybook styles */

.sb-show-main {
/* For side-by-side theme view */
padding: 0 !important;
}
3 changes: 2 additions & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-actions',
'@storybook/preset-create-react-app'
'@storybook/preset-create-react-app',
'@storybook/addon-cssresources'
]
}
1 change: 0 additions & 1 deletion .storybook/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ addons.setConfig({
sidebarAnimations: true,
enableShortcuts: true,
isToolshown: true,
theme: undefined,
selectedPanel: 'Controls',
initialActive: 'sidebar',
showRoots: false
Expand Down
23 changes: 0 additions & 23 deletions .storybook/preview.ts

This file was deleted.

161 changes: 161 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import './index.css'
import cn from 'classnames'
import document from 'global/document'
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'
import isChromatic from 'chromatic/isChromatic'
import { Story } from '@storybook/react/types-6-0'
import { StoryContext } from '@storybook/addons'
import {
themes,
Theme,
ThemeType
} from '../src/components/assets/styles/themes'
import { createUseStyles, ThemeProvider, useTheme } from 'react-jss'
import { withCssResources } from '@storybook/addon-cssresources'
import React, { FC, ReactNode, useEffect } from 'react'

enum LayoutTypes {
sideBySide = 'side-by-side',
left = 'left',
right = 'right'
}

const { sideBySide, left, right } = LayoutTypes

const { dark, light } = ThemeType

const useStyles = createUseStyles({
storyContainer: {
display: 'flex'
},
storyWrapper: {
padding: '1rem'
}
})

const useStylesWithTheme = createUseStyles({
themeBlock: {
background: ({ theme }: { theme: Theme }) => theme.background.primary,
height: '100vh',
left: props => (props.side === left ? 0 : '50vw'),
overflow: 'auto',
right: props => (props.side === right ? '50vw' : 0),
width: '50vw'
}
})

const ThemedCanvasBg = () => {
const theme: Theme = useTheme()

useEffect(() => {
document.body.style.background = theme.background.primary
})

return null
}

interface StoryWrapperProps {
children: ReactNode
dark?: boolean
}
/*
This wrapper does two things:
1. Adds padding to the story since it was removed from .sb-show-main in ./index.css
2. Toggles 'dark' theme class
*/
const StoryWrapper: FC<StoryWrapperProps> = ({
children,
dark = false
}: StoryWrapperProps) => {
const classes = useStyles()
const wrapperClasses = cn({
dark,
[classes.storyWrapper]: true
})

return <div className={wrapperClasses}>{children}</div>
}

interface ThemedBlockProps {
children: ReactNode
side: LayoutTypes.left | LayoutTypes.right
}
/* This adds a wrapper to style the left and right blocks for side-by-side viewing of dark and light themes. */
const ThemedBlock: FC<ThemedBlockProps> = ({
children,
...props
}: ThemedBlockProps) => {
const theme = useTheme()
const classes = useStylesWithTheme({ ...props, theme })
const { side } = props

return (
<div className={classes.themeBlock}>
<StoryWrapper dark={side === right}>{children}</StoryWrapper>
</div>
)
}

/* This is the decorator that wraps the stories with a theme provider and a wrapper div for side-by-side view. */
const ThemeDecorator = (
ComponentStory: Story,
{ globals: { theme = light } }: StoryContext
) => {
const classes = useStyles()

switch (theme) {
case sideBySide: {
return (
<div className={classes.storyContainer}>
<ThemeProvider theme={themes[light]}>
<ThemedBlock side={left}>
<ComponentStory />
</ThemedBlock>
</ThemeProvider>
<ThemeProvider theme={themes[dark]}>
<ThemedBlock side={right}>
<ComponentStory />
</ThemedBlock>
</ThemeProvider>
</div>
)
}

default: {
return (
<ThemeProvider theme={themes[theme]}>
<ThemedCanvasBg />
<StoryWrapper dark={theme === dark}>
<ComponentStory />
</StoryWrapper>
</ThemeProvider>
)
}
}
}

export const globalTypes = {
theme: {
/* Setting side-by-side as default for chromatic allows for visual regression testing on both dark and light themed stories. */
defaultValue: isChromatic() ? sideBySide : light,
description: 'Global theme for components',
name: 'Theme',
toolbar: {
icon: 'circlehollow',
items: [
{ icon: 'circlehollow', title: light, value: light },
{ icon: 'circle', title: dark, value: dark },
{
icon: 'sidebar',
title: 'side by side',
value: sideBySide
}
]
}
},
viewport: {
viewports: INITIAL_VIEWPORTS
}
}

export const decorators = [withCssResources, ThemeDecorator]
Loading

0 comments on commit 0f81ad2

Please sign in to comment.