<![CDATA[Jalaj Gupta]]>https://blog.jalaj.codesRSS for NodeSun, 01 Aug 2021 19:59:06 GMT60<![CDATA[Keeping the Footer at the Bottom of the Page]]>When creating a website with dyanmic content, we sometimes face a problem where the content on the page doesn't fill the page and the footer, rather than staying in the bottom, moves up leaving blank space beneath it.

There are many ways to solve this problem like,

  • Absolute positioning the footer at the bottom (this doesn't work when content grows larger than the viewport, the footer gets ‘stuck’ to the bottom of the viewport.)

  • Using sticky or fixed positioning (this works if you want your footer to always be visible ;(

  • Using Flexbox or Grid (Both of these technologies allows us to get the behaviour we want but in my opinion using grid is easier and more elegant)

I'll explain how to use grid to push footer at the bottom in this post and let's leave flexbox for a later post.

Page Structure

Your page structure should match the html below.

   <div class="page-wrapper">

Maybe your page structure is somewhat more complex, in that case you need to keep in mind to put your Header, Footer and Main inside a parent container.

Applying CSS Magic

.page-wrapper {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 100%;
    grid-template-rows: auto 1fr auto;

Let see what each line of above code does.

  • min-height: 100vh - Here we are telling the browser to fill the entire viewport
  • display: grid - This line makes the element a grid container
  • grid-template-columns: 1fr - We are creating a single column and giving it a width of 1fr. If that 1fr is new to you, it essentially means “take the remaining space” which, in this case, is the entire width of the grid container, .page-wrapper.

Now the most important line,

  • grid-template-rows: auto 1fr auto:

    • Here we are telling the brower to create three rows. The first and third row, which is the header and footer, respectively, are sized with auto, which means they’ll take up as much space as needed. In other words: no need for hard-coded sizes! (isn't css grid just awesome?)
    • The middle row is our content. We’ve assigned it a size of 1fr which, again, just means it takes up all of the remaining space that’s left over from the other two rows. If you’re wondering why we aren’t making it auto as well, it’s because the entire grid spans the viewport’s whole height, so we need one section to grow and fill up any unused space.

I've prepared a working example on codepen. Go ahead and see what happens when you type more text.

https://blog.jalaj.codes/keeping-the-footer-at-the-bottom-of-the-page-ckpl32krw0hmhz0s1ecjr4asuhttps://blog.jalaj.codes/keeping-the-footer-at-the-bottom-of-the-page-ckpl32krw0hmhz0s1ecjr4asuSun, 06 Jun 2021 11:09:49 GMThttps://cdn.hashnode.com/res/hashnode/image/upload/v1622971299349/r9l2SLyPE.png
<![CDATA[The easy-peasy React state management library]]>Every application needs to manage state. In React, we can go a long way using hooks, and in particular useState(), and passing props around.

In my personal projects when things get more complicated than that, I like to immediately jump to a state management library. One of my favorites lately is easy-peasy.

It builds on top of Redux, and it provides a simpler way to interact with state.

I like to keep my code as simple as possible. Simple is understandable. Simple is beautiful.

Complexity should be avoided at all costs, and if possible hidden away in libraries that expose a simple interface to us. It’s the case of this library, and that’s why I like it!

Install it using:

yarn add easy-peasy

First of all we need to create a store. The store is the place where we’ll store our state, and the functions needed to modify it.

Create the store in the file store.js in the root of your project, with this content:

import { createStore, action } from 'easy-peasy'

export default createStore({})

We’ll add more things to this file later.

Now let's wrap our React app into the StoreProvider component provided by easy-peasy. It depends on what you use. With create-react-app for example, I'll add this to my index.js file:

import { StoreProvider } from 'easy-peasy'
import store from '../store'

    <StoreProvider store={store}>
      <App />

This operation makes now our store available in every component of the app.

Now we're ready to go in the store.js file and add some state, and some actions to change that state.

Let’s do a simple example. We can create a name state, and we create a setName action to change the name:

import { createStore, action } from 'easy-peasy'

export default createStore({
  name: '',
  setName: action((state, payload) => {
    name = payload

Now inside any component of our app we can import useStoreState and useStoreActions from easy-peasy:

import { useStoreState, useStoreActions } from 'easy-peasy'

We use useStoreState to access the store state properties:

const name = useStoreState((state) => state.name)

and useStoreActions to access the actions we defined:

const setName = useStoreActions((actions) => actions.setName)

Now we can call this action whenever something happens in our app, for example if we click a button:

  onClick={() => {
  Set name

Now any other component that is accessing the state through useStoreState() will see the value updated.

This is a simple example but it all starts from this. We can add as many state variables and as many actions we want, and I found that centralizing it all to a store.js file makes the application very easy to scale.

https://blog.jalaj.codes/the-easy-peasy-react-state-management-library-ckp16vfuq0mhqcrs17r3c237xhttps://blog.jalaj.codes/the-easy-peasy-react-state-management-library-ckp16vfuq0mhqcrs17r3c237xSun, 23 May 2021 13:00:50 GMThttps://cdn.hashnode.com/res/hashnode/image/upload/v1621774817073/jV7BSYKiE.png
<![CDATA[Reversing a String in Javascript]]>In this post I will explain different methods to reverse the string using javascript, so without any further ado let get right into it.

Below given code is how I wrote the solution at first, I'll explain it and after that discuss other methods of solving the problem.

function reverseString(str) {
    let arr = str.split("");
    str = arr.join("");
    return str;

What above code does is it first uses the split function which splits the passed string object into array of strings by separating strings into substrings.

After that I reversed the array we created above using reverse method. In the last I joined all the elements of array into string using the join method and returned the string.

So that's my solution to the challenge. Now let’s talk about other ways.

To make above code shorter we can chain methods and return immediately.

function reverseString(str){
    return str.split("").reverse().join("");

While we're at it we can make it even shorter if we use ES6 arrow function syntax.

const reverseString = str => str.split("").reverse().join("");

Now imagine your interviewer saying, 'Great, now solve it without using these inbuilt methods with a simple for loop.'

Don't sweat yet! Below I'll tell how to do just that...

Reversing a string using for loop

We can also reverse a String without using builtin methods like reverse by using for loop.

function reverseString(str) {
    let newString = "";
        newString += str[i];
    return newString;

Okay so what I am doing in this code is at first I declared a new variable to hold our reversed string.

After that I created a for loop. The starting point of the for loop is str.length - 1. which is the index of the last character of the string. As long as the value of i is greater than or equal to zero the loop will go on and we decrement the value of i with each iteration.

Checkout the pseudocode explaining the process below.

For example let’s suppose the string passed to the function is “hello”.

Now hello’s length equals 5
For each iteration: i = str.length  1 and newString = newString + str[i]
First iteration: i = 5  1 = 4, newString = “” + “o” = “o”
Second iteration: i = 4  1 = 3, newString = “o” + “l” = “ol”
Third iteration: i = 3  1 = 2, newString = “ol” + “l” = “oll”
Fourth iteration: i = 2  1 = 1, newString = “oll” + “e” = “olle”
Fifth iteration: i = 1  1 = 0, newString = “olle” + “h” = “olleh”
End of the FOR Loop

Aaaand in the last we returned the reversed string.

Hope you got that! If not then don’t hesitate to comment and I’ll be more than happy to help.

Still awake? Let's see yet another method to reverse your strings.

Reversing string using Recursion

In this method, I will use two methods: the String.prototype.substr() method and the String.prototype.charAt() method.


"hello".substr(1); // "ello"

The charAt() method returns the specified character from a string.


Now the whole code,

function reverseString(str) {
    if (str === "") { // This is the terminal case that will end the recursion
        return "";
    } else {
        return reverseString(str.substr(1)) + str.charAt(0);
reverseString("hello"); // olleh


First Part of the recursion method

  We need to remember that there won’t be just one call, we’ll have several nested calls

  Each call will return       reverseString(str.subst(1))   +    str.charAt(0)

  1st call – reverseString("Hello")   will return   reverseString("ello")    + "h"
  2nd call – reverseString("ello")    will return   reverseString("llo")      + "e"
  3rd call – reverseString("llo")     will return   reverseString("lo")       + "l"
  4th call – reverseString("lo")      will return   reverseString("o")        + "l"
  5th call – reverseString("o")       will return   reverseString("")          + "o"

Second part of the recursion method

  The method hits the if condition and the most highly nested call returns immediately

  5th call will return reverseString("") + "o" = "o"
  4th call will return reverseString("o") + "l" = "o" + "l"
  3rd call will return reverseString("lo") + "l" = "o" + "l" + "l"
  2nd call will return reverserString("llo") + "e" = "o" + "l" + "l" + "e"
  1st call will return reverserString("ello") + "h" = "o" + "l" + "l" + "e" + "h"

In the end we get the reversed string.

So this one was heavy and I doubt if someone could come up with this solution on his own in interview. If you don't understand this solution right now its totally fine.

Now continuing on our tradition from above, here's the shortened version of above code using arrow functions and ternary operators.

const reversedString = str => (str === "") ? "" : reverseString(str.substr(1)) + str.charAt(0);

Parting words

Hope you learned something from the article. Reversing a string is a simple problem which can be useful in solving more complex problems in interview or maybe if you are lucky enough you'll be asked just to reverse a string ;)

See you in next post, till then Happy Coding!

https://blog.jalaj.codes/reversing-a-string-in-javascript-ckp12d1000lb2crs171icg5nrhttps://blog.jalaj.codes/reversing-a-string-in-javascript-ckp12d1000lb2crs171icg5nrSun, 23 May 2021 10:54:33 GMThttps://cdn.hashnode.com/res/hashnode/image/upload/v1621764485915/RqlzDtWVj.png
<![CDATA[Creating Page Transitions in React using Framer Motion]]>Page transitions are animated transition between pages which are used to give websites that extra touch that distinguishes them as a top-notch and worthy of a good browse, when applied correctly they not only give a sense of liveliness but also helps greatly with navigation.

We all love to see smooth and cool page transitions when browsing websites. I've always been fascinated by them and wanted to learn how to add those to my sites. Libraries like Barba makes it very easy to add them in our site, but they don't work well with React.

Thankfully, Framer Motion makes it possible (and easier) to create sleek and smooth page transitions in React and similar libraries and in this article, I'll show you how. Scroll down to the bottom if you want to see the final demo.

Framer Motion

The basics of Framer Motion involve creating a motion component and passing some values to set the styles we want an element to start at and animate to. So if I want to have an element to come in from the left when it's rendered, I can play with the x property. Check out the sandbox below, try changing x to y and see what happens.

    initial={{ opacity: 0, x: "-100vh" }}
    animate={{ opacity: 1, x: 0 }}
   <p>Animated text</p>


In the above example, you should notice that the top text slides in as it's being mounted, while the normal text renders without any sort of transition. The slide in is smoother, but both texts exhibit the same behavior when they are unmounted. Even though our motion.div component slides in, it doesn't slide out.

To get the desired behavior, we can import and wrap AnimatePresence around our conditionally rendered element. Now we can use the exit prop on our motion.div to have the element slide out as it's being unmounted.

          {isDisplayed && (
                initial={{ x: "-100vh" }}
                animate={{ x: 0 }}
                exit={{ x: "100vh" }}
                <p>Animated text</p>
              <p>Normal text</p>

Pretty cool, huh? Let's reuse the above logic to apply animation when a route is changed in this simple react application.

Starter Sandbox

Our first step is to wrap our pages inside a <AnimatePresence>. Where we wrap it will depend on where our router is rendering the pages. In our case, we'll do that in App.js file because that's where routes are defined.

AnimatePresence demands that each of its direct children needs to have a unique key prop so it can track their presence in the tree. We can use the location object from the useLocation hook by importing it from react-router-dom.

Here's how the App.js file will look like after making the necessary changes. Notice that I've kept the <Navbar/> component outside of AnimatePresence because we don't want it to animate with the whole page.

import React from "react";
import { Route, Switch, useLocation } from "react-router-dom";
import { AnimatePresence } from "framer-motion";

import Home from "./pages/Home.js";
import About from "./pages/About.js";
import Contact from "./pages/Contact.js";
import Navbar from "./components/Navbar.js";

const App = () => {
  const location = useLocation();

  return (
      <Navbar />
      <AnimatePresence exitBeforeEnter>
        <Switch location={location} key={location.pathname}>

export default App;

If you look closely you will notice that I've added a prop called exitBeforeEnter to AnimatePresence. This prop guarantees that our component will have unmounted (i.e. completed its exit animation) before allowing the new component to animate in. If we remove this prop the exit and enter animation will take place at the same time and we won't be able to see the enter animation while changing routes.

Now all that's left is to use a motion component in our pages and define our initial, animate, and exit props like we did earlier!

So, we'll wrap the return value of all the three pages of our site with a motion.div component and add the necessary props. We'll also add a transition prop to change the duration of the animation so that we can see it more easily. Here's how Home.js will look like after making the changes.

import React from "react";
import Banner from "../components/Banner.js";
import { motion } from "framer-motion";

const Home = () => {
  return (
      initial={{ opacity: 0, x: -200 }}
      exit={{ opacity: 0, x: 200 }}
      transition={{ duration: 0.7 }}
      <Banner title="Welcome stranger!" subtitle="Put something witty here!" />
      <div className="container">
          Lorem ipsum........
          Maecenas dapibus.......
export default Home;

Final Demo


I hope you enjoyed reading the article and learned something from it.

We have only scratched the surface of what framer motion can do. In the next post, we'll use some advanced features of framer motion like AnimateSharedLayout to create a fairly complex page transition.

https://blog.jalaj.codes/creating-page-transitions-in-react-using-framer-motion-ckolcx5hh06zv3js15642fi06https://blog.jalaj.codes/creating-page-transitions-in-react-using-framer-motion-ckolcx5hh06zv3js15642fi06Wed, 12 May 2021 11:05:49 GMThttps://cdn.hashnode.com/res/hashnode/image/upload/v1620817294069/8mjZL-nk-.png
<![CDATA[GiTrack - Statistics and Issue Tracker for Open Source Enthusiasts]]>👋 Introduction

Hi folks!

First of all, I want to thank the Hashnode team for providing us with the opportunity to get out of our comfort zone (or should I say Tutorial Hell 😉) and actually build and deploy something into the real world. This is my first ever hackathon and I am very excited to share what I created with all of you.

I am Jalaj, a student from India currently pursuing my bachelor's degree. I started contributing to Open source last year in December since then I've contributed to 10+ repositories with over 30+ merged pull requests.

Working in Open Source has taught me a lot of things and I would recommend everyone to try it, we get to learn to work with other people, learn and improve by reading code and a lot of other things which one simply can't get by just watching a tutorial on Youtube or Udemy and creating simple and trivial apps.

Introducing GiTrack

I like to keep track of things and while contributing simultaneously to various repositories, it sometimes gets difficult to keep track of assigned issues and pull requests. To solve that problem, I built GiTrack, a website for Open Source Enthusiasts to keep track of issues assigned to them and arrange them in a nice looking Kanban board.

I wanted to create something useful but also simple enough for everyone to use, that's why I went with a Kanban board (coz everyone's familiar with it? 😅) besides that I also decide to add a profile page to the website that shows some useful statistics to the user such as the Total number of their contributions, issues they have opened, pull requests they have created, their current streak and a lot more...

Github has their own project board for a per-project basis, but the idea behind GiTrack is to be an issue tracker for all repositories, owned or otherwise, plus you get some nice statistics.

Here's what I had in mind when I started building the website:

  • It should allow users to log in via Github. (who wants to type their email and password?)
  • It should have a beautiful homepage that lists features of the website.
  • It should allow users to fetch currently assigned issues directly into the board.
  • Board state should be saved every time a user makes any changes. So that the next time they visit they can start where they left.
  • Profile page should list different stats that might be useful for users.

I used AWS Amplify to host the site. Amplify's CLI is a dream come true for developers. Just one command and the site is deployed live.

💻 Screenshots

Light mode:

Home page


Login Page

login screen


ScreenHunter Mar. 03 10.44.png Issue Tracker issue tracker

Dark mode:

Home page

ScreenHunter Mar. 03 10.37.png

Login page

ScreenHunter Mar. 03 10.40.png Statistics

ScreenHunter Mar. 03 10.43.png Issue tracker ScreenHunter Mar. 03 10.48.png

👀 Features

  • Issue Tracker
  • Github Statistics
  • Fetch issues assigned to you directly from Github.
  • Client Side Storage using IndexedDB for super fast page loads.
  • Persistent board state, so no worries about accidentally closing the page.
  • Beautiful UI
  • Open Source (checkout code on github)
  • One Click Login using Github OAuth

Here's a quick video showing how to use the issue tracker.

🏢 Build Process

I really wanted to get out of my comfort zone and build something with the technologies I've never used before. In the tech stack listed below, I was only familiar with Typescript before I started this project.

👩‍💻 Tech Stack

  • Next JS
  • Typescript
  • AWS Amplify
  • Firebase
  • Chakra UI

I read about this hackathon at the starting of February and I created a repo and pushed the initial commit the on 14th. But after that, I started procrastinating didn't do anything for the next few days. It was 22 when I got some confidence boost and started working on the project again.

I used OpenChakra to quickly create a basic boilerplate for the pages and edited it to fit my needs. I chose firebase to do the authentication and storage. I really wanted to use Amplify for auth but they don't have Github OAuth. Anyways, after getting done with a basic MVP of the project I deployed it on Amplify using its CLI.

Here are some of the packages I used:

  • nextjs : for building the app
  • typescript for writing type safe code
  • react-trello for issue tracker
  • chakra-ui as a UI framework
  • firebase for auth and storage
  • localforage for storing data in indexedDB
  • octokit as a github rest client

🏆 Challenges faced while developing

  • Persist board state: I wanted to store board state every time a user makes any change to the tracker board. I could use firebase for this but I wanted to keep it fast. So my only option was to store data in the browser. As the data was complex I was having trouble storing it in localstorage, I did some research and decided to use IndexedDB.

  • As I wasn't requesting any special permissions while using GitHub OAuth I had to find an alternative way to get assigned issues for the user. I did some research and used github issues and pull requests search endpoint to get the required data.

  • Persist login state: Firebase provides a function just for this purpose but it wasn't working as I expected it to be, it logged the user in without checking if there is data in IndexedDB or not so I had to modify it with added logic of fetching the state from indexedDB first and if there is no data in DB then don't log the user in.

🌟 What's Next

  • Add Dark Mode
    • Update 3/3/21: Dark mode added. (Check Screenshots above)
  • Allow users to get issues they recently commented on.
  • Allow users to get their merged pull requests.
  • Keyboard shortcuts

🥳 Conclusion

All in all, it was fun working on the project in a strict timeline. Once again thanks to the folks over at Hashnode for this opportunity.

Thanks to the reader for reading this far, I hope you like the app, and please don't hesitate to message me or comment below if you have any feedback.

https://blog.jalaj.codes/gitrack-statistics-and-issue-tracker-for-open-source-enthusiasts-cklnsnr1z01mg95s1fcqwbmm5https://blog.jalaj.codes/gitrack-statistics-and-issue-tracker-for-open-source-enthusiasts-cklnsnr1z01mg95s1fcqwbmm5Sat, 27 Feb 2021 14:02:50 GMThttps://cdn.hashnode.com/res/hashnode/image/upload/v1614435522263/VtKRIBVv-.png