A tiny, fast web app to keep your favourite quotes and your own thoughts — private to you, backed up as PDF.
- ✅ Works immediately — open it with no login, no setup, and even offline. Entries are saved on your device (local mode). It works the same before and after you deploy it.
- 🔐 Optional Google sign-in — when you add Firebase (below), each person sees only their own
entries, synced across devices. Sign in later and it offers to move your on-device entries into your account.
Google's own button runs on the page, so its account chooser says "to continue to your site"
rather than naming a
…firebaseapp.comaddress. - 🗂️ Two spaces in one app — ❝ Ponder (quotes & thoughts) and 🌿 Healthy Tips — each with its own database and its own tags. Every entry has a date added, an optional source, and a tag.
- 🌐 English / Korean — one click switches the whole interface (your saved entries are never translated).
▶️ Inline media — paste a YouTube / Vimeo / Instagram link or a direct image URL and it becomes a click-to-play preview. The PDF export even embeds the thumbnails.- 🔀 Shuffle one random entry at a time, and ⧉ Find duplicates to clean up near-identical notes.
- 🌙 Dark / light mode (defaults to dark), 📱 installable (PWA — add to home screen).
- ⚙️ Settings — choose which space the app opens on (Ponder, Healthy Tips, or whichever you used last) and which ordering a space opens in. Both are remembered on your device.
- ⚡ Very light & fast — no framework, no web fonts, works on low-spec CPUs with no GPU. The whole app shell is ~27 KB gzipped; Firebase is only downloaded if you actually configure it.
- 📶 Low-internet friendly — entries are cached; reloads are instant even with thousands stored.
- 📄 Export everything as a PDF for backup — in any script you write in, Korean included, and however long your entries are.
- 🆓 Runs 100% free: static files on GitHub Pages + Firebase free tier (which, unlike some alternatives, does not pause when you don't use it — good for a backup app).
Don't want accounts/sync at all? You can skip the whole Firebase setup and just use it in local mode. Only set up Firebase if you want Google login + syncing across devices.
| ⚙️ Settings | 🌿 Opens on Healthy Tips |
|---|---|
![]() |
![]() |
| 🔀 Shuffle | ☀️ Light mode |
|---|---|
![]() |
![]() |
On a phone the top bar stacks and the toolbar goes full width:
| 📱 Phone | 📱 Settings on a phone |
|---|---|
![]() |
![]() |
| File | What it is |
|---|---|
index.html, styles.css, app.js |
The whole app |
firebase-config.js |
Paste your Firebase keys here (only needed for login/sync), plus the OAuth client id that decides what Google's sign-in prompt calls your site |
firestore.rules |
Security rules (copy into Firebase) so users can't see each other's entries |
favicon.svg, icon-192.png, icon-512.png, apple-touch-icon.png |
App / tab / home-screen icons |
site.webmanifest |
PWA manifest (makes the app installable) |
og-image.jpg |
Social share / link-preview image |
404.html |
Friendly, themed "page not found" page |
robots.txt, sitemap.xml |
SEO — let search engines index the site |
version.json, bump-version.sh |
Auto-update: open tabs notice a new deploy and offer to reload |
serve.py |
Optional local dev server (no-cache, so edits show on refresh) |
docs/screenshots/ |
The images used in this README |
README.md |
This file |
- Go to https://console.firebase.google.com and click Add project. Give it any name. You can turn Google Analytics off.
- In the left menu: Build → Authentication → Get started.
- Open the Sign-in method tab → click Google → toggle Enable → pick a support email → Save.
- Left menu: Build → Firestore Database → Create database.
- Choose a location near you → start in Production mode → Enable.
- In Firestore Database, open the Rules tab.
- Delete what's there and paste the contents of
firestore.rules. - Click Publish.
These rules are what keep every user's quotes private to them.
- Click the ⚙️ gear (top-left) → Project settings → scroll to Your apps → click the web icon
</>. - Give it a nickname → Register app (you do not need Hosting).
- Firebase shows a
firebaseConfig = { ... }block. Copy those values intofirebase-config.js, replacing theYOUR_...placeholders.
These keys are safe to commit to GitHub — they only identify your project, and the security rules protect your data.
Skip this and sign-in still works — but Google's account chooser will say
"to continue to your-project.firebaseapp.com", because that's the address Firebase's popup
hands off to, and a project id is the only thing Google has been given to name.
The fix is to let Google's own button run on the page, so the browser never leaves the site and Google names the site it's actually on. That needs the project's OAuth web client id:
- Go to https://console.cloud.google.com/apis/credentials and pick your Firebase project.
- Under OAuth 2.0 Client IDs, open "Web client (auto created by Google Service)" — Firebase created it for you back in step 2.
- Copy the Client ID into
googleClientIdinfirebase-config.js. - On that same page, under Authorised JavaScript origins, click Add URI and add every origin
you serve the app from —
https://yourname.github.io, and your custom domain if you have one. (http://localhostis always allowed, so local testing needs nothing.)
Step 4 is not optional if you did step 3. Firebase's Authorized domains list is a separate thing and does not grant this — an origin missing here means Google's button quietly refuses to sign anyone in, and the app falls back to the popup (i.e. back to the ugly name).
A client id is public and is meant to be read out of the page; its only protection is that it refuses to work from an origin you haven't listed, which is exactly what step 4 sets up.
Because the app uses ES modules, open it through a small local server (not by double-clicking the file):
# from inside this folder
python3 serve.py # visit http://localhost:8080
# (or plain: python3 -m http.server 8000)serve.py disables caching so your edits always show up on refresh. localhost is already an
allowed sign-in domain in Firebase, so Google login works there too.
- Create a new GitHub repository and push these files to it:
git init git add . git commit -m "Quotes app" git branch -M main git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git git push -u origin main
- On GitHub: Settings → Pages → under Build and deployment, set Source = Deploy from a branch, Branch = main, folder /(root) → Save.
- Wait ~1 minute. Your site will be at
https://YOUR_USERNAME.github.io/YOUR_REPO/.
Google sign-in only works on domains you approve, in two separate places:
- Firebase → Authentication → Settings → Authorized domains → Add domain →
YOUR_USERNAME.github.io→ Add. (Required — this is what lets the app sign in at all.) - Google Cloud → APIs & Services → Credentials → your web client → Authorised JavaScript
origins → add
https://YOUR_USERNAME.github.io. (Only if you did step 6 — this is what keeps Google's prompt naming your site.)
Done — open your GitHub Pages URL and sign in. 🎉
- Switch between ❝ Ponder and 🌿 Healthy Tips with the slider at the top-left.
- Type an entry, add a source and pick a tag, hit Add (or
Ctrl+Enter). - Paste a YouTube / Vimeo / Instagram link or a direct image URL to embed playable media.
- Search, sort (newest / oldest / by tag), 🔀 Shuffle, or ⧉ Find duplicates.
- ⬇ Export PDF downloads a backup of everything in the current space (with media thumbnails).
- 🌐 toggles English / Korean; 🌙 / ☀️ toggles dark / light.
- ⚙️ opens Settings: Open on start (Last one I used / ❝ Ponder / 🌿 Healthy Tips) and Default sort (newest / oldest / by tag). The sort also applies each time you switch space, so you're never dropped back into newest-first when you didn't ask for it.
Settings are stored per browser, in
localStorage— they aren't synced through your account, so each device (and each browser) keeps its own preference.
Open app.js and edit the SPACES object near the top. Each space defines its collection
(Firestore), localKey, and its own tags. Add another entry to SPACES (and to SPACE_ORDER)
and it appears in the nav automatically. Korean labels for tags live in the I18N dictionary
(the "tag.<name>" keys) just below.
Firebase's free "Spark" plan gives ~50,000 reads and ~20,000 writes per day and 1 GB storage — far more than a personal quotes collection needs.






