My collection of PWAs with fixes and modifications.
The Live Demos work in any broswer (mobile or desktop). The apps can also be installed on a mobile device. This gives the app an icon on the home screen and allows it to work in offline mode.
- View the Live Demo in your mobile browser
- Android (Chrome): open the menu (three dots), then Add to Home screen, and Install
- A VPN may be required for some regions
- iOS (Safari): press the share button (box with up arrow), then Add to Home Screen
- Keep Open as Wep App selected
A PWA that converts temperatures.
- Live Demo
- App files
- Upstream source: MicrosoftEdge/Demos and Microsoft Learn
A basic app for tracking menstrual cycles.
- Live Demo
- App files
- Upstream source: mdn/pwa-examples
- Local fixes
- Manifest
- Use site subdirectory (
./) as starting URL for the app - Upstream's live demo used site root (
/), giving a 404 for app installed from GitHub pages
- Use site subdirectory (
- Service worker
- Look for files in app directory (
./) instead of site root (/) - Add manifest and app icon to cache to improve installability
- Look for files in app directory (
- See this comment for details
- Manifest
- This app uses local storage to record periods.
- On Android, local storage is shared between the browser and installed app. So, if you enter a period in CycleTracker in the browser, it will also show up in the installed app.
- On iOS, local storage for the browser and installed app are separate. Data entered in one won't appear in the other.
An upgrade of CycleTracker to use Supabase for storage and authentication. The database schema was developed with the AI assistant in Supabase. The application code was developed with Cursor.
Details from Cursor
-
Email auth UI (in
index.html):- Added a small
#authsection above the period form with:auth-form(email + password fields, “Sign in / Sign up” button)sign-outbutton (hidden when signed out)auth-statusmessage area.
- Added a small
-
Supabase config + client loading (in
index.html):- Added a global config object you can edit with your real project details:
window.CT2_SUPABASE_CONFIG = { url: "https://YOUR-PROJECT-ref.supabase.co", anonKey: "YOUR-PUBLISHABLE-OR-ANON-KEY", };
- Included Supabase JS v2 via CDN before
app.js:<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script> <script src="app.js" defer></script>
- Added a global config object you can edit with your real project details:
-
Supabase initialization and auth handling (in
app.js):- New globals and wiring:
- Auth elements:
authFormEl,authEmailInputEl,authPasswordInputEl,signOutButtonEl,authStatusEl. - Supabase state:
let supabaseClient = null; let currentUserId = null;.
- Auth elements:
initSupabase():- Reads
window.CT2_SUPABASE_CONFIG, createssupabaseClient, fetches existing session, and subscribes toauth.onAuthStateChange.
- Reads
handleEmailAuth(email, password):- Tries
signInWithPassword; on failure, falls back tosignUp. - Updates
auth-statusmessages accordingly. - Calls
onAuthSessionChanged(session)when a session is available.
- Tries
onAuthSessionChanged(session):- On sign-out: clears
currentUserId, hides sign-out button, shows “Signed out”. - On sign-in: sets
currentUserId, shows sign-out, displays “Signed in as …”. - Ensures a corresponding row exists in
user_profiles(ensureUserProfile()), then pulls remote cycles (syncCyclesFromRemote()).
- On sign-out: clears
ensureUserProfile():upsertintouser_profileswith{ id: currentUserId }socycles.user_idcan reference it (matching your schema + RLS).
syncCyclesFromRemote():- Selects
start_date, end_datefromcycles(RLS restricts to the authenticated user). - Maps them to the local format
{ startDate, endDate }, stores inlocalStorage, and callsrenderPastPeriods().
- Selects
- New globals and wiring:
-
Period storage integration with Supabase (in
app.js):- Existing
storeNewPeriodbehavior is preserved (localStorage is still the primary store and works fully offline). - Added
savePeriodRemote(startDate, endDate):- If
supabaseClientandcurrentUserIdare available, inserts intocycleswithuser_id = currentUserId,start_date,end_date. - Called from
storeNewPeriodas a best-effort async write; failures don’t affect local behavior.
- If
- Existing
-
Event wiring (in
app.js):authFormElsubmit →handleEmailAuth(email, password)(if Supabase is available; otherwise it informs the user that only local storage is available).signOutButtonElclick →supabaseClient.auth.signOut().newPeriodFormElsubmit remains essentially the same, but now also triggerssavePeriodRemote.
- Uses
user_profiles(id uuid PRIMARY KEY DEFAULT auth.uid())by:- Creating a row with
id = auth.uid()(viaensureUserProfile()), satisfying the FK fromcycles.user_id.
- Creating a row with
- Uses
cycles(user_id, start_date, end_date, ...)by:- Inserting
user_id = currentUserId(which isauth.uid()from the Supabase session). - Fetching only
start_dateandend_dateper the RLS policies you defined; each authenticated user only sees their own cycles.
- Inserting
- Fill in your Supabase details in
CT2/index.html:- Replace
YOUR-PROJECT-refwith your project ref (e.g.,abc123.supabase.co). - Replace
YOUR-PUBLISHABLE-OR-ANON-KEYwith your publishable/anon key from Supabase.
- Replace
- Apply the SQL in
CT2/supabase.sqlto your Supabase project (e.g., via the SQL editor or migrations) souser_profilesandcyclesplus RLS are in place. - Run the CT2 PWA (as you already do), then:
- Enter an email/password in the new auth form and submit.
- A first attempt will sign in if the account exists, or sign up otherwise.
- Add new cycles; they will be stored locally and, if signed in, also persisted into the
cyclestable tied to your authenticated user.
This keeps the CT2 app small and mostly unchanged while adding email-based auth and database-backed storage that respects your Supabase schema and RLS policies.