Skip to content

Commit

Permalink
feat: EasterEgg
Browse files Browse the repository at this point in the history
* feat: EasterEgg falling bunnies add useKonamiCheatCode hook and FallingBunnies component

* refactor: Fixes and adding snapshot test for FallingBunnies Component

* refactor: Fixes import order and rename randPos to position and delete key prop from interface
  • Loading branch information
z3s authored Feb 26, 2021
1 parent d73f67f commit 1783785
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 0 deletions.
58 changes: 58 additions & 0 deletions src/__tests__/components/fallingbunnies.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import { renderWithTheme } from "../../testHelpers";
import FallingBunnies from "../../components/FallingBunnies/FallingBunnies";

beforeEach(() => {
jest.spyOn(global.Math, "random").mockReturnValue(0.5);
});

afterEach(() => {
jest.spyOn(global.Math, "random").mockRestore();
});

it("renders correctly", () => {
const { asFragment } = renderWithTheme(<FallingBunnies count={1} />);
expect(asFragment()).toMatchInlineSnapshot(`
<DocumentFragment>
<div>
<div
class="sc-gsTCUz jYheWP"
>
<svg
class="sc-bdfBwQ cuuOmQ"
color="text"
height="32"
viewBox="0 0 32 32"
width="32"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M5.84199 5.00181C5.35647 2.40193 7.35138 0 9.9962 0C12.3302 0 14.2222 1.89206 14.2222 4.22603V9.43607C14.806 9.39487 15.3992 9.37374 16 9.37374C16.5772 9.37374 17.1474 9.39324 17.709 9.43131V4.22603C17.709 1.89206 19.601 0 21.935 0C24.5798 0 26.5747 2.40193 26.0892 5.00181L24.9456 11.1259C28.8705 12.8395 31.8384 15.8157 31.8384 19.5556V21.8182C31.8384 24.8936 29.8038 27.4686 26.9594 29.2068C24.0928 30.9586 20.2149 32 16 32C11.7851 32 7.90719 30.9586 5.04062 29.2068C2.19624 27.4686 0.161621 24.8936 0.161621 21.8182V19.5556C0.161621 15.8355 3.09899 12.8708 6.99084 11.1538L5.84199 5.00181ZM23.48 11.9305L24.8183 4.76446C25.1552 2.96 23.7707 1.29293 21.935 1.29293C20.3151 1.29293 19.0019 2.60612 19.0019 4.22603V10.8562C18.5774 10.8018 18.1462 10.7586 17.709 10.7274C17.1484 10.6873 16.5782 10.6667 16 10.6667C15.3982 10.6667 14.8049 10.689 14.2222 10.7324C13.785 10.765 13.3537 10.8094 12.9293 10.8651V4.22603C12.9293 2.60612 11.6161 1.29293 9.9962 1.29293C8.16055 1.29293 6.77597 2.96 7.11295 4.76446L8.45562 11.9543C4.25822 13.5135 1.45455 16.3344 1.45455 19.5556V21.8182C1.45455 26.7274 7.96677 30.7071 16 30.7071C24.0332 30.7071 30.5455 26.7274 30.5455 21.8182V19.5556C30.5455 16.318 27.7131 13.4847 23.48 11.9305Z"
fill="#633001"
fill-rule="evenodd"
/>
<path
d="M30.5455 21.8183C30.5455 26.7275 24.0333 30.7072 16 30.7072C7.96681 30.7072 1.45459 26.7275 1.45459 21.8183V19.5557H30.5455V21.8183Z"
fill="#FEDC90"
/>
<path
clip-rule="evenodd"
d="M7.11298 4.7645C6.77601 2.96004 8.16058 1.29297 9.99624 1.29297C11.6161 1.29297 12.9293 2.60616 12.9293 4.22607V10.8652C13.9192 10.7351 14.9466 10.6667 16 10.6667C17.0291 10.6667 18.0333 10.732 19.0019 10.8562V4.22607C19.0019 2.60616 20.3151 1.29297 21.935 1.29297C23.7707 1.29297 25.1553 2.96004 24.8183 4.7645L23.4801 11.9306C27.7131 13.4847 30.5455 16.318 30.5455 19.5556C30.5455 24.4648 24.0333 28.4445 16 28.4445C7.96681 28.4445 1.45459 24.4648 1.45459 19.5556C1.45459 16.3345 4.25826 13.5135 8.45566 11.9543L7.11298 4.7645Z"
fill="#D1884F"
fill-rule="evenodd"
/>
<path
d="M11.9595 18.9091C11.9595 20.248 11.2359 21.3333 10.3433 21.3333C9.45075 21.3333 8.72717 20.248 8.72717 18.9091C8.72717 17.5702 9.45075 16.4849 10.3433 16.4849C11.2359 16.4849 11.9595 17.5702 11.9595 18.9091Z"
fill="#633001"
/>
<path
d="M23.1111 18.9091C23.1111 20.248 22.3875 21.3333 21.4949 21.3333C20.6024 21.3333 19.8788 20.248 19.8788 18.9091C19.8788 17.5702 20.6024 16.4849 21.4949 16.4849C22.3875 16.4849 23.1111 17.5702 23.1111 18.9091Z"
fill="#633001"
/>
</svg>
</div>
</div>
</DocumentFragment>
`);
});
83 changes: 83 additions & 0 deletions src/components/FallingBunnies/FallingBunnies.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from "react";
import styled, { keyframes } from "styled-components";
import BunnyIcon from "../Svg/Icons/Logo";
import { BunnyProps, FallingBunniesProps } from "./types";

