Skip to content

Enhancement from Dev2Auto - #12

Draft
RootDeveloperDS wants to merge 32 commits into
mainfrom
Dev2Auto
Draft

Enhancement from Dev2Auto#12
RootDeveloperDS wants to merge 32 commits into
mainfrom
Dev2Auto

Conversation

@RootDeveloperDS

@RootDeveloperDS RootDeveloperDS commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Core Objective

Improve portfolio accessibility, interaction feedback, runtime performance, and initial loading.

  • Add keyboard focus styles and descriptive ARIA labels to navigation, links, buttons, and project controls.
  • Add hover and pressed-state feedback to interactive elements.
  • Lazy-load non-overview tabs with React.lazy and Suspense.
  • Optimize canvas rendering, pointer updates, and event listeners.
  • Memoize reusable components and callbacks.
  • Add repository review and contribution guidance.

Architectural Impact

  • AnimatedBackground uses React.memo, offscreen canvas rendering, batched particle paths, cached device-pixel-ratio values, and passive listeners.
  • HeroAvatar caches layout measurements and batches pointer updates with requestAnimationFrame.
  • Index lazy-loads ProjectsTab, ExperienceTab, and TerminalTab, and memoizes navigation handlers.
  • AnimatedBackground, Footer, TopNav, ProjectsTab, ExperienceTab, and VisarAgentButton use React.memo.
  • Module-scope constants reduce repeated allocation for social and contact data.
  • Vite separates vendor and Framer Motion dependencies into manual chunks.
  • Portfolio controls now provide clearer keyboard and screen-reader behavior.

Removal Breakdown

  • The obsolete Vite allowedHosts comment was removed because it had no runtime effect.
  • The @tanstack/query-core Vite deduplication entry was removed because the current dependency setup does not require it.
  • No files were deleted.
  • Analytics now use the active name and tagline fields instead of removed title and subtitle fields.

Potential Breakages

  • Lazy-loaded tabs can show loading or deployment errors if their chunks fail to load.
  • Canvas and animation changes require validation during resize, scrolling, high-DPI rendering, and reduced-motion use.
  • Updated analytics fields require validation across all analytics consumers.
  • Memoized component exports can affect consumers that rely on component identity or metadata.
  • Accessibility changes require keyboard and screen-reader verification for all portfolio controls.
  • Manual chunking can affect dependency loading and cache behavior.

RootDeveloperDS and others added 21 commits August 3, 2026 01:38
Added standard focus-visible styles to key interactive elements (TopNav, ThemeToggle, and VisarAgentButton) to improve keyboard navigation and accessibility.
…11809011763327

⚡ Bolt: Canvas batch rendering optimization for AnimatedBackground
…129047635301157378

⚡ Bolt: Lazy load non-default tabs for faster initial load
Added standard focus-visible styles to key interactive elements (TopNav, ThemeToggle, and VisarAgentButton) to improve keyboard navigation and accessibility.
Fix build error regarding @tanstack/query-core dedupe in vite.config.ts
…lity-7986750439426607560

🎨 Palette: Enhance keyboard accessibility with focus rings
- Debounce getBoundingClientRect in HeroAvatar
- Configure manualChunks for Vite
Adds descriptive ARIA labels to project links (GitHub, Live Demo) across different views and adds standard structural ARIA attributes to the Accordion component (`aria-controls`, `aria-labelledby`, `role="region"`, `aria-expanded`). Also fixes incorrect telemetry property mappings (`title` -> `name`, `subtitle` -> `tagline`).
…ions-1710075515296347115

⚡ Bolt: [performance improvement] Debounce layout reads and optimize chunking
…012584936826662474

🎨 Palette: Improve accessibility of project links and accordion
Pre-render the cursor's radial gradient glow to an off-screen canvas and use `drawImage()` instead of recreating `createRadialGradient()` and executing a full-screen `fillRect()` on every frame.
- Improved ARIA label on the Command Palette button in TopNav to include keyboard shortcuts for better screen reader accessibility.
- Added `focus-within` styles to the flagship project bento-cards in ProjectsTab to highlight the entire card when a child element receives keyboard focus.
…594670425571579069

🎨 Palette: Improve accessibility and keyboard navigation
⚡ Bolt: Optimize Canvas Background Rendering
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devanshsharma-portfolio Ready Ready Preview Aug 10, 2026 3:01pm

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

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

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "path_filters"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b938a6f0-1f05-4466-9ce7-bf7ffc9ad0d0

📥 Commits

Reviewing files that changed from the base of the PR and between 0b843a3 and 233fcbc.

📒 Files selected for processing (2)
  • src/components/portfolio/ExperienceTab.tsx
  • src/components/portfolio/ProjectsTab.tsx

