Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 252 lines 5.9 kB view raw
1import React from 'react' 2import {createTheme, type Theme, type ThemeName} from '@bsky.app/alf' 3import chroma from 'chroma-js' 4 5import {useThemePrefs} from '#/state/shell/color-mode' 6import { 7 computeFontScaleMultiplier, 8 getFontFamily, 9 getFontScale, 10 setFontFamily as persistFontFamily, 11 setFontScale as persistFontScale, 12} from '#/alf/fonts' 13import { 14 blackskyscheme, 15 blueskyscheme, 16 catppuccinscheme, 17 deerscheme, 18 evergardenscheme, 19 kittyscheme, 20 type Palette, 21 reddwarfscheme, 22 themes, 23 witchskyscheme, 24 zeppelinscheme, 25} from '#/alf/themes' 26import {type Device} from '#/storage' 27 28export { 29 type TextStyleProp, 30 type Theme, 31 utils, 32 type ViewStyleProp, 33} from '@bsky.app/alf' 34export {atoms} from '#/alf/atoms' 35export * from '#/alf/breakpoints' 36export * from '#/alf/fonts' 37export * as tokens from '#/alf/tokens' 38export * from '#/alf/util/flatten' 39export * from '#/alf/util/platform' 40export * from '#/alf/util/themeSelector' 41export * from '#/alf/util/useGutters' 42 43export type Alf = { 44 themeName: ThemeName 45 theme: Theme 46 themes: typeof themes 47 fonts: { 48 scale: Exclude<Device['fontScale'], undefined> 49 scaleMultiplier: number 50 family: Device['fontFamily'] 51 setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void 52 setFontFamily: (fontFamily: Device['fontFamily']) => void 53 } 54 /** 55 * Feature flags or other gated options 56 */ 57 flags: {} 58} 59 60/* 61 * Context 62 */ 63export const Context = React.createContext<Alf>({ 64 themeName: 'light', 65 theme: themes.light, 66 themes, 67 fonts: { 68 scale: getFontScale(), 69 scaleMultiplier: computeFontScaleMultiplier(getFontScale()), 70 family: getFontFamily(), 71 setFontScale: () => {}, 72 setFontFamily: () => {}, 73 }, 74 flags: {}, 75}) 76Context.displayName = 'AlfContext' 77 78export type SchemeType = typeof themes 79 80export function changeHue(colorStr: string, hueShift: number) { 81 if (!hueShift || hueShift === 0) return colorStr 82 83 const color = chroma(colorStr).oklch() 84 85 const newHue = (color[2] + hueShift + 360) % 360 86 87 return chroma.oklch(color[0], color[1], newHue).hex() 88} 89 90export function shiftPalette(palette: Palette, hueShift: number): Palette { 91 const newPalette = {...palette} 92 const keys = Object.keys(newPalette) as Array<keyof Palette> 93 94 keys.forEach(key => { 95 if ( 96 key.startsWith('positive_') || 97 key.startsWith('negative_') || 98 key === 'like' || 99 key === 'pink' || 100 key === 'yellow' 101 ) { 102 return 103 } 104 newPalette[key] = changeHue(newPalette[key], hueShift) 105 }) 106 107 return newPalette 108} 109 110export function hueShifter(scheme: SchemeType, hueShift: number): SchemeType { 111 if (!hueShift || hueShift === 0) { 112 return scheme 113 } 114 115 const lightPalette = shiftPalette(scheme.lightPalette, hueShift) 116 const darkPalette = shiftPalette(scheme.darkPalette, hueShift) 117 const dimPalette = shiftPalette(scheme.dimPalette, hueShift) 118 119 const light = createTheme({ 120 scheme: 'light', 121 name: 'light', 122 palette: lightPalette, 123 }) 124 125 const dark = createTheme({ 126 scheme: 'dark', 127 name: 'dark', 128 palette: darkPalette, 129 options: { 130 shadowOpacity: 0.4, 131 }, 132 }) 133 134 const dim = createTheme({ 135 scheme: 'dark', 136 name: 'dim', 137 palette: dimPalette, 138 options: { 139 shadowOpacity: 0.4, 140 }, 141 }) 142 143 return { 144 lightPalette, 145 darkPalette, 146 dimPalette, 147 light, 148 dark, 149 dim, 150 } 151} 152 153export function selectScheme(colorScheme: string | undefined): SchemeType { 154 switch (colorScheme) { 155 case 'witchsky': 156 return witchskyscheme 157 case 'bluesky': 158 return blueskyscheme 159 case 'blacksky': 160 return blackskyscheme 161 case 'deer': 162 return deerscheme 163 case 'zeppelin': 164 return zeppelinscheme 165 case 'kitty': 166 return kittyscheme 167 case 'reddwarf': 168 return reddwarfscheme 169 case 'catppuccin': 170 return catppuccinscheme 171 case 'evergarden': 172 return evergardenscheme 173 default: 174 return themes 175 } 176} 177 178export function ThemeProvider({ 179 children, 180 theme: themeName, 181}: React.PropsWithChildren<{theme: ThemeName}>) { 182 const {colorScheme, hue} = useThemePrefs() 183 const currentScheme = selectScheme(colorScheme) 184 const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(() => 185 getFontScale(), 186 ) 187 const [fontScaleMultiplier, setFontScaleMultiplier] = React.useState(() => 188 computeFontScaleMultiplier(fontScale), 189 ) 190 const setFontScaleAndPersist = React.useCallback< 191 Alf['fonts']['setFontScale'] 192 >( 193 fs => { 194 setFontScale(fs) 195 persistFontScale(fs) 196 setFontScaleMultiplier(computeFontScaleMultiplier(fs)) 197 }, 198 [setFontScale], 199 ) 200 const [fontFamily, setFontFamily] = React.useState<Alf['fonts']['family']>( 201 () => getFontFamily(), 202 ) 203 const setFontFamilyAndPersist = React.useCallback< 204 Alf['fonts']['setFontFamily'] 205 >( 206 ff => { 207 setFontFamily(ff) 208 persistFontFamily(ff) 209 }, 210 [setFontFamily], 211 ) 212 213 const value = React.useMemo<Alf>(() => { 214 const shiftedThemes = hueShifter(currentScheme, hue) 215 216 return { 217 themes: shiftedThemes, 218 themeName: themeName, 219 theme: shiftedThemes[themeName], 220 fonts: { 221 scale: fontScale, 222 scaleMultiplier: fontScaleMultiplier, 223 family: fontFamily, 224 setFontScale: setFontScaleAndPersist, 225 setFontFamily: setFontFamilyAndPersist, 226 }, 227 flags: {}, 228 } 229 }, [ 230 currentScheme, 231 hue, 232 themeName, 233 fontScale, 234 fontScaleMultiplier, 235 fontFamily, 236 setFontScaleAndPersist, 237 setFontFamilyAndPersist, 238 ]) 239 240 return <Context.Provider value={value}>{children}</Context.Provider> 241} 242 243export function useAlf() { 244 return React.useContext(Context) 245} 246 247export function useTheme(theme?: ThemeName) { 248 const alf = useAlf() 249 return React.useMemo(() => { 250 return theme ? alf.themes[theme] : alf.theme 251 }, [theme, alf]) 252}