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


    This is a solution to the Time tracking dashboard challenge on Frontend Mentor.

    Users should be able to:

    • View the optimal layout for the site depending on their device's screen size
    • See hover states for all interactive elements on the page
    • Switch between viewing Daily, Weekly, and Monthly stats

    • Semantic HTML5 markup
    • Flexbox
    • CSS Grid
    • Mobile-first workflow
    • Tailwind - For styles
    • React - JS library
    • Astro - Static Site Generator
    • Vercel - Hosting website

    Astro is used to build static sites that support multiple javascript frameworks & libraries while shipping little javascript. From my understanding, Astro islands are similar to react components, but this time, islands are converted to static HTML. you can find more information on Astro's islands architecture here

    Unlike other Frameworks & libraries I've worked with in the past, Astro generates an MPA (Multi-Page Application) instead of an SPA (Single-Page Application). More details on this can be found here.

    You can learn more here

    The concept of a layout component & different pages in the pages directory isn't a new thing to me. The only thing I had to learn when making a layout component is that you need to insert a <slot /> in the layout, this is where the page would put itself in.

    My layout component & my homepage

    The code below is from the astro docs

    ---
    import BaseHead from '../components/BaseHead.astro';
    import Footer from '../components/Footer.astro';
    const { title } = Astro.props;
    ---
    
    <html lang='en'>
    <head>
    <meta charset='utf-8' />
    <meta name='viewport' content='width=device-width, initial-scale=1' />
    <BaseHead title={title} />
    </head>
    <body>
    <nav>
    <a href='#'>Home</a>
    <a href='#'>Posts</a>
    <a href='#'>Contact</a>
    </nav>
    <h1>{title}</h1>
    <article>
    <slot />
    </article>
    <Footer />
    </body>
    </html>
    
    ---
    import MySiteLayout from '../layouts/MySiteLayout.astro';
    ---
    
    <MySiteLayout title='Home Page'>
    <p>My page content, wrapped in a layout!</p>
    </MySiteLayout>
    

    One of the most enjoyable things about Astro is working with the CLI. This is a simple project, but when installing packages from Astro, I didn't have to touch any config files. This seems small, but it automatically added tailwind, image & react to the astro config.

    For example, when I wanted to use Tailwind, I simply ran the following command in the terminal, npx astro add tailwind. I didn't have to manually install tailwind, configure astro etc... 😃

    In order to use react, I ran the following command:

    npx astro add react
    

    I placed my react components inside the components directory & used the .tsx file extension.

    Importing and using the components was easy, this is how it looks like:

    ---
    import Buttons from '../components/Buttons';
    import DashboardCard from '../components/DashboardCard';
    ---
    
    <Layout title='Time Tracking Dashboard'>
    <main>
    <Buttons client:load />
    
    <DashboardCard
    title={title}
    illustration={illustration}
    tframes={timeframes}
    bgColor={bgColor}
    client:idle
    />
    </main>
    </Layout>
    

    This was the trickiest part for me, but before I explain 'sharing state between islands', we first need to understand why we had to share state between them in the first place.

    Making a component, which has its own state is easy, but when the user clicks Daily, Weekly or Monthly, the content of each Dashboard has to update and display the correct information. In order to achieve this, I made use of Nano Store.

    Using Nano Store reminded me of Redux and React's useContext hook.

    The store can be found here, let's go over it line by line:

    import { atom } from 'nanostores';
    
    type timeFrameTypes = 'Daily' | 'Weekly' | 'Monthly';
    
    export const timeFrames: timeFrameTypes[] = ['Daily', 'Weekly', 'Monthly'];
    
    export const activeTimeFrame = atom<timeFrameTypes>('Weekly');
    

    import { atom } from 'nanostores'; - I import atom from nanostores. The reason I used atom is because we are going to store a string, nothing complicated.

    type timeFrameTypes = 'Daily' | 'Weekly' | 'Monthly'; - This is typescript, and I wanted to leverage it by restricting the type of value the string would contain, Similar to using an enum. because of this, we know that there can only be 3 different values, & when we set the value, we are only restricted to those 3 values. This is why I love Typescript.

    export const timeFrames: timeFrameTypes[] = ['Daily', 'Weekly', 'Monthly']; - I wanted to store the 3 different values in an array, this is important for buttons component. I used this array to display the 3 different time frames & assign event listeners to them.

    export const activeTimeFrame = atom<timeFrameTypes>('Weekly'); - Export the store. We also assign the type that the atom store holds by using Generics, (the angle brackets < & >)

    Buttons

    import { useStore } from '@nanostores/react';
    import { timeFrames, activeTimeFrame } from '../timeFramesStore';
    
    export default function Buttons() {
    return (
    <div
    id='timeframes'
    className='flex w-full items-start justify-between gap-4 p-8 brk:flex-col'
    >
    {timeFrames.map((timeFrame, key) => {
    const $active = useStore(activeTimeFrame);
    const isActive = timeFrame === $active;
    
    const handleClick = () => activeTimeFrame.set(timeFrame);
    
    return (
    <button
    className={`${isActive && 'text-white'}`}
    key={key}
    onClick={handleClick}
    >
    {timeFrame}
    </button>
    );
    })}
    </div>
    );
    }
    

    import { timeFrames, activeTimeFrame } from '../timeFramesStore'; - activeTimeFrame stores the current value/state. in order to get its value, we place the store inside the useStore method. I remember while reading the docs, it said that you have to prefix the variable name with $. This is how we end up with const $active = useStore(activeTimeFrame);.

    in order to update the state, we use the .set(/* new state */) method.

    It seems like I will have to learn client:directives & other directives

    <Buttons client:load />
    
    • Astro Docs - This helped me for XYZ reason. I really liked this pattern and will use it going forward.
    • Tailwind Docs - This is an amazing article which helped me finally understand XYZ. I'd recommend it to anyone still learning this concept.

    I initially wanted to use flexbox, but eventually realised that css grid would fit this well. I wanted it to look good on desktop, tablet & mobile devices.

  • Submitted


    This is the first time I ever touched Tailwind CSS. The thing I love about it is that I still had control over how I styled my components through utility. Something that I really enjoyed is that I didn't have to constantly jump between JSX & CSS files. This made it feel like I was saving a bit of time during development.

    I love how you can configure Tailwind. In this project, colours & fonts were given, which were easily included in the config file. One thing I had to get used to was putting all the breakpoints in the config file.

    I was worried about how everything would look if I used tailwind, but while reading through the docs (https://tailwindcss.com/docs/utility-first), my worries were alleviated. Something I also really loved was Automatic class sorting with Prettier.

    The last thing I had to adjust to, was learning how to develop in a mobile-first development workflow. It didn't really take time to adjust, especially considering how you can make websites responsive using Tailwind.

    Although the current config file has different screens, colours & font-families, what was lacking was proper spacing & font sizes. This could probably be attributed to the fact that I didn't have access to the actual design file, but rather the images of the designs alone. So I had to approximate the sizes. Using opening the design images in Figma helped when trying to determine things, but it's not always accurate.

  • Submitted


    This was a really good start with Gatsby Js, I learned the basics. I was disappointed with the fact that I didn't work a lot with images. Gatsby has a few plugins that optimise images, & I really wanted to experience that. The only image I had to work with was the logo image, but the plugins don't support SVG images. I just put the logo image in the static directory.

    What I enjoyed most about Gatsby is the fact that it's an SSG (Static Site Generator). This really boosts SEO performance compared to React projects. This happens because React performs client-side rendering.

    During development, I went through one of the most traumatic events in my web development career, NPM Peer dependencies. I learned that modules can depend on each other, but due to different versions, this can result in peer dependency errors. Never in my life have I appreciated Git & GitHub. Although I didn't resolve the issues, (I just moved back to the previous commit), this really exposed me to some of the inner workings of NPM.

    Live Site - https://frontendmentorexpenseschartcom.gatsbyjs.io/

    Hosting - https://www.gatsbyjs.com/products/cloud/

    Repo - https://github.com/ThaBeanBoy/Front-End-Mentor-Expenses-Chart-Component

    Front End Mentor - https://www.frontendmentor.io/home

    Challenge - https://www.frontendmentor.io/challenges/expenses-chart-component-e7yJBUdjwt/hub/expenses-chart-component-pRP0otU6Pw

    Framer Motion - https://www.framer.com/motion/

    My Github Account - https://github.com/ThaBeanBoy

    Linkedin - https://www.linkedin.com/in/gibbs-chipoyera-0948b9193/

    Instagram - https://www.instagram.com/tiin_giib_chiip/

    #googlefonts #webdeveloper - #webdevelopment - #webdev #webdesign

    • #uidesign
    • #design - #ui #figma
  • Submitted


    The only challenging thing about this project was making the site responsive. I think that might be my weakness when it comes to front-end web development. One thing I want to learn is HTML landmark tags. All I know is that it aids in accessibility, but I'm not sure about SEO.

    I hope I didn't break the design from widths 933-1260px, The site looked weird, so I adjusted the positioning of the cards to give additional space to the form and thank you status.

    My biggest curiosity throughout this project is how exactly do websites & applications process payments? do they use some sort of api, does the api support multiple regions? How would this be handled on the back-end? I've been wondering for some time now.

    Thanks for checking this out.

  • Submitted


    The only challenging thing about this project was making the site responsive. I think that might be my weakness when it comes to front-end web development. One thing I want to learn is HTML landmark tags. All I know is that it aids in accessibility, but I'm not sure about SEO.

    I hope I didn't break the design from widths 933-1260px, The site looked weird, so I adjusted the positioning of the cards to give additional space to the form and thank you status.

    My biggest curiosity throughout this project is how exactly do websites & applications process payments? do they use some sort of api, does the api support multiple regions? How would this be handled on the back-end? I've been wondering for some time now.

    Thanks for checking this out.

  • Submitted

    RESP

    • HTML
    • CSS

    1

  • Submitted


    The tricky thing was deciding between spreading the elements equally vertically or letting the body overflow the user's screen. The original design was designed with a 1440x1024 screen in mind. This site had to be responsive, so if I used flexbox and spread the elements equally, The site would've looked weird on smaller screens. I decided to let the body exceed the height of the user's screen should the body overflow the height of the screen.

    In the case that the body didn't overflow the body, I set the minimum height to 100vh, That way, at a minimum, the body would at least cover the screen.

    In order to show errors in the user's input, I'd use the invalid CSS property of an input element. Using this allowed me to style the input when the value of the input is invalid. Using the same technique as before, I could also let the error message of the input be displayed based on the validity of the user's input.

  • Submitted


    Overall, it was a fun project, but I had trouble with the background colour of the ""thank you" box and the Rating box

  • Submitted


    I am unsure about the mobile breakpoint, is it strictly supposed to be 375px? because I adjusted it to 550px. I did this because The card would overlap the window screen between 375 and 550px. I hope this isn't bad practice