Namefeature/typing animation#85
Conversation
Creates a dedicated /services/:slug route for each service with sections for what is included, ideal audience, 4-step process, highlights, FAQ accordion, and a quote CTA. Fixes react-router import errors, removes deprecated baseUrl from tsconfig, and adds ScrollToTop on route change. Closes hrx01-dev#73
Keep upstream splash screen, BrowserRouter, AuthProvider, and dashboard routes. Add our ScrollToTop (inside BrowserRouter) and /services/:slug route alongside the existing routes.
- Convert useTheme to a ThemeProvider context so Navbar and DashboardLayout share a single theme state instance - Fix FOUC: lazy useState initializer reads localStorage synchronously before first render instead of in useEffect - Wrap useCallback around toggleTheme to stabilise the reference - Add theme toggle button to DashboardLayout sidebar and mobile header - Remove per-component theme state/effect from Navbar
Signed-in users now see a Dashboard button in the Navbar (desktop and mobile) that routes directly to /dashboard. Replaces the bare welcome-text + Sign Out layout with Dashboard CTA + outlined Sign Out. Closes hrx01-dev#73
Required for branch protection — runs on PRs and pushes to main, analysing JavaScript/TypeScript with build-mode: none (no build step needed for static analysis of a Vite/React project).
App.tsx already owns the BrowserRouter. Adopt main branch safer null check (if root) instead of non-null assertion.
Introduces a reusable TypingText component that renders text character-by-character with a blinking cursor. Applied to the hero h1 (triggers on load after splash fades) and 5 section headings (Services, Process, Testimonials, Pricing, FAQ — each fires once when the heading enters the viewport via useInView). Respects prefers-reduced-motion: shows the full string instantly with no cursor when the user has reduced-motion enabled. Screen readers receive the complete text via aria-label at all times. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a reusable ChangesService Pages, TypingText Animation, and Theme
CodeQL CI and Minor Fixes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…s/Settings2 main added AI Estimate and Pricing Config nav items (Sparkles, Settings2). Our branch added the theme toggle (Moon, Sun). Keep all four imports and include both sets of NAV_ITEMS so neither feature is lost. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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 @.github/workflows/codeql.yml:
- Line 23: Replace all mutable version tags in the GitHub Actions workflow with
their corresponding full commit SHAs. Specifically, update the `uses` fields
that currently reference `actions/checkout@v4`, and any other action references
using `@v3` or `@v4` tags, by replacing the version tag with the full
40-character commit SHA for that action version. This ensures the workflow uses
immutable references and prevents supply-chain risks from tag modifications.
- Around line 22-23: The actions/checkout@v4 step in the checkout repository
task does not explicitly disable credential persistence, which allows the
GITHUB_TOKEN to remain in the Git configuration. Add the `persist-credentials:
false` parameter to the checkout step to ensure the token is not stored in the
Git configuration, reducing the risk of token exposure in artifacts or
subsequent steps.
In `@src/app/App.tsx`:
- Around line 36-39: The ScrollToTop component unconditionally scrolls to the
top whenever the pathname changes, which interferes with hash-based navigation
like /#services or /#contact. Update the useEffect hook in the ScrollToTop
function to check if a hash exists in the URL using location.hash. Only call
window.scrollTo(0, 0) when navigating to a new pathname that does not have a
hash fragment, allowing the browser to naturally scroll to hash-based anchor
elements before ScrollToTop takes effect. You may also need to update the
dependency array to include hash information if necessary.
In `@src/app/components/ServiceDetailPage.tsx`:
- Around line 21-25: The accordion button component is missing proper
accessibility linkage to its associated panel. Add an aria-controls attribute to
the button (with the onClick and aria-expanded attributes) that references a
unique id, then add that matching id to the answer panel element (lines 35-42).
Additionally, use aria-hidden on the answer panel to hide it from assistive
technology when the accordion is collapsed (when open is false), ensuring screen
readers cannot access the hidden content.
In `@src/app/components/TypingText.tsx`:
- Around line 82-93: The TypingText component currently displays text that grows
from empty to full length during the typing animation, which causes visible
layout reflow on smaller screens. To fix this, reserve the full text width from
the start by rendering the complete text invisibly as a reference while
displaying only the currently typed portion. Modify the span containing
displayed to either include the full text hidden behind it for width
reservation, or wrap the display logic to ensure the container maintains a
constant width equal to the final text width throughout the entire animation,
preventing layout shifts as more characters appear.
In `@src/app/hooks/useTheme.ts`:
- Around line 33-36: The useEffect hook in the theme persistence logic writes to
localStorage without error handling, which can throw in restricted storage
contexts and break the effect, while the getInitialTheme function already
implements defensive error handling for storage reads. Wrap the
localStorage.setItem call inside the useEffect (when isDarkMode changes) in a
try-catch block to safely handle any storage access errors and match the
existing error handling pattern already established in getInitialTheme.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c0dd1c1d-e5e8-4013-8e20-fdf697a4e6e1
📒 Files selected for processing (16)
.github/workflows/codeql.ymlsrc/app/App.tsxsrc/app/components/FAQ.tsxsrc/app/components/Hero.tsxsrc/app/components/Navbar.tsxsrc/app/components/Pricing.tsxsrc/app/components/Process.tsxsrc/app/components/ServiceDetailPage.tsxsrc/app/components/Services.tsxsrc/app/components/Testimonials.tsxsrc/app/components/TypingText.tsxsrc/app/data/servicesData.tssrc/app/hooks/useTheme.tssrc/dashboard/components/DashboardLayout.tsxsrc/main.tsxtsconfig.json
💤 Files with no reviewable changes (1)
- tsconfig.json
| - name: Checkout repository | ||
| uses: actions/checkout@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify checkout steps explicitly disable credential persistence
rg -nP 'uses:\s*actions/checkout@' .github/workflows -A4 -B1Repository: hrx01-dev/Servio
Length of output: 1496
🌐 Web query:
GitHub actions checkout persist-credentials false security best practice
💡 Result:
Setting persist-credentials: false is considered a security best practice for GitHub Actions workflows that do not require authenticated Git operations [1][2][3]. By default, the actions/checkout action is configured with persist-credentials: true [4][2]. This setting automatically persists the authentication token (typically GITHUB_TOKEN) into the local Git configuration of the checked-out repository [4][5][3]. This behavior was originally designed to allow subsequent steps in a workflow to perform authenticated Git operations, such as git fetch or git push, without additional configuration [4][6][7]. However, this practice introduces several security risks: - Credential Exposure in Artifacts: If a workflow archives or uploads the repository directory as an artifact, the persisted credentials stored in.git/config may be included and leaked [2][3]. - Unauthorized Access: Any subsequent step or third-party action executed within the same job can read these credentials from the Git configuration and potentially use them to perform unauthorized actions, such as pushing commits or accessing other repository data [5][2][3]. To mitigate these risks, you should explicitly set persist-credentials to false in your workflow definition whenever your job does not need to perform authenticated Git commands [1][2][3]: - uses: actions/checkout@v4 with: persist-credentials: false While modern versions of actions/checkout have improved security by storing credentials in a separate file under $RUNNER_TEMP rather than directly in.git/config [4][6][7], setting persist-credentials: false remains the recommended practice to adhere to the principle of least privilege and minimize the exposure of sensitive tokens [1][2]. If your workflow does require authenticated Git operations, ensure that your GITHUB_TOKEN permissions are scoped as strictly as possible [5].
Citations:
- 1: https://cheatsheetseries.owasp.org/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.html
- 2: https://actsense.dev/vulnerabilities/unsafe_checkout/
- 3: https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/
- 4: https://github.com/actions/checkout/?tab=readme-ov-file
- 5: Remove
persist-credentialsor change the default tofalseactions/checkout#485 - 6: https://github.com/actions/checkout
- 7: https://github.com/actions/checkout/blob/main/README.md
🏁 Script executed:
#!/bin/bash
# Check all workflow files for checkout usage and credential persistence settings
fd '\.yml$' .github/workflows/ | while read file; do
echo "=== $file ==="
grep -A 5 'actions/checkout' "$file" || true
doneRepository: hrx01-dev/Servio
Length of output: 892
Add persist-credentials: false to the checkout step.
The actions/checkout step should explicitly disable credential persistence to prevent the GITHUB_TOKEN from being stored in the Git configuration, reducing the risk of token exposure in artifacts or unauthorized access by subsequent steps.
Suggested hardening
- name: Checkout repository
uses: actions/checkout@v4
+ with:
+ persist-credentials: falseThis is a security best practice recommended by OWASP and aligns with the principle of least privilege.
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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 @.github/workflows/codeql.yml around lines 22 - 23, The actions/checkout@v4
step in the checkout repository task does not explicitly disable credential
persistence, which allows the GITHUB_TOKEN to remain in the Git configuration.
Add the `persist-credentials: false` parameter to the checkout step to ensure
the token is not stored in the Git configuration, reducing the risk of token
exposure in artifacts or subsequent steps.
Source: Linters/SAST tools
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify non-SHA action refs in workflows
rg -nP '^\s*uses:\s*[^@]+@v\d+' .github/workflowsRepository: hrx01-dev/Servio
Length of output: 977
Pin GitHub Actions to commit SHAs instead of mutable version tags.
Lines 23, 26, and 32 use mutable tags (@v4, @v3). This weakens CI supply-chain integrity and introduces risk if these tags are re-released or modified upstream.
Suggested fix
- - name: Checkout repository
- uses: actions/checkout@v4
+ - name: Checkout repository
+ uses: actions/checkout@<full_commit_sha>
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@<full_commit_sha>
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@<full_commit_sha>🧰 Tools
🪛 zizmor (1.25.2)
[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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 @.github/workflows/codeql.yml at line 23, Replace all mutable version tags in
the GitHub Actions workflow with their corresponding full commit SHAs.
Specifically, update the `uses` fields that currently reference
`actions/checkout@v4`, and any other action references using `@v3` or `@v4`
tags, by replacing the version tag with the full 40-character commit SHA for
that action version. This ensures the workflow uses immutable references and
prevents supply-chain risks from tag modifications.
Source: Linters/SAST tools
| function ScrollToTop() { | ||
| const { pathname } = useLocation(); | ||
| useEffect(() => { window.scrollTo(0, 0); }, [pathname]); | ||
| return null; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/app/App.tsx | head -50Repository: hrx01-dev/Servio
Length of output: 2754
🏁 Script executed:
rg "`#services`|`#quote`" --type jsx --type tsx --type js --type tsRepository: hrx01-dev/Servio
Length of output: 88
🏁 Script executed:
rg "useLocation|scrollIntoView" -A 3 -B 3Repository: hrx01-dev/Servio
Length of output: 4279
🏁 Script executed:
rg "href=\"#|navigate.*#" -A 2 -B 2Repository: hrx01-dev/Servio
Length of output: 3214
🏁 Script executed:
grep -r "scrollToSection\|href=\"#" src/ --include="*.tsx" --include="*.ts"Repository: hrx01-dev/Servio
Length of output: 2481
ScrollToTop may interfere with hash-based section navigation.
Line 38 calls window.scrollTo(0, 0) whenever pathname changes. This can conflict with hash-based navigation (e.g., /#services, /#contact, /#portfolio) by scrolling users to the top before the browser can scroll to the target element when navigating between pages.
Proposed fix
function ScrollToTop() {
- const { pathname } = useLocation();
- useEffect(() => { window.scrollTo(0, 0); }, [pathname]);
+ const { pathname, hash } = useLocation();
+ useEffect(() => {
+ if (hash) {
+ const id = hash.slice(1);
+ requestAnimationFrame(() => {
+ document.getElementById(id)?.scrollIntoView({ behavior: 'auto' });
+ });
+ return;
+ }
+ window.scrollTo(0, 0);
+ }, [pathname, hash]);
return null;
}📝 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.
| function ScrollToTop() { | |
| const { pathname } = useLocation(); | |
| useEffect(() => { window.scrollTo(0, 0); }, [pathname]); | |
| return null; | |
| function ScrollToTop() { | |
| const { pathname, hash } = useLocation(); | |
| useEffect(() => { | |
| if (hash) { | |
| const id = hash.slice(1); | |
| requestAnimationFrame(() => { | |
| document.getElementById(id)?.scrollIntoView({ behavior: 'auto' }); | |
| }); | |
| return; | |
| } | |
| window.scrollTo(0, 0); | |
| }, [pathname, hash]); | |
| return null; | |
| } |
🤖 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/app/App.tsx` around lines 36 - 39, The ScrollToTop component
unconditionally scrolls to the top whenever the pathname changes, which
interferes with hash-based navigation like /#services or /#contact. Update the
useEffect hook in the ScrollToTop function to check if a hash exists in the URL
using location.hash. Only call window.scrollTo(0, 0) when navigating to a new
pathname that does not have a hash fragment, allowing the browser to naturally
scroll to hash-based anchor elements before ScrollToTop takes effect. You may
also need to update the dependency array to include hash information if
necessary.
| <button | ||
| onClick={() => setOpen(!open)} | ||
| className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left" | ||
| aria-expanded={open} | ||
| > |
There was a problem hiding this comment.
Complete accordion a11y wiring for FAQ items.
Line 24 sets aria-expanded, but the control is not linked to a panel (aria-controls/id), and the collapsed answer at Line 37 is only visually hidden. Add explicit control-panel linkage and hide collapsed content from AT.
Proposed fix
function FAQItem({ question, answer, index }: { question: string; answer: string; index: number }) {
const [open, setOpen] = useState(false);
const reduce = useReducedMotion();
+ const panelId = `faq-panel-${index}`;
+ const buttonId = `faq-button-${index}`;
return (
@@
<button
onClick={() => setOpen(!open)}
className="w-full flex items-center justify-between gap-4 px-6 py-5 text-left"
aria-expanded={open}
+ aria-controls={panelId}
+ id={buttonId}
>
@@
<motion.div
+ id={panelId}
+ role="region"
+ aria-labelledby={buttonId}
+ aria-hidden={!open}
initial={false}
animate={{ height: open ? 'auto' : 0, opacity: open ? 1 : 0 }}
transition={{ duration: 0.3, ease: [0.21, 0.47, 0.32, 0.98] }}
className="overflow-hidden"
>Also applies to: 35-42
🤖 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/app/components/ServiceDetailPage.tsx` around lines 21 - 25, The accordion
button component is missing proper accessibility linkage to its associated
panel. Add an aria-controls attribute to the button (with the onClick and
aria-expanded attributes) that references a unique id, then add that matching id
to the answer panel element (lines 35-42). Additionally, use aria-hidden on the
answer panel to hide it from assistive technology when the accordion is
collapsed (when open is false), ensuring screen readers cannot access the hidden
content.
| return ( | ||
| <span ref={ref} aria-label={text}> | ||
| <span aria-hidden="true">{displayed}</span> | ||
| {showCursor && !done && ( | ||
| <span | ||
| aria-hidden="true" | ||
| className={`inline-block w-[2px] h-[0.85em] align-text-bottom ml-[1px] rounded-sm ${cursorColor} transition-opacity duration-75 ${ | ||
| blink ? 'opacity-100' : 'opacity-0' | ||
| }`} | ||
| /> | ||
| )} | ||
| </span> |
There was a problem hiding this comment.
Reserve text width to avoid heading reflow during typing.
The current render path grows content from '' to full text, which can cause visible layout shifts while typing on smaller breakpoints.
💡 Suggested fix
- return (
- <span ref={ref} aria-label={text}>
- <span aria-hidden="true">{displayed}</span>
- {showCursor && !done && (
- <span
- aria-hidden="true"
- className={`inline-block w-[2px] h-[0.85em] align-text-bottom ml-[1px] rounded-sm ${cursorColor} transition-opacity duration-75 ${
- blink ? 'opacity-100' : 'opacity-0'
- }`}
- />
- )}
- </span>
- );
+ return (
+ <span ref={ref} aria-label={text} className="relative inline-block">
+ {/* Reserve final width/height to prevent reflow */}
+ <span aria-hidden="true" className="invisible">
+ {text}
+ </span>
+ <span aria-hidden="true" className="absolute inset-0 whitespace-nowrap">
+ {displayed}
+ {showCursor && !done && (
+ <span
+ className={`inline-block w-[2px] h-[0.85em] align-text-bottom ml-[1px] rounded-sm ${cursorColor} transition-opacity duration-75 ${
+ blink ? 'opacity-100' : 'opacity-0'
+ }`}
+ />
+ )}
+ </span>
+ </span>
+ );📝 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.
| return ( | |
| <span ref={ref} aria-label={text}> | |
| <span aria-hidden="true">{displayed}</span> | |
| {showCursor && !done && ( | |
| <span | |
| aria-hidden="true" | |
| className={`inline-block w-[2px] h-[0.85em] align-text-bottom ml-[1px] rounded-sm ${cursorColor} transition-opacity duration-75 ${ | |
| blink ? 'opacity-100' : 'opacity-0' | |
| }`} | |
| /> | |
| )} | |
| </span> | |
| return ( | |
| <span ref={ref} aria-label={text} className="relative inline-block"> | |
| {/* Reserve final width/height to prevent reflow */} | |
| <span aria-hidden="true" className="invisible"> | |
| {text} | |
| </span> | |
| <span aria-hidden="true" className="absolute inset-0 whitespace-nowrap"> | |
| {displayed} | |
| {showCursor && !done && ( | |
| <span | |
| className={`inline-block w-[2px] h-[0.85em] align-text-bottom ml-[1px] rounded-sm ${cursorColor} transition-opacity duration-75 ${ | |
| blink ? 'opacity-100' : 'opacity-0' | |
| }`} | |
| /> | |
| )} | |
| </span> | |
| </span> | |
| ); |
🤖 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/app/components/TypingText.tsx` around lines 82 - 93, The TypingText
component currently displays text that grows from empty to full length during
the typing animation, which causes visible layout reflow on smaller screens. To
fix this, reserve the full text width from the start by rendering the complete
text invisibly as a reference while displaying only the currently typed portion.
Modify the span containing displayed to either include the full text hidden
behind it for width reservation, or wrap the display logic to ensure the
container maintains a constant width equal to the final text width throughout
the entire animation, preventing layout shifts as more characters appear.
| useEffect(() => { | ||
| document.documentElement.classList.toggle('dark', isDarkMode); | ||
| localStorage.setItem('theme', isDarkMode ? 'dark' : 'light'); | ||
| }, [isDarkMode]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/app/hooks/useTheme.tsRepository: hrx01-dev/Servio
Length of output: 1761
Guard theme persistence writes against storage access failures.
Line 35 writes to localStorage without error handling, while reads are already guarded in getInitialTheme (lines 19–25). In restricted storage contexts, this write can throw and break the effect. Wrap the persistence call in try-catch to match the existing defensive pattern.
Proposed fix
useEffect(() => {
document.documentElement.classList.toggle('dark', isDarkMode);
- localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
+ try {
+ localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
+ } catch {
+ // Ignore persistence failures (e.g., restricted storage mode)
+ }
}, [isDarkMode]);📝 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.
| useEffect(() => { | |
| document.documentElement.classList.toggle('dark', isDarkMode); | |
| localStorage.setItem('theme', isDarkMode ? 'dark' : 'light'); | |
| }, [isDarkMode]); | |
| useEffect(() => { | |
| document.documentElement.classList.toggle('dark', isDarkMode); | |
| try { | |
| localStorage.setItem('theme', isDarkMode ? 'dark' : 'light'); | |
| } catch { | |
| // Ignore persistence failures (e.g., restricted storage mode) | |
| } | |
| }, [isDarkMode]); |
🤖 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/app/hooks/useTheme.ts` around lines 33 - 36, The useEffect hook in the
theme persistence logic writes to localStorage without error handling, which can
throw in restricted storage contexts and break the effect, while the
getInitialTheme function already implements defensive error handling for storage
reads. Wrap the localStorage.setItem call inside the useEffect (when isDarkMode
changes) in a try-catch block to safely handle any storage access errors and
match the existing error handling pattern already established in
getInitialTheme.
…x01-dev#72) Skeleton used bg-accent which maps to #06B6D4 (bright cyan) in light mode. Switched to bg-muted (#f4f4f8 light / dark-gray dark) so loading states are visually neutral and consistent across both themes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/dashboard/components/DashboardLayout.tsx`:
- Around line 35-36: The navigation items with labels "AI Estimate" pointing to
/dashboard/estimation and "Pricing Config" pointing to /dashboard/pricing-config
in the DashboardLayout navigation array reference routes that do not exist in
your routing configuration. Either remove these two navigation entries from the
DashboardLayout component's navigation item list until the corresponding
features are implemented, or add the missing route definitions to App.tsx that
match these paths. Choose the approach based on whether these features are
planned or should be removed from the navigation.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dc506626-20db-4d7e-9171-7a26b995dad9
📒 Files selected for processing (2)
src/app/components/ui/skeleton.tsxsrc/dashboard/components/DashboardLayout.tsx
✅ Files skipped from review due to trivial changes (1)
- src/app/components/ui/skeleton.tsx
…d @google/generative-ai upstream/main added AI estimation (PR hrx01-dev#83) and admin RBAC (PR hrx01-dev#82) and reverted the broken vite-plugin-ssg prerender step (PR hrx01-dev#87). DashboardLayout conflict resolved: keep our Moon/Sun theme toggle imports alongside upstream's Sparkles/Settings2 for the new nav items. Install @google/generative-ai@^0.24.1 required by the new estimationService. Closes hrx01-dev#71 — theme toggle is already implemented in both the sidebar and mobile header of DashboardLayout; this merge makes it available to all authenticated users on the latest codebase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Description
TypingTextcomponent — character-by-character typing with a blinking cursor, powered byuseInViewfrommotion/reactConverts) types on page load, 1.2 s delay to wait for the splash screen fade-inCloses #75
Summary by CodeRabbit
Release Notes