diff options
Diffstat (limited to 'src/alf')
-rw-r--r-- | src/alf/atoms.ts | 41 | ||||
-rw-r--r-- | src/alf/index.tsx | 6 | ||||
-rw-r--r-- | src/alf/themes.ts | 87 | ||||
-rw-r--r-- | src/alf/tokens.ts | 46 | ||||
-rw-r--r-- | src/alf/util/colorGeneration.ts | 17 | ||||
-rw-r--r-- | src/alf/util/platform.ts | 26 | ||||
-rw-r--r-- | src/alf/util/useColorModeTheme.ts | 19 |
7 files changed, 185 insertions, 57 deletions
diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts index f75e8ffe0..0b473ba90 100644 --- a/src/alf/atoms.ts +++ b/src/alf/atoms.ts @@ -1,3 +1,5 @@ +import {Platform} from 'react-native' +import {web, native} from '#/alf/util/platform' import * as tokens from '#/alf/tokens' export const atoms = { @@ -5,7 +7,7 @@ export const atoms = { * Positioning */ fixed: { - position: 'fixed', + position: Platform.select({web: 'fixed', native: 'absolute'}) as 'absolute', }, absolute: { position: 'absolute', @@ -48,6 +50,9 @@ export const atoms = { h_full: { height: '100%', }, + h_full_vh: web({ + height: '100vh', + }), /* * Border radius @@ -110,9 +115,18 @@ export const atoms = { flex_row: { flexDirection: 'row', }, + flex_col_reverse: { + flexDirection: 'column-reverse', + }, + flex_row_reverse: { + flexDirection: 'row-reverse', + }, flex_wrap: { flexWrap: 'wrap', }, + flex_0: { + flex: web('0 0 auto') || (native(0) as number), + }, flex_1: { flex: 1, }, @@ -176,46 +190,65 @@ export const atoms = { }, text_2xs: { fontSize: tokens.fontSize._2xs, + letterSpacing: 0.25, }, text_xs: { fontSize: tokens.fontSize.xs, + letterSpacing: 0.25, }, text_sm: { fontSize: tokens.fontSize.sm, + letterSpacing: 0.25, }, text_md: { fontSize: tokens.fontSize.md, + letterSpacing: 0.25, }, text_lg: { fontSize: tokens.fontSize.lg, + letterSpacing: 0.25, }, text_xl: { fontSize: tokens.fontSize.xl, + letterSpacing: 0.25, }, text_2xl: { fontSize: tokens.fontSize._2xl, + letterSpacing: 0.25, }, text_3xl: { fontSize: tokens.fontSize._3xl, + letterSpacing: 0.25, }, text_4xl: { fontSize: tokens.fontSize._4xl, + letterSpacing: 0.25, }, text_5xl: { fontSize: tokens.fontSize._5xl, + letterSpacing: 0.25, }, leading_tight: { lineHeight: 1.15, }, leading_snug: { - lineHeight: 1.25, + lineHeight: 1.3, }, leading_normal: { lineHeight: 1.5, }, + tracking_normal: { + letterSpacing: 0, + }, + tracking_wide: { + letterSpacing: 0.25, + }, font_normal: { fontWeight: tokens.fontWeight.normal, }, + font_semibold: { + fontWeight: '500', + }, font_bold: { fontWeight: tokens.fontWeight.semibold, }, @@ -501,6 +534,10 @@ export const atoms = { /* * Margin */ + mx_auto: { + marginLeft: 'auto', + marginRight: 'auto', + }, m_2xs: { margin: tokens.space._2xs, }, diff --git a/src/alf/index.tsx b/src/alf/index.tsx index 06d6ebf01..f0a0ede7a 100644 --- a/src/alf/index.tsx +++ b/src/alf/index.tsx @@ -16,8 +16,9 @@ type BreakpointName = keyof typeof breakpoints const breakpoints: { [key: string]: number } = { + gtPhone: 500, gtMobile: 800, - gtTablet: 1200, + gtTablet: 1300, } function getActiveBreakpoints({width}: {width: number}) { const active: (keyof typeof breakpoints)[] = Object.keys(breakpoints).filter( @@ -26,6 +27,7 @@ function getActiveBreakpoints({width}: {width: number}) { return { active: active[active.length - 1], + gtPhone: active.includes('gtPhone'), gtMobile: active.includes('gtMobile'), gtTablet: active.includes('gtTablet'), } @@ -39,6 +41,7 @@ export const Context = React.createContext<{ theme: themes.Theme breakpoints: { active: BreakpointName | undefined + gtPhone: boolean gtMobile: boolean gtTablet: boolean } @@ -47,6 +50,7 @@ export const Context = React.createContext<{ theme: themes.light, breakpoints: { active: undefined, + gtPhone: false, gtMobile: false, gtTablet: false, }, diff --git a/src/alf/themes.ts b/src/alf/themes.ts index 72e08e894..0c95a459e 100644 --- a/src/alf/themes.ts +++ b/src/alf/themes.ts @@ -1,6 +1,7 @@ import * as tokens from '#/alf/tokens' import type {Mutable} from '#/alf/types' import {atoms} from '#/alf/atoms' +import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration' export type ThemeName = 'light' | 'dim' | 'dark' export type ReadonlyTheme = typeof light @@ -132,21 +133,63 @@ export const darkPalette: Palette = { export const dimPalette: Palette = { ...darkPalette, - black: tokens.color.gray_1000, + black: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[0]}%)`, - contrast_25: tokens.color.gray_975, - contrast_50: tokens.color.gray_950, - contrast_100: tokens.color.gray_900, - contrast_200: tokens.color.gray_800, - contrast_300: tokens.color.gray_700, - contrast_400: tokens.color.gray_600, - contrast_500: tokens.color.gray_500, - contrast_600: tokens.color.gray_400, - contrast_700: tokens.color.gray_300, - contrast_800: tokens.color.gray_200, - contrast_900: tokens.color.gray_100, - contrast_950: tokens.color.gray_50, - contrast_975: tokens.color.gray_25, + contrast_25: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[1]}%)`, + contrast_50: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[2]}%)`, + contrast_100: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[3]}%)`, + contrast_200: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[4]}%)`, + contrast_300: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[5]}%)`, + contrast_400: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[6]}%)`, + contrast_500: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[7]}%)`, + contrast_600: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[8]}%)`, + contrast_700: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[9]}%)`, + contrast_800: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[10]}%)`, + contrast_900: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[11]}%)`, + contrast_950: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[12]}%)`, + contrast_975: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[13]}%)`, + + primary_25: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[13]}%)`, + primary_50: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[12]}%)`, + primary_100: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[11]}%)`, + primary_200: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[10]}%)`, + primary_300: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[9]}%)`, + primary_400: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[8]}%)`, + primary_500: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[7]}%)`, + primary_600: `hsl(${BLUE_HUE}, 95%, ${tokens.dimScale[6]}%)`, + primary_700: `hsl(${BLUE_HUE}, 90%, ${tokens.dimScale[5]}%)`, + primary_800: `hsl(${BLUE_HUE}, 82%, ${tokens.dimScale[4]}%)`, + primary_900: `hsl(${BLUE_HUE}, 70%, ${tokens.dimScale[3]}%)`, + primary_950: `hsl(${BLUE_HUE}, 60%, ${tokens.dimScale[2]}%)`, + primary_975: `hsl(${BLUE_HUE}, 50%, ${tokens.dimScale[1]}%)`, + + positive_25: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[13]}%)`, + positive_50: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[12]}%)`, + positive_100: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[11]}%)`, + positive_200: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[10]}%)`, + positive_300: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[9]}%)`, + positive_400: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[8]}%)`, + positive_500: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[7]}%)`, + positive_600: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[6]}%)`, + positive_700: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[5]}%)`, + positive_800: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[4]}%)`, + positive_900: `hsl(${GREEN_HUE}, 70%, ${tokens.dimScale[3]}%)`, + positive_950: `hsl(${GREEN_HUE}, 60%, ${tokens.dimScale[2]}%)`, + positive_975: `hsl(${GREEN_HUE}, 50%, ${tokens.dimScale[1]}%)`, + + negative_25: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[13]}%)`, + negative_50: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[12]}%)`, + negative_100: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[11]}%)`, + negative_200: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[10]}%)`, + negative_300: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[9]}%)`, + negative_400: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[8]}%)`, + negative_500: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[7]}%)`, + negative_600: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[6]}%)`, + negative_700: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[5]}%)`, + negative_800: `hsl(${RED_HUE}, 88%, ${tokens.dimScale[4]}%)`, + negative_900: `hsl(${RED_HUE}, 84%, ${tokens.dimScale[3]}%)`, + negative_950: `hsl(${RED_HUE}, 80%, ${tokens.dimScale[2]}%)`, + negative_975: `hsl(${RED_HUE}, 70%, ${tokens.dimScale[1]}%)`, } as const export const light = { @@ -325,6 +368,7 @@ export const dark: Theme = { export const dim: Theme = { ...dark, name: 'dim', + palette: dimPalette, atoms: { ...dark.atoms, text: { @@ -393,5 +437,20 @@ export const dim: Theme = { border_contrast_high: { borderColor: dimPalette.contrast_300, }, + shadow_sm: { + ...atoms.shadow_sm, + shadowOpacity: 0.7, + shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, + }, + shadow_md: { + ...atoms.shadow_md, + shadowOpacity: 0.7, + shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, + }, + shadow_lg: { + ...atoms.shadow_lg, + shadowOpacity: 0.7, + shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, + }, }, } diff --git a/src/alf/tokens.ts b/src/alf/tokens.ts index f0b8c7c69..4045c831c 100644 --- a/src/alf/tokens.ts +++ b/src/alf/tokens.ts @@ -1,25 +1,35 @@ -const BLUE_HUE = 211 -const RED_HUE = 346 -const GREEN_HUE = 152 +import { + BLUE_HUE, + RED_HUE, + GREEN_HUE, + generateScale, +} from '#/alf/util/colorGeneration' + +export const scale = generateScale(6, 100) +// dim shifted 6% lighter +export const dimScale = generateScale(12, 100) export const color = { trueBlack: '#000000', - gray_0: `hsl(${BLUE_HUE}, 20%, 100%)`, - gray_25: `hsl(${BLUE_HUE}, 20%, 97%)`, - gray_50: `hsl(${BLUE_HUE}, 20%, 95%)`, - gray_100: `hsl(${BLUE_HUE}, 20%, 90%)`, - gray_200: `hsl(${BLUE_HUE}, 20%, 80%)`, - gray_300: `hsl(${BLUE_HUE}, 20%, 70%)`, - gray_400: `hsl(${BLUE_HUE}, 20%, 60%)`, - gray_500: `hsl(${BLUE_HUE}, 20%, 50%)`, - gray_600: `hsl(${BLUE_HUE}, 24%, 42%)`, - gray_700: `hsl(${BLUE_HUE}, 24%, 34%)`, - gray_800: `hsl(${BLUE_HUE}, 28%, 26%)`, - gray_900: `hsl(${BLUE_HUE}, 28%, 18%)`, - gray_950: `hsl(${BLUE_HUE}, 28%, 10%)`, - gray_975: `hsl(${BLUE_HUE}, 28%, 7%)`, - gray_1000: `hsl(${BLUE_HUE}, 28%, 4%)`, + temp_purple: 'rgb(105 0 255)', + temp_purple_dark: 'rgb(83 0 202)', + + gray_0: `hsl(${BLUE_HUE}, 20%, ${scale[14]}%)`, + gray_25: `hsl(${BLUE_HUE}, 20%, ${scale[13]}%)`, + gray_50: `hsl(${BLUE_HUE}, 20%, ${scale[12]}%)`, + gray_100: `hsl(${BLUE_HUE}, 20%, ${scale[11]}%)`, + gray_200: `hsl(${BLUE_HUE}, 20%, ${scale[10]}%)`, + gray_300: `hsl(${BLUE_HUE}, 20%, ${scale[9]}%)`, + gray_400: `hsl(${BLUE_HUE}, 20%, ${scale[8]}%)`, + gray_500: `hsl(${BLUE_HUE}, 20%, ${scale[7]}%)`, + gray_600: `hsl(${BLUE_HUE}, 24%, ${scale[6]}%)`, + gray_700: `hsl(${BLUE_HUE}, 24%, ${scale[5]}%)`, + gray_800: `hsl(${BLUE_HUE}, 28%, ${scale[4]}%)`, + gray_900: `hsl(${BLUE_HUE}, 28%, ${scale[3]}%)`, + gray_950: `hsl(${BLUE_HUE}, 28%, ${scale[2]}%)`, + gray_975: `hsl(${BLUE_HUE}, 28%, ${scale[1]}%)`, + gray_1000: `hsl(${BLUE_HUE}, 28%, ${scale[0]}%)`, blue_25: `hsl(${BLUE_HUE}, 99%, 97%)`, blue_50: `hsl(${BLUE_HUE}, 99%, 95%)`, diff --git a/src/alf/util/colorGeneration.ts b/src/alf/util/colorGeneration.ts new file mode 100644 index 000000000..929a01d3a --- /dev/null +++ b/src/alf/util/colorGeneration.ts @@ -0,0 +1,17 @@ +export const BLUE_HUE = 211 +export const RED_HUE = 346 +export const GREEN_HUE = 152 + +/** + * Smooth progression of lightness "stops" for generating HSL colors. + */ +export const COLOR_STOPS = [ + 0, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.95, 1, +] + +export function generateScale(start: number, end: number) { + const range = end - start + return COLOR_STOPS.map(stop => { + return start + range * stop + }) +} diff --git a/src/alf/util/platform.ts b/src/alf/util/platform.ts index 544f5480b..294e08a8b 100644 --- a/src/alf/util/platform.ts +++ b/src/alf/util/platform.ts @@ -1,25 +1,25 @@ -import {Platform} from 'react-native' +import {isAndroid, isIOS, isNative, isWeb} from 'platform/detection' export function web(value: any) { - return Platform.select({ - web: value, - }) + if (isWeb) { + return value + } } export function ios(value: any) { - return Platform.select({ - ios: value, - }) + if (isIOS) { + return value + } } export function android(value: any) { - return Platform.select({ - android: value, - }) + if (isAndroid) { + return value + } } export function native(value: any) { - return Platform.select({ - native: value, - }) + if (isNative) { + return value + } } diff --git a/src/alf/util/useColorModeTheme.ts b/src/alf/util/useColorModeTheme.ts index 48cf904fe..4f8921bf9 100644 --- a/src/alf/util/useColorModeTheme.ts +++ b/src/alf/util/useColorModeTheme.ts @@ -13,7 +13,7 @@ export function useColorModeTheme(): ThemeName { React.useLayoutEffect(() => { const theme = getThemeName(colorScheme, colorMode, darkTheme) updateDocument(theme) - updateSystemBackground(theme) + SystemUI.setBackgroundColorAsync(getBackgroundColor(theme)) }, [colorMode, colorScheme, darkTheme]) return React.useMemo( @@ -42,23 +42,24 @@ function updateDocument(theme: ThemeName) { if (isWeb && typeof window !== 'undefined') { // @ts-ignore web only const html = window.document.documentElement + // @ts-ignore web only + const meta = window.document.querySelector('meta[name="theme-color"]') + // remove any other color mode classes html.className = html.className.replace(/(theme)--\w+/g, '') - html.classList.add(`theme--${theme}`) + // set color to 'theme-color' meta tag + meta?.setAttribute('content', getBackgroundColor(theme)) } } -function updateSystemBackground(theme: ThemeName) { +function getBackgroundColor(theme: ThemeName): string { switch (theme) { case 'light': - SystemUI.setBackgroundColorAsync(light.atoms.bg.backgroundColor) - break + return light.atoms.bg.backgroundColor case 'dark': - SystemUI.setBackgroundColorAsync(dark.atoms.bg.backgroundColor) - break + return dark.atoms.bg.backgroundColor case 'dim': - SystemUI.setBackgroundColorAsync(dim.atoms.bg.backgroundColor) - break + return dim.atoms.bg.backgroundColor } } |