|
| 1 | +import React, { memo, useMemo } from 'react'; |
| 2 | +import { LinearGradient } from 'expo-linear-gradient'; |
| 3 | +import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native'; |
| 4 | +import { Text, useColorMode, type TextProps } from '@/design-system'; |
| 5 | +import { GradientText } from '@/components/text'; |
| 6 | +import { GradientBorderView } from '@/components/gradient-border/GradientBorderView'; |
| 7 | +import { THICK_BORDER_WIDTH } from '@/styles/constants'; |
| 8 | +import { InnerShadow } from '@/features/polymarket/components/InnerShadow'; |
| 9 | +import { opacity } from '@/framework/ui/utils/opacity'; |
| 10 | +import { getValueForColorMode } from '@/design-system/color/palettes'; |
| 11 | + |
| 12 | +type ShadowStyle = Pick<ViewStyle, 'shadowColor' | 'shadowOffset' | 'shadowOpacity' | 'shadowRadius'>; |
| 13 | + |
| 14 | +export const RNBW_BUTTON_CONFIG = { |
| 15 | + gradient: { |
| 16 | + start: { x: 0, y: 0 }, |
| 17 | + end: { x: 0, y: 1 }, |
| 18 | + }, |
| 19 | + primary: { |
| 20 | + colors: ['#FFE380', '#E3A700'], |
| 21 | + border: { |
| 22 | + light: [opacity('#B5910D', 0.1125), opacity('#B5910D', 0.15)], |
| 23 | + dark: [opacity('#B5910D', 0.1125), opacity('#B5910D', 0.15)], |
| 24 | + }, |
| 25 | + text: { |
| 26 | + colors: ['#4F3605', '#90630E'], |
| 27 | + start: { x: 0, y: 0 }, |
| 28 | + end: { x: 0, y: 1 }, |
| 29 | + shadow: { |
| 30 | + textShadowOffset: { width: 1, height: 1 }, |
| 31 | + textShadowRadius: 0, |
| 32 | + textShadowColor: 'rgba(255, 255, 255, 0.26)', |
| 33 | + }, |
| 34 | + }, |
| 35 | + shadows: { |
| 36 | + light: [ |
| 37 | + { shadowColor: '#8A6216', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.04, shadowRadius: 10 }, |
| 38 | + { shadowColor: '#000000', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 2.5 }, |
| 39 | + ] as ShadowStyle[], |
| 40 | + dark: [{ shadowColor: '#FFDD20', shadowOffset: { width: 0, height: 0 }, shadowOpacity: 0.3, shadowRadius: 15 }] as ShadowStyle[], |
| 41 | + }, |
| 42 | + }, |
| 43 | + secondary: { |
| 44 | + colors: { |
| 45 | + light: [opacity('#F8DE7D', 0.4), opacity('#D9B550', 0.4)], |
| 46 | + dark: [opacity('#FFE380', 0.1), opacity('#E3A700', 0.1)], |
| 47 | + }, |
| 48 | + border: { |
| 49 | + light: [opacity('#B5910D', 0.08), opacity('#B5910D', 0.08)], |
| 50 | + dark: [opacity('#B5910D', 0.049), opacity('#B5910D', 0.07)], |
| 51 | + }, |
| 52 | + text: { |
| 53 | + color: { light: '#6F4D0A', dark: '#FAD96B' }, |
| 54 | + }, |
| 55 | + shadows: { |
| 56 | + light: [ |
| 57 | + { shadowColor: '#8A6216', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.04, shadowRadius: 10 }, |
| 58 | + { shadowColor: '#000000', shadowOffset: { width: 0, height: 3 }, shadowOpacity: 0.08, shadowRadius: 2.5 }, |
| 59 | + ] as ShadowStyle[], |
| 60 | + dark: [{ shadowColor: '#F8DE7D', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.04, shadowRadius: 10 }] as ShadowStyle[], |
| 61 | + }, |
| 62 | + }, |
| 63 | +} as const; |
| 64 | + |
| 65 | +type RnbwButtonSurfaceProps = { |
| 66 | + variant?: 'primary' | 'secondary'; |
| 67 | + height?: number; |
| 68 | + children: React.ReactNode; |
| 69 | + style?: StyleProp<ViewStyle>; |
| 70 | +}; |
| 71 | + |
| 72 | +export const RnbwButtonSurface = memo(function RnbwButtonSurface({ |
| 73 | + variant = 'primary', |
| 74 | + height = 42, |
| 75 | + children, |
| 76 | + style, |
| 77 | +}: RnbwButtonSurfaceProps) { |
| 78 | + const { isDarkMode, colorMode } = useColorMode(); |
| 79 | + const borderRadius = height / 2; |
| 80 | + |
| 81 | + const { borderGradientColors, gradientColors, shadows } = useMemo( |
| 82 | + () => ({ |
| 83 | + borderGradientColors: getValueForColorMode(RNBW_BUTTON_CONFIG[variant].border, colorMode), |
| 84 | + gradientColors: getValueForColorMode(RNBW_BUTTON_CONFIG[variant].colors, colorMode), |
| 85 | + shadows: getValueForColorMode(RNBW_BUTTON_CONFIG[variant].shadows, colorMode), |
| 86 | + }), |
| 87 | + [variant, colorMode] |
| 88 | + ); |
| 89 | + |
| 90 | + const resolvedContainerStyle = useMemo( |
| 91 | + () => |
| 92 | + [ |
| 93 | + { |
| 94 | + height, |
| 95 | + borderRadius, |
| 96 | + justifyContent: 'center', |
| 97 | + alignItems: 'center', |
| 98 | + overflow: 'visible', |
| 99 | + }, |
| 100 | + shadows, |
| 101 | + style, |
| 102 | + ] as StyleProp<ViewStyle>, |
| 103 | + [height, borderRadius, style, shadows] |
| 104 | + ); |
| 105 | + |
| 106 | + return ( |
| 107 | + <GradientBorderView |
| 108 | + borderWidth={isDarkMode ? THICK_BORDER_WIDTH : 1} |
| 109 | + borderGradientColors={borderGradientColors} |
| 110 | + start={RNBW_BUTTON_CONFIG.gradient.start} |
| 111 | + end={RNBW_BUTTON_CONFIG.gradient.end} |
| 112 | + style={resolvedContainerStyle} |
| 113 | + > |
| 114 | + <LinearGradient |
| 115 | + colors={gradientColors} |
| 116 | + start={RNBW_BUTTON_CONFIG.gradient.start} |
| 117 | + end={RNBW_BUTTON_CONFIG.gradient.end} |
| 118 | + style={[StyleSheet.absoluteFill, { borderRadius }]} |
| 119 | + /> |
| 120 | + {variant === 'primary' && ( |
| 121 | + <LinearGradient |
| 122 | + colors={[opacity('#FFE67E', 0), opacity('#FFE67E', 0.5), opacity('#FFE67E', 0)]} |
| 123 | + start={{ x: 0.25, y: 0.5 }} |
| 124 | + end={{ x: 0.75, y: 0.5 }} |
| 125 | + style={StyleSheet.absoluteFill} |
| 126 | + /> |
| 127 | + )} |
| 128 | + <InnerShadow color={'rgba(255, 255, 255, 0.1)'} blur={1} dx={0} dy={3} borderRadius={borderRadius} /> |
| 129 | + {children} |
| 130 | + </GradientBorderView> |
| 131 | + ); |
| 132 | +}); |
| 133 | + |
| 134 | +export const RnbwButtonText = memo(function RnbwButtonText({ |
| 135 | + variant = 'primary', |
| 136 | + size = '20pt', |
| 137 | + weight = 'heavy', |
| 138 | + children, |
| 139 | +}: { |
| 140 | + variant?: 'primary' | 'secondary'; |
| 141 | + size?: TextProps['size']; |
| 142 | + weight?: TextProps['weight']; |
| 143 | + children: string; |
| 144 | +}) { |
| 145 | + const { colorMode } = useColorMode(); |
| 146 | + |
| 147 | + if (variant === 'primary') { |
| 148 | + return ( |
| 149 | + <GradientText |
| 150 | + colors={RNBW_BUTTON_CONFIG.primary.text.colors} |
| 151 | + start={RNBW_BUTTON_CONFIG.primary.text.start} |
| 152 | + end={RNBW_BUTTON_CONFIG.primary.text.end} |
| 153 | + shadow={RNBW_BUTTON_CONFIG.primary.text.shadow} |
| 154 | + > |
| 155 | + <Text size={size} weight={weight} color="label"> |
| 156 | + {children} |
| 157 | + </Text> |
| 158 | + </GradientText> |
| 159 | + ); |
| 160 | + } |
| 161 | + |
| 162 | + return ( |
| 163 | + <Text size={size} weight={weight} color={{ custom: getValueForColorMode(RNBW_BUTTON_CONFIG.secondary.text.color, colorMode) }}> |
| 164 | + {children} |
| 165 | + </Text> |
| 166 | + ); |
| 167 | +}); |
0 commit comments