UI/UX Overhaul – Premium AlignUI-Inspired Experience#294
UI/UX Overhaul – Premium AlignUI-Inspired Experience#294RishiGoswami-code wants to merge 3 commits intoAOSSIE-Org:mainfrom
Conversation
📝 WalkthroughWalkthroughOverhauls the landing site: updates HTML title and entry script; replaces route rendering with a composed App layout (Navbar, LayoutFrame, ScrollToTop, Footer); and adds multiple new UI/visual components and rewrites Landing, HowItWorks, Integrations, Privacy, and Legal pages. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Fix all issues with AI agents
In `@LandingPage/index.html`:
- Around line 5-8: Uncomment and restore the favicon link in
LandingPage/index.html by re-enabling the commented <link rel="icon" ...>
element, update its href to point to your actual favicon asset (e.g.,
/favicon.ico or /assets/favicon.svg) and ensure the type attribute matches the
file (image/x-icon for .ico or image/svg+xml for .svg) so browsers display your
branded icon instead of a generic one.
In `@LandingPage/src/App.tsx`:
- Around line 1-13: The app currently never exposes the standalone compliance
pages (Privacy.tsx and Legal.tsx) and Footer links are placeholders; fix by
wiring proper routes and matching Footer links or by turning Footer links into
in-page anchors. Specifically, update the App component (function App) to wrap
the app in a router (e.g., BrowserRouter) and add Routes/Route entries that
import and render the Privacy and Legal components (Privacy and Legal/Terms) at
paths like "/privacy" and "/terms", and update Footer to use Link/NavLink or
hrefs that point to those routes; alternatively, if you want inline anchors,
modify Footer to use fragment IDs that match anchors in Landing or LayoutFrame
and add those anchors to the pages. Ensure imports for Privacy and Legal are
added and that Footer's link targets match the chosen approach.
In `@LandingPage/src/components/Footer.tsx`:
- Around line 60-61: The Footer component contains misspelled brand casing
"InpactAI"; update every occurrence to "InPactAI" (e.g., the span with className
"text-lg font-bold text-white tracking-tight" and the other brand instances in
the same Footer component) so the displayed brand matches site title/PR
branding, ensuring exact capitalization is "InPactAI".
- Around line 65-68: The social icon links in the Footer component are missing
accessible names; update the three anchor elements that wrap <Twitter />,
<Github />, and <Linkedin /> inside Footer.tsx to include descriptive aria-label
attributes (e.g., "Follow on Twitter", "View GitHub profile", "Connect on
LinkedIn") so screen readers can identify each link; ensure the aria-label text
clearly matches the action and target for each icon.
In `@LandingPage/src/components/howitworks.tsx`:
- Around line 51-53: The component copies use the incorrect brand casing
"Inpact"; update all occurrences in this component (e.g., the description string
in the AI-Powered Matching step and the other strings around lines referenced)
to the correct brand "InPactAI" so the header and each step copy use consistent
casing—search for the literal "Inpact" in howitworks.tsx (including the
title/description objects shown and the strings at the other referenced block)
and replace with "InPactAI".
In `@LandingPage/src/components/Navbar.tsx`:
- Around line 76-82: The useEffect that adds the scroll listener (the
handleScroll function which calls setIsScrolled) doesn't initialize isScrolled
on mount; after registering the listener in the effect, invoke handleScroll()
once to sync state with the current window.scrollY so the Navbar renders
correctly when the page loads scrolled (e.g., via hash navigation). Locate the
useEffect containing handleScroll, window.addEventListener('scroll',
handleScroll) and setIsScrolled, and add a single call to handleScroll()
immediately after adding the listener, keeping the existing cleanup that removes
the listener.
In `@LandingPage/src/components/ShootingStars.tsx`:
- Around line 69-139: The animate loop currently calls requestAnimationFrame
recursively but only the first returned id (animationId) is stored, so
subsequent frames can't be cancelled; introduce a mutable frame id variable
(e.g., let frameId) and an active flag (e.g., let isActive = true) at the top of
the effect, update frameId = requestAnimationFrame(animate) each time you
schedule a frame inside animate, and early-return from animate when !isActive;
in the cleanup set isActive = false and call cancelAnimationFrame(frameId) (and
still removeEventListener('resize', handleResize)). This ensures the animate
function and its recursive frames (requestAnimationFrame) are stopped and
cancelled on unmount.
In `@LandingPage/src/Pages/Landing.tsx`:
- Around line 312-321: The Tailwind class in the motion.div inside the
features.map render is misspelled: replace the invalid "transaction-colors" with
the correct "transition-colors" in the className string so the hover color
transition works; locate the motion.div used in the features.map callback (the
element with key={index}, initial/whileInView props) and update its className to
use "transition-colors" instead.
- Around line 47-65: The Typewriter effect currently creates an interval inside
the setTimeout callback that isn’t cleared by the outer effect cleanup; update
the useEffect in the Typewriter component so the interval ID is accessible to
the effect scope (e.g., declare let intervalId or useRef before setTimeout),
start the interval inside the timeout as you do now, and ensure the effect’s
cleanup function clears both the timeout and the interval (clearTimeout(timeout)
and clearInterval(intervalId)) so the typing interval stops when the component
unmounts or dependencies change.
🧹 Nitpick comments (4)
LandingPage/src/components/Community.tsx (1)
57-60: Use a stable key for social cards.Index keys can cause subtle animation/state glitches if the list order changes. The name is already unique.
🔧 Suggested tweak
- {socials.map((social, index) => ( + {socials.map((social, index) => ( <motion.a - key={index} + key={social.name} href={social.href}LandingPage/src/components/LayoutFrame.tsx (1)
1-10: Remove the no-opuseEffectto avoid empty-hook lint warnings.If there’s no immediate resize logic, drop the hook now and reintroduce it when needed.
🧹 Suggested cleanup
-import { useEffect } from 'react'; ... - useEffect(() => { - // Optional: could use window height for dynamic ruler calculation - }, []);LandingPage/src/components/integration.tsx (1)
9-14: Use functional state updates intoggleConnect.This avoids stale state when React batches updates.
🔁 Suggested change
- const toggleConnect = (index: number) => { - if (connected.includes(index)) { - setConnected(connected.filter(i => i !== index)); - } else { - setConnected([...connected, index]); - } - }; + const toggleConnect = (index: number) => { + setConnected((prev) => + prev.includes(index) ? prev.filter(i => i !== index) : [...prev, index] + ); + };LandingPage/src/components/howitworks.tsx (1)
12-32: Tighten FloatingLogo’sytype for consistent animation
yis typed asnumber | string, but the animation path only handles numeric values. If percent-based placement isn’t needed, constrainytonumberand simplify the motion values to avoid unit jumps.♻️ Suggested tweak
-const FloatingLogo = ({ d, className, delay, x, y }: { d: string, className?: string, delay: number, x: number | string, y: number | string }) => ( +const FloatingLogo = ({ d, className, delay, x, y }: { d: string, className?: string, delay: number, x: number | string, y: number }) => ( <motion.div className={`absolute opacity-20 pointer-events-none ${className}`} initial={{ x, y }} animate={{ - y: [typeof y === 'number' ? y : 0, typeof y === 'number' ? y - 40 : -40, typeof y === 'number' ? y : 0], + y: [y, y - 40, y], rotate: [0, 10, -10, 0] }}
| <!-- <link rel="icon" type="image/svg+xml" href="/" /> --> | ||
| <script src="https://cdn.tailwindcss.com"></script> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>Vite + React + TS</title> | ||
| <title>InPactAI</title> |
There was a problem hiding this comment.
Consider restoring a real favicon link.
With the favicon commented out, browsers will show a generic icon. If you have an asset, wire it back in for polish.
💡 Example fix (adjust the path to your actual asset)
- <!-- <link rel="icon" type="image/svg+xml" href="/" /> -->
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />📝 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.
| <!-- <link rel="icon" type="image/svg+xml" href="/" /> --> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Vite + React + TS</title> | |
| <title>InPactAI</title> | |
| <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>InPactAI</title> |
🤖 Prompt for AI Agents
In `@LandingPage/index.html` around lines 5 - 8, Uncomment and restore the favicon
link in LandingPage/index.html by re-enabling the commented <link rel="icon"
...> element, update its href to point to your actual favicon asset (e.g.,
/favicon.ico or /assets/favicon.svg) and ensure the type attribute matches the
file (image/x-icon for .ico or image/svg+xml for .svg) so browsers display your
branded icon instead of a generic one.
| title: "AI-Powered Matching", | ||
| description: "Inpact uses AI to suggest ideal brand-creator collaborations based on past work.", | ||
| icon: <SparklesIcon className="w-5 h-5" />, |
There was a problem hiding this comment.
Check brand casing (“InpactAI”) for consistency
If the official name is “InPactAI,” update the header and step copy to match the brand styling throughout the site.
✏️ Suggested copy tweak
- description: "Inpact uses AI to suggest ideal brand-creator collaborations based on past work.",
+ description: "InPactAI uses AI to suggest ideal brand-creator collaborations based on past work.",
...
- How InpactAI works
+ How InPactAI worksAlso applies to: 119-123
🤖 Prompt for AI Agents
In `@LandingPage/src/components/howitworks.tsx` around lines 51 - 53, The
component copies use the incorrect brand casing "Inpact"; update all occurrences
in this component (e.g., the description string in the AI-Powered Matching step
and the other strings around lines referenced) to the correct brand "InPactAI"
so the header and each step copy use consistent casing—search for the literal
"Inpact" in howitworks.tsx (including the title/description objects shown and
the strings at the other referenced block) and replace with "InPactAI".
| const Typewriter = ({ text, delay = 0, className }: { text: string; delay?: number; className?: string }) => { | ||
| const [displayedText, setDisplayedText] = useState(''); | ||
|
|
||
| useEffect(() => { | ||
| const timeout = setTimeout(() => { | ||
| let currentIndex = 0; | ||
| const interval = setInterval(() => { | ||
| if (currentIndex <= text.length) { | ||
| setDisplayedText(text.slice(0, currentIndex)); | ||
| currentIndex++; | ||
| } else { | ||
| clearInterval(interval); | ||
| } | ||
| }, 50); // Typing speed | ||
| return () => clearInterval(interval); | ||
| }, delay * 1000); | ||
|
|
||
| return () => clearTimeout(timeout); | ||
| }, [text, delay]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "Landing.tsx" -type fRepository: AOSSIE-Org/InPactAI
Length of output: 98
🏁 Script executed:
cat -n ./LandingPage/src/Pages/Landing.tsx | sed -n '40,70p'Repository: AOSSIE-Org/InPactAI
Length of output: 1265
Clear the typing interval in the effect cleanup function
The interval created inside setTimeout is not properly cleaned up when the effect unmounts or dependencies change. Line 61's return statement is inside the setTimeout callback and has no effect on cleanup. The actual cleanup function (line 64) only clears the timeout, leaving the interval running if the component unmounts or dependencies change after the initial delay.
🧹 Suggested fix
useEffect(() => {
+ let interval: ReturnType<typeof setInterval> | undefined;
const timeout = setTimeout(() => {
let currentIndex = 0;
- const interval = setInterval(() => {
+ interval = setInterval(() => {
if (currentIndex <= text.length) {
setDisplayedText(text.slice(0, currentIndex));
currentIndex++;
} else {
clearInterval(interval);
}
}, 50); // Typing speed
- return () => clearInterval(interval);
}, delay * 1000);
- return () => clearTimeout(timeout);
+ return () => {
+ clearTimeout(timeout);
+ if (interval) clearInterval(interval);
+ };
}, [text, delay]);🤖 Prompt for AI Agents
In `@LandingPage/src/Pages/Landing.tsx` around lines 47 - 65, The Typewriter
effect currently creates an interval inside the setTimeout callback that isn’t
cleared by the outer effect cleanup; update the useEffect in the Typewriter
component so the interval ID is accessible to the effect scope (e.g., declare
let intervalId or useRef before setTimeout), start the interval inside the
timeout as you do now, and ensure the effect’s cleanup function clears both the
timeout and the interval (clearTimeout(timeout) and clearInterval(intervalId))
so the typing interval stops when the component unmounts or dependencies change.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@LandingPage/src/components/ShootingStars.tsx`:
- Around line 92-131: The loop mutates shootingStars with splice(index, 1)
inside shootingStars.forEach, which can skip elements; instead build a new array
of surviving stars (or reassign shootingStars = shootingStars.filter(...)) using
the same removal conditions (x > canvas.width + 100 || y > canvas.height + 100
|| opacity <= 0) so drawing still uses each star's updated x,y,opacity; locate
the shootingStars.forEach block in ShootingStars.tsx and replace the
splice-based removal with a filter or a push-to-new-array approach to preserve
iteration correctness.
In `@LandingPage/src/Pages/Landing.tsx`:
- Around line 304-306: Update the displayed brand casing from "InpactAI" to
"InPactAI" wherever the literal appears in this component; specifically change
the text content inside the <h2> element ("What's inside InpactAI?") and the
other heading/label occurrences referenced (around the other instance at lines
~415-417) to "InPactAI" so the site title and headings match the correct brand
casing.







Premium UI / UX Overhaul (AlignUI-Inspired)
Overview
This PR introduces a comprehensive UI/UX upgrade to elevate the product to a premium, modern SaaS experience inspired by AlignUI design principles while preserving the existing brand colors and identity.
The focus is on:
Typography
Plus Jakarta Sans/OutfitLayout, Grid & Borders
LayoutFramecomponent with fixed overlay ruler linesMotion & Visual Effects
Hero
Glow & Scroll
Navigation
Navbar
Landing.tsxSection Redesigns
Features
How It Works
Community
Integrations
Waitlist (“Join the Revolution”)
ShootingStarsbackground componentRefactors & Cleanup
Verification Checklist
Result
The application now presents a founder-grade, premium SaaS interface with improved clarity, structure, and engagement—aligned with modern design systems while remaining uniquely branded.
Summary by CodeRabbit
New Features
Refactor
Style
Chores