📝 Walkthrough

Walkthrough

The portfolio adds accessibility states and labels, visible keyboard focus styles, optimized canvas and pointer rendering, memoized components and data, lazy-loaded tabs, Vite manual chunks, and repository review guidance.

Changes

Portfolio accessibility and keyboard interaction

Layer / File(s) Summary
Project controls and links
src/components/portfolio/AccordionMatrix.tsx, src/components/portfolio/ProjectsTab.tsx
Accordion controls expose linked IDs and expanded panels expose region semantics. Filters expose pressed state. Project links use descriptive labels and focus styles.
Navigation and contact controls
src/components/portfolio/Footer.tsx, src/components/portfolio/OverviewTab.tsx, src/components/portfolio/TerminalTab.tsx, src/components/portfolio/TopNav.tsx, src/components/portfolio/ThemeToggle.tsx, src/components/portfolio/VisarAgentButton.tsx
Links and controls expose accessible labels and visible keyboard focus styles.

Rendering and component reuse

Layer / File(s) Summary
Animation and pointer updates
src/components/portfolio/AnimatedBackground.tsx, src/components/portfolio/HeroAvatar.tsx
The background caches the cursor glow and batches particle drawing. Hero avatar updates use cached layout data and cancellable animation frames.
Memoized components and stable data
src/components/portfolio/Footer.tsx, src/components/portfolio/OverviewTab.tsx, src/components/portfolio/TerminalTab.tsx, src/components/portfolio/TopNav.tsx, src/components/portfolio/VisarAgentButton.tsx, src/components/portfolio/ExperienceTab.tsx
Components are memoized where applicable. Static lookup data and derived collections move outside render functions.

Lazy tab loading and bundle chunks

Layer / File(s) Summary
Deferred tab rendering and Vite output configuration
src/pages/Index.tsx, vite.config.ts
Projects, Experience, and Terminal load through React.lazy inside Suspense. Vite separates vendor and animation dependencies into manual chunks.

Review and repository guidance

Layer / File(s) Summary
Review configuration and contribution guidance
.coderabbit.yaml, AGENTS.md, .Jules/palette.md
Review settings define summary and file-filter behavior. Repository guidance and palette documentation define pull request sections, verification details, accessibility guidance, and temporary-artifact restrictions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Index
  participant ReactSuspense
  participant LazyTab
  Index->>ReactSuspense: Render selected tab with loading fallback
  ReactSuspense->>LazyTab: Load deferred tab module
  LazyTab-->>ReactSuspense: Provide tab component
  ReactSuspense-->>Index: Render loaded tab
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title indicates an enhancement but does not identify the accessibility, performance, or loading changes in the pull request. Replace the title with a concise summary, such as "Improve portfolio accessibility and performance".
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Dev2Auto

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

@RootDeveloperDS

Copy link
Copy Markdown
Owner Author

here its perfect , and can be succesfully merged , anytime.

RootDeveloperDS and others added 3 commits August 6, 2026 02:14
This commit improves the accessibility of the VISAR Portfolio by dynamically injecting `aria-label`s for screen readers on links within the social matrix in `Footer.tsx` and the communication channels in `TerminalTab.tsx`.
…48335348121691503

🎨 Palette: Add ARIA labels to social matrix and terminal channels

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@src/components/portfolio/AccordionMatrix.tsx`:
- Around line 116-120: Update the accordion button’s aria-controls handling in
the project mapping that uses toggle(project.id), and the corresponding second
accordion instance, so it never references an unmounted panel. Either keep each
panel-${project.id} element mounted while collapsed and make it non-interactive,
or conditionally provide aria-controls only when isOpen is true.

In `@src/pages/Index.tsx`:
- Line 50: Add role="status" and aria-live="polite" to the Suspense fallback div
in the Index component, preserving its existing styling and loading text so
screen readers announce lazy-tab loading updates.
- Around line 50-55: Wrap the existing Suspense block in an ErrorBoundary so
rejected lazy imports in the tab components do not unmount the route. Implement
a fallback that displays the failure state and provides a retry action, reusing
the route/tab context in Index.tsx and preserving the current Suspense loading
fallback.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: f99065fe-279e-4a21-9a20-ba4505812832

📥 Commits

Reviewing files that changed from the base of the PR and between f4c4c31 and 7ea0c55.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • src/components/portfolio/AccordionMatrix.tsx
  • src/components/portfolio/AnimatedBackground.tsx
  • src/components/portfolio/Footer.tsx
  • src/components/portfolio/HeroAvatar.tsx
  • src/components/portfolio/ProjectsTab.tsx
  • src/components/portfolio/TerminalTab.tsx
  • src/components/portfolio/ThemeToggle.tsx
  • src/components/portfolio/TopNav.tsx
  • src/components/portfolio/VisarAgentButton.tsx
  • src/pages/Index.tsx
  • vite.config.ts

Comment on lines +116 to +120
id={`accordion-${project.id}`}
onClick={() => toggle(project.id)}
className="w-full text-left group"
aria-expanded={isOpen}
aria-controls={`panel-${project.id}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the aria-controls target mounted or remove the dangling reference.

