DEV Community

Cover image for Contributing to ChatCraft
Amnish Singh Arora
Amnish Singh Arora

Posted on

Contributing to ChatCraft

My last contribution to ChatCraft was a UI bug fix from last month, and I wrote about it and the project itself in this post. This week, I decided to revisit the project and continue contributing to some areas that I wanted to, but couldn't last time due to time constraints.

Table of Contents

 1. Table of Contents
 2. Enhancing the Sidebar
       2.1. Implementing the enhancement 👨‍💻
       2.2. Result 🎊
       2.3. Pull Request
 3. ZIndex Issue
       3.1. Pull Request
 4. Conclusion 🎇
 5. Attribution

Enhancing the Sidebar

In the original layout, the Sidebar was placed in a GridItem within the main Grid that was being used for page layout. Whenever the sidebar was toggled, that GridItem was dynamically sized to reveal the element, otherwise its width was set to 0.

Here's what the layout looked like

Sidebar Layout

And this is what the markup looked like.

ChatBase.tsx

<Grid
      w="100%"
      h="100%"
      gridTemplateRows="min-content 1fr min-content"
      gridTemplateColumns={{
        base: isSidebarVisible ? "300px 1fr" : "0 1fr",
        sm: isSidebarVisible ? "300px 1fr" : "0 1fr",
        md: isSidebarVisible ? "minmax(300px, 1fr) 4fr" : "0: 1fr",
      }}
      bgGradient="linear(to-b, white, gray.100)"
      _dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
    >
    ...
    <GridItem rowSpan={2} overflowY="auto">
        <Sidebar selectedChat={chat} />
    </GridItem>
    ...
    ...
</Grid>
Enter fullscreen mode Exit fullscreen mode

Notice how the gridTemplateColumns are being set based on the visibility of the sidebar. While this is not bad, as a user of ChatCraft, I always felt an itch whenever I had to toggle the sidebar as it displaced the rest of the content when opening.

Sidebar Old

Not only that, but on smaller widths it squished the content to its right, which wouldn't leave a good impression on the users.

Squished Content

Even though other competitors use a similar approach of displacing the content for desktop sized screens, they do handle the mobile screens in a differnt manner.

ChatGPT Example

Inspired by all this reasoning, I opened an issue to enhance the sidebar by allowing it to sit over the main content instead of pushing it away.

Implementing the enhancement 👨‍💻

I started out by planning how to add this behavior to sidebar while preserving the original Grid Layout as much as possible.

1. Changes to gridTemplateColumns

The first step was to modify the grid layout by fixing the widths assigned to grid columns.

<Grid
      w="100%"
      h="100%"
      gridTemplateRows="min-content 1fr min-content"
      gridTemplateColumns={"0 1fr"}
      bgGradient="linear(to-b, white, gray.100)"
      _dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
    >
Enter fullscreen mode Exit fullscreen mode

2. Placing Sidebar over Content

Now that toggling the sidebar didn't have any effect on sidebar column width, I started working on placing it over the main content when toggled. This involved wrapping the Sidebar component in a Box that would handle all the positioning.

<GridItem rowSpan={2} colSpan={1}>
  <Box
    position="relative"
    minWidth={"300px"}
    width={"20vw"}
    bgGradient="linear(to-b, white, gray.100)"
    _dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
    zIndex={theme.zIndices.modal}
    overflowY="auto"
    height={"100%"}
    maxHeight={"100%"}
    boxShadow={"base"}
  >
    <Sidebar selectedChat={chat} />
  </Box>
</GridItem>
Enter fullscreen mode Exit fullscreen mode

Let's break down what I did.
I set a position of relative, and a zIndex of from the default chakra theme.

Chakra Theme Z Indices

This successfully placed the content in a higher stacking order, but some improvements were needed to styling since the sidebar itself was transparent, making the content underneath visible.

Leaking content

To fix this issue, I added the following theming properties to the sidebar wrapper, so it could blend well with the rest of the page.

bgGradient="linear(to-b, white, gray.100)"
_dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
boxShadow={"base"}
Enter fullscreen mode Exit fullscreen mode

