tmp.spacet.me devlog part 1
Tags: dohackathon
Published: 2020-12-27 15:04:45

---
title: tmp.spacet.me devlog part 1
published: true
description: 
tags: dohackathon
series: tmp.spacet.me devlog
canonical_url: https://notes.dt.in.th/20201216T165355Z3976
---

This is part of DigitalOcean App Platform Hackathon. The project I want to build is a web-based local file storage.

**Why?** Nowadays, there are so many web-based tools that work with files, such as:

- [Squoosh](https://squoosh.app/ 'Squoosh') image compressor
- [Photopea](http://www.photopea.com/ 'Photopea | Online Photo Editor') photo editor
- [gifcap](https://gifcap.dev/ 'gifcap') screen recorder
- [Diagrams.net](https://www.diagrams.net/ 'Diagram Software and Flowchart Maker') diagram and flowchart maker
- [vox.spacet.me](https://vox.spacet.me/) voice recorder (I made this one)
- [json.spacet.me](https://json.spacet.me/) JSON viewer (I made this one too)
- [instant.io](http://www.instant.io/ 'Instant.io - Streaming file transfer over WebTorrent') streaming file transfer over WebTorrent
- [ShareDrop](https://www.sharedrop.io/ 'ShareDrop') file transfer over WebRTC
- [StackEdit](https://stackedit.io/ 'StackEdit – In-browser Markdown editor') and [Dillinger](https://dillinger.io/ 'Online Markdown Editor - Dillinger, the Last Markdown ...') Markdown editor
- [Carbon](https://carbon.now.sh/ 'Carbon | Create and share beautiful images of your source code') code image generator
- other specialized tools that I create for specific situations

**Now comes my pain point:** When I want to use multiple apps together, I have to go through a lot of Download-then-Upload experience, and thus my Downloads folder fills up with many temporary files.

**Many apps are inconsistent in how they handle input/output.** To get data into a web app, you can use the usual [File open][openfile] dialog (via `<input type="file">`), the [Drag and Drop API][dnd], the [Clipboard API][pasteimg], and the [Share Target API][sharetarget]. To get data out, there's `<a>`'s [download][dlattr] attribute, [DownloadURL DataTransfer type for dragging files out of the browser][downloadurl], the [Clipboard API][clipboard], the [Web Share API][webshare], and the classic "Save Link As", "Save Image As" and "Copy Image" menu items.

Most apps support only a subset of these APIs. Some apps also have integrations with cloud storage services like Google Drive, but many don't. [Paul Kinlan (2017), Web sites as unintended silos: The problem with getting data in and out of the web client](https://paul.kinlan.me/unintended-silos/) is an interesting read.

[openfile]: https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications 'Using files from web applications - Web APIs | MDN'
[dnd]: https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications#Selecting_files_using_drag_and_drop 'Selecting files using drag and drop | Using files from web applications - Web APIs | MDN'
[pasteimg]: https://stackoverflow.com/questions/6333814/how-does-the-paste-image-from-clipboard-functionality-work-in-gmail-and-google-c 'javascript - How does the paste image from clipboard functionality work in Gmail and Google Chrome 12+? - Stack Overflow'
[clipboard]: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API 'Clipboard API - Web APIs | MDN'
[sharetarget]: https://web.dev/web-share-target/ 'Receiving shared data with the Web Share Target API'
[dlattr]: https://www.w3schools.com/tags/att_a_download.asp 'HTML a download Attribute'
[downloadurl]: https://webplatform.news/issues/2017-07-26 "'DownloadURL' for drag and drop | Web Platform News"
[webshare]: https://web.dev/web-share/ 'Integrate with the OS sharing UI with the Web Share API'
[message]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage 'Window.postMessage() - Web APIs | MDN'

Now the web has the [`postMessage`][message] API that lets web applications throw data around among different websites. So, I'm pondering about the idea of having a web-based portal, a hub of sort, that takes care of importing/exporting files using all the available Web APIs...

![](https://static.dt.in.th/uploads/2020/12/18/tmp-core.png)

...and integrates with all the different apps.

![](https://static.dt.in.th/uploads/2020/12/18/tmp-extension.png)

**It should be extensible.** Of course I'm lazy and I won't be integrating all the different apps myself. Instead, integrations will be provided through an extensions system. (In the above picture, the text in blue are to be implemented as an extension rather than as a core feature.)

If all goes according to the plan, extensions will be HTML pages and communicate with this app through the `postMessage` API. This way new extensions can be written using any tool, and added to the app without having to touch the main app. This is a nice opportunity to learn about "[micro-frontends][micro]."

**Deployment structure:** The main app will be deployed as a Static Site application, while extensions may be deployed as separate apps, and some of them might require a database. This is also an opportunity to try out App Platform services such as [DigitalOcean Managed Databases][db].

[micro]: https://martinfowler.com/articles/micro-frontends.html 'Micro Frontends - Martin Fowler'
[db]: https://www.digitalocean.com/products/managed-databases/ 'Managed Database - DigitalOcean'

**Project name:** This is one of the hardest thing in computer science. I intended it to be a place where I temporarily put files in. For the lack of better name, I just called it "tmp".

**Project setup:** I applied for a DigitalOcean credit, created a [Next.js][nextjs] static app, set up [Tailwind][tailwindnext], [TypeScript][nextts] and [next-pwa][next-pwa]. I deployed the app to DigitalOcean App Platform and it just works (except the part where I waited for the spinner to finish. By the way everyone, please don't add a spinner if you will not also automatically refresh it.)

[nextjs]: https://nextjs.org/ 'Next.js by Vercel - The React Framework'
[nextts]: https://nextjs.org/docs/basic-features/typescript 'Basic Features: TypeScript | Next.js'
[tailwindnext]: https://tailwindcss.com/docs/guides/nextjs 'Install Tailwind CSS with Next.js - Tailwind CSS'
[next-pwa]: https://github.com/shadowwalker/next-pwa 'shadowwalker/next-pwa: Zero config PWA plugin for Next.js, with workbox'

![](https://static.dt.in.th/uploads/2020/12/16/spin.gif)

**Implementating the core features:** I then implemented the basic import/export functionalities using various Browser APIs and npm packages:

- [Clipboard API][clipboard]
- [Web Share Target API][sharetarget]
- [DownloadURL for Drag and Drop][downloadurl]
- [window.open()][windowopen]
- [downloadjs][downloadjs]
- [Browser-NativeFS][browser-nativefs]

File data and all other data will be stored inside IndexedDB, through the help of [PouchDB][pouch]. Querying data from the local database in the React app is done using [React Query][query].

[downloadjs]: https://www.npmjs.com/package/downloadjs
[windowopen]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open
[browser-nativefs]: https://www.npmjs.com/package/browser-nativefs
[pouch]: https://pouchdb.com/
[query]: https://react-query.tanstack.com/

After a few days of coding, most of the core features are implemented.
Now, for example, I can share photos from Google Photos directly to tmp.
Within tmp, I can view the image (using the browser's built-in image viewer) and share it to other apps.

![](https://static.dt.in.th/uploads/2020/12/18/tmp-sharing.png)

Right now the UI is very unpolished, and the rename functionality has not yet been implemented. But there are more important stuff to do first. The elephant in the room -- `postMessage`-based integrations.

**Open source contributions:** Along the way I sent some quick PRs:

- [shadowwalker/next-pwa#132](https://github.com/shadowwalker/next-pwa/pull/132 'Print errors on webpack build failure by dtinth · Pull Request #132 · shadowwalker/next-pwa') improves error messages

**Next up:** I will probably be implementing a first iteration of a `postMessage`-based integration system. It will integrate with an external tool I have already created. Meanwhile, the source code is on GitHub at [dtinth/tmp](https://github.com/dtinth/tmp).