From 472974bd3dd4604655a3d7d400820bb9e195405b Mon Sep 17 00:00:00 2001 From: rickcedwhat-ai Date: Wed, 13 May 2026 00:59:01 -0400 Subject: [PATCH 1/9] docs(lab): add LabConcurrencyAnimator, clean up lab components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add LabConcurrencyAnimator: animated 3-scenario × 3-mode concurrency demo (all-DOM, column-virtual, click-for-name) with broken-mode reveal, speed controls, cursor animation, table shake, and avatar expansion - Add ConfigSwatch and MethodBadge utility components - Update LabDebuggerWidget and LabGetRowTrace - Remove placeholder lab components no longer needed Co-Authored-By: Claude Sonnet 4.6 --- .../theme/components/ConfigSwatch.vue | 89 ++ .../theme/components/MethodBadge.vue | 35 + .../components/lab/LabConcurrencyAnimator.vue | 919 ++++++++++++++++++ .../theme/components/lab/LabDebugPlayback.vue | 140 --- .../components/lab/LabDebuggerWidget.vue | 11 +- .../theme/components/lab/LabFailureStates.vue | 111 --- .../theme/components/lab/LabGetRowTrace.vue | 183 +++- .../components/lab/LabMethodWalkthrough.vue | 180 ---- .../components/lab/LabStrategyPicker.vue | 64 -- .../components/lab/LabTableTypeGallery.vue | 104 -- docs/.vitepress/theme/index.ts | 16 +- docs/lab/index.md | 101 ++ 12 files changed, 1301 insertions(+), 652 deletions(-) create mode 100644 docs/.vitepress/theme/components/ConfigSwatch.vue create mode 100644 docs/.vitepress/theme/components/MethodBadge.vue create mode 100644 docs/.vitepress/theme/components/lab/LabConcurrencyAnimator.vue delete mode 100644 docs/.vitepress/theme/components/lab/LabDebugPlayback.vue delete mode 100644 docs/.vitepress/theme/components/lab/LabFailureStates.vue delete mode 100644 docs/.vitepress/theme/components/lab/LabMethodWalkthrough.vue delete mode 100644 docs/.vitepress/theme/components/lab/LabStrategyPicker.vue delete mode 100644 docs/.vitepress/theme/components/lab/LabTableTypeGallery.vue create mode 100644 docs/lab/index.md diff --git a/docs/.vitepress/theme/components/ConfigSwatch.vue b/docs/.vitepress/theme/components/ConfigSwatch.vue new file mode 100644 index 00000000..408ca9c0 --- /dev/null +++ b/docs/.vitepress/theme/components/ConfigSwatch.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/docs/.vitepress/theme/components/MethodBadge.vue b/docs/.vitepress/theme/components/MethodBadge.vue new file mode 100644 index 00000000..43fecfd5 --- /dev/null +++ b/docs/.vitepress/theme/components/MethodBadge.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/docs/.vitepress/theme/components/lab/LabConcurrencyAnimator.vue b/docs/.vitepress/theme/components/lab/LabConcurrencyAnimator.vue new file mode 100644 index 00000000..c6c5a907 --- /dev/null +++ b/docs/.vitepress/theme/components/lab/LabConcurrencyAnimator.vue @@ -0,0 +1,919 @@ + + + + + diff --git a/docs/.vitepress/theme/components/lab/LabDebugPlayback.vue b/docs/.vitepress/theme/components/lab/LabDebugPlayback.vue deleted file mode 100644 index 39ecd7db..00000000 --- a/docs/.vitepress/theme/components/lab/LabDebugPlayback.vue +++ /dev/null @@ -1,140 +0,0 @@ - - - - - diff --git a/docs/.vitepress/theme/components/lab/LabDebuggerWidget.vue b/docs/.vitepress/theme/components/lab/LabDebuggerWidget.vue index 80b9311b..12784355 100644 --- a/docs/.vitepress/theme/components/lab/LabDebuggerWidget.vue +++ b/docs/.vitepress/theme/components/lab/LabDebuggerWidget.vue @@ -157,11 +157,11 @@ onUnmounted(() => { }) // --- -const advanceIcon = computed(() => !hasStarted.value ? '▶' : isDone.value ? '✓' : '⏭') -const advanceLabel = computed(() => !hasStarted.value ? 'Play' : isDone.value ? 'Playback complete' : `Run line ${nextLine.value + 1}`) +const advanceIcon = computed(() => !hasStarted.value ? '▶' : isDone.value ? '↺' : '⏭') +const advanceLabel = computed(() => !hasStarted.value ? 'Play' : isDone.value ? 'Replay' : `Run line ${nextLine.value + 1}`) function stepLine() { - if (isDone.value) return + if (isDone.value) { resetDebugger(); return } if (!executedSet.value.has(nextLine.value)) executed.value = [...executed.value, nextLine.value] nextLine.value += 1 } @@ -179,12 +179,9 @@ function cellClass(rowIndex: number, header: string): string {
{{ title ?? 'Debugger widget' }}
- -
diff --git a/docs/.vitepress/theme/components/lab/LabFailureStates.vue b/docs/.vitepress/theme/components/lab/LabFailureStates.vue deleted file mode 100644 index 04fe2fd3..00000000 --- a/docs/.vitepress/theme/components/lab/LabFailureStates.vue +++ /dev/null @@ -1,111 +0,0 @@ - - - - - diff --git a/docs/.vitepress/theme/components/lab/LabGetRowTrace.vue b/docs/.vitepress/theme/components/lab/LabGetRowTrace.vue index 72b6d65c..a6c66237 100644 --- a/docs/.vitepress/theme/components/lab/LabGetRowTrace.vue +++ b/docs/.vitepress/theme/components/lab/LabGetRowTrace.vue @@ -24,31 +24,38 @@ const TARGET_CELL = 'Office' const TARGET_VALUE = 'Sydney' const targetPage = pages.findIndex(p => p.some(r => r.name === TARGET_NAME)) -// idle → checking → rejected (user clicks Next) | found → asserting → done -type Phase = 'idle' | 'checking' | 'rejected' | 'found' | 'asserting' | 'done' +type Scenario = 'success' | 'exhausted' +const scenario = ref('success') +const started = ref(false) +const MAX_PAGES: Record = { success: 5, exhausted: 2 } + +// idle → checking → rejected (user clicks Next) | found → asserting → done | exhausted +type Phase = 'idle' | 'checking' | 'rejected' | 'found' | 'asserting' | 'done' | 'exhausted' const phase = ref('idle') const pageIdx = ref(0) const currentRows = computed(() => pages[pageIdx.value]) function rowState(name: string): 'idle' | 'checking' | 'rejected' | 'match' { - if (phase.value === 'idle') return 'idle' - if (phase.value === 'checking') return 'checking' - if (phase.value === 'rejected') return 'rejected' + if (phase.value === 'idle') return 'idle' + if (phase.value === 'checking') return 'checking' + if (phase.value === 'rejected' || phase.value === 'exhausted') return 'rejected' if (phase.value === 'found' || phase.value === 'asserting' || phase.value === 'done') return name === TARGET_NAME ? 'match' : 'rejected' return 'idle' } const statusText = computed(() => { - if (phase.value === 'idle') return '' - if (phase.value === 'checking') return `checking page ${pageIdx.value + 1}…` - if (phase.value === 'rejected') return `no match on page ${pageIdx.value + 1}` - if (phase.value === 'found') return `✓ found on page ${pageIdx.value + 1}` + if (phase.value === 'idle') return '' + if (phase.value === 'checking') return `checking page ${pageIdx.value + 1}…` + if (phase.value === 'rejected') return `no match on page ${pageIdx.value + 1}` + if (phase.value === 'exhausted') return `✗ maxPages (${MAX_PAGES[scenario.value]}) exhausted — row not found` + if (phase.value === 'found') return `✓ found on page ${pageIdx.value + 1}` if (phase.value === 'asserting' || phase.value === 'done') return `✓ '${TARGET_VALUE}' matches` return '' }) -const statusOk = computed(() => ['found','asserting','done'].includes(phase.value)) +const statusOk = computed(() => ['found','asserting','done'].includes(phase.value)) +const statusErr = computed(() => phase.value === 'exhausted') const timers: ReturnType[] = [] function after(ms: number, fn: () => void) { timers.push(setTimeout(fn, ms)) } @@ -57,18 +64,28 @@ onUnmounted(() => timers.forEach(clearTimeout)) function landOnPage() { phase.value = 'checking' after(700, () => { - if (pageIdx.value === targetPage) { + if (pageIdx.value === targetPage && scenario.value === 'success') { phase.value = 'found' after(1000, () => { phase.value = 'asserting' after(1800, () => { phase.value = 'done' }) }) } else { - phase.value = 'rejected' + // Check if we've hit maxPages limit + if (pageIdx.value + 1 >= MAX_PAGES[scenario.value]) { + phase.value = 'exhausted' + } else { + phase.value = 'rejected' + } } }) } +function onStart() { + started.value = true + landOnPage() +} + function onNext() { if (phase.value !== 'rejected') return pageIdx.value++ @@ -76,30 +93,52 @@ function onNext() { after(200, () => landOnPage()) } -function onReplay() { +function reset() { timers.forEach(clearTimeout) timers.length = 0 phase.value = 'idle' pageIdx.value = 0 - after(300, () => landOnPage()) + started.value = false } -// auto-start -landOnPage() +function setScenario(s: Scenario) { + if (scenario.value === s) return + scenario.value = s + reset() +} - +
diff --git a/docs/api/table-methods.md b/docs/api/table-methods.md index 53586709..37b2949d 100644 --- a/docs/api/table-methods.md +++ b/docs/api/table-methods.md @@ -268,7 +268,7 @@ const exactRows = await table.findRows( ### See it in action -Walk through a full `findRow` flow end-to-end: table init, header mapping, multi-page scan, match highlight, and the final `getCell` + checkbox interaction — all animated step by step. +Walk through a full `findRows` flow end-to-end: table init, header mapping, multi-page scan, match highlight, and the final `getCell` + checkbox interaction — all animated step by step.