Introducing MDSLIDE - Create Minimalistic Slide Presentations powered by Markdown. ๐
Auth0 Hackathon Submission
Hello there ๐ I'm super excited to show you my side project that I've been working on for nearly a month now.
Inspiration
After blogging for some time at Hashnode, I started to appreciate the Simple yet Powerful Markdown format.
The other day I came across this site. I loved how simple and distraction free this site is. That's when the idea of building MDSLIDE struck my mind ๐ก.
Why use a lot, when a little would do.
Introducing MDSLIDE ๐
Create Minimalistic Slide Presentations powered by Markdown!
Note: Currently Not supported for Smaller device screens.
Demo
Try the app: MDSLIDE
โจ Result
You can find the above presentation published here. You can find the option to enter presentation mode in the top right corner.
๐ Features
- โก Powered by Markdown.
- ๐ Publish your Slide Presentation.
- ๐ป Present your/published Slide presentations in Fullscreen.
- ๐จ Custom background color, font color, and fonts.
- ๐ Synced to the Cloud automatically. No need to save manually!
๐จโ๐ป Built with
- Nextjs: for building both the frontend and backend.
- Auth0: Complete User Authentication
- MongoDB: to persist data in the backend.
- Chakra UI: for building UI
- Vercel: for hosting
- Zustand: used react state management solution
- @uiw/react-md-editor: react markdown editor
- swr: for fetching data from the backend api
- react-window: to virtualize the slide navigator list
- next-pwa: make the next app a PWA
๐ฆ Planning and Building
Design
I wanted to be as agile as possible. So, I used a pen and paper to scribble the overall initial workflow, logic, and UI. I worked on iterations to improve the app.
I chose Nextjs to build the frontend and backend (as it is better for SEO). This is my first experience with Nextjs and I absolutely loved it!
I chose to use MongoDB because of its flexible Schema. The final MongoDB schema now looks like the below. I didn't have to store the user details other than his/her email as those details are being managed by Auth0.
Keeping track
I used the GitHub project feature to keep track of future features and the current feature/bug being worked on.
Coding and The Problems Faced
Authentication
I started with the authentication feature. I was mind blown by how little code I had to write to integrate a complete authentication into my application ๐คฏ
// [...auth0].ts
import { handleAuth } from "@auth0/nextjs-auth0";
export default handleAuth();
Adding just these two lines created backend APIs required to handle the authentication. Cool, isn't it?
Sync with the Cloud
Whenever some change has been made to the presentation, it has to be saved to the backend database. I created a REST API to update the presentation stored in the database. It worked! but with a gotcha. It started to overload the backend with a ton of requests.
The solution was to debounce the request. The idea is simple, if you are requesting to update the same resource and only the latest request made matters, then you try to make only the last request (in a given interval).
In Javascript/Typescript it can be done using the debounce
npm package.
npm install debounce
import debounce from "debounce";
const INTERVAL = 500;
const makeApiRequest = debounce (async () => {
await fetch("/some/url").then(r => r.json());
}, INTERVAL);
Slide Rendering
The problem is to render the slide with the same proportion in a given space (constraint width and height). In other words, the rendered Slide should look the same in any screen size or resolution.
My first attempt was to render the markdown as HTML and provide the font size and the padding dynamically based on the constraint width and height. It failed miserably :(
My Next attempt was to render the markdown as HTML to a standard size and scale it down to fit the constraint height and width. It worked perfectly!
Now the implementation renders the Slide to 1920
X 1080
size always and scales it down using the CSS transition
property and the position CSS property is set as absolute
to position the slide correctly.
In the codebase, It looks something like the below.
<Box
position="absolute"
top={-1 * 540 + slideSize.height / 2}
left={-1 * (1920 / 2) + slideSize.width / 2}
transform={`scale(${getScaleFactor(constraintSize)})`}
height={1080}
>
{/*........*/}
</Box>
The above two are a few of the interesting problems that I worked on. It's getting long, So I'll stop here.
Mistakes
- Not Testing - I postponed writing tests so long, that the amount of code that needs to be written to test all the features increased a lot. I chose to focus on improving the app rather than the spend time on writing tests. The result is that I had to test manually every time to ensure the working of the app.
โจ What's next?
- Responsive UI for smaller device screens.
- Upload custom image (Currently only external image links are supported).
- Add custom font sizes and include more fonts.
- Fork a published presentation.
- Dark Mode
- Export as pdf, .html, .pptx
Wrapping up
I had a lot of fun working on many interesting problems in this hackathon. If you want to know more about any feature, feel free to browse through the GitHub repository or make a comment in this blog post. If you like my project feel free to give it a star :)
Let's Connect
See y'all in my next blog post ๐