Skip to main content

max / goingson

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