From 304e4a8a24493de2dd63945a1842ef2c993f2ae0 Mon Sep 17 00:00:00 2001 From: timmy Date: Wed, 19 Aug 2026 17:33:26 +0000 Subject: [PATCH] feat: guide first mobile task activation (Closes #1140) --- frontend/dashboard.css | 9 ++ frontend/dashboard.js | 8 ++ frontend/index.html | 17 +++ frontend/mobile-first-task.js | 95 +++++++++++++ frontend/mobile-work-entry.js | 2 + frontend/service-worker.js | 1 + src/frontend_bundle.py | 2 +- .../e2e/test_mobile_home_bootstrap_release.py | 55 ++++++++ tests/test_mobile_first_task.py | 125 ++++++++++++++++++ tests/test_mobile_task_dock.py | 29 ++++ tests/test_service_worker.py | 1 + 11 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 frontend/mobile-first-task.js create mode 100644 tests/test_mobile_first_task.py diff --git a/frontend/dashboard.css b/frontend/dashboard.css index 0003623..1014ab9 100644 --- a/frontend/dashboard.css +++ b/frontend/dashboard.css @@ -1169,6 +1169,15 @@ textarea { resize: vertical; min-height: 120px; } .mobile-task-dock { position:fixed; inset:auto 0 0; z-index:45; display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:2px; padding:6px 8px; padding-bottom:env(safe-area-inset-bottom); border-top:1px solid #2a496e; background:rgba(11,21,38,.98); backdrop-filter:blur(12px); } .mobile-queue-sheet { width:100%; max-width:none; margin:auto 0 0; padding:0; border:0; border-radius:18px 18px 0 0; color:var(--text); background:#102641; } + .mobile-first-task { box-sizing:border-box; width:100%; max-width:none; max-height:100dvh; margin:auto 0 0; padding:0; border:0; border-radius:18px 18px 0 0; color:var(--text); background:#102641; } + .mobile-first-task::backdrop { background:rgba(3,9,18,.78); } + .mobile-first-task-panel { display:grid; gap:14px; padding:16px; padding-bottom:calc(16px + env(safe-area-inset-bottom)); } + .mobile-first-task-panel header { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; } + .mobile-first-task-panel h2, .mobile-first-task-panel p { margin:0; } + .mobile-first-task-actions { display:grid; gap:10px; } + .mobile-first-task-actions button { min-height:48px; width:100%; } + .mobile-first-task-actions button:disabled { opacity:.55; } + .mobile-queue-sheet::backdrop { background:rgba(3,9,18,.7); } .mobile-queue-panel { padding:16px; padding-bottom:calc(16px + env(safe-area-inset-bottom)); } .mobile-queue-panel header { display:flex; align-items:center; justify-content:space-between; gap:12px; } diff --git a/frontend/dashboard.js b/frontend/dashboard.js index ba9292d..bbee033 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -140,6 +140,11 @@ if (!sheet.open) qs('#mobile-queue-sheet').showModal(); qs('#mobile-start-day-action').focus(); } + const mobileFirstTask = createMobileFirstTask({ + getLogin: () => confirmedOwnerLogin, + hasWork: () => todayMyWork.length > 0 || activeMyWork.length > 0, + }); + mobileFirstTask.start(); const mobileWorkEntry = createMobileWorkEntry({ isTodayActive: () => workSession.checkpointed(), isTodayResumable: () => workSession.resumable(), @@ -152,6 +157,8 @@ startToday: startTodaySession, planToday: () => openPlanToday(mobileTaskButtons.work), prepareToday: openMobileStartDay, + shouldActivate: () => mobileFirstTask.required(), + openActivation: () => mobileFirstTask.open(), findWork: () => qs('#find-work').click(), }); const mobileStartDay = createMobileStartDay({ @@ -3225,6 +3232,7 @@ }); mobileStartDay.render(); mobileTaskDock.updateQueues(counts); + mobileFirstTask.refresh(); mobileTaskDock.updateWork(mobileWorkEntry.mode()); mobileTaskDock.updateAttention(countMyWork(activeMyWork).attention); const activeQueue = qs('[data-work-filter="' + selectedWorkFilter + '"]'); diff --git a/frontend/index.html b/frontend/index.html index 5d22517..6ecd390 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1829,6 +1829,22 @@ + +
+
+

Welcome to Work

Start your first task

+ +
+

Choose work, start it, then return to Work whenever you want to continue.

+

+
+ + + +
+
+
+