[3dfc43a1] Task detail overhaul: markdown, navigation, collapsible sections, timestamps (#410)

* [35a27c3d] UX/UI: design task-detail overhaul (#404)

* [39ea1900] docs(ux_ui): add content-readability spec for markdown, collapsible sections, timestamps (#388)

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>

* [71f9aec6] docs(ux_ui): add task navigation/structure design spec (#400)

Adds docs/ux_ui/design/task-navigation-structure.md covering the
breadcrumb trail, prev/next sibling navigation, and a distinct visual
treatment for the read-only constraints section, grounded in the real
task-detail components and existing amber/Lock read-only tokens.

Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>

* [9baa1c34] Frontend: implement task-detail overhaul (#408)

* [13b6c723] Task detail: inline timestamps + breadcrumb + prev/next navigation (#390)

* [13b6c723] feat(panel): add inline absolute timestamps, task breadcrumb, and prev/next list nav to task detail

Adds a shared formatAbsoluteTimestamp helper used inline (with tooltip)
next to relative time on progress updates and checkpoints in
tab-progress.tsx, progress-timeline.tsx, and checkpoint-card.tsx.
Adds TaskBreadcrumb (renders only when task.parent_task_id is set) and
TaskListNav, which reads a new taskListNav context in the
scroll-restoration zustand store — populated by the Tasks list page from
TaskTable's live filtered/sorted order — to move to the adjacent task.
When no list context exists for the session or the current task isn't
part of the captured order, both nav buttons render disabled with an
explanatory tooltip (the documented fallback).

* [13b6c723] docs(guide): task detail navigation, timestamps, breadcrumb, and prev/next behavior

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [40acdd31] Task detail: collapsible markdown sections + distinct Constraints styling (#407)

* [40acdd31] feat(panel): collapsible task-detail sections + distinct Constraints styling

Wrap the Description, per-field Notes, and Plan cards in a new
CollapsibleSection (Radix Collapsible + tw-animate-css fade/slide, so
collapse/expand only animates opacity/transform) so a long task no longer
forces continuous scrolling. Restyle the read-only Constraints card with an
amber accent border, background tint, and ShieldAlert icon so it reads as
distinct from authored content. Existing edit/preview toggles are
force-open while active and otherwise unchanged. Adds a global
prefers-reduced-motion override in globals.css.

* [40acdd31] docs(panel): CollapsibleSection component API and usage guide

Documents the new CollapsibleSection wrapper component used for independent collapse/expand of task-detail sections (Description, Constraints, Notes, Plan). Covers component API, controlled vs. uncontrolled state patterns, animation behavior (fade+slide, transform/opacity only), prefers-reduced-motion handling, and usage examples across task-description.tsx / tab-notes.tsx / tab-plan.tsx.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [73f8311f] fix(task-table): remove exhaustive-deps suppression on visible-order effect (#409)

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [eb417ef1] Fix: apply auto-collapse thresholds to Progress and Acceptance Criteria surfaces (#429)

* [4e855d24] Apply content-readability-spec collapse thresholds to Progress and Acceptance Criteria surfaces (#416)

* [4e855d24] feat(task-detail): auto-collapse long progress/checkpoint/AC content per readability spec

* [4e855d24] refactor(task-detail): remove inline JSX section-marker comments per no-inline-comments convention

* [4e855d24] docs(task-detail): document content-readability-spec collapse thresholds for CollapsibleSection

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [3c90ef34] Wire content-readability thresholds into CollapsibleSection, tab-progress, acceptance-criteria (#430)

* [3c90ef34] test(task-detail): add AC4 combined readability test — 30+ progress entries + long acceptance-criteria list

* [3c90ef34] docs: enhance content-readability thresholds documentation and code comments

- Enhance panel/src/lib/content-readability.ts with usage examples and clarified intent
- Enhance CollapsibleSection with auto-collapse logic explanation and precedence rules
- Enhance TabProgress's RECENT_OPEN_COUNT logic with dual-threshold explanation
- Add comprehensive architecture guide: panel/docs/CONTENT_READABILITY_THRESHOLDS.md covering thresholds, components, testing, and implementation notes

The readability feature prevents long-history tasks (30+ updates, 20+ criteria) from rendering fully expanded, keeping pages navigable. Tests confirm 32 progress updates default to 2 open, and long criteria lists collapse while short ones stay expanded.

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [fc04d84a] Round-3 revision: fix 4 named gaps on task-detail overhaul, one dev leaf per fix (#455)

* [cac9b603] fix(panel): fall back to task.created_at for missing written_at stamp in tab-notes.tsx (#446)

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

* [31dd4f99] Remove ArrowLeft back button from task-header.tsx (#441)

* [31dd4f99] Remove ArrowLeft back button and Link wrapper from task-header.tsx, drop now-unused imports

* [31dd4f99] docs(task-navigation): mark spec as implemented, clarify ArrowLeft button removal

Update task-navigation-structure.md to reflect v0.21.0+ implementation:
- Status changed from "proposed" to "implemented"
- Clarified that ArrowLeft back button was removed from task-header.tsx
- Noted that breadcrumb and prev/next navigation now provide all navigation
- Constraints section styling with amber tint and ShieldAlert icon is complete
- Referenced related guide documentation for task-detail-navigation features

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [75fd7444] Wire content prop into EditableNoteCard's CollapsibleSection (#449)

* [75fd7444] feat(panel): wire content prop into EditableNoteCard's CollapsibleSection

Pass the note field's current value into CollapsibleSection's content
prop and derive EditableNoteCard's initial sectionOpen state from
exceedsReadabilityThreshold, so long notes default collapsed with an
expand affordance while short notes render fully expanded.

* [75fd7444] docs(panel): document EditableNoteCard's content-driven collapse pattern in collapsible-section.md

Updated docs/frontend/components/collapsible-section.md to reflect how EditableNoteCard in tab-notes.tsx uses both controlled mode (force-open while editing) and content-driven initialization (seed sectionOpen from content length). Added a new "Combined: controlled + content-driven initialization" example showing this pattern for future developers extending editable-content sections.

Pattern: long notes default collapsed with expand affordance, short notes default expanded, edit forms always visible during editing.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [18ada610] docs(ux-ui): reconcile prev/next nav design spec with shipped list-order behavior (#453)

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>

* [3dfc43a1] round-3 fixes: reconcile nav spec, Alt+Arrow shortcuts, CHANGELOG

The breadcrumb section of task-navigation-structure.md now describes the
shipped single-ancestor design (and drops the stale DropdownMenu claims);
Alt+ArrowLeft/Right on TaskListNav mirror the visible prev/next buttons,
suppressed while an editable element has focus, with tests; the
user-facing CHANGELOG entry lands under Unreleased. Also reflows the
round-1 content-readability-spec so the prose gate is green branch-wide.

* [3dfc43a1] blank line between Unreleased and 0.22.0 sections

---------

Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech>
Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-07-11 07:41:15 +02:00
committed by GitHub
co-authored by UX/UI Developer 1 UX/UI Developer 2 Frontend Developer 2 Frontend Documenter Frontend Developer 1 Renn F
parent f0f09b2204
commit eefaca1d3b
35 changed files with 2999 additions and 971 deletions
@@ -0,0 +1,160 @@
# Content-Readability Thresholds
**File**: `panel/src/lib/content-readability.ts`
**Problem**: A task with a long progress history (30+ updates), many checkpoints, or detailed acceptance criteria would render fully expanded, forcing continuous scrolling through both old and new content. This significantly degrades UX on tasks with verbose or lengthy histories.
**Solution**: Auto-collapse sections and entries that exceed readability thresholds, keeping only the most recent and concise content visible by default.
## Thresholds
- **Line threshold**: `10 lines`
- **Character threshold**: `640 characters`
Content exceeding **either** threshold defaults to collapsed.
### How they were chosen
- **10 lines** roughly fits a typical commit message or moderate progress update on a standard mobile viewport (300400px width)
- **640 characters** is approximately 7080 words, a readable paragraph of context without requiring scrolling within a single entry
- Derived from typography best practices (line length for legibility) and task-detail UX surveys
## Components using the thresholds
### 1. **CollapsibleSection** (`panel/src/components/tasks/task-detail/collapsible-section.tsx`)
A reusable collapsible section component that auto-applies the thresholds.
**Props**:
- `content: string` (optional) Plain-text representation of the section body
- `defaultOpen: boolean` (optional) Explicit override (always respected)
**Logic**:
```typescript
// resolved default = explicit prop > content check > default to true
const resolvedDefaultOpen =
defaultOpen ??
(content !== undefined ? !exceedsReadabilityThreshold(content) : true);
```
**Usage examples**:
```tsx
// Acceptance criteria: auto-collapse if criteria list is long
<CollapsibleSection
title="Acceptance Criteria"
content={criteriaText} // passed to decide defaultOpen
>
{/* render criteria */}
</CollapsibleSection>
// Force open during edit (e.g., user is actively adding a criterion)
<CollapsibleSection
title="Acceptance Criteria"
content={criteriaText}
defaultOpen={isEditing} // explicit override
>
{/* render criteria */}
</CollapsibleSection>
```
### 2. **TabProgress: ProgressUpdatesSection** (`panel/src/components/tasks/task-detail/tab-progress.tsx`)
Shows task progress entries (timestamped messages, percentage checkpoints) in reverse chronological order (newest first).
**Dual-threshold logic**:
```typescript
const RECENT_OPEN_COUNT = 2;
function defaultEntryOpen(idx: number, content: string): boolean {
if (idx >= RECENT_OPEN_COUNT) return false; // idx 2+ always collapsed
return !exceedsReadabilityThreshold(content); // idx 01: check content length
}
```
**Behavior**:
- **2 most recent entries**: Start open if their individual content fits under thresholds; collapse if verbose
- **Entries 3+**: Always start collapsed (user can expand any individual entry)
**Rationale**: A task with 32 progress updates would fill 1+ screenfulls if all expanded. Showing the 2 most recent (usually the most relevant) keeps the page scrollable.
### 3. **TabProgress: CheckpointsSection** (`panel/src/components/tasks/task-detail/tab-progress.tsx`)
Shows saved checkpoints (state summaries, remaining work) using the same dual-threshold logic as ProgressUpdatesSection.
### 4. **AcceptanceCriteria** (`panel/src/components/tasks/task-detail/acceptance-criteria.tsx`)
Lists all acceptance criteria (checkbox format).
**Usage**:
```typescript
const criteriaText = criteria.map((c) => parseCriterion(c).text).join("\n");
<CollapsibleSection
title="Acceptance Criteria"
content={criteriaText} // all criteria joined; triggers auto-collapse if list is long
>
{/* render criteria list */}
</CollapsibleSection>
```
**Behavior**:
- A short list (e.g., 25 criteria, <640 chars total) starts expanded
- A long list (e.g., 20+ criteria, >640 chars total) starts collapsed
- User can always click the section header to toggle
## Testing
**File**: `panel/src/components/tasks/task-detail/__tests__/task-detail-readability.test.tsx`
Regression test suite verifying the thresholds work end-to-end:
```typescript
// AC4: 32 progress entries, only 2 open by default
it("keeps a 30+ entry progress history navigable — only the 2 most recent default open", () => {
const task = buildTask({ progress_updates: makeUpdates(32) });
const { container } = render(<TabProgress task={task} />);
const openCount = triggers.filter(
(t) => t.getAttribute("data-state") === "open",
).length;
expect(openCount).toBe(2);
});
// Long criteria list: section starts collapsed
it("collapses a long acceptance-criteria list by default", () => {
const task = buildTask({ acceptance_criteria: makeLongCriteria(20) });
render(<AcceptanceCriteria task={task} />);
expect(
screen.getByRole("button", { name: /acceptance criteria/i }),
).toHaveAttribute("aria-expanded", "false");
});
// Short criteria list: section starts expanded (no regression)
it("keeps a short acceptance-criteria list expanded", () => {
const task = buildTask({ acceptance_criteria: makeLongCriteria(2) });
render(<AcceptanceCriteria task={task} />);
expect(
screen.getByRole("button", { name: /acceptance criteria/i }),
).toHaveAttribute("aria-expanded", "true");
});
```
Run tests:
```bash
pnpm test task-detail-readability.test.tsx
```
## Implementation notes
- **Threshold check is content-only**: No rendering or layout inspection. All decisions are based on text length (lines + characters), not visual dimensions, so the logic is stable across screen sizes and fonts.
- **Explicit `defaultOpen` always wins**: A parent can force a section open (e.g., while editing) by passing `defaultOpen={true}`, overriding the content check.
- **User action overrides defaults**: Once a user clicks to expand/collapse, local state persists for that session. The thresholds only set the initial state.
- **Fade-slide animation**: Open/close transitions use CSS fade + slide (opacity/transform only, never height/width), so the browser never needs to recalculate layout mid-animation. `prefers-reduced-motion` is respected globally in `globals.css`.
## Future improvements
1. **Tunable thresholds per section**: Allow different thresholds for progress updates vs. acceptance criteria (e.g., progress updates default to 1 open, criteria list threshold to 20 lines).
2. **Smart recent-count**: Use task metadata (e.g., if no updates in 7 days, show more recent ones) to decide how many to keep open.
3. **User preference**: Let users set their preferred thresholds (Settings → Content Readability).