When isOpen is false, the panel-${project.id} element is not rendered because the panel is inside {isOpen && (...)}. The collapsed button therefore references an element that does not exist, which can prevent assistive technology from resolving the controlled region.

Keep the panel mounted while collapsed and remove it from interaction, or set aria-controls only when the panel exists.

Minimal fix
-                  aria-controls={`panel-${project.id}`}
+                  aria-controls={isOpen ? `panel-${project.id}` : undefined}

Also applies to: 165-167

🤖 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 `@src/components/portfolio/AccordionMatrix.tsx` around lines 116 - 120, Update
the accordion button’s aria-controls handling in the project mapping that uses
toggle(project.id), and the corresponding second accordion instance, so it never
references an unmounted panel. Either keep each panel-${project.id} element
mounted while collapsed and make it non-interactive, or conditionally provide
aria-controls only when isOpen is true.

Comment thread src/pages/Index.tsx
{active === "projects" && <ProjectsTab />}
{active === "experience" && <ExperienceTab />}
{active === "terminal" && <TerminalTab />}
<Suspense fallback={<div className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Expose the loading state as a live status.

The fallback is a plain div, so a screen reader may not announce it when a lazy tab suspends. Add role="status" and aria-live="polite".

Proposed fix
-<Suspense fallback={<div className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>
+<Suspense fallback={<div role="status" aria-live="polite" className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>
📝 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
<Suspense fallback={<div className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>
<Suspense fallback={<div role="status" aria-live="polite" className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>
🤖 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 `@src/pages/Index.tsx` at line 50, Add role="status" and aria-live="polite" to
the Suspense fallback div in the Index component, preserving its existing
styling and loading text so screen readers announce lazy-tab loading updates.

Comment thread src/pages/Index.tsx
Comment on lines +50 to +55
<Suspense fallback={<div className="h-[50vh] flex items-center justify-center font-mono text-sm text-primary animate-pulse">loading payload...</div>}>
{active === "overview" && <OverviewTab onNavigate={handleNavigate} />}
{active === "projects" && <ProjectsTab />}
{active === "experience" && <ExperienceTab />}
{active === "terminal" && <TerminalTab />}
</Suspense>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -u

rg -n -C 6 'ErrorBoundary|componentDidCatch|getDerivedStateFromError' src || true
rg -n -C 6 'PortfolioShell|<Index' src || true

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 2240


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- src/pages/Index.tsx ---'
cat -n src/pages/Index.tsx
printf '%s\n' '--- src/App.tsx ---'
cat -n src/App.tsx
printf '%s\n' '--- boundary-related files and references ---'
git ls-files | rg -i '(^|/)(error(boundary)?|boundary|fallback)|ErrorBoundary|componentDidCatch|getDerivedStateFromError' || true
rg -n -C 3 'ErrorBoundary|componentDidCatch|getDerivedStateFromError|lazy\(' . \
  -g '!node_modules' -g '!dist' -g '!build' || true

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 5865


Add an error boundary for lazy tab failures.

No ErrorBoundary wraps PortfolioShell or the route. A rejected lazy import can unmount the route. Add an ErrorBoundary around this Suspense boundary with a retry action.

🤖 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 `@src/pages/Index.tsx` around lines 50 - 55, Wrap the existing Suspense block
in an ErrorBoundary so rejected lazy imports in the tab components do not
unmount the route. Implement a fallback that displays the failure state and
provides a retry action, reusing the route/tab context in Index.tsx and
preserving the current Suspense loading fallback.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 (1)
src/components/portfolio/Footer.tsx (1)

347-347: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a label that matches the link action.

src/components/portfolio/data.ts defines the Email item with a mailto: destination, but this code exposes Visit Email to assistive technology. Use an action label for mailto: links and keep Visit ... for web destinations.

Proposed fix
-                        aria-label={`Visit ${item.name}`}
+                        aria-label={
+                          item.href.startsWith("mailto:")
+                            ? "Contact via Email"
+                            : `Visit ${item.name}`
+                        }
🤖 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 `@src/components/portfolio/Footer.tsx` at line 347, Update the aria-label in
the footer link rendering around item.name to use an email-specific action label
for mailto destinations, while preserving “Visit …” for web URLs. Reuse the
existing item destination field and keep the label derived from item.name.
🤖 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 `@src/components/portfolio/AccordionMatrix.tsx`:
- Line 47: Update the category filtering expression in AccordionMatrix to
compare the URL-derived activeCategory value against each project category
without using the explicit any cast. Preserve the existing filtering behavior
while satisfying ESLint and retaining type-safe comparison.

---

Outside diff comments:
In `@src/components/portfolio/Footer.tsx`:
- Line 347: Update the aria-label in the footer link rendering around item.name
to use an email-specific action label for mailto destinations, while preserving
“Visit …” for web URLs. Reuse the existing item destination field and keep the
label derived from item.name.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 328c7b85-9e63-43ab-b5af-fd0e2ab06928

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea0c55 and 01da8bd.

📒 Files selected for processing (2)
  • src/components/portfolio/AccordionMatrix.tsx
  • src/components/portfolio/Footer.tsx

const filtered = useMemo(() => {
return activeCategory === "all"
? projects
: projects.filter((p) => p.categories.includes(activeCategory as any));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the explicit any cast from the category filter.

ESLint reports Line 47 as an error. Compare the URL value with each category instead of suppressing type checking with any.

Proposed fix
-      : projects.filter((p) => p.categories.includes(activeCategory as any));
+      : projects.filter((p) =>
+          p.categories.some((category) => category === activeCategory)
+        );
📝 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
: projects.filter((p) => p.categories.includes(activeCategory as any));
: projects.filter((p) =>
p.categories.some((category) => category === activeCategory)
);
🧰 Tools
🪛 ESLint

[error] 47-47: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🤖 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 `@src/components/portfolio/AccordionMatrix.tsx` at line 47, Update the category
filtering expression in AccordionMatrix to compare the URL-derived
activeCategory value against each project category without using the explicit
any cast. Preserve the existing filtering behavior while satisfying ESLint and
retaining type-safe comparison.

Source: Linters/SAST tools

…ity enhancements

- Add React.memo to TopNav, Footer, AnimatedBackground, and VisarAgentButton
- Add passive listeners and devicePixelRatio caching in canvas render loop
- Prevent layout thrashing in HeroAvatar by caching getBoundingClientRect
- Lift static arrays outside render scope in TerminalTab and OverviewTab
- Add focus-visible ring styles across interactive elements and styled empty matrix state

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/pages/Index.tsx (2)

57-62: ⚠️ Potential issue | 🟡 Minor

Expose lazy-tab loading to assistive technology.

The Suspense fallback remains a plain div. Screen readers may not announce it as a status. Add role="status" and aria-live="polite" while preserving the existing styling and text.

🤖 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 `@src/pages/Index.tsx` around lines 57 - 62, Update the Suspense fallback div
in the tab-rendering block to include role="status" and aria-live="polite",
preserving its existing styling and loading text.

57-62: ⚠️ Potential issue | 🟠 Major

Keep lazy-tab failures inside a recoverable boundary.

Confirm that a route-level ErrorBoundary wraps PortfolioShell. If no such boundary exists, a rejected ProjectsTab, ExperienceTab, or TerminalTab import is not handled by Suspense. Add an error boundary with a retry action around this block.

🤖 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 `@src/pages/Index.tsx` around lines 57 - 62, Verify that PortfolioShell is
wrapped by a route-level ErrorBoundary; if not, add a recoverable error boundary
around the Suspense block containing OverviewTab, ProjectsTab, ExperienceTab,
and TerminalTab. Handle rejected lazy imports by displaying an error state with
a retry action that resets the boundary and retries rendering.
🤖 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 @.coderabbit.yaml:
- Around line 15-18: Move the path_filters configuration under the reviews
section in the CodeRabbit configuration, preserving the existing patch, log, and
tmp exclusion patterns. Do not leave a duplicate root-level path_filters key;
add validation only if enforcing artifact rejection is required.

In `@AGENTS.md`:
- Around line 12-13: Restart the ordered list after the table by renumbering the
entries currently labeled 3 and 4 to 1 and 2, preserving their existing text and
satisfying Markdownlint MD029.

In `@src/components/portfolio/AccordionMatrix.tsx`:
- Around line 275-289: Add role="status" to the empty-state motion.div in
AccordionMatrix so screen readers announce the no-results message when filters
return no projects.

In `@src/components/portfolio/HeroAvatar.tsx`:
- Around line 21-35: Update the onMove animation-frame callback in HeroAvatar to
refresh rect with el.getBoundingClientRect() before calculating cx, cy, mx, and
my, so parent scale and avatar rotation transforms are reflected during
movement.

In `@src/pages/Index.tsx`:
- Around line 28-35: Update handleNavigate to read the current active tab from a
ref for the notification payload, keeping that ref synchronized with active,
then remove active from the useCallback dependency array while retaining
setSearchParams and the existing navigation behavior.

---

Duplicate comments:
In `@src/pages/Index.tsx`:
- Around line 57-62: Update the Suspense fallback div in the tab-rendering block
to include role="status" and aria-live="polite", preserving its existing styling
and loading text.
- Around line 57-62: Verify that PortfolioShell is wrapped by a route-level
ErrorBoundary; if not, add a recoverable error boundary around the Suspense
block containing OverviewTab, ProjectsTab, ExperienceTab, and TerminalTab.
Handle rejected lazy imports by displaying an error state with a retry action
that resets the boundary and retries rendering.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1020abdb-6669-44b5-9868-cfdb6e34aa93

📥 Commits

Reviewing files that changed from the base of the PR and between 01da8bd and 41cb0e8.

📒 Files selected for processing (12)
  • .coderabbit.yaml
  • AGENTS.md
  • src/components/portfolio/AccordionMatrix.tsx
  • src/components/portfolio/AnimatedBackground.tsx
  • src/components/portfolio/Footer.tsx
  • src/components/portfolio/HeroAvatar.tsx
  • src/components/portfolio/OverviewTab.tsx
  • src/components/portfolio/ProjectsTab.tsx
  • src/components/portfolio/TerminalTab.tsx
  • src/components/portfolio/TopNav.tsx
  • src/components/portfolio/VisarAgentButton.tsx
  • src/pages/Index.tsx

Comment thread .coderabbit.yaml
Comment on lines +15 to +18
path_filters:
- "!**/*.patch"
- "!**/*.log"
- "!**/*.tmp"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

! grep -nE '^path_filters:' .coderabbit.yaml
grep -nE '^  path_filters:' .coderabbit.yaml

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 187


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- .coderabbit.yaml ---'
sed -n '1,35p' .coderabbit.yaml

printf '%s\n' '--- references to path_filters and reviews ---'
rg -n -C 3 'path_filters|^reviews:' . --glob '!node_modules' --glob '!dist' --glob '!build'

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 946


🌐 Web query:

CodeRabbit configuration path_filters reviews.path_filters official documentation

💡 Result:

In CodeRabbit, the reviews.path_filters setting is a configuration option used to control which files are included in or excluded from AI reviews [1][2]. It is defined within the.coderabbit.yaml configuration file [2][3]. Key features and usage include: Configuration Structure You can define path_filters under the reviews section of your configuration file [1][2]: reviews: path_filters: - "!dist/" - "!node_modules/" - "src/" Pattern Syntax Path filters use standard glob patterns [4][2]. - Exclusion: Patterns prefixed with "!" are excluded from the review (e.g.,!dist/) [1][5]. - Inclusion: Patterns without the "!" prefix are explicitly included (e.g., src/) [1][2]. - Default Behavior: By default, CodeRabbit automatically skips common non-code files such as lock files, binaries, build artifacts, and generated code [1][6]. These filters allow you to override those defaults or further refine the scope [1]. Functional Impact - Scope Control: These filters define the scope of the review [1]. Files excluded here do not appear in CodeRabbit review surfaces, such as the walkthrough or Change Stack [1]. - Performance: Keeping reviews focused by excluding irrelevant files like large generated files or dependencies helps maintain review speed and quality [1][2]. - Git Integration: These patterns also apply to git sparse-checkout when cloning the repository [4]. Changes to the path_filters configuration take effect on the next pull request without requiring a restart or reinstallation [2].

Citations:


Move path_filters under reviews.

CodeRabbit documents path_filters as reviews.path_filters. The current root-level key may be ignored. Add CI or pre-commit validation if these artifacts must be rejected automatically.

🤖 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 @.coderabbit.yaml around lines 15 - 18, Move the path_filters configuration
under the reviews section in the CodeRabbit configuration, preserving the
existing patch, log, and tmp exclusion patterns. Do not leave a duplicate
root-level path_filters key; add validation only if enforcing artifact rejection
is required.

Comment thread AGENTS.md
Comment on lines +12 to +13
3. **Verification**: State tests run or how you verified this won't break existing IPC/UI threads.
4. **Clean Artifacts**: NEVER commit `.patch`, `.log`, or `.tmp` files.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restart the ordered list after the table.

The table at Lines 8-10 ends the first ordered list. Markdownlint reports MD029 because Lines 12-13 start a new list with 3. and 4.. Use 1. and 2. for this second list.

Proposed fix
-3. **Verification**: State tests run or how you verified this won't break existing IPC/UI threads.
-4. **Clean Artifacts**: NEVER commit `.patch`, `.log`, or `.tmp` files.
+1. **Verification**: State tests run or how you verified this won't break existing IPC/UI threads.
+2. **Clean Artifacts**: NEVER commit `.patch`, `.log`, or `.tmp` files.
📝 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
3. **Verification**: State tests run or how you verified this won't break existing IPC/UI threads.
4. **Clean Artifacts**: NEVER commit `.patch`, `.log`, or `.tmp` files.
1. **Verification**: State tests run or how you verified this won't break existing IPC/UI threads.
2. **Clean Artifacts**: NEVER commit `.patch`, `.log`, or `.tmp` files.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 12-12: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/2/3

(MD029, ol-prefix)


[warning] 13-13: Ordered list item prefix
Expected: 2; Actual: 4; Style: 1/2/3

(MD029, ol-prefix)

🤖 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 `@AGENTS.md` around lines 12 - 13, Restart the ordered list after the table by
renumbering the entries currently labeled 3 and 4 to 1 and 2, preserving their
existing text and satisfying Markdownlint MD029.

Source: Linters/SAST tools

Comment on lines +275 to +289
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="flex flex-col items-center justify-center py-16 px-6 text-center border-t border-border"
>
<div className="mb-4 rounded-full bg-primary/10 p-3 border border-primary/20">
<Database className="h-6 w-6 text-primary/70" />
</div>
<p className="font-mono text-sm text-primary mb-2 uppercase tracking-wider">
[ NO SYSTEMS DETECTED ]
</p>
<p className="text-xs text-muted-foreground max-w-[250px] mx-auto">
The selected filter parameters returned no active records in the current matrix.
</p>
</motion.div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Announce the empty result state.

When a filter returns no projects, a screen-reader user can remain on the filter button without hearing the new message. Add role="status" to the empty-state container.

Proposed fix
           <motion.div
+            role="status"
             initial={{ opacity: 0, scale: 0.95 }}
📝 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
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="flex flex-col items-center justify-center py-16 px-6 text-center border-t border-border"
>
<div className="mb-4 rounded-full bg-primary/10 p-3 border border-primary/20">
<Database className="h-6 w-6 text-primary/70" />
</div>
<p className="font-mono text-sm text-primary mb-2 uppercase tracking-wider">
[ NO SYSTEMS DETECTED ]
</p>
<p className="text-xs text-muted-foreground max-w-[250px] mx-auto">
The selected filter parameters returned no active records in the current matrix.
</p>
</motion.div>
<motion.div
role="status"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="flex flex-col items-center justify-center py-16 px-6 text-center border-t border-border"
>
<div className="mb-4 rounded-full bg-primary/10 p-3 border border-primary/20">
<Database className="h-6 w-6 text-primary/70" />
</div>
<p className="font-mono text-sm text-primary mb-2 uppercase tracking-wider">
[ NO SYSTEMS DETECTED ]
</p>
<p className="text-xs text-muted-foreground max-w-[250px] mx-auto">
The selected filter parameters returned no active records in the current matrix.
</p>
</motion.div>
🤖 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 `@src/components/portfolio/AccordionMatrix.tsx` around lines 275 - 289, Add
role="status" to the empty-state motion.div in AccordionMatrix so screen readers
announce the no-results message when filters return no projects.

Comment on lines +21 to +35
let rect = el.getBoundingClientRect();
const updateRect = () => {
rect = el.getBoundingClientRect();
};

let rafId: number | undefined;
const onMove = (e: MouseEvent) => {
const rect = el.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
mx.set(((e.clientX - cx) / rect.width) * 100);
my.set(((e.clientY - cy) / rect.height) * 100);
// ⚡ Bolt: Cache getBoundingClientRect to avoid layout thrashing on every mouse move
if (rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(() => {
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
mx.set(((e.clientX - cx) / rect.width) * 100);
my.set(((e.clientY - cy) / rect.height) * 100);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- HeroAvatar.tsx ---'
sed -n '1,220p' src/components/portfolio/HeroAvatar.tsx
printf '%s\n' '--- OverviewTab.tsx references ---'
rg -n -C 8 'HeroAvatar|scale|rotateX|rotateY|getBoundingClientRect|ResizeObserver|scroll' src/components/portfolio/OverviewTab.tsx src/components/portfolio

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 34400


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
import math

def rotated_aabb(width, height, angle_deg, scale=1):
    a = math.radians(angle_deg)
    # A rectangle transformed around its center. The center stays fixed;
    # the axis-aligned bounding-box dimensions change.
    w = scale * (abs(width * math.cos(a)) + abs(height * math.sin(a)))
    h = scale * (abs(width * math.sin(a)) + abs(height * math.cos(a)))
    return w, h

base = rotated_aabb(320, 320, 0, 0.9)
entry_done = rotated_aabb(320, 320, 0, 1)
rotated = rotated_aabb(320, 320, 8, 1)

print("cached during parent entry:", base)
print("after parent entry:", entry_done)
print("after rotateY/rotateX:", rotated)
print("center shift for center-origin transforms:", (0, 0))
PY

Repository: RootDeveloperDS/devanshsharmadev

Length of output: 362


Refresh the cached rectangle after transforms change.

The cached rectangle becomes stale during the parent scale animation and avatar rotation. getBoundingClientRect() includes these transforms, so its width and height change without a resize or scroll event. Measure the rectangle inside the coalesced animation frame, or measure an untransformed element.

🤖 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 `@src/components/portfolio/HeroAvatar.tsx` around lines 21 - 35, Update the
onMove animation-frame callback in HeroAvatar to refresh rect with
el.getBoundingClientRect() before calculating cx, cy, mx, and my, so parent
scale and avatar rotation transforms are reflected during movement.

Comment thread src/pages/Index.tsx
Comment on lines +28 to +35
// ⚡ Bolt: Memoize navigation handler so it has a stable reference across renders
const handleNavigate = useCallback((id: TabId) => {
if (id !== active) {
sendTelegramNotification("Navigated Tab", { from: active, to: id });
}
setSearchParams({ tab: id });
window.scrollTo({ top: 0, behavior: "smooth" });
};
}, [active, setSearchParams]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Keep handleNavigate stable for memoized children.

active changes on every tab switch, so the dependency array creates a new callback on every navigation. Footer is memoized in src/components/portfolio/Footer.tsx Line 81 but receives this callback at Line 67. The callback identity therefore defeats that memoization and re-renders the large footer on each tab switch.

Store the current tab in a ref for telemetry, then remove active from the dependency array.

Proposed refactor
-import { Suspense, lazy, useCallback, useEffect, useState } from "react";
+import { Suspense, lazy, useCallback, useEffect, useRef, useState } from "react";

   const active = (searchParams.get("tab") as TabId) || "overview";
+  const activeRef = useRef(active);
+  activeRef.current = active;

   const handleNavigate = useCallback((id: TabId) => {
-    if (id !== active) {
-      sendTelegramNotification("Navigated Tab", { from: active, to: id });
+    const from = activeRef.current;
+    if (id !== from) {
+      sendTelegramNotification("Navigated Tab", { from, to: id });
     }
...
-  }, [active, setSearchParams]);
+  }, [setSearchParams]);

Also applies to: 45-45

🤖 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 `@src/pages/Index.tsx` around lines 28 - 35, Update handleNavigate to read the
current active tab from a ref for the notification payload, keeping that ref
synchronized with active, then remove active from the useCallback dependency
array while retaining setSearchParams and the existing navigation behavior.

RootDeveloperDS and others added 3 commits August 10, 2026 02:25
- Added `aria-label` to the main `<nav>` element in `TopNav.tsx` for better screen reader support.
- Added `focus-visible` utility classes to the terminal contact links and copy button in `TerminalTab.tsx` to ensure clear keyboard navigation visibility.
- Added a subtle scale animation on hover (`group-hover:scale-110 transition-transform`) to the contact icons in `TerminalTab.tsx` for enhanced premium interaction feedback.
- Wraps ExperienceTab in React.memo()
- Wraps ProjectsTab in React.memo()
…ancements-12899734241171852656

🎨 Palette: Improve Accessibility and Interaction Feedback

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/portfolio/TopNav.tsx (1)

84-85: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a cross-platform shortcut hint.

CommandPalette.tsx handles both metaKey and ctrlKey, but TopNav.tsx renders only ⌘K. Render a platform-aware hint or Cmd/Ctrl+K to match the supported shortcut.

🤖 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 `@src/components/portfolio/TopNav.tsx` around lines 84 - 85, Update the
shortcut hint in the TopNav command-palette trigger, including its aria-label,
to represent both supported platforms using a platform-aware label or
“Cmd/Ctrl+K” instead of only “⌘K”. Keep the shortcut behavior handled by
CommandPalette unchanged.
🤖 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 @.Jules/palette.md:
- Around line 1-3: Update the first heading in the palette document to a
top-level Markdown heading, then add a blank line before the following content.
Preserve the existing heading text and content while ensuring the document
satisfies MD041 and MD022.

In `@src/components/portfolio/TerminalTab.tsx`:
- Line 273: Update the link accessible name around the aria-label in TerminalTab
so it includes both the connection label and destination value, or remove
aria-label if the visible text already provides both. Preserve the existing
connection action and ensure screen readers can identify the destination.
- Line 294: Update the channel rendering near the link and copy control so the
copy button is a sibling of the anchor rather than nested inside it. Preserve
the existing copy behavior and styling, while ensuring its click does not bubble
to the channel link or emit the link’s navigation analytics event.

---

Outside diff comments:
In `@src/components/portfolio/TopNav.tsx`:
- Around line 84-85: Update the shortcut hint in the TopNav command-palette
trigger, including its aria-label, to represent both supported platforms using a
platform-aware label or “Cmd/Ctrl+K” instead of only “⌘K”. Keep the shortcut
behavior handled by CommandPalette unchanged.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 302814b8-9e2f-40e7-8d19-70ab2fe9b2e8

📥 Commits

Reviewing files that changed from the base of the PR and between 41cb0e8 and 0b843a3.

📒 Files selected for processing (3)
  • .Jules/palette.md
  • src/components/portfolio/TerminalTab.tsx
  • src/components/portfolio/TopNav.tsx

Comment thread .Jules/palette.md
Comment on lines +1 to +3
## 2023-10-27 - A11y & Focus Enhancements
**Learning:** Adding `focus-visible` classes to interactive elements like custom buttons or links significantly improves keyboard accessibility without degrading the mouse/touch experience. Simple hover transitions (like a subtle scale) boost the premium feel.
**Action:** Always verify custom interactive components have clear focus rings (`focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ring-offset-background`). Ensure semantic tags like `<nav>` have `aria-label`s for screen readers.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the Markdown heading structure.

Change Line 1 to a top-level heading and add a blank line after it. This resolves markdownlint warnings MD041 and MD022.

Proposed fix
-## 2023-10-27 - A11y & Focus Enhancements
+# 2023-10-27 - A11y & Focus Enhancements
+
 **Learning:** Adding `focus-visible` classes to interactive elements like custom buttons or links significantly improves keyboard accessibility without degrading the mouse/touch experience. Simple hover transitions (like a subtle scale) boost the premium feel.
📝 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
## 2023-10-27 - A11y & Focus Enhancements
**Learning:** Adding `focus-visible` classes to interactive elements like custom buttons or links significantly improves keyboard accessibility without degrading the mouse/touch experience. Simple hover transitions (like a subtle scale) boost the premium feel.
**Action:** Always verify custom interactive components have clear focus rings (`focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ring-offset-background`). Ensure semantic tags like `<nav>` have `aria-label`s for screen readers.
# 2023-10-27 - A11y & Focus Enhancements
**Learning:** Adding `focus-visible` classes to interactive elements like custom buttons or links significantly improves keyboard accessibility without degrading the mouse/touch experience. Simple hover transitions (like a subtle scale) boost the premium feel.
**Action:** Always verify custom interactive components have clear focus rings (`focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ring-offset-background`). Ensure semantic tags like `<nav>` have `aria-label`s for screen readers.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 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 @.Jules/palette.md around lines 1 - 3, Update the first heading in the
palette document to a top-level Markdown heading, then add a blank line before
the following content. Preserve the existing heading text and content while
ensuring the document satisfies MD041 and MD022.

Source: Linters/SAST tools

href={href}
target={href.startsWith("http") ? "_blank" : undefined}
rel="noopener noreferrer"
aria-label={`Connect via ${label}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include the destination in the accessible name.

aria-label replaces the link's visible accessible name. Screen readers will hear only Connect via ${label} and not value. Remove the attribute if the visible text is sufficient, or include the value in the label.

🤖 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 `@src/components/portfolio/TerminalTab.tsx` at line 273, Update the link
accessible name around the aria-label in TerminalTab so it includes both the
connection label and destination value, or remove aria-label if the visible text
already provides both. Preserve the existing connection action and ensure screen
readers can identify the destination.

toast({ title: "Copied", description: value });
}}
className="shrink-0 text-muted-foreground transition-colors hover:text-primary"
className="shrink-0 text-muted-foreground transition-colors hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-sm"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Move the copy control outside the channel link.

The button at Line 287 is nested inside the anchor at Line 268. This creates two interactive controls in one accessible control. The click also bubbles to the anchor, so copying can emit Clicked Contact Channel (Terminal) even when navigation is prevented. Render the link and copy button as sibling controls.

🤖 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 `@src/components/portfolio/TerminalTab.tsx` at line 294, Update the channel
rendering near the link and copy control so the copy button is a sibling of the
anchor rather than nested inside it. Preserve the existing copy behavior and
styling, while ensuring its click does not bubble to the channel link or emit
the link’s navigation analytics event.

…747562232708588653

⚡ Bolt: Memoize Experience and Projects Tabs
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.

1 participant