mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
* [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>
183 lines
9.3 KiB
Markdown
183 lines
9.3 KiB
Markdown
# Task Detail Navigation & Timestamps
|
|
|
|
This guide documents three related UI features added to the task-detail page: inline absolute timestamps, parent-task breadcrumbs, and list-context-aware prev/next navigation.
|
|
|
|
## Inline Absolute Timestamps
|
|
|
|
**Location:** `panel/src/lib/utils.ts`, `formatAbsoluteTimestamp()`
|
|
|
|
All progress updates and checkpoints now display a standardized absolute timestamp (e.g., "Jul 10, 2026, 3:45 PM") **in addition to** the existing relative time text (e.g., "2m ago"). The absolute format is consistent across the panel, achieved via a shared helper that was extracted from the earlier `checkpoint-card.tsx` local implementation.
|
|
|
|
### Implementation
|
|
|
|
```typescript
|
|
// lib/utils.ts
|
|
export function formatAbsoluteTimestamp(timestamp: string): string {
|
|
return new Date(timestamp).toLocaleString("en-US", {
|
|
year: "numeric",
|
|
month: "short",
|
|
day: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
}
|
|
```
|
|
|
|
### Usage in Components
|
|
|
|
- **`tab-progress.tsx` ProgressUpdatesSection:** Each progress entry now shows relative time + `·` + absolute time on the same line, with the absolute time also in the `title` tooltip for hover clarity.
|
|
- **`tab-progress.tsx` CheckpointsSection:** Same treatment as progress updates.
|
|
- **`progress-timeline.tsx`:** In the timeline view, relative time + absolute time on the same line.
|
|
- **`checkpoint-card.tsx`:** The checkpoint component now uses the shared helper instead of its own format.
|
|
|
|
The relative time remains the primary visual — it's glanceable. The absolute time is the secondary, precise reference, useful when comparing timestamps across different time zones or when exact dates matter (e.g., "was this before or after June 30?").
|
|
|
|
## Parent Task Breadcrumb
|
|
|
|
**Location:** `panel/src/components/tasks/task-detail/task-breadcrumb.tsx`
|
|
|
|
When a task has a parent, a breadcrumb renders above the task title: `Parent Title > Child Title`. The breadcrumb is absent for root tasks (those with `parent_task_id = null`), keeping the UI clean for single-level work.
|
|
|
|
### Implementation Details
|
|
|
|
- Renders only if `task.parent_task_id` is set; otherwise returns `null`.
|
|
- Uses `useTask(parentId)` to fetch the parent task data (title + styling).
|
|
- While loading, a skeleton placeholder avoids layout shift.
|
|
- The parent title is a clickable link to `/tasks/{parent.id}`.
|
|
- Long titles are truncated with a `title` attribute tooltip.
|
|
- Only the immediate parent is shown — deeper ancestry is reachable by following the chain one hop at a time, matching how the rest of the panel represents task hierarchy.
|
|
|
|
### Example
|
|
|
|
If Task B is a child of Task A:
|
|
- Viewing Task B shows: `Task A > Task B`
|
|
- Clicking "Task A" navigates to that parent
|
|
- If Task A also has a parent, viewing Task A shows that grandparent, not Task B
|
|
|
|
This recursive, one-level-at-a-time model prevents breadcrumbs from becoming unwieldy and mirrors the panel's task-tree representation elsewhere.
|
|
|
|
## Prev/Next Task Navigation
|
|
|
|
**Location:** `panel/src/components/tasks/task-detail/task-list-nav.tsx`
|
|
|
|
Two chevron buttons (← →) on the task-detail page move to the adjacent task **within the current Tasks list filter/sort context**. This preserves the user's list view experience: if they filtered by status, sorted by priority, or searched for a term, those same filters apply when they navigate prev/next.
|
|
|
|
### How It Works
|
|
|
|
1. **List context capture:** The Tasks page (`tasks/page.tsx`) passes the currently visible task IDs (id + title) to `useScrollRestorationStore.setTaskListNav()` whenever the table's filtered/sorted order changes. The context includes the full query string (filters, search, sort) so a "Back to list" link can restore the exact view.
|
|
|
|
2. **Session-scoped state:** The context lives in `sessionStorage` via Zustand's persist middleware. It survives navigation within the same browser session but is cleared if the browser is closed. This matches the "come back where you left off" UX without persisting across sessions.
|
|
|
|
3. **Fallback when no context:** If the user navigates to a task via a direct link, search result, notification, or any path that doesn't pass through the Tasks list, `taskListNav` is `null`. Both buttons render **disabled** with a tooltip explaining: "Open this task from the Tasks list to enable prev/next navigation within that list's filter/sort order." This is the **documented fallback** — no guessing, no silent behavior change.
|
|
|
|
4. **Edge cases:**
|
|
- **First item in list:** Prev button is disabled; next is enabled.
|
|
- **Last item in list:** Next button is disabled; prev is enabled.
|
|
- **Task not in captured list:** Both buttons are disabled (task was navigated to via another route after the list was visited).
|
|
- **Query string preservation:** The href for each nav link includes the original query string, so navigating back to the Tasks page from a nested task restores the same filters.
|
|
|
|
### Components
|
|
|
|
**`TaskListNav`:** The main export. Reads `taskListNav` from the store, computes prev/next items, and renders two `NavButton` children.
|
|
|
|
**`NavButton`:** A single direction button. If enabled, it wraps a Next.js `<Link>`; if disabled, it's a plain button with a tooltip explaining why. The tooltip shows either the next task's title (when enabled) or the reason it's disabled.
|
|
|
|
### Implementation Example
|
|
|
|
```typescript
|
|
export function TaskListNav({ task }: TaskListNavProps) {
|
|
const context = useScrollRestorationStore((state) => state.taskListNav);
|
|
|
|
const items = context?.items ?? [];
|
|
const index = items.findIndex((item) => item.id === task.id);
|
|
const hasContext = index !== -1;
|
|
const prevItem = hasContext && index > 0 ? items[index - 1] : null;
|
|
const nextItem =
|
|
hasContext && index < items.length - 1 ? items[index + 1] : null;
|
|
|
|
const query = context?.queryString ? `?${context.queryString}` : "";
|
|
// Render NavButton for each direction with the computed item and query
|
|
}
|
|
```
|
|
|
|
## Store Extension
|
|
|
|
**Location:** `panel/src/lib/stores/scroll-restoration-store.ts`
|
|
|
|
The `useScrollRestorationStore` (already managing scroll positions, section expansions, etc.) now includes:
|
|
|
|
- **`taskListNav: TaskListNavContext | null`** — The current task list context, or `null` if no list has been visited.
|
|
- **`setTaskListNav(context: TaskListNavContext)`** — Updates the context when the Tasks table reports a new visible order.
|
|
|
|
### Schema
|
|
|
|
```typescript
|
|
export interface TaskListNavItem {
|
|
id: string;
|
|
title: string;
|
|
}
|
|
|
|
export interface TaskListNavContext {
|
|
items: TaskListNavItem[];
|
|
queryString: string; // e.g., "status=in_progress&sort=-created_at"
|
|
}
|
|
```
|
|
|
|
The store uses `sessionStorage` persistence, so state is automatically restored on page reload within the same session but is cleared when the session ends.
|
|
|
|
## Integration Points
|
|
|
|
### Tasks List Page (`tasks/page.tsx`)
|
|
|
|
Calls `setTaskListNav()` whenever the table's visible order changes:
|
|
|
|
```typescript
|
|
const setTaskListNav = useScrollRestorationStore((state) => state.setTaskListNav);
|
|
const handleVisibleOrderChange = useCallback(
|
|
(items: { id: string; title: string }[]) => {
|
|
setTaskListNav({ items, queryString: searchParamsString });
|
|
},
|
|
[setTaskListNav, searchParamsString],
|
|
);
|
|
```
|
|
|
|
### TaskTable (`components/tasks/task-table.tsx`)
|
|
|
|
Now accepts an optional `onVisibleOrderChange` callback, fired whenever the computed visible task order changes (e.g., on filter, sort, pagination, or expansion/collapse). The Tasks page wires this callback to capture the order.
|
|
|
|
### Task Detail Page (`[taskId]/page.tsx`)
|
|
|
|
Renders both `TaskBreadcrumb` and `TaskListNav` near the top of the page, in a flex row:
|
|
|
|
```tsx
|
|
<div className="flex items-center justify-between gap-4">
|
|
<TaskBreadcrumb task={task} />
|
|
<TaskListNav task={task} />
|
|
</div>
|
|
```
|
|
|
|
The breadcrumb takes the left; nav buttons take the right, preserving the layout for long parent titles.
|
|
|
|
## Design Considerations
|
|
|
|
### Why relative + absolute times?
|
|
|
|
Relative times ("2m ago") are glanceable but ambiguous across time zones and when comparing entries hours or days apart. Absolute times are precise but verbose if shown alone. Combining them gives quick context (relative) + accuracy (absolute) without sacrificing space.
|
|
|
|
### Why session-scoped, not persistent?
|
|
|
|
Task lists reflect current filters, which change frequently. Persisting a stale list order across sessions (e.g., "I opened this task from a filtered search yesterday, but I reopened the browser and the filter is gone") would silently navigate to the wrong next task. Session scope keeps the invariant: prev/next only works within the current session's list context.
|
|
|
|
### Why disable instead of guess?
|
|
|
|
A task opened via direct link, notification, or external system doesn't have a parent list context. We could try to infer one (e.g., "show all tasks" or "show tasks in this project"), but that's invisible magic — the user wouldn't know why they're seeing a particular next task. Disabling with a clear explanation ("open from the list to enable this") is explicit and honest.
|
|
|
|
## Future Extensions
|
|
|
|
Possible enhancements:
|
|
|
|
1. **Remember list context across sessions:** A "pin this list" feature could persist context across browser sessions.
|
|
2. **Breadcrumb depth:** Allow showing full ancestry (A > B > C) instead of one level; would require more space and careful truncation.
|
|
3. **Recently viewed tasks:** A dropdown of tasks you've visited recently, separate from the list context.
|
|
4. **Keyboard shortcuts:** Arrow keys to navigate prev/next when the buttons are enabled.
|