about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-07-11 16:59:12 -0500
committerGitHub <noreply@github.com>2024-07-11 16:59:12 -0500
commit74186950b2d7f3f5829e3d5bb8919c4a43293ba8 (patch)
tree9b6f15a5dd21789d02fa165651911f1854295821
parentea0586cd67427ce68f867ee25e03bb92169f23c3 (diff)
downloadvoidsky-74186950b2d7f3f5829e3d5bb8919c4a43293ba8.tar.zst
[ALF] Theme & palette cleanup (#4769)
* Invert primary scale

* Invert negative palette

* Replace theme specific styles in Toggle

* Remove theme specific colors from Button, improves secondary solid on dark mode

* TextField

* Remove from MessageItem

* Threadgate editor

* IconCircle

* Muted words

* Generate themes from hues

* Cleanup

* Deprecate more values, fix circular import

* Invert positive too, hardly use

* Button tweaks, some theme diffs

* Match disabled state for negative button

* Fix unread noty bg
-rw-r--r--src/alf/index.tsx21
-rw-r--r--src/alf/themes.ts992
-rw-r--r--src/alf/tokens.ts78
-rw-r--r--src/alf/types.ts172
-rw-r--r--src/alf/util/colorGeneration.ts4
-rw-r--r--src/alf/util/themeSelector.ts2
-rw-r--r--src/alf/util/useColorModeTheme.ts3
-rw-r--r--src/components/Button.tsx62
-rw-r--r--src/components/IconCircle.tsx11
-rw-r--r--src/components/dialogs/MutedWords.tsx7
-rw-r--r--src/components/dialogs/ThreadgateEditor.tsx5
-rw-r--r--src/components/dms/MessageItem.tsx10
-rw-r--r--src/components/forms/TextField.tsx9
-rw-r--r--src/components/forms/Toggle.tsx21
-rw-r--r--src/components/icons/common.tsx5
-rw-r--r--src/lib/ThemeContext.tsx5
-rw-r--r--src/lib/themes.ts14
-rw-r--r--src/view/screens/Storybook/Buttons.tsx50
-rw-r--r--src/view/screens/Storybook/Forms.tsx10
19 files changed, 839 insertions, 642 deletions
diff --git a/src/alf/index.tsx b/src/alf/index.tsx
index 75ea28eb0..ade2ce145 100644
--- a/src/alf/index.tsx
+++ b/src/alf/index.tsx
@@ -1,7 +1,9 @@
 import React from 'react'
 import {Dimensions} from 'react-native'
 
-import * as themes from '#/alf/themes'
+import {createThemes, defaultTheme} from '#/alf/themes'
+import {Theme, ThemeName} from '#/alf/types'
+import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
 
 export {atoms} from '#/alf/atoms'
 export * as tokens from '#/alf/tokens'
@@ -39,8 +41,8 @@ function getActiveBreakpoints({width}: {width: number}) {
  * Context
  */
 export const Context = React.createContext<{
-  themeName: themes.ThemeName
-  theme: themes.Theme
+  themeName: ThemeName
+  theme: Theme
   breakpoints: {
     active: BreakpointName | undefined
     gtPhone: boolean
@@ -49,7 +51,7 @@ export const Context = React.createContext<{
   }
 }>({
   themeName: 'light',
-  theme: themes.light,
+  theme: defaultTheme,
   breakpoints: {
     active: undefined,
     gtPhone: false,
@@ -61,7 +63,16 @@ export const Context = React.createContext<{
 export function ThemeProvider({
   children,
   theme: themeName,
-}: React.PropsWithChildren<{theme: themes.ThemeName}>) {
+}: React.PropsWithChildren<{theme: ThemeName}>) {
+  const themes = React.useMemo(() => {
+    return createThemes({
+      hues: {
+        primary: BLUE_HUE,
+        negative: RED_HUE,
+        positive: GREEN_HUE,
+      },
+    })
+  }, [])
   const theme = themes[themeName]
   const [breakpoints, setBreakpoints] = React.useState(() =>
     getActiveBreakpoints({width: Dimensions.get('window').width}),
diff --git a/src/alf/themes.ts b/src/alf/themes.ts
index acfd269f8..b430fa65e 100644
--- a/src/alf/themes.ts
+++ b/src/alf/themes.ts
@@ -1,456 +1,578 @@
 import {atoms} from '#/alf/atoms'
-import * as tokens from '#/alf/tokens'
-import type {Mutable} from '#/alf/types'
-import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
+import {Palette, Theme} from '#/alf/types'
+import {
+  BLUE_HUE,
+  defaultScale,
+  dimScale,
+  GREEN_HUE,
+  RED_HUE,
+} from '#/alf/util/colorGeneration'
 
-export type ThemeName = 'light' | 'dim' | 'dark'
-export type ReadonlyTheme = typeof light
-export type Theme = Mutable<ReadonlyTheme> & {name: ThemeName}
-export type ReadonlyPalette = typeof lightPalette
-export type Palette = Mutable<ReadonlyPalette>
+const themes = createThemes({
+  hues: {
+    primary: BLUE_HUE,
+    negative: RED_HUE,
+    positive: GREEN_HUE,
+  },
+})
 
-export const lightPalette = {
-  white: tokens.color.gray_0,
-  black: tokens.color.gray_1000,
+/**
+ * @deprecated use ALF and access palette from `useTheme()`
+ */
+export const lightPalette = themes.lightPalette
+/**
+ * @deprecated use ALF and access palette from `useTheme()`
+ */
+export const darkPalette = themes.darkPalette
+/**
+ * @deprecated use ALF and access palette from `useTheme()`
+ */
+export const dimPalette = themes.dimPalette
+/**
+ * @deprecated use ALF and access theme from `useTheme()`
+ */
+export const light = themes.light
+/**
+ * @deprecated use ALF and access theme from `useTheme()`
+ */
+export const dark = themes.dark
+/**
+ * @deprecated use ALF and access theme from `useTheme()`
+ */
+export const dim = themes.dim
 
-  contrast_25: tokens.color.gray_25,
-  contrast_50: tokens.color.gray_50,
-  contrast_100: tokens.color.gray_100,
-  contrast_200: tokens.color.gray_200,
-  contrast_300: tokens.color.gray_300,
-  contrast_400: tokens.color.gray_400,
-  contrast_500: tokens.color.gray_500,
-  contrast_600: tokens.color.gray_600,
-  contrast_700: tokens.color.gray_700,
-  contrast_800: tokens.color.gray_800,
-  contrast_900: tokens.color.gray_900,
-  contrast_950: tokens.color.gray_950,
-  contrast_975: tokens.color.gray_975,
+export const defaultTheme = themes.light
 
-  primary_25: tokens.color.blue_25,
-  primary_50: tokens.color.blue_50,
-  primary_100: tokens.color.blue_100,
-  primary_200: tokens.color.blue_200,
-  primary_300: tokens.color.blue_300,
-  primary_400: tokens.color.blue_400,
-  primary_500: tokens.color.blue_500,
-  primary_600: tokens.color.blue_600,
-  primary_700: tokens.color.blue_700,
-  primary_800: tokens.color.blue_800,
-  primary_900: tokens.color.blue_900,
-  primary_950: tokens.color.blue_950,
-  primary_975: tokens.color.blue_975,
+export function createThemes({
+  hues,
+}: {
+  hues: {
+    primary: number
+    negative: number
+    positive: number
+  }
+}): {
+  lightPalette: Palette
+  darkPalette: Palette
+  dimPalette: Palette
+  light: Theme
+  dark: Theme
+  dim: Theme
+} {
+  const color = {
+    trueBlack: '#000000',
 
-  positive_25: tokens.color.green_25,
-  positive_50: tokens.color.green_50,
-  positive_100: tokens.color.green_100,
-  positive_200: tokens.color.green_200,
-  positive_300: tokens.color.green_300,
-  positive_400: tokens.color.green_400,
-  positive_500: tokens.color.green_500,
-  positive_600: tokens.color.green_600,
-  positive_700: tokens.color.green_700,
-  positive_800: tokens.color.green_800,
-  positive_900: tokens.color.green_900,
-  positive_950: tokens.color.green_950,
-  positive_975: tokens.color.green_975,
+    gray_0: `hsl(${hues.primary}, 20%, ${defaultScale[14]}%)`,
+    gray_25: `hsl(${hues.primary}, 20%, ${defaultScale[13]}%)`,
+    gray_50: `hsl(${hues.primary}, 20%, ${defaultScale[12]}%)`,
+    gray_100: `hsl(${hues.primary}, 20%, ${defaultScale[11]}%)`,
+    gray_200: `hsl(${hues.primary}, 20%, ${defaultScale[10]}%)`,
+    gray_300: `hsl(${hues.primary}, 20%, ${defaultScale[9]}%)`,
+    gray_400: `hsl(${hues.primary}, 20%, ${defaultScale[8]}%)`,
+    gray_500: `hsl(${hues.primary}, 20%, ${defaultScale[7]}%)`,
+    gray_600: `hsl(${hues.primary}, 24%, ${defaultScale[6]}%)`,
+    gray_700: `hsl(${hues.primary}, 24%, ${defaultScale[5]}%)`,
+    gray_800: `hsl(${hues.primary}, 28%, ${defaultScale[4]}%)`,
+    gray_900: `hsl(${hues.primary}, 28%, ${defaultScale[3]}%)`,
+    gray_950: `hsl(${hues.primary}, 28%, ${defaultScale[2]}%)`,
+    gray_975: `hsl(${hues.primary}, 28%, ${defaultScale[1]}%)`,
+    gray_1000: `hsl(${hues.primary}, 28%, ${defaultScale[0]}%)`,
 
-  negative_25: tokens.color.red_25,
-  negative_50: tokens.color.red_50,
-  negative_100: tokens.color.red_100,
-  negative_200: tokens.color.red_200,
-  negative_300: tokens.color.red_300,
-  negative_400: tokens.color.red_400,
-  negative_500: tokens.color.red_500,
-  negative_600: tokens.color.red_600,
-  negative_700: tokens.color.red_700,
-  negative_800: tokens.color.red_800,
-  negative_900: tokens.color.red_900,
-  negative_950: tokens.color.red_950,
-  negative_975: tokens.color.red_975,
-} as const
+    primary_25: `hsl(${hues.primary}, 99%, 97%)`,
+    primary_50: `hsl(${hues.primary}, 99%, 95%)`,
+    primary_100: `hsl(${hues.primary}, 99%, 90%)`,
+    primary_200: `hsl(${hues.primary}, 99%, 80%)`,
+    primary_300: `hsl(${hues.primary}, 99%, 70%)`,
+    primary_400: `hsl(${hues.primary}, 99%, 60%)`,
+    primary_500: `hsl(${hues.primary}, 99%, 53%)`,
+    primary_600: `hsl(${hues.primary}, 99%, 42%)`,
+    primary_700: `hsl(${hues.primary}, 99%, 34%)`,
+    primary_800: `hsl(${hues.primary}, 99%, 26%)`,
+    primary_900: `hsl(${hues.primary}, 99%, 18%)`,
+    primary_950: `hsl(${hues.primary}, 99%, 10%)`,
+    primary_975: `hsl(${hues.primary}, 99%, 7%)`,
 
-export const darkPalette: Palette = {
-  white: tokens.color.gray_0,
-  black: tokens.color.trueBlack,
+    green_25: `hsl(${hues.positive}, 82%, 97%)`,
+    green_50: `hsl(${hues.positive}, 82%, 95%)`,
+    green_100: `hsl(${hues.positive}, 82%, 90%)`,
+    green_200: `hsl(${hues.positive}, 82%, 80%)`,
+    green_300: `hsl(${hues.positive}, 82%, 70%)`,
+    green_400: `hsl(${hues.positive}, 82%, 60%)`,
+    green_500: `hsl(${hues.positive}, 82%, 50%)`,
+    green_600: `hsl(${hues.positive}, 82%, 42%)`,
+    green_700: `hsl(${hues.positive}, 82%, 34%)`,
+    green_800: `hsl(${hues.positive}, 82%, 26%)`,
+    green_900: `hsl(${hues.positive}, 82%, 18%)`,
+    green_950: `hsl(${hues.positive}, 82%, 10%)`,
+    green_975: `hsl(${hues.positive}, 82%, 7%)`,
 
-  contrast_25: tokens.color.gray_1000,
-  contrast_50: tokens.color.gray_975,
-  contrast_100: tokens.color.gray_950,
-  contrast_200: tokens.color.gray_900,
-  contrast_300: tokens.color.gray_800,
-  contrast_400: tokens.color.gray_700,
-  contrast_500: tokens.color.gray_600,
-  contrast_600: tokens.color.gray_500,
-  contrast_700: tokens.color.gray_400,
-  contrast_800: tokens.color.gray_300,
-  contrast_900: tokens.color.gray_200,
-  contrast_950: tokens.color.gray_100,
-  contrast_975: tokens.color.gray_50,
+    red_25: `hsl(${hues.negative}, 91%, 97%)`,
+    red_50: `hsl(${hues.negative}, 91%, 95%)`,
+    red_100: `hsl(${hues.negative}, 91%, 90%)`,
+    red_200: `hsl(${hues.negative}, 91%, 80%)`,
+    red_300: `hsl(${hues.negative}, 91%, 70%)`,
+    red_400: `hsl(${hues.negative}, 91%, 60%)`,
+    red_500: `hsl(${hues.negative}, 91%, 50%)`,
+    red_600: `hsl(${hues.negative}, 91%, 42%)`,
+    red_700: `hsl(${hues.negative}, 91%, 34%)`,
+    red_800: `hsl(${hues.negative}, 91%, 26%)`,
+    red_900: `hsl(${hues.negative}, 91%, 18%)`,
+    red_950: `hsl(${hues.negative}, 91%, 10%)`,
+    red_975: `hsl(${hues.negative}, 91%, 7%)`,
+  } as const
 
-  primary_25: tokens.color.blue_25,
-  primary_50: tokens.color.blue_50,
-  primary_100: tokens.color.blue_100,
-  primary_200: tokens.color.blue_200,
-  primary_300: tokens.color.blue_300,
-  primary_400: tokens.color.blue_400,
-  primary_500: tokens.color.blue_500,
-  primary_600: tokens.color.blue_600,
-  primary_700: tokens.color.blue_700,
-  primary_800: tokens.color.blue_800,
-  primary_900: tokens.color.blue_900,
-  primary_950: tokens.color.blue_950,
-  primary_975: tokens.color.blue_975,
+  const lightPalette = {
+    white: color.gray_0,
+    black: color.gray_1000,
 
-  positive_25: tokens.color.green_25,
-  positive_50: tokens.color.green_50,
-  positive_100: tokens.color.green_100,
-  positive_200: tokens.color.green_200,
-  positive_300: tokens.color.green_300,
-  positive_400: tokens.color.green_400,
-  positive_500: tokens.color.green_500,
-  positive_600: tokens.color.green_600,
-  positive_700: tokens.color.green_700,
-  positive_800: tokens.color.green_800,
-  positive_900: tokens.color.green_900,
-  positive_950: tokens.color.green_950,
-  positive_975: tokens.color.green_975,
+    contrast_25: color.gray_25,
+    contrast_50: color.gray_50,
+    contrast_100: color.gray_100,
+    contrast_200: color.gray_200,
+    contrast_300: color.gray_300,
+    contrast_400: color.gray_400,
+    contrast_500: color.gray_500,
+    contrast_600: color.gray_600,
+    contrast_700: color.gray_700,
+    contrast_800: color.gray_800,
+    contrast_900: color.gray_900,
+    contrast_950: color.gray_950,
+    contrast_975: color.gray_975,
 
-  negative_25: tokens.color.red_25,
-  negative_50: tokens.color.red_50,
-  negative_100: tokens.color.red_100,
-  negative_200: tokens.color.red_200,
-  negative_300: tokens.color.red_300,
-  negative_400: tokens.color.red_400,
-  negative_500: tokens.color.red_500,
-  negative_600: tokens.color.red_600,
-  negative_700: tokens.color.red_700,
-  negative_800: tokens.color.red_800,
-  negative_900: tokens.color.red_900,
-  negative_950: tokens.color.red_950,
-  negative_975: tokens.color.red_975,
-} as const
+    primary_25: color.primary_25,
+    primary_50: color.primary_50,
+    primary_100: color.primary_100,
+    primary_200: color.primary_200,
+    primary_300: color.primary_300,
+    primary_400: color.primary_400,
+    primary_500: color.primary_500,
+    primary_600: color.primary_600,
+    primary_700: color.primary_700,
+    primary_800: color.primary_800,
+    primary_900: color.primary_900,
+    primary_950: color.primary_950,
+    primary_975: color.primary_975,
 
-export const dimPalette: Palette = {
-  ...darkPalette,
-  black: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[0]}%)`,
+    positive_25: color.green_25,
+    positive_50: color.green_50,
+    positive_100: color.green_100,
+    positive_200: color.green_200,
+    positive_300: color.green_300,
+    positive_400: color.green_400,
+    positive_500: color.green_500,
+    positive_600: color.green_600,
+    positive_700: color.green_700,
+    positive_800: color.green_800,
+    positive_900: color.green_900,
+    positive_950: color.green_950,
+    positive_975: color.green_975,
 
-  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]}%)`,
+    negative_25: color.red_25,
+    negative_50: color.red_50,
+    negative_100: color.red_100,
+    negative_200: color.red_200,
+    negative_300: color.red_300,
+    negative_400: color.red_400,
+    negative_500: color.red_500,
+    negative_600: color.red_600,
+    negative_700: color.red_700,
+    negative_800: color.red_800,
+    negative_900: color.red_900,
+    negative_950: color.red_950,
+    negative_975: color.red_975,
+  } as const
 
-  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]}%)`,
+  const darkPalette: Palette = {
+    white: color.gray_0,
+    black: color.trueBlack,
 
-  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]}%)`,
+    contrast_25: color.gray_1000,
+    contrast_50: color.gray_975,
+    contrast_100: color.gray_950,
+    contrast_200: color.gray_900,
+    contrast_300: color.gray_800,
+    contrast_400: color.gray_700,
+    contrast_500: color.gray_600,
+    contrast_600: color.gray_500,
+    contrast_700: color.gray_400,
+    contrast_800: color.gray_300,
+    contrast_900: color.gray_200,
+    contrast_950: color.gray_100,
+    contrast_975: color.gray_50,
 
-  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
+    primary_25: color.primary_975,
+    primary_50: color.primary_950,
+    primary_100: color.primary_900,
+    primary_200: color.primary_800,
+    primary_300: color.primary_700,
+    primary_400: color.primary_600,
+    primary_500: color.primary_500,
+    primary_600: color.primary_400,
+    primary_700: color.primary_300,
+    primary_800: color.primary_200,
+    primary_900: color.primary_100,
+    primary_950: color.primary_50,
+    primary_975: color.primary_25,
 
-export const light = {
-  name: 'light' as ThemeName,
-  palette: lightPalette,
-  atoms: {
-    text: {
-      color: lightPalette.black,
-    },
-    text_contrast_low: {
-      color: lightPalette.contrast_400,
-    },
-    text_contrast_medium: {
-      color: lightPalette.contrast_700,
-    },
-    text_contrast_high: {
-      color: lightPalette.contrast_900,
-    },
-    text_inverted: {
-      color: lightPalette.white,
-    },
-    bg: {
-      backgroundColor: lightPalette.white,
-    },
-    bg_contrast_25: {
-      backgroundColor: lightPalette.contrast_25,
-    },
-    bg_contrast_50: {
-      backgroundColor: lightPalette.contrast_50,
-    },
-    bg_contrast_100: {
-      backgroundColor: lightPalette.contrast_100,
-    },
-    bg_contrast_200: {
-      backgroundColor: lightPalette.contrast_200,
-    },
-    bg_contrast_300: {
-      backgroundColor: lightPalette.contrast_300,
-    },
-    bg_contrast_400: {
-      backgroundColor: lightPalette.contrast_400,
-    },
-    bg_contrast_500: {
-      backgroundColor: lightPalette.contrast_500,
-    },
-    bg_contrast_600: {
-      backgroundColor: lightPalette.contrast_600,
-    },
-    bg_contrast_700: {
-      backgroundColor: lightPalette.contrast_700,
-    },
-    bg_contrast_800: {
-      backgroundColor: lightPalette.contrast_800,
-    },
-    bg_contrast_900: {
-      backgroundColor: lightPalette.contrast_900,
-    },
-    bg_contrast_950: {
-      backgroundColor: lightPalette.contrast_950,
-    },
-    bg_contrast_975: {
-      backgroundColor: lightPalette.contrast_975,
-    },
-    border_contrast_low: {
-      borderColor: lightPalette.contrast_100,
-    },
-    border_contrast_medium: {
-      borderColor: lightPalette.contrast_200,
-    },
-    border_contrast_high: {
-      borderColor: lightPalette.contrast_300,
-    },
-    shadow_sm: {
-      ...atoms.shadow_sm,
-      shadowColor: lightPalette.black,
-    },
-    shadow_md: {
-      ...atoms.shadow_md,
-      shadowColor: lightPalette.black,
-    },
-    shadow_lg: {
-      ...atoms.shadow_lg,
-      shadowColor: lightPalette.black,
-    },
-  },
-}
+    positive_25: color.green_975,
+    positive_50: color.green_950,
+    positive_100: color.green_900,
+    positive_200: color.green_800,
+    positive_300: color.green_700,
+    positive_400: color.green_600,
+    positive_500: color.green_500,
+    positive_600: color.green_400,
+    positive_700: color.green_300,
+    positive_800: color.green_200,
+    positive_900: color.green_100,
+    positive_950: color.green_50,
+    positive_975: color.green_25,
 
-export const dark: Theme = {
-  name: 'dark' as ThemeName,
-  palette: darkPalette,
-  atoms: {
-    text: {
-      color: darkPalette.white,
-    },
-    text_contrast_low: {
-      color: darkPalette.contrast_400,
-    },
-    text_contrast_medium: {
-      color: darkPalette.contrast_700,
-    },
-    text_contrast_high: {
-      color: darkPalette.contrast_900,
-    },
-    text_inverted: {
-      color: darkPalette.black,
-    },
-    bg: {
-      backgroundColor: darkPalette.black,
-    },
-    bg_contrast_25: {
-      backgroundColor: darkPalette.contrast_25,
-    },
-    bg_contrast_50: {
-      backgroundColor: darkPalette.contrast_50,
-    },
-    bg_contrast_100: {
-      backgroundColor: darkPalette.contrast_100,
-    },
-    bg_contrast_200: {
-      backgroundColor: darkPalette.contrast_200,
-    },
-    bg_contrast_300: {
-      backgroundColor: darkPalette.contrast_300,
-    },
-    bg_contrast_400: {
-      backgroundColor: darkPalette.contrast_400,
-    },
-    bg_contrast_500: {
-      backgroundColor: darkPalette.contrast_500,
-    },
-    bg_contrast_600: {
-      backgroundColor: darkPalette.contrast_600,
-    },
-    bg_contrast_700: {
-      backgroundColor: darkPalette.contrast_700,
-    },
-    bg_contrast_800: {
-      backgroundColor: darkPalette.contrast_800,
-    },
-    bg_contrast_900: {
-      backgroundColor: darkPalette.contrast_900,
-    },
-    bg_contrast_950: {
-      backgroundColor: darkPalette.contrast_950,
-    },
-    bg_contrast_975: {
-      backgroundColor: darkPalette.contrast_975,
-    },
-    border_contrast_low: {
-      borderColor: darkPalette.contrast_100,
-    },
-    border_contrast_medium: {
-      borderColor: darkPalette.contrast_200,
-    },
-    border_contrast_high: {
-      borderColor: darkPalette.contrast_300,
-    },
-    shadow_sm: {
-      ...atoms.shadow_sm,
-      shadowOpacity: 0.7,
-      shadowColor: tokens.color.trueBlack,
-    },
-    shadow_md: {
-      ...atoms.shadow_md,
-      shadowOpacity: 0.7,
-      shadowColor: tokens.color.trueBlack,
-    },
-    shadow_lg: {
-      ...atoms.shadow_lg,
-      shadowOpacity: 0.7,
-      shadowColor: tokens.color.trueBlack,
-    },
-  },
-}
+    negative_25: color.red_975,
+    negative_50: color.red_950,
+    negative_100: color.red_900,
+    negative_200: color.red_800,
+    negative_300: color.red_700,
+    negative_400: color.red_600,
+    negative_500: color.red_500,
+    negative_600: color.red_400,
+    negative_700: color.red_300,
+    negative_800: color.red_200,
+    negative_900: color.red_100,
+    negative_950: color.red_50,
+    negative_975: color.red_25,
+  } as const
 
-export const dim: Theme = {
-  ...dark,
-  name: 'dim' as ThemeName,
-  palette: dimPalette,
-  atoms: {
-    ...dark.atoms,
-    text: {
-      color: dimPalette.white,
-    },
-    text_contrast_low: {
-      color: dimPalette.contrast_400,
-    },
-    text_contrast_medium: {
-      color: dimPalette.contrast_700,
-    },
-    text_contrast_high: {
-      color: dimPalette.contrast_900,
-    },
-    text_inverted: {
-      color: dimPalette.black,
-    },
-    bg: {
-      backgroundColor: dimPalette.black,
-    },
-    bg_contrast_25: {
-      backgroundColor: dimPalette.contrast_25,
-    },
-    bg_contrast_50: {
-      backgroundColor: dimPalette.contrast_50,
-    },
-    bg_contrast_100: {
-      backgroundColor: dimPalette.contrast_100,
-    },
-    bg_contrast_200: {
-      backgroundColor: dimPalette.contrast_200,
-    },
-    bg_contrast_300: {
-      backgroundColor: dimPalette.contrast_300,
-    },
-    bg_contrast_400: {
-      backgroundColor: dimPalette.contrast_400,
-    },
-    bg_contrast_500: {
-      backgroundColor: dimPalette.contrast_500,
-    },
-    bg_contrast_600: {
-      backgroundColor: dimPalette.contrast_600,
-    },
-    bg_contrast_700: {
-      backgroundColor: dimPalette.contrast_700,
-    },
-    bg_contrast_800: {
-      backgroundColor: dimPalette.contrast_800,
-    },
-    bg_contrast_900: {
-      backgroundColor: dimPalette.contrast_900,
-    },
-    bg_contrast_950: {
-      backgroundColor: dimPalette.contrast_950,
-    },
-    bg_contrast_975: {
-      backgroundColor: dimPalette.contrast_975,
-    },
-    border_contrast_low: {
-      borderColor: dimPalette.contrast_100,
-    },
-    border_contrast_medium: {
-      borderColor: dimPalette.contrast_200,
-    },
-    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%)`,
-    },
-  },
+  const dimPalette: Palette = {
+    ...darkPalette,
+    black: `hsl(${hues.primary}, 28%, ${dimScale[0]}%)`,
+
+    contrast_25: `hsl(${hues.primary}, 28%, ${dimScale[1]}%)`,
+    contrast_50: `hsl(${hues.primary}, 28%, ${dimScale[2]}%)`,
+    contrast_100: `hsl(${hues.primary}, 28%, ${dimScale[3]}%)`,
+    contrast_200: `hsl(${hues.primary}, 28%, ${dimScale[4]}%)`,
+    contrast_300: `hsl(${hues.primary}, 24%, ${dimScale[5]}%)`,
+    contrast_400: `hsl(${hues.primary}, 24%, ${dimScale[6]}%)`,
+    contrast_500: `hsl(${hues.primary}, 20%, ${dimScale[7]}%)`,
+    contrast_600: `hsl(${hues.primary}, 20%, ${dimScale[8]}%)`,
+    contrast_700: `hsl(${hues.primary}, 20%, ${dimScale[9]}%)`,
+    contrast_800: `hsl(${hues.primary}, 20%, ${dimScale[10]}%)`,
+    contrast_900: `hsl(${hues.primary}, 20%, ${dimScale[11]}%)`,
+    contrast_950: `hsl(${hues.primary}, 20%, ${dimScale[12]}%)`,
+    contrast_975: `hsl(${hues.primary}, 20%, ${dimScale[13]}%)`,
+
+    primary_25: `hsl(${hues.primary}, 99%, ${dimScale[1]}%)`,
+    primary_50: `hsl(${hues.primary}, 99%, ${dimScale[2]}%)`,
+    primary_100: `hsl(${hues.primary}, 99%, ${dimScale[3]}%)`,
+    primary_200: `hsl(${hues.primary}, 99%, ${dimScale[4]}%)`,
+    primary_300: `hsl(${hues.primary}, 99%, ${dimScale[5]}%)`,
+    primary_400: `hsl(${hues.primary}, 99%, ${dimScale[6]}%)`,
+    primary_500: `hsl(${hues.primary}, 99%, ${dimScale[7]}%)`,
+    primary_600: `hsl(${hues.primary}, 95%, ${dimScale[8]}%)`,
+    primary_700: `hsl(${hues.primary}, 90%, ${dimScale[9]}%)`,
+    primary_800: `hsl(${hues.primary}, 82%, ${dimScale[10]}%)`,
+    primary_900: `hsl(${hues.primary}, 70%, ${dimScale[11]}%)`,
+    primary_950: `hsl(${hues.primary}, 60%, ${dimScale[12]}%)`,
+    primary_975: `hsl(${hues.primary}, 50%, ${dimScale[13]}%)`,
+
+    positive_25: `hsl(${hues.positive}, 82%, ${dimScale[1]}%)`,
+    positive_50: `hsl(${hues.positive}, 82%, ${dimScale[2]}%)`,
+    positive_100: `hsl(${hues.positive}, 82%, ${dimScale[3]}%)`,
+    positive_200: `hsl(${hues.positive}, 82%, ${dimScale[4]}%)`,
+    positive_300: `hsl(${hues.positive}, 82%, ${dimScale[5]}%)`,
+    positive_400: `hsl(${hues.positive}, 82%, ${dimScale[6]}%)`,
+    positive_500: `hsl(${hues.positive}, 82%, ${dimScale[7]}%)`,
+    positive_600: `hsl(${hues.positive}, 82%, ${dimScale[8]}%)`,
+    positive_700: `hsl(${hues.positive}, 82%, ${dimScale[9]}%)`,
+    positive_800: `hsl(${hues.positive}, 82%, ${dimScale[10]}%)`,
+    positive_900: `hsl(${hues.positive}, 70%, ${dimScale[11]}%)`,
+    positive_950: `hsl(${hues.positive}, 60%, ${dimScale[12]}%)`,
+    positive_975: `hsl(${hues.positive}, 50%, ${dimScale[13]}%)`,
+
+    negative_25: `hsl(${hues.negative}, 91%, ${dimScale[1]}%)`,
+    negative_50: `hsl(${hues.negative}, 91%, ${dimScale[2]}%)`,
+    negative_100: `hsl(${hues.negative}, 91%, ${dimScale[3]}%)`,
+    negative_200: `hsl(${hues.negative}, 91%, ${dimScale[4]}%)`,
+    negative_300: `hsl(${hues.negative}, 91%, ${dimScale[5]}%)`,
+    negative_400: `hsl(${hues.negative}, 91%, ${dimScale[6]}%)`,
+    negative_500: `hsl(${hues.negative}, 91%, ${dimScale[7]}%)`,
+    negative_600: `hsl(${hues.negative}, 91%, ${dimScale[8]}%)`,
+    negative_700: `hsl(${hues.negative}, 91%, ${dimScale[9]}%)`,
+    negative_800: `hsl(${hues.negative}, 88%, ${dimScale[10]}%)`,
+    negative_900: `hsl(${hues.negative}, 84%, ${dimScale[11]}%)`,
+    negative_950: `hsl(${hues.negative}, 80%, ${dimScale[12]}%)`,
+    negative_975: `hsl(${hues.negative}, 70%, ${dimScale[13]}%)`,
+  } as const
+
+  const light: Theme = {
+    name: 'light',
+    palette: lightPalette,
+    atoms: {
+      text: {
+        color: lightPalette.black,
+      },
+      text_contrast_low: {
+        color: lightPalette.contrast_400,
+      },
+      text_contrast_medium: {
+        color: lightPalette.contrast_700,
+      },
+      text_contrast_high: {
+        color: lightPalette.contrast_900,
+      },
+      text_inverted: {
+        color: lightPalette.white,
+      },
+      bg: {
+        backgroundColor: lightPalette.white,
+      },
+      bg_contrast_25: {
+        backgroundColor: lightPalette.contrast_25,
+      },
+      bg_contrast_50: {
+        backgroundColor: lightPalette.contrast_50,
+      },
+      bg_contrast_100: {
+        backgroundColor: lightPalette.contrast_100,
+      },
+      bg_contrast_200: {
+        backgroundColor: lightPalette.contrast_200,
+      },
+      bg_contrast_300: {
+        backgroundColor: lightPalette.contrast_300,
+      },
+      bg_contrast_400: {
+        backgroundColor: lightPalette.contrast_400,
+      },
+      bg_contrast_500: {
+        backgroundColor: lightPalette.contrast_500,
+      },
+      bg_contrast_600: {
+        backgroundColor: lightPalette.contrast_600,
+      },
+      bg_contrast_700: {
+        backgroundColor: lightPalette.contrast_700,
+      },
+      bg_contrast_800: {
+        backgroundColor: lightPalette.contrast_800,
+      },
+      bg_contrast_900: {
+        backgroundColor: lightPalette.contrast_900,
+      },
+      bg_contrast_950: {
+        backgroundColor: lightPalette.contrast_950,
+      },
+      bg_contrast_975: {
+        backgroundColor: lightPalette.contrast_975,
+      },
+      border_contrast_low: {
+        borderColor: lightPalette.contrast_100,
+      },
+      border_contrast_medium: {
+        borderColor: lightPalette.contrast_200,
+      },
+      border_contrast_high: {
+        borderColor: lightPalette.contrast_300,
+      },
+      shadow_sm: {
+        ...atoms.shadow_sm,
+        shadowColor: lightPalette.black,
+      },
+      shadow_md: {
+        ...atoms.shadow_md,
+        shadowColor: lightPalette.black,
+      },
+      shadow_lg: {
+        ...atoms.shadow_lg,
+        shadowColor: lightPalette.black,
+      },
+    },
+  }
+
+  const dark: Theme = {
+    name: 'dark',
+    palette: darkPalette,
+    atoms: {
+      text: {
+        color: darkPalette.white,
+      },
+      text_contrast_low: {
+        color: darkPalette.contrast_400,
+      },
+      text_contrast_medium: {
+        color: darkPalette.contrast_700,
+      },
+      text_contrast_high: {
+        color: darkPalette.contrast_900,
+      },
+      text_inverted: {
+        color: darkPalette.black,
+      },
+      bg: {
+        backgroundColor: darkPalette.black,
+      },
+      bg_contrast_25: {
+        backgroundColor: darkPalette.contrast_25,
+      },
+      bg_contrast_50: {
+        backgroundColor: darkPalette.contrast_50,
+      },
+      bg_contrast_100: {
+        backgroundColor: darkPalette.contrast_100,
+      },
+      bg_contrast_200: {
+        backgroundColor: darkPalette.contrast_200,
+      },
+      bg_contrast_300: {
+        backgroundColor: darkPalette.contrast_300,
+      },
+      bg_contrast_400: {
+        backgroundColor: darkPalette.contrast_400,
+      },
+      bg_contrast_500: {
+        backgroundColor: darkPalette.contrast_500,
+      },
+      bg_contrast_600: {
+        backgroundColor: darkPalette.contrast_600,
+      },
+      bg_contrast_700: {
+        backgroundColor: darkPalette.contrast_700,
+      },
+      bg_contrast_800: {
+        backgroundColor: darkPalette.contrast_800,
+      },
+      bg_contrast_900: {
+        backgroundColor: darkPalette.contrast_900,
+      },
+      bg_contrast_950: {
+        backgroundColor: darkPalette.contrast_950,
+      },
+      bg_contrast_975: {
+        backgroundColor: darkPalette.contrast_975,
+      },
+      border_contrast_low: {
+        borderColor: darkPalette.contrast_100,
+      },
+      border_contrast_medium: {
+        borderColor: darkPalette.contrast_200,
+      },
+      border_contrast_high: {
+        borderColor: darkPalette.contrast_300,
+      },
+      shadow_sm: {
+        ...atoms.shadow_sm,
+        shadowOpacity: 0.7,
+        shadowColor: color.trueBlack,
+      },
+      shadow_md: {
+        ...atoms.shadow_md,
+        shadowOpacity: 0.7,
+        shadowColor: color.trueBlack,
+      },
+      shadow_lg: {
+        ...atoms.shadow_lg,
+        shadowOpacity: 0.7,
+        shadowColor: color.trueBlack,
+      },
+    },
+  }
+
+  const dim: Theme = {
+    ...dark,
+    name: 'dim',
+    palette: dimPalette,
+    atoms: {
+      ...dark.atoms,
+      text: {
+        color: dimPalette.white,
+      },
+      text_contrast_low: {
+        color: dimPalette.contrast_400,
+      },
+      text_contrast_medium: {
+        color: dimPalette.contrast_700,
+      },
+      text_contrast_high: {
+        color: dimPalette.contrast_900,
+      },
+      text_inverted: {
+        color: dimPalette.black,
+      },
+      bg: {
+        backgroundColor: dimPalette.black,
+      },
+      bg_contrast_25: {
+        backgroundColor: dimPalette.contrast_25,
+      },
+      bg_contrast_50: {
+        backgroundColor: dimPalette.contrast_50,
+      },
+      bg_contrast_100: {
+        backgroundColor: dimPalette.contrast_100,
+      },
+      bg_contrast_200: {
+        backgroundColor: dimPalette.contrast_200,
+      },
+      bg_contrast_300: {
+        backgroundColor: dimPalette.contrast_300,
+      },
+      bg_contrast_400: {
+        backgroundColor: dimPalette.contrast_400,
+      },
+      bg_contrast_500: {
+        backgroundColor: dimPalette.contrast_500,
+      },
+      bg_contrast_600: {
+        backgroundColor: dimPalette.contrast_600,
+      },
+      bg_contrast_700: {
+        backgroundColor: dimPalette.contrast_700,
+      },
+      bg_contrast_800: {
+        backgroundColor: dimPalette.contrast_800,
+      },
+      bg_contrast_900: {
+        backgroundColor: dimPalette.contrast_900,
+      },
+      bg_contrast_950: {
+        backgroundColor: dimPalette.contrast_950,
+      },
+      bg_contrast_975: {
+        backgroundColor: dimPalette.contrast_975,
+      },
+      border_contrast_low: {
+        borderColor: dimPalette.contrast_100,
+      },
+      border_contrast_medium: {
+        borderColor: dimPalette.contrast_200,
+      },
+      border_contrast_high: {
+        borderColor: dimPalette.contrast_300,
+      },
+      shadow_sm: {
+        ...atoms.shadow_sm,
+        shadowOpacity: 0.7,
+        shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
+      },
+      shadow_md: {
+        ...atoms.shadow_md,
+        shadowOpacity: 0.7,
+        shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
+      },
+      shadow_lg: {
+        ...atoms.shadow_lg,
+        shadowOpacity: 0.7,
+        shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
+      },
+    },
+  }
+
+  return {
+    lightPalette,
+    darkPalette,
+    dimPalette,
+    light,
+    dark,
+    dim,
+  }
 }
diff --git a/src/alf/tokens.ts b/src/alf/tokens.ts
index 675844e29..0208945ee 100644
--- a/src/alf/tokens.ts
+++ b/src/alf/tokens.ts
@@ -1,77 +1,6 @@
-import {
-  BLUE_HUE,
-  generateScale,
-  GREEN_HUE,
-  RED_HUE,
-} 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',
-
   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%)`,
-  blue_100: `hsl(${BLUE_HUE}, 99%, 90%)`,
-  blue_200: `hsl(${BLUE_HUE}, 99%, 80%)`,
-  blue_300: `hsl(${BLUE_HUE}, 99%, 70%)`,
-  blue_400: `hsl(${BLUE_HUE}, 99%, 60%)`,
-  blue_500: `hsl(${BLUE_HUE}, 99%, 53%)`,
-  blue_600: `hsl(${BLUE_HUE}, 99%, 42%)`,
-  blue_700: `hsl(${BLUE_HUE}, 99%, 34%)`,
-  blue_800: `hsl(${BLUE_HUE}, 99%, 26%)`,
-  blue_900: `hsl(${BLUE_HUE}, 99%, 18%)`,
-  blue_950: `hsl(${BLUE_HUE}, 99%, 10%)`,
-  blue_975: `hsl(${BLUE_HUE}, 99%, 7%)`,
-
-  green_25: `hsl(${GREEN_HUE}, 82%, 97%)`,
-  green_50: `hsl(${GREEN_HUE}, 82%, 95%)`,
-  green_100: `hsl(${GREEN_HUE}, 82%, 90%)`,
-  green_200: `hsl(${GREEN_HUE}, 82%, 80%)`,
-  green_300: `hsl(${GREEN_HUE}, 82%, 70%)`,
-  green_400: `hsl(${GREEN_HUE}, 82%, 60%)`,
-  green_500: `hsl(${GREEN_HUE}, 82%, 50%)`,
-  green_600: `hsl(${GREEN_HUE}, 82%, 42%)`,
-  green_700: `hsl(${GREEN_HUE}, 82%, 34%)`,
-  green_800: `hsl(${GREEN_HUE}, 82%, 26%)`,
-  green_900: `hsl(${GREEN_HUE}, 82%, 18%)`,
-  green_950: `hsl(${GREEN_HUE}, 82%, 10%)`,
-  green_975: `hsl(${GREEN_HUE}, 82%, 7%)`,
-
-  red_25: `hsl(${RED_HUE}, 91%, 97%)`,
-  red_50: `hsl(${RED_HUE}, 91%, 95%)`,
-  red_100: `hsl(${RED_HUE}, 91%, 90%)`,
-  red_200: `hsl(${RED_HUE}, 91%, 80%)`,
-  red_300: `hsl(${RED_HUE}, 91%, 70%)`,
-  red_400: `hsl(${RED_HUE}, 91%, 60%)`,
-  red_500: `hsl(${RED_HUE}, 91%, 50%)`,
-  red_600: `hsl(${RED_HUE}, 91%, 42%)`,
-  red_700: `hsl(${RED_HUE}, 91%, 34%)`,
-  red_800: `hsl(${RED_HUE}, 91%, 26%)`,
-  red_900: `hsl(${RED_HUE}, 91%, 18%)`,
-  red_950: `hsl(${RED_HUE}, 91%, 10%)`,
-  red_975: `hsl(${RED_HUE}, 91%, 7%)`,
 } as const
 
 export const space = {
@@ -178,10 +107,3 @@ export const gradients = {
     hover_value: '#755B62',
   },
 } as const
-
-export type Color = keyof typeof color
-export type Space = keyof typeof space
-export type FontSize = keyof typeof fontSize
-export type LineHeight = keyof typeof lineHeight
-export type BorderRadius = keyof typeof borderRadius
-export type FontWeight = keyof typeof fontWeight
diff --git a/src/alf/types.ts b/src/alf/types.ts
index dd8d816d2..41822b8dd 100644
--- a/src/alf/types.ts
+++ b/src/alf/types.ts
@@ -1,21 +1,4 @@
-import {StyleProp, ViewStyle, TextStyle} from 'react-native'
-
-type LiteralToCommon<T extends PropertyKey> = T extends number
-  ? number
-  : T extends string
-  ? string
-  : T extends symbol
-  ? symbol
-  : never
-
-/**
- * @see https://stackoverflow.com/questions/68249999/use-as-const-in-typescript-without-adding-readonly-modifiers
- */
-export type Mutable<T> = {
-  -readonly [K in keyof T]: T[K] extends PropertyKey
-    ? LiteralToCommon<T[K]>
-    : Mutable<T[K]>
-}
+import {StyleProp, TextStyle, ViewStyle} from 'react-native'
 
 export type TextStyleProp = {
   style?: StyleProp<TextStyle>
@@ -24,3 +7,156 @@ export type TextStyleProp = {
 export type ViewStyleProp = {
   style?: StyleProp<ViewStyle>
 }
+
+export type ThemeName = 'light' | 'dim' | 'dark'
+export type Palette = {
+  white: string
+  black: string
+
+  contrast_25: string
+  contrast_50: string
+  contrast_100: string
+  contrast_200: string
+  contrast_300: string
+  contrast_400: string
+  contrast_500: string
+  contrast_600: string
+  contrast_700: string
+  contrast_800: string
+  contrast_900: string
+  contrast_950: string
+  contrast_975: string
+
+  primary_25: string
+  primary_50: string
+  primary_100: string
+  primary_200: string
+  primary_300: string
+  primary_400: string
+  primary_500: string
+  primary_600: string
+  primary_700: string
+  primary_800: string
+  primary_900: string
+  primary_950: string
+  primary_975: string
+
+  positive_25: string
+  positive_50: string
+  positive_100: string
+  positive_200: string
+  positive_300: string
+  positive_400: string
+  positive_500: string
+  positive_600: string
+  positive_700: string
+  positive_800: string
+  positive_900: string
+  positive_950: string
+  positive_975: string
+
+  negative_25: string
+  negative_50: string
+  negative_100: string
+  negative_200: string
+  negative_300: string
+  negative_400: string
+  negative_500: string
+  negative_600: string
+  negative_700: string
+  negative_800: string
+  negative_900: string
+  negative_950: string
+  negative_975: string
+}
+export type ThemedAtoms = {
+  text: {
+    color: string
+  }
+  text_contrast_low: {
+    color: string
+  }
+  text_contrast_medium: {
+    color: string
+  }
+  text_contrast_high: {
+    color: string
+  }
+  text_inverted: {
+    color: string
+  }
+  bg: {
+    backgroundColor: string
+  }
+  bg_contrast_25: {
+    backgroundColor: string
+  }
+  bg_contrast_50: {
+    backgroundColor: string
+  }
+  bg_contrast_100: {
+    backgroundColor: string
+  }
+  bg_contrast_200: {
+    backgroundColor: string
+  }
+  bg_contrast_300: {
+    backgroundColor: string
+  }
+  bg_contrast_400: {
+    backgroundColor: string
+  }
+  bg_contrast_500: {
+    backgroundColor: string
+  }
+  bg_contrast_600: {
+    backgroundColor: string
+  }
+  bg_contrast_700: {
+    backgroundColor: string
+  }
+  bg_contrast_800: {
+    backgroundColor: string
+  }
+  bg_contrast_900: {
+    backgroundColor: string
+  }
+  bg_contrast_950: {
+    backgroundColor: string
+  }
+  bg_contrast_975: {
+    backgroundColor: string
+  }
+  border_contrast_low: {
+    borderColor: string
+  }
+  border_contrast_medium: {
+    borderColor: string
+  }
+  border_contrast_high: {
+    borderColor: string
+  }
+  shadow_sm: {
+    shadowRadius: number
+    shadowOpacity: number
+    elevation: number
+    shadowColor: string
+  }
+  shadow_md: {
+    shadowRadius: number
+    shadowOpacity: number
+    elevation: number
+    shadowColor: string
+  }
+  shadow_lg: {
+    shadowRadius: number
+    shadowOpacity: number
+    elevation: number
+    shadowColor: string
+  }
+}
+export type Theme = {
+  name: ThemeName
+  palette: Palette
+  atoms: ThemedAtoms
+}
diff --git a/src/alf/util/colorGeneration.ts b/src/alf/util/colorGeneration.ts
index 929a01d3a..8d769b51b 100644
--- a/src/alf/util/colorGeneration.ts
+++ b/src/alf/util/colorGeneration.ts
@@ -15,3 +15,7 @@ export function generateScale(start: number, end: number) {
     return start + range * stop
   })
 }
+
+export const defaultScale = generateScale(6, 100)
+// dim shifted 6% lighter
+export const dimScale = generateScale(12, 100)
diff --git a/src/alf/util/themeSelector.ts b/src/alf/util/themeSelector.ts
index f484bc526..e79f86387 100644
--- a/src/alf/util/themeSelector.ts
+++ b/src/alf/util/themeSelector.ts
@@ -1,4 +1,4 @@
-import {ThemeName} from '#/alf/themes'
+import {ThemeName} from '#/alf/types'
 
 export function select<T>(name: ThemeName, options: Record<ThemeName, T>) {
   switch (name) {
diff --git a/src/alf/util/useColorModeTheme.ts b/src/alf/util/useColorModeTheme.ts
index ce1558747..12840c706 100644
--- a/src/alf/util/useColorModeTheme.ts
+++ b/src/alf/util/useColorModeTheme.ts
@@ -4,7 +4,8 @@ import * as SystemUI from 'expo-system-ui'
 
 import {isWeb} from 'platform/detection'
 import {useThemePrefs} from 'state/shell'
-import {dark, dim, light, ThemeName} from '#/alf/themes'
+import {dark, dim, light} from '#/alf/themes'
+import {ThemeName} from '#/alf/types'
 
 export function useColorModeTheme(): ThemeName {
   const theme = useThemeName()
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index dfdcde6ed..457164d11 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -13,7 +13,7 @@ import {
 } from 'react-native'
 import {LinearGradient} from 'expo-linear-gradient'
 
-import {android, atoms as a, flatten, tokens, useTheme} from '#/alf'
+import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf'
 import {Props as SVGIconProps} from '#/components/icons/common'
 import {normalizeTextStyles} from '#/components/Typography'
 
@@ -152,7 +152,6 @@ export const Button = React.forwardRef<View, ButtonProps>(
     const {baseStyles, hoverStyles} = React.useMemo(() => {
       const baseStyles: ViewStyle[] = []
       const hoverStyles: ViewStyle[] = []
-      const light = t.name === 'light'
 
       if (color === 'primary') {
         if (variant === 'solid') {
@@ -165,7 +164,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
             })
           } else {
             baseStyles.push({
-              backgroundColor: t.palette.primary_700,
+              backgroundColor: select(t.name, {
+                light: t.palette.primary_700,
+                dim: t.palette.primary_300,
+                dark: t.palette.primary_300,
+              }),
             })
           }
         } else if (variant === 'outline') {
@@ -178,24 +181,18 @@ export const Button = React.forwardRef<View, ButtonProps>(
               borderColor: t.palette.primary_500,
             })
             hoverStyles.push(a.border, {
-              backgroundColor: light
-                ? t.palette.primary_50
-                : t.palette.primary_950,
+              backgroundColor: t.palette.primary_50,
             })
           } else {
             baseStyles.push(a.border, {
-              borderColor: light
-                ? t.palette.primary_200
-                : t.palette.primary_900,
+              borderColor: t.palette.primary_200,
             })
           }
         } else if (variant === 'ghost') {
           if (!disabled) {
             baseStyles.push(t.atoms.bg)
             hoverStyles.push({
-              backgroundColor: light
-                ? t.palette.primary_100
-                : t.palette.primary_900,
+              backgroundColor: t.palette.primary_100,
             })
           }
         }
@@ -203,14 +200,26 @@ export const Button = React.forwardRef<View, ButtonProps>(
         if (variant === 'solid') {
           if (!disabled) {
             baseStyles.push({
-              backgroundColor: t.palette.contrast_25,
+              backgroundColor: select(t.name, {
+                light: t.palette.contrast_25,
+                dim: t.palette.contrast_100,
+                dark: t.palette.contrast_100,
+              }),
             })
             hoverStyles.push({
-              backgroundColor: t.palette.contrast_50,
+              backgroundColor: select(t.name, {
+                light: t.palette.contrast_50,
+                dim: t.palette.contrast_200,
+                dark: t.palette.contrast_200,
+              }),
             })
           } else {
             baseStyles.push({
-              backgroundColor: t.palette.contrast_100,
+              backgroundColor: select(t.name, {
+                light: t.palette.contrast_100,
+                dim: t.palette.contrast_25,
+                dark: t.palette.contrast_25,
+              }),
             })
           }
         } else if (variant === 'outline') {
@@ -247,7 +256,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
             })
           } else {
             baseStyles.push({
-              backgroundColor: t.palette.contrast_700,
+              backgroundColor: t.palette.contrast_600,
             })
           }
         } else if (variant === 'outline') {
@@ -284,7 +293,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
             })
           } else {
             baseStyles.push({
-              backgroundColor: t.palette.negative_700,
+              backgroundColor: select(t.name, {
+                light: t.palette.negative_700,
+                dim: t.palette.negative_300,
+                dark: t.palette.negative_300,
+              }),
             })
           }
         } else if (variant === 'outline') {
@@ -297,24 +310,18 @@ export const Button = React.forwardRef<View, ButtonProps>(
               borderColor: t.palette.negative_500,
             })
             hoverStyles.push(a.border, {
-              backgroundColor: light
-                ? t.palette.negative_50
-                : t.palette.negative_975,
+              backgroundColor: t.palette.negative_50,
             })
           } else {
             baseStyles.push(a.border, {
-              borderColor: light
-                ? t.palette.negative_200
-                : t.palette.negative_900,
+              borderColor: t.palette.negative_200,
             })
           }
         } else if (variant === 'ghost') {
           if (!disabled) {
             baseStyles.push(t.atoms.bg)
             hoverStyles.push({
-              backgroundColor: light
-                ? t.palette.negative_100
-                : t.palette.negative_975,
+              backgroundColor: t.palette.negative_100,
             })
           }
         }
