I guess here's my first blog post, which was the reason I wanted to build this personal site in the first place. A project I wanted to build recently was building a digital scrapbook for me and my girlfriend. A means to look back on our memories. With our data scattered across many mediums, ie photos on WhatsApp, Messenger, Discord, Google Photos, and of course locally, I wanted a way that we could curate exactly what we remembered ourselves. Of course there's always the standard photobook/scrapbook but as a software engineer and slight data hoarder 💀 I wanted to do this in a digital medium. That way we could see the memories everywhere without concern of losing or destroying the scrapbook overtime. From this came the idea.
Not going to provide the link to the site though since I don't want to dox our relationship lol
Goals and Ideas
There were many goals with building this project.
1. Be easyish to build
Ideally this is a project that stays throughout our lives. And I know that because you would want to update the site frequently, you need to make it easy to update. Because of this I want something that I can access easily, have basic copy and paste features, and can just hide away a lot of the implementation.
2. Having the data be open/future proofing the project
One of goals of this project was to make sure our photos/info remained as open as possible. I didn't like that all of our information was already scattered across many apps so ideally I liked the idea of storing the journal to something as close as markdown/raw text as possible. That way, even if the provider suddenly changed their policies/pricing we could always migrate the journal elsewhere easily.
3. Be free or inexpensive
This one is a given.
4. Allow for collaboration (maybe realtime)
Since this was a project for me and my girlfriend, I thought it would be neat if we could collaborate on it live together.
5. Be customizable
This goal was less important but I liked the idea of being able to build new components and customize the entire experience if I so desired.
With this I came up with three solutions: Using Docusaurus, Notion, or an markdown editor such as Obsidian. Basically the tradeoffs go down the line of Notion > Obsidian > Docusaurus of the general trade offs of user controlled vs ease of use.
Ease of Use | Future Proofing | Collaboration | Customizable | |
---|---|---|---|---|
Docusaurus | 1️⃣ | 2️⃣ | 2️⃣ | 3️⃣ |
Obsidian | 2️⃣ | 3️⃣ | 2️⃣ | 1️⃣ |
Notion | 3️⃣ | 1️⃣ | 3️⃣ | 1️⃣ |
Now don't get me wrong, I think Notion is an amazing app, and I love what the Notion team has built choosing a huge emphasis on design. I think Notion would have been an ideal solution, however even though the pricing for this project was currently free the fact that the data was vaguely locked behind Notion's own functionality (though they do have an export function but I haven't tested this out that much) turned me away from it. This is during the time that I wanted to unify my entire stack and I prefer the idea of just having everything on one platform such as GitHub.
Obsidian was another thought that I had. It provides essentially a souped up version of a markdown editor which is perfect for ease of use. You can obviously host this all using Git however, I still wanted us to be able to view the journal/scrapbook on mobile and while Obsidian has a phone app, I'm pretty sure for Obsidian to provide the syncing between Desktop and mobile there is a cost.
This left Docusaurus. I work with Docusaurus at Radar and I always thought it was a nifty code base. I liked that it was essentially markdown however, you could customize it/build whatever component you liked to your React heart's content. In fact this very site is also built using Docusaurus as another good feature of Docusaurus is this very blog that I am writing on right now. Docusaurus is relatively easy due to the .mdx
nature. It's maintained by Meta and stored as essentially markdown. Through git and live share features you could have collaboration and since it has React it's by far the most customizable.
Implementation
Tech Stack
These products probably do more than just this but this is what I use them for
🦖 Docusaurus - Meta's open source documentation library allowing you to use .mdx
files which are markdown files with React
💻 GitHub - Pretty well known lol, history/hosting the project/collaboration.
🔺 Vercel - Easy way to host various projects including Docusaurus. You can also deploy using GitHub to make the stack even smaller but deploying via Vercel was a lot easier.
Now I know one of my main points in my goals was not to be tied down to any provider yet here I am using both GitHub and Vercel however, I was more okay with this as obviously I'm just using git, and any static site provider which there will always be more.
General Build
I don't claim to be a Docusaurus expert so there is probably a few better things to do.
For the most part, I just followed along to the tutorial when building the site. I customized things such as the favicon, colours, and home page. I deleted the blog portion as that was unnecessary and also used .scss
instead of just .css
.
src/custom.scss
:root {
--ifm-color-primary: #FF2A6B;
--ifm-color-primary-dark: #CC2255;
--ifm-color-primary-darker: #7F1535;
--ifm-color-primary-darkest: #7F3B50;
--ifm-color-primary-light: #FF77A0;
--ifm-color-primary-lighter: #F2ACC6;
--ifm-color-primary-lightest: #F2C2CF;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
For deploying I just followed along to the deploying to vercel docs which automatically deploys per each commit.
Some Cool Components
Of course since this is purely React you can build some pretty cool components that Notion or Obsidian don't really have.
Polaroid
For example a common feature of scrapbooks are polaroid photos place haphazardly around. These can be achieved pretty easily just with some padding and some box shadow. Allowing the user to pass in a transform makes the component customizable.
src/css/polaroid.scss
@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap');
.Polaroid {
width: 350px;
height: 450px;
background: white;
padding-top: 15px;
box-shadow: 0px 0px 30px #00000038, 0px 0px 10px #00000012;
position: absolute;
z-index: 10;
@media (max-width: 800px) {
scale:0.55;
}
.text {
padding-left: 15px;
padding-right: 15px;
font-family: 'Caveat', cursive;
margin-top: 8px;
text-align: center;
font-size: x-large;
}
p {
margin: 0;
}
img {
height: 370px;
width: 320px;
object-fit: cover;
}
}
src/components/Polaroid.jsx
import React from 'react';
const Polaroid = ({ transform, text, children }) => {
return (
<div className="Polaroid" style={{transform: transform}}>
{children}
<div className="text">
{text}
</div>
</div>
);
};
export default Polaroid;
home/2022.mdx
import Polaroid from "../../../../src/components/Polaroid.jsx";
<Polaroid
text={"Plane flight to London"}
transform={"rotate(-2deg) translate(750px, -200px)"}
>
![](image-1.png)
</Polaroid>
Stickers
Another common element are stickers. These are a lot more complicated to build than you may think. Basically, how I wanted to build a sticker was applying a white border, and then a shadow around the element.
However this is super non trivial. I thought there would be a css effect which just places the border around the already pre-cropped image, however it just places a border around the "rectangle" of the image. You can specify a border yourself, but that seemed non trivial to do. The sort of jank solution I came up with is creating 3 separate copies of the image. At the back you have the shadow scaled to 1.13, with a lower opacity and a brightness zero filter. Then, you have the white outline, which is scaled to 1.1, and has a inverted brightness filter to make it white. Finally, you have the actual image. It's not a perfect solution but it works well enough for me to be satisfied.
Similarly you can pass in the transform to place it as desired.
Sticker.scss
.Sticker {
p {
position: absolute;
z-index: 3;
}
.outline {
p {
filter: brightness(0) invert(1);
scale: 1.1;
z-index: 2;
}
}
.shadow {
p {
opacity: 0.15;
scale: 1.13;
z-index: 1;
filter: brightness(0%);
}
}
}
Sticker.jsx
import React from 'react';
// General format
{/* <Sticker>
![](image-49.png)
<div className="outline">
![](image-49.png)
</div>
<div className="shadow">
![](image-49.png)
</div>
</Sticker> */}
const Sticker = ({ transform, children }) => {
return (
<div className="Sticker" style={{transform: transform}}>
{children}
</div>
);
};
export default Sticker;
Spotify Embed
An easier one, that can't be emulated easily physically is embedding songs that were important to us around that period of time.
home/2022.mdx
<iframe
src="https://open.spotify.com/embed/track/32iNr3J93tqFkxaMYwdRYi?utm_source=generator"
width="100%"
height="352"
frameBorder="0"
allowfullscreen=""
allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
loading="lazy"
>
</iframe>
Carousel
I can't take credit for the carousel but I basically adapted this CodePen I found online into it's own React component
These are just some of the components I used to make our scrapbook feel more alive, however the possibilities really are endless
Thoughts
I definitely do have some gripes about the projects as with any project. I notice that when I build out the photos I constantly want to be adding stickers and carousels and other things to make it look nicer. While I made it as easy as possible with just wrapping the component it's still a little bit of a tedious process. Ideally a drag and drop user interface would be the best, however those mostly only exist in WYSIWYG editors. Maybe I'll think of some way in the future to make this process feel even more streamlined.
I also have some future ideas I have to put onto the site. I like the idea of placing a map of all the places we've been on the journal. Whether this be embedding a Google my map, or building on the components using some combination of open source mapping repos
I also like the ideas of having videos, as I think a video captures feelings that photos don't but that would imply that I get comfortable with shooting video first.
As an aside, overall I like the idea of having this blog. It incentivizes me to build more projects and learn more and communicate and story tell better. I liked in this blog post I have the room to talk about the how and why of implementations and I hope I can find more things to talk about in the future (and maybe some stuff that is not engineering specific).