max / goingson
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
6 files changed,
+47 insertions,
-27 deletions
| @@ -119,6 +119,24 @@ | |||
| 119 | 119 | there is no hover, so `.row-actions` is shown unconditionally; any such override must | |
| 120 | 120 | restore `pointer-events` as well as `opacity`. | |
| 121 | 121 | ||
| 122 | + | ### Row text parts: `.row-primary` / `.row-secondary` / `.row-meta` | |
| 123 | + | Generated too, and they are only the three content colours (`--content`, | |
| 124 | + | `--content-secondary`, `--content-muted`). Unlike `.row-actions` they are not scoped | |
| 125 | + | to a `.row` ancestor, so a list row that carries no hidden actions can still wear | |
| 126 | + | them: the email search result does. | |
| 127 | + | ||
| 128 | + | Put one on any row text whose colour is the hierarchy and nothing more, and delete | |
| 129 | + | the declaration it replaces. Worn today by the task row's project, due and | |
| 130 | + | recurrence cells and its no-subtasks dash; the email item's from, subject, date and | |
| 131 | + | preview; the event row's date number, time and location. | |
| 132 | + | ||
| 133 | + | A part is not worn where the colour means something other than rank. The overdue | |
| 134 | + | task description and due date, the recurring event's pattern label and every badge | |
| 135 | + | keep their own rule, and each of those out-specifies the part class it sits next to. | |
| 136 | + | A row element with no colour declaration of its own does not gain a part class | |
| 137 | + | either: it already inherits `--content`, so the class would add a declaration | |
| 138 | + | without replacing one. | |
| 139 | + | ||
| 122 | 140 | **Canonical helper (to be added):** `GoingsOn.ui.renderRow(kind, model, opts)`. Each `renderXxx` above becomes a thin adapter that maps the model to the shared "icon · primary · secondary · meta · actions" slot layout. Surface audits in Phase 1+ assume this exists. | |
| 123 | 141 | ||
| 124 | 142 | ### Task row state classes (composed onto `.task-row`) |
| @@ -153,6 +153,10 @@ | |||
| 153 | 153 | DO write it on a list row that hides actions until hover: .row is the | |
| 154 | 154 | ancestor .row-actions reveals from. Worn today by the task row, the email | |
| 155 | 155 | item, the event row and the filled month goal. | |
| 156 | + | The three text parts are NOT scoped to that ancestor -- they are just the | |
| 157 | + | content, secondary and muted colours -- so wear .row-primary / | |
| 158 | + | -secondary / -meta on any list-row text whose colour is its rank, .row | |
| 159 | + | above it or not, and delete the declaration they replace. | |
| 156 | 160 | ||
| 157 | 161 | COMPONENT PRIMITIVES | |
| 158 | 162 | .button + .button--primary / --secondary / --danger / --sm | |
| @@ -1164,9 +1168,11 @@ | |||
| 1164 | 1168 | max-width: 100%; | |
| 1165 | 1169 | } | |
| 1166 | 1170 | ||
| 1171 | + | /* The tasks-table project cell. Colour comes from the generated .row-secondary, | |
| 1172 | + | which the cell wears. Scoped away from the review-card pill of the same name | |
| 1173 | + | further down this file, which used to win here by source order alone. */ | |
| 1167 | 1174 | .task-project { | |
| 1168 | 1175 | font-size: var(--font-size-base); | |
| 1169 | - | color: var(--content-secondary); | |
| 1170 | 1176 | white-space: nowrap; | |
| 1171 | 1177 | } | |
| 1172 | 1178 | ||
| @@ -1357,7 +1363,6 @@ | |||
| 1357 | 1363 | .event-cell-date .event-date-num { | |
| 1358 | 1364 | font-weight: 700; | |
| 1359 | 1365 | font-size: var(--font-size-base); | |
| 1360 | - | color: var(--content); | |
| 1361 | 1366 | margin-right: var(--gap-bound); | |
| 1362 | 1367 | } | |
| 1363 | 1368 | ||
| @@ -1377,7 +1382,6 @@ | |||
| 1377 | 1382 | .event-cell-time { | |
| 1378 | 1383 | font-family: var(--font-mono); | |
| 1379 | 1384 | font-size: var(--font-size-base); | |
| 1380 | - | color: var(--content-secondary); | |
| 1381 | 1385 | } | |
| 1382 | 1386 | ||
| 1383 | 1387 | .event-cell-title { | |
| @@ -1385,7 +1389,6 @@ | |||
| 1385 | 1389 | } | |
| 1386 | 1390 | ||
| 1387 | 1391 | .event-cell-location { | |
| 1388 | - | color: var(--content-secondary); | |
| 1389 | 1392 | font-size: var(--font-size-base); | |
| 1390 | 1393 | } | |
| 1391 | 1394 | ||
| @@ -1601,20 +1604,17 @@ | |||
| 1601 | 1604 | } | |
| 1602 | 1605 | ||
| 1603 | 1606 | .email-from { | |
| 1604 | - | color: var(--content); | |
| 1605 | 1607 | font-size: var(--font-size-base); | |
| 1606 | 1608 | font-weight: 600; | |
| 1607 | 1609 | } | |
| 1608 | 1610 | ||
| 1609 | 1611 | .email-date { | |
| 1610 | - | color: var(--content-muted); | |
| 1611 | 1612 | font-size: var(--font-size-md); | |
| 1612 | 1613 | flex-shrink: 0; | |
| 1613 | 1614 | font-weight: 600; | |
| 1614 | 1615 | } | |
| 1615 | 1616 | ||
| 1616 | 1617 | .email-subject { | |
| 1617 | - | color: var(--content); | |
| 1618 | 1618 | font-size: var(--font-size-lg); | |
| 1619 | 1619 | margin-bottom: var(--gap-bound); | |
| 1620 | 1620 | white-space: nowrap; | |
| @@ -1623,7 +1623,6 @@ | |||
| 1623 | 1623 | } | |
| 1624 | 1624 | ||
| 1625 | 1625 | .email-preview { | |
| 1626 | - | color: var(--content-muted); | |
| 1627 | 1626 | font-size: var(--font-size-base); | |
| 1628 | 1627 | white-space: nowrap; | |
| 1629 | 1628 | overflow: hidden; | |
| @@ -4186,7 +4185,6 @@ | |||
| 4186 | 4185 | } | |
| 4187 | 4186 | ||
| 4188 | 4187 | .no-subtasks { | |
| 4189 | - | color: var(--content-secondary); | |
| 4190 | 4188 | font-size: var(--font-size-base); | |
| 4191 | 4189 | } | |
| 4192 | 4190 | ||
| @@ -4992,7 +4990,6 @@ | |||
| 4992 | 4990 | ||
| 4993 | 4991 | .task-recurrence { | |
| 4994 | 4992 | font-size: var(--font-size-base); | |
| 4995 | - | color: var(--content-secondary); | |
| 4996 | 4993 | } | |
| 4997 | 4994 | ||
| 4998 | 4995 | .task-due { | |
| @@ -6125,7 +6122,12 @@ | |||
| 6125 | 6122 | font-size: var(--font-size-base); | |
| 6126 | 6123 | } | |
| 6127 | 6124 | ||
| 6128 | - | .task-project { | |
| 6125 | + | /* Review-card pills. Scoped to their two containers: bare, these two rules also | |
| 6126 | + | painted the tasks-table cells of the same name -- same specificity, later in | |
| 6127 | + | the file -- so the table's project cell rendered as a small raised pill and | |
| 6128 | + | its due cell went muted, neither of which the table's own rules asked for. */ | |
| 6129 | + | .task-item .task-project, | |
| 6130 | + | .event-item .task-project { | |
| 6129 | 6131 | font-size: var(--font-size-sm); | |
| 6130 | 6132 | padding: var(--step-tight) var(--step-base); | |
| 6131 | 6133 | background: var(--surface-raised); | |
| @@ -6133,7 +6135,7 @@ | |||
| 6133 | 6135 | color: var(--content-muted); | |
| 6134 | 6136 | } | |
| 6135 | 6137 | ||
| 6136 | - | .task-due { | |
| 6138 | + | .task-item .task-due { | |
| 6137 | 6139 | font-size: var(--font-size-sm); | |
| 6138 | 6140 | color: var(--content-muted); | |
| 6139 | 6141 | } |
| @@ -45,13 +45,13 @@ | |||
| 45 | 45 | </div> | |
| 46 | 46 | <div class="email-content" data-act="emails.open" data-a1="${escAttr(e.id)}" role="button"> | |
| 47 | 47 | <div class="email-header"> | |
| 48 | - | <span class="email-from">${esc(e.from)}</span> | |
| 48 | + | <span class="row-primary email-from">${esc(e.from)}</span> | |
| 49 | 49 | ${threadBadge} | |
| 50 | 50 | ${isSnoozed ? `<span class="snooze-badge" title="Snoozed until ${escAttr(e.snoozedUntilFormatted || '')}" aria-label="Snoozed until ${escAttr(e.snoozedUntilFormatted || '')}">Snoozed</span>` : ''} | |
| 51 | - | <span class="email-date">${e.receivedFormatted}</span> | |
| 51 | + | <span class="row-meta email-date">${e.receivedFormatted}</span> | |
| 52 | 52 | </div> | |
| 53 | - | <div class="email-subject">${esc(e.subject)}${labelBadges ? ' ' + labelBadges : ''}</div> | |
| 54 | - | <div class="email-preview">${esc(e.bodyPreview)}...</div> | |
| 53 | + | <div class="row-primary email-subject">${esc(e.subject)}${labelBadges ? ' ' + labelBadges : ''}</div> | |
| 54 | + | <div class="row-meta email-preview">${esc(e.bodyPreview)}...</div> | |
| 55 | 55 | </div> | |
| 56 | 56 | <button class="button--icon row-actions kebab-btn" data-act="contextMenus.showEmail" data-a1="@event" data-a2="${escAttr(e.id)}" title="Actions" aria-label="Email actions">⋮</button> | |
| 57 | 57 | </div> |
| @@ -455,9 +455,9 @@ | |||
| 455 | 455 | tabindex="0" role="listitem"> | |
| 456 | 456 | <div class="email-content"> | |
| 457 | 457 | <div class="email-header"> | |
| 458 | - | <span class="email-subject">${esc(r.title)}</span> | |
| 458 | + | <span class="row-primary email-subject">${esc(r.title)}</span> | |
| 459 | 459 | </div> | |
| 460 | - | ${r.snippet ? `<div class="email-preview">${esc(r.snippet)}</div>` : ''} | |
| 460 | + | ${r.snippet ? `<div class="row-meta email-preview">${esc(r.snippet)}</div>` : ''} | |
| 461 | 461 | </div> | |
| 462 | 462 | </div> | |
| 463 | 463 | `).join(''); |
| @@ -543,9 +543,9 @@ | |||
| 543 | 543 | data-contextmenu="contextMenus.showEvent" data-a1="@event" data-a2="${escAttr(e.id)}" | |
| 544 | 544 | tabindex="0" role="row"> | |
| 545 | 545 | <div class="event-cell event-cell-date"><span class="event-recurrence-pattern">${esc(patternLabel)}</span></div> | |
| 546 | - | <div class="event-cell event-cell-time">${e.timeFormatted}</div> | |
| 546 | + | <div class="event-cell row-secondary event-cell-time">${e.timeFormatted}</div> | |
| 547 | 547 | <div class="event-cell event-cell-title">${esc(displayTitle)}</div> | |
| 548 | - | <div class="event-cell event-cell-location">${e.location ? esc(e.location) : '-'}</div> | |
| 548 | + | <div class="event-cell row-secondary event-cell-location">${e.location ? esc(e.location) : '-'}</div> | |
| 549 | 549 | <div class="event-cell" style="text-align: right;" data-act="ui.noop"> | |
| 550 | 550 | <button class="button--icon row-actions kebab-btn" data-act="contextMenus.showEvent" data-a1="@event" data-a2="${escAttr(e.id)}" title="Actions" aria-label="Event actions">⋮</button> | |
| 551 | 551 | </div> | |
| @@ -584,12 +584,12 @@ | |||
| 584 | 584 | aria-label="Select event"> | |
| 585 | 585 | </div> | |
| 586 | 586 | <div class="event-cell event-cell-date"> | |
| 587 | - | <span class="event-date-num">${startDate.getDate()} ${monthName}</span> | |
| 587 | + | <span class="row-primary event-date-num">${startDate.getDate()} ${monthName}</span> | |
| 588 | 588 | <span class="event-date-badge event-proximity-${e.proximityClass || 'default'}">${e.proximityLabel || ''}</span> | |
| 589 | 589 | </div> | |
| 590 | - | <div class="event-cell event-cell-time">${e.timeFormatted}</div> | |
| 590 | + | <div class="event-cell row-secondary event-cell-time">${e.timeFormatted}</div> | |
| 591 | 591 | <div class="event-cell event-cell-title">${esc(displayTitle)}</div> | |
| 592 | - | <div class="event-cell event-cell-location">${e.location ? esc(e.location) : '-'}</div> | |
| 592 | + | <div class="event-cell row-secondary event-cell-location">${e.location ? esc(e.location) : '-'}</div> | |
| 593 | 593 | <div class="event-cell" style="text-align: right;" data-act="ui.noop"> | |
| 594 | 594 | <button class="button--icon row-actions kebab-btn" data-act="contextMenus.showEvent" data-a1="@event" data-a2="${escAttr(e.id)}" title="Actions" aria-label="Event actions">⋮</button> | |
| 595 | 595 | </div> |
| @@ -157,10 +157,10 @@ | |||
| 157 | 157 | ${t.contactName ? `<span class="contact-badge" title="${escAttrVal(t.contactName)}">${esc(t.contactName)}</span>` : ''} | |
| 158 | 158 | ${t.isSnoozed ? `<span class="snooze-badge" title="Snoozed until ${escAttr(t.snoozedUntilFormatted || '')}" aria-label="Snoozed until ${escAttr(t.snoozedUntilFormatted || '')}">Snoozed</span>` : ''} | |
| 159 | 159 | </div> | |
| 160 | - | <div class="task-cell task-project">${esc(t.projectName) || '-'}${GoingsOn.groups.taskSharedBadge(t.projectId)}</div> | |
| 160 | + | <div class="task-cell row-secondary task-project">${esc(t.projectName) || '-'}${GoingsOn.groups.taskSharedBadge(t.projectId)}</div> | |
| 161 | 161 | <div class="task-cell priority-${t.priority.toLowerCase()}" aria-label="Priority ${t.priority}">${t.priority.charAt(0)}</div> | |
| 162 | - | <div class="task-cell task-due">${t.dueFormatted || '-'}</div> | |
| 163 | - | <div class="task-cell task-recurrence">${formatRecurrence(t)}</div> | |
| 162 | + | <div class="task-cell row-meta task-due">${t.dueFormatted || '-'}</div> | |
| 163 | + | <div class="task-cell row-secondary task-recurrence">${formatRecurrence(t)}</div> | |
| 164 | 164 | <div class="task-cell task-progress"> | |
| 165 | 165 | ${t.subtaskCount > 0 ? ` | |
| 166 | 166 | <div class="progress" title="${t.subtaskCompleted}/${t.subtaskCount} subtasks" | |
| @@ -168,7 +168,7 @@ | |||
| 168 | 168 | aria-label="${t.subtaskCompleted} of ${t.subtaskCount} subtasks completed"> | |
| 169 | 169 | <div class="progress-fill" data-tone="success" style="width: ${progress}%"></div> | |
| 170 | 170 | </div> | |
| 171 | - | ` : '<span class="no-subtasks">-</span>'} | |
| 171 | + | ` : '<span class="row-secondary no-subtasks">-</span>'} | |
| 172 | 172 | </div> | |
| 173 | 173 | <div class="task-cell task-actions-cell"> | |
| 174 | 174 | ${renderRowActions(t, isStarted)} |