React

220731 Trailing cursor FAB & hovered text effect

FAB는 position: absolute or fixed?

const droneRef: React.MutableRefObject<null> Object is possibly 'null'.

Generic & optional chaining

shake

import React, { useRef, useState } from 'react'; import styled, { keyframes } from 'styled-components'; import { throttle } from 'lodash'; import './App.css'; const droneStartMotion = process.env.PUBLIC_URL + '/drone_150_start.gif'; const droneLoopMotion = process.env.PUBLIC_URL + '/drone_150_loop.gif'; function App() { const droneRef = useRef<HTMLImageElement>(null); const [droneMotion, setDroneMotion] = useState<string>(droneLoopMotion); function handleMouseMove(evt: React.MouseEvent<HTMLDivElement, MouseEvent>) { const x = -(window.innerWidth / 2 - evt.pageX) / 55; const y = -(window.innerHeight / 2 - evt.pageX) / 45; const radian = Math.atan2(evt.pageX - x, evt.pageY - y); const rot = radian * ((90 / Math.PI) * -1 + 35); if (!droneRef || !droneRef.current) return; droneRef.current.style.transform = `rotate(${ (x + y >= 10 ? -420 / (x + y) : -45) + rot }deg) translateX(${x}px) translateY(${x + y >= 10 ? -y + 10 : y}px)`; } return ( <div className="App" style={{ minHeight: '100vh' }} onMouseMove={throttle((evt) => handleMouseMove(evt), 50)} > <HeaderContainer> <Header>Trip Activity</Header> </HeaderContainer> <DroneFAB ref={droneRef} src={droneMotion} alt="drone FAB" onMouseEnter={() => setDroneMotion(droneStartMotion)} onMouseLeave={() => setDroneMotion(droneLoopMotion)} /> </div> ); } const HeaderContainer = styled.div` transform: skewY(-8deg); background: linear-gradient( 109.6deg, rgb(116, 255, 217) 11.2%, rgb(88, 200, 223) 91.1% ); box-shadow: #0bc 0px 0px 6px; `; const ShakeHeader = keyframes` 0% { transform: translate(-3px, 2px); } 20% { transform: translate(2px, -2px); } 40% { transform: translate(4px, 3px); } 60% { transform: translate(5px, 4px); } 80% { transform: translate(6px, 4px); } 100% { transform: translate(1px, 1px); } }`; const Header = styled.h1` text-transform: uppercase; font-size: 72px; padding: 30px; text-shadow: -15px 5px 20px #ced0d3; color: white; &:hover { animation: ${ShakeHeader} 2s 1s infinite linear alternate; } `; const DroneFAB = styled.img` position: fixed; right: 10px; bottom: 0px; z-index: 9; transition: 0.2s; `; export default App;
TypeScript
복사

PR drone

import React, { useRef, useState } from 'react'; import styled from 'styled-components'; import { throttle } from 'lodash'; import './App.css'; const droneStartMotion = process.env.PUBLIC_URL + '/drone_150_start.gif'; const droneLoopMotion = process.env.PUBLIC_URL + '/drone_150_loop.gif'; function App() { const droneRef = useRef<HTMLImageElement>(null); const [droneMotion, setDroneMotion] = useState<string>(droneLoopMotion); function handleMouseMove(evt: React.MouseEvent<HTMLDivElement, MouseEvent>) { const x = -(window.innerWidth / 2 - evt.pageX) / 55; const y = -(window.innerHeight / 2 - evt.pageX) / 45; const radian = Math.atan2(evt.pageX - x, evt.pageY - y); const rot = radian * ((90 / Math.PI) * -1 + 35); if (!droneRef || !droneRef.current) return; droneRef.current.style.transform = `rotate(${ (x + y >= 10 ? -420 / (x + y) : -45) + rot }deg) translateX(${x}px) translateY(${x + y >= 10 ? -y + 10 : y}px)`; } return ( <div className="App" style={{ minHeight: '100vh' }} onMouseMove={throttle((evt) => handleMouseMove(evt), 50)} > <HeaderContainer> <Header>Trip Activity</Header> </HeaderContainer> <DroneFAB ref={droneRef} src={droneMotion} alt="drone FAB" onMouseEnter={() => setDroneMotion(droneStartMotion)} onMouseLeave={() => setDroneMotion(droneLoopMotion)} /> </div> ); } const HeaderContainer = styled.div` transform: skewY(-8deg); background: linear-gradient( 109.6deg, rgb(116, 255, 217) 11.2%, rgb(88, 200, 223) 91.1% ); box-shadow: #0bc 0px 0px 6px; `; const Header = styled.h1` text-transform: uppercase; font-size: 72px; padding: 30px; text-shadow: -15px 5px 20px #ced0d3; color: white; `; const DroneFAB = styled.img` position: fixed; right: 10px; bottom: 0px; z-index: 9; transition: 0.2s; `; export default App;
TypeScript
복사

Archive

import React, { useRef, useState } from 'react'; import styled from 'styled-components'; import { throttle } from 'lodash'; import './App.css'; const droneStartMotion = process.env.PUBLIC_URL + '/drone_150_start.gif'; const droneLoopMotion = process.env.PUBLIC_URL + '/drone_150_loop.gif'; function App() { const droneRef = useRef<HTMLImageElement>(null); const [droneMotion, setDroneMotion] = useState<string>(droneLoopMotion); function handleMouseMove(evt: React.MouseEvent<HTMLDivElement, MouseEvent>) { const x = -(window.innerWidth / 2 - evt.pageX) / 55; const y = -(window.innerHeight / 2 - evt.pageX) / 45; const radian = Math.atan2(evt.pageX - x, evt.pageY - y); const rot = radian * ((90 / Math.PI) * -1 + 35); if (!droneRef || !droneRef.current) return; droneRef.current.style.transform = `rotate(${ (x + y >= 10 ? -420 / (x + y) : -45) + rot }deg) translateX(${x}px) translateY(${x + y >= 10 ? -y + 10 : y}px)`; } return ( <div className="App" style={{ minHeight: '100vh' }} onMouseMove={throttle((evt) => handleMouseMove(evt), 50)} > <HeaderContainer> <Header>Trip Activity</Header> </HeaderContainer> <DroneFAB ref={droneRef} src={droneMotion} alt="drone FAB" onMouseEnter={() => setDroneMotion(droneStartMotion)} onMouseLeave={() => setDroneMotion(droneLoopMotion)} /> </div> ); } const HeaderContainer = styled.div` transform: skewY(-8deg); background: linear-gradient( 109.6deg, rgb(116, 255, 217) 11.2%, rgb(88, 200, 223) 91.1% ); box-shadow: #0bc 0px 0px 6px; `; const Header = styled.h1` text-transform: uppercase; font-size: 72px; padding: 30px; text-shadow: -15px 5px 20px #ced0d3; color: white; `; const DroneFAB = styled.img` position: fixed; right: 10px; bottom: 0px; z-index: 9; transition: 0.2s; `; export default App;
TypeScript
복사