Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found

All solutions

  • 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


    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


    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

    gsap animation

    • HTML
    • CSS
    • JS

    0


    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


    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

    react hook form

    • HTML
    • CSS
    • JS

    0


    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


    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


    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

    react

    • HTML
    • CSS
    • JS

    0

  • 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();
        });
      });
    })