Add a design system (#34)
* Add theming system * Add standard Button control and update RadioButtons * Unify radiobutton with design system * Update debug screen to have multiple views * Add ToggleButton * Update error controls to use design system * Add typography to <Text> element * Move DropdownButton into the design system * Clean out old code * Move Text into design system * Add 'inverted' color palette * Move LoadingPlaceholder into the design system
This commit is contained in:
parent
cc63660982
commit
7e31645e9a
78 changed files with 1431 additions and 375 deletions
70
src/view/lib/ThemeContext.tsx
Normal file
70
src/view/lib/ThemeContext.tsx
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import React, {createContext, useContext, useMemo} from 'react'
|
||||
import {TextStyle, useColorScheme, ViewStyle} from 'react-native'
|
||||
import {darkTheme, defaultTheme} from './themes'
|
||||
|
||||
export type ColorScheme = 'light' | 'dark'
|
||||
|
||||
export type PaletteColorName =
|
||||
| 'default'
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'inverted'
|
||||
| 'error'
|
||||
export type PaletteColor = {
|
||||
isLowContrast: boolean
|
||||
background: string
|
||||
backgroundLight: string
|
||||
text: string
|
||||
textLight: string
|
||||
textInverted: string
|
||||
link: string
|
||||
border: string
|
||||
icon: string
|
||||
}
|
||||
export type Palette = Record<PaletteColorName, PaletteColor>
|
||||
|
||||
export type ShapeName = 'button' | 'bigButton' | 'smallButton'
|
||||
export type Shapes = Record<ShapeName, ViewStyle>
|
||||
|
||||
export type TypographyVariant =
|
||||
| 'h1'
|
||||
| 'h2'
|
||||
| 'h3'
|
||||
| 'h4'
|
||||
| 'subtitle1'
|
||||
| 'subtitle2'
|
||||
| 'body1'
|
||||
| 'body2'
|
||||
| 'button'
|
||||
| 'caption'
|
||||
| 'overline'
|
||||
export type Typography = Record<TypographyVariant, TextStyle>
|
||||
|
||||
export interface Theme {
|
||||
colorScheme: ColorScheme
|
||||
palette: Palette
|
||||
shapes: Shapes
|
||||
typography: Typography
|
||||
}
|
||||
|
||||
export interface ThemeProviderProps {
|
||||
theme?: ColorScheme
|
||||
}
|
||||
|
||||
export const ThemeContext = createContext<Theme>(defaultTheme)
|
||||
|
||||
export const useTheme = () => useContext(ThemeContext)
|
||||
|
||||
export const ThemeProvider: React.FC<ThemeProviderProps> = ({
|
||||
theme,
|
||||
children,
|
||||
}) => {
|
||||
const colorScheme = useColorScheme()
|
||||
|
||||
const value = useMemo(
|
||||
() => ((theme || colorScheme) === 'dark' ? darkTheme : defaultTheme),
|
||||
[colorScheme, theme],
|
||||
)
|
||||
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import {useState} from 'react'
|
||||
import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native'
|
||||
import {RootStoreModel} from '../../state'
|
||||
import {RootStoreModel} from '../../../state'
|
||||
|
||||
export type OnScrollCb = (
|
||||
event: NativeSyntheticEvent<NativeScrollEvent>,
|
||||
41
src/view/lib/hooks/usePalette.ts
Normal file
41
src/view/lib/hooks/usePalette.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import {TextStyle, ViewStyle} from 'react-native'
|
||||
import {useTheme, PaletteColorName, PaletteColor} from '../ThemeContext'
|
||||
|
||||
export interface UsePaletteValue {
|
||||
colors: PaletteColor
|
||||
view: ViewStyle
|
||||
border: ViewStyle
|
||||
text: TextStyle
|
||||
textLight: TextStyle
|
||||
textInverted: TextStyle
|
||||
link: TextStyle
|
||||
}
|
||||
export function usePalette(color: PaletteColorName): UsePaletteValue {
|
||||
const palette = useTheme().palette[color]
|
||||
return {
|
||||
colors: palette,
|
||||
view: {
|
||||
backgroundColor: palette.background,
|
||||
},
|
||||
border: {
|
||||
borderWidth: 1,
|
||||
borderColor: palette.border,
|
||||
},
|
||||
text: {
|
||||
color: palette.text,
|
||||
fontWeight: palette.isLowContrast ? '500' : undefined,
|
||||
},
|
||||
textLight: {
|
||||
color: palette.textLight,
|
||||
fontWeight: palette.isLowContrast ? '500' : undefined,
|
||||
},
|
||||
textInverted: {
|
||||
color: palette.textInverted,
|
||||
fontWeight: palette.isLowContrast ? '500' : undefined,
|
||||
},
|
||||
link: {
|
||||
color: palette.link,
|
||||
fontWeight: palette.isLowContrast ? '500' : undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
163
src/view/lib/themes.ts
Normal file
163
src/view/lib/themes.ts
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import type {Theme} from './ThemeContext'
|
||||
import {colors} from './styles'
|
||||
|
||||
export const defaultTheme: Theme = {
|
||||
colorScheme: 'light',
|
||||
palette: {
|
||||
default: {
|
||||
isLowContrast: false,
|
||||
background: colors.white,
|
||||
backgroundLight: colors.gray2,
|
||||
text: colors.black,
|
||||
textLight: colors.gray5,
|
||||
textInverted: colors.white,
|
||||
link: colors.blue3,
|
||||
border: colors.gray3,
|
||||
icon: colors.gray2,
|
||||
},
|
||||
primary: {
|
||||
isLowContrast: true,
|
||||
background: colors.blue3,
|
||||
backgroundLight: colors.blue2,
|
||||
text: colors.white,
|
||||
textLight: colors.blue0,
|
||||
textInverted: colors.blue3,
|
||||
link: colors.blue0,
|
||||
border: colors.blue4,
|
||||
icon: colors.blue4,
|
||||
},
|
||||
secondary: {
|
||||
isLowContrast: true,
|
||||
background: colors.green3,
|
||||
backgroundLight: colors.green2,
|
||||
text: colors.white,
|
||||
textLight: colors.green1,
|
||||
textInverted: colors.green4,
|
||||
link: colors.green1,
|
||||
border: colors.green4,
|
||||
icon: colors.green4,
|
||||
},
|
||||
inverted: {
|
||||
isLowContrast: true,
|
||||
background: colors.black,
|
||||
backgroundLight: colors.gray6,
|
||||
text: colors.white,
|
||||
textLight: colors.gray3,
|
||||
textInverted: colors.black,
|
||||
link: colors.blue2,
|
||||
border: colors.gray3,
|
||||
icon: colors.gray5,
|
||||
},
|
||||
error: {
|
||||
isLowContrast: true,
|
||||
background: colors.red3,
|
||||
backgroundLight: colors.red2,
|
||||
text: colors.white,
|
||||
textLight: colors.red1,
|
||||
textInverted: colors.red3,
|
||||
link: colors.red1,
|
||||
border: colors.red4,
|
||||
icon: colors.red4,
|
||||
},
|
||||
},
|
||||
shapes: {
|
||||
button: {
|
||||
// TODO
|
||||
},
|
||||
bigButton: {
|
||||
// TODO
|
||||
},
|
||||
smallButton: {
|
||||
// TODO
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
h1: {
|
||||
fontSize: 48,
|
||||
fontWeight: '500',
|
||||
},
|
||||
h2: {
|
||||
fontSize: 34,
|
||||
letterSpacing: 0.25,
|
||||
fontWeight: '500',
|
||||
},
|
||||
h3: {
|
||||
fontSize: 24,
|
||||
fontWeight: '500',
|
||||
},
|
||||
h4: {
|
||||
fontWeight: '500',
|
||||
fontSize: 20,
|
||||
letterSpacing: 0.15,
|
||||
},
|
||||
subtitle1: {
|
||||
fontSize: 16,
|
||||
letterSpacing: 0.15,
|
||||
},
|
||||
subtitle2: {
|
||||
fontWeight: '500',
|
||||
fontSize: 14,
|
||||
letterSpacing: 0.1,
|
||||
},
|
||||
body1: {
|
||||
fontSize: 16,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
body2: {
|
||||
fontSize: 14,
|
||||
letterSpacing: 0.25,
|
||||
},
|
||||
button: {
|
||||
fontWeight: '500',
|
||||
fontSize: 14,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
caption: {
|
||||
fontSize: 12,
|
||||
letterSpacing: 0.4,
|
||||
},
|
||||
overline: {
|
||||
fontSize: 10,
|
||||
letterSpacing: 1.5,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const darkTheme: Theme = {
|
||||
...defaultTheme,
|
||||
colorScheme: 'dark',
|
||||
palette: {
|
||||
...defaultTheme.palette,
|
||||
default: {
|
||||
isLowContrast: true,
|
||||
background: colors.black,
|
||||
backgroundLight: colors.gray6,
|
||||
text: colors.white,
|
||||
textLight: colors.gray3,
|
||||
textInverted: colors.black,
|
||||
link: colors.blue2,
|
||||
border: colors.gray3,
|
||||
icon: colors.gray5,
|
||||
},
|
||||
primary: {
|
||||
...defaultTheme.palette.primary,
|
||||
textInverted: colors.blue2,
|
||||
},
|
||||
secondary: {
|
||||
...defaultTheme.palette.secondary,
|
||||
textInverted: colors.green2,
|
||||
},
|
||||
inverted: {
|
||||
isLowContrast: false,
|
||||
background: colors.white,
|
||||
backgroundLight: colors.gray2,
|
||||
text: colors.black,
|
||||
textLight: colors.gray5,
|
||||
textInverted: colors.white,
|
||||
link: colors.blue3,
|
||||
border: colors.gray3,
|
||||
icon: colors.gray1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export const FAB = 1
|
||||
export const BASE = 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue