Skip to content

feat: add AI section to homepage#2768

Open
chenparnasa wants to merge 11 commits intomainfrom
feat-ai-section
Open

feat: add AI section to homepage#2768
chenparnasa wants to merge 11 commits intomainfrom
feat-ai-section

Conversation

@chenparnasa
Copy link

@chenparnasa chenparnasa commented Feb 24, 2026

What does this PR do?

This PR adds a new AI-focused section below the "Build like a team of hundreds" section on the homepage.
The section showcases AI-related features like MCP, agent skills, agent rules, Supported IDEs.

The section is fully responsive and supports mobile behavior.

**On first commit, local build showed a 500 error on /threads/data.json, but I'm not aware of changes made to it. Tested in the dev server and preview works as expected.

Update: Added benchmark preview + new illustrations

Screen.Recording.2026-03-03.at.18.31.52.mov

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

Summary by CodeRabbit

  • New Features
    • Added an AI section to the marketing page with a responsive two-column layout showcasing MCP and Skills visual animations.
    • Included a full-width ecosystem strip of six tool icons with desktop hover tooltips and a tap-to-select mobile interaction, plus subtle hover lighting and per-tool theming.
    • Animations and interactions respond to hover and in-view triggers on desktop and mobile, enhancing engagement without altering data flows.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new Svelte component at src/routes/(marketing)/(components)/ai.svelte and mounts it in the marketing page. The new component composes two SVG animation components (mcp.svelte and skills.svelte) that use GridPaper backdrops, requestAnimationFrame-driven easing animations, and hover/in-view triggers with desktop/mobile behavior. It also adds a full-width ecosystem/tool strip with masked tool icons, per-tool gradients, desktop tooltips, and a tap-to-select mobile interaction. All UI is driven by local state and static arrays; no runtime data fetching or external API changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add AI section to homepage' clearly and concisely describes the main change—adding a new AI-focused section to the homepage. It aligns with the primary objective and is specific enough for quick understanding.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-ai-section

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 63-85: The two Svelte each-blocks are missing stable keys; update
the first each "{`#each` categories as category, i}" to include a key such as
"(category.id ?? category.label ?? i)" and update the second each to include an
index (e.g., "{`#each` categories[active].features as feature, j}") and a key such
as "(feature.id ?? feature.title ?? j)" so Svelte can track items reliably and
satisfy ESLint.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 81c6e0d and eb7f465.

📒 Files selected for processing (2)
  • src/routes/(marketing)/(components)/ai.svelte
  • src/routes/(marketing)/+page.svelte

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/routes/(marketing)/(components)/ai.svelte (1)

54-87: ⚠️ Potential issue | 🟠 Major

Add a stable key to the #each block.

The loop is unkeyed (Line 54), which triggers svelte/require-each-key and can cause unstable DOM updates.

🛠️ Suggested fix
-                    {`#each` tools as tool, i}
+                    {`#each` tools as tool, i (tool.name)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 54 - 87, The
`#each` block iterating "tools" is unkeyed (in the {`#each` tools as tool, i} loop)
causing unstable DOM updates; update the each block to include a stable unique
key (preferably tool.id, falling back to tool.name or another immutable unique
field) so Svelte can track items reliably—locate the loop around the
Tooltip.Root/Tooltip.Trigger/Tooltip.Content components and add the key
expression to the {`#each`} statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/mcp.svelte:
- Around line 7-14: The SVG is decorative and should be hidden from assistive
tech: update the <svg> element in mcp.svelte to include accessibility attributes
such as aria-hidden="true" and focusable="false" (and remove any role or title
that would expose it) so screen readers ignore the graphic; locate the <svg> tag
in the component and add those attributes to apply AT hiding.

In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 7-14: The SVG at the top of the component is decorative and should
be hidden from assistive tech; update the opening <svg> element (the SVG with
viewBox="0 0 541 273") to include aria-hidden="true", role="presentation" and
focusable="false" so screen readers ignore it and it is not keyboard-focusable.

In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 60-72: Tooltip.Trigger is currently icon-only and lacks an
accessible name; add an accessible label so screen readers can identify each
control by setting an aria-label (or title) on Tooltip.Trigger using the tool's
descriptive property (e.g., tool.name or tool.label) and, for robustness,
include a visually-hidden fallback span (class="sr-only") inside the trigger
with the same text; ensure the trigger remains keyboard-focusable (add
tabindex="0" if Tooltip.Trigger doesn't render a native focusable element).
- Line 2: The module imports the Icon symbol but never uses it; remove the
unused import statement "import Icon from
'$lib/components/ui/icon/icon.svelte';" at the top of the file (or alternatively
use the Icon component where intended) so the unused-import lint error is
resolved; ensure no other references to Icon remain after removal.

---

Duplicate comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 54-87: The `#each` block iterating "tools" is unkeyed (in the {`#each`
tools as tool, i} loop) causing unstable DOM updates; update the each block to
include a stable unique key (preferably tool.id, falling back to tool.name or
another immutable unique field) so Svelte can track items reliably—locate the
loop around the Tooltip.Root/Tooltip.Trigger/Tooltip.Content components and add
the key expression to the {`#each`} statement.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb7f465 and dcd4151.

📒 Files selected for processing (3)
  • src/routes/(marketing)/(components)/(ai-animations)/mcp.svelte
  • src/routes/(marketing)/(components)/(ai-animations)/skills.svelte
  • src/routes/(marketing)/(components)/ai.svelte

@@ -0,0 +1,92 @@
<script lang="ts">
import Icon from '$lib/components/ui/icon/icon.svelte';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused Icon import.

Icon is imported but never used (Line 2), which currently fails lint.

🧹 Suggested fix
-    import Icon from '$lib/components/ui/icon/icon.svelte';
     import Noise from '$lib/components/fancy/noise.svelte';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import Icon from '$lib/components/ui/icon/icon.svelte';
🧰 Tools
🪛 ESLint

[error] 2-2: 'Icon' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte at line 2, The module imports
the Icon symbol but never uses it; remove the unused import statement "import
Icon from '$lib/components/ui/icon/icon.svelte';" at the top of the file (or
alternatively use the Icon component where intended) so the unused-import lint
error is resolved; ensure no other references to Icon remain after removal.

