diff --git a/packages/components/src/components/AppGlobalStyles.web.tsx b/packages/components/src/components/AppGlobalStyles.web.tsx index 03318157..93406fc1 100644 --- a/packages/components/src/components/AppGlobalStyles.web.tsx +++ b/packages/components/src/components/AppGlobalStyles.web.tsx @@ -4,10 +4,24 @@ import { Theme } from '@devhub/core/src/types' import { useTheme } from './context/ThemeContext' function getStyles(params: { theme: Theme }) { + const t = params.theme return ` ::-webkit-scrollbar-thumb { - background-color: ${params.theme.backgroundColorDarker08}; + background-color:${t.backgroundColorDarker08}; + } + + body { + --theme_backgroundColor:${t.backgroundColor}; + --theme_backgroundColorDarker08:${t.backgroundColorDarker08}; + --theme_backgroundColorLess08:${t.backgroundColorLess08}; + --theme_backgroundColorLighther08:${t.backgroundColorLighther08}; + --theme_backgroundColorMore08:${t.backgroundColorMore08}; + --theme_backgroundColorTransparent10:${t.backgroundColorTransparent10}; + --theme_foregroundColor:${t.foregroundColor}; + --theme_foregroundColorMuted50:${t.foregroundColorMuted50}; + --theme_foregroundColorTransparent50:${t.foregroundColorTransparent50}; + --theme_foregroundColorTransparent80:${t.foregroundColorTransparent80}; } ` } diff --git a/packages/components/src/components/animated/AnimatedLink.tsx b/packages/components/src/components/animated/AnimatedLink.tsx index f30bc5b1..01e1405a 100644 --- a/packages/components/src/components/animated/AnimatedLink.tsx +++ b/packages/components/src/components/animated/AnimatedLink.tsx @@ -7,4 +7,6 @@ export interface AnimatedLinkProps extends Omit { style: any } -export const AnimatedLink = (props: AnimatedLinkProps) => +export const AnimatedLink = (props: AnimatedLinkProps) => ( + +) diff --git a/packages/components/src/components/common/Link.tsx b/packages/components/src/components/common/Link.tsx index 77d3e738..3b0e60fa 100644 --- a/packages/components/src/components/common/Link.tsx +++ b/packages/components/src/components/common/Link.tsx @@ -1,11 +1,9 @@ import React, { AnchorHTMLAttributes } from 'react' import { Animated, - StyleProp, TouchableOpacity, TouchableOpacityProps, View, - ViewStyle, } from 'react-native' import { Browser } from '../../libs/browser' diff --git a/packages/components/src/components/common/Screen.tsx b/packages/components/src/components/common/Screen.tsx index 12784536..a663c303 100644 --- a/packages/components/src/components/common/Screen.tsx +++ b/packages/components/src/components/common/Screen.tsx @@ -6,6 +6,7 @@ import SplashScreen from 'react-native-splash-screen' import { AnimatedSafeAreaView } from '../../components/animated/AnimatedSafeAreaView' import { AnimatedStatusBar } from '../../components/animated/AnimatedStatusBar' import { useAnimatedTheme } from '../../hooks/use-animated-theme' +import { useTheme } from '../context/ThemeContext' let isSplashScreenVisible = true @@ -24,7 +25,8 @@ const styles = StyleSheet.create({ }) export function Screen(props: ScreenProps) { - const theme = useAnimatedTheme() + const theme = useTheme() + const animatedTheme = useAnimatedTheme() useEffect(() => { if (isSplashScreenVisible && SplashScreen) { @@ -42,7 +44,9 @@ export function Screen(props: ScreenProps) { <> diff --git a/packages/components/src/components/common/TransparentTextOverlay.tsx b/packages/components/src/components/common/TransparentTextOverlay.tsx index 8d7788a8..bec94169 100644 --- a/packages/components/src/components/common/TransparentTextOverlay.tsx +++ b/packages/components/src/components/common/TransparentTextOverlay.tsx @@ -3,6 +3,7 @@ import React, { ReactNode } from 'react' import { StyleProp, View, ViewStyle } from 'react-native' import { LinearGradient } from '../../libs/linear-gradient' +import { computeThemeColor } from '../../utils/helpers/colors' export type From = 'top' | 'bottom' | 'left' | 'right' export type FromWithVH = 'vertical' | 'horizontal' | From @@ -88,7 +89,11 @@ function getProps(from: From, size: number) { function GradientLayerOverlay( props: TransparentTextOverlayProps & { from: From }, ) { - const { color, from, radius, size, style, ...otherProps } = props + const { color: _color, from, radius, size, style, ...otherProps } = props + + const color = computeThemeColor(_color) + if (!color) return null + return ( - + {theme.displayName} diff --git a/packages/components/src/hooks/use-animated-theme.shared.ts b/packages/components/src/hooks/use-animated-theme.shared.ts new file mode 100644 index 00000000..10b6c704 --- /dev/null +++ b/packages/components/src/hooks/use-animated-theme.shared.ts @@ -0,0 +1,87 @@ +import _ from 'lodash' +import { useEffect, useRef, useState } from 'react' +import { Animated, Easing } from 'react-native' + +import { useReduxStore } from '../redux/context/ReduxStoreContext' +import { themeSelector } from '../redux/selectors' + +export function useAnimatedTheme() { + const store = useReduxStore() + + const themeRef = useRef(themeSelector(store.getState())) + const animatedValueRef = useRef(new Animated.Value(0)) + + const [animatedTheme, setAnimatedTheme] = useState(() => { + const getInterpolate = (value: string) => + animatedValueRef.current.interpolate({ + inputRange: [0, 0], + outputRange: [value, value], + }) + + return { + backgroundColor: getInterpolate(themeRef.current.backgroundColor), + backgroundColorDarker08: getInterpolate( + themeRef.current.backgroundColorDarker08, + ), + backgroundColorLess08: getInterpolate( + themeRef.current.backgroundColorLess08, + ), + backgroundColorLighther08: getInterpolate( + themeRef.current.backgroundColorLighther08, + ), + backgroundColorMore08: getInterpolate( + themeRef.current.backgroundColorMore08, + ), + backgroundColorTransparent10: getInterpolate( + themeRef.current.backgroundColorTransparent10, + ), + foregroundColor: getInterpolate(themeRef.current.foregroundColor), + foregroundColorMuted50: getInterpolate( + themeRef.current.foregroundColorMuted50, + ), + foregroundColorTransparent50: getInterpolate( + themeRef.current.foregroundColorTransparent50, + ), + foregroundColorTransparent80: getInterpolate( + themeRef.current.foregroundColorTransparent80, + ), + } + }) + + useEffect( + () => { + return store.subscribe(() => { + const newTheme = themeSelector(store.getState()) + if (newTheme === themeRef.current) return + + animatedValueRef.current.setValue(0) + + const keys = Object.keys(animatedTheme) as Array< + keyof typeof animatedTheme + > + keys.forEach(key => { + const currentValue = themeRef.current[key] + const newValue = newTheme[key] + + animatedTheme[key] = animatedValueRef.current.interpolate({ + inputRange: [0, 1], + outputRange: [currentValue, newValue], + }) + }) + + themeRef.current = newTheme + + Animated.timing(animatedValueRef.current, { + easing: Easing.linear, + toValue: 1, + duration: 150, + }).start() + + setAnimatedTheme({ ...animatedTheme }) + }) + }, + [store, animatedTheme], + ) + + return animatedTheme +} diff --git a/packages/components/src/hooks/use-animated-theme.ts b/packages/components/src/hooks/use-animated-theme.ts index 47912b3b..543c6a32 100644 --- a/packages/components/src/hooks/use-animated-theme.ts +++ b/packages/components/src/hooks/use-animated-theme.ts @@ -1,103 +1 @@ -import _ from 'lodash' -import { useEffect, useRef, useState } from 'react' -import { Animated, Easing } from 'react-native' - -import { useReduxStore } from '../redux/context/ReduxStoreContext' -import { themeSelector } from '../redux/selectors' - -export function useAnimatedTheme() { - const store = useReduxStore() - - const themeRef = useRef(themeSelector(store.getState())) - const animatedValueRef = useRef(new Animated.Value(0)) - - const [animatedTheme, setAnimatedTheme] = useState(() => { - const getInterpolate = (value: string) => - animatedValueRef.current.interpolate({ - inputRange: [0, 0], - outputRange: [value, value], - }) - - return { - id: themeRef.current.id, - displayName: themeRef.current.displayName, - isDark: themeRef.current.isDark, - invert: themeRef.current.invert, - backgroundColor: getInterpolate(themeRef.current.backgroundColor), - backgroundColorDarker08: getInterpolate( - themeRef.current.backgroundColorDarker08, - ), - backgroundColorLess08: getInterpolate( - themeRef.current.backgroundColorLess08, - ), - backgroundColorLighther08: getInterpolate( - themeRef.current.backgroundColorLighther08, - ), - backgroundColorMore08: getInterpolate( - themeRef.current.backgroundColorMore08, - ), - backgroundColorTransparent10: getInterpolate( - themeRef.current.backgroundColorTransparent10, - ), - foregroundColor: getInterpolate(themeRef.current.foregroundColor), - foregroundColorMuted50: getInterpolate( - themeRef.current.foregroundColorMuted50, - ), - foregroundColorTransparent50: getInterpolate( - themeRef.current.foregroundColorTransparent50, - ), - foregroundColorTransparent80: getInterpolate( - themeRef.current.foregroundColorTransparent80, - ), - } - }) - - useEffect( - () => { - return store.subscribe(() => { - const newTheme = themeSelector(store.getState()) - if (newTheme === themeRef.current) return - - animatedValueRef.current.setValue(0) - - const keys = Object.keys(animatedTheme) as Array< - keyof typeof animatedTheme - > - keys.forEach(key => { - const currentValue = themeRef.current[key] - const newValue = newTheme[key] - - if ( - key.toLowerCase().includes('color') && - currentValue && - typeof currentValue === 'string' && - newValue && - typeof newValue === 'string' - ) { - if (animatedTheme[key] && typeof animatedTheme[key] === 'object') { - animatedTheme[key] = animatedValueRef.current.interpolate({ - inputRange: [0, 1], - outputRange: [currentValue, newValue], - }) - } - } else { - animatedTheme[key] = newValue - } - }) - - themeRef.current = newTheme - - Animated.timing(animatedValueRef.current, { - easing: Easing.linear, - toValue: 1, - duration: 250, - }).start() - - setAnimatedTheme({ ...animatedTheme }) - }) - }, - [store, animatedTheme], - ) - - return animatedTheme -} +export { useAnimatedTheme } from './use-animated-theme.shared' diff --git a/packages/components/src/hooks/use-animated-theme.web.ts b/packages/components/src/hooks/use-animated-theme.web.ts new file mode 100644 index 00000000..ad13d835 --- /dev/null +++ b/packages/components/src/hooks/use-animated-theme.web.ts @@ -0,0 +1,32 @@ +import _ from 'lodash' + +import { Platform } from '../libs/platform' + +const cssVariablesTheme = { + backgroundColor: 'var(--theme_backgroundColor)', + backgroundColorDarker08: 'var(--theme_backgroundColorDarker08)', + backgroundColorLess08: 'var(--theme_backgroundColorLess08)', + backgroundColorLighther08: 'var(--theme_backgroundColorLighther08)', + backgroundColorMore08: 'var(--theme_backgroundColorMore08)', + backgroundColorTransparent10: 'var(--theme_backgroundColorTransparent10)', + foregroundColor: 'var(--theme_foregroundColor)', + foregroundColorMuted50: 'var(--theme_foregroundColorMuted50)', + foregroundColorTransparent50: 'var(--theme_foregroundColorTransparent50)', + foregroundColorTransparent80: 'var(--theme_foregroundColorTransparent80)', +} + +function useCSSVariableTheme() { + return cssVariablesTheme +} + +const _window = typeof window !== 'undefined' ? (window as any) : undefined +const supportsCSSVariables = + Platform.OS === 'web' && + _window && + _window.CSS && + _window.CSS.supports && + _window.CSS.supports('--fake-var', 0) + +export const useAnimatedTheme = (supportsCSSVariables + ? () => useCSSVariableTheme + : () => require('./use-animated-theme.shared').useAnimatedTheme)() // tslint:disable-line diff --git a/packages/components/src/utils/helpers/colors.ts b/packages/components/src/utils/helpers/colors.ts new file mode 100644 index 00000000..4d68dff1 --- /dev/null +++ b/packages/components/src/utils/helpers/colors.ts @@ -0,0 +1,11 @@ +import { Platform } from '../../libs/platform' + +export function computeThemeColor(color: string) { + return Platform.OS === 'web' && color && color.includes('var(--') + ? typeof getComputedStyle === 'function' + ? getComputedStyle(document.body) + .getPropertyValue(color.replace(/var\((.+)\)$/, '$1')) + .trim() + : undefined + : color +} diff --git a/packages/web/src/index.css b/packages/web/src/index.css index 4a72d559..4f85b871 100644 --- a/packages/web/src/index.css +++ b/packages/web/src/index.css @@ -1,3 +1,9 @@ +* { + transition: all 150ms linear !important; + box-sizing: border-box; + cursor: default; +} + ::-webkit-scrollbar { width: 2px; height: 2px;