const bunnyFall = keyframes`
0% {
opacity: 1;
transform: translate(0, -100%) rotateZ(0deg);
}
75% {
opacity: 1;
transform: translate(100px, 75vh) rotateZ(270deg);
}
100% {
opacity: 0;
transform: translate(150px, 100vh) rotateZ(360deg);
}
`;

const Bunny = styled.div<BunnyProps>`
display: inline-flex;
position: fixed;
top: 0;
left: ${({ position }) => `${position}vw`};
transform: translate3d(0, -100%, 0);
user-select: none;
pointer-events: none;
z-index: 99999;
animation-name: ${bunnyFall};
animation-duration: ${({ duration }) => `${duration}s`};
animation-timing-function: linear;
animation-iteration-count: ${({ iterations }) => (Number.isFinite(iterations) ? String(iterations) : "infinite")};
animation-play-state: running;
&:nth-child(5n + 5) {
animation-delay: ${({ duration }) => `${(duration / 10) * 1.3}s`};
}
&:nth-child(3n + 2) {
animation-delay: ${({ duration }) => `${(duration / 10) * 1.5}s`};
}
&:nth-child(2n + 5) {
animation-delay: ${({ duration }) => `${(duration / 10) * 1.7}s`};
}
&:nth-child(3n + 10) {
animation-delay: ${({ duration }) => `${(duration / 10) * 2.7}s`};
}
&:nth-child(7n + 2) {
animation-delay: ${({ duration }) => `${(duration / 10) * 3.5}s`};
}
&:nth-child(4n + 5) {
animation-delay: ${({ duration }) => `${(duration / 10) * 5.5}s`};
}
&:nth-child(3n + 7) {
animation-delay: ${({ duration }) => `${(duration / 10) * 8}s`};
}
`;

const FallingBunnies: React.FC<FallingBunniesProps> = ({
count = 30,
size = 32,
iterations = Infinity,
duration = 10,
}) => {
const bunnies = [...Array(count)].map((_, index) => (
<Bunny key={String(index)} position={Math.random() * 100} iterations={iterations} duration={duration}>
<BunnyIcon width={size} height={size} />
</Bunny>
));

return <div>{bunnies}</div>;
};

export default FallingBunnies;
12 changes: 12 additions & 0 deletions src/components/FallingBunnies/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
import FallingBunnies from "./FallingBunnies";

export default {
title: "Components/FallingBunnies",
component: FallingBunnies,
argTypes: {},
};

export const Default: React.FC = () => {
return <FallingBunnies />;
};
2 changes: 2 additions & 0 deletions src/components/FallingBunnies/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as FallingBunnies } from "./FallingBunnies";
export type { FallingBunniesProps } from "./types";
12 changes: 12 additions & 0 deletions src/components/FallingBunnies/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface BunnyProps {
position: number;
iterations: number;
duration: number;
}

export interface FallingBunniesProps {
size?: number;
count?: number;
iterations?: number;
duration?: number;
}
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as useMatchBreakpoints } from "./useMatchBreakpoints";
export { default as useParticleBurst } from "./useParticleBurst";
export { default as useKonamiCheatCode } from "./useKonamiCheatCode";
20 changes: 20 additions & 0 deletions src/hooks/useKonamiCheatCode.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { useCallback, useState } from "react";
import useKonamiCheatCode from "./useKonamiCheatCode";

export default {
title: "Hooks/useKonamiCheatCode",
argTypes: {},
};

export const Default: React.FC = () => {
const [correctCodeEntered, setCorrectCodeEntered] = useState(false);
const correctCodeHandler = useCallback(() => setCorrectCodeEntered(true), [setCorrectCodeEntered]);
useKonamiCheatCode(correctCodeHandler);

return (
<div style={{ padding: "32px" }}>
<div>Enter: ArrowUp, ArrowUp, ArrowDown, ArrowDown, ArrowLeft, ArrowRight, ArrowLeft, ArrowRight</div>
<pre>Code Entered: {JSON.stringify(correctCodeEntered)}</pre>
</div>
);
};
37 changes: 37 additions & 0 deletions src/hooks/useKonamiCheatCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect } from "react";

const useKonamiCheatCode = (matchedCodeHandler: () => void): void => {
useEffect(() => {
const pattern = [
"ArrowUp",
"ArrowUp",
"ArrowDown",
"ArrowDown",
"ArrowLeft",
"ArrowRight",
"ArrowLeft",
"ArrowRight",
];

let currentIndex = 0;

const onKeyUpHandler = (event: KeyboardEvent) => {
const { key } = event;
// is key in correct order otherwise reset
if (key !== pattern[currentIndex]) {
currentIndex = 0;
return;
}
currentIndex += 1;
if (pattern.length === currentIndex) {
currentIndex = 0;
matchedCodeHandler();
}
};

document.addEventListener("keyup", onKeyUpHandler);
return () => document.removeEventListener("keyup", onKeyUpHandler);
}, [matchedCodeHandler]);
};

export default useKonamiCheatCode;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from "./components/ButtonMenu";
export * from "./components/Card";
export * from "./components/Checkbox";
export * from "./components/Dropdown";
export * from "./components/FallingBunnies";
export * from "./components/Heading";
export * from "./components/Image";
export * from "./components/Input";
Expand Down

0 comments on commit 1783785

Please sign in to comment.