Skip to content

Commit

Permalink
feat(project): add dynamic blur
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut committed May 6, 2021
1 parent 59def36 commit 47b409d
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/components/DynamicBlur/DynamicBlur.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@use '../../styles/variables';
@use '../../styles/theme';

.BlurBackground {
position: fixed;
height: 100vh;
width: 100vw;
background-position: center;
background-size: cover;
box-sizing: border-box;
filter: blur(30px);
z-index: -1;
}
12 changes: 12 additions & 0 deletions src/components/DynamicBlur/DynamicBlur.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { render } from '@testing-library/react';

import DynamicBlur from './DynamicBlur';

describe('<DynamicBlur>', () => {
test('renders and matches snapshot', () => {
const { container } = render(<DynamicBlur />);

expect(container).toMatchSnapshot();
});
});
66 changes: 66 additions & 0 deletions src/components/DynamicBlur/DynamicBlur.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { memo, useEffect, useRef, useState } from 'react';

import { debounce } from '../../utils/common';

import styles from './DynamicBlur.module.scss';

type ImgState = {
current: 'first' | 'second' | 'none';
srcFirst: string;
srcSecond: string;
};

const defaultImgState: ImgState = {
current: 'none',
srcFirst: '',
srcSecond: '',
};

type Props = {
url: string;
transitionTime?: number;
};

const DynamicBlur: React.FC<Props> = ({ url, transitionTime = 1 }: Props) => {
const [imgState, setImgState] = useState<ImgState>(defaultImgState);
const loadImgRef = useRef(debounce((url: string, imgState: ImgState) => loadImage(url, imgState), 350));

const loadImage = (url: string, imgState: ImgState) => {
const img = document.createElement('img');
img.onload = () => {
setImgState({
current: imgState.current === 'first' ? 'second' : 'first',
srcFirst: imgState.current === 'first' ? imgState.srcFirst : url,
srcSecond: imgState.current === 'second' ? imgState.srcSecond : url,
});
};
if (url) img.src = url;
};

useEffect(() => {
if (url !== imgState.srcFirst && url !== imgState.srcSecond) loadImgRef.current(url, imgState);
}, [url, imgState]);

return (
<React.Fragment>
<div
style={{
background: `url('${imgState.srcFirst}')`,
opacity: imgState.current === 'first' ? 0.3 : 0,
transition: `opacity ${transitionTime}s ease-in-out`,
}}
className={styles.BlurBackground}
/>
<div
style={{
background: `url('${imgState.srcSecond}')`,
opacity: imgState.current === 'second' ? 0.3 : 0,
transition: `opacity ${transitionTime}s ease-in-out`,
}}
className={styles.BlurBackground}
/>
</React.Fragment>
);
};

export default memo(DynamicBlur);
14 changes: 14 additions & 0 deletions src/components/DynamicBlur/__snapshots__/DynamicBlur.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<DynamicBlur> renders and matches snapshot 1`] = `
<div>
<div
class="BlurBackground"
style="background: url(); opacity: 0; transition: opacity 1s ease-in-out;"
/>
<div
class="BlurBackground"
style="background: url(); opacity: 0; transition: opacity 1s ease-in-out;"
/>
</div>
`;
11 changes: 9 additions & 2 deletions src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import React, { ReactNode, FC, useState } from 'react';
import React, { ReactNode, FC, useState, useContext } from 'react';

import Header from '../Header/Header';
import SideBar from '../SideBar/SideBar';

import DynamicBlur from '../DynamicBlur/DynamicBlur';
import styles from './Layout.module.scss';
import type { Config } from 'types/Config';
import { ConfigContext } from '../../providers/configProvider';
import { UIStateContext } from '../../providers/uiStateProvider';

type LayoutProps = {
children?: ReactNode;
};

const Layout: FC<LayoutProps> = ({ children }) => {
const config: Config = useContext(ConfigContext);
const { blurImage } = useContext(UIStateContext);
const [sideBarOpen, setSideBarOpen] = useState(false);
const hasDynamicBlur = config?.options.dynamicBlur === true;

return (
<div className={styles.layout}>
{hasDynamicBlur && blurImage && <DynamicBlur url={blurImage} />}
<Header onMenuButtonClick={() => setSideBarOpen(true)} />
<SideBar isOpen={sideBarOpen} onClose={() => setSideBarOpen(false)} />
{children}
Expand Down

0 comments on commit 47b409d

Please sign in to comment.