Here's the result.

Sidebar theming

The next challenge was to make the new sidebar scrollable when the content overflowed.

No Scrollbar

This was simple enough to fix, by setting the overflowY to auto.

overflowY="auto"
Enter fullscreen mode Exit fullscreen mode

And now we have the scrollbar.

Adding scrollbar

3. Adding toggle animation 🕹️

The last thing to handle was adding an open/close animation, as in its the then state, it was always visible.

It made sense to go with css-in-js approach and I came up with two keyframes animations, one for when the sidebar was opened and another when it was closed.

import { ...
  keyframes,
} from "@chakra-ui/react";

// Sidebar Animations
  const sidebarOpenAnimation = keyframes`
  0% {
    transform: scaleX(0);
  }
  50% {
    transform: scaleX(1.075);
  }
  100% {
    transform: scaleX(1);
  }
`;

  const sidebarClosedAnimation = keyframes`
  from {
    transform: scaleX(1);
  }
  to {
    transform: scaleX(0);
  }
  `;
Enter fullscreen mode Exit fullscreen mode

and added the following properties to the sidebar wrapper

transformOrigin={"left"}
transform={`translateX(${isSidebarVisible ? 0 : "-100%"})`}
animation={`${
  isSidebarVisible ? sidebarOpenAnimation : sidebarClosedAnimation
} 150ms ease-out forwards`}
Enter fullscreen mode Exit fullscreen mode

This made sure to trigger the open and close animations on the sidebar as required.

New Sidebar Animation

Sweet!
Now, one last problem was that whenever you refreshed the page, the close animation would trigger unnecessarily.

Bad Close Animation

To fix this, I had to use an additional to check to only trigger sidebar animation when it was actually triggered

const [sidebarTouched, setSidebarTouched] = useState<boolean>(false);

const handleToggleSidebarVisible = useCallback(() => {
  ...
  setSidebarTouched(true);
}, [isSidebarVisible, settings, setSettings, toggleSidebarVisible]);

<GridItem rowSpan={2} colSpan={1}>
  <Box
    position="relative"
    ...
    transform={`translateX(${isSidebarVisible ? 0 : "-100%"})`}
    animation={`${
      isSidebarVisible // If visible, trigger open animation
        ? sidebarOpenAnimation
        : // Only trigger closed animation when closed manually.
        // This is because the sidebar open/close state is persisted across refreshes
        // and may cause unnecessary animations if not handled
        sidebarTouched
        ? sidebarClosedAnimation
        : "none"
    } 150ms ease-out forwards`}
    >
    <Sidebar selectedChat={chat} />
  </Box>
</GridItem>
Enter fullscreen mode Exit fullscreen mode

I used the transform property as a fallback for when the close animation was not triggered. I had to spend a lot of time in fixing this one, but I am sure there could be a better solution for this. Feel free to share in the comments!

Result 🎊

Now that we fixed all problems with the sidebar, let's see it in action.

Sidebar in Action

Awesome!

Pull Request

All this progress, of course, was not part of a single commit.
Here's the pull request with all the converstaions and commits that went into this contribtion. It is still not merged as maintainers are not sure if they like it, will update the post when the decision is made.

Pull Request

ZIndex Issue

After working on the sidebar enhancement, I remembered there was a follow up issue from my last contribution where the model selection menu list required a higher z index.

Even though it looks a quick fix, I had to spend a while researching about the correct way assigning a z-index in such a project, that I have already discussed above.

Pull Request

After fixing the problem and testing locally, I opened another pull request which got merged fairly quickly as this was a small one.

Another Pull Request

Conclusion 🎇

In this post, I discussed about two of my latest contributions I made to ChatCraft (one tentative). Even though I thought the sidebar enhancement would be a quick one, it took quite a while to plan, implement and then debug the layout, while teaching me a couple of new things I didn't know about.
Overall, it was again a great and I would say, a fun learning experience.
Hope you liked the post and as always
Thanks for reading!

Attribution

Photo by Lautaro Andreani on Unsplash

Top comments (0)