Daily Uplift: A Mindful PWA for Affirmations

Overview

Daily Uplift is a lightweight Progressive Web App (PWA) that delivers a single daily affirmation. The idea came from two things. First, I had just lost access to my Google developer account. I had been working on a similar motivational quotes app, but never got the chance to fully release it. When my account lapsed, I started looking into ways to build outside of the app store. Simply put, I wanted something faster, easier to maintain, and more open.

Second, I was frustrated with the state of mental wellness apps. Many of them on the app store are cluttered with ads or locked features. I understand the business side of it, but I also think some things don't need to be monetized. Sometimes people just need a little encouragement without strings attached.

I started doing some research and discovered that PWAs could help me achieve what I had in mind. That’s how Daily Uplift came to life.


UX + Design Decisions

  • Minimal friction: Just one screen, one purpose. The affirmation appears immediately, without any navigation required.

  • Theme toggle: A simple light/dark switch so you can choose what feels easiest on your eyes.

  • Barebones: The UI is stripped down to the essentials. The typography carries the weight, and the layout is made for mobile first.

Design and Development Challenges

One of the biggest hurdles was handling the PWA installation flow. I wanted users to have a smooth, one-tap install experience with a custom button, but browsers don’t all play by the same rules. Chrome made it easy, but Firefox and others don’t support the same prompts. After some trial and error, I settled on showing or hiding the install button based on user interaction and browser capabilities, and simply guiding Firefox users to manually add the app via their menu. It’s not perfect, but it keeps the experience clean and avoids confusion.

Firefox Add to Home Screen Feature.

Another ongoing challenge was designing for different screen sizes. Even with a simple layout, minor tweaks were needed to make sure the app looked balanced on mobile devices without extra clutter or awkward spacing. It’s a small detail, but important for a calm, distraction-free user experience.

These challenges taught me a lot about balancing technical limits with design goals and how important it is to know when to keep things simple rather than over-engineer a solution.

Core Features and Implementation

Keeping Affirmations Fresh

To ensure affirmations don’t repeat, I store the most recent message in localStorage and cycle through unused ones until all have been seen. This gives each session a sense of freshness and entices users to come back the next day.

const generateAffirmation = function() {
    let usedAffirmations = JSON.parse(localStorage.getItem("usedAffirmations")) || [];
    let newAffirmationIndex;

    if (usedAffirmations.length === affirmations.length) {
        usedAffirmations = [];
    }

    do {
        newAffirmationIndex = Math.floor(Math.random() * affirmations.length);
    } while (usedAffirmations.includes(newAffirmationIndex));

    usedAffirmations.push(newAffirmationIndex);
    localStorage.setItem("usedAffirmations", JSON.stringify(usedAffirmations));
    localStorage.setItem("affirmationIndex", newAffirmationIndex);
    localStorage.setItem("lastVisited", new Date().toDateString());

    return newAffirmationIndex;
}

Designing for Comfort

One subtle but handy feature I added is that the app remembers users’ theme preferences using localStorage, so it always looks the way they like when they open it.

const loadSavedTheme = function() {
    const savedTheme = localStorage.getItem("theme");

    if (savedTheme === "light") {
        document.body.classList.add("light-mode");
        document.body.classList.remove("dark-mode");
        themeToggle.classList.replace("fa-sun", "fa-moon");
    } else {
        themeToggle.classList.replace("fa-moon", "fa-sun");
    }
}

Custom Install Flow

The snippet below hides the install button if the user has already dismissed the prompt. Since I’m using a custom button instead of the browser’s built-in one, this helps avoid showing the install option repeatedly and keeps the experience straightforward.

window.addEventListener("beforeinstallprompt", function(event) {
    event.preventDefault();
    deferredPrompt = event;

    if (!isDismissed) {
        installSection.style.display = "block";    
    } else {
        installSection.style.display = "none";
    }
});

Community Affirmations

I initially invited people on LinkedIn to share their own affirmations, and I’m still keeping that form open. It’s a small way to make this app feel a little more personal and connected, letting users contribute positive messages that might brighten someone else’s day.

Submit your affirmation: Google Form

Final Takeaway

Daily Uplift isn’t about flashy features or endless options. It’s about a single moment of calm, a little boost for mental health, without distractions or noise. Building it taught me that sometimes, the best approach is to keep things simple, thoughtful, and purposeful.

Explore the Project

Try it out here: View Project
Check out the code: GitHub Repo
Watch the video: Coming soon!


— Dominique
Learning out loud, one project at a time.

0
Subscribe to my newsletter

Read articles from Dominique Thomas directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dominique Thomas
Dominique Thomas