feat: guide mobile start-day review (Closes #897)
CI / lint (pull_request) Successful in 1m54s
CI / build-release (pull_request) Successful in 5s
CI / browser-journey (pull_request) Successful in 57s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-15 14:31:37 +00:00
1 parent 7351363982
commit d4aafbf351
17 files changed
+238 -20

No files matched your search

+4
View File
@@ -850,6 +850,10 @@ textarea { resize: vertical; min-height: 120px; }
.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; }
.mobile-queue-panel h2 { margin:0; }
.mobile-start-day { display:grid; gap:12px; max-width:100%; overflow-wrap:anywhere; margin-top:12px; padding:14px; border:1px solid #31577f; border-radius:14px; background:linear-gradient(135deg,#173b64,#102641); }
.mobile-start-day h3, .mobile-start-day p { margin:0; }
.mobile-start-day p + p { margin-top:4px; }
.mobile-start-day-action { width:100%; min-height:48px; text-align:center; }
.mobile-queue-list { display:grid; gap:8px; margin-top:12px; }
.mobile-queue-list button { display:flex; align-items:center; justify-content:space-between; gap:12px; min-height:56px; width:100%; padding:10px 14px; text-align:left; }
.mobile-queue-list button > span:first-child { display:grid; gap:2px; }
+12
View File
@@ -95,7 +95,18 @@
findWork: () => qs('#find-work').click(),
});
const mobileStartDay = createMobileStartDay({
getCounts: () => mobileQueueCounts,
openQueue: name => name === 'find' ? qs('#find-work').click() : mobileQueueLauncher.open(name),
elements: {
summary: qs('#mobile-start-day-summary'),
phases: qs('#mobile-start-day-phases'),
action: qs('#mobile-start-day-action'),
},
});
mobileStartDay.start();
function showMobileQueueCompletion(completedName, cleared = true) {
mobileStartDay.render();
const next = mobileQueueLauncher.recommend();
qs('#mobile-queue-heading').textContent = completedName + (cleared ? ' cleared' : '');
document.querySelectorAll('[data-mobile-queue]').forEach(row => row.removeAttribute('data-recommended'));
@@ -2639,6 +2650,7 @@
if (element) element.textContent = count;
});
mobileQueueCounts = counts;
mobileStartDay.render();
mobileTaskDock.updateQueues(counts);
mobileTaskDock.updateWork(mobileWorkEntry.mode());
mobileTaskDock.updateAttention(countMyWork(activeMyWork).attention);
+9
View File
@@ -1223,6 +1223,14 @@
<button id="review-kept-updates" type="button" hidden>Review kept unread</button>
</div>
<p class="small muted">Choose what to work through next.</p>
<section class="mobile-start-day" aria-labelledby="mobile-start-day-heading">
<div>
<h3 id="mobile-start-day-heading">Prepare Today</h3>
<p id="mobile-start-day-summary" class="small" aria-live="polite">Reviewing urgent queues…</p>
<p id="mobile-start-day-phases" class="small muted">Checking Agenda, Attention, Updates, and Filed</p>
</div>
<button class="mobile-start-day-action" id="mobile-start-day-action" type="button">Prepare Today</button>
</section>
<div class="mobile-queue-list">
<button data-mobile-queue="today" type="button"><span><strong>Today</strong><small>Planned work</small></span><span data-mobile-queue-count="today">0</span></button>
<button data-mobile-queue="agenda" type="button"><span><strong>Agenda</strong><small>Upcoming deadlines</small></span><span data-mobile-queue-count="agenda">0</span></button>
@@ -1322,6 +1330,7 @@
<script src="static/mobile-task-dock.js"></script>
<script src="static/mobile-work-entry.js"></script>
<script src="static/mobile-queue-launcher.js"></script>
<script src="static/mobile-start-day.js"></script>
<script src="static/update-triage-session.js"></script>
<script src="static/update-review-handoff.js"></script>
<script src="static/update-read-position.js"></script>
+58
View File
@@ -0,0 +1,58 @@
(function (root, factory) {
if (typeof module === 'object' && module.exports) module.exports = factory;
else root.createMobileStartDay = factory;
})(typeof self !== 'undefined' ? self : this, function createMobileStartDay(options) {
const reviewOrder = [
['agenda', 'Agenda'],
['attention', 'Attention'],
['update', 'Updates'],
['filed', 'Filed'],
];
function count(value) {
return Math.max(0, Number(value) || 0);
}
function briefing() {
const counts = options.getCounts ? options.getCounts() : {};
const phases = reviewOrder
.map(([name, label]) => ({name, label, count: count(counts[name])}))
.filter(phase => phase.count > 0);
const total = phases.reduce((sum, phase) => sum + phase.count, 0);
const today = count(counts.today);
const next = phases.length ? phases[0].name : (today ? 'today' : 'find');
const nextLabel = phases.length ? 'Review ' + phases[0].label : (today ? 'Continue Today' : 'Find Work');
return {
total,
next,
label: nextLabel,
summary: total ? total + ' items before Today · ' + today + ' planned' :
(today ? 'Review clear · ' + today + ' planned' : 'Review clear · Today is empty'),
phases,
};
}
function startNext() {
const next = briefing().next;
options.openQueue(next);
return next;
}
function render() {
const current = briefing();
if (!options.elements) return current;
options.elements.summary.textContent = current.summary;
options.elements.phases.textContent = current.phases.length ?
current.phases.map(phase => phase.label + ' ' + phase.count).join(' · ') :
'All urgent queues reviewed';
options.elements.action.textContent = current.label;
return current;
}
function start() {
render();
if (options.elements) options.elements.action.addEventListener('click', startNext);
}
return {briefing, render, start, startNext};
});
+2 -1
View File
@@ -1,7 +1,7 @@
const BASE = new URL('./', self.location.href).pathname;
importScripts(BASE + 'static/private-data-registry.js');
importScripts(BASE + 'static/background-issue-sync.js');
const CACHE = 'stackchain-dashboard-shell-v102';
const CACHE = 'stackchain-dashboard-shell-v103';
const OFFLINE_LEASE_URL = new URL(BASE + '__offline-session-lease', self.location.origin).href;
const OUTAGE_STATUSES = new Set([500, 502, 503, 504]);
const NAVIGATION_TIMEOUT_MS = self.__STACKCHAIN_NAVIGATION_TIMEOUT_MS || 4000;
@@ -87,6 +87,7 @@ const SHELL = [
BASE + 'static/mobile-task-dock.js',
BASE + 'static/mobile-work-entry.js',
BASE + 'static/mobile-queue-launcher.js',
BASE + 'static/mobile-start-day.js',
BASE + 'static/update-triage-session.js',
BASE + 'static/update-review-handoff.js',
BASE + 'static/update-read-position.js',