Skip to main content

max / goingson

43.9 KB · 710 lines History Blame Raw
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
6 <!-- Phase 7 Tier 3 #13: iOS / PWA chrome integration.
7 theme-color is updated by js/themes.js when the theme changes so the
8 iOS status bar and Android browser chrome match the active surface. -->
9 <meta name="theme-color" content="#E0E4FA" id="meta-theme-color">
10 <meta name="apple-mobile-web-app-capable" content="yes">
11 <meta name="apple-mobile-web-app-status-bar-style" content="default">
12 <meta name="apple-mobile-web-app-title" content="GoingsOn">
13 <title>GoingsOn</title>
14 <link rel="icon" type="image/svg+xml" href="favicon.svg">
15 <link rel="icon" type="image/png" sizes="32x32" href="../icons/32x32.png">
16 <link rel="apple-touch-icon" href="../icons/128x128.png">
17
18 <!-- UI mode detection. Runs BEFORE the stylesheet so the class is on
19 <html> when CSS evaluates (no flash). Precedence:
20 1. ?ui=mobile|desktop URL param (dev/testing, bug repros)
21 2. localStorage.goingson.uiMode (dev Settings toggle)
22 3. navigator.userAgentData.mobile (UA Client Hints, modern)
23 4. UA regex with iPad-as-Mac fallback (Safari iOS/iPadOS, legacy)
24 Works in both browser dev and Tauri-mobile webviews: WKWebView (iOS)
25 and Android WebView both expose iOS/Android in the UA string. iPad
26 on Safari 13+ reports as Mac by default; the maxTouchPoints branch
27 catches that. Production lockdown of overrides is deferred to
28 phase 5 of ui_mode_separation_plan.md. -->
29 <script src="js/bootstrap-uimode.js"></script>
30
31 <link rel="stylesheet" href="css/styles.min.css">
32 </head>
33 <body>
34 <a href="#main-content" class="skip-link">Skip to main content</a>
35 <header class="app-header">
36 <div class="header-content">
37 <h1 class="app-title">GoingsOn</h1>
38 <span class="app-subtitle">Personal Productivity</span>
39 <span class="mobile-view-title" id="mobile-view-title"></span>
40 </div>
41 <nav class="tab-navigation" role="tablist" aria-label="Main navigation">
42 <a href="#" class="tab active" data-view="work" role="tab" aria-selected="true" aria-label="Work: tasks and projects">
43 <span class="tab-label">Work</span>
44 </a>
45 <a href="#" class="tab" data-view="time" role="tab" aria-selected="false" aria-label="Time: day planning, calendar, reviews">
46 <span class="tab-label">Time</span>
47 </a>
48 <a href="#" class="tab" data-view="messages" role="tab" aria-selected="false" aria-label="Messages: email and contacts">
49 <span class="tab-label">Messages</span>
50 </a>
51 </nav>
52 <div class="header-actions">
53 <button class="sync-indicator row-flex row-flex-2 hidden" id="sync-indicator" data-act="settings.openCloudSync" title="Cloud Sync" aria-label="Cloud sync status">
54 <span class="sync-dot" id="sync-dot"></span>
55 <span class="sync-label" id="sync-label"></span>
56 </button>
57 <button class="btn" data-act="settings.open" title="Settings" aria-label="Open settings">Settings</button>
58 <button class="btn shortcut-hint-btn" data-act="keyboard.showShortcuts" title="Keyboard shortcuts (?)" aria-label="Show keyboard shortcuts">?</button>
59 </div>
60 </header>
61
62 <div class="app-body">
63 <main id="main-content" class="main-content">
64 <!-- Work Tab Group -->
65 <div id="work-view" class="view tab-group">
66 <div class="pill-nav" role="tablist" aria-label="Work views">
67 <button class="pill active" data-subview="tasks">Tasks</button>
68 <button class="pill" data-subview="projects">Projects</button>
69 </div>
70
71 <!-- Tasks Sub-View -->
72 <div id="tasks-view" class="subview">
73 <div class="page-header">
74 <h2 class="page-title">Tasks</h2>
75 <div class="row-flex row-flex-4">
76 <div class="view-toggle" id="task-view-toggle">
77 <button class="view-toggle-btn active" data-mode="list" data-act="tasks.setViewMode" data-a1="list">List</button>
78 <button class="view-toggle-btn" data-mode="board" data-act="tasks.setViewMode" data-a1="board">Board</button>
79 </div>
80 <button class="btn btn-secondary mobile-hide" data-act="keyboard.openQuickAddModal" title="Quick add (q)">Quick Add</button>
81 <button class="btn btn-primary" data-act="tasks.openNew" title="New task (n)">+ New Task <kbd class="kbd-hint">n</kbd></button>
82 </div>
83 </div>
84 <div id="task-bulk-actions" class="bulk-actions-bar hidden" role="toolbar" aria-label="Bulk task actions">
85 <span id="task-bulk-count" class="bulk-count">0 selected</span>
86 <button class="btn btn-sm" data-act="bulk.completeTasks">Complete</button>
87 <button class="btn btn-sm" data-act="bulk.setProjectTasks">Set Project</button>
88 <button class="btn btn-sm" data-act="bulk.setPriorityTasks">Set Priority</button>
89 <button class="btn btn-sm" data-act="bulk.snoozeTasks">Snooze</button>
90 <button class="btn btn-sm btn-danger" data-act="bulk.deleteTasks">Delete</button>
91 <button class="btn btn-sm bulk-select-all" data-act="bulk.selectAllTasks">Select All</button>
92 </div>
93 <div class="mobile-sort-bar" id="task-mobile-sort">
94 <button class="mobile-filter-toggle" data-act="tasks.toggleMobileFilters">Filters</button>
95 <select class="filter-select" data-change="tasks.mobileSortChange">
96 <option value="urgency">Sort: Urgency</option>
97 <option value="description">Sort: Name</option>
98 <option value="project">Sort: Project</option>
99 <option value="priority">Sort: Priority</option>
100 <option value="due">Sort: Due Date</option>
101 </select>
102 </div>
103 <div class="filter-bar" id="task-filter-bar" role="search" aria-label="Task filters">
104 <select id="filter-status" class="filter-select" data-change="tasks.applyFilters">
105 <option value="">All Status</option>
106 <option value="pending" selected>Pending</option>
107 <option value="started">Started</option>
108 <option value="completed">Completed</option>
109 </select>
110 <select id="filter-project" class="filter-select" data-change="tasks.applyFilters">
111 <option value="">All Projects</option>
112 </select>
113 <select id="filter-priority" class="filter-select" data-change="tasks.applyFilters">
114 <option value="">All Priority</option>
115 <option value="H">High</option>
116 <option value="M">Medium</option>
117 <option value="L">Low</option>
118 </select>
119 <select id="filter-milestone" class="filter-select hidden" data-change="tasks.applyFilters">
120 <option value="">All Milestones</option>
121 </select>
122 <label class="filter-checkbox" title="Include tasks hidden until a later date">
123 <input type="checkbox" id="filter-snoozed" data-change="tasks.applyFilters">
124 Show Snoozed
125 </label>
126 <label class="filter-checkbox" title="Tasks waiting on someone else to respond">
127 <input type="checkbox" id="filter-waiting" data-change="tasks.applyFilters">
128 Waiting Only
129 </label>
130 <div class="filter-actions">
131 <span id="task-count" class="filter-count" aria-live="polite"></span>
132 <button class="btn btn-link" data-act="tasks.clearFilters">Clear filters</button>
133 </div>
134 </div>
135 <div class="task-table" id="task-table" role="grid" aria-label="Tasks list">
136 <div class="task-header-row" role="row">
137 <div class="task-cell sortable" data-sort="description" data-act="tasks.sort" data-a1="description" role="columnheader" tabindex="0">
138 Description <span class="sort-arrow"></span>
139 </div>
140 <div class="task-cell sortable" data-sort="project" data-act="tasks.sort" data-a1="project" role="columnheader" tabindex="0">
141 Project <span class="sort-arrow"></span>
142 </div>
143 <div class="task-cell sortable" data-sort="priority" data-act="tasks.sort" data-a1="priority" role="columnheader" tabindex="0" aria-label="Priority">
144 Priority <span class="sort-arrow"></span>
145 </div>
146 <div class="task-cell sortable" data-sort="due" data-act="tasks.sort" data-a1="due" role="columnheader" tabindex="0">
147 Due <span class="sort-arrow"></span>
148 </div>
149 <div class="task-cell" role="columnheader">Recurs</div>
150 <div class="task-cell" role="columnheader">Progress</div>
151 <div class="task-cell task-actions-header" role="columnheader"><span class="sr-only">Actions</span></div>
152 </div>
153 <div class="task-list-container" id="task-list-container" aria-live="polite">
154 <div class="skeleton-shimmer" aria-label="Loading tasks">
155 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line short"></div></div></div>
156 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div>
157 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
158 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line short"></div><div class="skeleton-line long"></div></div></div>
159 </div>
160 </div>
161 </div>
162 <div id="task-kanban-board" class="kanban-board hidden" role="region" aria-label="Task board">
163 <!-- Rendered by tasks-kanban.js -->
164 </div>
165 <!-- Pagination -->
166 <div id="task-pagination" class="pagination-controls hidden" role="navigation" aria-label="Task list pagination">
167 <button class="btn btn-sm" id="task-prev-page" data-act="tasks.goToPage" data-a1="prev" disabled aria-label="Previous page">&larr; Previous</button>
168 <span id="task-page-info" class="pagination-info">Page 1 of 1</span>
169 <button class="btn btn-sm" id="task-next-page" data-act="tasks.goToPage" data-a1="next" disabled aria-label="Next page">Next &rarr;</button>
170 </div>
171 </div>
172
173 <!-- Projects Sub-View -->
174 <div id="projects-view" class="subview hidden" role="tabpanel" aria-labelledby="projects-tab">
175 <div class="page-header">
176 <h2 class="page-title">Projects</h2>
177 <div class="page-header-actions">
178 <span id="projects-filter-slot"></span>
179 <button class="btn btn-primary" data-act="projects.openNew" title="New project (n)">+ New Project <kbd class="kbd-hint">n</kbd></button>
180 </div>
181 </div>
182 <div class="cards-grid" id="projects-grid">
183 <div class="skeleton-shimmer" aria-label="Loading projects">
184 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
185 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line short"></div></div></div>
186 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div>
187 </div>
188 </div>
189 </div>
190
191 <!-- Project Dashboard Sub-View -->
192 <div id="project-dashboard-view" class="subview hidden">
193 <div class="page-header">
194 <div class="row-flex row-flex-4">
195 <button class="btn btn-secondary" data-act="projects.closeDashboard">&larr; Back</button>
196 <h2 class="page-title" id="project-dashboard-title">Project</h2>
197 </div>
198 <button class="btn btn-secondary" id="edit-project-btn" data-act="projects.editCurrent">Edit Project</button>
199 </div>
200 <p id="project-dashboard-description" class="project-dashboard-desc"></p>
201 <div id="project-milestones-section" class="milestones-section"></div>
202 <div class="project-dashboard-grid">
203 <div class="dashboard-column">
204 <div class="dashboard-column-header">
205 <h3>Tasks</h3>
206 <button class="btn btn-sm btn-primary" data-act="projects.addTask">+ Add</button>
207 </div>
208 <div id="project-tasks-list" class="dashboard-list">
209 <div class="skeleton-shimmer" aria-label="Loading tasks"><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line short"></div></div></div><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div></div>
210 </div>
211 </div>
212 <div class="dashboard-column">
213 <div class="dashboard-column-header">
214 <h3>Events</h3>
215 <button class="btn btn-sm btn-primary" data-act="projects.addEvent">+ Add</button>
216 </div>
217 <div id="project-events-list" class="dashboard-list">
218 <div class="skeleton-shimmer" aria-label="Loading events"><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line short"></div></div></div><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div></div>
219 </div>
220 </div>
221 <div class="dashboard-column">
222 <div class="dashboard-column-header">
223 <h3>Emails</h3>
224 <button class="btn btn-sm btn-primary" data-act="projects.linkEmail">+ Link</button>
225 </div>
226 <div id="project-emails-list" class="dashboard-list">
227 <div class="skeleton-shimmer" aria-label="Loading emails"><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div><div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line short"></div><div class="skeleton-line long"></div></div></div></div>
228 </div>
229 </div>
230 <div class="dashboard-column">
231 <div class="dashboard-column-header">
232 <h3>Attachments</h3>
233 <button class="btn btn-sm btn-primary" id="project-attach-btn">+ Attach</button>
234 </div>
235 <div id="project-attachments-list" class="dashboard-list">
236 <div class="empty-state empty-state--dashboard">No attachments</div>
237 </div>
238 </div>
239 </div>
240 </div>
241 <!-- Task Overview Sub-View -->
242 <div id="task-overview-view" class="subview hidden">
243 <div class="page-header">
244 <div class="row-flex row-flex-4">
245 <button class="btn btn-secondary" data-act="taskOverview.close">&larr; Back</button>
246 <h2 class="page-title" id="task-overview-title">Task Overview</h2>
247 </div>
248 <div id="task-overview-actions"></div>
249 </div>
250 <div id="task-overview-content">
251 <div class="skeleton-shimmer" aria-label="Loading task overview">
252 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
253 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line short"></div></div></div>
254 </div>
255 </div>
256 </div>
257
258 </div><!-- /work-view -->
259
260 <!-- Time Tab Group -->
261 <div id="time-view" class="view tab-group hidden">
262 <div class="pill-nav" role="tablist" aria-label="Time views">
263 <button class="pill active" data-subview="day-plan">Day</button>
264 <button class="pill" data-subview="weekly-review">Week</button>
265 <button class="pill" data-subview="monthly-review">Month</button>
266 <button class="pill" data-subview="timer" title="Pomodoro-style focus sessions">Timer</button>
267 <button class="pill" data-subview="events">Events</button>
268 </div>
269
270 <!-- Day Plan Sub-View -->
271 <div id="day-plan-view" class="subview" role="tabpanel" aria-labelledby="day-plan-tab">
272 <div class="page-header">
273 <div class="day-plan-nav">
274 <button class="btn btn-secondary" data-act="dayPlan.previousDay" title="Previous day ([)">&larr;</button>
275 <button class="btn btn-secondary" data-act="dayPlan.goToToday">Today</button>
276 <button class="btn btn-secondary" data-act="dayPlan.nextDay" title="Next day (])">&rarr;</button>
277 <input type="date" id="day-plan-date" class="day-plan-date-picker" data-change="dayPlan.onDatePickerChange">
278 <span id="day-plan-date-display" class="day-plan-date-display"></span>
279 </div>
280 <span id="day-review-status-badge" class="review-status hidden"></span>
281 </div>
282 <div class="day-plan-content">
283 <div class="day-plan-main" id="day-plan-container">
284 <p class="timeline-hint">Click and drag across time slots to schedule blocks</p>
285 <div class="timeline-container" id="timeline-container">
286 <div class="timeline-scroll-area">
287 <div class="timeline-current-time" id="timeline-current-time"></div>
288 <div id="timeline-slots"></div>
289 <div id="timeline-items"></div>
290 </div>
291 </div>
292 </div>
293 <div class="day-plan-sidebar">
294 <div id="time-summary-container"></div>
295 <button class="day-plan-sidebar-toggle" data-act="dayPlan.toggleSidebar">
296 <span>Tasks to Schedule</span>
297 <span class="toggle-arrow">&#x25BC;</span>
298 </button>
299 <div class="sidebar-header">
300 <h3>Tasks to Schedule</h3>
301 </div>
302 <div id="unscheduled-tasks" class="sidebar-task-list" role="list">
303 <!-- Virtual scroller renders items here -->
304 </div>
305 <div id="day-accomplished-inline" class="day-accomplished-inline"></div>
306 </div>
307 </div>
308 <div class="finish-review-bar">
309 <button class="btn btn-primary finish-review-btn" id="day-finish-review-btn" data-act="dayPlanSchedule.openFinishReviewModal">
310 Finish &amp; Review
311 </button>
312 </div>
313 </div>
314
315 <!-- Weekly Review Sub-View -->
316 <div id="weekly-review-view" class="subview hidden" role="tabpanel" aria-labelledby="weekly-review-tab">
317 <div class="page-header">
318 <h2 class="page-title">Weekly Review</h2>
319 </div>
320 <div id="weekly-review-content" class="weekly-review-content">
321 <div class="skeleton-shimmer" aria-label="Loading weekly review">
322 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
323 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div>
324 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line short"></div><div class="skeleton-line long"></div></div></div>
325 </div>
326 </div>
327 </div>
328
329 <!-- Monthly Review Sub-View -->
330 <div id="monthly-review-view" class="subview hidden" role="tabpanel" aria-labelledby="monthly-review-tab">
331 <div class="page-header">
332 <div class="monthly-review-nav">
333 <button class="btn btn-secondary" data-act="monthlyReview.previousMonth" title="Previous month">&larr;</button>
334 <button class="btn btn-secondary" data-act="monthlyReview.goToCurrentMonth">This Month</button>
335 <button class="btn btn-secondary" data-act="monthlyReview.nextMonth" title="Next month">&rarr;</button>
336 <span id="monthly-review-month-display" class="monthly-review-month-display"></span>
337 </div>
338 <span id="month-review-status-badge" class="review-status hidden"></span>
339 </div>
340 <div id="monthly-review-content" class="monthly-review-content">
341 <div class="skeleton-shimmer" aria-label="Loading monthly review">
342 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
343 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div>
344 </div>
345 </div>
346 </div>
347
348 <!-- Timer Sub-View -->
349 <div id="timer-view" class="subview hidden" role="tabpanel">
350 <div class="page-header">
351 <h2 class="page-title">Timer</h2>
352 </div>
353 <div id="timer-subview-content">
354 <!-- Rendered by time-tracking.js -->
355 </div>
356 </div>
357
358 <!-- Events Sub-View (accessible via keyboard/URL, not shown in pill nav) -->
359 <div id="events-view" class="subview hidden" role="tabpanel" aria-labelledby="events-tab">
360 <div class="page-header">
361 <h2 class="page-title">Events</h2>
362 <button class="btn btn-primary" data-act="events.openNew" title="New event (n)">+ New Event <kbd class="kbd-hint">n</kbd></button>
363 </div>
364 <div class="filter-bar" id="events-filter-bar">
365 <label class="filter-checkbox" title="Include events hidden until a later date">
366 <input type="checkbox" id="filter-events-snoozed" data-change="events.onFilterChange">
367 Show Snoozed
368 </label>
369 </div>
370 <div id="events-bulk-bar" class="bulk-actions-bar hidden">
371 <span class="bulk-count">0 selected</span>
372 <button class="btn btn-sm" data-act="events.selectAllEvents">Select All</button>
373 <button class="btn btn-sm btn-danger" data-act="events.bulkDelete">Delete</button>
374 <button class="btn btn-sm" data-act="events.clearEventSelection">Cancel</button>
375 </div>
376 <div class="events-list" id="events-list">
377 <details class="past-events-section hidden" id="recurring-events-section" open>
378 <summary class="past-events-toggle">
379 <span class="past-events-label">Recurring</span>
380 <span class="past-events-count" id="recurring-events-count">0</span>
381 </summary>
382 <div class="event-table-virtual" id="recurring-event-table">
383 <div class="event-header-row" role="row">
384 <div class="event-cell" role="columnheader">Pattern</div>
385 <div class="event-cell" role="columnheader">Time</div>
386 <div class="event-cell" role="columnheader">Event</div>
387 <div class="event-cell" role="columnheader">Location</div>
388 <div class="event-cell" role="columnheader"></div>
389 </div>
390 <div class="event-list-container" id="recurring-event-list-container"></div>
391 </div>
392 </details>
393 <h3 class="events-section-heading hidden" id="future-events-heading">Upcoming</h3>
394 <div class="event-table-virtual" id="event-table" role="grid" aria-label="Upcoming events">
395 <div class="event-header-row" role="row">
396 <div class="event-cell" role="columnheader">Date</div>
397 <div class="event-cell" role="columnheader">Time</div>
398 <div class="event-cell" role="columnheader">Event</div>
399 <div class="event-cell" role="columnheader">Location</div>
400 <div class="event-cell" role="columnheader"></div>
401 </div>
402 <div class="event-list-container" id="event-list-container" aria-live="polite">
403 <div class="skeleton-shimmer" aria-label="Loading events">
404 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line short"></div></div></div>
405 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
406 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line short"></div><div class="skeleton-line long"></div></div></div>
407 </div>
408 </div>
409 </div>
410 <details class="past-events-section hidden" id="past-events-section">
411 <summary class="past-events-toggle">
412 <span class="past-events-label">Past Events</span>
413 <span class="past-events-count" id="past-events-count">0</span>
414 </summary>
415 <div class="event-table-virtual event-table-past" id="past-event-table">
416 <div class="event-header-row" role="row">
417 <div class="event-cell" role="columnheader">Date</div>
418 <div class="event-cell" role="columnheader">Time</div>
419 <div class="event-cell" role="columnheader">Event</div>
420 <div class="event-cell" role="columnheader">Location</div>
421 </div>
422 <div class="event-list-container" id="past-event-list-container">
423 </div>
424 </div>
425 </details>
426 </div>
427 </div>
428 </div><!-- /time-view -->
429
430 <!-- Messages Tab Group -->
431 <div id="messages-view" class="view tab-group hidden">
432 <div class="pill-nav" role="tablist" aria-label="Messages views">
433 <button class="pill active" data-subview="emails">Email</button>
434 <button class="pill" data-subview="contacts">Contacts</button>
435 </div>
436
437 <!-- Emails Sub-View -->
438 <div id="emails-view" class="subview" role="tabpanel" aria-labelledby="emails-tab">
439 <div class="page-header">
440 <h2 class="page-title">Emails</h2>
441 <div class="row-flex row-flex-2">
442 <button class="btn btn-secondary mobile-hide" data-act="emails.openDrafts">Drafts</button>
443 <button class="btn btn-primary" data-act="emails.openCompose" title="Compose email (n)">+ Compose</button>
444 </div>
445 </div>
446 <div class="email-filter-row mb-2">
447 <input type="text" class="form-input" id="email-search" placeholder="Search emails..." data-input="emails.search">
448 <select class="form-select" id="email-folder-filter" data-change="emails.filterByFolder">
449 <option value="">All folders</option>
450 </select>
451 <select class="form-select" id="email-label-filter" data-change="emails.filterByLabel">
452 <option value="">All labels</option>
453 </select>
454 <span id="email-count" class="filter-count" aria-live="polite"></span>
455 </div>
456 <div id="email-bulk-actions" class="bulk-actions-bar hidden" role="toolbar" aria-label="Bulk email actions">
457 <span id="email-bulk-count" class="bulk-count">0 selected</span>
458 <button class="btn btn-sm" data-act="bulk.markEmailsRead">Mark Read</button>
459 <button class="btn btn-sm" data-act="bulk.archiveEmails">Archive</button>
460 <button class="btn btn-sm" data-act="bulk.snoozeEmails">Snooze</button>
461 <button class="btn btn-sm btn-danger" data-act="bulk.deleteEmails">Delete</button>
462 <button class="btn btn-sm bulk-select-all" data-act="bulk.selectAllEmails">Select All</button>
463 </div>
464 <div class="card card--shell email-list" id="email-list-wrapper" role="list">
465 <div class="email-list-container" id="email-list" aria-live="polite">
466 <div class="skeleton-shimmer" aria-label="Loading emails">
467 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
468 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line short"></div></div></div>
469 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line long"></div></div></div>
470 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line short"></div><div class="skeleton-line medium"></div></div></div>
471 </div>
472 </div>
473 </div>
474 <!-- Pagination -->
475 <div id="email-pagination" class="pagination-controls hidden" role="navigation" aria-label="Email list pagination">
476 <button class="btn btn-sm" id="email-prev-page" data-act="emails.goToPage" data-a1="prev" disabled aria-label="Previous page">&larr; Previous</button>
477 <span id="email-page-info" class="pagination-info">Page 1 of 1</span>
478 <button class="btn btn-sm" id="email-next-page" data-act="emails.goToPage" data-a1="next" disabled aria-label="Next page">Next &rarr;</button>
479 </div>
480 </div>
481
482 <!-- Contacts Sub-View -->
483 <div id="contacts-view" class="subview hidden" role="tabpanel" aria-labelledby="contacts-tab">
484 <div class="page-header">
485 <h2 class="page-title">Contacts</h2>
486 <div class="contacts-filter-row">
487 <input type="text" class="form-input" id="contacts-search" placeholder="Search contacts..." data-input="contacts.filterBySearch">
488 <select class="filter-select" id="contacts-tag-filter" data-change="contacts.filterByTag">
489 <option value="">All Tags</option>
490 </select>
491 <button class="btn btn-primary" data-act="contacts.openNew" title="New contact (n)">+ New Contact <kbd class="kbd-hint">n</kbd></button>
492 </div>
493 </div>
494 <div id="contacts-bulk-bar" class="bulk-actions-bar hidden">
495 <span class="bulk-count">0 selected</span>
496 <button class="btn btn-sm" data-act="contacts.selectAll">Select All</button>
497 <button class="btn btn-sm" data-act="contacts.bulkTag">Tag</button>
498 <button class="btn btn-sm btn-danger" data-act="contacts.bulkDelete">Delete</button>
499 <button class="btn btn-sm" data-act="contacts.clearSelection">Cancel</button>
500 </div>
501 <div class="cards-grid" id="contacts-grid">
502 <div class="skeleton-shimmer" aria-label="Loading contacts">
503 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line short"></div></div></div>
504 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line long"></div></div></div>
505 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
506 </div>
507 </div>
508 </div>
509 <!-- Contact Dashboard Sub-View -->
510 <div id="contact-dashboard-view" class="subview hidden">
511 <div class="page-header">
512 <div class="row-flex row-flex-4">
513 <button class="btn btn-secondary" data-act="contactDashboard.close">&larr; Back</button>
514 <h2 class="page-title" id="contact-dashboard-title">Contact</h2>
515 </div>
516 <div id="contact-dashboard-actions"></div>
517 </div>
518 <div id="contact-dashboard-content">
519 <div class="skeleton-shimmer" aria-label="Loading contact">
520 <div class="skeleton-row"><div class="skeleton-avatar"></div><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
521 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line short"></div></div></div>
522 </div>
523 </div>
524 </div>
525
526 </div><!-- /messages-view -->
527
528 <!-- Settings View (standalone, not a tab group) -->
529 </main>
530 </div><!-- /app-body -->
531
532 <!-- Settings Overlay (Phase 7 Tier 6: settings as modeless drawer) -->
533 <div id="settings-overlay" class="settings-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="settings-overlay-title" aria-hidden="true">
534 <div class="settings-overlay-backdrop" data-act="settings.goBack" aria-hidden="true"></div>
535 <div id="settings-view" class="view settings-overlay-card">
536 <div class="settings-page-layout">
537 <nav class="settings-sidebar">
538 <button class="btn-link mb-1 settings-back" data-act="settings.goBack" aria-label="Close settings">&larr; Close</button>
539 <h2 class="sr-only" id="settings-overlay-title">Settings</h2>
540 <div class="settings-nav-items">
541 <button class="settings-nav-item active" data-section="appearance" data-act="settings.showSection" data-a1="appearance">Appearance</button>
542 <button class="settings-nav-item" data-section="notifications" data-act="settings.showSection" data-a1="notifications">Notifications</button>
543 <button class="settings-nav-item" data-section="email" data-act="settings.showSection" data-a1="email">Email Accounts</button>
544 <button class="settings-nav-item" data-section="planning" data-act="settings.showSection" data-a1="planning">Planning &amp; Review</button>
545 <button class="settings-nav-item" data-section="sync" data-act="settings.showSection" data-a1="sync">Cloud Sync</button>
546 <button class="settings-nav-item" data-section="sharing" data-act="settings.showSection" data-a1="sharing">Sharing</button>
547 <button class="settings-nav-item" data-section="data" data-act="settings.showSection" data-a1="data">Import &amp; Export</button>
548 <button class="settings-nav-item" data-section="about" data-act="settings.showSection" data-a1="about">About</button>
549 </div>
550 </nav>
551 <div class="settings-content" id="settings-content">
552 <!-- Populated by JS -->
553 </div>
554 </div>
555 </div>
556 </div><!-- /settings-overlay -->
557
558 <!-- Modal -->
559 <div id="modal-overlay" class="modal-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="modal-title">
560 <div id="modal-container" class="modal-container">
561 <div class="modal-drag-handle"></div>
562 <div class="modal-header">
563 <h2 id="modal-title">Modal Title</h2>
564 <button class="modal-close" data-act="ui.closeModal" aria-label="Close modal">&times;</button>
565 </div>
566 <div id="modal-content" class="modal-content"></div>
567 </div>
568 </div>
569
570 <!-- Context Menu -->
571 <div id="context-menu" class="context-menu" role="menu" aria-label="Context menu" aria-hidden="true">
572 <!-- Content populated dynamically by JS -->
573 </div>
574
575 <!-- Task Detail Drawer (Phase 7 Tier 6: side-drawer task detail) -->
576 <aside id="task-detail-drawer" class="task-drawer" role="dialog" aria-modal="false" aria-labelledby="task-drawer-title" aria-hidden="true">
577 <div class="task-drawer-header">
578 <button class="btn btn-sm btn-secondary task-drawer-close" data-act="taskOverview.close" title="Close (Esc)" aria-label="Close task detail">&times;</button>
579 <h2 class="task-drawer-title" id="task-drawer-title">Task</h2>
580 <div class="task-drawer-actions" id="task-drawer-actions"></div>
581 </div>
582 <div class="task-drawer-content" id="task-drawer-content">
583 <div class="skeleton-shimmer" aria-label="Loading task detail">
584 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line long"></div><div class="skeleton-line medium"></div></div></div>
585 <div class="skeleton-row"><div class="skeleton-lines"><div class="skeleton-line medium"></div><div class="skeleton-line short"></div></div></div>
586 </div>
587 </div>
588 </aside>
589
590 <!-- Mobile Bottom Tab Bar (hidden on desktop) -->
591 <nav id="mobile-tab-bar" class="mobile-tab-bar" role="tablist" aria-label="Mobile navigation">
592 <button class="mobile-tab active" data-view="work" role="tab" aria-selected="true">
593 <span class="mobile-tab-label">Work</span>
594 </button>
595 <button class="mobile-tab" data-view="time" role="tab" aria-selected="false">
596 <span class="mobile-tab-label">Time</span>
597 </button>
598 <button class="mobile-tab" data-view="messages" role="tab" aria-selected="false">
599 <span class="mobile-tab-label">Messages</span>
600 </button>
601 <button class="mobile-tab mobile-tab-create" id="mobile-create-btn" aria-label="Create new item">+</button>
602 </nav>
603
604 <!-- Action Bottom Sheet (mobile context menus) -->
605 <div id="action-sheet" class="action-sheet hidden" role="dialog" aria-modal="true" aria-label="Actions">
606 <div class="action-sheet-backdrop"></div>
607 <div class="action-sheet-container">
608 <div class="action-sheet-handle"></div>
609 <div class="action-sheet-content" id="action-sheet-content"></div>
610 <button class="action-sheet-cancel" data-act="ui.hideActionSheet">Cancel</button>
611 </div>
612 </div>
613
614
615 <!-- Namespace (must load first) -->
616 <script src="js/goingson.js"></script>
617 <script src="js/config.js"></script>
618 <script src="js/dispatch.js"></script>
619 <script src="js/viewport.js"></script>
620
621 <!-- Core Layer -->
622 <script src="js/api.js"></script>
623 <script src="js/state.js"></script>
624 <script src="js/escape.js"></script>
625 <script src="js/utils.js"></script>
626 <script src="js/components-modal.js"></script>
627 <script src="js/components.js"></script>
628 <script src="js/form-modal.js"></script>
629 <script src="js/themes.js"></script>
630 <script src="js/query-state.js"></script>
631
632 <!-- Utility Managers -->
633 <script src="js/cache.js"></script>
634 <script src="js/selection-manager.js"></script>
635 <script src="js/pagination-manager.js"></script>
636 <script src="js/virtual-scroller.js"></script>
637
638 <!-- Features (no domain dependencies) -->
639 <script src="js/router.js"></script>
640 <script src="js/navigation.js"></script>
641 <script src="js/snooze.js"></script>
642 <script src="js/touch.js"></script>
643 <!-- Domain render modules (load before their parent domains) -->
644 <script src="js/projects-render.js"></script>
645 <script src="js/groups.js"></script>
646 <script src="js/tasks-render.js"></script>
647 <script src="js/tasks-kanban.js"></script>
648 <script src="js/contacts-render.js"></script>
649 <script src="js/day-planning-render.js"></script>
650 <script src="js/day-planning-paint.js"></script>
651 <script src="js/day-planning-schedule.js"></script>
652 <script src="js/weekly-review-render.js"></script>
653 <script src="js/monthly-review-render.js"></script>
654 <!-- Domains -->
655 <script src="js/projects.js"></script>
656 <script src="js/tasks-filter.js"></script>
657 <script src="js/task-forms.js"></script>
658 <script src="js/task-board.js"></script>
659 <script src="js/attachments.js"></script>
660 <script src="js/autocomplete.js"></script>
661 <script src="js/address-highlight.js"></script>
662 <script src="js/compose-form.js"></script>
663 <script src="js/tasks.js"></script>
664 <script src="js/task-overview.js"></script>
665 <script src="js/events.js"></script>
666 <script src="js/events-calendar.js"></script>
667 <script src="js/emails-render.js"></script>
668 <script src="js/emails-compose.js"></script>
669 <script src="js/emails.js"></script>
670 <script src="js/email-accounts.js"></script>
671 <script src="js/contacts.js"></script>
672 <script src="js/contact-dashboard.js"></script>
673 <script src="js/plan-review-toggle.js"></script>
674 <script src="js/day-planning.js"></script>
675 <script src="js/weekly-review.js"></script>
676 <script src="js/monthly-review.js"></script>
677 <!-- Time Tracking -->
678 <script src="js/time-tracking.js"></script>
679 <script src="js/focus-timer.js"></script>
680 <script src="js/time-summary.js"></script>
681
682 <!-- Features (with domain dependencies) -->
683 <script src="js/bulk-actions.js"></script>
684 <script src="js/saved-views.js"></script>
685 <script src="js/search.js"></script>
686 <script src="js/keyboard.js"></script>
687
688 <!-- UI -->
689 <script src="js/settings.js"></script>
690 <script src="js/settings-sync.js"></script>
691 <script src="js/settings-sharing.js"></script>
692 <script src="js/export.js"></script>
693 <script src="js/import.js"></script>
694 <script src="js/import-external.js"></script>
695 <script src="js/context-menus.js"></script>
696
697 <!-- Mobile interaction wiring (no-op on desktop) -->
698 <script src="js/mobile.js"></script>
699
700 <!-- OTA update notifications -->
701 <script src="js/shared-updater.js"></script>
702 <script src="js/updater.js"></script>
703 <script src="js/whats-new.js"></script>
704
705 <!-- Bootstrap -->
706 <script src="js/app.js"></script>
707 <script src="js/seed-data.js"></script>
708 </body>
709 </html>
710