Contributing to ChatCraft
Tags: opensource, react, frontend, webdev
Published: 2023-11-26 17:59:51

My last contribution to [ChatCraft](https://github.com/tarasglek/chatcraft.org) was a UI bug fix from last month, and I wrote about it and the project itself in this [post](https://dev.to/amnish04/no-backing-away-when-hacking-away-2h27). 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
&nbsp;1. [Table of Contents](#table-of-contents)
&nbsp;2. [Enhancing the Sidebar](#enhancing-the-sidebar)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1. [Implementing the enhancement 👨‍💻](#implementing-the-enhancement)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2. [Result 🎊](#result)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.3. [Pull Request](#pull-request)
&nbsp;3. [ZIndex Issue](#zindex-issue)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.1. [Pull Request](#pull-request)
&nbsp;4. [Conclusion 🎇](#conclusion)
&nbsp;5. [Attribution](#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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eptdu0189wtq889dmkri.png)

And this is what the **markup** looked like.

[**ChatBase.tsx**](https://github.com/tarasglek/chatcraft.org/blob/main/src/Chat/ChatBase.tsx)
```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>
```
Notice how the [gridTemplateColumns](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8io5ua9vnnila3nzje5u.gif)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/81kgb2tfqgq9axdev7ti.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/473g6ddd95qjfgfo9ykc.png)

Inspired by all this reasoning, I opened an [issue](https://github.com/tarasglek/chatcraft.org/issues/299) 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.

```tsx
<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)" }}
    >
```

**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](https://chakra-ui.com/docs/components/box/usage) that would handle all the positioning.

```tsx
<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>
```

Let's break down what I did.
I set a position of [relative](https://developer.mozilla.org/en-US/docs/Web/CSS/position), and a [zIndex](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index) of  from the [default chakra theme](https://chakra-ui.com/docs/styled-system/theme#z-index-values).

![Chakra Theme Z Indices](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bp81isxiwqcc7zhcssy9.png)

This successfully placed the content in a higher [stacking order](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context), but some improvements were needed to styling since the sidebar itself was transparent, making the content underneath visible.

![Leaking content](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uunwraj0njuc7rzduk87.png)

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.
```tsx
bgGradient="linear(to-b, white, gray.100)"
_dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
boxShadow={"base"}
```

Here's the result.

![Sidebar theming](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7ovjo3ijpkha6sxo17k.png)

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

![No Scrollbar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wptcb8wnt2kckel5ntl3.png)

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

```tsx
overflowY="auto"
```

And now we have the scrollbar.

![Adding scrollbar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9oqsb62y8zwcctt8n7p0.png)

**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](https://en.wikipedia.org/wiki/CSS-in-JS) approach and I came up with **two** [keyframes](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) animations, one for when the sidebar was opened and another when it was closed.

```tsx
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);
  }
  `;
```

and added the following properties to the **sidebar wrapper**

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

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

![New Sidebar Animation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umksnbked678kppssbq7.gif)

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

![Bad Close Animation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyn08z0ygtlw4g08840b.gif)

To fix this, I had to use an additional to check to only trigger sidebar animation when it was actually triggered
```tsx
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>
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2isbkplmbv1aewyl92v0.gif)

**Awesome!**

### Pull Request

All this progress, of course, was not part of a single commit.
Here's the [pull request](https://github.com/tarasglek/chatcraft.org/pull/300) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87nyt2ypzxw2t1gwpszl.png)

## ZIndex Issue

After working on the **sidebar enhancement**, I remembered there was a [follow up](https://github.com/tarasglek/chatcraft.org/issues/273) issue from my [last contribution](https://github.com/tarasglek/chatcraft.org/pull/271) 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]([default chakra theme](https://chakra-ui.com/docs/styled-system/theme#z-index-values)) 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](https://github.com/tarasglek/chatcraft.org/pull/301) which got merged fairly quickly as this was a small one.

![Another Pull Request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7dudtko4oqed81dx23g.png)

## Conclusion 🎇

In this post, I discussed about two of my latest contributions I made to [ChatCraft](https://chatcraft.org/c/zcHECojlPNhAGfII0ossC) (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 <a href="https://unsplash.com/@lautaroandreani?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Lautaro Andreani</a> on <a href="https://unsplash.com/photos/a-computer-screen-with-a-logo-on-it-xkBaqlcqeb4?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>