From a630ad778f87db943b26a7ce4eac7298fc4c7bb8 Mon Sep 17 00:00:00 2001 From: hechang27-sprt Date: Thu, 26 Mar 2026 15:33:57 +0800 Subject: [PATCH] chore: record journal --- .../check.jsonl | 2 + .../debug.jsonl | 1 + .../implement.jsonl | 4 + .../03-25-list-table-v2-timestamp-jsx/prd.md | 71 +++++++++++ .../task.json | 44 +++++++ .trellis/tasks/plan-resize-probe-row.md | 120 ++++++++++++++++++ .trellis/workspace/hechang27-sprt/index.md | 7 +- .../workspace/hechang27-sprt/journal-1.md | 32 +++++ 8 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 .trellis/tasks/03-25-list-table-v2-timestamp-jsx/check.jsonl create mode 100644 .trellis/tasks/03-25-list-table-v2-timestamp-jsx/debug.jsonl create mode 100644 .trellis/tasks/03-25-list-table-v2-timestamp-jsx/implement.jsonl create mode 100644 .trellis/tasks/03-25-list-table-v2-timestamp-jsx/prd.md create mode 100644 .trellis/tasks/03-25-list-table-v2-timestamp-jsx/task.json create mode 100644 .trellis/tasks/plan-resize-probe-row.md diff --git a/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/check.jsonl b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/check.jsonl new file mode 100644 index 0000000..81114a7 --- /dev/null +++ b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/check.jsonl @@ -0,0 +1,2 @@ +{"file": ".claude/commands/trellis/finish-work.md", "reason": "Finish work checklist"} +{"file": ".claude/commands/trellis/check-frontend.md", "reason": "Frontend check spec"} diff --git a/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/debug.jsonl b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/debug.jsonl new file mode 100644 index 0000000..837f464 --- /dev/null +++ b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/debug.jsonl @@ -0,0 +1 @@ +{"file": ".claude/commands/trellis/check-frontend.md", "reason": "Frontend check spec"} diff --git a/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/implement.jsonl b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/implement.jsonl new file mode 100644 index 0000000..0301f6b --- /dev/null +++ b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/implement.jsonl @@ -0,0 +1,4 @@ +{"file": ".trellis/workflow.md", "reason": "Project workflow and conventions"} +{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend development guide"} +{"file": "packages/base/data/list-table-v2.vue", "reason": "Main component being modified"} +{"file": "packages/base/item/tzDateTime.vue", "reason": "Referenced for timestamp implementation"} diff --git a/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/prd.md b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/prd.md new file mode 100644 index 0000000..0d2f721 --- /dev/null +++ b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/prd.md @@ -0,0 +1,71 @@ +# list-table-v2 Timestamp + Vue JSX + +## Goal + +Add Vue JSX support to the project and upgrade `list-table-v2.vue` to use `tzDateTime.vue` for timestamp columns with enhanced type support. + +## Requirements + +### 1. Enable Vue JSX +- Install `@vitejs/plugin-vue-jsx` package +- Add JSX plugin to `vite.config.ts` + +### 2. Enhanced Timestamp Type + +Update `TableColumn.timestamp` type from `boolean` to: +```typescript +undefined | boolean | string | { + valueFormat?: string; + valueTz?: string; + displayFormat?: string; + locale?: string; + type?: "iso8601" | "unix" | "unixMillis"; +} +``` + +**Behavior:** +- `undefined` or falsy → column is not a timestamp +- `true` → equivalent to `{ type: 'unixMillis', displayFormat: 'YYYY-MM-DD HH:mm:ss' }` +- `string` → pass to either `type` or `valueFormat` depending on the value +- Otherwise → pass as props to `TzDateTime` + +### 3. Use tzDateTime.vue for Timestamp Columns +- Import `TzDateTime` component in `list-table-v2.vue` +- Replace inline `formatStamp` with `TzDateTime` component via JSX rendering +- Ensure dayjs plugins are loaded when needed + +## Technical Notes + +### Files to Modify +1. `vite.config.ts` - Add JSX plugin +2. `packages/base/data/list-table-v2.vue` - Update timestamp handling + +### tzDateTime Props Interface +```typescript +interface Props { + value: string | number; + valueFormat?: string; + valueTz?: string; + displayFormat?: string; + locale?: string; + type?: "iso8601" | "unix" | "unixMillis"; + slot?: boolean; +} +``` + +### Conversion Logic +``` +timestamp value → TzDateTime props: +- timestamp=true → { type: 'unixMillis', displayFormat: 'YYYY-MM-DD HH:mm:ss' } +- timestamp='unix' → { type: 'unix' } (shorthand) +- timestamp='YYYY-MM-DD' → { valueFormat: 'YYYY-MM-DD' } +- timestamp={ type: 'iso8601' } → passed directly +``` + +## Acceptance Criteria +- [ ] `@vitejs/plugin-vue-jsx` installed +- [ ] `vite.config.ts` includes JSX plugin +- [ ] `TableColumn` interface updated with new timestamp type +- [ ] `list-table-v2.vue` uses `TzDateTime` for timestamp columns +- [ ] Backward compatible with existing `timestamp={true}` usage +- [ ] TypeScript compiles without errors diff --git a/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/task.json b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/task.json new file mode 100644 index 0000000..767f90b --- /dev/null +++ b/.trellis/tasks/03-25-list-table-v2-timestamp-jsx/task.json @@ -0,0 +1,44 @@ +{ + "id": "list-table-v2-timestamp-jsx", + "name": "list-table-v2-timestamp-jsx", + "title": "list-table-v2 timestamp + vue jsx", + "description": "", + "status": "planning", + "dev_type": null, + "scope": null, + "priority": "P2", + "creator": "hechang27-sprt", + "assignee": "hechang27-sprt", + "createdAt": "2026-03-25", + "completedAt": null, + "branch": null, + "base_branch": "dev", + "worktree_path": null, + "current_phase": 0, + "next_action": [ + { + "phase": 1, + "action": "implement" + }, + { + "phase": 2, + "action": "check" + }, + { + "phase": 3, + "action": "finish" + }, + { + "phase": 4, + "action": "create-pr" + } + ], + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [], + "notes": "", + "meta": {} +} \ No newline at end of file diff --git a/.trellis/tasks/plan-resize-probe-row.md b/.trellis/tasks/plan-resize-probe-row.md new file mode 100644 index 0000000..9c0de04 --- /dev/null +++ b/.trellis/tasks/plan-resize-probe-row.md @@ -0,0 +1,120 @@ +# Plan: Viewport Resize Handling for list-table-v2 + +## 1. Problem Analysis + +### Current State +- The `list-table-v2` component uses a probe row technique to dynamically measure row height when `rowHeight` is NOT explicitly set (dynamic height mode) +- The `measureProbeRow` function (lines 217-231) already exists and correctly: + - Clears `estimatedRowHeight.value` before re-measuring + - Uses TWO `requestAnimationFrame` calls after `nextTick` to let el-table-v2 fully settle + - Measures the probe row's `offsetHeight` + +### Problem +- When the viewport width changes, column widths may adjust (due to `flexGrow: 1` in `tableColumns` computed) +- This can cause row heights to change, but currently there is no trigger to re-measure +- Without re-measuring, the `estimatedRowHeight` may become inaccurate, causing layout issues + +### Constraints (from previous attempts) +1. ResizeObserver on container caused errors in component setup - AVOID +2. Must use TWO `requestAnimationFrame` calls after `nextTick` for proper el-table-v2 settlement +3. Must clear `estimatedRowHeight` before re-measuring for el-table-v2 to recalculate properly + +--- + +## 2. Implementation Approach + +### Strategy +Add a debounced window resize event listener that: +1. Checks if dynamic height mode is active (`shouldUseProbeRow`) +2. Calls the existing `measureProbeRow` function +3. Cleans up properly on component unmount + +### Why Window Resize Instead of ResizeObserver +- `el-auto-resizer` already handles container size changes internally +- Window resize is the correct trigger because column widths change based on viewport width (via `flexGrow`) +- ResizeObserver on container caused setup errors in previous attempts + +### Debounce Strategy +- Use lodash's `debounce` (already imported as `lodash-es`) +- Debounce delay: ~200-300ms to avoid excessive recalculations during active resize +- The debounced function will be created with `onMounted` and cleaned up with `onUnmounted` + +--- + +## 3. Code Changes Needed + +### File: `/home/hechang27/Documents/sprt/noob-components/packages/base/data/list-table-v2.vue` + +#### Import Additions (line 53) +```typescript +import { ref, computed, watch, h, onMounted, onUpdated, onUnmounted, useSlots, renderSlot, nextTick } from "vue"; +``` + +#### New State Variable +After line 66 (`const estimatedRowHeight = ref(undefined);`): +```typescript +// Debounced resize handler for re-measuring probe row +const debouncedResizeHandler = ref<() => void>(); +``` + +#### New Lifecycle Hooks +After line 214 (after the existing `watch` block): + +```typescript +// Setup resize listener on mount +onMounted(() => { + // Create debounced handler + debouncedResizeHandler.value = lodash.debounce(() => { + // Only re-measure in dynamic height mode + if (shouldUseProbeRow.value) { + measureProbeRow(); + } + }, 250); // 250ms debounce delay + + // Attach window resize listener + window.addEventListener('resize', debouncedResizeHandler.value); +}); + +// Cleanup on unmount +onUnmounted(() => { + if (debouncedResizeHandler.value) { + window.removeEventListener('resize', debouncedResizeHandler.value); + debouncedResizeHandler.value.cancel(); // Cancel any pending debounce calls + } +}); +``` + +--- + +## 4. Verification Steps + +### Manual Testing +1. Open a page using `list-table-v2` without explicit `rowHeight` prop +2. Open browser DevTools and inspect a row element to see its height +3. Resize the browser window (change width) +4. Verify that: + - No console errors occur during resize + - The row height is recalculated correctly after resize settles + - The table layout remains correct after resize + +### Edge Cases to Verify +1. **Rapid resize**: Resize window quickly back and forth - should not cause errors or excessive measurements +2. **Minimum width**: Table should handle minimum width gracefully without breaking +3. **No explicit rowHeight**: Verify resize handling is NOT active when `rowHeight` IS set (fixed height mode) +4. **Unmount cleanup**: Navigate away from the page and verify no memory leaks or hanging listeners + +### Code Review Checklist +- [ ] `onUnmounted` is imported and used +- [ ] Debounced handler is properly cancelled on unmount +- [ ] `shouldUseProbeRow.value` check prevents unnecessary calls in fixed-height mode +- [ ] Two RAF frames are used in `measureProbeRow` (existing pattern preserved) +- [ ] `estimatedRowHeight` is cleared before re-measuring (existing pattern preserved) + +--- + +## 5. Dependencies + +- lodash-es debounce (already imported) +- Vue lifecycle hooks (already available) + +No new dependencies required. diff --git a/.trellis/workspace/hechang27-sprt/index.md b/.trellis/workspace/hechang27-sprt/index.md index 186a5fc..2997e4d 100644 --- a/.trellis/workspace/hechang27-sprt/index.md +++ b/.trellis/workspace/hechang27-sprt/index.md @@ -8,8 +8,8 @@ - **Active File**: `journal-1.md` -- **Total Sessions**: 2 -- **Last Active**: 2026-03-25 +- **Total Sessions**: 3 +- **Last Active**: 2026-03-26 --- @@ -19,7 +19,7 @@ | File | Lines | Status | |------|-------|--------| -| `journal-1.md` | ~72 | Active | +| `journal-1.md` | ~104 | Active | --- @@ -29,6 +29,7 @@ | # | Date | Title | Commits | |---|------|-------|---------| +| 3 | 2026-03-26 | Add viewport resize handling for list-table-v2 | `96fef48` | | 2 | 2026-03-25 | Create list-table-v2.vue with el-table-v2 | `2a2bba8`, `1024bb1` | | 1 | 2026-03-24 | Bootstrap coding specs with CC + Codex pipeline | `785e6b2` | diff --git a/.trellis/workspace/hechang27-sprt/journal-1.md b/.trellis/workspace/hechang27-sprt/journal-1.md index 59d610e..fce22d7 100644 --- a/.trellis/workspace/hechang27-sprt/journal-1.md +++ b/.trellis/workspace/hechang27-sprt/journal-1.md @@ -70,3 +70,35 @@ Implemented list-table-v2.vue using Element Plus el-table-v2 with virtual scroll ### Next Steps - None - task complete + + +## Session 3: Add viewport resize handling for list-table-v2 + +**Date**: 2026-03-26 +**Task**: Add viewport resize handling for list-table-v2 + +### Summary + +Implemented debounced window resize handler (250ms) to re-measure probe row height when viewport changes. Only active in dynamic height mode (when rowHeight is undefined). Properly cleans up on unmount. Fixed TypeScript typing for lodash debounce cancel method. + +### Main Changes + + + +### Git Commits + +| Hash | Message | +|------|---------| +| `96fef48` | (see git log) | + +### Testing + +- [OK] (Add test results) + +### Status + +[OK] **Completed** + +### Next Steps + +- None - task complete