feat: Implement colored blur backgrounds
This commit is contained in:
@@ -2,7 +2,9 @@ import { BlurView, BlurViewProperties } from '@react-native-community/blur';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { ColorSchemeName, StyleSheet, useColorScheme } from 'react-native';
|
||||
import { ColorSchemeName, Platform, StyleSheet, useColorScheme } from 'react-native';
|
||||
|
||||
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
|
||||
|
||||
/**
|
||||
* Function for generating both the dark and light stylesheets, so that they
|
||||
@@ -92,6 +94,11 @@ export function ColoredBlurView(props: PropsWithChildren<BlurViewProperties>) {
|
||||
const scheme = useColorScheme();
|
||||
|
||||
return (
|
||||
<BlurView {...props} blurType={scheme === 'dark' ? 'extraDark' : 'xlight'} />
|
||||
<BlurView
|
||||
{...props}
|
||||
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
|
||||
? 'material'
|
||||
: scheme === 'dark' ? 'extraDark' : 'xlight'
|
||||
} />
|
||||
);
|
||||
}
|
||||
85
src/components/CoverImage.tsx
Normal file
85
src/components/CoverImage.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Dimensions, ViewProps } from 'react-native';
|
||||
import { Canvas, Blur, Image as SkiaImage, useImage, Offset, Mask, RoundedRect, Shadow } from '@shopify/react-native-skia';
|
||||
import useDefaultStyles from './Colors';
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
const Screen = Dimensions.get('screen');
|
||||
|
||||
const Container = styled.View<{ size: number }>`
|
||||
width: ${(props) => props.size}px;
|
||||
height: ${(props) => props.size}px;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const BlurContainer = styled(Canvas)<{ size: number, offset: number }>`
|
||||
position: absolute;
|
||||
left: -${(props) => props.offset}px;
|
||||
top: -${(props) => props.offset}px;
|
||||
width: ${(props) => props.size}px;
|
||||
height: ${(props) => props.size}px;
|
||||
z-index: 2;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
blurRadius?: number;
|
||||
opacity?: number;
|
||||
margin?: number;
|
||||
radius?: number;
|
||||
style?: ViewProps['style'];
|
||||
src: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will take a cover image, and apply shadows and a really nice background
|
||||
* blur to the image in question. Additionally, we'll add some margin and radius
|
||||
* to the corners.
|
||||
*/
|
||||
function CoverImage({
|
||||
blurRadius = 256,
|
||||
opacity = 0.85,
|
||||
margin = 112,
|
||||
radius = 12,
|
||||
style,
|
||||
src,
|
||||
}: Props) {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
|
||||
const image = useImage(src || '');
|
||||
const { canvasSize, imageSize } = useMemo(() => {
|
||||
const imageSize = Screen.width - margin;
|
||||
const canvasSize = imageSize + blurRadius * 2;
|
||||
return { imageSize, canvasSize };
|
||||
}, [blurRadius, margin]);
|
||||
|
||||
return (
|
||||
<Container size={imageSize} style={style}>
|
||||
<BlurContainer size={canvasSize} offset={blurRadius}>
|
||||
<RoundedRect x={blurRadius} y={blurRadius} width={imageSize} height={imageSize} color={defaultStyles.imageBackground.backgroundColor} r={12}>
|
||||
<Shadow dx={0} dy={1} blur={2} color="#0000000d" />
|
||||
<Shadow dx={0} dy={2} blur={4} color="#0000000d" />
|
||||
<Shadow dx={0} dy={4} blur={8} color="#0000000d" />
|
||||
<Shadow dx={0} dy={8} blur={16} color="#0000000d" />
|
||||
<Shadow dx={0} dy={16} blur={32} color="#0000000d" />
|
||||
</RoundedRect>
|
||||
{image ? (
|
||||
<>
|
||||
<SkiaImage image={image} width={imageSize} height={imageSize} opacity={opacity}>
|
||||
<Offset x={blurRadius} y={blurRadius} />
|
||||
<Blur blur={blurRadius / 2} />
|
||||
</SkiaImage>
|
||||
<Mask mask={<RoundedRect width={imageSize} height={imageSize} x={blurRadius} y={blurRadius} r={radius} />}>
|
||||
{image ? (
|
||||
<SkiaImage image={image} width={imageSize} height={imageSize}>
|
||||
<Offset x={blurRadius} y={blurRadius} />
|
||||
</SkiaImage>
|
||||
) : null}
|
||||
</Mask>
|
||||
</>
|
||||
) : null}
|
||||
</BlurContainer>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default CoverImage;
|
||||
@@ -1,26 +0,0 @@
|
||||
import {GestureHandlerRefContext} from '@react-navigation/stack';
|
||||
import React, {PropsWithChildren, useCallback, useState} from 'react';
|
||||
import {ScrollViewProps} from 'react-native';
|
||||
import {ScrollView} from 'react-native-gesture-handler';
|
||||
|
||||
export const DismissableScrollView = (
|
||||
props: PropsWithChildren<ScrollViewProps>,
|
||||
) => {
|
||||
const [scrolledTop, setScrolledTop] = useState(true);
|
||||
const onScroll = useCallback(({nativeEvent}) => {
|
||||
console.log(nativeEvent.contentOffset);
|
||||
setScrolledTop(nativeEvent.contentOffset.y <= 0);
|
||||
}, []);
|
||||
return (
|
||||
<GestureHandlerRefContext.Consumer>
|
||||
{(ref) => (
|
||||
<ScrollView
|
||||
waitFor={scrolledTop ? ref : undefined}
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</GestureHandlerRefContext.Consumer>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user