An ATproto social media client -- with an independent Appview.

refactor!: remove deprecated `usePalette` hook

removes the already-deprecated `usePalette` hook from the codebase.

authored by

serenity and committed by
GitHub
61535897 ee11b4fa

+1634 -592
+3
.editorconfig
··· 1 1 [*.{kt,kts}] 2 2 indent_size=2 3 + 4 + [*.{ts,tsx}] 5 + indent_size=2
+28
src/alf/catppuccin/palette.ts
··· 1 + export const mocha = { 2 + crust: '#11111b', 3 + mantle: '#181825', 4 + base: '#1e1e2e', 5 + surface0: '#313244', 6 + surface1: '#45475a', 7 + surface2: '#585b70', 8 + overlay0: '#6c7086', 9 + overlay1: '#7f849c', 10 + overlay2: '#9399b2', 11 + subtext0: '#a6adc8', 12 + subtext1: '#bac2de', 13 + text: '#cdd6f4', 14 + lavender: '#b4befe', 15 + blue: '#89b4fa', 16 + sapphire: '#74c7ec', 17 + sky: '#89dceb', 18 + teal: '#94e2d5', 19 + green: '#a6e3a1', 20 + yellow: '#f9e2af', 21 + peach: '#fab387', 22 + maroon: '#eba0ac', 23 + red: '#f38ba8', 24 + mauve: '#cba6f7', 25 + pink: '#f5c2e7', 26 + flamingo: '#f2cdcd', 27 + rosewater: '#f5e0dc', 28 + }
+223
src/alf/util/colors/conversion.ts
··· 1 + import {type HexCode, type HslColor, type RgbColor} from '#/alf/util/colors' 2 + 3 + /** 4 + * Converts a hexcode string in the format `"#RRGGBB"` to a `HslColor` object (`{ h: number, s: number, l: number, a: number}`). 5 + * @param {HexCode} hex - A hexcode string in the format `#RRGGBB`. The leading "#" symbol is optional. 6 + * @returns{HslColor} A HSL colour object. 7 + */ 8 + export const hexToHsl = (hex: HexCode): HslColor => { 9 + hex = hex.replace('#', '') 10 + 11 + const r = parseInt(hex.substring(0, 2), 16) / 255 12 + const g = parseInt(hex.substring(2, 4), 16) / 255 13 + const b = parseInt(hex.substring(4, 6), 16) / 255 14 + const a = hex.length > 6 ? parseInt(hex.substring(6, 8), 16) / 255 : undefined 15 + 16 + const max = Math.max(r, g, b) 17 + const min = Math.min(r, g, b) 18 + const diff = max - min 19 + 20 + let h = 0, 21 + s, 22 + l 23 + 24 + l = (max + min) / 2 25 + 26 + if (diff === 0) { 27 + h = s = 0 28 + } else { 29 + s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min) 30 + 31 + switch (max) { 32 + case r: 33 + h = (g - b) / diff + (g < b ? 6 : 0) 34 + break 35 + case g: 36 + h = (b - r) / diff + 2 37 + break 38 + case b: 39 + h = (r - g) / diff + 4 40 + break 41 + } 42 + h /= 6 43 + } 44 + 45 + return { 46 + h: h * 360, 47 + s: s * 100, 48 + l: l * 100, 49 + a, 50 + } 51 + } 52 + 53 + /** 54 + * Converts a `HslColor` object (`{ h: number, s: number, l: number, a: number }`) to a hexcode string in the format `"#RRGGBB"`. 55 + * @param {HslColor} hsl - A HSL colour object. 56 + * @param {boolean} appendSymbol - Whether to append "#" to the start of the hex string. Defaults to true. 57 + * @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional. 58 + */ 59 + export const hslToHex = ( 60 + {h, s, l, a}: HslColor, 61 + appendSymbol: boolean = true, 62 + ): HexCode => { 63 + h = (h % 360) / 360 64 + s = Math.max(0, Math.min(1, s / 100)) 65 + l = Math.max(0, Math.min(1, l / 100)) 66 + 67 + let m2: number, m1: number 68 + 69 + if (l <= 0.5) { 70 + m2 = l * (s + 1) 71 + } else { 72 + m2 = l + s - l * s 73 + } 74 + 75 + m1 = l * 2 - m2 76 + 77 + function hue(hueValue: number) { 78 + hueValue = 79 + hueValue < 0 ? hueValue + 1 : hueValue > 1 ? hueValue - 1 : hueValue 80 + 81 + if (hueValue * 6 < 1) { 82 + return m1 + (m2 - m1) * hueValue * 6 83 + } else if (hueValue * 2 < 1) { 84 + return m2 85 + } else if (hueValue * 3 < 2) { 86 + return m1 + (m2 - m1) * (2 / 3 - hueValue) * 6 87 + } else { 88 + return m1 89 + } 90 + } 91 + 92 + const r = Math.round(hue(h + 1 / 3) * 255) 93 + const g = Math.round(hue(h) * 255) 94 + const b = Math.round(hue(h - 1 / 3) * 255) 95 + 96 + return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}${typeof a !== 'undefined' ? Math.round(a).toString(16) : ''}` 97 + } 98 + 99 + /** 100 + * Converts an `RgbColor` object (`{ r: number, g: number, b: number, a: number }`) to a hexcode string in the format `"#RRGGBB"`. 101 + * @param {RgbColor} rgb - An RGB colour object. 102 + * @param {boolean} appendSymbol - Whether to append "#" to the start of the hex string. Defaults to true. 103 + * @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional. 104 + */ 105 + export const rgbToHex = ( 106 + {r, g, b, a}: RgbColor, 107 + appendSymbol: boolean = true, 108 + ): HexCode => { 109 + return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}${typeof a !== 'undefined' ? a.toString(16) : ''}` 110 + } 111 + 112 + /** 113 + * Converts a hexcode string in the format `"#RRGGBB"` to an `RgbColor` object (`{ r: number, g: number, b: number, a: number }`). 114 + * @param {HexCode} hex - A hexcode string in the format `#RRGGBB`. The leading "#" symbol is optional. 115 + * @returns {RgbColor} An RGB colour object. 116 + */ 117 + export const hexToRgb = (hex: HexCode): RgbColor => { 118 + hex = hex.replace('#', '') 119 + const r = parseInt(hex.substring(0, 2), 16) / 255 120 + const g = parseInt(hex.substring(2, 4), 16) / 255 121 + const b = parseInt(hex.substring(4, 6), 16) / 255 122 + const a = hex.length > 6 ? parseInt(hex.substring(6, 8), 16) / 255 : undefined 123 + return {r, g, b, a} 124 + } 125 + 126 + /** 127 + * Converts an `RgbColor` object (`{ r: number, g: number, b: number, a: number }`) to a `HslColor` object (`{ h: number, s: number, l: number, a: number }`) 128 + * @param {RgbColor} - An RGB colour object. 129 + * @returns {HslColor} A HSL colour object. 130 + */ 131 + export const rgbToHsl = ({r, g, b, a}: RgbColor): HslColor => { 132 + r = r / 255 133 + g = g / 255 134 + b = b / 255 135 + const max = Math.max(r, g, b) 136 + const min = Math.min(r, g, b) 137 + const diff = max - min 138 + 139 + let h = 0, 140 + s, 141 + l 142 + 143 + l = (max + min) / 2 144 + 145 + if (diff === 0) { 146 + h = s = 0 147 + } else { 148 + s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min) 149 + 150 + switch (max) { 151 + case r: 152 + h = (g - b) / diff + (g < b ? 6 : 0) 153 + break 154 + case g: 155 + h = (b - r) / diff + 2 156 + break 157 + case b: 158 + h = (r - g) / diff + 4 159 + break 160 + } 161 + h /= 6 162 + } 163 + 164 + return { 165 + h: h * 360, 166 + s: s * 100, 167 + l: l * 100, 168 + a: typeof a !== 'undefined' ? (a / 255) * 100 : undefined, 169 + } 170 + } 171 + 172 + /** 173 + * Converts a `HslColor` object (`{ h: number, s: number, l: number, a: number }`) to a `RgbColor` object (`{ r: number, g: number, b: number, a: number }`) 174 + * @param {HslColor} - A HSL colour object. 175 + * @returns {RgbColor} An RGB colour object. 176 + */ 177 + export const hslToRgb = ({h, s, l, a}: HslColor): RgbColor => { 178 + h = (h % 360) / 360 179 + s = Math.max(0, Math.min(1, s / 100)) 180 + l = Math.max(0, Math.min(1, l / 100)) 181 + 182 + let m2: number, m1: number 183 + 184 + if (l <= 0.5) { 185 + m2 = l * (s + 1) 186 + } else { 187 + m2 = l + s - l * s 188 + } 189 + 190 + m1 = l * 2 - m2 191 + 192 + function hue(hueValue: number) { 193 + hueValue = 194 + hueValue < 0 ? hueValue + 1 : hueValue > 1 ? hueValue - 1 : hueValue 195 + 196 + if (hueValue * 6 < 1) { 197 + return m1 + (m2 - m1) * hueValue * 6 198 + } else if (hueValue * 2 < 1) { 199 + return m2 200 + } else if (hueValue * 3 < 2) { 201 + return m1 + (m2 - m1) * (2 / 3 - hueValue) * 6 202 + } else { 203 + return m1 204 + } 205 + } 206 + 207 + const r = hue(h + 1 / 3) * 255 208 + const g = hue(h) * 255 209 + const b = hue(h - 1 / 3) * 255 210 + 211 + return { 212 + r: Math.round(r), 213 + g: Math.round(g), 214 + b: Math.round(b), 215 + a: typeof a !== 'undefined' ? (a / 100) * 255 : undefined, 216 + } 217 + } 218 + 219 + export const rgbObjectToString = ({r, g, b, a}: RgbColor) => { 220 + const res = `rgba(${r}, ${g}, ${b}${a ? `, ${(a / 255) * 100}` : ''})` 221 + console.log(res) 222 + return res 223 + }
+66
src/alf/util/colors/index.ts
··· 1 + import { 2 + hexToHsl, 3 + hslToHex, 4 + hslToRgb, 5 + rgbObjectToString, 6 + } from '#/alf/util/colors/conversion' 7 + 8 + export interface HslColor { 9 + h: number 10 + s: number 11 + l: number 12 + a?: number 13 + } 14 + 15 + export interface RgbColor { 16 + r: number 17 + g: number 18 + b: number 19 + a?: number 20 + } 21 + 22 + export type HexCode = `#${string}` | string 23 + 24 + export const clamp = (val: number) => { 25 + return Math.min(1, Math.max(0, val)) 26 + } 27 + 28 + export const lighten = ( 29 + hex: HexCode, 30 + amount: number, 31 + method: 'relative' | undefined = undefined, 32 + ) => { 33 + const hsl = hexToHsl(hex) 34 + 35 + if (typeof method !== 'undefined' && method === 'relative') { 36 + hsl.l += (hsl.l * amount) / 100 37 + } else { 38 + hsl.l += amount / 100 39 + } 40 + hsl.l = clamp(hsl.l) 41 + return hslToHex(hsl) 42 + } 43 + 44 + export const darken = ( 45 + hex: HexCode, 46 + amount: number, 47 + method: 'relative' | undefined = undefined, 48 + ) => { 49 + const hsl = hexToHsl(hex) 50 + 51 + if (typeof method !== 'undefined' && method === 'relative') { 52 + hsl.l -= (hsl.l * amount) / 100 53 + } else { 54 + hsl.l -= amount / 100 55 + } 56 + hsl.l = clamp(hsl.l) 57 + return hslToHex(hsl) 58 + } 59 + 60 + export const fade = (hex: HexCode, amount: number) => { 61 + const hsl = hexToHsl(hex) 62 + 63 + hsl.a = amount / 100 64 + hsl.a = clamp(hsl.a) 65 + return rgbObjectToString(hslToRgb(hsl)) 66 + }
+13 -4
src/components/Post/Embed/PostPlaceholder.tsx
··· 1 1 import {StyleSheet, View} from 'react-native' 2 2 3 - import {usePalette} from '#/lib/hooks/usePalette' 4 3 import {InfoCircleIcon} from '#/lib/icons' 5 4 import {Text} from '#/view/com/util/text/Text' 6 5 import {atoms as a, useTheme} from '#/alf' 6 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 7 7 8 8 export function PostPlaceholder({children}: {children: React.ReactNode}) { 9 9 const t = useTheme() 10 - const pal = usePalette('default') 10 + const colorMode = useColorModeTheme() 11 11 return ( 12 12 <View 13 13 style={[styles.errorContainer, a.border, t.atoms.border_contrast_low]}> 14 - <InfoCircleIcon size={18} style={pal.text} /> 15 - <Text type="lg" style={pal.text}> 14 + <InfoCircleIcon 15 + size={18} 16 + style={{ 17 + color: colorMode === 'light' ? t.palette.black : t.palette.white, 18 + }} 19 + /> 20 + <Text 21 + type="lg" 22 + style={{ 23 + color: colorMode === 'light' ? t.palette.black : t.palette.white, 24 + }}> 16 25 {children} 17 26 </Text> 18 27 </View>
+5 -7
src/components/Post/Embed/index.tsx
··· 11 11 import {Trans} from '@lingui/macro' 12 12 import {useQueryClient} from '@tanstack/react-query' 13 13 14 - import {usePalette} from '#/lib/hooks/usePalette' 15 14 import {makeProfileLink} from '#/lib/routes/links' 16 15 import {useModerationOpts} from '#/state/preferences/moderation-opts' 17 16 import {unstableCacheProfileView} from '#/state/queries/profile' ··· 176 175 case 'post_not_found': { 177 176 return ( 178 177 <PostPlaceholderText> 179 - <Trans>Deleted</Trans> 178 + <Trans>Deleted </Trans> 180 179 </PostPlaceholderText> 181 180 ) 182 181 } 183 182 case 'post_blocked': { 184 183 return ( 185 184 <PostPlaceholderText> 186 - <Trans>Blocked</Trans> 185 + <Trans>Blocked </Trans> 187 186 </PostPlaceholderText> 188 187 ) 189 188 } ··· 209 208 return ( 210 209 <PostPlaceholderText> 211 210 {isViewerOwner ? ( 212 - <Trans>Removed by you</Trans> 211 + <Trans> Removed by you </Trans> 213 212 ) : ( 214 - <Trans>Removed by author</Trans> 213 + <Trans>Removed by author </Trans> 215 214 )} 216 215 </PostPlaceholderText> 217 216 ) ··· 247 246 248 247 const t = useTheme() 249 248 const queryClient = useQueryClient() 250 - const pal = usePalette('default') 251 249 const itemUrip = new AtUri(quote.uri) 252 250 const itemHref = makeProfileLink(quote.author, 'post', itemUrip.rkey) 253 251 const itemTitle = `Post by ${quote.author.handle}` ··· 287 285 {!active && <SubtleWebHover hover={hover} style={[a.rounded_md]} />} 288 286 <Link 289 287 style={[!active && a.p_md]} 290 - hoverStyle={{borderColor: pal.colors.borderLinkHover}} 288 + hoverStyle={{borderColor: t.palette.contrast_300}} 291 289 href={itemHref} 292 290 title={itemTitle} 293 291 onBeforePress={onBeforePress}>
+6 -4
src/components/SearchError.tsx
··· 1 1 import {View} from 'react-native' 2 2 3 - import {usePalette} from '#/lib/hooks/usePalette' 4 - import {atoms as a, useBreakpoints} from '#/alf' 3 + import {atoms as a, useBreakpoints, useTheme} from '#/alf' 5 4 import * as Layout from '#/components/Layout' 6 5 import {Text} from '#/components/Typography' 7 6 import {TimesLarge_Stroke2_Corner0_Rounded} from './icons/Times' ··· 13 12 title?: string 14 13 children?: React.ReactNode 15 14 }) { 15 + const theme = useTheme() 16 16 const {gtMobile} = useBreakpoints() 17 - const pal = usePalette('default') 18 17 19 18 return ( 20 19 <Layout.Content> ··· 27 26 paddingVertical: 150, 28 27 }, 29 28 ]}> 30 - <TimesLarge_Stroke2_Corner0_Rounded width={32} fill={pal.colors.icon} /> 29 + <TimesLarge_Stroke2_Corner0_Rounded 30 + width={32} 31 + fill={theme.palette.contrast_500} 32 + /> 31 33 <View 32 34 style={[ 33 35 a.align_center,
-65
src/lib/hooks/usePalette.ts
··· 1 - import {useMemo} from 'react' 2 - import {type TextStyle, type ViewStyle} from 'react-native' 3 - 4 - import { 5 - type PaletteColor, 6 - type PaletteColorName, 7 - useTheme, 8 - } from '../ThemeContext' 9 - 10 - export interface UsePaletteValue { 11 - colors: PaletteColor 12 - view: ViewStyle 13 - viewLight: ViewStyle 14 - btn: ViewStyle 15 - border: ViewStyle 16 - borderDark: ViewStyle 17 - text: TextStyle 18 - textLight: TextStyle 19 - textInverted: TextStyle 20 - link: TextStyle 21 - icon: TextStyle 22 - } 23 - 24 - /** 25 - * @deprecated use `useTheme` from `#/alf` 26 - */ 27 - export function usePalette(color: PaletteColorName): UsePaletteValue { 28 - const theme = useTheme() 29 - return useMemo(() => { 30 - const palette = theme.palette[color] 31 - return { 32 - colors: palette, 33 - view: { 34 - backgroundColor: palette.background, 35 - }, 36 - viewLight: { 37 - backgroundColor: palette.backgroundLight, 38 - }, 39 - btn: { 40 - backgroundColor: palette.backgroundLight, 41 - }, 42 - border: { 43 - borderColor: palette.border, 44 - }, 45 - borderDark: { 46 - borderColor: palette.borderDark, 47 - }, 48 - text: { 49 - color: palette.text, 50 - }, 51 - textLight: { 52 - color: palette.textLight, 53 - }, 54 - textInverted: { 55 - color: palette.textInverted, 56 - }, 57 - link: { 58 - color: palette.link, 59 - }, 60 - icon: { 61 - color: palette.icon, 62 - }, 63 - } 64 - }, [theme, color]) 65 - }
+25 -9
src/screens/Profile/ProfileFeed/index.tsx
··· 1 1 import React, {useCallback, useMemo} from 'react' 2 - import {StyleSheet, View} from 'react-native' 2 + import {StyleSheet, type TextStyle, View} from 'react-native' 3 3 import {useAnimatedRef} from 'react-native-reanimated' 4 4 import {AppBskyFeedDefs} from '@atproto/api' 5 5 import {msg, Trans} from '@lingui/macro' ··· 10 10 11 11 import {VIDEO_FEED_URIS} from '#/lib/constants' 12 12 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 13 import {useSetTitle} from '#/lib/hooks/useSetTitle' 15 14 import {ComposeIcon2} from '#/lib/icons' 16 15 import {type CommonNavigatorParams} from '#/lib/routes/types' ··· 45 44 ProfileFeedHeader, 46 45 ProfileFeedHeaderSkeleton, 47 46 } from '#/screens/Profile/components/ProfileFeedHeader' 47 + import {useTheme} from '#/alf' 48 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 48 49 import * as Layout from '#/components/Layout' 49 50 50 51 type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'> ··· 56 57 feedCacheKey: props.route.params.feedCacheKey, 57 58 } 58 59 : undefined 59 - const pal = usePalette('default') 60 + const theme = useTheme() 61 + const colorMode = useColorModeTheme() 60 62 const {_} = useLingui() 61 63 const navigation = useNavigation<NavigationProp>() 62 64 65 + const textStyle: TextStyle = { 66 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 67 + } 68 + 63 69 const uri = useMemo( 64 70 () => makeRecordUri(handleOrDid, 'app.bsky.feed.generator', rkey), 65 71 [rkey, handleOrDid], ··· 78 84 return ( 79 85 <Layout.Screen testID="profileFeedScreenError"> 80 86 <Layout.Content> 81 - <View style={[pal.view, pal.border, styles.notFoundContainer]}> 82 - <Text type="title-lg" style={[pal.text, s.mb10]}> 83 - <Trans>Could not load feed</Trans> 87 + <View 88 + style={[ 89 + { 90 + borderColor: theme.palette.contrast_100, 91 + backgroundColor: 92 + colorMode === 'light' 93 + ? theme.palette.white 94 + : theme.palette.black, 95 + }, 96 + styles.notFoundContainer, 97 + ]}> 98 + <Text type="title-lg" style={[textStyle, s.mb10]}> 99 + <Trans>Could not load feed </Trans> 84 100 </Text> 85 - <Text type="md" style={[pal.text, s.mb20]}> 101 + <Text type="md" style={[textStyle, s.mb20]}> 86 102 {error.toString()} 87 103 </Text> 88 104 ··· 93 109 accessibilityHint={_(msg`Returns to previous page`)} 94 110 onPress={onPressBack} 95 111 style={{flexShrink: 1}}> 96 - <Text type="button" style={pal.text}> 97 - <Trans>Go Back</Trans> 112 + <Text type="button" style={textStyle}> 113 + <Trans>Go Back </Trans> 98 114 </Text> 99 115 </Button> 100 116 </View>
+2 -4
src/screens/Search/SearchResults.tsx
··· 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import {augmentSearchQuery} from '#/lib/strings/helpers' 9 8 import {useActorSearch} from '#/state/queries/actor-search' 10 9 import {usePopularFeedsSearch} from '#/state/queries/feed' ··· 193 192 hasNextPage, 194 193 } = useSearchPostsQuery({query: augmentedQuery, sort, enabled: active}) 195 194 196 - const pal = usePalette('default') 197 195 const t = useTheme() 198 196 const onPullToRefresh = useCallback(async () => { 199 197 setIsPTR(true) ··· 254 252 <Text style={[a.text_md, a.text_center, a.leading_snug]}> 255 253 <Trans> 256 254 <InlineLinkText 257 - style={[pal.link]} 255 + style={[{color: t.palette.primary_500}]} 258 256 label={_(msg`Sign in`)} 259 257 to={'#'} 260 258 onPress={showSignIn}> ··· 262 260 </InlineLinkText> 263 261 <Text style={t.atoms.text_contrast_medium}> or </Text> 264 262 <InlineLinkText 265 - style={[pal.link]} 263 + style={[{color: t.palette.primary_500}]} 266 264 label={_(msg`Create an account`)} 267 265 to={'#'} 268 266 onPress={showCreateAccount}>
+31 -6
src/view/com/composer/Composer.tsx
··· 69 69 import {useAppState} from '#/lib/hooks/useAppState' 70 70 import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible' 71 71 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 72 - import {usePalette} from '#/lib/hooks/usePalette' 73 72 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 74 73 import {mimeToExt} from '#/lib/media/video/util' 75 74 import {type NavigationProp} from '#/lib/routes/types' ··· 121 120 import {Text} from '#/view/com/util/text/Text' 122 121 import {UserAvatar} from '#/view/com/util/UserAvatar' 123 122 import {atoms as a, native, useTheme, web} from '#/alf' 123 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 124 124 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 125 125 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' 126 126 import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji' ··· 994 994 topBarAnimatedStyle: StyleProp<ViewStyle> 995 995 children?: React.ReactNode 996 996 }) { 997 - const pal = usePalette('default') 997 + const theme = useTheme() 998 + const colorMode = useColorModeTheme() 998 999 const {_} = useLingui() 999 1000 return ( 1000 1001 <Animated.View ··· 1019 1020 <View style={a.flex_1} /> 1020 1021 {isPublishing ? ( 1021 1022 <> 1022 - <Text style={pal.textLight}>{publishingStage}</Text> 1023 + <Text 1024 + style={{ 1025 + color: 1026 + colorMode === 'light' 1027 + ? theme.palette.white 1028 + : theme.palette.black, 1029 + }}> 1030 + {publishingStage} 1031 + </Text> 1023 1032 <View style={styles.postBtn}> 1024 1033 <ActivityIndicator /> 1025 1034 </View> ··· 1085 1094 } 1086 1095 1087 1096 function AltTextReminder({error}: {error: string}) { 1088 - const pal = usePalette('default') 1097 + const theme = useTheme() 1098 + const colorMode = useColorModeTheme() 1089 1099 return ( 1090 - <View style={[styles.reminderLine, pal.viewLight]}> 1100 + <View 1101 + style={[ 1102 + styles.reminderLine, 1103 + { 1104 + backgroundColor: theme.palette.contrast_25, 1105 + }, 1106 + ]}> 1091 1107 <View style={styles.errorIcon}> 1092 1108 <FontAwesomeIcon 1093 1109 icon="exclamation" ··· 1095 1111 size={10} 1096 1112 /> 1097 1113 </View> 1098 - <Text style={[pal.text, a.flex_1]}>{error}</Text> 1114 + <Text 1115 + style={[ 1116 + { 1117 + color: 1118 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 1119 + }, 1120 + a.flex_1, 1121 + ]}> 1122 + {error} 1123 + </Text> 1099 1124 </View> 1100 1125 ) 1101 1126 }
+13 -6
src/view/com/composer/char-progress/CharProgress.tsx
··· 10 10 import ProgressPie from 'react-native-progress/Pie' 11 11 12 12 import {MAX_GRAPHEME_LENGTH} from '#/lib/constants' 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 - import {atoms as a} from '#/alf' 13 + import {atoms as a, useTheme} from '#/alf' 14 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 15 15 import {Text} from '../../util/text/Text' 16 16 17 17 export function CharProgress({ ··· 27 27 textStyle?: StyleProp<TextStyle> 28 28 size?: number 29 29 }) { 30 + const theme = useTheme() 31 + const colorMode = useColorModeTheme() 30 32 const maxLength = max || MAX_GRAPHEME_LENGTH 31 - const pal = usePalette('default') 32 - const textColor = count > maxLength ? '#e60000' : pal.colors.text 33 - const circleColor = count > maxLength ? '#e60000' : pal.colors.link 33 + const textColor = 34 + count > maxLength 35 + ? theme.palette.negative_500 36 + : colorMode === 'light' 37 + ? theme.palette.black 38 + : theme.palette.white 39 + const circleColor = 40 + count > maxLength ? theme.palette.negative_500 : theme.palette.primary_500 34 41 return ( 35 42 <View 36 43 style={[a.flex_row, a.align_center, a.justify_between, a.gap_sm, style]}> ··· 55 62 <ProgressCircle 56 63 size={size ?? 30} 57 64 borderWidth={1} 58 - borderColor={pal.colors.border} 65 + borderColor={theme.palette.contrast_100} 59 66 color={circleColor} 60 67 progress={count / maxLength} 61 68 />
+18 -10
src/view/com/lists/MyLists.tsx
··· 11 11 import {msg} from '@lingui/macro' 12 12 import {useLingui} from '@lingui/react' 13 13 14 - import {usePalette} from '#/lib/hooks/usePalette' 15 14 import {cleanError} from '#/lib/strings/errors' 16 15 import {s} from '#/lib/styles' 17 16 import {logger} from '#/logger' 18 17 import {useModerationOpts} from '#/state/preferences/moderation-opts' 19 18 import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 20 19 import {atoms as a, useTheme} from '#/alf' 20 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 21 21 import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 22 22 import * as ListCard from '#/components/ListCard' 23 23 import {Text} from '#/components/Typography' ··· 41 41 renderItem?: (list: GraphDefs.ListView, index: number) => JSX.Element 42 42 testID?: string 43 43 }) { 44 - const pal = usePalette('default') 45 - const t = useTheme() 44 + const theme = useTheme() 45 + const colorMode = useColorModeTheme() 46 46 const {_} = useLingui() 47 47 const moderationOpts = useModerationOpts() 48 48 const [isPTRing, setIsPTRing] = React.useState(false) ··· 108 108 a.align_center, 109 109 a.justify_center, 110 110 a.rounded_full, 111 - t.atoms.bg_contrast_25, 111 + theme.atoms.bg_contrast_25, 112 112 { 113 113 width: 32, 114 114 height: 32, 115 115 }, 116 116 ]}> 117 - <ListIcon size="md" fill={t.atoms.text_contrast_low.color} /> 117 + <ListIcon size="md" fill={theme.atoms.text_contrast_low.color} /> 118 118 </View> 119 119 <Text 120 120 style={[ ··· 122 122 a.flex_1, 123 123 a.text_sm, 124 124 a.leading_snug, 125 - t.atoms.text_contrast_medium, 125 + theme.atoms.text_contrast_medium, 126 126 { 127 127 maxWidth: 200, 128 128 }, ··· 151 151 <View 152 152 style={[ 153 153 index !== 0 && a.border_t, 154 - t.atoms.border_contrast_low, 154 + theme.atoms.border_contrast_low, 155 155 a.px_lg, 156 156 a.py_lg, 157 157 ]}> ··· 159 159 </View> 160 160 ) 161 161 }, 162 - [t, renderItem, error, onRefresh, emptyText], 162 + [theme, renderItem, error, onRefresh, emptyText], 163 163 ) 164 164 165 165 if (inline) { ··· 175 175 <RefreshControl 176 176 refreshing={isPTRing} 177 177 onRefresh={onRefresh} 178 - tintColor={pal.colors.text} 179 - titleColor={pal.colors.text} 178 + tintColor={ 179 + colorMode === 'light' 180 + ? theme.palette.black 181 + : theme.palette.white 182 + } 183 + titleColor={ 184 + colorMode === 'light' 185 + ? theme.palette.black 186 + : theme.palette.white 187 + } 180 188 /> 181 189 } 182 190 contentContainerStyle={[s.contentContainer]}
+46 -15
src/view/com/modals/CreateOrEditList.tsx
··· 5 5 ScrollView, 6 6 StyleSheet, 7 7 TextInput, 8 + type TextStyle, 8 9 TouchableOpacity, 10 + useColorScheme, 9 11 View, 12 + type ViewStyle, 10 13 } from 'react-native' 11 14 import {LinearGradient} from 'expo-linear-gradient' 12 15 import {type AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api' 13 16 import {msg, Trans} from '@lingui/macro' 14 17 import {useLingui} from '@lingui/react' 15 18 16 - import {usePalette} from '#/lib/hooks/usePalette' 17 19 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 18 20 import {cleanError, isNetworkError} from '#/lib/strings/errors' 19 21 import {enforceLen} from '#/lib/strings/helpers' 20 22 import {richTextToString} from '#/lib/strings/rich-text-helpers' 21 23 import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip' 22 24 import {colors, gradients, s} from '#/lib/styles' 23 - import {useTheme} from '#/lib/ThemeContext' 24 25 import {type ImageMeta} from '#/state/gallery' 25 26 import {useModalControls} from '#/state/modals' 26 27 import { ··· 32 33 import {Text} from '#/view/com/util/text/Text' 33 34 import * as Toast from '#/view/com/util/Toast' 34 35 import {EditableUserAvatar} from '#/view/com/util/UserAvatar' 36 + import {useTheme} from '#/alf' 37 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 35 38 36 39 const MAX_NAME = 64 // todo 37 40 const MAX_DESCRIPTION = 300 // todo ··· 50 53 const {closeModal} = useModalControls() 51 54 const {isMobile} = useWebMediaQueries() 52 55 const [error, setError] = useState<string>('') 53 - const pal = usePalette('default') 54 56 const theme = useTheme() 57 + const colorMode = useColorModeTheme() 55 58 const {_} = useLingui() 56 59 const listCreateMutation = useListCreateMutation() 57 60 const listMetadataMutation = useListMetadataMutation() ··· 92 95 return shortenLinks(descriptionRt).graphemeLength 93 96 }, [descriptionRt]) 94 97 const isDescriptionOver = graphemeLength > MAX_DESCRIPTION 98 + 99 + const colorScheme = useColorScheme() ?? 'default' 100 + 101 + const viewStyle: ViewStyle = { 102 + backgroundColor: 103 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 104 + } 105 + 106 + const textStyle: TextStyle = { 107 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 108 + } 109 + 110 + const textStyleLight: TextStyle = { 111 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 112 + } 113 + 114 + const borderStyle: ViewStyle = { 115 + borderColor: theme.palette.contrast_100, 116 + } 95 117 96 118 const [avatar, setAvatar] = useState<string | undefined>(list?.avatar) 97 119 const [newAvatar, setNewAvatar] = useState<ImageMeta | undefined | null>() ··· 211 233 <KeyboardAvoidingView behavior="height"> 212 234 <ScrollView 213 235 style={[ 214 - pal.view, 236 + viewStyle, 215 237 { 216 238 paddingHorizontal: isMobile ? 16 : 0, 217 239 }, 218 240 ]} 219 241 testID="createOrEditListModal"> 220 - <Text style={[styles.title, pal.text]}> 242 + <Text style={[styles.title, textStyle]}> 221 243 {isCurateList ? ( 222 244 list ? ( 223 245 <Trans>Edit User List</Trans> ··· 235 257 <ErrorMessage message={error} /> 236 258 </View> 237 259 )} 238 - <Text style={[styles.label, pal.text]}> 260 + <Text style={[styles.label, textStyle]}> 239 261 <Trans>List Avatar</Trans> 240 262 </Text> 241 - <View style={[styles.avi, {borderColor: pal.colors.background}]}> 263 + <View 264 + style={[ 265 + styles.avi, 266 + { 267 + borderColor: 268 + colorMode === 'light' 269 + ? theme.palette.white 270 + : theme.palette.black, 271 + }, 272 + ]}> 242 273 <EditableUserAvatar 243 274 type="list" 244 275 size={80} ··· 249 280 <View style={styles.form}> 250 281 <View> 251 282 <View style={styles.labelWrapper}> 252 - <Text style={[styles.label, pal.text]} nativeID="list-name"> 283 + <Text style={[styles.label, textStyle]} nativeID="list-name"> 253 284 <Trans>List Name</Trans> 254 285 </Text> 255 286 </View> 256 287 <TextInput 257 288 testID="editNameInput" 258 - style={[styles.textInput, pal.border, pal.text]} 289 + style={[styles.textInput, borderStyle, textStyle]} 259 290 placeholder={ 260 291 isCurateList 261 292 ? _(msg`e.g. Great Posters`) ··· 273 304 <View style={s.pb10}> 274 305 <View style={styles.labelWrapper}> 275 306 <Text 276 - style={[styles.label, pal.text]} 307 + style={[styles.label, textStyle]} 277 308 nativeID="list-description"> 278 309 <Trans>Description</Trans> 279 310 </Text> 280 311 <Text 281 - style={[!isDescriptionOver ? pal.textLight : s.red3, s.f13]}> 282 - {graphemeLength}/{MAX_DESCRIPTION} 312 + style={[!isDescriptionOver ? textStyleLight : s.red3, s.f13]}> 313 + {graphemeLength} / {MAX_DESCRIPTION} 283 314 </Text> 284 315 </View> 285 316 <TextInput 286 317 testID="editDescriptionInput" 287 - style={[styles.textArea, pal.border, pal.text]} 318 + style={[styles.textArea, borderStyle, textStyle]} 288 319 placeholder={ 289 320 isCurateList 290 321 ? _(msg`e.g. The posters who never miss.`) 291 322 : _(msg`e.g. Users that repeatedly reply with ads.`) 292 323 } 293 324 placeholderTextColor={colors.gray4} 294 - keyboardAppearance={theme.colorScheme} 325 + keyboardAppearance={colorScheme} 295 326 multiline 296 327 value={descriptionRt.text} 297 328 onChangeText={onDescriptionChange} ··· 334 365 accessibilityHint="" 335 366 onAccessibilityEscape={onPressCancel}> 336 367 <View style={[styles.btn]}> 337 - <Text style={[s.black, s.bold, pal.text]}> 368 + <Text style={[s.black, s.bold, textStyle]}> 338 369 <Trans context="action">Cancel</Trans> 339 370 </Text> 340 371 </View>
+4 -4
src/view/com/modals/CropImage.web.tsx
··· 6 6 import {useLingui} from '@lingui/react' 7 7 import ReactCrop, {type PercentCrop} from 'react-image-crop' 8 8 9 - import {usePalette} from '#/lib/hooks/usePalette' 10 9 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 11 10 import {type PickerImage} from '#/lib/media/picker.shared' 12 11 import {getDataUriSize} from '#/lib/media/util' 13 12 import {gradients, s} from '#/lib/styles' 14 13 import {useModalControls} from '#/state/modals' 15 14 import {Text} from '#/view/com/util/text/Text' 15 + import {useTheme} from '#/alf' 16 16 17 17 export const snapPoints = ['0%'] 18 18 ··· 27 27 circular?: boolean 28 28 onSelect: (img?: PickerImage) => void 29 29 }) { 30 - const pal = usePalette('default') 30 + const theme = useTheme() 31 31 const {_} = useLingui() 32 32 33 33 const {closeModal} = useModalControls() ··· 78 78 79 79 return ( 80 80 <View> 81 - <View style={[styles.cropper, pal.borderDark]}> 81 + <View style={[styles.cropper, {borderColor: theme.palette.contrast_200}]}> 82 82 <ReactCrop 83 83 aspect={aspect} 84 84 crop={crop} ··· 93 93 accessibilityRole="button" 94 94 accessibilityLabel={_(msg`Cancel image crop`)} 95 95 accessibilityHint={_(msg`Exits image cropping process`)}> 96 - <Text type="xl" style={pal.link}> 96 + <Text type="xl" style={{color: theme.palette.primary_500}}> 97 97 <Trans>Cancel</Trans> 98 98 </Text> 99 99 </TouchableOpacity>
+49 -23
src/view/com/modals/DeleteAccount.tsx
··· 3 3 ActivityIndicator, 4 4 SafeAreaView, 5 5 StyleSheet, 6 + type TextStyle, 6 7 TouchableOpacity, 8 + useColorScheme, 7 9 View, 10 + type ViewStyle, 8 11 } from 'react-native' 9 12 import {LinearGradient} from 'expo-linear-gradient' 10 13 import {msg, Trans} from '@lingui/macro' 11 14 import {useLingui} from '@lingui/react' 12 15 13 16 import {DM_SERVICE_HEADERS} from '#/lib/constants' 14 - import {usePalette} from '#/lib/hooks/usePalette' 15 17 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 16 18 import {cleanError} from '#/lib/strings/errors' 17 19 import {colors, gradients, s} from '#/lib/styles' 18 - import {useTheme} from '#/lib/ThemeContext' 19 20 import {isAndroid, isWeb} from '#/platform/detection' 20 21 import {useModalControls} from '#/state/modals' 21 22 import {useAgent, useSession, useSessionApi} from '#/state/session' 22 23 import {atoms as a, useTheme as useNewTheme} from '#/alf' 24 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 23 25 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 24 26 import {Text as NewText} from '#/components/Typography' 25 27 import {resetToTab} from '../../../Navigation' ··· 31 33 export const snapPoints = isAndroid ? ['90%'] : ['55%'] 32 34 33 35 export function Component({}: {}) { 34 - const pal = usePalette('default') 35 - const theme = useTheme() 36 - const t = useNewTheme() 36 + const theme = useNewTheme() 37 + const colorMode = useColorModeTheme() 37 38 const {currentAccount} = useSession() 38 39 const agent = useAgent() 39 40 const {removeAccount} = useSessionApi() 40 41 const {_} = useLingui() 41 42 const {closeModal} = useModalControls() 42 43 const {isMobile} = useWebMediaQueries() 44 + 45 + const colorScheme = useColorScheme() ?? 'default' 46 + 47 + const viewStyle: ViewStyle = { 48 + backgroundColor: 49 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 50 + } 51 + 52 + const textStyle: TextStyle = { 53 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 54 + } 55 + 56 + const textStyleLight: TextStyle = { 57 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 58 + } 59 + 43 60 const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false) 44 61 const [confirmCode, setConfirmCode] = React.useState<string>('') 45 62 const [password, setPassword] = React.useState<string>('') ··· 95 112 } 96 113 return ( 97 114 <SafeAreaView style={[s.flex1]}> 98 - <ScrollView style={[pal.view]} keyboardShouldPersistTaps="handled"> 99 - <View style={[styles.titleContainer, pal.view]}> 100 - <Text type="title-xl" style={[s.textCenter, pal.text]}> 115 + <ScrollView style={[viewStyle]} keyboardShouldPersistTaps="handled"> 116 + <View style={[styles.titleContainer, viewStyle]}> 117 + <Text type="title-xl" style={[s.textCenter, textStyle]}> 101 118 <Trans> 102 119 Delete Account{' '} 103 - <Text type="title-xl" style={[pal.text, s.bold]}> 120 + <Text type="title-xl" style={[textStyle, s.bold]}> 104 121 " 105 122 </Text> 106 123 <Text ··· 108 125 numberOfLines={1} 109 126 style={[ 110 127 isMobile ? styles.titleMobile : styles.titleDesktop, 111 - pal.text, 128 + textStyle, 112 129 s.bold, 113 130 ]}> 114 131 {currentAccount?.handle} 115 132 </Text> 116 - <Text type="title-xl" style={[pal.text, s.bold]}> 133 + <Text type="title-xl" style={[textStyle, s.bold]}> 117 134 " 118 135 </Text> 119 136 </Trans> ··· 121 138 </View> 122 139 {!isEmailSent ? ( 123 140 <> 124 - <Text type="lg" style={[styles.description, pal.text]}> 141 + <Text type="lg" style={[styles.description, textStyle]}> 125 142 <Trans> 126 143 For security reasons, we'll need to send a confirmation code to 127 144 your email address. ··· 166 183 accessibilityLabel={_(msg`Cancel account deletion`)} 167 184 accessibilityHint="" 168 185 onAccessibilityEscape={onCancel}> 169 - <Text type="button-lg" style={pal.textLight}> 186 + <Text type="button-lg" style={textStyleLight}> 170 187 <Trans context="action">Cancel</Trans> 171 188 </Text> 172 189 </TouchableOpacity> ··· 182 199 a.mt_lg, 183 200 a.p_lg, 184 201 a.rounded_sm, 185 - t.atoms.bg_contrast_25, 202 + theme.atoms.bg_contrast_25, 186 203 ]}> 187 204 <CircleInfo 188 205 size="md" ··· 208 225 {/* TODO: Update this label to be more concise */} 209 226 <Text 210 227 type="lg" 211 - style={[pal.text, styles.description]} 228 + style={[textStyle, styles.description]} 212 229 nativeID="confirmationCode"> 213 230 <Trans> 214 231 Check your inbox for an email with the confirmation code to ··· 216 233 </Trans> 217 234 </Text> 218 235 <TextInput 219 - style={[styles.textInput, pal.borderDark, pal.text, styles.mb20]} 236 + style={[ 237 + styles.textInput, 238 + {borderColor: theme.palette.contrast_200}, 239 + textStyle, 240 + styles.mb20, 241 + ]} 220 242 placeholder={_(msg`Confirmation code`)} 221 - placeholderTextColor={pal.textLight.color} 222 - keyboardAppearance={theme.colorScheme} 243 + placeholderTextColor={textStyleLight.color} 244 + keyboardAppearance={colorScheme} 223 245 value={confirmCode} 224 246 onChangeText={setConfirmCode} 225 247 accessibilityLabelledBy="confirmationCode" ··· 230 252 /> 231 253 <Text 232 254 type="lg" 233 - style={[pal.text, styles.description]} 255 + style={[textStyle, styles.description]} 234 256 nativeID="password"> 235 257 <Trans>Please enter your password as well:</Trans> 236 258 </Text> 237 259 <TextInput 238 - style={[styles.textInput, pal.borderDark, pal.text]} 260 + style={[ 261 + styles.textInput, 262 + {borderColor: theme.palette.contrast_200}, 263 + textStyle, 264 + ]} 239 265 placeholder={_(msg`Password`)} 240 - placeholderTextColor={pal.textLight.color} 241 - keyboardAppearance={theme.colorScheme} 266 + placeholderTextColor={textStyleLight.color} 267 + keyboardAppearance={colorScheme} 242 268 secureTextEntry 243 269 value={password} 244 270 onChangeText={setPassword} ··· 274 300 accessibilityLabel={_(msg`Cancel account deletion`)} 275 301 accessibilityHint={_(msg`Exits account deletion process`)} 276 302 onAccessibilityEscape={onCancel}> 277 - <Text type="button-lg" style={pal.textLight}> 303 + <Text type="button-lg" style={textStyleLight}> 278 304 <Trans context="action">Cancel</Trans> 279 305 </Text> 280 306 </TouchableOpacity>
+55 -18
src/view/com/modals/InviteCodes.tsx
··· 2 2 import { 3 3 ActivityIndicator, 4 4 StyleSheet, 5 + type TextStyle, 5 6 TouchableOpacity, 6 7 View, 8 + type ViewStyle, 7 9 } from 'react-native' 8 10 import {setStringAsync} from 'expo-clipboard' 9 11 import {type ComAtprotoServerDefs} from '@atproto/api' ··· 14 16 import {msg, Trans} from '@lingui/macro' 15 17 import {useLingui} from '@lingui/react' 16 18 17 - import {usePalette} from '#/lib/hooks/usePalette' 18 19 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 19 20 import {makeProfileLink} from '#/lib/routes/links' 20 21 import {cleanError} from '#/lib/strings/errors' ··· 25 26 type InviteCodesQueryResponse, 26 27 useInviteCodesQuery, 27 28 } from '#/state/queries/invites' 29 + import {useTheme} from '#/alf' 30 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 28 31 import {ErrorMessage} from '../util/error/ErrorMessage' 29 32 import {Button} from '../util/forms/Button' 30 33 import {Link} from '../util/Link' ··· 50 53 } 51 54 52 55 export function Inner({invites}: {invites: InviteCodesQueryResponse}) { 53 - const pal = usePalette('default') 56 + const theme = useTheme() 57 + const colorMode = useColorModeTheme() 54 58 const {_} = useLingui() 55 59 const {closeModal} = useModalControls() 56 60 const {isTabletOrDesktop} = useWebMediaQueries() ··· 59 63 closeModal() 60 64 }, [closeModal]) 61 65 66 + const viewStyle: ViewStyle = { 67 + backgroundColor: 68 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 69 + } 70 + 71 + const viewStyleLight: ViewStyle = { 72 + backgroundColor: theme.palette.contrast_25, 73 + } 74 + 75 + const textStyle: TextStyle = { 76 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 77 + } 78 + 79 + const borderStyle: ViewStyle = { 80 + borderColor: theme.palette.contrast_100, 81 + } 82 + 62 83 if (invites.all.length === 0) { 63 84 return ( 64 - <View style={[styles.container, pal.view]} testID="inviteCodesModal"> 65 - <View style={[styles.empty, pal.viewLight]}> 66 - <Text type="lg" style={[pal.text, styles.emptyText]}> 85 + <View style={[styles.container, viewStyle]} testID="inviteCodesModal"> 86 + <View style={[styles.empty, viewStyleLight]}> 87 + <Text type="lg" style={[textStyle, styles.emptyText]}> 67 88 <Trans> 68 89 You don't have any invite codes yet! We'll send you some when 69 90 you've been on Bluesky for a little longer. ··· 89 110 } 90 111 91 112 return ( 92 - <View style={[styles.container, pal.view]} testID="inviteCodesModal"> 93 - <Text type="title-xl" style={[styles.title, pal.text]}> 94 - <Trans>Invite a Friend</Trans> 113 + <View style={[styles.container, viewStyle]} testID="inviteCodesModal"> 114 + <Text type="title-xl" style={[styles.title, textStyle]}> 115 + <Trans>Invite a Friend </Trans> 95 116 </Text> 96 - <Text type="lg" style={[styles.description, pal.text]}> 117 + <Text type="lg" style={[styles.description, textStyle]}> 97 118 <Trans> 98 119 Each code works once. You'll receive more invite codes periodically. 99 120 </Trans> 100 121 </Text> 101 - <ScrollView style={[styles.scrollContainer, pal.border]}> 122 + <ScrollView style={[styles.scrollContainer, borderStyle]}> 102 123 {invites.available.map((invite, i) => ( 103 124 <InviteCode 104 125 testID={`inviteCode-${i}`} ··· 142 163 used?: boolean 143 164 invites: InviteCodesQueryResponse 144 165 }) { 145 - const pal = usePalette('default') 166 + const theme = useTheme() 167 + const colorMode = useColorModeTheme() 146 168 const {_} = useLingui() 147 169 const invitesState = useInvitesState() 148 170 const {setInviteCopied} = useInvitesAPI() ··· 154 176 setInviteCopied(invite.code) 155 177 }, [setInviteCopied, invite, _]) 156 178 179 + const textStyle: TextStyle = { 180 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 181 + } 182 + 183 + const textStyleLight: TextStyle = { 184 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 185 + } 186 + 187 + const borderStyle: ViewStyle = { 188 + borderColor: theme.palette.contrast_100, 189 + } 190 + 157 191 return ( 158 192 <View 159 193 style={[ 160 - pal.border, 194 + borderStyle, 161 195 {borderBottomWidth: 1, paddingHorizontal: 20, paddingVertical: 14}, 162 196 ]}> 163 197 <TouchableOpacity ··· 174 208 <Text 175 209 testID={`${testID}-code`} 176 210 type={used ? 'md' : 'md-bold'} 177 - style={used ? [pal.textLight, styles.strikeThrough] : pal.text}> 211 + style={used ? [textStyleLight, styles.strikeThrough] : textStyle}> 178 212 {invite.code} 179 213 </Text> 180 214 <View style={styles.flex1} /> 181 215 {!used && invitesState.copiedInvites.includes(invite.code) && ( 182 - <Text style={[pal.textLight, styles.codeCopied]}> 216 + <Text style={[textStyleLight, styles.codeCopied]}> 183 217 <Trans>Copied</Trans> 184 218 </Text> 185 219 )} 186 220 {!used && ( 187 221 <FontAwesomeIcon 188 222 icon={['far', 'clone']} 189 - style={pal.text as FontAwesomeIconStyle} 223 + style={textStyle as FontAwesomeIconStyle} 190 224 /> 191 225 )} 192 226 </TouchableOpacity> ··· 197 231 gap: 8, 198 232 paddingTop: 6, 199 233 }}> 200 - <Text style={pal.text}> 234 + <Text style={textStyle}> 201 235 <Trans>Used by:</Trans>{' '} 202 236 {uses.map((use, i) => ( 203 237 <Link ··· 206 240 style={{ 207 241 flexDirection: 'row', 208 242 }}> 209 - <UserInfoText did={use.usedBy} style={pal.link} /> 210 - {i !== uses.length - 1 && <Text style={pal.text}>, </Text>} 243 + <UserInfoText 244 + did={use.usedBy} 245 + style={{color: theme.palette.primary_500}} 246 + /> 247 + {i !== uses.length - 1 && <Text style={textStyle}>, </Text>} 211 248 </Link> 212 249 ))} 213 250 </Text>
+17 -7
src/view/com/modals/Modal.tsx
··· 1 1 import {Fragment, useEffect, useRef} from 'react' 2 - import {StyleSheet} from 'react-native' 2 + import {StyleSheet, type ViewStyle} from 'react-native' 3 3 import {SafeAreaView} from 'react-native-safe-area-context' 4 4 import BottomSheet from '@discord/bottom-sheet/src' 5 5 6 - import {usePalette} from '#/lib/hooks/usePalette' 7 6 import {useModalControls, useModals} from '#/state/modals' 7 + import {useTheme} from '#/alf' 8 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 8 9 import {FullWindowOverlay} from '#/components/FullWindowOverlay' 9 10 import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' 10 11 import * as CreateOrEditListModal from './CreateOrEditList' ··· 20 21 const {isModalActive, activeModals} = useModals() 21 22 const {closeModal} = useModalControls() 22 23 const bottomSheetRef = useRef<BottomSheet>(null) 23 - const pal = usePalette('default') 24 + const theme = useTheme() 25 + const colorMode = useColorModeTheme() 24 26 const activeModal = activeModals[activeModals.length - 1] 25 27 28 + const viewStyle: ViewStyle = { 29 + backgroundColor: 30 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 31 + } 32 + 26 33 const onBottomSheetChange = async (snapPoint: number) => { 27 34 if (snapPoint === -1) { 28 35 closeModal() ··· 65 72 66 73 if (snapPoints[0] === 'fullscreen') { 67 74 return ( 68 - <SafeAreaView style={[styles.fullscreenContainer, pal.view]}> 75 + <SafeAreaView style={[styles.fullscreenContainer, viewStyle]}> 69 76 {element} 70 77 </SafeAreaView> 71 78 ) ··· 86 93 backdropComponent={ 87 94 isModalActive ? createCustomBackdrop(onClose) : undefined 88 95 } 89 - handleIndicatorStyle={{backgroundColor: pal.text.color}} 90 - handleStyle={[styles.handle, pal.view]} 91 - backgroundStyle={pal.view} 96 + handleIndicatorStyle={{ 97 + backgroundColor: 98 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 99 + }} 100 + handleStyle={[styles.handle, viewStyle]} 101 + backgroundStyle={viewStyle} 92 102 onChange={onBottomSheetChange}> 93 103 {element} 94 104 </BottomSheet>
+11 -4
src/view/com/modals/Modal.web.tsx
··· 2 2 import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' 3 3 import {RemoveScrollBar} from 'react-remove-scroll-bar' 4 4 5 - import {usePalette} from '#/lib/hooks/usePalette' 6 5 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 7 6 import {type Modal as ModalIface} from '#/state/modals' 8 7 import {useModalControls, useModals} from '#/state/modals' 8 + import {useTheme} from '#/alf' 9 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 9 10 import * as CreateOrEditListModal from './CreateOrEditList' 10 11 import * as DeleteAccountModal from './DeleteAccount' 11 12 import * as InviteCodesModal from './InviteCodes' ··· 30 31 } 31 32 32 33 function Modal({modal}: {modal: ModalIface}) { 34 + const theme = useTheme() 35 + const colorMode = useColorModeTheme() 33 36 const {isModalActive} = useModals() 34 37 const {closeModal} = useModalControls() 35 - const pal = usePalette('default') 36 38 const {isMobile} = useWebMediaQueries() 37 39 38 40 if (!isModalActive) { ··· 75 77 style={[ 76 78 styles.container, 77 79 isMobile && styles.containerMobile, 78 - pal.view, 79 - pal.border, 80 + { 81 + backgroundColor: 82 + colorMode === 'light' 83 + ? theme.palette.white 84 + : theme.palette.black, 85 + borderColor: theme.palette.contrast_100, 86 + }, 80 87 ]}> 81 88 {element} 82 89 </View>
+61 -12
src/view/com/modals/UserAddRemoveLists.tsx
··· 2 2 import { 3 3 ActivityIndicator, 4 4 StyleSheet, 5 + type TextStyle, 5 6 useWindowDimensions, 6 7 View, 7 8 } from 'react-native' ··· 9 10 import {msg, Trans} from '@lingui/macro' 10 11 import {useLingui} from '@lingui/react' 11 12 12 - import {usePalette} from '#/lib/hooks/usePalette' 13 13 import {sanitizeDisplayName} from '#/lib/strings/display-names' 14 14 import {cleanError} from '#/lib/strings/errors' 15 15 import {sanitizeHandle} from '#/lib/strings/handles' ··· 24 24 useListMembershipRemoveMutation, 25 25 } from '#/state/queries/list-memberships' 26 26 import {useSession} from '#/state/session' 27 + import {useTheme} from '#/alf' 28 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 27 29 import {MyLists} from '../lists/MyLists' 28 30 import {Button} from '../util/forms/Button' 29 31 import {Text} from '../util/text/Text' ··· 45 47 onAdd?: (listUri: string) => void 46 48 onRemove?: (listUri: string) => void 47 49 }) { 50 + const theme = useTheme() 51 + const colorMode = useColorModeTheme() 48 52 const {closeModal} = useModalControls() 49 - const pal = usePalette('default') 50 53 const {height: screenHeight} = useWindowDimensions() 51 54 const {_} = useLingui() 52 55 const {data: memberships} = useDangerousListMembershipsQuery() 53 56 57 + const textStyle: TextStyle = { 58 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 59 + } 60 + 54 61 const onPressDone = useCallback(() => { 55 62 closeModal() 56 63 }, [closeModal]) 57 64 58 65 const listStyle = React.useMemo(() => { 59 66 if (isMobileWeb) { 60 - return [pal.border, {height: screenHeight / 2}] 67 + return [ 68 + { 69 + borderColor: theme.palette.contrast_100, 70 + }, 71 + {height: screenHeight / 2}, 72 + ] 61 73 } else if (isWeb) { 62 - return [pal.border, {height: screenHeight / 1.5}] 74 + return [ 75 + { 76 + borderColor: theme.palette.contrast_100, 77 + }, 78 + {height: screenHeight / 1.5}, 79 + ] 63 80 } 64 81 65 - return [pal.border, {flex: 1, borderTopWidth: StyleSheet.hairlineWidth}] 66 - }, [pal.border, screenHeight]) 82 + return [ 83 + { 84 + borderColor: theme.palette.contrast_100, 85 + }, 86 + {flex: 1, borderTopWidth: StyleSheet.hairlineWidth}, 87 + ] 88 + }, [theme, screenHeight]) 67 89 68 90 const headerStyles = [ 69 91 { ··· 73 95 marginBottom: 12, 74 96 paddingHorizontal: 12, 75 97 } as const, 76 - pal.text, 98 + textStyle, 77 99 ] 78 100 79 101 return ( ··· 104 126 )} 105 127 style={listStyle} 106 128 /> 107 - <View style={[styles.btns, pal.border]}> 129 + <View 130 + style={[ 131 + styles.btns, 132 + { 133 + borderColor: theme.palette.contrast_100, 134 + }, 135 + ]}> 108 136 <Button 109 137 testID="doneBtn" 110 138 type="default" ··· 137 165 onAdd?: (listUri: string) => void 138 166 onRemove?: (listUri: string) => void 139 167 }) { 140 - const pal = usePalette('default') 168 + const theme = useTheme() 169 + const colorMode = useColorModeTheme() 141 170 const {_} = useLingui() 142 171 const {currentAccount} = useSession() 143 172 const [isProcessing, setIsProcessing] = React.useState(false) ··· 192 221 testID={`toggleBtn-${list.name}`} 193 222 style={[ 194 223 styles.listItem, 195 - pal.border, 224 + { 225 + borderColor: theme.palette.contrast_100, 226 + }, 196 227 index !== 0 && {borderTopWidth: StyleSheet.hairlineWidth}, 197 228 ]}> 198 229 <View style={styles.listItemAvi}> ··· 201 232 <View style={styles.listItemContent}> 202 233 <Text 203 234 type="lg" 204 - style={[s.bold, pal.text]} 235 + style={[ 236 + s.bold, 237 + { 238 + color: 239 + colorMode === 'light' 240 + ? theme.palette.black 241 + : theme.palette.white, 242 + }, 243 + ]} 205 244 numberOfLines={1} 206 245 lineHeight={1.2}> 207 246 {sanitizeDisplayName(list.name)} 208 247 </Text> 209 - <Text type="md" style={[pal.textLight]} numberOfLines={1}> 248 + <Text 249 + type="md" 250 + style={[ 251 + { 252 + color: 253 + colorMode === 'light' 254 + ? theme.palette.white 255 + : theme.palette.black, 256 + }, 257 + ]} 258 + numberOfLines={1}> 210 259 {list.purpose === 'app.bsky.graph.defs#curatelist' && 211 260 (list.creator.did === currentAccount?.did ? ( 212 261 <Trans>User list by you</Trans>
+3 -3
src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx
··· 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {usePalette} from '#/lib/hooks/usePalette' 7 6 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 8 7 import {colors, gradients, s} from '#/lib/styles' 8 + import {useTheme} from '#/alf' 9 9 10 10 export const ConfirmLanguagesButton = ({ 11 11 onPress, ··· 14 14 onPress: () => void 15 15 extraText?: string 16 16 }) => { 17 - const pal = usePalette('default') 17 + const theme = useTheme() 18 18 const {_} = useLingui() 19 19 const {isMobile} = useWebMediaQueries() 20 20 return ( 21 21 <View 22 22 style={[ 23 23 styles.btnContainer, 24 - pal.borderDark, 24 + {borderColor: theme.palette.contrast_200}, 25 25 isMobile && { 26 26 paddingBottom: 40, 27 27 borderTopWidth: 1,
+22 -7
src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
··· 1 1 import React from 'react' 2 - import {StyleSheet, View} from 'react-native' 2 + import {StyleSheet, type TextStyle, View, type ViewStyle} from 'react-native' 3 3 import {Trans} from '@lingui/macro' 4 4 5 - import {usePalette} from '#/lib/hooks/usePalette' 6 5 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 7 6 import {deviceLanguageCodes} from '#/locale/deviceLocales' 8 7 import {languageName} from '#/locale/helpers' ··· 11 10 useLanguagePrefs, 12 11 useLanguagePrefsApi, 13 12 } from '#/state/preferences/languages' 13 + import {useTheme} from '#/alf' 14 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 14 15 import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' 15 16 import {Text} from '../../util/text/Text' 16 17 import {ScrollView} from '../util' ··· 23 24 const {closeModal} = useModalControls() 24 25 const langPrefs = useLanguagePrefs() 25 26 const setLangPrefs = useLanguagePrefsApi() 26 - const pal = usePalette('default') 27 + const theme = useTheme() 28 + const colorMode = useColorModeTheme() 27 29 const {isMobile} = useWebMediaQueries() 28 30 const onPressDone = React.useCallback(() => { 29 31 closeModal() 30 32 }, [closeModal]) 31 33 34 + const viewStyle: ViewStyle = { 35 + backgroundColor: 36 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 37 + } 38 + 39 + const textStyle: TextStyle = { 40 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 41 + } 42 + 43 + const textStyleLight: TextStyle = { 44 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 45 + } 46 + 32 47 const languages = React.useMemo(() => { 33 48 const langs = LANGUAGES.filter( 34 49 lang => ··· 61 76 <View 62 77 testID="contentLanguagesModal" 63 78 style={[ 64 - pal.view, 79 + viewStyle, 65 80 styles.container, 66 81 // @ts-ignore vh is web only 67 82 isMobile ··· 72 87 maxHeight: '90vh', 73 88 }, 74 89 ]}> 75 - <Text style={[pal.text, styles.title]}> 90 + <Text style={[textStyle, styles.title]}> 76 91 <Trans>Content Languages</Trans> 77 92 </Text> 78 - <Text style={[pal.text, styles.description]}> 93 + <Text style={[textStyle, styles.description]}> 79 94 <Trans> 80 95 Which languages would you like to see in your algorithmic feeds? 81 96 </Trans> 82 97 </Text> 83 - <Text style={[pal.textLight, styles.description]}> 98 + <Text style={[textStyleLight, styles.description]}> 84 99 <Trans>Leave them all unselected to see any language.</Trans> 85 100 </Text> 86 101 <ScrollView style={styles.scrollContainer}>
+7 -3
src/view/com/modals/lang-settings/LanguageToggle.tsx
··· 1 1 import {StyleSheet} from 'react-native' 2 2 3 - import {usePalette} from '#/lib/hooks/usePalette' 4 3 import {toPostLanguages, useLanguagePrefs} from '#/state/preferences/languages' 5 4 import {ToggleButton} from '#/view/com/util/forms/ToggleButton' 5 + import {useTheme} from '#/alf' 6 6 7 7 export function LanguageToggle({ 8 8 code2, ··· 15 15 onPress: () => void 16 16 langType: 'contentLanguages' | 'postLanguages' 17 17 }) { 18 - const pal = usePalette('default') 18 + const theme = useTheme() 19 19 const langPrefs = useLanguagePrefs() 20 20 21 21 const values = ··· 35 35 label={name} 36 36 isSelected={isSelected} 37 37 onPress={isDisabled ? undefined : onPress} 38 - style={[pal.border, styles.languageToggle, isDisabled && styles.dimmed]} 38 + style={[ 39 + {borderColor: theme.palette.contrast_100}, 40 + styles.languageToggle, 41 + isDisabled && styles.dimmed, 42 + ]} 39 43 /> 40 44 ) 41 45 }
+39 -20
src/view/com/notifications/NotificationFeedItem.tsx
··· 33 33 import {MAX_POST_LINES} from '#/lib/constants' 34 34 import {DM_SERVICE_HEADERS} from '#/lib/constants' 35 35 import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue' 36 - import {usePalette} from '#/lib/hooks/usePalette' 37 36 import {makeProfileLink} from '#/lib/routes/links' 38 37 import {type NavigationProp} from '#/lib/routes/types' 39 38 import {forceLTR} from '#/lib/strings/bidi' ··· 51 50 import {TimeElapsed} from '#/view/com/util/TimeElapsed' 52 51 import {PreviewableUserAvatar, UserAvatar} from '#/view/com/util/UserAvatar' 53 52 import {atoms as a, platform, useTheme} from '#/alf' 53 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 54 54 import {Button, ButtonText} from '#/components/Button' 55 55 import {BellRinging_Filled_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging' 56 56 import { ··· 94 94 hideTopBorder?: boolean 95 95 }): React.ReactNode => { 96 96 const queryClient = useQueryClient() 97 - const pal = usePalette('default') 97 + const theme = useTheme() 98 + const colorMode = useColorModeTheme() 98 99 const t = useTheme() 99 100 const {_, i18n} = useLingui() 100 101 const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false) ··· 200 201 post={item.subject} 201 202 style={ 202 203 isHighlighted && { 203 - backgroundColor: pal.colors.unreadNotifBg, 204 - borderColor: pal.colors.unreadNotifBorder, 204 + backgroundColor: theme.palette.primary_25, 205 + borderColor: theme.palette.primary_100, 205 206 } 206 207 } 207 208 hideTopBorder={hideTopBorder} ··· 281 282 liked your post 282 283 </Trans> 283 284 ) : ( 284 - <Trans>{firstAuthorLink} liked your post</Trans> 285 + <Trans>{firstAuthorLink} liked your post </Trans> 285 286 ) 286 287 } else if (item.type === 'repost') { 287 288 a11yLabel = hasMultipleAuthors ··· 305 306 reposted your post 306 307 </Trans> 307 308 ) : ( 308 - <Trans>{firstAuthorLink} reposted your post</Trans> 309 + <Trans>{firstAuthorLink} reposted your post </Trans> 309 310 ) 310 311 icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} /> 311 312 } else if (item.type === 'follow') { ··· 339 340 * see `src/state/queries/notifications/util.ts` 340 341 */ 341 342 a11yLabel = _(msg`${firstAuthorName} followed you back`) 342 - notificationContent = <Trans>{firstAuthorLink} followed you back</Trans> 343 + notificationContent = <Trans>{firstAuthorLink} followed you back </Trans> 343 344 } else { 344 345 a11yLabel = hasMultipleAuthors 345 346 ? _( ··· 362 363 followed you 363 364 </Trans> 364 365 ) : ( 365 - <Trans>{firstAuthorLink} followed you</Trans> 366 + <Trans>{firstAuthorLink} followed you </Trans> 366 367 ) 367 368 } 368 369 icon = <PersonPlusIcon size="xl" style={{color: t.palette.primary_500}} /> ··· 388 389 liked your custom feed 389 390 </Trans> 390 391 ) : ( 391 - <Trans>{firstAuthorLink} liked your custom feed</Trans> 392 + <Trans>{firstAuthorLink} liked your custom feed </Trans> 392 393 ) 393 394 } else if (item.type === 'starterpack-joined') { 394 395 a11yLabel = hasMultipleAuthors ··· 412 413 signed up with your starter pack 413 414 </Trans> 414 415 ) : ( 415 - <Trans>{firstAuthorLink} signed up with your starter pack</Trans> 416 + <Trans>{firstAuthorLink} signed up with your starter pack </Trans> 416 417 ) 417 418 icon = ( 418 419 <View style={{height: 30, width: 30}}> ··· 431 432 notificationContent = hasMultipleAuthors ? ( 432 433 <Trans> 433 434 {firstAuthorLink} and{' '} 434 - <Text style={[pal.text, s.bold]}> 435 + <Text 436 + style={[ 437 + { 438 + color: 439 + colorMode === 'light' 440 + ? theme.palette.black 441 + : theme.palette.white, 442 + }, 443 + s.bold, 444 + ]}> 435 445 <Plural 436 446 value={additionalAuthorsCount} 437 447 one={`${formattedAuthorsCount} other`} ··· 441 451 verified you 442 452 </Trans> 443 453 ) : ( 444 - <Trans>{firstAuthorLink} verified you</Trans> 454 + <Trans>{firstAuthorLink} verified you </Trans> 445 455 ) 446 456 icon = <VerifiedCheck size="xl" /> 447 457 } else if (item.type === 'unverified') { ··· 456 466 notificationContent = hasMultipleAuthors ? ( 457 467 <Trans> 458 468 {firstAuthorLink} and{' '} 459 - <Text style={[pal.text, s.bold]}> 469 + <Text 470 + style={[ 471 + { 472 + color: 473 + colorMode === 'light' 474 + ? theme.palette.black 475 + : theme.palette.white, 476 + }, 477 + s.bold, 478 + ]}> 460 479 <Plural 461 480 value={additionalAuthorsCount} 462 481 one={`${formattedAuthorsCount} other`} ··· 493 512 liked your repost 494 513 </Trans> 495 514 ) : ( 496 - <Trans>{firstAuthorLink} liked your repost</Trans> 515 + <Trans>{firstAuthorLink} liked your repost </Trans> 497 516 ) 498 517 } else if (item.type === 'repost-via-repost') { 499 518 a11yLabel = hasMultipleAuthors ··· 517 536 reposted your repost 518 537 </Trans> 519 538 ) : ( 520 - <Trans>{firstAuthorLink} reposted your repost</Trans> 539 + <Trans>{firstAuthorLink} reposted your repost </Trans> 521 540 ) 522 541 icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} /> 523 542 } else if (item.type === 'subscribed-post') { ··· 574 593 item.notification.isRead 575 594 ? undefined 576 595 : { 577 - backgroundColor: pal.colors.unreadNotifBg, 578 - borderColor: pal.colors.unreadNotifBorder, 596 + backgroundColor: theme.palette.primary_25, 597 + borderColor: theme.palette.primary_100, 579 598 }, 580 599 !hideTopBorder && a.border_t, 581 600 a.overflow_hidden, ··· 728 747 </Pressable> 729 748 ) 730 749 } else { 731 - return <>{children}</> 750 + return <>{children} </> 732 751 } 733 752 } 734 753 ··· 773 792 } 774 793 }}> 775 794 <ButtonText> 776 - <Trans>Say hello!</Trans> 795 + <Trans>Say hello! </Trans> 777 796 </ButtonText> 778 797 </Button> 779 798 ) ··· 809 828 style={[a.ml_xs, a.mr_md, t.atoms.text_contrast_high]} 810 829 /> 811 830 <Text style={[a.text_md, t.atoms.text_contrast_high]}> 812 - <Trans context="action">Hide</Trans> 831 + <Trans context="action"> Hide </Trans> 813 832 </Text> 814 833 </TouchableOpacity> 815 834 </View>
+3 -4
src/view/com/post/Post.tsx
··· 12 12 13 13 import {MAX_POST_LINES} from '#/lib/constants' 14 14 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 15 - import {usePalette} from '#/lib/hooks/usePalette' 16 15 import {makeProfileLink} from '#/lib/routes/links' 17 16 import {countLines} from '#/lib/strings/helpers' 18 17 import {colors} from '#/lib/styles' ··· 26 25 import {Link} from '#/view/com/util/Link' 27 26 import {PostMeta} from '#/view/com/util/PostMeta' 28 27 import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' 29 - import {atoms as a} from '#/alf' 28 + import {atoms as a, useTheme} from '#/alf' 30 29 import {ContentHider} from '#/components/moderation/ContentHider' 31 30 import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe' 32 31 import {PostAlerts} from '#/components/moderation/PostAlerts' ··· 114 113 onBeforePress?: () => void 115 114 }) { 116 115 const queryClient = useQueryClient() 117 - const pal = usePalette('default') 116 + const theme = useTheme() 118 117 const {openComposer} = useOpenComposer() 119 118 const [limitLines, setLimitLines] = useState( 120 119 () => countLines(richText?.text) >= MAX_POST_LINES, ··· 156 155 href={itemHref} 157 156 style={[ 158 157 styles.outer, 159 - pal.border, 158 + {borderColor: theme.palette.contrast_100}, 160 159 !hideTopBorder && {borderTopWidth: StyleSheet.hairlineWidth}, 161 160 style, 162 161 ]}
+15 -8
src/view/com/posts/CustomFeedEmptyState.tsx
··· 1 1 import React from 'react' 2 - import {StyleSheet, View} from 'react-native' 2 + import {StyleSheet, type TextStyle, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 5 type FontAwesomeIconStyle, ··· 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 - import {usePalette} from '#/lib/hooks/usePalette' 11 10 import {MagnifyingGlassIcon} from '#/lib/icons' 12 11 import {type NavigationProp} from '#/lib/routes/types' 13 12 import {s} from '#/lib/styles' 14 13 import {isWeb} from '#/platform/detection' 14 + import {useTheme} from '#/alf' 15 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 15 16 import {Button} from '../util/forms/Button' 16 17 import {Text} from '../util/text/Text' 17 18 18 19 export function CustomFeedEmptyState() { 19 - const pal = usePalette('default') 20 - const palInverted = usePalette('inverted') 20 + const theme = useTheme() 21 + const colorMode = useColorModeTheme() 21 22 const navigation = useNavigation<NavigationProp>() 23 + const textStyle: TextStyle = { 24 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 25 + } 26 + const textStyleInverted: TextStyle = { 27 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 28 + } 22 29 23 30 const onPressFindAccounts = React.useCallback(() => { 24 31 if (isWeb) { ··· 32 39 return ( 33 40 <View style={styles.emptyContainer}> 34 41 <View style={styles.emptyIconContainer}> 35 - <MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} /> 42 + <MagnifyingGlassIcon style={[styles.emptyIcon, textStyle]} size={62} /> 36 43 </View> 37 - <Text type="xl-medium" style={[s.textCenter, pal.text]}> 44 + <Text type="xl-medium" style={[s.textCenter, textStyle]}> 38 45 <Trans> 39 46 This feed is empty! You may need to follow more users or tune your 40 47 language settings. ··· 44 51 type="inverted" 45 52 style={styles.emptyBtn} 46 53 onPress={onPressFindAccounts}> 47 - <Text type="lg-medium" style={palInverted.text}> 54 + <Text type="lg-medium" style={textStyleInverted}> 48 55 <Trans>Find accounts to follow</Trans> 49 56 </Text> 50 57 <FontAwesomeIcon 51 58 icon="angle-right" 52 - style={palInverted.text as FontAwesomeIconStyle} 59 + style={textStyleInverted as FontAwesomeIconStyle} 53 60 size={14} 54 61 /> 55 62 </Button>
+23 -7
src/view/com/posts/DiscoverFallbackHeader.tsx
··· 1 1 import {View} from 'react-native' 2 2 import {Trans} from '@lingui/macro' 3 3 4 - import {usePalette} from '#/lib/hooks/usePalette' 5 4 import {InfoCircleIcon} from '#/lib/icons' 5 + import {useTheme} from '#/alf' 6 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 6 7 import {TextLink} from '../util/Link' 7 8 import {Text} from '../util/text/Text' 8 9 9 10 export function DiscoverFallbackHeader() { 10 - const pal = usePalette('default') 11 + const theme = useTheme() 12 + const colorMode = useColorModeTheme() 11 13 return ( 12 14 <View 13 15 style={[ ··· 17 19 paddingVertical: 12, 18 20 paddingHorizontal: 12, 19 21 borderTopWidth: 1, 22 + borderColor: theme.palette.contrast_100, 23 + backgroundColor: theme.palette.contrast_25, 20 24 }, 21 - pal.border, 22 - pal.viewLight, 23 25 ]}> 24 26 <View style={{width: 68, paddingLeft: 12}}> 25 - <InfoCircleIcon size={36} style={pal.textLight} strokeWidth={1.5} /> 27 + <InfoCircleIcon 28 + size={36} 29 + style={{ 30 + color: 31 + colorMode === 'dark' 32 + ? theme.palette.contrast_600 33 + : theme.palette.contrast_700, 34 + }} 35 + strokeWidth={1.5} 36 + /> 26 37 </View> 27 38 <View style={{flex: 1}}> 28 - <Text type="md" style={pal.text}> 39 + <Text 40 + type="md" 41 + style={{ 42 + color: 43 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 44 + }}> 29 45 <Trans> 30 46 We ran out of posts from your follows. Here's the latest from{' '} 31 47 <TextLink 32 48 type="md-medium" 33 49 href="/profile/bsky.app/feed/whats-hot" 34 50 text="Discover" 35 - style={pal.link} 51 + style={{color: theme.palette.primary_500}} 36 52 /> 37 53 . 38 54 </Trans>
+21 -13
src/view/com/posts/FollowingEmptyState.tsx
··· 1 1 import React from 'react' 2 - import {StyleSheet, View} from 'react-native' 2 + import {StyleSheet, type TextStyle, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 5 type FontAwesomeIconStyle, ··· 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 - import {usePalette} from '#/lib/hooks/usePalette' 11 10 import {MagnifyingGlassIcon} from '#/lib/icons' 12 11 import {type NavigationProp} from '#/lib/routes/types' 13 12 import {s} from '#/lib/styles' 14 13 import {isWeb} from '#/platform/detection' 14 + import {useTheme} from '#/alf' 15 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 15 16 import {Button} from '../util/forms/Button' 16 17 import {Text} from '../util/text/Text' 17 18 18 19 export function FollowingEmptyState() { 19 - const pal = usePalette('default') 20 - const palInverted = usePalette('inverted') 20 + const theme = useTheme() 21 + const colorMode = useColorModeTheme() 21 22 const navigation = useNavigation<NavigationProp>() 22 23 24 + const textStyle: TextStyle = { 25 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 26 + } 27 + const textStyleInverted: TextStyle = { 28 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 29 + } 30 + 23 31 const onPressFindAccounts = React.useCallback(() => { 24 32 if (isWeb) { 25 33 navigation.navigate('Search', {}) ··· 37 45 <View style={styles.container}> 38 46 <View style={styles.inner}> 39 47 <View style={styles.iconContainer}> 40 - <MagnifyingGlassIcon style={[styles.icon, pal.text]} size={62} /> 48 + <MagnifyingGlassIcon style={[styles.icon, textStyle]} size={62} /> 41 49 </View> 42 - <Text type="xl-medium" style={[s.textCenter, pal.text]}> 50 + <Text type="xl-medium" style={[s.textCenter, textStyle]}> 43 51 <Trans> 44 52 Your following feed is empty! Follow more users to see what's 45 53 happening. ··· 49 57 type="inverted" 50 58 style={styles.emptyBtn} 51 59 onPress={onPressFindAccounts}> 52 - <Text type="lg-medium" style={palInverted.text}> 53 - <Trans>Find accounts to follow</Trans> 60 + <Text type="lg-medium" style={textStyleInverted}> 61 + <Trans>Find accounts to follow </Trans> 54 62 </Text> 55 63 <FontAwesomeIcon 56 64 icon="angle-right" 57 - style={palInverted.text as FontAwesomeIconStyle} 65 + style={textStyleInverted as FontAwesomeIconStyle} 58 66 size={14} 59 67 /> 60 68 </Button> 61 69 62 - <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}> 70 + <Text type="xl-medium" style={[s.textCenter, textStyle, s.mt20]}> 63 71 <Trans>You can also discover new Custom Feeds to follow.</Trans> 64 72 </Text> 65 73 <Button 66 74 type="inverted" 67 75 style={[styles.emptyBtn, s.mt10]} 68 76 onPress={onPressDiscoverFeeds}> 69 - <Text type="lg-medium" style={palInverted.text}> 70 - <Trans>Discover new custom feeds</Trans> 77 + <Text type="lg-medium" style={textStyleInverted}> 78 + <Trans>Discover new custom feeds </Trans> 71 79 </Text> 72 80 <FontAwesomeIcon 73 81 icon="angle-right" 74 - style={palInverted.text as FontAwesomeIconStyle} 82 + style={textStyleInverted as FontAwesomeIconStyle} 75 83 size={14} 76 84 /> 77 85 </Button>
+25 -14
src/view/com/posts/FollowingEndOfFeed.tsx
··· 1 1 import React from 'react' 2 - import {Dimensions, StyleSheet, View} from 'react-native' 2 + import {Dimensions, StyleSheet, type TextStyle, View} from 'react-native' 3 3 import { 4 4 FontAwesomeIcon, 5 5 type FontAwesomeIconStyle, ··· 7 7 import {Trans} from '@lingui/macro' 8 8 import {useNavigation} from '@react-navigation/native' 9 9 10 - import {usePalette} from '#/lib/hooks/usePalette' 11 10 import {type NavigationProp} from '#/lib/routes/types' 12 11 import {s} from '#/lib/styles' 13 12 import {isWeb} from '#/platform/detection' 13 + import {useTheme} from '#/alf' 14 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 14 15 import {Button} from '../util/forms/Button' 15 16 import {Text} from '../util/text/Text' 16 17 17 18 export function FollowingEndOfFeed() { 18 - const pal = usePalette('default') 19 - const palInverted = usePalette('inverted') 19 + const theme = useTheme() 20 + const colorMode = useColorModeTheme() 20 21 const navigation = useNavigation<NavigationProp>() 21 22 23 + const textStyle: TextStyle = { 24 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 25 + } 26 + 27 + const textStyleInverted: TextStyle = { 28 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 29 + } 30 + 22 31 const onPressFindAccounts = React.useCallback(() => { 23 32 if (isWeb) { 24 33 navigation.navigate('Search', {}) ··· 36 45 <View 37 46 style={[ 38 47 styles.container, 39 - pal.border, 40 - {minHeight: Dimensions.get('window').height * 0.75}, 48 + { 49 + minHeight: Dimensions.get('window').height * 0.75, 50 + borderColor: theme.palette.contrast_100, 51 + }, 41 52 ]}> 42 53 <View style={styles.inner}> 43 - <Text type="xl-medium" style={[s.textCenter, pal.text]}> 54 + <Text type="xl-medium" style={[s.textCenter, textStyle]}> 44 55 <Trans> 45 56 You've reached the end of your feed! Find some more accounts to 46 57 follow. ··· 50 61 type="inverted" 51 62 style={styles.emptyBtn} 52 63 onPress={onPressFindAccounts}> 53 - <Text type="lg-medium" style={palInverted.text}> 54 - <Trans>Find accounts to follow</Trans> 64 + <Text type="lg-medium" style={textStyleInverted}> 65 + <Trans>Find accounts to follow </Trans> 55 66 </Text> 56 67 <FontAwesomeIcon 57 68 icon="angle-right" 58 - style={palInverted.text as FontAwesomeIconStyle} 69 + style={textStyleInverted as FontAwesomeIconStyle} 59 70 size={14} 60 71 /> 61 72 </Button> 62 73 63 - <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}> 74 + <Text type="xl-medium" style={[s.textCenter, textStyle, s.mt20]}> 64 75 <Trans>You can also discover new Custom Feeds to follow.</Trans> 65 76 </Text> 66 77 <Button 67 78 type="inverted" 68 79 style={[styles.emptyBtn, s.mt10]} 69 80 onPress={onPressDiscoverFeeds}> 70 - <Text type="lg-medium" style={palInverted.text}> 71 - <Trans>Discover new custom feeds</Trans> 81 + <Text type="lg-medium" style={textStyleInverted}> 82 + <Trans>Discover new custom feeds </Trans> 72 83 </Text> 73 84 <FontAwesomeIcon 74 85 icon="angle-right" 75 - style={palInverted.text as FontAwesomeIconStyle} 86 + style={textStyleInverted as FontAwesomeIconStyle} 76 87 size={14} 77 88 /> 78 89 </Button>
+21 -7
src/view/com/posts/PostFeedErrorMessage.tsx
··· 9 9 import {useLingui} from '@lingui/react' 10 10 import {useNavigation} from '@react-navigation/native' 11 11 12 - import {usePalette} from '#/lib/hooks/usePalette' 13 12 import {type NavigationProp} from '#/lib/routes/types' 14 13 import {cleanError} from '#/lib/strings/errors' 15 14 import {logger} from '#/logger' 16 15 import {type FeedDescriptor} from '#/state/queries/post-feed' 17 16 import {useRemoveFeedMutation} from '#/state/queries/preferences' 17 + import {useTheme} from '#/alf' 18 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 18 19 import * as Prompt from '#/components/Prompt' 19 20 import {EmptyState} from '../util/EmptyState' 20 21 import {ErrorMessage} from '../util/error/ErrorMessage' ··· 94 95 rawError?: Error 95 96 savedFeedConfig?: AppBskyActorDefs.SavedFeed 96 97 }) { 97 - const pal = usePalette('default') 98 + const theme = useTheme() 99 + const colorMode = useColorModeTheme() 98 100 const {_: _l} = useLingui() 99 101 const navigation = useNavigation<NavigationProp>() 100 102 const msg = React.useMemo( ··· 189 191 <> 190 192 <View 191 193 style={[ 192 - pal.border, 193 - pal.viewLight, 194 + {borderColor: theme.palette.contrast_100}, 195 + {backgroundColor: theme.palette.contrast_25}, 194 196 { 195 197 borderTopWidth: 1, 196 198 paddingHorizontal: 20, ··· 198 200 gap: 12, 199 201 }, 200 202 ]}> 201 - <Text style={pal.text}>{msg}</Text> 203 + <Text 204 + style={{ 205 + color: 206 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 207 + }}> 208 + {msg} 209 + </Text> 202 210 203 211 {rawError?.message && ( 204 - <Text style={pal.textLight}> 205 - <Trans>Message from server: {rawError.message}</Trans> 212 + <Text 213 + style={{ 214 + color: 215 + colorMode === 'dark' 216 + ? theme.palette.contrast_600 217 + : theme.palette.contrast_700, 218 + }}> 219 + <Trans>Message from server: {rawError.message} </Trans> 206 220 </Text> 207 221 )} 208 222
+65 -16
src/view/com/posts/PostFeedItem.tsx
··· 17 17 import {isReasonFeedSource, type ReasonFeedSource} from '#/lib/api/feed/types' 18 18 import {MAX_POST_LINES} from '#/lib/constants' 19 19 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 20 - import {usePalette} from '#/lib/hooks/usePalette' 21 20 import {makeProfileLink} from '#/lib/routes/links' 22 21 import {sanitizeDisplayName} from '#/lib/strings/display-names' 23 22 import {sanitizeHandle} from '#/lib/strings/handles' ··· 40 39 import {PostMeta} from '#/view/com/util/PostMeta' 41 40 import {Text} from '#/view/com/util/text/Text' 42 41 import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' 43 - import {atoms as a} from '#/alf' 42 + import {atoms as a, useTheme} from '#/alf' 43 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 44 44 import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 45 45 import {Repost_Stroke2_Corner2_Rounded as RepostIcon} from '#/components/icons/Repost' 46 46 import {ContentHider} from '#/components/moderation/ContentHider' ··· 167 167 }): React.ReactNode => { 168 168 const queryClient = useQueryClient() 169 169 const {openComposer} = useOpenComposer() 170 - const pal = usePalette('default') 170 + const theme = useTheme() 171 + const colorMode = useColorModeTheme() 171 172 const {_} = useLingui() 172 173 173 174 const [hover, setHover] = useState(false) ··· 247 248 const outerStyles = [ 248 249 styles.outer, 249 250 { 250 - borderColor: pal.colors.border, 251 + borderColor: theme.palette.contrast_100, 251 252 paddingBottom: 252 253 isThreadLastChild || (!isThreadChild && !isThreadParent) 253 254 ? 8 ··· 308 309 styles.replyLine, 309 310 { 310 311 flexGrow: 1, 311 - backgroundColor: pal.colors.replyLine, 312 + backgroundColor: 313 + colorMode === 'light' 314 + ? theme.palette.contrast_100 315 + : theme.palette.contrast_200, 312 316 marginBottom: 4, 313 317 }, 314 318 ]} ··· 321 325 <Link href={reason.href}> 322 326 <Text 323 327 type="sm-bold" 324 - style={pal.textLight} 328 + style={{ 329 + color: 330 + colorMode === 'dark' 331 + ? theme.palette.contrast_600 332 + : theme.palette.contrast_700, 333 + }} 325 334 lineHeight={1.2} 326 335 numberOfLines={1}> 327 336 <Trans context="from-feed"> ··· 332 341 href={reason.href} 333 342 lineHeight={1.2} 334 343 numberOfLines={1} 335 - style={pal.textLight} 344 + style={{ 345 + color: 346 + colorMode === 'dark' 347 + ? theme.palette.contrast_600 348 + : theme.palette.contrast_700, 349 + }} 336 350 /> 337 351 </Trans> 338 352 </Text> ··· 352 366 } 353 367 onBeforePress={onOpenReposter}> 354 368 <RepostIcon 355 - style={{color: pal.colors.textLight, marginRight: 3}} 369 + style={{ 370 + color: 371 + colorMode === 'dark' 372 + ? theme.palette.contrast_600 373 + : theme.palette.contrast_700, 374 + marginRight: 3, 375 + }} 356 376 width={13} 357 377 height={13} 358 378 /> 359 379 <Text 360 380 type="sm-bold" 361 - style={pal.textLight} 381 + style={{ 382 + color: 383 + colorMode === 'dark' 384 + ? theme.palette.contrast_600 385 + : theme.palette.contrast_700, 386 + }} 362 387 lineHeight={1.2} 363 388 numberOfLines={1}> 364 389 {isOwner ? ( 365 - <Trans>Reposted by you</Trans> 390 + <Trans> Reposted by you </Trans> 366 391 ) : ( 367 392 <Trans> 368 393 Reposted by{' '} 369 394 <ProfileHoverCard did={reason.by.did}> 370 395 <TextLinkOnWebOnly 371 396 type="sm-bold" 372 - style={pal.textLight} 397 + style={{ 398 + color: 399 + colorMode === 'dark' 400 + ? theme.palette.contrast_600 401 + : theme.palette.contrast_700, 402 + }} 373 403 lineHeight={1.2} 374 404 numberOfLines={1} 375 405 text={ 376 406 <Text 377 407 emoji 378 408 type="sm-bold" 379 - style={pal.textLight} 409 + style={{ 410 + color: 411 + colorMode === 'dark' 412 + ? theme.palette.contrast_600 413 + : theme.palette.contrast_700, 414 + }} 380 415 lineHeight={1.2}> 381 416 {sanitizeDisplayName( 382 417 reason.by.displayName || ··· 396 431 ) : AppBskyFeedDefs.isReasonPin(reason) ? ( 397 432 <View style={styles.includeReason}> 398 433 <PinIcon 399 - style={{color: pal.colors.textLight, marginRight: 3}} 434 + style={{ 435 + color: 436 + colorMode === 'dark' 437 + ? theme.palette.contrast_600 438 + : theme.palette.contrast_700, 439 + marginRight: 3, 440 + }} 400 441 width={13} 401 442 height={13} 402 443 /> 403 444 <Text 404 445 type="sm-bold" 405 - style={pal.textLight} 446 + style={{ 447 + color: 448 + colorMode === 'dark' 449 + ? theme.palette.contrast_600 450 + : theme.palette.contrast_700, 451 + }} 406 452 lineHeight={1.2} 407 453 numberOfLines={1}> 408 - <Trans>Pinned</Trans> 454 + <Trans>Pinned </Trans> 409 455 </Text> 410 456 </View> 411 457 ) : null} ··· 428 474 styles.replyLine, 429 475 { 430 476 flexGrow: 1, 431 - backgroundColor: pal.colors.replyLine, 477 + backgroundColor: 478 + colorMode === 'light' 479 + ? theme.palette.contrast_100 480 + : theme.palette.contrast_200, 432 481 marginTop: live ? 8 : 4, 433 482 }, 434 483 ]}
+18 -7
src/view/com/posts/ViewFullThread.tsx
··· 5 5 import {msg} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 7 8 - import {usePalette} from '#/lib/hooks/usePalette' 9 8 import {makeProfileLink} from '#/lib/routes/links' 9 + import {useTheme} from '#/alf' 10 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 10 11 import {useInteractionState} from '#/components/hooks/useInteractionState' 11 12 import {SubtleWebHover} from '#/components/SubtleWebHover' 12 13 import {Link} from '../util/Link' ··· 18 19 onIn: onHoverIn, 19 20 onOut: onHoverOut, 20 21 } = useInteractionState() 21 - const pal = usePalette('default') 22 + const theme = useTheme() 23 + const colorMode = useColorModeTheme() 22 24 const itemHref = React.useMemo(() => { 23 25 const urip = new AtUri(uri) 24 26 return makeProfileLink({did: urip.hostname, handle: ''}, 'post', urip.rkey) ··· 45 47 y1="0" 46 48 x2="2" 47 49 y2="15" 48 - stroke={pal.colors.replyLine} 50 + stroke={ 51 + colorMode === 'light' 52 + ? theme.palette.contrast_100 53 + : theme.palette.contrast_200 54 + } 49 55 strokeWidth="2" 50 56 /> 51 - <Circle cx="2" cy="22" r="1.5" fill={pal.colors.replyLineDot} /> 52 - <Circle cx="2" cy="28" r="1.5" fill={pal.colors.replyLineDot} /> 53 - <Circle cx="2" cy="34" r="1.5" fill={pal.colors.replyLineDot} /> 57 + <Circle cx="2" cy="22" r="1.5" fill={theme.palette.contrast_200} /> 58 + <Circle cx="2" cy="28" r="1.5" fill={theme.palette.contrast_200} /> 59 + <Circle cx="2" cy="34" r="1.5" fill={theme.palette.contrast_200} /> 54 60 </Svg> 55 61 </View> 56 62 57 - <Text type="md" style={[pal.link, {paddingTop: 18, paddingBottom: 4}]}> 63 + <Text 64 + type="md" 65 + style={[ 66 + {color: theme.palette.primary_500}, 67 + {paddingTop: 18, paddingBottom: 4}, 68 + ]}> 58 69 {/* HACKFIX: Trans isn't working after SDK 53 upgrade -sfn */} 59 70 {_(msg`View full thread`)} 60 71 </Text>
+23 -8
src/view/com/profile/ProfileSubpageHeader.tsx
··· 1 1 import React from 'react' 2 - import {Pressable, View} from 'react-native' 2 + import {Pressable, type TextStyle, View} from 'react-native' 3 3 import Animated, { 4 4 measure, 5 5 type MeasuredDimensions, ··· 12 12 import {useLingui} from '@lingui/react' 13 13 import {useNavigation} from '@react-navigation/native' 14 14 15 - import {usePalette} from '#/lib/hooks/usePalette' 16 15 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 17 16 import {makeProfileLink} from '#/lib/routes/links' 18 17 import {type NavigationProp} from '#/lib/routes/types' ··· 23 22 import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 24 23 import {Text} from '#/view/com/util/text/Text' 25 24 import {UserAvatar, type UserAvatarType} from '#/view/com/util/UserAvatar' 25 + import {useTheme} from '#/alf' 26 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 26 27 import {StarterPack} from '#/components/icons/StarterPack' 27 28 import * as Layout from '#/components/Layout' 28 29 ··· 55 56 const {_} = useLingui() 56 57 const {isMobile} = useWebMediaQueries() 57 58 const {openLightbox} = useLightboxControls() 58 - const pal = usePalette('default') 59 + const theme = useTheme() 60 + const colorMode = useColorModeTheme() 59 61 const canGoBack = navigation.canGoBack() 60 62 const aviRef = useAnimatedRef() 63 + 64 + const textLightStyle: TextStyle = { 65 + color: 66 + colorMode === 'dark' 67 + ? theme.palette.contrast_600 68 + : theme.palette.contrast_700, 69 + } 61 70 62 71 const _openLightbox = React.useCallback( 63 72 (uri: string, thumbRect: MeasuredDimensions | null) => { ··· 142 151 testID="headerTitle" 143 152 type="title-xl" 144 153 href={href} 145 - style={[pal.text, {fontWeight: '600'}]} 154 + style={{ 155 + fontWeight: '600', 156 + color: 157 + colorMode === 'light' 158 + ? theme.palette.black 159 + : theme.palette.white, 160 + }} 146 161 text={title || ''} 147 162 onPress={emitSoftReset} 148 163 numberOfLines={4} ··· 152 167 {isLoading || !creator ? ( 153 168 <LoadingPlaceholder width={50} height={8} /> 154 169 ) : ( 155 - <Text type="lg" style={[pal.textLight]} numberOfLines={1}> 170 + <Text type="lg" style={textLightStyle} numberOfLines={1}> 156 171 {purpose === 'app.bsky.graph.defs#curatelist' ? ( 157 172 isOwner ? ( 158 173 <Trans>List by you</Trans> ··· 162 177 <TextLink 163 178 text={sanitizeHandle(creator.handle || '', '@')} 164 179 href={makeProfileLink(creator)} 165 - style={pal.textLight} 180 + style={textLightStyle} 166 181 /> 167 182 </Trans> 168 183 ) ··· 175 190 <TextLink 176 191 text={sanitizeHandle(creator.handle || '', '@')} 177 192 href={makeProfileLink(creator)} 178 - style={pal.textLight} 193 + style={textLightStyle} 179 194 /> 180 195 </Trans> 181 196 ) ··· 188 203 <TextLink 189 204 text={sanitizeHandle(creator.handle || '', '@')} 190 205 href={makeProfileLink(creator)} 191 - style={pal.textLight} 206 + style={textLightStyle} 192 207 /> 193 208 </Trans> 194 209 )
+10 -6
src/view/com/util/EmptyState.tsx
··· 5 5 type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 8 - import {usePalette} from '#/lib/hooks/usePalette' 9 8 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 10 9 import {UserGroupIcon} from '#/lib/icons' 10 + import {useTheme} from '#/alf' 11 11 import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' 12 12 import {Text} from './text/Text' 13 13 ··· 22 22 message: string 23 23 style?: StyleProp<ViewStyle> 24 24 }) { 25 - const pal = usePalette('default') 25 + const theme = useTheme() 26 26 const {isTabletOrDesktop} = useWebMediaQueries() 27 27 const iconSize = isTabletOrDesktop ? 64 : 48 28 28 return ( ··· 31 31 style={[ 32 32 styles.iconContainer, 33 33 isTabletOrDesktop && styles.iconContainerBig, 34 - pal.viewLight, 34 + {backgroundColor: theme.palette.contrast_25}, 35 35 ]}> 36 36 {icon === 'user-group' ? ( 37 37 <UserGroupIcon size={iconSize} /> 38 38 ) : icon === 'growth' ? ( 39 - <Growth width={iconSize} fill={pal.colors.emptyStateIcon} /> 39 + <Growth width={iconSize} fill={theme.palette.contrast_300} /> 40 40 ) : ( 41 41 <FontAwesomeIcon 42 42 icon={icon} 43 43 size={iconSize} 44 - style={[{color: pal.colors.emptyStateIcon} as FontAwesomeIconStyle]} 44 + style={[ 45 + {color: theme.palette.contrast_300} as FontAwesomeIconStyle, 46 + ]} 45 47 /> 46 48 )} 47 49 </View> 48 - <Text type="xl" style={[{color: pal.colors.textLight}, styles.text]}> 50 + <Text 51 + type="xl" 52 + style={[{color: theme.palette.contrast_600}, styles.text]}> 49 53 {message} 50 54 </Text> 51 55 </View>
+17 -8
src/view/com/util/EmptyStateWithButton.tsx
··· 1 - import {StyleSheet, View} from 'react-native' 1 + import {StyleSheet, type TextStyle, View} from 'react-native' 2 2 import {type IconProp} from '@fortawesome/fontawesome-svg-core' 3 3 import { 4 4 FontAwesomeIcon, 5 5 type FontAwesomeIconStyle, 6 6 } from '@fortawesome/react-native-fontawesome' 7 7 8 - import {usePalette} from '#/lib/hooks/usePalette' 9 8 import {s} from '#/lib/styles' 9 + import {useTheme} from '#/alf' 10 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 10 11 import {Button} from './forms/Button' 11 12 import {Text} from './text/Text' 12 13 ··· 19 20 } 20 21 21 22 export function EmptyStateWithButton(props: Props) { 22 - const pal = usePalette('default') 23 - const palInverted = usePalette('inverted') 23 + const theme = useTheme() 24 + const colorMode = useColorModeTheme() 25 + 26 + const textStyle: TextStyle = { 27 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 28 + } 29 + 30 + const textStyleInverted: TextStyle = { 31 + color: colorMode === 'light' ? theme.palette.white : theme.palette.black, 32 + } 24 33 25 34 return ( 26 35 <View testID={props.testID} style={styles.container}> 27 36 <View style={styles.iconContainer}> 28 37 <FontAwesomeIcon 29 38 icon={props.icon} 30 - style={[styles.icon, pal.text]} 39 + style={[styles.icon, textStyle]} 31 40 size={62} 32 41 /> 33 42 </View> 34 - <Text type="xl-medium" style={[s.textCenter, pal.text]}> 43 + <Text type="xl-medium" style={[s.textCenter, textStyle]}> 35 44 {props.message} 36 45 </Text> 37 46 <View style={styles.btns}> ··· 42 51 onPress={props.onPress}> 43 52 <FontAwesomeIcon 44 53 icon="plus" 45 - style={palInverted.text as FontAwesomeIconStyle} 54 + style={textStyleInverted as FontAwesomeIconStyle} 46 55 size={14} 47 56 /> 48 - <Text type="lg-medium" style={palInverted.text}> 57 + <Text type="lg-medium" style={textStyleInverted}> 49 58 {props.buttonLabel} 50 59 </Text> 51 60 </Button>
+25 -4
src/view/com/util/LoadMoreRetryBtn.tsx
··· 4 4 type FontAwesomeIconStyle, 5 5 } from '@fortawesome/react-native-fontawesome' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 7 + import {useTheme} from '#/alf' 8 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 8 9 import {Button} from './forms/Button' 9 10 import {Text} from './text/Text' 10 11 ··· 15 16 label: string 16 17 onPress: () => void 17 18 }) { 18 - const pal = usePalette('default') 19 + const theme = useTheme() 20 + const colorMode = useColorModeTheme() 19 21 return ( 20 22 <Button type="default-light" onPress={onPress} style={styles.loadMoreRetry}> 21 23 <FontAwesomeIcon 22 24 icon="arrow-rotate-left" 23 - style={pal.textLight as FontAwesomeIconStyle} 25 + style={ 26 + { 27 + color: 28 + colorMode === 'dark' 29 + ? theme.palette.contrast_600 30 + : theme.palette.contrast_700, 31 + } as FontAwesomeIconStyle 32 + } 24 33 size={18} 25 34 /> 26 - <Text style={[pal.textLight, styles.label]}>{label}</Text> 35 + <Text 36 + style={[ 37 + { 38 + color: 39 + colorMode === 'dark' 40 + ? theme.palette.contrast_600 41 + : theme.palette.contrast_700, 42 + }, 43 + styles.label, 44 + ]}> 45 + {' '} 46 + {label}{' '} 47 + </Text> 27 48 </Button> 28 49 ) 29 50 }
+54 -23
src/view/com/util/LoadingPlaceholder.tsx
··· 7 7 type ViewStyle, 8 8 } from 'react-native' 9 9 10 - import {usePalette} from '#/lib/hooks/usePalette' 11 10 import {s} from '#/lib/styles' 12 - import {useTheme} from '#/lib/ThemeContext' 13 - import {atoms as a, useTheme as useTheme_NEW} from '#/alf' 11 + import {atoms as a, useTheme} from '#/alf' 12 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 14 13 import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble' 15 14 import { 16 15 Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled, ··· 35 34 { 36 35 width, 37 36 height, 38 - backgroundColor: theme.palette.default.backgroundLight, 37 + backgroundColor: theme.palette.contrast_25, 39 38 }, 40 39 style, 41 40 ]} ··· 48 47 }: { 49 48 style?: StyleProp<ViewStyle> 50 49 }) { 51 - const t = useTheme_NEW() 52 - const pal = usePalette('default') 50 + const theme = useTheme() 51 + const colorMode = useColorModeTheme() 53 52 return ( 54 - <View style={[styles.post, pal.view, style]}> 53 + <View 54 + style={[ 55 + styles.post, 56 + { 57 + backgroundColor: 58 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 59 + }, 60 + style, 61 + ]}> 55 62 <LoadingPlaceholder 56 63 width={42} 57 64 height={42} ··· 74 81 <Bubble 75 82 style={[ 76 83 { 77 - color: t.palette.contrast_500, 84 + color: theme.palette.contrast_500, 78 85 }, 79 86 {pointerEvents: 'none'}, 80 87 ]} ··· 87 94 <Repost 88 95 style={[ 89 96 { 90 - color: t.palette.contrast_500, 97 + color: theme.palette.contrast_500, 91 98 }, 92 99 {pointerEvents: 'none'}, 93 100 ]} ··· 100 107 <HeartIconOutline 101 108 style={[ 102 109 { 103 - color: t.palette.contrast_500, 110 + color: theme.palette.contrast_500, 104 111 }, 105 112 {pointerEvents: 'none'}, 106 113 ]} ··· 137 144 }: { 138 145 style?: StyleProp<ViewStyle> 139 146 }) { 140 - const pal = usePalette('default') 147 + const theme = useTheme() 148 + const colorMode = useColorModeTheme() 141 149 return ( 142 - <View style={[styles.notification, pal.view, style]}> 150 + <View 151 + style={[ 152 + styles.notification, 153 + { 154 + backgroundColor: 155 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 156 + }, 157 + style, 158 + ]}> 143 159 <View style={[{width: 60}, a.align_end, a.pr_sm, a.pt_2xs]}> 144 - <HeartIconFilled 145 - size="xl" 146 - style={{color: pal.colors.backgroundLight}} 147 - /> 160 + <HeartIconFilled size="xl" style={{color: theme.palette.contrast_25}} /> 148 161 </View> 149 162 <View style={{flex: 1}}> 150 163 <View style={[a.flex_row, s.mb10]}> ··· 184 197 }: { 185 198 style?: StyleProp<ViewStyle> 186 199 }) { 187 - const pal = usePalette('default') 200 + const theme = useTheme() 201 + const colorMode = useColorModeTheme() 188 202 return ( 189 - <View style={[styles.profileCard, pal.view, style]}> 203 + <View 204 + style={[ 205 + styles.profileCard, 206 + { 207 + backgroundColor: 208 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 209 + }, 210 + style, 211 + ]}> 190 212 <LoadingPlaceholder 191 213 width={40} 192 214 height={40} ··· 228 250 showTopBorder?: boolean 229 251 showLowerPlaceholder?: boolean 230 252 }) { 231 - const pal = usePalette('default') 253 + const theme = useTheme() 254 + const colorMode = useColorModeTheme() 232 255 return ( 233 256 <View 234 257 style={[ ··· 236 259 padding: 16, 237 260 borderTopWidth: showTopBorder ? StyleSheet.hairlineWidth : 0, 238 261 }, 239 - pal.border, 262 + {borderColor: theme.palette.contrast_100}, 240 263 style, 241 264 ]}> 242 - <View style={[pal.view, {flexDirection: 'row'}]}> 265 + <View 266 + style={[ 267 + { 268 + backgroundColor: 269 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 270 + }, 271 + {flexDirection: 'row'}, 272 + ]}> 243 273 <LoadingPlaceholder 244 274 width={36} 245 275 height={36} ··· 282 312 }: { 283 313 style?: StyleProp<ViewStyle> 284 314 }) { 285 - const t = useTheme_NEW() 315 + const theme = useTheme() 286 316 const random = useMemo(() => Math.random(), []) 287 317 return ( 288 - <View style={[a.flex_row, a.gap_md, a.px_lg, a.mt_lg, t.atoms.bg, style]}> 318 + <View 319 + style={[a.flex_row, a.gap_md, a.px_lg, a.mt_lg, theme.atoms.bg, style]}> 289 320 <LoadingPlaceholder width={52} height={52} style={a.rounded_full} /> 290 321 <View> 291 322 <LoadingPlaceholder width={140} height={12} style={a.mt_xs} />
+39 -8
src/view/com/util/ViewSelector.tsx
··· 10 10 } from 'react-native' 11 11 12 12 import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 13 import {clamp} from '#/lib/numbers' 15 14 import {colors, s} from '#/lib/styles' 16 15 import {isAndroid} from '#/platform/detection' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import {Text} from './text/Text' 18 19 import {FlatList_INTERNAL} from './Views' 19 20 ··· 59 60 }, 60 61 ref, 61 62 ) { 62 - const pal = usePalette('default') 63 + const theme = useTheme() 64 + const colorMode = useColorModeTheme() 63 65 const [selectedIndex, setSelectedIndex] = useState<number>(0) 64 66 const flatListRef = React.useRef<FlatList_INTERNAL>(null) 65 67 ··· 127 129 <RefreshControl 128 130 refreshing={refreshing!} 129 131 onRefresh={onRefresh} 130 - tintColor={pal.colors.text} 132 + tintColor={ 133 + colorMode === 'light' ? theme.palette.black : theme.palette.white 134 + } 131 135 /> 132 136 } 133 137 onEndReachedThreshold={0.6} ··· 147 151 items: string[] 148 152 onSelect?: (index: number) => void 149 153 }) { 150 - const pal = usePalette('default') 154 + const theme = useTheme() 155 + const colorMode = useColorModeTheme() 151 156 const borderColor = useColorSchemeStyle( 152 157 {borderColor: colors.black}, 153 158 {borderColor: colors.white}, ··· 161 166 <View 162 167 style={{ 163 168 width: '100%', 164 - backgroundColor: pal.colors.background, 169 + backgroundColor: 170 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 165 171 }}> 166 172 <ScrollView 167 173 testID="selector" 168 174 horizontal 169 175 showsHorizontalScrollIndicator={false}> 170 - <View style={[pal.view, styles.outer]}> 176 + <View 177 + style={[ 178 + { 179 + backgroundColor: 180 + colorMode === 'light' 181 + ? theme.palette.white 182 + : theme.palette.black, 183 + }, 184 + styles.outer, 185 + ]}> 171 186 {items.map((item, i) => { 172 187 const selected = i === selectedIndex 173 188 return ( ··· 189 204 <Text 190 205 style={ 191 206 selected 192 - ? [styles.labelSelected, pal.text] 193 - : [styles.label, pal.textLight] 207 + ? [ 208 + styles.labelSelected, 209 + { 210 + color: 211 + colorMode === 'light' 212 + ? theme.palette.black 213 + : theme.palette.white, 214 + }, 215 + ] 216 + : [ 217 + styles.label, 218 + { 219 + color: 220 + colorMode === 'light' 221 + ? theme.palette.white 222 + : theme.palette.black, 223 + }, 224 + ] 194 225 }> 195 226 {item} 196 227 </Text>
+5 -4
src/view/com/util/Views.web.tsx
··· 23 23 } from 'react-native' 24 24 import Animated from 'react-native-reanimated' 25 25 26 - import {usePalette} from '#/lib/hooks/usePalette' 27 26 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 28 27 import {addStyle} from '#/lib/styles' 29 - import {useLayoutBreakpoints} from '#/alf' 28 + import {useLayoutBreakpoints, useTheme} from '#/alf' 30 29 import {useDialogContext} from '#/components/Dialog' 31 30 import {CENTER_COLUMN_OFFSET} from '#/components/Layout' 32 31 ··· 47 46 >, 48 47 ref: React.Ref<View>, 49 48 ) { 50 - const pal = usePalette('default') 49 + const theme = useTheme() 51 50 const {isMobile} = useWebMediaQueries() 52 51 const {centerColumnOffset} = useLayoutBreakpoints() 53 52 const {isWithinDialog} = useDialogContext() ··· 61 60 style = addStyle(style, { 62 61 borderTopWidth: 1, 63 62 }) 64 - style = addStyle(style, pal.border) 63 + style = addStyle(style, { 64 + borderColor: theme.palette.contrast_100, 65 + }) 65 66 } 66 67 return <View ref={ref} style={style} {...props} /> 67 68 })
+12 -8
src/view/com/util/error/ErrorMessage.tsx
··· 12 12 import {msg} from '@lingui/macro' 13 13 import {useLingui} from '@lingui/react' 14 14 15 - import {usePalette} from '#/lib/hooks/usePalette' 16 - import {useTheme} from '#/lib/ThemeContext' 15 + import {useTheme} from '#/alf' 17 16 import * as Layout from '#/components/Layout' 18 17 import {Text} from '../text/Text' 19 18 ··· 29 28 onPressTryAgain?: () => void 30 29 }) { 31 30 const theme = useTheme() 32 - const pal = usePalette('error') 33 31 const {_} = useLingui() 34 32 return ( 35 33 <Layout.Center> 36 - <View testID="errorMessageView" style={[styles.outer, pal.view, style]}> 34 + <View 35 + testID="errorMessageView" 36 + style={[ 37 + styles.outer, 38 + {backgroundColor: theme.palette.negative_300}, 39 + style, 40 + ]}> 37 41 <View 38 42 style={[ 39 43 styles.errorIcon, 40 - {backgroundColor: theme.palette.error.icon}, 44 + {backgroundColor: theme.palette.negative_400}, 41 45 ]}> 42 46 <FontAwesomeIcon 43 47 icon="exclamation" 44 - style={pal.text as FontAwesomeIconStyle} 48 + style={{color: theme.palette.negative_400} as FontAwesomeIconStyle} 45 49 size={16} 46 50 /> 47 51 </View> 48 52 <Text 49 53 type="sm-medium" 50 - style={[styles.message, pal.text]} 54 + style={[styles.message, {color: theme.palette.white}]} 51 55 numberOfLines={numberOfLines}> 52 56 {message} 53 57 </Text> ··· 63 67 )}> 64 68 <FontAwesomeIcon 65 69 icon="arrows-rotate" 66 - style={{color: theme.palette.error.icon}} 70 + style={{color: theme.palette.negative_400}} 67 71 size={18} 68 72 /> 69 73 </TouchableOpacity>
+11 -6
src/view/com/util/error/ErrorScreen.tsx
··· 6 6 import {msg, Trans} from '@lingui/macro' 7 7 import {useLingui} from '@lingui/react' 8 8 9 - import {usePalette} from '#/lib/hooks/usePalette' 10 9 import {atoms as a, useTheme} from '#/alf' 10 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 11 11 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 12 12 import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as ArrowRotateCounterClockwiseIcon} from '#/components/icons/ArrowRotateCounterClockwise' 13 13 import * as Layout from '#/components/Layout' ··· 29 29 showHeader?: boolean 30 30 }) { 31 31 const t = useTheme() 32 - const pal = usePalette('default') 32 + const colorMode = useColorModeTheme() 33 33 const {_} = useLingui() 34 34 35 35 return ( ··· 39 39 <Layout.Header.BackButton /> 40 40 <Layout.Header.Content> 41 41 <Layout.Header.TitleText> 42 - <Trans>Error</Trans> 42 + <Trans>Error </Trans> 43 43 </Layout.Header.TitleText> 44 44 </Layout.Header.Content> 45 45 <Layout.Header.Slot /> ··· 57 57 ]}> 58 58 <FontAwesomeIcon 59 59 icon="exclamation" 60 - style={pal.textInverted as FontAwesomeIconStyle} 60 + style={ 61 + { 62 + color: 63 + colorMode === 'light' ? t.palette.white : t.palette.black, 64 + } as FontAwesomeIconStyle 65 + } 61 66 size={24} 62 67 /> 63 68 </View> ··· 65 70 <Text style={[a.text_center, a.font_heavy, a.text_2xl, a.mb_md]}> 66 71 {title} 67 72 </Text> 68 - <Text style={[a.text_center, a.text_md, a.mb_xl]}>{message}</Text> 73 + <Text style={[a.text_center, a.text_md, a.mb_xl]}> {message} </Text> 69 74 {details && ( 70 75 <View 71 76 style={[ ··· 100 105 )}> 101 106 <ButtonIcon icon={ArrowRotateCounterClockwiseIcon} /> 102 107 <ButtonText> 103 - <Trans context="action">Try again</Trans> 108 + <Trans context="action"> Try again </Trans> 104 109 </ButtonText> 105 110 </Button> 106 111 </View>
+37 -13
src/view/com/util/forms/NativeDropdown.tsx
··· 3 3 Platform, 4 4 Pressable, 5 5 StyleSheet, 6 + type TextStyle, 6 7 View, 7 8 type ViewStyle, 8 9 } from 'react-native' ··· 11 12 import * as DropdownMenu from 'zeego/dropdown-menu' 12 13 import {type MenuItemCommonProps} from 'zeego/lib/typescript/menu' 13 14 14 - import {usePalette} from '#/lib/hooks/usePalette' 15 - import {useTheme} from '#/lib/ThemeContext' 16 15 import {isIOS} from '#/platform/detection' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import {Portal} from '#/components/Portal' 18 19 19 20 // Custom Dropdown Menu Components ··· 43 44 export const DropdownMenuTrigger = DropdownMenu.create( 44 45 (props: TriggerProps) => { 45 46 const theme = useTheme() 46 - const defaultCtrlColor = theme.palette.default.postCtrl 47 + 48 + const defaultCtrlColor = theme.palette.contrast_500 47 49 48 50 return ( 49 51 // This Pressable doesn't actually do anything other than ··· 80 82 export const DropdownMenuItem = DropdownMenu.create( 81 83 (props: ItemProps & {testID?: string}) => { 82 84 const theme = useTheme() 85 + const colorMode = useColorModeTheme() 83 86 const [focused, setFocused] = React.useState(false) 84 - const backgroundColor = theme.colorScheme === 'dark' ? '#fff1' : '#0001' 87 + const backgroundColor = 88 + colorMode === 'light' ? theme.palette.black : theme.palette.white 85 89 86 90 return ( 87 91 <DropdownMenu.Item ··· 107 111 */ 108 112 export const DropdownMenuItemTitle = DropdownMenu.create( 109 113 (props: TitleProps) => { 110 - const pal = usePalette('default') 114 + const theme = useTheme() 115 + const colorMode = useColorModeTheme() 116 + 111 117 return ( 112 118 <DropdownMenu.ItemTitle 113 119 {...props} 114 - style={[props.style, pal.text, styles.itemTitle]} 120 + style={[ 121 + props.style, 122 + { 123 + color: 124 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 125 + }, 126 + styles.itemTitle, 127 + ]} 115 128 /> 116 129 ) 117 130 }, ··· 132 145 */ 133 146 export const DropdownMenuSeparator = DropdownMenu.create( 134 147 (props: SeparatorProps) => { 135 - const pal = usePalette('default') 136 148 const theme = useTheme() 149 + const colorMode = useColorModeTheme() 137 150 const {borderColor: separatorColor} = 138 - theme.colorScheme === 'dark' ? pal.borderDark : pal.border 151 + colorMode === 'dark' 152 + ? { 153 + borderColor: theme.palette.contrast_200, 154 + } 155 + : { 156 + borderColor: theme.palette.contrast_100, 157 + } 139 158 return ( 140 159 <DropdownMenu.Separator 141 160 {...props} ··· 185 204 accessibilityLabel, 186 205 accessibilityHint, 187 206 }: React.PropsWithChildren<Props>) { 188 - const pal = usePalette('default') 189 207 const theme = useTheme() 208 + const colorMode = useColorModeTheme() 190 209 const [isOpen, setIsOpen] = React.useState(false) 191 - const dropDownBackgroundColor = 192 - theme.colorScheme === 'dark' ? pal.btn : pal.viewLight 210 + const dropDownBackgroundColor = { 211 + backgroundColor: theme.palette.contrast_25, 212 + } 213 + 214 + const textStyle: TextStyle = { 215 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 216 + } 193 217 194 218 return ( 195 219 <> ··· 234 258 <FontAwesomeIcon 235 259 icon={item.icon.web} 236 260 size={20} 237 - style={[pal.text]} 261 + style={[textStyle]} 238 262 /> 239 263 </DropdownMenuItemIcon> 240 264 )} ··· 255 279 <FontAwesomeIcon 256 280 icon={item.icon.web} 257 281 size={20} 258 - style={[pal.text]} 282 + style={[textStyle]} 259 283 /> 260 284 </DropdownMenuItemIcon> 261 285 )}
+39 -11
src/view/com/util/forms/NativeDropdown.web.tsx
··· 3 3 Pressable, 4 4 StyleSheet, 5 5 Text, 6 + type TextStyle, 6 7 type View, 7 8 type ViewStyle, 8 9 } from 'react-native' ··· 12 13 import {type MenuItemCommonProps} from 'zeego/lib/typescript/menu' 13 14 14 15 import {HITSLOP_10} from '#/lib/constants' 15 - import {usePalette} from '#/lib/hooks/usePalette' 16 - import {useTheme} from '#/lib/ThemeContext' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 18 19 // Custom Dropdown Menu Components 19 20 // == ··· 22 23 23 24 type ItemProps = React.ComponentProps<(typeof DropdownMenu)['Item']> 24 25 export const DropdownMenuItem = (props: ItemProps & {testID?: string}) => { 26 + const [focused, setFocused] = React.useState(false) 25 27 const theme = useTheme() 26 - const [focused, setFocused] = React.useState(false) 27 - const backgroundColor = theme.colorScheme === 'dark' ? '#fff1' : '#0001' 28 + const colorMode = useColorModeTheme() 29 + const backgroundColor = 30 + colorMode === 'light' ? theme.palette.black : theme.palette.white 28 31 29 32 return ( 30 33 <DropdownMenu.Item ··· 163 166 items: DropdownItem[] 164 167 menuRef: React.RefObject<HTMLDivElement | null> 165 168 }) { 166 - const pal = usePalette('default') 167 169 const theme = useTheme() 170 + const colorMode = useColorModeTheme() 168 171 const dropDownBackgroundColor = 169 - theme.colorScheme === 'dark' ? pal.btn : pal.view 172 + colorMode === 'dark' 173 + ? { 174 + backgroundColor: theme.palette.contrast_25, 175 + } 176 + : { 177 + backgroundColor: 178 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 179 + } 170 180 const {borderColor: separatorColor} = 171 - theme.colorScheme === 'dark' ? pal.borderDark : pal.border 181 + colorMode === 'dark' 182 + ? { 183 + borderColor: theme.palette.contrast_200, 184 + } 185 + : { 186 + borderColor: theme.palette.contrast_100, 187 + } 188 + 189 + const textStyle: TextStyle = { 190 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 191 + } 172 192 173 193 return ( 174 194 <DropdownMenu.Content ··· 200 220 <DropdownMenuItem 201 221 key={getKey(item.label, index, item.testID)} 202 222 onSelect={item.onPress}> 203 - <Text selectable={false} style={[pal.text, styles.itemTitle]}> 223 + <Text selectable={false} style={[textStyle, styles.itemTitle]}> 204 224 {item.label} 205 225 </Text> 206 226 {item.icon && ( 207 227 <FontAwesomeIcon 208 228 icon={item.icon.web} 209 229 size={20} 210 - color={pal.colors.textLight} 230 + color={ 231 + colorMode === 'light' 232 + ? theme.palette.white 233 + : theme.palette.black 234 + } 211 235 /> 212 236 )} 213 237 </DropdownMenuItem> ··· 218 242 <DropdownMenuItem 219 243 key={getKey(item.label, index, item.testID)} 220 244 onSelect={item.onPress}> 221 - <Text selectable={false} style={[pal.text, styles.itemTitle]}> 245 + <Text selectable={false} style={[textStyle, styles.itemTitle]}> 222 246 {item.label} 223 247 </Text> 224 248 {item.icon && ( 225 249 <FontAwesomeIcon 226 250 icon={item.icon.web} 227 251 size={20} 228 - color={pal.colors.textLight} 252 + color={ 253 + colorMode === 'light' 254 + ? theme.palette.white 255 + : theme.palette.black 256 + } 229 257 /> 230 258 )} 231 259 </DropdownMenuItem>
+35 -11
src/view/com/util/layouts/LoggedOutLayout.tsx
··· 1 - import {ScrollView, StyleSheet, View} from 'react-native' 1 + import {ScrollView, StyleSheet, View, type ViewStyle} from 'react-native' 2 2 import type React from 'react' 3 3 4 4 import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' 5 5 import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible' 6 - import {usePalette} from '#/lib/hooks/usePalette' 7 6 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 8 7 import {isWeb} from '#/platform/detection' 9 - import {atoms as a} from '#/alf' 8 + import {atoms as a, useTheme} from '#/alf' 9 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 10 10 import {Text} from '../text/Text' 11 11 12 12 export const LoggedOutLayout = ({ ··· 22 22 scrollable?: boolean 23 23 }>) => { 24 24 const {isMobile, isTabletOrMobile} = useWebMediaQueries() 25 - const pal = usePalette('default') 26 - const sideBg = useColorSchemeStyle(pal.viewLight, pal.view) 27 - const contentBg = useColorSchemeStyle(pal.view, { 28 - backgroundColor: pal.colors.background, 29 - borderColor: pal.colors.border, 25 + const theme = useTheme() 26 + const colorMode = useColorModeTheme() 27 + const viewStyle: ViewStyle = { 28 + backgroundColor: 29 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 30 + } 31 + const sideBg = useColorSchemeStyle( 32 + {backgroundColor: theme.palette.contrast_25}, 33 + viewStyle, 34 + ) 35 + const contentBg = useColorSchemeStyle(viewStyle, { 36 + backgroundColor: 37 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 38 + borderColor: theme.palette.contrast_25, 30 39 borderLeftWidth: 1, 31 40 }) 32 41 ··· 54 63 <View style={[styles.side, sideBg]}> 55 64 <Text 56 65 style={[ 57 - pal.textLight, 66 + { 67 + color: 68 + colorMode === 'dark' 69 + ? theme.palette.contrast_600 70 + : theme.palette.contrast_700, 71 + }, 58 72 styles.leadinText, 59 73 isTabletOrMobile && styles.leadinTextSmall, 60 74 ]}> ··· 62 76 </Text> 63 77 <Text 64 78 style={[ 65 - pal.link, 79 + {color: theme.palette.primary_500}, 66 80 styles.titleText, 67 81 isTabletOrMobile && styles.titleTextSmall, 68 82 ]}> 69 83 {title} 70 84 </Text> 71 - <Text type="2xl-medium" style={[pal.textLight, styles.descriptionText]}> 85 + <Text 86 + type="2xl-medium" 87 + style={[ 88 + { 89 + color: 90 + colorMode === 'dark' 91 + ? theme.palette.contrast_600 92 + : theme.palette.contrast_700, 93 + }, 94 + styles.descriptionText, 95 + ]}> 72 96 {description} 73 97 </Text> 74 98 </View>
+9 -3
src/view/icons/Logomark.tsx
··· 1 1 import Svg, {Path, type PathProps, type SvgProps} from 'react-native-svg' 2 2 3 - import {usePalette} from '#/lib/hooks/usePalette' 3 + import {useTheme} from '#/alf' 4 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 4 5 5 6 const ratio = 54 / 61 6 7 ··· 8 9 fill, 9 10 ...rest 10 11 }: {fill?: PathProps['fill']} & SvgProps) { 11 - const pal = usePalette('default') 12 + const theme = useTheme() 13 + const colorMode = useColorModeTheme() 12 14 // @ts-ignore it's fiiiiine 13 15 const size = parseInt(rest.width || 32) 14 16 ··· 20 22 width={size} 21 23 height={Number(size) * ratio}> 22 24 <Path 23 - fill={fill || pal.text.color} 25 + fill={ 26 + fill || colorMode === 'light' 27 + ? theme.palette.black 28 + : theme.palette.white 29 + } 24 30 d="M13.223 3.602C20.215 8.832 27.738 19.439 30.5 25.13c2.762-5.691 10.284-16.297 17.278-21.528C52.824-.172 61-3.093 61 6.2c0 1.856-1.068 15.59-1.694 17.82-2.178 7.752-10.112 9.73-17.17 8.532 12.337 2.092 15.475 9.021 8.697 15.95-12.872 13.159-18.5-3.302-19.943-7.52-.264-.773-.388-1.135-.39-.827-.002-.308-.126.054-.39.827-1.442 4.218-7.071 20.679-19.943 7.52-6.778-6.929-3.64-13.858 8.697-15.95-7.058 1.197-14.992-.78-17.17-8.532C1.068 21.79 0 8.056 0 6.2 0-3.093 8.176-.172 13.223 3.602Z" 25 31 /> 26 32 </Svg>
+9 -3
src/view/icons/Logotype.tsx
··· 1 1 import Svg, {Path, type PathProps, type SvgProps} from 'react-native-svg' 2 2 3 - import {usePalette} from '#/lib/hooks/usePalette' 3 + import {useTheme} from '#/alf' 4 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 4 5 5 6 const ratio = 17 / 64 6 7 ··· 8 9 fill, 9 10 ...rest 10 11 }: {fill?: PathProps['fill']} & SvgProps) { 11 - const pal = usePalette('default') 12 + const theme = useTheme() 13 + const colorMode = useColorModeTheme() 12 14 // @ts-ignore it's fiiiiine 13 15 const size = parseInt(rest.width || 32) 14 16 ··· 20 22 width={size} 21 23 height={Number(size) * ratio}> 22 24 <Path 23 - fill={fill || pal.text.color} 25 + fill={ 26 + fill || colorMode === 'light' 27 + ? theme.palette.black 28 + : theme.palette.white 29 + } 24 30 d="M8.478 6.252c1.503.538 2.3 1.78 2.3 3.172 0 2.356-1.576 3.785-4.6 3.785H0V0h5.974c2.875 0 4.267 1.466 4.267 3.413 0 1.3-.594 2.245-1.763 2.839Zm-2.69-4.193H2.504v3.45h3.284c1.28 0 1.967-.667 1.967-1.78 0-1.02-.705-1.67-1.967-1.67Zm-3.284 9.072h3.544c1.41 0 2.17-.65 2.17-1.818 0-1.224-.723-1.837-2.17-1.837H2.504v3.655ZM14.251 13.209h-2.337V0h2.337v13.209ZM22.001 8.998V3.636h2.338v9.573h-2.263v-1.392c-.724 1.076-1.726 1.614-3.006 1.614-2.022 0-3.34-1.224-3.34-3.45V3.636h2.338v5.955c0 1.206.594 1.818 1.8 1.818 1.132 0 2.133-.835 2.133-2.411ZM34.979 8.59v.556h-7.161c.167 1.651 1.076 2.467 2.486 2.467 1.076 0 1.8-.463 2.189-1.372h2.244c-.5 1.947-2.17 3.19-4.452 3.19-1.428 0-2.579-.463-3.45-1.372-.872-.91-1.318-2.115-1.318-3.637 0-1.502.427-2.708 1.299-3.636.872-.909 2.004-1.372 3.432-1.372 1.447 0 2.597.482 3.45 1.428.854.946 1.28 2.208 1.28 3.747Zm-4.75-3.358c-1.28 0-2.17.742-2.393 2.281h4.805c-.204-1.391-1.057-2.281-2.411-2.281ZM40.16 13.469c-2.783 0-4.249-1.095-4.379-3.303h2.282c.13 1.188.724 1.633 2.134 1.633 1.261 0 1.892-.39 1.892-1.15 0-.687-.445-1.02-1.874-1.262l-1.094-.185c-2.097-.353-3.136-1.318-3.136-2.894 0-1.8 1.429-2.894 3.97-2.894 2.728 0 4.138 1.075 4.23 3.246h-2.207c-.056-1.169-.742-1.577-2.023-1.577-1.113 0-1.67.371-1.67 1.113 0 .668.483.965 1.596 1.169l1.206.186c2.32.426 3.32 1.28 3.32 2.912 0 1.93-1.557 3.006-4.247 3.006ZM54.667 13.209h-2.671l-2.783-4.453-1.447 1.447v3.006h-2.3V0h2.3v7.606l3.896-3.97h2.783l-3.618 3.618 3.84 5.955ZM60.772 6.048l.78-2.412H64l-3.692 10.352c-.39 1.057-.872 1.818-1.484 2.245-.612.426-1.484.63-2.634.63-.39 0-.724-.018-1.02-.055V14.97h.89c1.057 0 1.577-.65 1.577-1.54 0-.445-.149-1.094-.446-1.929l-2.746-7.866h2.487l.779 2.393c.575 1.8 1.076 3.58 1.521 5.343.408-1.521.928-3.302 1.54-5.324Z" 25 31 /> 26 32 </Svg>
+22 -5
src/view/screens/CommunityGuidelines.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import { 9 8 type CommonNavigatorParams, 10 9 type NativeStackScreenProps, ··· 14 13 import {TextLink} from '#/view/com/util/Link' 15 14 import {Text} from '#/view/com/util/text/Text' 16 15 import {ScrollView} from '#/view/com/util/Views' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import * as Layout from '#/components/Layout' 18 19 import {ViewHeader} from '../com/util/ViewHeader' 19 20 ··· 22 23 'CommunityGuidelines' 23 24 > 24 25 export const CommunityGuidelinesScreen = (_props: Props) => { 25 - const pal = usePalette('default') 26 + const theme = useTheme() 27 + const colorMode = useColorModeTheme() 26 28 const {_} = useLingui() 27 29 const setMinimalShellMode = useSetMinimalShellMode() 28 30 ··· 35 37 return ( 36 38 <Layout.Screen> 37 39 <ViewHeader title={_(msg`Community Guidelines`)} /> 38 - <ScrollView style={[s.hContentRegion, pal.view]}> 40 + <ScrollView 41 + style={[ 42 + s.hContentRegion, 43 + { 44 + backgroundColor: 45 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 46 + }, 47 + ]}> 39 48 <View style={[s.p20]}> 40 - <Text style={pal.text}> 49 + <Text 50 + style={{ 51 + color: 52 + colorMode === 'light' 53 + ? theme.palette.black 54 + : theme.palette.white, 55 + }}> 41 56 <Trans> 42 57 The Community Guidelines have been moved to{' '} 43 58 <TextLink 44 - style={pal.link} 59 + style={{ 60 + color: theme.palette.primary_500, 61 + }} 45 62 href="https://bsky.social/about/support/community-guidelines" 46 63 text="bsky.social/about/support/community-guidelines" 47 64 />
+22 -5
src/view/screens/CopyrightPolicy.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import { 9 8 type CommonNavigatorParams, 10 9 type NativeStackScreenProps, ··· 14 13 import {TextLink} from '#/view/com/util/Link' 15 14 import {Text} from '#/view/com/util/text/Text' 16 15 import {ScrollView} from '#/view/com/util/Views' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import * as Layout from '#/components/Layout' 18 19 import {ViewHeader} from '../com/util/ViewHeader' 19 20 20 21 type Props = NativeStackScreenProps<CommonNavigatorParams, 'CopyrightPolicy'> 21 22 export const CopyrightPolicyScreen = (_props: Props) => { 22 - const pal = usePalette('default') 23 + const theme = useTheme() 24 + const colorMode = useColorModeTheme() 23 25 const {_} = useLingui() 24 26 const setMinimalShellMode = useSetMinimalShellMode() 25 27 ··· 32 34 return ( 33 35 <Layout.Screen> 34 36 <ViewHeader title={_(msg`Copyright Policy`)} /> 35 - <ScrollView style={[s.hContentRegion, pal.view]}> 37 + <ScrollView 38 + style={[ 39 + s.hContentRegion, 40 + { 41 + backgroundColor: 42 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 43 + }, 44 + ]}> 36 45 <View style={[s.p20]}> 37 - <Text style={pal.text}> 46 + <Text 47 + style={{ 48 + color: 49 + colorMode === 'light' 50 + ? theme.palette.black 51 + : theme.palette.white, 52 + }}> 38 53 <Trans> 39 54 The Copyright Policy has been moved to{' '} 40 55 <TextLink 41 - style={pal.link} 56 + style={{ 57 + color: theme.palette.primary_500, 58 + }} 42 59 href="https://bsky.social/about/support/copyright" 43 60 text="bsky.social/about/support/copyright" 44 61 />
+110 -72
src/view/screens/Debug.tsx
··· 1 1 import React from 'react' 2 - import {ScrollView, View} from 'react-native' 2 + import {ScrollView, type TextStyle, View} from 'react-native' 3 3 import {msg} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 5 6 - import {usePalette} from '#/lib/hooks/usePalette' 7 6 import { 8 7 type CommonNavigatorParams, 9 8 type NativeStackScreenProps, 10 9 } from '#/lib/routes/types' 11 10 import {s} from '#/lib/styles' 12 - import {type PaletteColorName, ThemeProvider} from '#/lib/ThemeContext' 11 + import {ThemeProvider} from '#/lib/ThemeContext' 13 12 import {EmptyState} from '#/view/com/util/EmptyState' 14 13 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 15 14 import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' ··· 20 19 import * as Toast from '#/view/com/util/Toast' 21 20 import {ViewHeader} from '#/view/com/util/ViewHeader' 22 21 import {ViewSelector} from '#/view/com/util/ViewSelector' 22 + import {useTheme} from '#/alf' 23 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 23 24 import * as Layout from '#/components/Layout' 24 25 25 26 const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs'] ··· 54 55 onToggleColorScheme: () => void 55 56 }) { 56 57 const [currentView, setCurrentView] = React.useState<number>(0) 57 - const pal = usePalette('default') 58 + const theme = useTheme() 59 + const colorMode = useColorModeTheme() 58 60 const {_} = useLingui() 59 61 60 62 const renderItem = (item: any) => { ··· 84 86 const items = [{currentView}] 85 87 86 88 return ( 87 - <View style={[s.hContentRegion, pal.view]}> 89 + <View 90 + style={[ 91 + s.hContentRegion, 92 + { 93 + backgroundColor: 94 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 95 + }, 96 + ]}> 88 97 <ViewHeader title={_(msg`Debug panel`)} /> 89 98 <ViewSelector 90 99 swipeEnabled ··· 98 107 } 99 108 100 109 function Heading({label}: {label: string}) { 101 - const pal = usePalette('default') 110 + const theme = useTheme() 111 + const colorMode = useColorModeTheme() 112 + 102 113 return ( 103 114 <View style={[s.pt10, s.pb5]}> 104 - <Text type="title-lg" style={pal.text}> 115 + <Text 116 + type="title-lg" 117 + style={{ 118 + color: 119 + colorMode === 'light' ? theme.palette.black : theme.palette.white, 120 + }}> 105 121 {label} 106 122 </Text> 107 123 </View> ··· 114 130 <Heading label="Typography" /> 115 131 <TypographyView /> 116 132 <Heading label="Palettes" /> 117 - <PaletteView palette="default" /> 118 - <PaletteView palette="primary" /> 119 - <PaletteView palette="secondary" /> 120 - <PaletteView palette="inverted" /> 121 - <PaletteView palette="error" /> 133 + {/* <PaletteView /> */} 122 134 <Heading label="Empty state" /> 123 135 <EmptyStateView /> 124 136 <Heading label="Loading placeholders" /> ··· 197 209 </View> 198 210 ) 199 211 } 200 - 201 - function PaletteView({palette}: {palette: PaletteColorName}) { 202 - const defaultPal = usePalette('default') 203 - const pal = usePalette(palette) 204 - return ( 205 - <View style={[pal.view, pal.border, s.p10, s.mb5, s.border1]}> 206 - <Text style={[pal.text]}>{palette} colors</Text> 207 - <Text style={[pal.textLight]}>Light text</Text> 208 - <Text style={[pal.link]}>Link text</Text> 209 - {palette !== 'default' && ( 210 - <View style={[defaultPal.view]}> 211 - <Text style={[pal.textInverted]}>Inverted text</Text> 212 - </View> 213 - )} 214 - </View> 215 - ) 216 - } 212 + // TODO: provide some way to view all the colours in a given theme. 213 + // since the concept of a 'palette' is mostly deprecated, we need to rethink this debug screen. 214 + // function PaletteView() { 215 + // const defaultTheme = useTheme() 216 + // const currColorMode = useColorModeTheme() 217 + // const pal = usePalette(palette) 218 + // return ( 219 + // <View style={[pal.view, pal.border, s.p10, s.mb5, s.border1]}> 220 + // <Text style={[pal.text]}> {palette} colors </Text> 221 + // <Text style={[pal.textLight]}> Light text </Text> 222 + // <Text style={[pal.link]}> Link text </Text> 223 + // {palette !== 'default' && ( 224 + // <View 225 + // style={{ 226 + // backgroundColor: 227 + // currColorMode === 'light' 228 + // ? defaultTheme.palette.white 229 + // : defaultTheme.palette.black, 230 + // }}> 231 + // <Text style={[pal.textInverted]}> Inverted text </Text> 232 + // </View> 233 + // )} 234 + // </View> 235 + // ) 236 + // } 217 237 218 238 function TypographyView() { 219 - const pal = usePalette('default') 239 + const theme = useTheme() 240 + const colorMode = useColorModeTheme() 241 + const textStyle: TextStyle = { 242 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 243 + } 220 244 return ( 221 - <View style={[pal.view]}> 222 - <Text type="2xl-thin" style={[pal.text]}> 245 + <View 246 + style={{ 247 + backgroundColor: 248 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 249 + }}> 250 + <Text type="2xl-thin" style={textStyle}> 223 251 '2xl-thin' lorem ipsum dolor 224 252 </Text> 225 - <Text type="2xl" style={[pal.text]}> 253 + <Text type="2xl" style={textStyle}> 226 254 '2xl' lorem ipsum dolor 227 255 </Text> 228 - <Text type="2xl-medium" style={[pal.text]}> 256 + <Text type="2xl-medium" style={textStyle}> 229 257 '2xl-medium' lorem ipsum dolor 230 258 </Text> 231 - <Text type="2xl-bold" style={[pal.text]}> 259 + <Text type="2xl-bold" style={textStyle}> 232 260 '2xl-bold' lorem ipsum dolor 233 261 </Text> 234 - <Text type="2xl-heavy" style={[pal.text]}> 262 + <Text type="2xl-heavy" style={textStyle}> 235 263 '2xl-heavy' lorem ipsum dolor 236 264 </Text> 237 - <Text type="xl-thin" style={[pal.text]}> 265 + <Text type="xl-thin" style={textStyle}> 238 266 'xl-thin' lorem ipsum dolor 239 267 </Text> 240 - <Text type="xl" style={[pal.text]}> 268 + <Text type="xl" style={textStyle}> 241 269 'xl' lorem ipsum dolor 242 270 </Text> 243 - <Text type="xl-medium" style={[pal.text]}> 271 + <Text type="xl-medium" style={textStyle}> 244 272 'xl-medium' lorem ipsum dolor 245 273 </Text> 246 - <Text type="xl-bold" style={[pal.text]}> 274 + <Text type="xl-bold" style={textStyle}> 247 275 'xl-bold' lorem ipsum dolor 248 276 </Text> 249 - <Text type="xl-heavy" style={[pal.text]}> 277 + <Text type="xl-heavy" style={textStyle}> 250 278 'xl-heavy' lorem ipsum dolor 251 279 </Text> 252 - <Text type="lg-thin" style={[pal.text]}> 280 + <Text type="lg-thin" style={textStyle}> 253 281 'lg-thin' lorem ipsum dolor 254 282 </Text> 255 - <Text type="lg" style={[pal.text]}> 283 + <Text type="lg" style={textStyle}> 256 284 'lg' lorem ipsum dolor 257 285 </Text> 258 - <Text type="lg-medium" style={[pal.text]}> 286 + <Text type="lg-medium" style={textStyle}> 259 287 'lg-medium' lorem ipsum dolor 260 288 </Text> 261 - <Text type="lg-bold" style={[pal.text]}> 289 + <Text type="lg-bold" style={textStyle}> 262 290 'lg-bold' lorem ipsum dolor 263 291 </Text> 264 - <Text type="lg-heavy" style={[pal.text]}> 292 + <Text type="lg-heavy" style={textStyle}> 265 293 'lg-heavy' lorem ipsum dolor 266 294 </Text> 267 - <Text type="md-thin" style={[pal.text]}> 295 + <Text type="md-thin" style={textStyle}> 268 296 'md-thin' lorem ipsum dolor 269 297 </Text> 270 - <Text type="md" style={[pal.text]}> 298 + <Text type="md" style={textStyle}> 271 299 'md' lorem ipsum dolor 272 300 </Text> 273 - <Text type="md-medium" style={[pal.text]}> 301 + <Text type="md-medium" style={textStyle}> 274 302 'md-medium' lorem ipsum dolor 275 303 </Text> 276 - <Text type="md-bold" style={[pal.text]}> 304 + <Text type="md-bold" style={textStyle}> 277 305 'md-bold' lorem ipsum dolor 278 306 </Text> 279 - <Text type="md-heavy" style={[pal.text]}> 307 + <Text type="md-heavy" style={textStyle}> 280 308 'md-heavy' lorem ipsum dolor 281 309 </Text> 282 - <Text type="sm-thin" style={[pal.text]}> 310 + <Text type="sm-thin" style={textStyle}> 283 311 'sm-thin' lorem ipsum dolor 284 312 </Text> 285 - <Text type="sm" style={[pal.text]}> 313 + <Text type="sm" style={textStyle}> 286 314 'sm' lorem ipsum dolor 287 315 </Text> 288 - <Text type="sm-medium" style={[pal.text]}> 316 + <Text type="sm-medium" style={textStyle}> 289 317 'sm-medium' lorem ipsum dolor 290 318 </Text> 291 - <Text type="sm-bold" style={[pal.text]}> 319 + <Text type="sm-bold" style={textStyle}> 292 320 'sm-bold' lorem ipsum dolor 293 321 </Text> 294 - <Text type="sm-heavy" style={[pal.text]}> 322 + <Text type="sm-heavy" style={textStyle}> 295 323 'sm-heavy' lorem ipsum dolor 296 324 </Text> 297 - <Text type="xs-thin" style={[pal.text]}> 325 + <Text type="xs-thin" style={textStyle}> 298 326 'xs-thin' lorem ipsum dolor 299 327 </Text> 300 - <Text type="xs" style={[pal.text]}> 328 + <Text type="xs" style={textStyle}> 301 329 'xs' lorem ipsum dolor 302 330 </Text> 303 - <Text type="xs-medium" style={[pal.text]}> 331 + <Text type="xs-medium" style={textStyle}> 304 332 'xs-medium' lorem ipsum dolor 305 333 </Text> 306 - <Text type="xs-bold" style={[pal.text]}> 334 + <Text type="xs-bold" style={textStyle}> 307 335 'xs-bold' lorem ipsum dolor 308 336 </Text> 309 - <Text type="xs-heavy" style={[pal.text]}> 337 + <Text type="xs-heavy" style={textStyle}> 310 338 'xs-heavy' lorem ipsum dolor 311 339 </Text> 312 340 313 - <Text type="title-2xl" style={[pal.text]}> 341 + <Text type="title-2xl" style={textStyle}> 314 342 'title-2xl' lorem ipsum dolor 315 343 </Text> 316 - <Text type="title-xl" style={[pal.text]}> 344 + <Text type="title-xl" style={textStyle}> 317 345 'title-xl' lorem ipsum dolor 318 346 </Text> 319 - <Text type="title-lg" style={[pal.text]}> 347 + <Text type="title-lg" style={textStyle}> 320 348 'title-lg' lorem ipsum dolor 321 349 </Text> 322 - <Text type="title" style={[pal.text]}> 350 + <Text type="title" style={textStyle}> 323 351 'title' lorem ipsum dolor 324 352 </Text> 325 - <Text type="button" style={[pal.text]}> 353 + <Text type="button" style={textStyle}> 326 354 Button 327 355 </Text> 328 - <Text type="button-lg" style={[pal.text]}> 329 - Button-lg 356 + <Text type="button-lg" style={textStyle}> 357 + Button - lg 330 358 </Text> 331 359 </View> 332 360 ) ··· 346 374 } 347 375 348 376 function ButtonsView() { 349 - const defaultPal = usePalette('default') 377 + const theme = useTheme() 378 + const colorMode = useColorModeTheme() 350 379 const buttonStyles = {marginRight: 5} 351 380 return ( 352 - <View style={[defaultPal.view]}> 381 + <View 382 + style={{ 383 + backgroundColor: 384 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 385 + }}> 353 386 <View style={[s.flexRow, s.mb5]}> 354 387 <Button type="primary" label="Primary solid" style={buttonStyles} /> 355 388 <Button type="secondary" label="Secondary solid" style={buttonStyles} /> ··· 394 427 } 395 428 396 429 function ToggleButtonsView() { 397 - const defaultPal = usePalette('default') 430 + const theme = useTheme() 431 + const colorMode = useColorModeTheme() 398 432 const buttonStyles = s.mb5 399 433 const [isSelected, setIsSelected] = React.useState(false) 400 434 const onToggle = () => setIsSelected(!isSelected) 401 435 return ( 402 - <View style={[defaultPal.view]}> 436 + <View 437 + style={{ 438 + backgroundColor: 439 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 440 + }}> 403 441 <ToggleButton 404 442 type="primary" 405 443 label="Primary solid"
+19 -11
src/view/screens/Feeds.tsx
··· 7 7 import debounce from 'lodash.debounce' 8 8 9 9 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 10 - import {usePalette} from '#/lib/hooks/usePalette' 11 10 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 12 11 import {ComposeIcon2} from '#/lib/icons' 13 12 import { ··· 33 32 import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' 34 33 import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' 35 34 import {atoms as a, useTheme} from '#/alf' 35 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 36 36 import {ButtonIcon} from '#/components/Button' 37 37 import {Divider} from '#/components/Divider' 38 38 import * as FeedCard from '#/components/FeedCard' ··· 104 104 } 105 105 106 106 export function FeedsScreen(_props: Props) { 107 - const pal = usePalette('default') 107 + const theme = useTheme() 108 + const colorMode = useColorModeTheme() 108 109 const {openComposer} = useOpenComposer() 109 110 const {isMobile} = useWebMediaQueries() 110 111 const [query, setQuery] = React.useState('') ··· 423 424 return ( 424 425 <View 425 426 style={[ 426 - pal.border, 427 427 { 428 428 borderBottomWidth: 1, 429 + borderColor: theme.palette.contrast_100, 429 430 }, 430 431 ]}> 431 432 <NoSavedFeedsOfAnyType /> ··· 469 470 paddingTop: 10, 470 471 paddingBottom: '150%', 471 472 }}> 472 - <Text type="lg" style={pal.textLight}> 473 - <Trans>No results found for "{query}"</Trans> 473 + <Text 474 + type="lg" 475 + style={{ 476 + color: 477 + colorMode === 'dark' 478 + ? theme.palette.contrast_600 479 + : theme.palette.contrast_700, 480 + }}> 481 + <Trans>No results found for "{query}" </Trans> 474 482 </Text> 475 483 </View> 476 484 ) ··· 478 486 return ( 479 487 <View 480 488 style={[ 481 - pal.border, 482 489 { 483 490 borderBottomWidth: 1, 491 + borderColor: theme.palette.contrast_100, 484 492 }, 485 493 ]}> 486 494 <NoFollowingFeed /> ··· 490 498 return null 491 499 }, 492 500 [ 501 + colorMode, 502 + theme, 493 503 _, 494 - pal.border, 495 - pal.textLight, 496 504 query, 497 505 onChangeQuery, 498 506 onPressCancelSearch, ··· 508 516 <Layout.Header.BackButton /> 509 517 <Layout.Header.Content> 510 518 <Layout.Header.TitleText> 511 - <Trans>Feeds</Trans> 519 + <Trans>Feeds </Trans> 512 520 </Layout.Header.TitleText> 513 521 </Layout.Header.Content> 514 522 <Layout.Header.Slot> ··· 701 709 <IconCircle icon={ListSparkle_Stroke2_Corner0_Rounded} size="lg" /> 702 710 <View style={[a.flex_1, a.gap_xs]}> 703 711 <Text style={[a.flex_1, a.text_2xl, a.font_heavy, t.atoms.text]}> 704 - <Trans>My Feeds</Trans> 712 + <Trans>My Feeds </Trans> 705 713 </Text> 706 714 <Text style={[t.atoms.text_contrast_high]}> 707 715 <Trans>All the feeds you've saved, right in one place.</Trans> ··· 727 735 /> 728 736 <View style={[a.flex_1, a.gap_sm]}> 729 737 <Text style={[a.flex_1, a.text_2xl, a.font_heavy, t.atoms.text]}> 730 - <Trans>Discover New Feeds</Trans> 738 + <Trans>Discover New Feeds </Trans> 731 739 </Text> 732 740 <Text style={[t.atoms.text_contrast_high]}> 733 741 <Trans>
+27 -5
src/view/screens/NotFound.tsx
··· 8 8 useNavigation, 9 9 } from '@react-navigation/native' 10 10 11 - import {usePalette} from '#/lib/hooks/usePalette' 12 11 import {type NavigationProp} from '#/lib/routes/types' 13 12 import {s} from '#/lib/styles' 14 13 import {useSetMinimalShellMode} from '#/state/shell' 15 14 import {Button} from '#/view/com/util/forms/Button' 16 15 import {Text} from '#/view/com/util/text/Text' 17 16 import {ViewHeader} from '#/view/com/util/ViewHeader' 17 + import {useTheme} from '#/alf' 18 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 18 19 import * as Layout from '#/components/Layout' 19 20 20 21 export const NotFoundScreen = () => { 21 - const pal = usePalette('default') 22 + const theme = useTheme() 23 + const colorMode = useColorModeTheme() 22 24 const {_} = useLingui() 23 25 const navigation = useNavigation<NavigationProp>() 24 26 const setMinimalShellMode = useSetMinimalShellMode() ··· 43 45 <Layout.Screen testID="notFoundView"> 44 46 <ViewHeader title={_(msg`Page Not Found`)} /> 45 47 <View style={styles.container}> 46 - <Text type="title-2xl" style={[pal.text, s.mb10]}> 47 - <Trans>Page not found</Trans> 48 + <Text 49 + type="title-2xl" 50 + style={[ 51 + { 52 + color: 53 + colorMode === 'light' 54 + ? theme.palette.black 55 + : theme.palette.white, 56 + }, 57 + s.mb10, 58 + ]}> 59 + <Trans>Page not found </Trans> 48 60 </Text> 49 - <Text type="md" style={[pal.text, s.mb10]}> 61 + <Text 62 + type="md" 63 + style={[ 64 + { 65 + color: 66 + colorMode === 'light' 67 + ? theme.palette.black 68 + : theme.palette.white, 69 + }, 70 + s.mb10, 71 + ]}> 50 72 <Trans> 51 73 We're sorry! We can't find the page you were looking for. 52 74 </Trans>
+20 -5
src/view/screens/PrivacyPolicy.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import { 9 8 type CommonNavigatorParams, 10 9 type NativeStackScreenProps, ··· 14 13 import {TextLink} from '#/view/com/util/Link' 15 14 import {Text} from '#/view/com/util/text/Text' 16 15 import {ScrollView} from '#/view/com/util/Views' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import * as Layout from '#/components/Layout' 18 19 import {ViewHeader} from '../com/util/ViewHeader' 19 20 20 21 type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'> 21 22 export const PrivacyPolicyScreen = (_props: Props) => { 22 - const pal = usePalette('default') 23 + const theme = useTheme() 24 + const colorMode = useColorModeTheme() 23 25 const {_} = useLingui() 24 26 const setMinimalShellMode = useSetMinimalShellMode() 25 27 ··· 32 34 return ( 33 35 <Layout.Screen> 34 36 <ViewHeader title={_(msg`Privacy Policy`)} /> 35 - <ScrollView style={[s.hContentRegion, pal.view]}> 37 + <ScrollView 38 + style={[ 39 + s.hContentRegion, 40 + { 41 + backgroundColor: 42 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 43 + }, 44 + ]}> 36 45 <View style={[s.p20]}> 37 - <Text style={pal.text}> 46 + <Text 47 + style={{ 48 + color: 49 + colorMode === 'light' 50 + ? theme.palette.black 51 + : theme.palette.white, 52 + }}> 38 53 <Trans> 39 54 The Privacy Policy has been moved to{' '} 40 55 <TextLink 41 - style={pal.link} 56 + style={{color: theme.palette.primary_500}} 42 57 href="https://bsky.social/about/support/privacy-policy" 43 58 text="bsky.social/about/support/privacy-policy" 44 59 />
+29 -7
src/view/screens/Support.tsx
··· 4 4 import {useFocusEffect} from '@react-navigation/native' 5 5 6 6 import {HELP_DESK_URL} from '#/lib/constants' 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import { 9 8 type CommonNavigatorParams, 10 9 type NativeStackScreenProps, ··· 15 14 import {Text} from '#/view/com/util/text/Text' 16 15 import {ViewHeader} from '#/view/com/util/ViewHeader' 17 16 import {CenteredView} from '#/view/com/util/Views' 17 + import {useTheme} from '#/alf' 18 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 18 19 import * as Layout from '#/components/Layout' 19 20 20 21 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'> 21 22 export const SupportScreen = (_props: Props) => { 22 - const pal = usePalette('default') 23 + const theme = useTheme() 24 + const colorMode = useColorModeTheme() 23 25 const setMinimalShellMode = useSetMinimalShellMode() 24 26 const {_} = useLingui() 25 27 ··· 33 35 <Layout.Screen> 34 36 <ViewHeader title={_(msg`Support`)} /> 35 37 <CenteredView> 36 - <Text type="title-xl" style={[pal.text, s.p20, s.pb5]}> 37 - <Trans>Support</Trans> 38 + <Text 39 + type="title-xl" 40 + style={[ 41 + { 42 + color: 43 + colorMode === 'light' 44 + ? theme.palette.black 45 + : theme.palette.white, 46 + }, 47 + s.p20, 48 + s.pb5, 49 + ]}> 50 + <Trans>Support </Trans> 38 51 </Text> 39 - <Text style={[pal.text, s.p20]}> 52 + <Text 53 + style={[ 54 + { 55 + color: 56 + colorMode === 'light' 57 + ? theme.palette.black 58 + : theme.palette.white, 59 + }, 60 + s.p20, 61 + ]}> 40 62 <Trans> 41 - The support form has been moved. If you need help, please{' '} 63 + The support form has been moved.If you need help, please{' '} 42 64 <TextLink 43 65 href={HELP_DESK_URL} 44 66 text={_(msg`click here`)} 45 - style={pal.link} 67 + style={{color: theme.palette.primary_500}} 46 68 />{' '} 47 69 or visit {HELP_DESK_URL} to get in touch with us. 48 70 </Trans>
+21 -6
src/view/screens/TermsOfService.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useFocusEffect} from '@react-navigation/native' 6 6 7 - import {usePalette} from '#/lib/hooks/usePalette' 8 7 import { 9 8 type CommonNavigatorParams, 10 9 type NativeStackScreenProps, ··· 14 13 import {TextLink} from '#/view/com/util/Link' 15 14 import {Text} from '#/view/com/util/text/Text' 16 15 import {ScrollView} from '#/view/com/util/Views' 16 + import {useTheme} from '#/alf' 17 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 17 18 import * as Layout from '#/components/Layout' 18 19 import {ViewHeader} from '../com/util/ViewHeader' 19 20 20 21 type Props = NativeStackScreenProps<CommonNavigatorParams, 'TermsOfService'> 21 22 export const TermsOfServiceScreen = (_props: Props) => { 22 - const pal = usePalette('default') 23 + const theme = useTheme() 24 + const colorMode = useColorModeTheme() 23 25 const setMinimalShellMode = useSetMinimalShellMode() 24 26 const {_} = useLingui() 25 27 ··· 32 34 return ( 33 35 <Layout.Screen> 34 36 <ViewHeader title={_(msg`Terms of Service`)} /> 35 - <ScrollView style={[s.hContentRegion, pal.view]}> 37 + <ScrollView 38 + style={[ 39 + s.hContentRegion, 40 + { 41 + backgroundColor: 42 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 43 + }, 44 + ]}> 36 45 <View style={[s.p20]}> 37 - <Text style={pal.text}> 38 - <Trans>The Terms of Service have been moved to</Trans>{' '} 46 + <Text 47 + style={{ 48 + color: 49 + colorMode === 'light' 50 + ? theme.palette.black 51 + : theme.palette.white, 52 + }}> 53 + <Trans>The Terms of Service have been moved to </Trans>{' '} 39 54 <TextLink 40 - style={pal.link} 55 + style={{color: theme.palette.primary_500}} 41 56 href="https://bsky.social/about/support/tos" 42 57 text="bsky.social/about/support/tos" 43 58 />
+35 -20
src/view/shell/bottom-bar/BottomBar.tsx
··· 1 1 import {type JSX, useCallback} from 'react' 2 - import {type GestureResponderEvent, View} from 'react-native' 2 + import {type GestureResponderEvent, type TextStyle, View} from 'react-native' 3 3 import Animated from 'react-native-reanimated' 4 4 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 5 import {msg, plural, Trans} from '@lingui/macro' ··· 15 15 import {useHideBottomBarBorder} from '#/lib/hooks/useHideBottomBarBorder' 16 16 import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform' 17 17 import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState' 18 - import {usePalette} from '#/lib/hooks/usePalette' 19 18 import {clamp} from '#/lib/numbers' 20 19 import {getTabState, TabState} from '#/lib/routes/helpers' 21 20 import {useGate} from '#/lib/statsig/statsig' ··· 32 31 import {UserAvatar} from '#/view/com/util/UserAvatar' 33 32 import {Logo} from '#/view/icons/Logo' 34 33 import {Logotype} from '#/view/icons/Logotype' 35 - import {atoms as a} from '#/alf' 34 + import {atoms as a, useTheme} from '#/alf' 35 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 36 36 import {Button, ButtonText} from '#/components/Button' 37 37 import {useDialogControl} from '#/components/Dialog' 38 38 import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount' ··· 57 57 58 58 export function BottomBar({navigation}: BottomTabBarProps) { 59 59 const {hasSession, currentAccount} = useSession() 60 - const pal = usePalette('default') 60 + const theme = useTheme() 61 + const colorMode = useColorModeTheme() 61 62 const {_} = useLingui() 62 63 const safeAreaInsets = useSafeAreaInsets() 63 64 const {footerHeight} = useShellLayout() ··· 76 77 const gate = useGate() 77 78 const hideBorder = useHideBottomBarBorder() 78 79 const iconWidth = 28 80 + 81 + const textStyle: TextStyle = { 82 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 83 + } 79 84 80 85 const showSignIn = useCallback(() => { 81 86 closeAllActiveElements() ··· 147 152 <Animated.View 148 153 style={[ 149 154 styles.bottomBar, 150 - pal.view, 151 - hideBorder ? {borderColor: pal.view.backgroundColor} : pal.border, 155 + { 156 + backgroundColor: 157 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 158 + }, 159 + hideBorder 160 + ? { 161 + borderColor: 162 + colorMode === 'light' 163 + ? theme.palette.white 164 + : theme.palette.black, 165 + } 166 + : {borderColor: theme.palette.contrast_100}, 152 167 {paddingBottom: clamp(safeAreaInsets.bottom, 15, 60)}, 153 168 footerMinimalShellTransform, 154 169 ]} ··· 163 178 isAtHome ? ( 164 179 <HomeFilled 165 180 width={iconWidth + 1} 166 - style={[styles.ctrlIcon, pal.text, styles.homeIcon]} 181 + style={[styles.ctrlIcon, textStyle, styles.homeIcon]} 167 182 /> 168 183 ) : ( 169 184 <Home 170 185 width={iconWidth + 1} 171 - style={[styles.ctrlIcon, pal.text, styles.homeIcon]} 186 + style={[styles.ctrlIcon, textStyle, styles.homeIcon]} 172 187 /> 173 188 ) 174 189 } ··· 183 198 isAtSearch ? ( 184 199 <MagnifyingGlassFilled 185 200 width={iconWidth + 2} 186 - style={[styles.ctrlIcon, pal.text, styles.searchIcon]} 201 + style={[styles.ctrlIcon, textStyle, styles.searchIcon]} 187 202 /> 188 203 ) : ( 189 204 <MagnifyingGlass 190 205 testID="bottomBarSearchBtn" 191 206 width={iconWidth + 2} 192 - style={[styles.ctrlIcon, pal.text, styles.searchIcon]} 207 + style={[styles.ctrlIcon, textStyle, styles.searchIcon]} 193 208 /> 194 209 ) 195 210 } ··· 204 219 isAtMessages ? ( 205 220 <MessageFilled 206 221 width={iconWidth - 1} 207 - style={[styles.ctrlIcon, pal.text, styles.feedsIcon]} 222 + style={[styles.ctrlIcon, textStyle, styles.feedsIcon]} 208 223 /> 209 224 ) : ( 210 225 <Message 211 226 width={iconWidth - 1} 212 - style={[styles.ctrlIcon, pal.text, styles.feedsIcon]} 227 + style={[styles.ctrlIcon, textStyle, styles.feedsIcon]} 213 228 /> 214 229 ) 215 230 } ··· 236 251 isAtNotifications ? ( 237 252 <BellFilled 238 253 width={iconWidth} 239 - style={[styles.ctrlIcon, pal.text, styles.bellIcon]} 254 + style={[styles.ctrlIcon, textStyle, styles.bellIcon]} 240 255 /> 241 256 ) : ( 242 257 <Bell 243 258 width={iconWidth} 244 - style={[styles.ctrlIcon, pal.text, styles.bellIcon]} 259 + style={[styles.ctrlIcon, textStyle, styles.bellIcon]} 245 260 /> 246 261 ) 247 262 } ··· 269 284 <View 270 285 style={[ 271 286 styles.ctrlIcon, 272 - pal.text, 287 + textStyle, 273 288 styles.profileIcon, 274 289 styles.onProfile, 275 290 { 276 - borderColor: pal.text.color, 291 + borderColor: textStyle.color, 277 292 borderWidth: live ? 0 : 1, 278 293 }, 279 294 ]}> ··· 291 306 <View 292 307 style={[ 293 308 styles.ctrlIcon, 294 - pal.text, 309 + textStyle, 295 310 styles.profileIcon, 296 311 { 297 312 borderWidth: live ? 0 : 1, ··· 335 350 style={{flexDirection: 'row', alignItems: 'center', gap: 8}}> 336 351 <Logo width={28} /> 337 352 <View style={{paddingTop: 4}}> 338 - <Logotype width={80} fill={pal.text.color} /> 353 + <Logotype width={80} fill={textStyle.color} /> 339 354 </View> 340 355 </View> 341 356 ··· 347 362 variant="solid" 348 363 color="primary"> 349 364 <ButtonText> 350 - <Trans>Create account</Trans> 365 + <Trans>Create account </Trans> 351 366 </ButtonText> 352 367 </Button> 353 368 <Button ··· 357 372 variant="solid" 358 373 color="secondary"> 359 374 <ButtonText> 360 - <Trans>Sign in</Trans> 375 + <Trans>Sign in </Trans> 361 376 </ButtonText> 362 377 </Button> 363 378 </View>
+32 -22
src/view/shell/desktop/LeftNav.tsx
··· 1 1 import {type JSX, useCallback, useMemo, useState} from 'react' 2 - import {StyleSheet, View} from 'react-native' 2 + import {StyleSheet, type TextStyle, View} from 'react-native' 3 3 import {type AppBskyActorDefs} from '@atproto/api' 4 4 import {msg, plural, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' ··· 8 8 import {useActorStatus} from '#/lib/actor-status' 9 9 import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' 10 10 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 11 - import {usePalette} from '#/lib/hooks/usePalette' 12 11 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 13 12 import {getCurrentRoute, isTab} from '#/lib/routes/helpers' 14 13 import {makeProfileLink} from '#/lib/routes/links' ··· 33 32 import {UserAvatar} from '#/view/com/util/UserAvatar' 34 33 import {NavSignupCard} from '#/view/shell/NavSignupCard' 35 34 import {atoms as a, tokens, useLayoutBreakpoints, useTheme, web} from '#/alf' 35 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 36 36 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 37 37 import {type DialogControlProps} from '#/components/Dialog' 38 38 import {ArrowBoxLeft_Stroke2_Corner0_Rounded as LeaveIcon} from '#/components/icons/ArrowBoxLeft' ··· 585 585 } 586 586 587 587 function ChatNavItem() { 588 - const pal = usePalette('default') 588 + const theme = useTheme() 589 + const colorMode = useColorModeTheme() 589 590 const {_} = useLingui() 590 591 const numUnreadMessages = useUnreadMessageCount() 592 + 593 + const textStyle: TextStyle = { 594 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 595 + } 591 596 592 597 return ( 593 598 <NavItem ··· 595 600 count={numUnreadMessages.numUnread} 596 601 hasNew={numUnreadMessages.hasNew} 597 602 icon={ 598 - <Message style={pal.text} aria-hidden={true} width={NAV_ICON_WIDTH} /> 603 + <Message style={textStyle} aria-hidden={true} width={NAV_ICON_WIDTH} /> 599 604 } 600 605 iconFilled={ 601 606 <MessageFilled 602 - style={pal.text} 607 + style={textStyle} 603 608 aria-hidden={true} 604 609 width={NAV_ICON_WIDTH} 605 610 /> ··· 611 616 612 617 export function DesktopLeftNav() { 613 618 const {hasSession, currentAccount} = useSession() 614 - const pal = usePalette('default') 619 + const theme = useTheme() 620 + const colorMode = useColorModeTheme() 615 621 const {_} = useLingui() 616 622 const {isDesktop} = useWebMediaQueries() 617 623 const {leftNavMinimal, centerColumnOffset} = useLayoutBreakpoints() 618 624 const numUnreadNotifications = useUnreadNotifications() 619 625 const hasHomeBadge = useHomeBadge() 620 626 const gate = useGate() 627 + 628 + const textStyle: TextStyle = { 629 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 630 + } 621 631 622 632 if (!hasSession && !isDesktop) { 623 633 return null ··· 658 668 <Home 659 669 aria-hidden={true} 660 670 width={NAV_ICON_WIDTH} 661 - style={pal.text} 671 + style={textStyle} 662 672 /> 663 673 } 664 674 iconFilled={ 665 675 <HomeFilled 666 676 aria-hidden={true} 667 677 width={NAV_ICON_WIDTH} 668 - style={pal.text} 678 + style={textStyle} 669 679 /> 670 680 } 671 681 label={_(msg`Home`)} ··· 674 684 href="/search" 675 685 icon={ 676 686 <MagnifyingGlass 677 - style={pal.text} 687 + style={textStyle} 678 688 aria-hidden={true} 679 689 width={NAV_ICON_WIDTH} 680 690 /> 681 691 } 682 692 iconFilled={ 683 693 <MagnifyingGlassFilled 684 - style={pal.text} 694 + style={textStyle} 685 695 aria-hidden={true} 686 696 width={NAV_ICON_WIDTH} 687 697 /> ··· 695 705 <Bell 696 706 aria-hidden={true} 697 707 width={NAV_ICON_WIDTH} 698 - style={pal.text} 708 + style={textStyle} 699 709 /> 700 710 } 701 711 iconFilled={ 702 712 <BellFilled 703 713 aria-hidden={true} 704 714 width={NAV_ICON_WIDTH} 705 - style={pal.text} 715 + style={textStyle} 706 716 /> 707 717 } 708 718 label={_(msg`Notifications`)} ··· 712 722 href="/feeds" 713 723 icon={ 714 724 <Hashtag 715 - style={pal.text} 725 + style={textStyle} 716 726 aria-hidden={true} 717 727 width={NAV_ICON_WIDTH} 718 728 /> 719 729 } 720 730 iconFilled={ 721 731 <HashtagFilled 722 - style={pal.text} 732 + style={textStyle} 723 733 aria-hidden={true} 724 734 width={NAV_ICON_WIDTH} 725 735 /> ··· 730 740 href="/lists" 731 741 icon={ 732 742 <List 733 - style={pal.text} 743 + style={textStyle} 734 744 aria-hidden={true} 735 745 width={NAV_ICON_WIDTH} 736 746 /> 737 747 } 738 748 iconFilled={ 739 749 <ListFilled 740 - style={pal.text} 750 + style={textStyle} 741 751 aria-hidden={true} 742 752 width={NAV_ICON_WIDTH} 743 753 /> ··· 748 758 href="/saved" 749 759 icon={ 750 760 <Bookmark 751 - style={pal.text} 761 + style={textStyle} 752 762 aria-hidden={true} 753 763 width={NAV_ICON_WIDTH} 754 764 /> 755 765 } 756 766 iconFilled={ 757 767 <BookmarkFilled 758 - style={pal.text} 768 + style={textStyle} 759 769 aria-hidden={true} 760 770 width={NAV_ICON_WIDTH} 761 771 /> ··· 773 783 <UserCircle 774 784 aria-hidden={true} 775 785 width={NAV_ICON_WIDTH} 776 - style={pal.text} 786 + style={textStyle} 777 787 /> 778 788 } 779 789 iconFilled={ 780 790 <UserCircleFilled 781 791 aria-hidden={true} 782 792 width={NAV_ICON_WIDTH} 783 - style={pal.text} 793 + style={textStyle} 784 794 /> 785 795 } 786 796 label={_(msg`Profile`)} ··· 791 801 <Settings 792 802 aria-hidden={true} 793 803 width={NAV_ICON_WIDTH} 794 - style={pal.text} 804 + style={textStyle} 795 805 /> 796 806 } 797 807 iconFilled={ 798 808 <SettingsFilled 799 809 aria-hidden={true} 800 810 width={NAV_ICON_WIDTH} 801 - style={pal.text} 811 + style={textStyle} 802 812 /> 803 813 } 804 814 label={_(msg`Settings`)}
+34 -11
src/view/shell/desktop/Search.tsx
··· 2 2 import { 3 3 ActivityIndicator, 4 4 StyleSheet, 5 + type TextStyle, 5 6 TouchableOpacity, 6 7 View, 7 8 type ViewStyle, ··· 10 11 import {useLingui} from '@lingui/react' 11 12 import {StackActions, useNavigation} from '@react-navigation/native' 12 13 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 14 import {type NavigationProp} from '#/lib/routes/types' 15 15 import {useModerationOpts} from '#/state/preferences/moderation-opts' 16 16 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 17 17 import {Link} from '#/view/com/util/Link' 18 18 import {Text} from '#/view/com/util/text/Text' 19 19 import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard' 20 - import {atoms as a} from '#/alf' 20 + import {atoms as a, useTheme} from '#/alf' 21 + import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 21 22 import {SearchInput} from '#/components/forms/SearchInput' 22 23 23 24 let SearchLinkCard = ({ ··· 31 32 onPress?: () => void 32 33 style?: ViewStyle 33 34 }): React.ReactNode => { 34 - const pal = usePalette('default') 35 + const theme = useTheme() 36 + const colorMode = useColorModeTheme() 37 + 38 + const textStyle: TextStyle = { 39 + color: colorMode === 'light' ? theme.palette.black : theme.palette.white, 40 + } 35 41 36 42 const inner = ( 37 43 <View 38 - style={[pal.border, {paddingVertical: 16, paddingHorizontal: 12}, style]}> 39 - <Text type="md" style={[pal.text]}> 44 + style={[ 45 + {borderColor: theme.palette.contrast_100}, 46 + {paddingVertical: 16, paddingHorizontal: 12}, 47 + style, 48 + ]}> 49 + <Text type="md" style={[textStyle]}> 40 50 {label} 41 51 </Text> 42 52 </View> ··· 57 67 <Link href={to} asAnchor anchorNoUnderline> 58 68 <View 59 69 style={[ 60 - pal.border, 70 + {borderColor: theme.palette.contrast_100}, 61 71 {paddingVertical: 16, paddingHorizontal: 12}, 62 72 style, 63 73 ]}> 64 - <Text type="md" style={[pal.text]}> 74 + <Text type="md" style={[textStyle]}> 65 75 {label} 66 76 </Text> 67 77 </View> ··· 73 83 74 84 export function DesktopSearch() { 75 85 const {_} = useLingui() 76 - const pal = usePalette('default') 86 + const theme = useTheme() 87 + const colorMode = useColorModeTheme() 77 88 const navigation = useNavigation<NavigationProp>() 78 89 const [isActive, setIsActive] = React.useState<boolean>(false) 79 90 const [query, setQuery] = React.useState<string>('') ··· 106 117 }, []) 107 118 108 119 return ( 109 - <View style={[styles.container, pal.view]}> 120 + <View 121 + style={[ 122 + styles.container, 123 + { 124 + backgroundColor: 125 + colorMode === 'light' ? theme.palette.white : theme.palette.black, 126 + }, 127 + ]}> 110 128 <SearchInput 111 129 value={query} 112 130 onChangeText={onChangeText} ··· 116 134 {query !== '' && isActive && moderationOpts && ( 117 135 <View 118 136 style={[ 119 - pal.view, 120 - pal.borderDark, 137 + { 138 + backgroundColor: 139 + colorMode === 'light' 140 + ? theme.palette.white 141 + : theme.palette.black, 142 + borderColor: theme.palette.contrast_200, 143 + }, 121 144 styles.resultsContainer, 122 145 a.overflow_hidden, 123 146 ]}>