Comment on lines +60 to +72
<Tooltip.Trigger
class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}"
>
<div
style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;"
class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]"
></div>
<div
class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10"
>
<Noise opacity={0.1} />
</div>
</Tooltip.Trigger>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Provide an accessible name for icon-only tooltip triggers.

Tooltip.Trigger is visual-only here; add an accessible label so screen reader users can identify each control (Line 60).

♿ Suggested fix
                                 <Tooltip.Trigger
+                                    aria-label={tool.name}
                                     class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}"
                                 >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Tooltip.Trigger
class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}"
>
<div
style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;"
class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]"
></div>
<div
class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10"
>
<Noise opacity={0.1} />
</div>
</Tooltip.Trigger>
<Tooltip.Trigger
aria-label={tool.name}
class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}"
>
<div
style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;"
class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]"
></div>
<div
class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10"
>
<Noise opacity={0.1} />
</div>
</Tooltip.Trigger>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 60 - 72,
Tooltip.Trigger is currently icon-only and lacks an accessible name; add an
accessible label so screen readers can identify each control by setting an
aria-label (or title) on Tooltip.Trigger using the tool's descriptive property
(e.g., tool.name or tool.label) and, for robustness, include a visually-hidden
fallback span (class="sr-only") inside the trigger with the same text; ensure
the trigger remains keyboard-focusable (add tabindex="0" if Tooltip.Trigger
doesn't render a native focusable element).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/routes/(marketing)/(components)/(ai-animations)/skills.svelte (1)

22-24: Consider extracting shared animation utilities.

The easeOut function is identical in both mcp.svelte and skills.svelte. Consider extracting it to a shared utility module if more animation components are planned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte around
lines 22 - 24, The easeOut function is duplicated between the skills.svelte and
mcp.svelte components; extract this shared animation utility into a single
module (e.g., an animations or easing utility file) and import it in both
components. Replace the local function declarations of easeOut in skills.svelte
and mcp.svelte with an import of the shared function, ensure the exported
function signature matches (easeOut(t: number)), and run the build/tests to
confirm no behavior changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/mcp.svelte:
- Around line 41-57: The $effect currently registers hover(container, ...) and
inView(container, ...) and starts an animation via slideTo/tick using rafId but
does not return a cleanup; update the $effect to return a single cleanup
function that (1) calls the unsubscribe/cleanup functions returned by hover(...)
and inView(...), (2) cancels any pending frame with cancelAnimationFrame(rafId),
and (3) unsubscribes any motion/spring subscriptions that slideTo/tick may have
touched so tick cannot access DOM nodes (leftBlock, rightCluster) after unmount;
locate the setup in the $effect and add this combined teardown to avoid orphaned
raf and subscriptions.

In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 47-63: The effect registered with $effect must return a teardown
that unsubscribes hover and inView and cancels any in-flight animation frames so
RAF callbacks don't touch an unmounted element; modify the block around $effect
to capture the cleanup handles returned by hover(container, ...) and
inView(container, ...), and capture the cancel function returned by
animateTo(DOCK_X, DOCK_Y) (and animateTo(0,0)) so you can call them on cleanup;
ensure animateTo is updated (if not already) to return a cancel function for its
RAF loop or guard its RAF callback with an alive flag, then return a single
cleanup function from $effect that calls the hover/inView unsubscribers and
cancels any pending animations (so references like container/piece are never
accessed after unmount).

---

Nitpick comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 22-24: The easeOut function is duplicated between the
skills.svelte and mcp.svelte components; extract this shared animation utility
into a single module (e.g., an animations or easing utility file) and import it
in both components. Replace the local function declarations of easeOut in
skills.svelte and mcp.svelte with an import of the shared function, ensure the
exported function signature matches (easeOut(t: number)), and run the
build/tests to confirm no behavior changes.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb7f465 and 390b22e.

📒 Files selected for processing (3)
  • src/routes/(marketing)/(components)/(ai-animations)/mcp.svelte
  • src/routes/(marketing)/(components)/(ai-animations)/skills.svelte
  • src/routes/(marketing)/(components)/ai.svelte

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 174-198: The each-block rendering tools lacks a stable key and
accessible labeling: update the {`#each` tools as tool, i} loop to use a unique
key (e.g., {`#each` tools as tool (tool.id ?? tool.name)}) and add accessible
attributes to the icon-only <button> rendered by handleMobileTap — include
aria-label={tool.name} (or aria-labelledby pointing to a visually hidden label)
and set aria-pressed={activeMobileIndex === i} so screen readers get state; keep
the Noise component and existing styling but ensure the mask div remains
decorative (role="img" with aria-hidden="true" if needed) so the button label is
the accessible name.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c099ba and 2b5b5da.

📒 Files selected for processing (1)
  • src/routes/(marketing)/(components)/ai.svelte

Comment on lines +174 to +198
{#each tools as tool, i}
<button
onclick={(e) => handleMobileTap(e, i)}
class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed {i ===
0
? 'border-l'
: ''}"
style="--primary-color:{tool.primary};--secondary-color:transparent"
>
<div
style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;"
class="h-9 w-9 transition-colors duration-500 {activeMobileIndex ===
i
? 'bg-[var(--primary-color)]'
: 'bg-white/40'}"
></div>
{#if activeMobileIndex === i}
<div
class="absolute inset-0 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10"
>
<Noise opacity={0.1} />
</div>
{/if}
</button>
{/each}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add keys and accessible labels to the mobile each-block.

Two issues here:

  1. Missing stable key for Svelte's diffing.
  2. Icon-only buttons lack accessible labels for screen reader users.
♿ Proposed fix
-                    {`#each` tools as tool, i}
+                    {`#each` tools as tool, i (tool.name)}
                         <button
+                            aria-label={tool.name}
                             onclick={(e) => handleMobileTap(e, i)}
                             class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed ..."
🧰 Tools
🪛 ESLint

[error] 174-198: Each block should have a key

(svelte/require-each-key)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 174 - 198, The
each-block rendering tools lacks a stable key and accessible labeling: update
the {`#each` tools as tool, i} loop to use a unique key (e.g., {`#each` tools as
tool (tool.id ?? tool.name)}) and add accessible attributes to the icon-only
<button> rendered by handleMobileTap — include aria-label={tool.name} (or
aria-labelledby pointing to a visually hidden label) and set
aria-pressed={activeMobileIndex === i} so screen readers get state; keep the
Noise component and existing styling but ensure the mask div remains decorative
(role="img" with aria-hidden="true" if needed) so the button label is the
accessible name.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (4)
src/routes/(marketing)/(components)/ai.svelte (4)

196-231: ⚠️ Potential issue | 🟡 Minor

Key the mobile tools loop and expose button state/accessibility label.

The mobile loop is also unkeyed, and the icon-only button should expose an accessible name and pressed state.

♿ Proposed fix
-                    {`#each` tools as tool, i}
+                    {`#each` tools as tool, i (tool.name)}
                         <button
+                            aria-label={tool.name}
+                            aria-pressed={activeMobileIndex === i}
                             onclick={(e) => handleMobileTap(e, i)}
                             class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed {i ===
                             0
                                 ? 'border-l'
                                 : ''}"
                             style="--primary-color:{tool.primary};--secondary-color:transparent"
                         >
+                            <span class="sr-only">{tool.name}</span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 196 - 231, The
mobile tools loop lacks a key and the icon-only <button> is missing
accessibility attributes; update the {`#each` tools as tool, i} block to include a
stable key (e.g., {`#each` tools as tool, i (tool.id ?? tool.name)}) and make the
button expose an accessible name and pressed state by adding
aria-label={tool.name} and aria-pressed={activeMobileIndex === i}; keep existing
click handler (handleMobileTap) and visual active logic using activeMobileIndex
unchanged so assistive tech can read the label and current selection.

3-3: ⚠️ Potential issue | 🟡 Minor

Remove unused Icon import.

Icon is imported but never referenced, which keeps lint failing.

🧹 Proposed fix
-    import Icon from '$lib/components/ui/icon/icon.svelte';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte at line 3, Remove the unused
import of Icon in ai.svelte: locate the line importing Icon (import Icon from
'$lib/components/ui/icon/icon.svelte';) and delete it so the module no longer
imports Icon that isn't referenced, which will resolve the linter failure.

157-172: ⚠️ Potential issue | 🟡 Minor

Add an accessible name to icon-only desktop tooltip triggers.

Tooltip.Trigger is icon-only here. Please expose an accessible label so screen readers can identify each control.

♿ Proposed fix
                                     <Tooltip.Trigger
+                                        aria-label={tool.name}
                                         class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i ===
                                         0
                                             ? 'border-l'
                                             : ''}"
                                     >
+                                        <span class="sr-only">{tool.name}</span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 157 - 172,
Tooltip.Trigger is currently icon-only and lacks an accessible name; update the
Tooltip.Trigger in the ai.svelte component to expose a descriptive label for
screen readers by either adding an aria-label attribute (e.g.,
aria-label={tool.name || tool.label}) to the Tooltip.Trigger element or by
including a visually-hidden text node (e.g., a span with an sr-only class using
tool.name) inside the trigger. Ensure the label uses the existing tool
identifier (tool.name/tool.label) so each icon has a unique, meaningful
accessible name and that the Noise component and mask styling remain unchanged.

151-188: ⚠️ Potential issue | 🟡 Minor

Add a stable key to the desktop tools each-block.

The tools loop is unkeyed, which violates svelte/require-each-key and can cause unstable DOM diffing during updates.

🛠️ Proposed fix
-                        {`#each` tools as tool, i}
+                        {`#each` tools as tool, i (tool.name)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(marketing)/(components)/ai.svelte around lines 151 - 188, The
each-block iterating over tools is unkeyed (the {`#each` tools as tool, i} block),
causing unstable DOM updates; add a stable key expression to the loop such as a
unique property on each tool (e.g., tool.id or tool.name) so it becomes {`#each`
tools as tool (tool.id)} (or use tool.name if id is not available), ensuring
Svelte can track items correctly and satisfy svelte/require-each-key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 196-231: The mobile tools loop lacks a key and the icon-only
<button> is missing accessibility attributes; update the {`#each` tools as tool,
i} block to include a stable key (e.g., {`#each` tools as tool, i (tool.id ??
tool.name)}) and make the button expose an accessible name and pressed state by
adding aria-label={tool.name} and aria-pressed={activeMobileIndex === i}; keep
existing click handler (handleMobileTap) and visual active logic using
activeMobileIndex unchanged so assistive tech can read the label and current
selection.
- Line 3: Remove the unused import of Icon in ai.svelte: locate the line
importing Icon (import Icon from '$lib/components/ui/icon/icon.svelte';) and
delete it so the module no longer imports Icon that isn't referenced, which will
resolve the linter failure.
- Around line 157-172: Tooltip.Trigger is currently icon-only and lacks an
accessible name; update the Tooltip.Trigger in the ai.svelte component to expose
a descriptive label for screen readers by either adding an aria-label attribute
(e.g., aria-label={tool.name || tool.label}) to the Tooltip.Trigger element or
by including a visually-hidden text node (e.g., a span with an sr-only class
using tool.name) inside the trigger. Ensure the label uses the existing tool
identifier (tool.name/tool.label) so each icon has a unique, meaningful
accessible name and that the Noise component and mask styling remain unchanged.
- Around line 151-188: The each-block iterating over tools is unkeyed (the
{`#each` tools as tool, i} block), causing unstable DOM updates; add a stable key
expression to the loop such as a unique property on each tool (e.g., tool.id or
tool.name) so it becomes {`#each` tools as tool (tool.id)} (or use tool.name if id
is not available), ensuring Svelte can track items correctly and satisfy
svelte/require-each-key.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b5b5da and b373997.

📒 Files selected for processing (1)
  • src/routes/(marketing)/(components)/ai.svelte

@HarshMN2345 HarshMN2345 self-requested a review March 9, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants