feat(site): refresh landing demos, stats, and metadata#432
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds two shared lightweight JavaScript rendering utilities ( ChangesDemo rendering, runtime, and component flow
Homepage SEO, analytics, stats, and demo progress sync
Site config, public metadata files, and docs content
Sequence Diagram(s)sequenceDiagram
participant User as User (scroll)
participant Page as index.astro (ScrollTrigger)
participant Runtime as component-demo-runtime.ts
participant Demo as touchai-components.html (iframe)
User->>Page: scroll through feature section
Page->>Runtime: dispatchMessage({type: "touchai-set-scroll-progress", progress: 0.4})
alt handlers registered
Runtime->>Demo: deliver progress message
Demo->>Demo: renderScrollProgress(0.4)
Demo->>Demo: setScrollDrivenState(true)
Demo->>Demo: keepLatestResponseVisible()
else handlers not yet registered
Runtime->>Runtime: queue message (replace by type)
end
Demo->>Runtime: notifyParent("touchai-solver-ready")
Runtime->>Runtime: flushPendingMessages(host)
Runtime->>Demo: deliver queued progress message
User->>Page: scroll past feature section
Page->>Runtime: dispatchMessage({type: "touchai-clear-scroll-driven"})
Runtime->>Demo: clear scroll-driven state
Demo->>Demo: setScrollDrivenState(false)
Demo->>Demo: aria-busy="false"
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/site/public/touchai-intro-en/touchai-components.html (1)
1651-1702:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winGuard the autoplay helper after the demo has already started.
typePromptThenSubmit()can still fire from the 900ms fallback after a user-triggered start, which clears the prompt and restarts the sequence mid-animation.Suggested fix
function showAnswer() { + window.clearTimeout(fallbackTimer); hasReceivedScrollProgress = false; setScrollDrivenState(false); clearPromptTyping(); @@ function typePromptThenSubmit() { + if ( + hasStarted || + document.body.classList.contains('is-answering') || + document.body.classList.contains('is-complete') + ) { + return; + } + + window.clearTimeout(fallbackTimer); hasReceivedScrollProgress = false; setScrollDrivenState(false); clearPromptTyping();Also applies to: 1757-1767
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro-en/touchai-components.html` around lines 1651 - 1702, typePromptThenSubmit() can run after the demo has already started and restart the sequence mid-animation; guard its work by checking the same start state used elsewhere: at the top of typePromptThenSubmit() and immediately before enqueuing/performing each timed step (inside typeNextPromptCharacter and before the submitButton.click callback) verify hasStarted is false (or that document.body does not contain 'is-answering'); if the demo has started, cancel timers (promptTypingTimer) and return early. Reference symbols: typePromptThenSubmit, typeNextPromptCharacter, promptTypingTimer, submitButton.click, hasStarted, showAnswer, submitPrompt.apps/site/src/scripts/component-demo-runtime.ts (1)
595-614:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFlush queued messages when the first
messagehandler is attached.Right now pending messages only drain at the end of
applyDocument(). If a demo registers itsmessagelistener fromDOMContentLoaded,load, or any later async path, queued progress/reset messages stay stranded forever.Suggested fix
windowHandlers.set( handler, wrappedMessageHandler as unknown as EventListenerOrEventListenerObject ); messageHandlers.add(wrappedMessageHandler); host.dataset.touchaiMessageHandlerCount = String(messageHandlers.size); + flushPendingMessages(host); return;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/scripts/component-demo-runtime.ts` around lines 595 - 614, When attaching a new 'message' handler, detect if this is the first handler (i.e., messageHandlers.size === 0 before adding) and, if so, immediately flush the queued/pending messages the same way applyDocument() does so stranded progress/reset messages are delivered; implement by calling the existing queue-drain logic (reuse the function or block used in applyDocument() that processes the pending message queue) right after registering wrappedMessageHandler and updating host.dataset.touchaiMessageHandlerCount so queued messages are not left stranded.apps/site/public/touchai-intro/touchai-components.html (1)
1722-1770:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReset
hasReceivedScrollProgresswhen switching back to manual playback.The English intro file clears this flag in both manual entry paths, but this localized version does not. After a scrub-driven run, replay/manual start stays on the “external progress received” path.
Suggested fix
function showAnswer() { + hasReceivedScrollProgress = false; setScrollDrivenState(false); clearPromptTyping(); clearPromptInput(); @@ function typePromptThenSubmit() { + hasReceivedScrollProgress = false; setScrollDrivenState(false); clearPromptTyping(); input.value = '';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro/touchai-components.html` around lines 1722 - 1770, Reset the hasReceivedScrollProgress flag when switching back to manual playback: set hasReceivedScrollProgress = false inside showAnswer() (so any manual showAnswer path clears external-scroll state) and also set hasReceivedScrollProgress = false at the start of typePromptThenSubmit() (immediately after setScrollDrivenState(false)) so the typed/manual entry path likewise clears the flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/site/public/demo-utils/touchai-lite-math.js`:
- Around line 2-6: escapeHtml currently returns raw strings when
window.TouchAILiteRenderer is unavailable, causing unescaped HTML to be injected
by renderMarkdownWithMath; replace the fallback with a proper escaping routine:
keep using renderer.escapeHtml(value) when renderer exists, otherwise implement
a local escape that converts &, <, >, ", ', and ` to their HTML entities; update
the escapeHtml function (and the identical fallback used around lines 229-231)
so renderMarkdownWithMath always receives safely escaped text.
In `@apps/site/public/feature-reminder-en/touchai-components.html`:
- Around line 1476-1482: The resetVisibleBlocks function's selector set is
missing tool card classes so .tool-call-list and .tool-call elements remain
visible after a reset; update the querySelectorAll call inside
resetVisibleBlocks to include '.tool-call-list' and '.tool-call' alongside the
existing selectors so those elements have 'is-visible' removed during resets.
In `@apps/site/public/feature-reminder/touchai-components.html`:
- Around line 1575-1595: The wheel handler forwardWheelToPage currently prevents
default and calls window.scrollBy, which only scrolls the iframe; instead
forward the computed delta (nextDeltaY) to the host so the embedding page can
handle scrolling—use window.parent.postMessage (or the existing postMessage
channel) to send a message containing { type: 'wheel-delta', deltaY: nextDeltaY
} when isScrollDriven && hasReceivedScrollProgress are true, keep the ctrl/meta
early-return logic, and remove or stop relying on window.scrollBy to avoid
trapping wheel input inside the iframe; reference forwardWheelToPage,
isScrollDriven, hasReceivedScrollProgress and the computed nextDeltaY when
implementing.
- Around line 496-500: The rule body.is-scroll-driven.is-complete .chat-panel is
overriding the mobile rule body.is-complete .chat-panel and reintroducing the
fixed 657px height on short viewports; limit this selector to desktop (e.g.,
wrap it in a desktop media query) or add a matching mobile override that
restores the mobile height behavior so short viewports don’t get the fixed
657px: update the CSS where body.is-scroll-driven.is-complete .chat-panel is
defined and either scope it with a desktop-only media query or add a
body.is-scroll-driven.is-complete .chat-panel mobile-specific rule that mirrors
the existing body.is-complete .chat-panel mobile override.
In `@apps/site/public/feature-solver-en/touchai-components.html`:
- Around line 1968-1988: The wheel handler forwardWheelToPage is trapping wheel
input because it calls event.preventDefault() and uses window.scrollBy() (which
only scrolls the iframe); instead forward the intended scroll to the host and
stop preventing the native event. Modify forwardWheelToPage to remove the
event.preventDefault() call that runs before handing the event off and replace
the iframe-only window.scrollBy(0, nextDeltaY) with a parent.postMessage({type:
'forward-wheel', deltaY: nextDeltaY}) (or, if the iframe and host are
same-origin, call parent.scrollBy(0, nextDeltaY)), keeping the existing guards
(isScrollDriven, hasReceivedScrollProgress) intact so only relevant wheel events
are forwarded.
- Line 2: The page declares lang="en" but still contains Chinese copy in
accessibility/fallback text (e.g., the strings near Line 982, Line 1023 and the
prerendered answer block starting at Line 1049), so either translate those
Chinese strings into English or revert lang to "zh" until translation is done;
specifically locate and update the Chinese text in the prerendered answer body,
any no-JS/failed-script fallback content, and ARIA/alt/label attributes (search
for the prerendered answer container and fallback block IDs/classes and the text
nodes around the noted lines) to their English equivalents so screen readers and
fallbacks get correct language context before keeping <html lang="en">.
- Around line 426-430: The selector body.is-scroll-driven.is-complete
.chat-panel is overriding the mobile-specific rule and forcing the fixed 657px
height on small screens; modify the CSS so the scroll-driven completion rule
does not apply the fixed height on narrow viewports—e.g., add a
media-query-specific override for body.is-scroll-driven.is-complete .chat-panel
(or alter that selector) to restore the mobile-safe properties (remove or unset
min-height/max-height/height or set them to auto/none) so the existing
body.is-complete .chat-panel mobile rule remains effective on small screens.
In `@apps/site/public/feature-solver/touchai-components.html`:
- Around line 1968-1988: The current forwardWheelToPage handler prevents default
and calls window.scrollBy, which only scrolls the iframe and swallows the wheel
for the parent; instead, stop preventing default and stop using window.scrollBy
inside the iframe — forward the computed delta to the host page (e.g., via
postMessage) so the parent can perform the scroll or allow the event to bubble
to the parent by removing event.preventDefault() before window.scrollBy; update
forwardWheelToPage to (1) keep the ctrl/meta early preventDefault branch, (2)
compute deltaMultiplier/nextDeltaY as now, and (3) either postMessage({type:
'wheel', deltaY: nextDeltaY}) to parent or simply remove the final
event.preventDefault() + window.scrollBy call so the host receives the wheel
event.
- Around line 426-430: The new selector body.is-scroll-driven.is-complete
.chat-panel is overriding the mobile rule body.is-complete .chat-panel and
forcing a fixed desktop height on short screens; update the CSS to preserve the
mobile override by adding a mobile-specific rule that targets the scroll-driven
completion state (e.g., inside the same small-screen media query add
body.is-scroll-driven.is-complete .chat-panel and set
min-height/max-height/height to the mobile variable or the previous values), or
increase specificity on the existing mobile selector so
body.is-scroll-driven.is-complete .chat-panel does not win.
In `@apps/site/src/content.config.ts`:
- Around line 1-3: The import block is out of order and failing
simple-import-sort; reorder the imports so external package imports are grouped
and sorted before local/alias imports—specifically ensure 'astro:content'
(defineCollection) and '`@astrojs/starlight/`...' imports (docsLoader, docsSchema)
follow the project's import-sort rules (or run the autofixer) so the imports for
defineCollection, docsLoader, and docsSchema are in the correct sorted groups
and order.
In `@apps/site/src/pages/index.astro`:
- Around line 37-52: The fetch blocks for repoApiUrl and repoOpenIssuesApiUrl
currently swallow all errors (empty catch) and ignore non-ok responses; update
the try/catch handlers around fetch(repoApiUrl, { headers }) and
fetch(repoOpenIssuesApiUrl, { headers }) to log diagnostics: on non-ok responses
log the URL and response.status/response.statusText, and in the catch blocks log
the thrown Error (including message/stack) along with which fetch (repoApiUrl or
repoOpenIssuesApiUrl) failed so build-time failures are visible (use your
existing logger or console.error).
- Around line 2685-2738: Add developer-facing privacy documentation and an
in-code comment noting legal/privacy implications when enabling analytics:
update the .env.example to document that PUBLIC_ANALYTICS_ENDPOINT enables
collection of referrer, viewport, and lang which may trigger GDPR/CCPA
disclosure/consent requirements, and add a clear comment immediately above the
sendAnalytics function (and mention analyticsEndpoint and trackPageView)
explaining what fields are collected, that tracking is opt-in via the env var,
and that deployers must ensure appropriate user notices/consent before enabling
it.
- Around line 1814-1817: The ANALYTICS_ENDPOINT environment value is embedded
directly into data-analytics-endpoint (and used by client fetches) without
validating its URL format; update the front-matter where ANALYTICS_ENDPOINT is
read to validate it (e.g., attempt new URL(ANALYTICS_ENDPOINT) or RegExp) and if
invalid set it to null/empty or a safe fallback, then only render the
data-analytics-endpoint attribute when the validated value exists; also update
the client-side code that reads dataset.analyticsEndpoint to check for a truthy,
valid URL before calling fetch to avoid silent failures.
- Around line 2907-2923: fetchRepoOverview currently adds a timestamp query via
withCacheBuster and also sets fetch option cache: 'no-store' — remove the
redundant timestamp approach: stop calling withCacheBuster(REPO_STATS_API_URL)
and withCacheBuster(REPO_OPEN_ISSUES_API_URL) and pass the plain
REPO_STATS_API_URL and REPO_OPEN_ISSUES_API_URL to fetch (leave cache:
'no-store' in the fetch options); update both fetch calls inside
fetchRepoOverview and, if withCacheBuster is unused elsewhere, remove the
withCacheBuster helper to keep the file clean.
---
Outside diff comments:
In `@apps/site/public/touchai-intro-en/touchai-components.html`:
- Around line 1651-1702: typePromptThenSubmit() can run after the demo has
already started and restart the sequence mid-animation; guard its work by
checking the same start state used elsewhere: at the top of
typePromptThenSubmit() and immediately before enqueuing/performing each timed
step (inside typeNextPromptCharacter and before the submitButton.click callback)
verify hasStarted is false (or that document.body does not contain
'is-answering'); if the demo has started, cancel timers (promptTypingTimer) and
return early. Reference symbols: typePromptThenSubmit, typeNextPromptCharacter,
promptTypingTimer, submitButton.click, hasStarted, showAnswer, submitPrompt.
In `@apps/site/public/touchai-intro/touchai-components.html`:
- Around line 1722-1770: Reset the hasReceivedScrollProgress flag when switching
back to manual playback: set hasReceivedScrollProgress = false inside
showAnswer() (so any manual showAnswer path clears external-scroll state) and
also set hasReceivedScrollProgress = false at the start of
typePromptThenSubmit() (immediately after setScrollDrivenState(false)) so the
typed/manual entry path likewise clears the flag.
In `@apps/site/src/scripts/component-demo-runtime.ts`:
- Around line 595-614: When attaching a new 'message' handler, detect if this is
the first handler (i.e., messageHandlers.size === 0 before adding) and, if so,
immediately flush the queued/pending messages the same way applyDocument() does
so stranded progress/reset messages are delivered; implement by calling the
existing queue-drain logic (reuse the function or block used in applyDocument()
that processes the pending message queue) right after registering
wrappedMessageHandler and updating host.dataset.touchaiMessageHandlerCount so
queued messages are not left stranded.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6da7003b-220a-4cf4-a68c-f1e64db562cc
⛔ Files ignored due to path filters (4)
apps/site/public/apple-touch-icon.pngis excluded by!**/*.pngapps/site/public/icon-192.pngis excluded by!**/*.pngapps/site/public/icon-512.pngis excluded by!**/*.pngapps/site/public/seo-card.pngis excluded by!**/*.png
📒 Files selected for processing (20)
apps/site/.env.exampleapps/site/astro.config.mjsapps/site/public/demo-utils/touchai-lite-math.jsapps/site/public/demo-utils/touchai-lite-renderer.jsapps/site/public/feature-reminder-en/touchai-components.htmlapps/site/public/feature-reminder/touchai-components.htmlapps/site/public/feature-solver-en/touchai-components.htmlapps/site/public/feature-solver/touchai-components.htmlapps/site/public/feature-work-organizer-en/touchai-components.htmlapps/site/public/feature-work-organizer/touchai-components.htmlapps/site/public/robots.txtapps/site/public/site.webmanifestapps/site/public/touchai-intro-en/touchai-components.htmlapps/site/public/touchai-intro/touchai-components.htmlapps/site/src/components/ComponentDemo.astroapps/site/src/content.config.tsapps/site/src/content/docs/404.mdapps/site/src/content/docs/getting-started.mdapps/site/src/pages/index.astroapps/site/src/scripts/component-demo-runtime.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (rust)
🧰 Additional context used
🪛 ESLint
apps/site/src/content.config.ts
[error] 1-3: Run autofix to sort these imports!
(simple-import-sort/imports)
apps/site/public/demo-utils/touchai-lite-renderer.js
[error] 26-29: Replace ⏎····················/\*\*([^*]+)\*\*/g,⏎····················'<strong>$1</strong>'⏎················ with /\*\*([^*]+)\*\*/g,·'<strong>$1</strong>'
(prettier/prettier)
[error] 51-53: Replace ⏎····················.map((item)·=>·
)⏎···················· with .map((item)·=>·)
(prettier/prettier)
apps/site/public/demo-utils/touchai-lite-math.js
[error] 29-29: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 29-29: Empty block statement.
(no-empty)
[error] 208-210: Replace ⏎············?·'formula-module'⏎··········· with ·?·'formula-module'
(prettier/prettier)
[error] 239-242: Replace ⏎····················new·RegExp(<p·class="paragraph-node">${token}
,·'g'),⏎····················replacement⏎················ with new·RegExp(<p·class="paragraph-node">${token},·'g'),·replacement
(prettier/prettier)
apps/site/src/scripts/component-demo-runtime.ts
[error] 527-528: Delete ⏎·······
(prettier/prettier)
🔇 Additional comments (36)
apps/site/astro.config.mjs (1)
13-13: LGTM!apps/site/src/content.config.ts (1)
5-10: LGTM!apps/site/public/robots.txt (1)
1-4: LGTM!apps/site/public/site.webmanifest (1)
1-29: LGTM!apps/site/src/content/docs/404.md (1)
1-7: LGTM!apps/site/src/content/docs/getting-started.md (1)
1-29: LGTM!apps/site/src/pages/index.astro (16)
117-226: LGTM!
291-301: LGTM!
842-965: LGTM!
1491-1548: LGTM!
1919-1929: LGTM!
2053-2076: LGTM!
2089-2097: LGTM!Also applies to: 2138-2146, 2186-2194, 2232-2240
2323-2328: LGTM!
2481-2565: LGTM!
2567-2606: LGTM!
2815-2992: LGTM!
3210-3213: LGTM!
3257-3291: LGTM!
3379-3474: LGTM!
3476-3544: LGTM!
3554-3588: LGTM!apps/site/.env.example (1)
15-17: LGTM!apps/site/public/feature-work-organizer/touchai-components.html (7)
1469-1489: Same issue as the English version: verify wheel forwarding target.This has the same
window.scrollByvswindow.parent.scrollByquestion flagged in the English variant.
1563-1567: Same indentation issue as the English version.Lines 1565-1566 are under-indented inside the if block.
86-88: LGTM!Also applies to: 155-168, 470-476, 496-515, 760-760
1116-1116: LGTM!Also applies to: 1130-1130, 1148-1148
1165-1189: LGTM!
1297-1324: LGTM!
1229-1229: LGTM!Also applies to: 1357-1357, 1368-1439, 1461-1467, 1501-1528, 1590-1650, 1661-1769
apps/site/public/feature-work-organizer-en/touchai-components.html (6)
86-88: LGTM!Also applies to: 155-168, 470-476, 496-515, 760-760
1118-1118: LGTM!Also applies to: 1132-1132, 1150-1150
1167-1191: LGTM!
1299-1326: LGTM!
1231-1231: LGTM!Also applies to: 1359-1359, 1370-1441, 1463-1469, 1503-1534, 1596-1656, 1667-1774
1471-1491: Wheel forwarding target is correct (window.scrollBy), no iframe involved.The demos are mounted into the page by
apps/site/src/scripts/component-demo-runtime.tsviadoc.body.cloneNode(true)+host.replaceChildren(...)on thetouchai-component-demoelement (not an iframe). Sowindow.scrollBy(0, nextDeltaY)scrolls the same document that GSAP/ScrollTrigger uses, makingwindow.parent.scrollByunnecessary here.> Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
apps/site/public/touchai-intro-en/touchai-components.html (2)
2-2:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winEnglish demo pages still expose Chinese document/ARIA metadata. The shared root cause is that the
*-endemos updated visible content to English but kept Chinese language and assistive labels.
apps/site/public/touchai-intro-en/touchai-components.html#L2-L2: change the document language fromzh-CNtoen.apps/site/public/touchai-intro-en/touchai-components.html#L1071-L1154: localize toolbar, prompt, copy, input, and send ARIA labels to English.apps/site/public/feature-reminder-en/touchai-components.html#L2-L2: change the document language fromzh-CNtoen.apps/site/public/feature-reminder-en/touchai-components.html#L1147-L1232: localize toolbar, prompt, copy, input, and send ARIA labels to English.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro-en/touchai-components.html` at line 2, English demo pages contain Chinese language metadata and ARIA labels that must be localized. Fix this across four locations: (1) In apps/site/public/touchai-intro-en/touchai-components.html at line 2, change the html lang attribute from "zh-CN" to "en"; (2) In the same file at lines 1071-1154, localize all ARIA labels and descriptive text for the toolbar, prompt, copy, input, and send button elements from Chinese to English; (3) In apps/site/public/feature-reminder-en/touchai-components.html at line 2, change the html lang attribute from "zh-CN" to "en"; (4) In the same feature-reminder file at lines 1147-1232, localize all ARIA labels and descriptive text for the toolbar, prompt, copy, input, and send button elements from Chinese to English.
1483-1503:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winWheel forwarding blocks browser zoom gestures across demos. Each
forwardWheelToPage()prevents default forctrlKey/metaKeywheel events before checking whether scroll-driven forwarding is active.
apps/site/public/touchai-intro-en/touchai-components.html#L1483-L1503: return withoutpreventDefault()for modifier wheel events.apps/site/public/touchai-intro/touchai-components.html#L1554-L1574: return withoutpreventDefault()for modifier wheel events.apps/site/public/feature-reminder-en/touchai-components.html#L1589-L1609: return withoutpreventDefault()for modifier wheel events.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro-en/touchai-components.html` around lines 1483 - 1503, Remove the event.preventDefault() call from the ctrlKey/metaKey modifier check in the forwardWheelToPage() function at all three affected files, allowing the browser's default zoom gesture to proceed instead of being blocked. At apps/site/public/touchai-intro-en/touchai-components.html lines 1483-1503 (anchor), change the first if block to return without preventDefault when modifier keys are detected. Apply the same change at the sibling locations in apps/site/public/touchai-intro/touchai-components.html lines 1554-1574 and apps/site/public/feature-reminder-en/touchai-components.html lines 1589-1609, as they contain identical problematic code.apps/site/public/feature-reminder/touchai-components.html (1)
1652-1699:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winClear
aria-busyafter scroll progress renders a completed answer.Each handler sets
aria-busybeforeanswerProgressis known, then the!hasStartedbranch can force it back totrue. If the first progress update lands at or past the completion threshold, the response is fully rendered but remains busy.
apps/site/public/feature-reminder/touchai-components.html#L1652-L1699: set the finalaria-busyvalue afteranswerProgressis computed, clearing it whenanswerProgress >= 1.apps/site/public/feature-solver-en/touchai-components.html#L1959-L2005: apply the same post-answerProgressbusy-state update.apps/site/public/feature-solver/touchai-components.html#L2045-L2091: apply the same post-answerProgressbusy-state update.Suggested pattern
- response.setAttribute( - 'aria-busy', - hasReceivedScrollProgress ? 'true' : 'false' - ); externalScrollProgress = scrubProgress; window.clearTimeout(typingTimer); window.clearTimeout(promptTypingTimer); @@ const answerProgress = Math.max(0, Math.min(1, (scrubProgress - 0.18) / 0.5)); const scrollProgress = Math.max(0, Math.min(1, (scrubProgress - 0.66) / 0.34)); + const responseIsBusy = hasReceivedScrollProgress && answerProgress < 1; @@ setResponseProgress(answerProgress); + response.setAttribute('aria-busy', responseIsBusy ? 'true' : 'false'); syncMathLineGeometry();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-reminder/touchai-components.html` around lines 1652 - 1699, The `aria-busy` attribute is being set in the `!hasStarted` branch before `answerProgress` is computed, which causes a fully rendered response to incorrectly remain marked as busy if the first progress update arrives at or past the completion threshold. Move the final `aria-busy` update to occur after `answerProgress` is calculated (after the line computing `const answerProgress = Math.max(0, Math.min(1, (scrubProgress - 0.18) / 0.5))`) and set it to 'false' when `answerProgress >= 1` to properly reflect the completion state. Apply this same fix at three locations: apps/site/public/feature-reminder/touchai-components.html lines 1652-1699 (anchor), apps/site/public/feature-solver-en/touchai-components.html lines 1959-2005 (sibling), and apps/site/public/feature-solver/touchai-components.html lines 2045-2091 (sibling).apps/site/src/pages/index.astro (3)
2966-2970:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRespect the GitHub stats cache before refetching.
After loading stored stats, Line 2970 always calls
refreshRepoStats({ force: true }), bypassing the request gap and making fresh-cache page loads hit GitHub twice anyway. Gate the initial refresh on the storedupdatedAt.Suggested fix
if (storedRepoStats) Object.assign(repoStats, storedRepoStats); renderRepoStats(repoStats); - refreshRepoStats({ force: true }); + if (shouldRefreshRepoStats(REPO_STATS_REFRESH_INTERVAL)) { + refreshRepoStats({ force: true }); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 2966 - 2970, The call to refreshRepoStats with force: true on line 2970 always bypasses the GitHub stats cache and forces a fresh fetch from GitHub, even when recently cached data is available. Instead of unconditionally calling refreshRepoStats({ force: true }), check the updatedAt timestamp from the storedRepoStats and only trigger a refresh if the cache is stale based on an appropriate time threshold. This way, fresh-cache page loads will respect the existing cache gap and avoid making redundant GitHub API requests.
1951-1951:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign the initial intro demo URL with the default language URL.
Line 1951 loads
?v=7, butsetLanguage('zh')immediately changes the same demo to?v=8on boot. That double-loads the hero demo for default-language visitors.Suggested fix
- src="/touchai-intro/touchai-components.html?v=7" + src="/touchai-intro/touchai-components.html?v=8"Also applies to: 2602-2606
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` at line 1951, The touchai-components.html demo is initially loaded with version 7 but immediately updated to version 8 when setLanguage is called on boot, causing an unnecessary double-load for default-language visitors. Update the initial src attribute for the touchai-components.html iframe to use version 8 instead of version 7, and ensure any other similar demo component URLs (including those around lines 2602-2606) are also updated to use the same consistent version parameter to prevent duplicate loads.
2507-2508:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForce progress sync after embedded demo reloads.
lastDispatchedDemoProgressis keyed by the host frame, so it survivesframe.reload(). The load/ready/replay paths resync withoutforce; when the progress value is unchanged, Line 2508 drops the message and the newly loaded iframe stays at its default state.Suggested fix
- solverFrame.addEventListener('load', () => { + solverFrame.addEventListener('load', () => { syncFeatureDemoProgress( solverFrame, - featureProgressByFrame.get(solverFrame) ?? 0 + featureProgressByFrame.get(solverFrame) ?? 0, + true ); });- workOrganizerFrame.addEventListener('load', () => { + workOrganizerFrame.addEventListener('load', () => { syncFeatureDemoProgress( workOrganizerFrame, - featureProgressByFrame.get(workOrganizerFrame) ?? 0 + featureProgressByFrame.get(workOrganizerFrame) ?? 0, + true ); });- reminderFrame.addEventListener('load', () => { + reminderFrame.addEventListener('load', () => { syncFeatureDemoProgress( reminderFrame, - featureProgressByFrame.get(reminderFrame) ?? 0 + featureProgressByFrame.get(reminderFrame) ?? 0, + true ); });const replayEmbeddedComponent = async (frame) => { const progress = featureProgressByFrame.get(frame) ?? 0; await Promise.resolve(frame.reload?.()); - syncFeatureDemoProgress(frame, progress); - window.setTimeout(() => syncFeatureDemoProgress(frame, progress), 120); - window.setTimeout(() => syncFeatureDemoProgress(frame, progress), 360); + syncFeatureDemoProgress(frame, progress, true); + window.setTimeout(() => syncFeatureDemoProgress(frame, progress, true), 120); + window.setTimeout(() => syncFeatureDemoProgress(frame, progress, true), 360); };For the intro demo, pass a force flag through the ready/load refresh path:
- const syncComponent = (progress) => { - queueDemoProgress(introDemo, 'touchai-set-progress', progress); + const syncComponent = (progress, force = false) => { + queueDemoProgress(introDemo, 'touchai-set-progress', progress, force); }; - const refreshPinnedIntro = () => { + const refreshPinnedIntro = (force = false) => { ScrollTrigger.refresh(); - syncComponent(componentTrigger?.progress ?? 0); + syncComponent(componentTrigger?.progress ?? 0, force); };- if (isActive) refreshPinnedIntro(); + if (isActive) refreshPinnedIntro(true);Also applies to: 3121-3125, 3141-3145, 3161-3165, 3177-3182, 3381-3392
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 2507 - 2508, The issue is that lastDispatchedDemoProgress survives frame reloads due to being keyed by the host frame, so when load/ready/replay paths resync without a force flag, the condition on line 2508 skips dispatching the progress message if the value is unchanged, leaving newly loaded iframes at their default state. To fix this, pass a force flag as true through the ready/load/replay paths for the intro demo to ensure the progress message is always dispatched after a frame reload, even when the progress value hasn't changed. Identify all calls that trigger these resync paths and modify them to include force set to true so the condition !force && lastProgress === snappedProgress evaluates correctly and allows the message through.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/site/src/pages/index.astro`:
- Line 2295: The footer docs link element with href={docsUrl} and
data-i18n="footer.docs" is missing the data-analytics-event attribute that is
present on neighboring footer links, causing analytics tracking to skip this
navigation. Add the data-analytics-event attribute to the docs footer link
anchor tag to ensure clicks on this link are tracked consistently with other
footer navigation elements.
- Around line 1915-1917: The span element with data-i18n="hero.heading"
references a translation key that does not exist in the translation maps for any
locale. This causes the screen-reader text to remain in Chinese even when
switching to English. Add the hero.heading key to both locale translation maps
(the English and Chinese translation files) with appropriate values so that the
screen-reader content respects the current language setting.
---
Outside diff comments:
In `@apps/site/public/feature-reminder/touchai-components.html`:
- Around line 1652-1699: The `aria-busy` attribute is being set in the
`!hasStarted` branch before `answerProgress` is computed, which causes a fully
rendered response to incorrectly remain marked as busy if the first progress
update arrives at or past the completion threshold. Move the final `aria-busy`
update to occur after `answerProgress` is calculated (after the line computing
`const answerProgress = Math.max(0, Math.min(1, (scrubProgress - 0.18) / 0.5))`)
and set it to 'false' when `answerProgress >= 1` to properly reflect the
completion state. Apply this same fix at three locations:
apps/site/public/feature-reminder/touchai-components.html lines 1652-1699
(anchor), apps/site/public/feature-solver-en/touchai-components.html lines
1959-2005 (sibling), and apps/site/public/feature-solver/touchai-components.html
lines 2045-2091 (sibling).
In `@apps/site/public/touchai-intro-en/touchai-components.html`:
- Line 2: English demo pages contain Chinese language metadata and ARIA labels
that must be localized. Fix this across four locations: (1) In
apps/site/public/touchai-intro-en/touchai-components.html at line 2, change the
html lang attribute from "zh-CN" to "en"; (2) In the same file at lines
1071-1154, localize all ARIA labels and descriptive text for the toolbar,
prompt, copy, input, and send button elements from Chinese to English; (3) In
apps/site/public/feature-reminder-en/touchai-components.html at line 2, change
the html lang attribute from "zh-CN" to "en"; (4) In the same feature-reminder
file at lines 1147-1232, localize all ARIA labels and descriptive text for the
toolbar, prompt, copy, input, and send button elements from Chinese to English.
- Around line 1483-1503: Remove the event.preventDefault() call from the
ctrlKey/metaKey modifier check in the forwardWheelToPage() function at all three
affected files, allowing the browser's default zoom gesture to proceed instead
of being blocked. At apps/site/public/touchai-intro-en/touchai-components.html
lines 1483-1503 (anchor), change the first if block to return without
preventDefault when modifier keys are detected. Apply the same change at the
sibling locations in apps/site/public/touchai-intro/touchai-components.html
lines 1554-1574 and apps/site/public/feature-reminder-en/touchai-components.html
lines 1589-1609, as they contain identical problematic code.
In `@apps/site/src/pages/index.astro`:
- Around line 2966-2970: The call to refreshRepoStats with force: true on line
2970 always bypasses the GitHub stats cache and forces a fresh fetch from
GitHub, even when recently cached data is available. Instead of unconditionally
calling refreshRepoStats({ force: true }), check the updatedAt timestamp from
the storedRepoStats and only trigger a refresh if the cache is stale based on an
appropriate time threshold. This way, fresh-cache page loads will respect the
existing cache gap and avoid making redundant GitHub API requests.
- Line 1951: The touchai-components.html demo is initially loaded with version 7
but immediately updated to version 8 when setLanguage is called on boot, causing
an unnecessary double-load for default-language visitors. Update the initial src
attribute for the touchai-components.html iframe to use version 8 instead of
version 7, and ensure any other similar demo component URLs (including those
around lines 2602-2606) are also updated to use the same consistent version
parameter to prevent duplicate loads.
- Around line 2507-2508: The issue is that lastDispatchedDemoProgress survives
frame reloads due to being keyed by the host frame, so when load/ready/replay
paths resync without a force flag, the condition on line 2508 skips dispatching
the progress message if the value is unchanged, leaving newly loaded iframes at
their default state. To fix this, pass a force flag as true through the
ready/load/replay paths for the intro demo to ensure the progress message is
always dispatched after a frame reload, even when the progress value hasn't
changed. Identify all calls that trigger these resync paths and modify them to
include force set to true so the condition !force && lastProgress ===
snappedProgress evaluates correctly and allows the message through.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: efc4e3bc-1745-43dc-8e3a-ea773d8e2e42
📒 Files selected for processing (14)
apps/site/public/demo-utils/touchai-lite-math.jsapps/site/public/demo-utils/touchai-lite-renderer.jsapps/site/public/feature-reminder-en/touchai-components.htmlapps/site/public/feature-reminder/touchai-components.htmlapps/site/public/feature-solver-en/touchai-components.htmlapps/site/public/feature-solver/touchai-components.htmlapps/site/public/feature-work-organizer-en/touchai-components.htmlapps/site/public/feature-work-organizer/touchai-components.htmlapps/site/public/site.webmanifestapps/site/public/touchai-intro-en/touchai-components.htmlapps/site/public/touchai-intro/touchai-components.htmlapps/site/src/content.config.tsapps/site/src/pages/index.astroapps/site/src/scripts/component-demo-runtime.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (rust)
🧰 Additional context used
🪛 ast-grep (0.43.0)
apps/site/public/demo-utils/touchai-lite-math.js
[warning] 239-239: Detects non-literal values in regular expressions
Context: new RegExp(token, 'g')
Note: Security best practice.
(detect-non-literal-regexp)
🪛 HTMLHint (1.9.2)
apps/site/public/feature-solver-en/touchai-components.html
[warning] 1515-1515: No matching [ label ] tag found.
(input-requires-label)
🔇 Additional comments (21)
apps/site/src/content.config.ts (2)
1-3: Import sort order is compliant withsimple-import-sortrules.Verification confirms that the import order on lines 1–3 passes the
simple-import-sort/importslinting rule without errors.
3-3: The import pathimport { defineCollection } from 'astro:content'is correct for Astro 6.3.1 and aligns with the official Astro Content Layer API documentation. No action needed.apps/site/public/site.webmanifest (1)
12-27: Icon files are properly committed and accessible.The manifest references three icon entries (
/icon-192.pngand/icon-512.png, plus a maskable variant), and both files exist inapps/site/public/with appropriate sizes (18K and 75K respectively).apps/site/public/demo-utils/touchai-lite-math.js (1)
2-6: Existing fallback escaping issue still applies.This code still captures
TouchAILiteRendereronce and falls back to rawString(value)when it is unavailable, matching the previous review finding.Also applies to: 229-231
apps/site/public/feature-reminder-en/touchai-components.html (1)
1488-1490: Existing tool-card reset issue still applies.
resetVisibleBlocks()still omits.tool-call-listand.tool-call, matching the previous review finding.apps/site/public/demo-utils/touchai-lite-renderer.js (1)
16-28: LGTM!Also applies to: 45-49
apps/site/src/scripts/component-demo-runtime.ts (1)
499-529: LGTM!apps/site/public/feature-reminder/touchai-components.html (2)
496-500: Duplicate: mobile completion still overrides the small-screen height.This is the same unresolved selector-specificity issue from the previous review.
1587-1607: Duplicate: wheel input is still swallowed inside the iframe.The handler still calls
preventDefault()andwindow.scrollBy()in the iframe instead of reaching the host page.apps/site/public/feature-solver-en/touchai-components.html (2)
426-430: Duplicate: mobile completion still overrides the small-screen height.This is the same unresolved selector-specificity issue from the previous review.
1890-1910: Duplicate: wheel input is still swallowed inside the iframe.The handler still calls
preventDefault()andwindow.scrollBy()in the iframe instead of reaching the host page.apps/site/public/feature-solver/touchai-components.html (2)
426-430: Duplicate: mobile completion still overrides the small-screen height.This is the same unresolved selector-specificity issue from the previous review.
1980-2000: Duplicate: wheel input is still swallowed inside the iframe.The handler still calls
preventDefault()andwindow.scrollBy()in the iframe instead of reaching the host page.apps/site/public/feature-work-organizer-en/touchai-components.html (4)
1118-1123: LGTM!Also applies to: 1137-1144
1552-1555: LGTM!Also applies to: 1586-1587
1739-1741: LGTM!
1790-1792: LGTM!apps/site/public/feature-work-organizer/touchai-components.html (4)
1116-1121: LGTM!Also applies to: 1135-1142
1546-1549: LGTM!Also applies to: 1580-1581
1734-1736: LGTM!
1785-1787: LGTM!
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/site/src/components/ComponentDemo.astro (1)
193-418: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider extracting shared CSS to reduce duplication.
The
hostCssblock here (~220 lines) closely mirrorshostCssForincomponent-demo-runtime.ts. Both must stay synchronized for SSR and client-mount behavior to match. Future CSS changes risk drift if applied to only one file.A shared CSS template (imported by both files) or a single source of truth would reduce this maintenance burden.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/components/ComponentDemo.astro` around lines 193 - 418, The hostCss variable in ComponentDemo.astro is duplicated with similar CSS code named hostCssFor in component-demo-runtime.ts, creating a maintenance risk where changes to one file may not be synchronized with the other. Extract the shared CSS template into a single source file (such as a shared utility module), and update both ComponentDemo.astro and component-demo-runtime.ts to import and use this common CSS template instead of maintaining separate copies. This ensures that SSR and client-mount behavior remain synchronized and reduces the burden of keeping the CSS logic in sync across multiple files.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/site/scripts/check-homepage-regressions.mjs`:
- Around line 59-68: The validation logic in the while loop uses an arbitrary
and fragile 1200-character window to search for CSS rules. Replace the current
approach that slices a fixed 1200-character fragment and checks if all selectors
and properties appear within it. Instead, check each selector individually by
searching the full source for patterns that verify each selector contains both
the min-height and height properties with the required !important flags. This
makes the validation robust to CSS formatting variations, comments, or
additional whitespace that might exceed the current window size.
- Around line 41-45: The regex pattern in the matchAll call for `.github-stats`
has the same limitation as the feature card checks: the pattern
`/\.github-stats\s*\{([^{}]*)\}/g` uses `[^{}]*` which stops at the first
closing brace and won't correctly handle nested CSS rules. Fix the regex pattern
to properly handle nested braces, similar to the approach used for the feature
card checks mentioned in lines 32-39, so that the check for `repeat(3` inside
the github-stats rule is robust and works correctly even with nested rule
structures.
- Around line 8-12: The readSiteFile function calls that read the homepage,
ComponentDemo, and runtime files lack error handling, causing the script to
crash with generic Node.js errors if any file is missing or unreadable. Wrap
each readSiteFile invocation in a try-catch block to catch potential errors, and
provide clear diagnostic messages indicating which specific file failed to read
and the reason for the failure, making it easier to debug issues with missing or
moved source files.
- Around line 32-39: The regex pattern in the loop that processes homepage CSS
rules does not properly handle CSS declarations nested inside media query blocks
because the pattern `[^{}]*` stops at the first closing brace, causing media
query overrides to be missed by the regression check. Replace the current
regex-based approach with a CSS parser that can traverse nested structures
properly, or modify the matching logic to separately search for the problematic
property patterns (height: auto and aspect-ratio: 760 / 657) across the entire
stylesheet content rather than relying on bracket-matched blocks. This will
ensure the regression detection at the fail() call captures violations
regardless of whether they appear in top-level rules or media query overrides.
---
Outside diff comments:
In `@apps/site/src/components/ComponentDemo.astro`:
- Around line 193-418: The hostCss variable in ComponentDemo.astro is duplicated
with similar CSS code named hostCssFor in component-demo-runtime.ts, creating a
maintenance risk where changes to one file may not be synchronized with the
other. Extract the shared CSS template into a single source file (such as a
shared utility module), and update both ComponentDemo.astro and
component-demo-runtime.ts to import and use this common CSS template instead of
maintaining separate copies. This ensures that SSR and client-mount behavior
remain synchronized and reduces the burden of keeping the CSS logic in sync
across multiple files.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 87dbf48e-32f3-4d5e-83ca-013f738de138
📒 Files selected for processing (5)
apps/site/package.jsonapps/site/scripts/check-homepage-regressions.mjsapps/site/src/components/ComponentDemo.astroapps/site/src/pages/index.astroapps/site/src/scripts/component-demo-runtime.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (rust)
🔇 Additional comments (22)
apps/site/src/scripts/component-demo-runtime.ts (2)
152-159: LGTM!
161-169: LGTM!apps/site/src/components/ComponentDemo.astro (3)
309-316: LGTM!
318-326: LGTM!
433-434: LGTM!apps/site/package.json (1)
10-10: LGTM!apps/site/scripts/check-homepage-regressions.mjs (3)
13-21: LGTM!
23-30: LGTM!
78-83: LGTM!apps/site/src/pages/index.astro (13)
23-43: LGTM!The build-time stats fetching logic correctly targets only stars and forks from the GitHub API. The headers and response handling are appropriate.
Note: The empty catch block diagnostic logging was flagged in a prior review.
2279-2279: Adddata-analytics-eventto footer docs link.This was flagged in a prior review: the footer docs link is missing the analytics tracking attribute that neighboring links have (
open_official_site,open_repository).
1905-1907: Missinghero.headingtranslation key.This was flagged in a prior review: the
data-i18n="hero.heading"attribute references a key that doesn't exist in either thezhorentranslation maps. The screen-reader H1 will retain its Chinese content when switching to English.
2884-2900: LGTM!The simplified single-fetch approach for repository stats is cleaner. The validation at line 2917 correctly checks only the stats being fetched (
stars,forks).Note: The redundant cache busting (
withCacheBuster+cache: 'no-store') was flagged in a prior review.
2641-2695: LGTM!The analytics implementation is well-structured:
sendBeaconwithfetchfallback, pageview deduplication viahasTrackedPageView, and click tracking delegation. Error handling with empty catch for fire-and-forget is appropriate here.Note: Privacy documentation and endpoint validation were flagged in prior reviews.
835-843: LGTM!The CSS changes introduce a consistent pattern across all feature cards: dynamic height via
--feature-demo-heightwith a minimal 35px fallback, andoverflow: visibleto allow the scaled iframe to extend beyond container bounds. This works correctly with the absolute-positioned, scaled frames usingtransform-origin: top left.Also applies to: 877-885, 919-920, 927-927
1458-1461: LGTM!The responsive breakpoints correctly mirror the desktop pattern for dynamic heights, and the 2-column grid layout for GitHub stats at narrow viewports is appropriate given there are now only 2 stats displayed.
Also applies to: 1677-1679, 1699-1699
2043-2060: ⚡ Quick winPR description states "Open issues" display is corrected, but implementation removes it entirely.
The PR objectives mention: "Correct the 'Open issues' display to count only open issues, excluding pull requests (verified locally as: 42 Stars / 24 Forks / 72 Open issues)." However, the implementation removes the issues stat completely—only Stars and Forks are displayed.
Please confirm whether this is intentional (and update the PR description accordingly) or if the issues stat should be restored with the corrected count.
3340-3436: LGTM!The scroll trigger setup demonstrates proper resource management:
- Each setup function returns a cleanup callback
gsap.matchMediacorrectly orchestrates viewport-specific triggers with cleanup on breakpoint change- Cleanup cancels queued progress and sends
touchai-clear-scroll-drivento iframesAlso applies to: 3438-3508, 3518-3552
2442-2521: LGTM!The queued progress system is well-designed:
WeakMapfor frame-keyed state prevents memory leakssnapDemoProgressprovides sensible quantization (1/240 increments)- RAF-based batching with deduplication avoids redundant postMessage calls
- Proper cleanup via
cancelQueuedDemoProgress
2523-2635: LGTM!The language switching implementation correctly updates localized head nodes, reloads demo iframes with language-specific URLs, and restores scroll progress. The
setTimeoutcascade inrestoreFeatureDemoProgressis a pragmatic workaround for iframe load timing uncertainty.
2966-3050: LGTM!The remaining client-side code demonstrates solid practices:
- Glimm shader initialization with proper WebGL fallback and error boundaries
- Interactive click handlers with comprehensive pointer event cleanup
- Replay card binding that prevents duplicate replays and correctly filters nested interactive elements
- Passive scroll listeners and debounced resize handlers
Also applies to: 3052-3087, 3149-3189, 3555-3570
2707-2728: The.querySelector('.chat-panel')assumption is based on an incorrect iframe model.The original review comment assumes
.chat-panelis inside an iframe and cannot be queried by the parent. However, the codebase shows thattouchai-component-demois a regular custom HTML element with inline content—not an iframe wrapper. Content is loaded asynchronously viaapplyDocument()(which callshost.replaceChildren(...)) and injected directly into the host element. The.chat-panelelement exists as a direct descendant once loaded.The real issue is timing:
syncFeatureFrameSizing()is called synchronously at page init (line 2964) before the feature frames' content has loaded, soframe.querySelector('.chat-panel')returns null on that initial call. However, this is mitigated by:
- The null-check fallback:
panel?.offsetHeight || 56(line 2710)- The load event listeners registered at line 2960-2961, which trigger
syncComponentBackground()→syncFeatureFrameSizing()after content actually loads- The guard at line 2720:
if (!panel) returnprevents setting up an incomplete observerThe current code handles the async loading correctly—the initial null is benign, and the observer is properly set up when content becomes available. No code changes appear necessary.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/site/public/feature-reminder/touchai-components.html (1)
1486-1492:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winClear tool-card visibility during resets.
The
resetVisibleBlocksselector omits.tool-call-listand.tool-call. After the first reveal, scrubbing back or replaying leaves those cards visible from the start of the next run, since the CSS at lines 763-764 hides them only when they lack.is-visible.Suggested fix
function resetVisibleBlocks() { response - .querySelectorAll('p, h2, ul, li, .math-block, .response-divider') + .querySelectorAll( + 'p, h2, ul, li, .tool-call-list, .tool-call, .math-block, .response-divider' + ) .forEach((block) => { block.classList.remove('is-visible'); }); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-reminder/touchai-components.html` around lines 1486 - 1492, The resetVisibleBlocks function is missing `.tool-call-list` and `.tool-call` from its querySelectorAll selector, so these elements retain visibility from previous runs. Add `.tool-call-list` and `.tool-call` to the selector string in the resetVisibleBlocks function's querySelectorAll call so that the `.is-visible` class is removed from these elements during reset, allowing the CSS rules to properly hide them.apps/site/public/feature-work-organizer-en/touchai-components.html (3)
496-500:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep the fixed complete height desktop-only.
This selector is more specific than the mobile
body.is-complete .chat-panelrule, so small screens can keepheight: 657pxduring scroll-driven completion and overflow the embedded card.📱 Proposed CSS fix
- body.is-scroll-driven.is-complete .chat-panel { - min-height: var(--window-min-height); - max-height: var(--window-min-height); - height: var(--window-min-height); - } + `@media` (min-width: 841px) { + body.is-scroll-driven.is-complete .chat-panel { + min-height: var(--window-min-height); + max-height: var(--window-min-height); + height: var(--window-min-height); + } + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer-en/touchai-components.html` around lines 496 - 500, The selector body.is-scroll-driven.is-complete .chat-panel is more specific than the mobile body.is-complete .chat-panel rule, causing the fixed height to apply incorrectly to small screens. Restrict this rule to desktop screens only by wrapping it in a media query (such as min-width based breakpoint) so that mobile devices continue to use the original height: 657px behavior during scroll-driven completion, preventing overflow of the embedded card.
2-2:⚠️ Potential issue | 🟠 Major | ⚡ Quick winLocalize the English demo’s document language and ARIA labels.
This English demo still declares
lang="zh-CN"and exposes Chinese control labels such as the toolbar, composer, scroll button, and answer actions. Screen readers will use the wrong language context and announce mixed-language controls.🌐 Proposed localization fix
-<html lang="zh-CN"> +<html lang="en"> ... - <section class="chat-panel is-unified" aria-label="TouchAI 对话组件"> - <header class="panel-top toolbar-fade-overlay" aria-label="窗口工具栏"> - <button class="toolbar-button" type="button" aria-label="新建会话"> + <section class="chat-panel is-unified" aria-label="TouchAI conversation demo"> + <header class="panel-top toolbar-fade-overlay" aria-label="Window toolbar"> + <button class="toolbar-button" type="button" aria-label="New conversation"> ... - <button class="scroll-bottom-button" type="button" aria-label="回到底部"> + <button class="scroll-bottom-button" type="button" aria-label="Scroll to bottom"> ... - <footer class="composer" aria-label="输入框"> - <form class="composer-form prompt-form" aria-label="输入框"> + <footer class="composer" aria-label="Message composer"> + <form class="composer-form prompt-form" aria-label="Message composer"> ... - aria-label="输入问题" + aria-label="Problem input" ... - <button class="submit-btn" type="submit" aria-label="发送"> + <button class="submit-btn" type="submit" aria-label="Send"> ... - <div class="response-actions" aria-label="回答操作"> - <span class="thinking-dots" aria-label="正在思考"> + <div class="response-actions" aria-label="Answer actions"> + <span class="thinking-dots" aria-label="Thinking"> ... - <button class="action-button copy-answer" type="button" aria-label="复制回答"> + <button class="action-button copy-answer" type="button" aria-label="Copy answer"> ... - <button class="action-button replay-answer" type="button" aria-label="重新生成"> + <button class="action-button replay-answer" type="button" aria-label="Regenerate answer">Also applies to: 1068-1153, 1228-1239
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer-en/touchai-components.html` at line 2, The HTML file's language declaration is set to Chinese (zh-CN) in the html element lang attribute at the root level, but this is an English demo. Change the lang attribute from "zh-CN" to "en" or "en-US" to properly declare the document language as English. Additionally, at lines 1068-1153 and 1228-1239, locate all ARIA labels, control labels, and text content for the toolbar, composer, scroll button, and answer actions that are currently in Chinese and translate them to English equivalents so that screen readers announce controls in the correct language and users see English text throughout the interface.
1489-1509:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel deltas to the host instead of scrolling the iframe.
In scroll-driven mode this handler calls
preventDefault()and thenwindow.scrollBy(), which only scrolls the iframe document. The wheel input is swallowed instead of advancing the parent page.🖱️ Proposed forwarding fix
- event.preventDefault(); - window.scrollBy(0, nextDeltaY); + event.preventDefault(); + try { + if (window.parent && window.parent !== window) { + window.parent.scrollBy(0, nextDeltaY); + } else { + window.scrollBy(0, nextDeltaY); + } + } catch (error) { + window.parent?.postMessage( + { type: 'touchai-forward-wheel', deltaY: nextDeltaY }, + window.location.origin + ); + }If you use the
postMessagefallback, add the matching host-page handler fortouchai-forward-wheel.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer-en/touchai-components.html` around lines 1489 - 1509, The forwardWheelToPage function currently calls window.scrollBy which only scrolls the iframe document instead of forwarding wheel input to the parent page. Replace the window.scrollBy(0, nextDeltaY) call with a postMessage call that sends the wheel delta to the parent window using window.parent.postMessage with a message type of touchai-forward-wheel and the nextDeltaY value included in the message payload. Additionally, add a corresponding message handler on the host page that listens for the touchai-forward-wheel message type and applies the forwarded wheel delta to scroll the parent page.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/site/scripts/check-homepage-regressions.mjs`:
- Around line 150-152: The check in the conditional statement uses overly broad
substring matching with html.includes('scrollProgress') which can produce false
positives when scrollProgress appears in variable names, function names,
comments, or strings unrelated to the problematic pattern. Replace the broad
substring checks with more specific pattern matching that anchors to the exact
problematic code patterns you want to reject, such as using a regular expression
that matches scrollProgress only when used as a variable reference in the
specific context that causes the regression (e.g., when used in an assignment or
expression in the problematic way), rather than matching any occurrence of the
substring anywhere in the HTML content.
---
Outside diff comments:
In `@apps/site/public/feature-reminder/touchai-components.html`:
- Around line 1486-1492: The resetVisibleBlocks function is missing
`.tool-call-list` and `.tool-call` from its querySelectorAll selector, so these
elements retain visibility from previous runs. Add `.tool-call-list` and
`.tool-call` to the selector string in the resetVisibleBlocks function's
querySelectorAll call so that the `.is-visible` class is removed from these
elements during reset, allowing the CSS rules to properly hide them.
In `@apps/site/public/feature-work-organizer-en/touchai-components.html`:
- Around line 496-500: The selector body.is-scroll-driven.is-complete
.chat-panel is more specific than the mobile body.is-complete .chat-panel rule,
causing the fixed height to apply incorrectly to small screens. Restrict this
rule to desktop screens only by wrapping it in a media query (such as min-width
based breakpoint) so that mobile devices continue to use the original height:
657px behavior during scroll-driven completion, preventing overflow of the
embedded card.
- Line 2: The HTML file's language declaration is set to Chinese (zh-CN) in the
html element lang attribute at the root level, but this is an English demo.
Change the lang attribute from "zh-CN" to "en" or "en-US" to properly declare
the document language as English. Additionally, at lines 1068-1153 and
1228-1239, locate all ARIA labels, control labels, and text content for the
toolbar, composer, scroll button, and answer actions that are currently in
Chinese and translate them to English equivalents so that screen readers
announce controls in the correct language and users see English text throughout
the interface.
- Around line 1489-1509: The forwardWheelToPage function currently calls
window.scrollBy which only scrolls the iframe document instead of forwarding
wheel input to the parent page. Replace the window.scrollBy(0, nextDeltaY) call
with a postMessage call that sends the wheel delta to the parent window using
window.parent.postMessage with a message type of touchai-forward-wheel and the
nextDeltaY value included in the message payload. Additionally, add a
corresponding message handler on the host page that listens for the
touchai-forward-wheel message type and applies the forwarded wheel delta to
scroll the parent page.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 67bcee92-177f-4ae5-a6c6-77cf395e1ee7
📒 Files selected for processing (10)
apps/site/public/feature-reminder-en/touchai-components.htmlapps/site/public/feature-reminder/touchai-components.htmlapps/site/public/feature-solver-en/touchai-components.htmlapps/site/public/feature-solver/touchai-components.htmlapps/site/public/feature-work-organizer-en/touchai-components.htmlapps/site/public/feature-work-organizer/touchai-components.htmlapps/site/scripts/check-homepage-regressions.mjsapps/site/src/components/ComponentDemo.astroapps/site/src/pages/index.astroapps/site/src/scripts/component-demo-runtime.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (rust)
🔇 Additional comments (52)
apps/site/src/pages/index.astro (4)
3092-3108: LGTM!
3114-3130: LGTM!
3136-3152: LGTM!
3460-3462: LGTM!apps/site/scripts/check-homepage-regressions.mjs (4)
13-20: LGTM!
55-69: LGTM!
71-77: LGTM!
110-135: LGTM!apps/site/public/feature-reminder-en/touchai-components.html (6)
496-500: Theis-scroll-driven.is-completerule may override mobile height constraints.This selector has higher specificity than the mobile
body.is-complete .chat-panelrule at lines 1133-1136. On short viewports, this reintroduces the fixed657pxheight during scroll-driven completion.
1486-1494: Clear tool-card visibility during resets.The
resetVisibleBlocksfunction's selector is missing.tool-call-listand.tool-call. After the first reveal, scrubbing back or replaying leaves those cards visible from the start of the next run, since the CSS at lines 763-764 hides them only when they lack.is-visible.
1593-1615: Wheel forwarding scrolls the iframe, not the parent page.After
preventDefault(),window.scrollBy(0, nextDeltaY)at line 1614 scrolls the iframe document rather than forwarding the delta to the embedding page. In scroll-driven mode, this traps wheel input inside the demo instead of allowing the parent to handle page scrolling.Consider forwarding the delta via
postMessageto let the parent handle scrolling:window.parent.postMessage({ type: 'touchai-wheel-delta', deltaY: nextDeltaY }, '*');
1-50: LGTM!
1195-1282: LGTM!
1617-1905: LGTM!apps/site/public/feature-reminder/touchai-components.html (5)
496-500: Theis-scroll-driven.is-completerule may override mobile height constraints.This issue was flagged in a previous review. The selector's specificity overrides the mobile
body.is-complete .chat-panelrule, reintroducing the fixed657pxheight on short viewports during scroll-driven completion.
1593-1613: Wheel forwarding scrolls the iframe, not the parent page.This issue was flagged in a previous review. After
preventDefault(),window.scrollBy()scrolls the iframe document rather than forwarding the delta to the embedding page, trapping wheel input inside the demo during scroll-driven mode.
1-50: LGTM!
1145-1282: LGTM!
1615-1904: LGTM!apps/site/src/scripts/component-demo-runtime.ts (4)
36-261: LGTM!
463-549: LGTM!
686-800: LGTM!
802-882: LGTM!apps/site/src/components/ComponentDemo.astro (2)
193-418: LGTM!
423-436: LGTM!apps/site/public/feature-solver-en/touchai-components.html (3)
426-430: Duplicate: preserve the mobile height override in scroll-driven completion.This still matches the previously flagged selector-specificity issue:
body.is-scroll-driven.is-complete .chat-panelcan override the mobile completion rule and restore the fixed desktop height on narrow viewports.
1896-1916: Duplicate: this wheel handler still scrolls only the iframe.This still matches the previously flagged wheel-trapping issue: after
preventDefault(),window.scrollBy()affects the iframe document, not the host page that owns the scroll-driven section.
668-668: LGTM!Also applies to: 1875-1879, 2017-2017
apps/site/public/feature-solver/touchai-components.html (3)
426-430: Duplicate: preserve the mobile height override in scroll-driven completion.This still matches the previously flagged selector-specificity issue: the scroll-driven completion selector can win over the mobile
body.is-complete .chat-panelrule and force the desktop657pxpanel height.
1986-2006: Duplicate: this wheel handler still scrolls only the iframe.This still matches the previously flagged wheel-trapping issue:
preventDefault()swallows the wheel event, thenwindow.scrollBy()runs inside the iframe instead of advancing the parent page.
668-668: LGTM!Also applies to: 1607-1607, 1965-1969, 2103-2103
apps/site/public/feature-work-organizer/touchai-components.html (21)
1-6: LGTM!
7-88: LGTM!
89-171: LGTM!
172-260: LGTM!
261-376: LGTM!
377-468: LGTM!
469-516: LGTM!
517-600: LGTM!
601-700: LGTM!
701-802: LGTM!
803-952: LGTM!
953-1064: LGTM!
1065-1159: LGTM!
1160-1241: LGTM!
1242-1336: LGTM!
1337-1420: LGTM!
1421-1470: LGTM!
1521-1606: LGTM!
1607-1726: LGTM!
1727-1795: LGTM!
1471-1520: No action needed - demos are inlined, not embedded in iframes.The review comment assumes the demos run in iframe contexts, but the ComponentDemo.astro component inlines the demo HTML directly into the page using
set:html. This means the demo JavaScript runs in the parent page's window context, makingwindow.scrollBy()the correct approach to scroll the parent page. Usingwindow.parent.scrollBy()would not work in this architecture and is unnecessary.> Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (16)
apps/site/public/touchai-intro/touchai-components.html (2)
501-505:⚠️ Potential issue | 🟠 Major | ⚡ Quick winScope the fixed scroll-driven complete height to desktop.
Line 501 is more specific than the mobile complete rule, so short/mobile viewports can get forced back to
657pxwhen scrub progress reaches the complete state. Wrap this rule in the same desktop media query used by the reminder demo.Suggested CSS fix
- body.is-scroll-driven.is-complete .chat-panel { - min-height: var(--window-min-height); - max-height: var(--window-min-height); - height: var(--window-min-height); - } + `@media` (min-width: 841px) { + body.is-scroll-driven.is-complete .chat-panel { + min-height: var(--window-min-height); + max-height: var(--window-min-height); + height: var(--window-min-height); + } + }Also applies to: 1065-1068
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro/touchai-components.html` around lines 501 - 505, The CSS rule for body.is-scroll-driven.is-complete .chat-panel is too specific and overrides mobile height rules when scroll-driven progress reaches the complete state. Wrap this rule (which appears at lines 501-505 and also at lines 1065-1068) in a desktop media query, using the same media query pattern already used for the reminder demo in this file, to prevent the fixed height from being applied to mobile viewports.
1201-1205:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel deltas to the parent instead of scrolling the iframe.
After
preventDefault(),window.scrollBy()only targets this iframe document, so scroll-driven mode traps wheel input instead of advancing the host page. Send the delta over the existing parent message channel and handle it in the host.Suggested child-side change
- function notifyParent(type) { + function notifyParent(type, payload = {}) { try { if (window.parent && window.parent !== window) { - window.parent.postMessage({ type }, window.location.origin); + window.parent.postMessage({ type, ...payload }, window.location.origin); } } catch (error) {} } ... event.preventDefault(); - window.scrollBy(0, nextDeltaY); + notifyParent('touchai-wheel-delta', { deltaY: nextDeltaY }); }Also applies to: 1560-1579
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro/touchai-components.html` around lines 1201 - 1205, The iframe is currently preventing default wheel behavior and scrolling itself, which traps wheel input. Instead, modify the wheel event handler to capture the wheel delta values (deltaX and deltaY) from the wheel event, and send these delta values to the parent via the notifyParent function's postMessage channel. Remove the window.scrollBy() call from the iframe's wheel handler so the parent page can handle the scrolling instead of being trapped by the iframe's scroll behavior.apps/site/public/touchai-intro-en/touchai-components.html (1)
1191-1195:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel deltas to the host page.
window.scrollBy()only scrolls the iframe after Line 1505 prevents the default wheel behavior, so embedded scroll-driven demos can swallow wheel input. Post the delta to the parent and let the host scroll handler consume it.Suggested child-side change
- function notifyParent(type) { + function notifyParent(type, payload = {}) { try { if (window.parent && window.parent !== window) { - window.parent.postMessage({ type }, window.location.origin); + window.parent.postMessage({ type, ...payload }, window.location.origin); } } catch (error) {} } ... event.preventDefault(); - window.scrollBy(0, nextDeltaY); + notifyParent('touchai-wheel-delta', { deltaY: nextDeltaY }); }Also applies to: 1487-1506
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/touchai-intro-en/touchai-components.html` around lines 1191 - 1195, The notifyParent function currently only posts message types to the parent window, but does not forward wheel delta information that would allow the parent page's scroll handler to consume scroll events. Modify the notifyParent function to accept wheel delta values (deltaX, deltaY) as parameters along with the type, and include these values in the postMessage payload being sent to window.parent. Additionally, locate the wheel event handler (likely in the vicinity of lines 1487-1506) and ensure it calls notifyParent with the type and the wheel event's deltaX and deltaY values so the parent can properly handle scrolling for embedded scroll-driven demos.apps/site/public/feature-reminder/touchai-components.html (1)
1595-1598:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not let
keepLatestResponseVisible()override the scrub threshold.Line 1732 gates
is-scrollingonscrubProgress >= 0.66, but Line 1597 immediately resets it tomaxScroll > 1, causing the scroll layout to activate as soon as content overflows.Suggested fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; + return maxScroll; }Also applies to: 1731-1736
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-reminder/touchai-components.html` around lines 1595 - 1598, The keepLatestResponseVisible() function is unconditionally toggling the is-scrolling class based on maxScroll > 1, overriding the scrub threshold gate that requires scrubProgress >= 0.66. Modify the toggle condition in keepLatestResponseVisible() to respect both constraints: only apply the is-scrolling class when maxScroll > 1 AND scrubProgress >= 0.66 are both true, ensuring the scroll layout respects the scrub threshold requirement defined elsewhere in the code.apps/site/public/feature-solver/touchai-components.html (1)
1967-1970:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not overwrite the scroll-driven threshold.
Line 2101 gates
is-scrollingonscrubProgress >= 0.66, butkeepLatestResponseVisible()immediately toggles the class back on whenever the solver content overflows. The long solution will enter scrolling layout before the scrub threshold.Proposed fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; }Also applies to: 2100-2105
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-solver/touchai-components.html` around lines 1967 - 1970, The keepLatestResponseVisible() function is unconditionally toggling the is-scrolling class whenever the solver content overflows, which overwrites the scroll-driven threshold check that should gate the class on scrubProgress >= 0.66. Remove the document.body.classList.toggle() call from keepLatestResponseVisible() and only keep the content.scrollTop assignment, allowing the is-scrolling class to be controlled exclusively by the scrub progress threshold check elsewhere in the code.apps/site/public/feature-reminder-en/touchai-components.html (2)
1622-1642:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel deltas to the parent instead of scrolling the iframe.
After Line 1640 calls
preventDefault(),window.scrollBy()only targets this iframe document, so wheel input is swallowed during scroll-driven playback instead of continuing the host page scroll.Proposed fix
- event.preventDefault(); - window.scrollBy(0, nextDeltaY); + try { + if (window.parent && window.parent !== window) { + event.preventDefault(); + window.parent.scrollBy(0, nextDeltaY); + } + } catch (error) {} }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-reminder-en/touchai-components.html` around lines 1622 - 1642, The forwardWheelToPage function is calling preventDefault() followed by window.scrollBy(), which only scrolls the iframe's own document instead of forwarding the wheel input to the parent page. Replace the window.scrollBy(0, nextDeltaY) call with window.parent.scrollBy(0, nextDeltaY) so that the wheel delta is forwarded to and scrolls the host/parent page instead of being consumed by the iframe document.
1601-1604:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve the scrub threshold when pinning the response.
Line 1738 sets
is-scrollingonly afterscrubProgress >= 0.66, butkeepLatestResponseVisible()immediately overwrites it based only on overflow. Once the response overflows, the scroll/composer state turns on before the intended scrub point.Proposed fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; }Also applies to: 1737-1742
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-reminder-en/touchai-components.html` around lines 1601 - 1604, The keepLatestResponseVisible() function is unconditionally toggling the is-scrolling class based solely on whether content overflows (maxScroll > 1), which overwrites the scrub threshold logic defined elsewhere that should only enable is-scrolling when scrubProgress reaches 0.66 or higher. Modify the keepLatestResponseVisible() function to respect the scrub threshold constraint instead of immediately setting is-scrolling on any overflow; the class should only be toggled when both the overflow condition is met and the scrub progress threshold (0.66) has been reached, preserving the intended scroll/composer state behavior.apps/site/public/feature-solver-en/touchai-components.html (1)
1877-1880:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep
is-scrollingcontrolled by the scrub threshold.Line 2015 correctly gates
is-scrollingonscrubProgress >= 0.66, butkeepLatestResponseVisible()immediately re-enables it whenever the long answer overflows. That makes the scroll/composer layout switch too early.Proposed fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; }Also applies to: 2014-2019
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-solver-en/touchai-components.html` around lines 1877 - 1880, The keepLatestResponseVisible() function is toggling the is-scrolling class based on content overflow, which conflicts with the scrub threshold control that correctly gates is-scrolling on scrubProgress >= 0.66 elsewhere. Remove the document.body.classList.toggle line that controls is-scrolling based on maxScroll overflow, keeping only the content.scrollTop assignment for scroll positioning. This ensures the is-scrolling class is exclusively controlled by the scrub threshold check, preventing premature layout switching.apps/site/public/feature-work-organizer-en/touchai-components.html (2)
1495-1514:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel scrolling to the host page, not the iframe.
In scroll-driven mode this handler calls
preventDefault(), then Line 1514 scrolls the iframe’s ownwindow. For the embedded demo, that consumes the wheel event without advancing the landing page; scroll the parent window or post the delta to the host runtime instead.🐛 Proposed fix
function forwardWheelToPage(event) { - if (event.ctrlKey || event.metaKey) { - event.preventDefault(); - return; - } - if (!isScrollDriven || !hasReceivedScrollProgress) { return; } + + if (event.ctrlKey || event.metaKey) { + return; + } const deltaMultiplier = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? window.innerHeight : 1; @@ event.preventDefault(); - window.scrollBy(0, nextDeltaY); + const scrollWindow = window.parent && window.parent !== window ? window.parent : window; + scrollWindow.scrollBy(0, nextDeltaY); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer-en/touchai-components.html` around lines 1495 - 1514, The forwardWheelToPage function currently scrolls the iframe's own window using window.scrollBy, which prevents the wheel event from advancing the parent landing page. Instead of scrolling the iframe window with window.scrollBy(0, nextDeltaY), scroll the parent window using window.parent.scrollBy(0, nextDeltaY) to forward the wheel movement to the host page, ensuring the embedded demo properly delegates scrolling to the parent document.
1474-1478:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve the scroll threshold before pinning to the bottom.
Line 1612 gates
is-scrollingbehindscrubProgress >= 0.66, but Line 1616 immediately callskeepLatestResponseVisible(), which togglesis-scrollingback on for any overflow. This bypasses the threshold and can make the panel jump into scrolling mode too early.🐛 Proposed fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; } @@ -const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); -document.body.classList.toggle( - 'is-scrolling', - maxScroll > 1 && scrubProgress >= 0.66 -); -keepLatestResponseVisible(); +const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); +const shouldAutoScroll = maxScroll > 1 && scrubProgress >= 0.66; +document.body.classList.toggle('is-scrolling', shouldAutoScroll); +if (shouldAutoScroll) { + keepLatestResponseVisible(); +} updateScrollAffordance();Also applies to: 1611-1617
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer-en/touchai-components.html` around lines 1474 - 1478, The keepLatestResponseVisible() function toggles the is-scrolling class unconditionally whenever there is overflow, which bypasses the scroll threshold gating at scrubProgress >= 0.66. Modify keepLatestResponseVisible() to respect the threshold condition before toggling is-scrolling, either by passing the scrubProgress threshold as a parameter or checking it within the function, so that is-scrolling is only activated when the threshold is actually met and the panel does not jump into scrolling mode prematurely.apps/site/public/feature-work-organizer/touchai-components.html (2)
1468-1472:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve the scroll threshold before pinning to the bottom.
Line 1602 gates
is-scrollingbehindscrubProgress >= 0.66, but Line 1606 immediately callskeepLatestResponseVisible(), which togglesis-scrollingback on for any overflow. This bypasses the threshold and can make the panel jump into scrolling mode too early.🐛 Proposed fix
function keepLatestResponseVisible() { const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); - document.body.classList.toggle('is-scrolling', maxScroll > 1); content.scrollTop = maxScroll; } @@ -const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); -document.body.classList.toggle( - 'is-scrolling', - maxScroll > 1 && scrubProgress >= 0.66 -); -keepLatestResponseVisible(); +const maxScroll = Math.max(0, content.scrollHeight - content.clientHeight); +const shouldAutoScroll = maxScroll > 1 && scrubProgress >= 0.66; +document.body.classList.toggle('is-scrolling', shouldAutoScroll); +if (shouldAutoScroll) { + keepLatestResponseVisible(); +} updateScrollAffordance();Also applies to: 1601-1607
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer/touchai-components.html` around lines 1468 - 1472, The keepLatestResponseVisible() function unconditionally toggles the is-scrolling class based on whether content overflows, which bypasses the scroll threshold check that was previously applied at line 1602. Instead of having keepLatestResponseVisible() toggle the is-scrolling class, modify it to only handle scrolling the content to the bottom by setting content.scrollTop to maxScroll, and remove the toggle logic that checks maxScroll > 1. Preserve the is-scrolling class state that was already determined by the threshold check at line 1602 so the panel does not jump into scrolling mode prematurely.
1489-1508:⚠️ Potential issue | 🟠 Major | ⚡ Quick winForward wheel scrolling to the host page, not the iframe.
In scroll-driven mode this handler calls
preventDefault(), then Line 1508 scrolls the iframe’s ownwindow. For the embedded demo, that consumes the wheel event without advancing the landing page; scroll the parent window or post the delta to the host runtime instead.🐛 Proposed fix
function forwardWheelToPage(event) { - if (event.ctrlKey || event.metaKey) { - event.preventDefault(); - return; - } - if (!isScrollDriven || !hasReceivedScrollProgress) { return; } + + if (event.ctrlKey || event.metaKey) { + return; + } const deltaMultiplier = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? window.innerHeight : 1; @@ event.preventDefault(); - window.scrollBy(0, nextDeltaY); + const scrollWindow = window.parent && window.parent !== window ? window.parent : window; + scrollWindow.scrollBy(0, nextDeltaY); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/public/feature-work-organizer/touchai-components.html` around lines 1489 - 1508, The forwardWheelToPage function currently scrolls the iframe's own window using window.scrollBy(0, nextDeltaY), which prevents the host page from scrolling. Replace this call with window.parent.scrollBy(0, nextDeltaY) to forward the wheel delta to the parent/host window instead, ensuring the landing page advances rather than being consumed within the embedded iframe.apps/site/src/pages/index.astro (4)
336-343:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMake the nav fade overlay non-interactive.
.nav::afterextends 24px below the sticky header and currently participates in hit testing, so the transparent strip can block clicks on content underneath. It should be visual-only.Proposed fix
.nav::after { content: ''; position: absolute; left: 0; right: 0; bottom: -24px; height: 24px; - pointer-events: auto; + pointer-events: none; opacity: 0;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 336 - 343, The `.nav::after` pseudo-element currently has `pointer-events: auto` which causes it to participate in hit testing and blocks clicks on content underneath the 24px transparent overlay below the sticky header. Change the `pointer-events` property from `auto` to `none` on the `.nav::after` rule so the overlay becomes visual-only and does not interfere with interactions on the content below it.
3485-3490:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winClear feature demos after leaving their scroll range.
Feature triggers set terminal progress but never send
touchai-clear-scroll-driven, unlike the intro trigger. Send the idle signal after0/1so feature iframes do not remain stuck in scroll-driven mode offscreen.Proposed fix
onLeave: () => { syncFeatureDemoProgress(frame, 1); + queueDemoScrollIdle(frame); }, onLeaveBack: () => { syncFeatureDemoProgress(frame, 0); + queueDemoScrollIdle(frame); },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 3485 - 3490, The feature demo scroll triggers in the onLeave and onLeaveBack callbacks are missing the idle signal that clears scroll-driven mode from the iframes. After each call to syncFeatureDemoProgress in both the onLeave and onLeaveBack callbacks, send the touchai-clear-scroll-driven signal to the frame to ensure feature iframes properly exit scroll-driven mode when they leave the viewport, preventing them from remaining stuck offscreen.
2042-2059:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRe-add the open-issues stat using the issues search API.
The current stats model and UI only render Stars/Forks, so the PR’s “Open issues” correction is no longer represented. Add an
issuesstat wired tosearch/issues?q=repo:${repoPath} is:issue state:openso pull requests stay excluded.Also applies to: 2802-2899
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 2042 - 2059, Add a third github-stat div block for open issues to the github-stats container, following the same structure as the existing stars and forks stats. The new issues stat should use a strong element with data-github-stat="issues" attribute, a corresponding span with data-i18n="teams.stats.issues" label, and ensure the parent github-stats div includes data-initial-issues attribute with the initial open issues count. The issues data should be configured to use the GitHub search API endpoint with the query format search/issues?q=repo:${repoPath} is:issue state:open to properly exclude pull requests from the count.
2456-2505:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReset progress dedupe when demos are cleared or reloaded.
lastDispatchedDemoProgresssurvivesreload()andtouchai-clear-scroll-driven. If the intro iframe reloads during language switching and the current progress is unchanged,queueDemoProgressdrops the ready-time sync, leaving the new iframe unsynced until scroll changes.Proposed direction
+const resetDemoProgressDedupe = (frame) => { + if (!frame) return; + lastDispatchedDemoProgress.delete(frame); +}; const cancelQueuedDemoProgress = (frame) => { if (!frame) return; const frameHandle = demoProgressFrameHandles.get(frame); if (frameHandle) { cancelAnimationFrame(frameHandle); demoProgressFrameHandles.delete(frame); } pendingDemoProgress.delete(frame); + resetDemoProgressDedupe(frame); }; const queueDemoScrollIdle = (frame) => { if (!frame) return; requestAnimationFrame(() => { + resetDemoProgressDedupe(frame); sendToDemo(frame, { type: 'touchai-clear-scroll-driven' }); }); };Also call
resetDemoProgressDedupe(introDemo)before changingintroDemo.dataset.src, or force the intro ready-time progress sync.Also applies to: 2568-2576, 3348-3354
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/site/src/pages/index.astro` around lines 2456 - 2505, The `lastDispatchedDemoProgress` Map persists across demo reloads and clear operations, causing the deduplication logic in `queueDemoProgress` to skip progress updates when the value hasn't changed since the last dispatch. This leaves newly reloaded iframes unsynced. Create a function called `resetDemoProgressDedupe` that clears entries from the `lastDispatchedDemoProgress` Map for a given frame, then call this function before changing `introDemo.dataset.src` or when handling the touchai-clear-scroll-driven message in `queueDemoScrollIdle` to ensure the deduplication state is reset and progress is re-synced to reloaded demos.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/site/src/pages/index.astro`:
- Line 1803: The ARIA labels for accessibility are hardcoded in Chinese and do
not respond to language changes, while visible copy properly localizes. Update
the nav header aria-label attribute (currently showing "主导航"), replay-card
labels, and theme toggle label/title to use the same locale-aware pattern used
for visible copy that switches between languages. Additionally, review the
execution order of setTheme() and setLanguage() functions to ensure that
setTheme() does not run after setLanguage() and overwrite the theme toggle text
with Chinese. Apply this locale-aware pattern consistently across all identified
locations including the nav aria-label, replay-card ARIA labels, and theme
toggle related labels.
---
Outside diff comments:
In `@apps/site/public/feature-reminder-en/touchai-components.html`:
- Around line 1622-1642: The forwardWheelToPage function is calling
preventDefault() followed by window.scrollBy(), which only scrolls the iframe's
own document instead of forwarding the wheel input to the parent page. Replace
the window.scrollBy(0, nextDeltaY) call with window.parent.scrollBy(0,
nextDeltaY) so that the wheel delta is forwarded to and scrolls the host/parent
page instead of being consumed by the iframe document.
- Around line 1601-1604: The keepLatestResponseVisible() function is
unconditionally toggling the is-scrolling class based solely on whether content
overflows (maxScroll > 1), which overwrites the scrub threshold logic defined
elsewhere that should only enable is-scrolling when scrubProgress reaches 0.66
or higher. Modify the keepLatestResponseVisible() function to respect the scrub
threshold constraint instead of immediately setting is-scrolling on any
overflow; the class should only be toggled when both the overflow condition is
met and the scrub progress threshold (0.66) has been reached, preserving the
intended scroll/composer state behavior.
In `@apps/site/public/feature-reminder/touchai-components.html`:
- Around line 1595-1598: The keepLatestResponseVisible() function is
unconditionally toggling the is-scrolling class based on maxScroll > 1,
overriding the scrub threshold gate that requires scrubProgress >= 0.66. Modify
the toggle condition in keepLatestResponseVisible() to respect both constraints:
only apply the is-scrolling class when maxScroll > 1 AND scrubProgress >= 0.66
are both true, ensuring the scroll layout respects the scrub threshold
requirement defined elsewhere in the code.
In `@apps/site/public/feature-solver-en/touchai-components.html`:
- Around line 1877-1880: The keepLatestResponseVisible() function is toggling
the is-scrolling class based on content overflow, which conflicts with the scrub
threshold control that correctly gates is-scrolling on scrubProgress >= 0.66
elsewhere. Remove the document.body.classList.toggle line that controls
is-scrolling based on maxScroll overflow, keeping only the content.scrollTop
assignment for scroll positioning. This ensures the is-scrolling class is
exclusively controlled by the scrub threshold check, preventing premature layout
switching.
In `@apps/site/public/feature-solver/touchai-components.html`:
- Around line 1967-1970: The keepLatestResponseVisible() function is
unconditionally toggling the is-scrolling class whenever the solver content
overflows, which overwrites the scroll-driven threshold check that should gate
the class on scrubProgress >= 0.66. Remove the document.body.classList.toggle()
call from keepLatestResponseVisible() and only keep the content.scrollTop
assignment, allowing the is-scrolling class to be controlled exclusively by the
scrub progress threshold check elsewhere in the code.
In `@apps/site/public/feature-work-organizer-en/touchai-components.html`:
- Around line 1495-1514: The forwardWheelToPage function currently scrolls the
iframe's own window using window.scrollBy, which prevents the wheel event from
advancing the parent landing page. Instead of scrolling the iframe window with
window.scrollBy(0, nextDeltaY), scroll the parent window using
window.parent.scrollBy(0, nextDeltaY) to forward the wheel movement to the host
page, ensuring the embedded demo properly delegates scrolling to the parent
document.
- Around line 1474-1478: The keepLatestResponseVisible() function toggles the
is-scrolling class unconditionally whenever there is overflow, which bypasses
the scroll threshold gating at scrubProgress >= 0.66. Modify
keepLatestResponseVisible() to respect the threshold condition before toggling
is-scrolling, either by passing the scrubProgress threshold as a parameter or
checking it within the function, so that is-scrolling is only activated when the
threshold is actually met and the panel does not jump into scrolling mode
prematurely.
In `@apps/site/public/feature-work-organizer/touchai-components.html`:
- Around line 1468-1472: The keepLatestResponseVisible() function
unconditionally toggles the is-scrolling class based on whether content
overflows, which bypasses the scroll threshold check that was previously applied
at line 1602. Instead of having keepLatestResponseVisible() toggle the
is-scrolling class, modify it to only handle scrolling the content to the bottom
by setting content.scrollTop to maxScroll, and remove the toggle logic that
checks maxScroll > 1. Preserve the is-scrolling class state that was already
determined by the threshold check at line 1602 so the panel does not jump into
scrolling mode prematurely.
- Around line 1489-1508: The forwardWheelToPage function currently scrolls the
iframe's own window using window.scrollBy(0, nextDeltaY), which prevents the
host page from scrolling. Replace this call with window.parent.scrollBy(0,
nextDeltaY) to forward the wheel delta to the parent/host window instead,
ensuring the landing page advances rather than being consumed within the
embedded iframe.
In `@apps/site/public/touchai-intro-en/touchai-components.html`:
- Around line 1191-1195: The notifyParent function currently only posts message
types to the parent window, but does not forward wheel delta information that
would allow the parent page's scroll handler to consume scroll events. Modify
the notifyParent function to accept wheel delta values (deltaX, deltaY) as
parameters along with the type, and include these values in the postMessage
payload being sent to window.parent. Additionally, locate the wheel event
handler (likely in the vicinity of lines 1487-1506) and ensure it calls
notifyParent with the type and the wheel event's deltaX and deltaY values so the
parent can properly handle scrolling for embedded scroll-driven demos.
In `@apps/site/public/touchai-intro/touchai-components.html`:
- Around line 501-505: The CSS rule for body.is-scroll-driven.is-complete
.chat-panel is too specific and overrides mobile height rules when scroll-driven
progress reaches the complete state. Wrap this rule (which appears at lines
501-505 and also at lines 1065-1068) in a desktop media query, using the same
media query pattern already used for the reminder demo in this file, to prevent
the fixed height from being applied to mobile viewports.
- Around line 1201-1205: The iframe is currently preventing default wheel
behavior and scrolling itself, which traps wheel input. Instead, modify the
wheel event handler to capture the wheel delta values (deltaX and deltaY) from
the wheel event, and send these delta values to the parent via the notifyParent
function's postMessage channel. Remove the window.scrollBy() call from the
iframe's wheel handler so the parent page can handle the scrolling instead of
being trapped by the iframe's scroll behavior.
In `@apps/site/src/pages/index.astro`:
- Around line 336-343: The `.nav::after` pseudo-element currently has
`pointer-events: auto` which causes it to participate in hit testing and blocks
clicks on content underneath the 24px transparent overlay below the sticky
header. Change the `pointer-events` property from `auto` to `none` on the
`.nav::after` rule so the overlay becomes visual-only and does not interfere
with interactions on the content below it.
- Around line 3485-3490: The feature demo scroll triggers in the onLeave and
onLeaveBack callbacks are missing the idle signal that clears scroll-driven mode
from the iframes. After each call to syncFeatureDemoProgress in both the onLeave
and onLeaveBack callbacks, send the touchai-clear-scroll-driven signal to the
frame to ensure feature iframes properly exit scroll-driven mode when they leave
the viewport, preventing them from remaining stuck offscreen.
- Around line 2042-2059: Add a third github-stat div block for open issues to
the github-stats container, following the same structure as the existing stars
and forks stats. The new issues stat should use a strong element with
data-github-stat="issues" attribute, a corresponding span with
data-i18n="teams.stats.issues" label, and ensure the parent github-stats div
includes data-initial-issues attribute with the initial open issues count. The
issues data should be configured to use the GitHub search API endpoint with the
query format search/issues?q=repo:${repoPath} is:issue state:open to properly
exclude pull requests from the count.
- Around line 2456-2505: The `lastDispatchedDemoProgress` Map persists across
demo reloads and clear operations, causing the deduplication logic in
`queueDemoProgress` to skip progress updates when the value hasn't changed since
the last dispatch. This leaves newly reloaded iframes unsynced. Create a
function called `resetDemoProgressDedupe` that clears entries from the
`lastDispatchedDemoProgress` Map for a given frame, then call this function
before changing `introDemo.dataset.src` or when handling the
touchai-clear-scroll-driven message in `queueDemoScrollIdle` to ensure the
deduplication state is reset and progress is re-synced to reloaded demos.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 69b89b87-6ed7-45a1-8ffa-e3983d1ae62e
⛔ Files ignored due to path filters (1)
apps/site/public/seo-card.pngis excluded by!**/*.png
📒 Files selected for processing (10)
apps/site/.env.exampleapps/site/public/feature-reminder-en/touchai-components.htmlapps/site/public/feature-reminder/touchai-components.htmlapps/site/public/feature-solver-en/touchai-components.htmlapps/site/public/feature-solver/touchai-components.htmlapps/site/public/feature-work-organizer-en/touchai-components.htmlapps/site/public/feature-work-organizer/touchai-components.htmlapps/site/public/touchai-intro-en/touchai-components.htmlapps/site/public/touchai-intro/touchai-components.htmlapps/site/src/pages/index.astro
💤 Files with no reviewable changes (1)
- apps/site/.env.example
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (rust)
🧰 Additional context used
🪛 ast-grep (0.43.0)
apps/site/public/feature-reminder-en/touchai-components.html
[warning] 1665-1665: Avoid using the initial state variable in setState
Context: setToolCallVisibility(ratio)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.
(setstate-same-var)
apps/site/public/feature-reminder/touchai-components.html
[warning] 1659-1659: Avoid using the initial state variable in setState
Context: setToolCallVisibility(ratio)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.
(setstate-same-var)
🔇 Additional comments (8)
apps/site/public/feature-reminder/touchai-components.html (2)
1616-1636: Duplicate: wheel deltas are still swallowed inside the iframe.This is the same unresolved issue already flagged on this file: after
preventDefault(),window.scrollBy()only scrolls the iframe document, not the embedding page.
511-517: LGTM!apps/site/public/feature-solver/touchai-components.html (1)
1988-2008: Duplicate: wheel input is still trapped inside the iframe.This is the same issue previously flagged: Line 2006 prevents the native wheel behavior, then Line 2007 scrolls only the iframe window rather than the host page.
apps/site/public/feature-solver-en/touchai-components.html (1)
1898-1918: Duplicate: wheel input is still trapped inside the iframe.This is the same issue previously flagged: Line 1916 prevents default wheel behavior, then Line 1917 scrolls only the iframe window instead of the host page.
apps/site/public/feature-work-organizer/touchai-components.html (1)
511-517: LGTM!Also applies to: 1118-1123, 1137-1144, 1162-1162, 1730-1767
apps/site/public/feature-work-organizer-en/touchai-components.html (1)
2-2: LGTM!Also applies to: 1070-1159, 1168-1168, 1235-1244
apps/site/src/pages/index.astro (2)
1802-1802: Already covered: validatePUBLIC_ANALYTICS_ENDPOINTbefore emitting it.A previous review comment already requested build/client validation for this dataset value.
627-634: LGTM!
4309fcc to
950efd4
Compare
|
Merged. Thank you for contributing to TouchAI again. 已合并。感谢你再次为 TouchAI 做出贡献。 We appreciate the continued help. |
Summary
Open issuescounts only open issues, not pull requests.robots.txt, sitemap reference, Starlight docs collection wiring, a custom 404 page, and a getting-started page.PUBLIC_ANALYTICS_ENDPOINTis set; when enabled it sends pageview/click metadata such as URL, path, title, language, referrer, viewport, event type, and link label.Scope note
This PR is intentionally
apps/site-only. It does not touch desktop app runtime, AgentService, MCP, database schema, release packaging, or Rust behavior. The scope is broader than a narrow demo bugfix: it updates the landing experience, repo stats, site metadata, docs surface, and optional analytics plumbing together as a follow-up to the prior site refresh work.The English solver demo now uses English page chrome, fallback content, and accessibility strings. The problem image is still described as a screenshot of a Chinese conic-section math problem, because the source problem image itself is Chinese.
Related issue or RFC
This is a follow-up to the previously merged site refresh and responsive/demo polish PRs.
AI assistance disclosure
apps/site; no desktop/runtime/database boundaries are changed.Testing evidence
Additional local browser verification:
Additional review validation on the PR head:
pnpm test:prwas not completed successfully locally. Earlier local runs were blocked by the RTK asset download path; the latest review run got farther but exhausted local disk space during Rust/C compilation (no space on deviceincheck:rust). Because this PR only changesapps/site, full desktop PR verification should be covered by CI or rerun on a machine with enough Rust build cache space before merge.Did you follow TDD? Partially. A small content assertion was run red/green for the English solver demo accessibility strings, then the site files were verified with Prettier, ESLint, and the site build. No broader automated site test suite exists in
apps/site.Risk notes
AgentService, runtime, MCP, or schema impact: nonePUBLIC_ANALYTICS_ENDPOINTshould provide appropriate disclosure/consent for collected pageview and click metadataScreenshots or recordings
Local browser verification was performed at:
Observed stats:
Checklist
[WIP]or similar title prefixes.AgentService, runtime, MCP, or schema boundaries, there is an accepted RFC. N/A.pnpm test:prfor this code PR, or this is a docs-only change. Local run did not complete; see validation notes above.pnpm test:coverage:rustor relied on CI coverage evidence. N/A.pnpm test:e2elocally or documented why CI is the first valid proof. N/A.