@@ -482,7 +489,6 @@ export function useSharedButtonTextStyles() {
   const {color, variant, disabled, size} = useButtonContext()
   return React.useMemo(() => {
     const baseStyles: TextStyle[] = []
-    const light = t.name === 'light'
 
     if (color === 'primary') {
       if (variant === 'solid') {
@@ -494,7 +500,7 @@ export function useSharedButtonTextStyles() {
       } else if (variant === 'outline') {
         if (!disabled) {
           baseStyles.push({
-            color: light ? t.palette.primary_600 : t.palette.primary_500,
+            color: t.palette.primary_600,
           })
         } else {
           baseStyles.push({color: t.palette.primary_600, opacity: 0.5})
diff --git a/src/components/IconCircle.tsx b/src/components/IconCircle.tsx
index aa779e37f..806d35c38 100644
--- a/src/components/IconCircle.tsx
+++ b/src/components/IconCircle.tsx
@@ -2,14 +2,14 @@ import React from 'react'
 import {View} from 'react-native'
 
 import {
-  useTheme,
   atoms as a,
-  ViewStyleProp,
-  TextStyleProp,
   flatten,
+  TextStyleProp,
+  useTheme,
+  ViewStyleProp,
 } from '#/alf'
-import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
 import {Props} from '#/components/icons/common'
+import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
 
 export function IconCircle({
   icon: Icon,
@@ -32,8 +32,7 @@ export function IconCircle({
         {
           width: size === 'lg' ? 52 : 64,
           height: size === 'lg' ? 52 : 64,
-          backgroundColor:
-            t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
+          backgroundColor: t.palette.primary_50,
         },
         flatten(style),
       ]}>
diff --git a/src/components/dialogs/MutedWords.tsx b/src/components/dialogs/MutedWords.tsx
index 534263422..526652be9 100644
--- a/src/components/dialogs/MutedWords.tsx
+++ b/src/components/dialogs/MutedWords.tsx
@@ -357,12 +357,11 @@ function TargetToggle({children}: React.PropsWithChildren<{}>) {
         a.px_sm,
         gtMobile && a.px_md,
         a.rounded_sm,
-        t.atoms.bg_contrast_50,
-        (ctx.hovered || ctx.focused) && t.atoms.bg_contrast_100,
+        t.atoms.bg_contrast_25,
+        (ctx.hovered || ctx.focused) && t.atoms.bg_contrast_50,
         ctx.selected && [
           {
-            backgroundColor:
-              t.name === 'light' ? t.palette.primary_50 : t.palette.primary_975,
+            backgroundColor: t.palette.primary_50,
           },
         ],
         ctx.disabled && {
diff --git a/src/components/dialogs/ThreadgateEditor.tsx b/src/components/dialogs/ThreadgateEditor.tsx
index 104766e26..92dd157b2 100644
--- a/src/components/dialogs/ThreadgateEditor.tsx
+++ b/src/components/dialogs/ThreadgateEditor.tsx
@@ -196,10 +196,7 @@ function Selectable({
             t.atoms.bg_contrast_50,
             (hovered || focused) && t.atoms.bg_contrast_100,
             isSelected && {
-              backgroundColor:
-                t.name === 'light'
-                  ? t.palette.primary_50
-                  : t.palette.primary_975,
+              backgroundColor: t.palette.primary_100,
             },
             style,
           ]}>
diff --git a/src/components/dms/MessageItem.tsx b/src/components/dms/MessageItem.tsx
index 61358c989..573c24f77 100644
--- a/src/components/dms/MessageItem.tsx
+++ b/src/components/dms/MessageItem.tsx
@@ -72,8 +72,7 @@ let MessageItem = ({
     lastInGroupRef.current = isLastInGroup
   }
 
-  const pendingColor =
-    t.name === 'light' ? t.palette.primary_200 : t.palette.primary_800
+  const pendingColor = t.palette.primary_200
 
   const rt = useMemo(() => {
     return new RichTextAPI({text: message.text, facets: message.facets})
@@ -110,12 +109,7 @@ let MessageItem = ({
             }>
             <RichText
               value={rt}
-              style={[
-                a.text_md,
-                isFromSelf && {color: t.palette.white},
-                isPending &&
-                  t.name !== 'light' && {color: t.palette.primary_300},
-              ]}
+              style={[a.text_md, isFromSelf && {color: t.palette.white}]}
               interactiveStyle={a.underline}
               enableTags
               emojiMultiplier={3}
diff --git a/src/components/forms/TextField.tsx b/src/components/forms/TextField.tsx
index d513a6db9..a5ecfdcb8 100644
--- a/src/components/forms/TextField.tsx
+++ b/src/components/forms/TextField.tsx
@@ -101,16 +101,13 @@ export function useSharedInputStyles() {
     ]
     const error: ViewStyle[] = [
       {
-        backgroundColor:
-          t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
-        borderColor:
-          t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800,
+        backgroundColor: t.palette.negative_25,
+        borderColor: t.palette.negative_300,
       },
     ]
     const errorHover: ViewStyle[] = [
       {
-        backgroundColor:
-          t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
+        backgroundColor: t.palette.negative_25,
         borderColor: t.palette.negative_500,
       },
     ]
diff --git a/src/components/forms/Toggle.tsx b/src/components/forms/Toggle.tsx
index 7285e5fac..8036223f2 100644
--- a/src/components/forms/Toggle.tsx
+++ b/src/components/forms/Toggle.tsx
@@ -281,24 +281,20 @@ export function createSharedToggleStyles({
 
   if (selected) {
     base.push({
-      backgroundColor:
-        t.name === 'light' ? t.palette.primary_25 : t.palette.primary_900,
+      backgroundColor: t.palette.primary_25,
       borderColor: t.palette.primary_500,
     })
 
     if (hovered) {
       baseHover.push({
-        backgroundColor:
-          t.name === 'light' ? t.palette.primary_100 : t.palette.primary_800,
-        borderColor:
-          t.name === 'light' ? t.palette.primary_600 : t.palette.primary_400,
+        backgroundColor: t.palette.primary_100,
+        borderColor: t.palette.primary_600,
       })
     }
   } else {
     if (hovered) {
       baseHover.push({
-        backgroundColor:
-          t.name === 'light' ? t.palette.contrast_50 : t.palette.contrast_100,
+        backgroundColor: t.palette.contrast_50,
         borderColor: t.palette.contrast_500,
       })
     }
@@ -306,16 +302,13 @@ export function createSharedToggleStyles({
 
   if (isInvalid) {
     base.push({
-      backgroundColor:
-        t.name === 'light' ? t.palette.negative_25 : t.palette.negative_975,
-      borderColor:
-        t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800,
+      backgroundColor: t.palette.negative_25,
+      borderColor: t.palette.negative_300,
     })
 
     if (hovered) {
       baseHover.push({
-        backgroundColor:
-          t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
+        backgroundColor: t.palette.negative_25,
         borderColor: t.palette.negative_600,
       })
     }
diff --git a/src/components/icons/common.tsx b/src/components/icons/common.tsx
index 662718338..387115d3a 100644
--- a/src/components/icons/common.tsx
+++ b/src/components/icons/common.tsx
@@ -4,7 +4,7 @@ import type {PathProps, SvgProps} from 'react-native-svg'
 import {Defs, LinearGradient, Stop} from 'react-native-svg'
 import {nanoid} from 'nanoid/non-secure'
 
-import {tokens} from '#/alf'
+import {tokens, useTheme} from '#/alf'
 
 export type Props = {
   fill?: PathProps['fill']
@@ -22,10 +22,11 @@ export const sizes = {
 }
 
 export function useCommonSVGProps(props: Props) {
+  const t = useTheme()
   const {fill, size, gradient, ...rest} = props
   const style = StyleSheet.flatten(rest.style)
   const _size = Number(size ? sizes[size] : rest.width || sizes.md)
-  let _fill = fill || style?.color || tokens.color.blue_500
+  let _fill = fill || style?.color || t.palette.primary_500
   let gradientDef = null
 
   if (gradient && tokens.gradients[gradient]) {
diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx
index 63e2beeb1..e4cebfcb2 100644
--- a/src/lib/ThemeContext.tsx
+++ b/src/lib/ThemeContext.tsx
@@ -1,7 +1,8 @@
-import React, {ReactNode, createContext, useContext} from 'react'
+import React, {createContext, ReactNode, useContext} from 'react'
 import {TextStyle, ViewStyle} from 'react-native'
+
+import {ThemeName} from '#/alf/types'
 import {darkTheme, defaultTheme, dimTheme} from './themes'
-import {ThemeName} from '#/alf/themes'
 
 export type ColorScheme = 'light' | 'dark'
 
diff --git a/src/lib/themes.ts b/src/lib/themes.ts
index 6fada40a7..f3382fc43 100644
--- a/src/lib/themes.ts
+++ b/src/lib/themes.ts
@@ -1,8 +1,8 @@
 import {Platform} from 'react-native'
-import type {Theme} from './ThemeContext'
-import {colors} from './styles'
 
-import {darkPalette, lightPalette, dimPalette} from '#/alf/themes'
+import {darkPalette, dimPalette, lightPalette} from '#/alf/themes'
+import {colors} from './styles'
+import type {Theme} from './ThemeContext'
 
 export const defaultTheme: Theme = {
   colorScheme: 'light',
@@ -308,8 +308,8 @@ export const darkTheme: Theme = {
       textVeryLight: darkPalette.contrast_400,
       replyLine: darkPalette.contrast_200,
       replyLineDot: darkPalette.contrast_200,
-      unreadNotifBg: darkPalette.primary_975,
-      unreadNotifBorder: darkPalette.primary_900,
+      unreadNotifBg: darkPalette.primary_25,
+      unreadNotifBorder: darkPalette.primary_100,
       postCtrl: darkPalette.contrast_500,
       brandText: darkPalette.primary_500,
       emptyStateIcon: darkPalette.contrast_300,
@@ -357,8 +357,8 @@ export const dimTheme: Theme = {
       textVeryLight: dimPalette.contrast_400,
       replyLine: dimPalette.contrast_200,
       replyLineDot: dimPalette.contrast_200,
-      unreadNotifBg: dimPalette.primary_975,
-      unreadNotifBorder: dimPalette.primary_900,
+      unreadNotifBg: dimPalette.primary_25,
+      unreadNotifBorder: dimPalette.primary_100,
       postCtrl: dimPalette.contrast_500,
       brandText: dimPalette.primary_500,
       emptyStateIcon: dimPalette.contrast_300,
diff --git a/src/view/screens/Storybook/Buttons.tsx b/src/view/screens/Storybook/Buttons.tsx
index 7cc3f60bf..2935103df 100644
--- a/src/view/screens/Storybook/Buttons.tsx
+++ b/src/view/screens/Storybook/Buttons.tsx
@@ -20,29 +20,31 @@ export function Buttons() {
       <H1>Buttons</H1>
 
       <View style={[a.flex_row, a.flex_wrap, a.gap_md, a.align_start]}>
-        {['primary', 'secondary', 'secondary_inverted'].map(color => (
-          <View key={color} style={[a.gap_md, a.align_start]}>
-            {['solid', 'outline', 'ghost'].map(variant => (
-              <React.Fragment key={variant}>
-                <Button
-                  variant={variant as ButtonVariant}
-                  color={color as ButtonColor}
-                  size="large"
-                  label="Click here">
-                  <ButtonText>Button</ButtonText>
-                </Button>
-                <Button
-                  disabled
-                  variant={variant as ButtonVariant}
-                  color={color as ButtonColor}
-                  size="large"
-                  label="Click here">
-                  <ButtonText>Button</ButtonText>
-                </Button>
-              </React.Fragment>
-            ))}
-          </View>
-        ))}
+        {['primary', 'secondary', 'secondary_inverted', 'negative'].map(
+          color => (
+            <View key={color} style={[a.gap_md, a.align_start]}>
+              {['solid', 'outline', 'ghost'].map(variant => (
+                <React.Fragment key={variant}>
+                  <Button
+                    variant={variant as ButtonVariant}
+                    color={color as ButtonColor}
+                    size="large"
+                    label="Click here">
+                    <ButtonText>Button</ButtonText>
+                  </Button>
+                  <Button
+                    disabled
+                    variant={variant as ButtonVariant}
+                    color={color as ButtonColor}
+                    size="large"
+                    label="Click here">
+                    <ButtonText>Button</ButtonText>
+                  </Button>
+                </React.Fragment>
+              ))}
+            </View>
+          ),
+        )}
 
         <View style={[a.flex_row, a.gap_md, a.align_start]}>
           <View style={[a.gap_md, a.align_start]}>
@@ -68,6 +70,7 @@ export function Buttons() {
               ),
             )}
           </View>
+          {/*
           <View style={[a.gap_md, a.align_start]}>
             {['gradient_sunset', 'gradient_nordic', 'gradient_bonfire'].map(
               name => (
@@ -91,6 +94,7 @@ export function Buttons() {
               ),
             )}
           </View>
+            */}
         </View>
       </View>
 
diff --git a/src/view/screens/Storybook/Forms.tsx b/src/view/screens/Storybook/Forms.tsx
index 1e4efdcc7..8c888f04d 100644
--- a/src/view/screens/Storybook/Forms.tsx
+++ b/src/view/screens/Storybook/Forms.tsx
@@ -41,6 +41,16 @@ export function Forms() {
           />
         </TextField.Root>
 
+        <TextField.Root>
+          <TextField.Icon icon={Globe} />
+          <TextField.Input
+            value={value}
+            onChangeText={setValue}
+            label="Text field"
+            isInvalid
+          />
+        </TextField.Root>
+
         <View style={[a.w_full]}>
           <TextField.LabelText>Text field</TextField.LabelText>
           <TextField.Root>