Submitted
gsap animation
- HTML
- CSS
@xup60521
Submitted
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
I used gsap
to implement two animations. First is number increment, and second is summary blocks entrance animation.
Both are easy to do with this animation library. When setting up the result value, the only thing we need to do is call gsap.to
function.
gsap.to("#result", {
innerText: "76",
duration: 1,
ease: "power1.inOut",
snap: { innerText: 1 },
});
Whenever an user open this page, the animation would automatically play.
Apart from that, I also add another animation. This one has a twist, and we need to take advantage of gsap
’s helper function.
const summaryBlocks = gsap.utils.toArray(".summary-block");
By doing so, summaryBlocks.forEach
can apply multiple GSAP animation to each component at once.
summaryBlocks.forEach((summaryBlock, index) => {
gsap.fromTo(
summaryBlock,
{
opacity: 0,
y: 10,
},
{
opacity: 1,
y: 0,
ease: "power1.out",
duration: 0.5,
delay: 0.1 * index + 0.225,
}
);
});
When an user enter this website, these elements fade in sequentially.
Submitted
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
Framer-motion is not easy to work with. It took me too much time adjusting the layout within AnimatePresence component.
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
Use zod to validate email input
const emailSchema = z.string().email();
function isEmailValid(email: string) {
return emailSchema.safeParse(email);
}
const { success } = isEmailValid(email);
if (!success) {
showEmailErrorMsg();
} else {
closeEmailErrorMsg();
}
Submitted
What are you most proud of, and what would you do differently next time?
Menu open animation
We can use gsap
to change height, making it an open and close animation.
function openMenu() {
gsap.to(menu, {
height: "100vh",
duration: 0.5,
ease: "power2.out"
});
}
function closeMenu() {
gsap.to(menu, {
height: "0",
duration: 0.5,
ease: "power2.out",
});
}
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
I used gsap
to add animation to menu when opening or closing.
import MenuIcon from "/images/icon-hamburger.svg";
import CloseIcon from "/images/icon-close.svg";
import gsap from "gsap";
const btn = document.getElementById("btn") as HTMLImageElement;
const menu = document.getElementById("menu") as HTMLDivElement;
let isMenuOpen = false;
btn.addEventListener("click", () => {
if (isMenuOpen) {
btn.src = MenuIcon;
gsap.to(menu, {
height: "0",
duration: 0.5,
ease: "power2.out",
onComplete: () => {
isMenuOpen = false;
},
});
} else {
btn.src = CloseIcon;
gsap.to(menu, {
height: "auto",
duration: 0.5,
ease: "power2.out",
onComplete: () => {
isMenuOpen = true;
},
});
}
});
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
In react, we often use onChange
to interact between state and UI. However in semantic HTML, the binding is different. We need to use input
instead of change
.
emailInput.addEventListener("input", (event) => {
// fix typescript error
const { value: email } = event.target as HTMLInputElement;
validateEmail()
});
Submitted
What are you most proud of, and what would you do differently next time?
Originally I used vanilla HTML, then I realized that the form validation is much more easier using a frontend framework.
react-hook-form
is goated dealing with form. Combined with zod, I bet there's no better way to manage form in react.
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
Template
Manually creating vite app, installing all the necessary packages and configuring the settings are quite annoying, so I decided to make a template to simplify the process.
template repo: https://github.com/xup60521/vite-tailwindcss-ts-html-template
Submitted
Submitted
Submitted
Submitted
Submitted
What are you most proud of, and what would you do differently next time?
I took some time to derive the mortgage repayment formula on my own. It was a little bit confusing, but after some careful thought, it figured out how the formula came from.
Submitted
What are you most proud of, and what would you do differently next time?
Testing
Originally I wanted to use Jest
to do testing, but then it turned out that it was too complicated to setup.
Here, I used screen.getByTestId
to get the element, using userEvent.type
, userEvant.click
from @testing-library/user-event
library to mock the keyboard input and the clicking event.
// ----------- //
import { describe, it, expect } from "vitest"
import {
render,
screen,
waitfor } from "@testing-library/react"
import App from "./App"
describe("test form", () => {
it("submit wrong email", async () => {
render();
const emailInput = screen.getByTestId("email-input");
const submitBtn = screen.getByTestId("submit-btn");
await userEvent.type(emailInput, "asdasd");
await userEvent.click(submitBtn);
await waitFor(() => {
const errorMsg = screen.getByText("Please provide a valid email");
expect(errorMsg).toBeInTheDocument();
});
});
})
Submitted