diff --git a/apps/web/src/app/app-routes.tsx b/apps/web/src/app/app-routes.tsx
index 9f8729d..379a2ea 100644
--- a/apps/web/src/app/app-routes.tsx
+++ b/apps/web/src/app/app-routes.tsx
@@ -18,7 +18,7 @@ const routes: RouteObject[] = [
{ path: '/dashboard', element: },
{ path: '/demo/*', element: },
{ path: '/dev', element: },
- { path: '/themes', element: },
+ { path: '/themes/*', element: },
{ path: '*', element: },
]
diff --git a/apps/web/src/app/app-theme.provider.tsx b/apps/web/src/app/app-theme.provider.tsx
index b961b6d..e89133b 100644
--- a/apps/web/src/app/app-theme.provider.tsx
+++ b/apps/web/src/app/app-theme.provider.tsx
@@ -3,6 +3,7 @@ import {
BACKGROUND_COLORS,
BackgroundColors,
defaultThemes,
+ mantineColorIds,
themeWithBrand,
UiTheme,
UiThemeSelectProvider,
@@ -10,24 +11,55 @@ import {
import { ThemeLink } from './app-routes'
import { atomWithStorage } from 'jotai/utils'
import { atom, useAtomValue, useSetAtom } from 'jotai/index'
-import { Button, MantineColor, Menu } from '@mantine/core'
+import { Button, Divider, MantineColor, Menu } from '@mantine/core'
+import { Link } from 'react-router-dom'
export interface AppTheme extends UiTheme {
active?: boolean
}
+function createAppTheme(color: MantineColor, dark?: BackgroundColors) {
+ const id = `${color}-${dark ?? 'default'}`
+ // Make sure `color` and `dark` are valid values
+ if (dark && !Object.keys(BACKGROUND_COLORS).includes(dark ?? 'default')) {
+ throw new Error(`Invalid value for dark: ${dark}`)
+ }
+ if (!mantineColorIds.includes(color)) {
+ console.log(`Invalid color: ${color}`)
+ throw new Error(`Invalid value for color: ${color}`)
+ }
+
+ return {
+ id,
+ theme: themeWithBrand(color, {
+ components: {
+ Input: {
+ styles: {
+ root: {
+ // backgroundColor: 'transparent',
+ },
+ },
+ },
+ },
+ colors: { dark: dark ? BACKGROUND_COLORS[dark] : undefined },
+ }),
+ }
+}
+
const appThemes: AppTheme[] = [
...defaultThemes,
- { id: 'gray-pink', theme: themeWithBrand('pink', { colors: { dark: BACKGROUND_COLORS['gray'] } }) },
- { id: 'zinc-pink', theme: themeWithBrand('pink', { colors: { dark: BACKGROUND_COLORS['zinc'] } }) },
- { id: 'neutral-pink', theme: themeWithBrand('pink', { colors: { dark: BACKGROUND_COLORS['neutral'] } }) },
- { id: 'slate-pink', theme: themeWithBrand('pink', { colors: { dark: BACKGROUND_COLORS['slate'] } }) },
- { id: 'stone-pink', theme: themeWithBrand('pink', { colors: { dark: BACKGROUND_COLORS['stone'] } }) },
- { id: 'gray-blue', theme: themeWithBrand('blue', { colors: { dark: BACKGROUND_COLORS['gray'] } }) },
- { id: 'zinc-blue', theme: themeWithBrand('blue', { colors: { dark: BACKGROUND_COLORS['zinc'] } }) },
- { id: 'neutral-blue', theme: themeWithBrand('blue', { colors: { dark: BACKGROUND_COLORS['neutral'] } }) },
- { id: 'slate-blue', theme: themeWithBrand('blue', { colors: { dark: BACKGROUND_COLORS['slate'] } }) },
- { id: 'stone-blue', theme: themeWithBrand('blue', { colors: { dark: BACKGROUND_COLORS['stone'] } }) },
+ createAppTheme('blue'),
+ createAppTheme('red'),
+ createAppTheme('pink'),
+ createAppTheme('grape'),
+ createAppTheme('violet'),
+ createAppTheme('indigo'),
+ createAppTheme('cyan'),
+ createAppTheme('green'),
+ createAppTheme('lime'),
+ createAppTheme('yellow'),
+ createAppTheme('orange'),
+ createAppTheme('teal'),
]
const initialThemes = appThemes
@@ -39,7 +71,7 @@ const themesAtom = atomWithStorage('pubkey-ui-app-themes', initialTh
const activeThemesAtom = atom((get) => {
const themes = get(themesAtom)
const theme = get(themeAtom)
- return themes.map((item) => ({
+ return themes?.map((item) => ({
...item,
active: item.id === theme.id,
}))
@@ -48,7 +80,7 @@ const activeThemesAtom = atom((get) => {
const activeThemeAtom = atom((get) => {
const themes = get(activeThemesAtom)
- return themes.find((item) => item.active) || themes[0]
+ return themes?.find((item) => item.active) || themes[0]
})
export interface AppThemeProviderContext {
@@ -56,7 +88,7 @@ export interface AppThemeProviderContext {
themes: AppTheme[]
addTheme: (color: MantineColor, dark?: BackgroundColors) => void
setTheme: (theme: AppTheme) => void
- resetThemes: () => void
+ resetThemes: () => Promise
}
const Context = createContext({} as AppThemeProviderContext)
@@ -71,27 +103,25 @@ export function AppThemeProvider({ children }: { children: ReactNode }) {
theme,
themes,
addTheme: (color: MantineColor, dark?: BackgroundColors) => {
- const id = `${color}-${dark ?? 'default'}`
+ const theme = createAppTheme(color, dark)
// Make sure we don't add a theme with the same id
- if (themes.find((item) => item.id === id)) {
+ if (themes.find((item) => item.id === theme.id)) {
return
}
- const theme: AppTheme = {
- id,
- theme: themeWithBrand(color, { colors: { dark: dark ? BACKGROUND_COLORS[dark] : undefined } }),
- }
+
setThemes((prev) => [...prev, theme])
setTheme(theme)
},
- resetThemes: () => {
- setThemes(initialThemes)
+ resetThemes: async () => {
+ setTheme({ ...initialTheme })
+ setThemes(() => [...initialThemes])
},
setTheme,
}
return (
-
+
{children}
@@ -116,6 +146,10 @@ export function AppThemeSelect() {
{item.id}
))}
+
+
+ App Themes
+
)
diff --git a/apps/web/src/app/features/themes/themes-feature.tsx b/apps/web/src/app/features/themes/themes-feature.tsx
index 77591ce..15189f8 100644
--- a/apps/web/src/app/features/themes/themes-feature.tsx
+++ b/apps/web/src/app/features/themes/themes-feature.tsx
@@ -5,35 +5,65 @@ import {
UiCard,
UiContainer,
UiDebug,
+ UiDebugModal,
UiInfo,
UiStack,
useUiThemeSelect,
} from '@pubkey-ui/core'
import { useAppTheme } from '../../app-theme.provider'
-import { Button, Group, MantineColor, Select } from '@mantine/core'
+import { Button, Grid, Group, MantineColor, Select, Text } from '@mantine/core'
import { useState } from 'react'
+import { DemoFeatureTabRoutes } from '../demo/demo-feature-tab-routes'
+import { DemoFeatureLoader } from '../demo/demo-feature-loader'
+import { DemoFeatureAlerts } from '../demo/demo-feature-alerts'
+import { DemoFeatureAnchor } from '../demo/demo-feature-anchor'
+import { DemoFeatureBack } from '../demo/demo-feature-back'
+import { DemoFeatureCopy } from '../demo/demo-feature-copy'
+import { DemoFeatureForm } from '../demo/demo-feature-form'
+import { DemoFeatureGridRoutes } from '../demo/demo-feature-grid-routes'
+import { DemoFeatureHeader } from '../demo/demo-feature-header'
+import { DemoFeatureMenu } from '../demo/demo-feature-menu'
+import { DemoFeatureNotFound } from '../demo/demo-feature-not-found'
+import { DemoFeaturePage } from '../demo/demo-feature-page'
+import { DemoFeatureSearchInput } from '../demo/demo-feature-search-input'
export function ThemesFeature() {
- const { themes, addTheme, setTheme, theme } = useAppTheme()
+ const { themes, addTheme, resetThemes, setTheme, theme } = useAppTheme()
const { selected } = useUiThemeSelect()
return (
+
+ These are some local themes that are stored in your browser.
+
+
+
+
+
+ }
+ />
-
- {themes.map((item) => (
-
- ))}
+ {themes
+ .sort((a, b) => a.id.localeCompare(b.id))
+ .map((item) => (
+
+ ))}
-
+
+
)
@@ -49,7 +79,7 @@ export function ThemeForm({ add }: { add: (color: MantineColor, dark?: Backgroun
label="Color"
description="Select the primary color"
required
- data={mantineColorIds.map((id) => ({ label: id, value: id }))}
+ data={mantineColorIds.sort((a, b) => a.localeCompare(b)).map((id) => ({ label: id, value: id }))}
value={color}
onChange={(value) => (value ? setColor(value as MantineColor) : undefined)}
/>
@@ -58,7 +88,7 @@ export function ThemeForm({ add }: { add: (color: MantineColor, dark?: Backgroun
label="Dark"
description="Select the dark color"
clearable
- data={backgroundColorIds.map((id) => ({ label: id, value: id }))}
+ data={backgroundColorIds.sort((a, b) => a.localeCompare(b)).map((id) => ({ label: id, value: id }))}
value={dark}
onChange={(value) => (value ? setDark(value as BackgroundColors) : undefined)}
/>
@@ -72,3 +102,37 @@ export function ThemeForm({ add }: { add: (color: MantineColor, dark?: Backgroun
)
}
+
+export function AppThemeUiDemo() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}