Creating a reddit client that looks like gmail: Introducing GmailKit
GmailKit is an open source reddit client that looks like gmail built in 4 hours. It’s built with AlpineJS and TailwindCSS.
Introduction
While I was scrolling TikTok, I saw a video about a cool reddit client that looks like Outlook, called Msoutlookit. I thought it was a really cool idea, so I decided to build my own version of it, but instead of Outlook, I will instead use Gmail as the base design.
Getting started
I decided my stack for this simple project:
- AlpineJS as a JavaScript framework, because it's lightweight and simple, perfect for this project.
- TailwindCSS as a CSS framework, since it's been my go-to CSS framework for the past few years.
- Reddit API as the API for making requests to reddit.
- GitHub Pages as the hosting platform, since it's free and easy to use.
I started by creating the barebone of the index.html
file. I used TailwindCSS's Play CDN to quickly get started with TailwindCSS. I don't recommend using this in production, but it's perfect for prototyping and small projects like this one. I installed the aspect-ratio
and line-clamp
plugins, since I will be using them later on.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Inbox - GMailKit</title>
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
<script src="https://cdn.tailwindcss.com?plugins=aspect-ratio,line-clamp"></script>
<script defer src="https://unpkg.com/alpinejs"></script>
<script>
const GmailKit = () => ({
// This is the state of the app.
});
</script>
</head>
</html>
As you can see, there is a GmailKit
function that returns an object. This is where we will store all of our state and functions. I also added the defer
attribute to the alpinejs
script tag, so that it will load after the GmailKit
function.
Getting the data.
Reddit has a very permissive CORS policy, allowing us to call fetch
directly from the browser. This means that we don't need to use a proxy to make requests to the Reddit API.
I started by setting up the state of the GmailKit
function.
const GmailKit = () => ({
subreddits: ["gaming", "pics", "askreddit", "jokes", "funny", "iama", "wtf"],
currentSubreddit: "all",
subredditLoaded: false,
subredditItems: [],
init() {
this.changeSubreddit(this.subreddits[0]);
}
changeSubreddit(subreddit) {
this.currentSubreddit = subreddit;
this.fetchSubreddit(subreddit);
},
fetchSubreddit(subreddit) {
this.subredditLoaded = false;
this.subredditItems = [];
fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then((response) => response.json())
.then((data) => {
this.subredditItems = data.data.children;
this.subredditLoaded = true;
});
},
});
And this for the view:
<main x-data="GmailKit">
<template x-for="post of subredditItems">
<p x-text="JSON.stringify(post)"></p>
</template>
</main>
Yay! We got a list of posts from the gaming
subreddit. The items themselves contain the author, the subreddit, the title, the thumbnail, the number of comments, the number of upvotes, the creation date, and other information. We only care about the author, the title, and the creation date for the post list.
Now, let's implement the logic to fetch the comments.
const GmailApp = () => ({
// ...
postContent: null,
viewedPosts: {},
postContentComments: [],
// ...
// ...
fetchPost(postData) {
this.postContent = postData;
this.fetchPostComments(postData.id);
this.viewedPosts[postData.id] = true;
},
fetchPostComments(postId) {
this.postContentComments = [];
fetch(
`https://www.reddit.com/r/${this.currentSubreddit}/comments/${postId}.json`
)
.then((response) => response.json())
.then((data) => {
this.postContentComments = data[1].data.children;
});
},
});
Great! Now we can fetch the comments for a post. The comments are also stored in the same format as the posts.
Creating the UI
Gmail has a pretty interesting UI design. At first glance, it looks very simple: appbar, sidebar, list of emails, and the email content. But if you look closely, there are a lot of details that make it look good.
While I was developing it, I made the mistake of assuming it was just 4 columns: appbar, drawer, list of emails, and email content. The base of the layout however is actually wrong: there is an appbar that integrates with a sidebar on the "toggle button", and the GMail logo is always visible (even when you hide the drawer).
I actually decided to stick to the layout that I was making, since I didn't want to spend too much time on this project. I copy-pasted the svg and the icons's urls icons from the Gmail app, picked really similar colors, and I was done.
I decided to not implement the "search" feature, since it's not really needed for this project. I also decided to allow the user to add subreddits with the "Compose" button, and allow them to change subreddits by clicking on the subreddit name in the list of tags above the Tags. Here I encountered an issue: how do I choose the icons? I decided to use the icons from the Gmail all in order, and then to default to the "inbox" icon for the rest of the subreddits.
For the post's list, I decided to put the author's name and the title of the post, that can break and show an ellipsis if it's too long using the line-clamp
utility. I also decided to put the creation date of the post in a local format.
Implementing the comment section.
From the absolute beginning I knew this would have been the hardest part, especially since I put myself a very short and strict deadline. I decided to make the comment section like the history section in the Gmail app. I didn't make the comments collapsible, and to be quite honest, I don't remember if it even shows the replies to the comments.
To give the history effect to the comments, I just put a border of 2 pixels on the side of the comment and called it a day. That didn't look very good, but the deadline made me accept it.
Other stuff I implemented
I decided to add the UI elements that would not make much sense for reddit to have but that were present in Gmail: I decided to put the "to me", the user's profile picture if present or the old default gmail default profile picture, and the action icons. I also decided to color the posts that the user has already seen.
Overall, during the time that I was making it, at a certain point I forgot which one was the real Gmail app and which one was the fake one, which boosted my confidence in the project.
After the deadline was over, I noticed that I actually forgot to add the buttons on top of the comment section like the ones gmail has, but I only noticed that after a side-by-side confrontation. I also noticed that it's not usable on mobile, but I didn't really care about that, since it's been a web clone of gmail from the very beginning.
Conclusion
Overall, I'm pretty happy with the result. I learned a lot about the Gmail app, I made a cool and funny project during the weekend, and I got to learn a bit of Reddit's API.
If you want to try it out, you can access it on https://niturobert.github.io/gmailkit/
Here is a video of the result: