Ali Zahid

Prodo

Prodo is a name I used for an SMS API I built years ago. But that never panned out, so I repurposed it when I built a snippet manager last weekend
September 29, 2019
Prodo

So far, I've kept my snippets in the macOS / iOS Notes app. I never realized the collection would grow so big that I'd need a proper app. After I got disappointed by the options available, I decided to take a crack at it myself.

From the offset, I knew this had to be a primarily desktop app. In the past, I've built some stuff with Electron but never finished or published anything. So I was excited to finally make something with Electron that I'd get to publish and use myself. The final product, however, runs well in the browser, too.

Setup

I started with create-react-app and added Electron to it. It took some effort to figure out the different nuisances of Electron, but I have a decent setup working now.

electron-window-state

I'm using electron-window-state to manage my app's window state. It remembers my window's size and position, so I don't have to resize and reposition it every time I open the app.

show: false

Here's an interesting piece I found during my research; there's a small delay between the window opening and the React bundle loading and rendering. A Medium article suggested I don't show the window until it's ready. I have loading states for different parts of the app, but the solution should make it seem more like a native app than an Electron app. I guess we'll find out more when I bundle the app and run it.

Firestore

I'm using Firebase for authentication and data storage. It's essential to ensure proper rules are in place, or anyone can mess around with the data. Here are my settings. Feel free to take inspiration.

rules_version = '2';

service cloud.firestore {
match /databases/{database}/documents {
match /snippets/{snippetId} {
allow read, update, delete: if request.auth.uid == resource.data.uid;
allow create: if request.auth.uid != null;
}
}
}
rules_version = '2';

service cloud.firestore {
match /databases/{database}/documents {
match /snippets/{snippetId} {
allow read, update, delete: if request.auth.uid == resource.data.uid;
allow create: if request.auth.uid != null;
}
}
}

Design

I've kept the design very minimal to focus on the content.
I've kept the design very minimal to focus on the content.

Each snippet has three main properties right now; title, content, and tags. All fields are searchable so that you can find the snippet easily.

With 30 snippets, the list is very performant. Mostly because it's the list item is just a link. Maybe in the future, I can add react-window for a virtualized list if it grows beyond a certain number where performance is affected.

The VS Code dark theme inspires the colors.

Features

  • Login or register with an email and password. Or anonymously. You can link your account later with an email and password, so you don't lose your data if you logout or remove the app
  • Create snippets with a title, content, and tags
  • The tags only allow lowercase alphabets, numbers, and hyphens to keep things simple. Will this be controversial?
  • Search snippets; lookup by title, content, or tags, all at once
  • CRUD for snippets, obviously
  • A collapsible sidebar so you have more space for your content
  • Electron features such as dialogs that fallback gracefully in the browser

Todo?

  • Add end-to-end encryption cause it's 2019
  • Look into improving performance by reducing re-renders
  • Prepare Electron for packaging
  • Test with more snippets and an extensive list

Updates

One

I've added end-to-end encryption. When you register, you get a unique key that stays locally and never reaches the server, and is used to encrypt all your snippets. I tried a keyless solution by encrypting with other fields, but they are available on the server. While that means your data is secure, I can still decrypt and view it because I can access Firestore and know the hashing mechanism. So, in the end, the best method was to use a key you can save so I can never see your data.

Two

I built the app with Electron, and it's a whopping 400MB! I need to play around with the config to bring down the app's size since it's ridiculous for the app's complexity. Perhaps I can load the webpage in Electron remotely? I think the main culprit is Firebase. Maybe I can switch to the CDN version instead of a locally installed dependency?

As usual, all the projects I build are open source. You can find the Prodo source code on GitHub. You can also take it for a spin.