Skip to content

Feat/landing page redesign#166

Open
Aspirant200715 wants to merge 5 commits into
SamXop123:mainfrom
Aspirant200715:feat/landing-page-redesign
Open

Feat/landing page redesign#166
Aspirant200715 wants to merge 5 commits into
SamXop123:mainfrom
Aspirant200715:feat/landing-page-redesign

Conversation

@Aspirant200715
Copy link
Copy Markdown

@Aspirant200715 Aspirant200715 commented Jun 1, 2026

📝 Description

This Pull Request introduces a monumental architectural shift for the Paraline landing page alongside a top-tier cinematic UI redesign. The legacy Vite-based SPA frontend has been completely deprecated in favor of a highly optimized, statically generated Next.js 15 Application.

Beyond the architectural migration, this PR delivers a premium, glassmorphic visual aesthetic and introduces a complex new Theme Comparison Engine that allows users to interactively test visualizers side-by-side.


🏗️ Architectural Changes

1. Next.js App Router Migration

The entire landing directory has been ported to Next.js 15, utilizing React 19.

  • Static Site Generation (SSG): All routes (/, /faq, /settings, /requirements, /themes, etc.) are now statically prerendered for instantaneous time-to-interactive (TTI) and optimal SEO.
  • Dependency Cleanup: Completely removed Vite, PostCSS configurations for Vite, and index.html. Introduced next.config.ts and Next. js-specific PostCSS modules.
  • Routing: Replaced React Router with Next.js file-system-based App Router.

2. State Management & Animations

  • Framer Motion Integration: Implemented deep framer-motion orchestration across all components. Layout transitions, modal pop-ups, and accordion expansions are now driven by spring physics (e.g., stiffness: 400, damping: 25).
  • React Portals (createPortal): Engineered the Comparison Modal to escape local DOM hierarchies and stacking contexts by portaling directly to document.body with z-[9999]. This permanently solves the issue of sidebars cutting off full-screen overlays.

🎨 UI/UX Enhancements

1. Studio-Grade Glassmorphism

The entire application now runs on a cohesive #060913 dark-mode base, significantly elevating the brand's premium feel.

  • Ambient Lighting: Deployed massive, highly-blurred (blur-[120px]) radial gradients using mix-blend-screen to create dynamic, overlapping light pools in the background.
  • Translucent Surfaces: Replaced solid cards with bg-white/[0.02] backgrounds, backdrop-blur-2xl, and subtle inner shadows (shadow-[inset_0_1px_1px_rgba(255,255,255,0.05)], border-white/10) to create a frosted glass aesthetic.

2. Interactive Theme Comparison Engine

This is the flagship feature of this PR, located in ThemeShowcase.tsx and ThemeComparisonModal.tsx.

  • Floating Action Bar: A sleek, sticky action bar that appears when users select 1-3 themes. It provides clear real-time feedback (e.g., "Select at least 2 themes to compare") and prevents invalid states.
  • Side-by-Side Modal: A full-screen overlay that simultaneously renders up to 3 live, animated visualizers side-by-side.
  • Metrics Table: Beneath the live previews, a responsive grid maps out key data points (Animation Style, Reactivity, Visual Intensity, Performance Impact, Best For) with dynamic, color-coded badges based on the tier (e.g., High = Purple, Low = Emerald).

3. Component Deep-Dives

  • /settings: Rebuilt the Configuration view. Added custom SVG icons, interactive toggle switches with smooth translateX transitions, and categorized bento grids.
  • /requirements: Overhauled the System Requirements page into a dynamic grid. Clearly delineates Minimum vs. Recommended specs, complete with glowing borders on hover and a high-contrast amber warning banner for Windows-only compatibility.
  • /faq: Upgraded to an AnimatePresence driven accordion, ensuring extremely smooth expand/collapse animations without layout jank.

📹 Visual Evidence & Walkthrough

(Maintainers: Please review the media below demonstrating the fluidity of the new architecture)

1. Live Comparison Engine Demo

Watch how seamlessly the modal portals into the DOM and renders multiple live visualizers.

Screen.Recording.2026-06-02.024213.mp4

2. Theme Gallery & Floating Action Bar

Demonstrating the new selection states and the dynamic floating action bar.
Screenshot 2026-06-02 025009

3. Settings & Hardware Requirements

The redesigned glassmorphic bento grids.
Screenshot 2026-06-02 025025
Screenshot 2026-06-02 025041
Screenshot 2026-06-02 025051
Screenshot 2026-06-02 025102


🔧 Upstream Sync & Testing

  • Conflict Resolution: Successfully merged 56 upstream commits from SamXop123/Paraline into this branch.
  • Vite Deprecation Conflicts: Intentionally resolved modify/delete conflicts by accepting deletions for the legacy React/Vite architecture components that were replaced by the App Router.
  • Build Verification: npm run build generates 12/12 static pages with 0 TypeScript/ESLint errors in <4 seconds.

Reviewer Notes: Please pay special attention to ThemeComparisonModal.tsx and the custom scrollbar implementations. Let me know if any further tweaks to the gradient meshes or spring configurations are desired!

Resolves #4

Summary by CodeRabbit

  • New Features

    • New landing site: Home, FAQ, Installation, System Requirements, Privacy, Terms, Theme Gallery, and Settings pages
    • Theme Showcase with multi-theme comparison (compare up to three) and apply/activate flows
    • Improved download flow with status feedback and automatic installer retrieval
    • New animated visualizers and richer interactive UI elements (logo, sidebar, footer, features, previews)
  • Documentation

    • Added landing README and agent notes for Next.js setup

# Conflicts:
#	landing/src/App.jsx
#	landing/src/components/Footer.jsx
#	landing/src/components/Sidebar.jsx
#	landing/src/components/previews/ThemeCard.jsx
#	landing/src/components/sections/CTASection.jsx
#	landing/src/components/sections/HeroSection.jsx
#	landing/src/components/sections/ThemeShowcaseSection.jsx
#	landing/src/data/themes.js
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

@Aspirant200715 is attempting to deploy a commit to the Dot_NotSam's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 837d8c72-04cb-44d3-aa93-2288e8644294

📥 Commits

Reviewing files that changed from the base of the PR and between d75d010 and a75dbbf.

📒 Files selected for processing (1)
  • landing/src/components/ThemeShowcase.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • landing/src/components/ThemeShowcase.tsx

📝 Walkthrough

Walkthrough

Migrates the landing app to Next.js (app dir): adds Next/TS/ESLint/PostCSS configs, root layout and globals, pages, many client UI components and visualizers, ThemeShowcase with comparison modal, and a download API route with utilities.

Changes

Next.js Landing Migration

Layer / File(s) Summary
Framework & config
landing/package.json, landing/next.config.ts, landing/postcss.config.mjs, landing/eslint.config.mjs, landing/tsconfig.json, landing/.gitignore, landing/README.md, landing/AGENTS.md, landing/CLAUDE.md
Switch project to Next.js 16: update dependencies, add Next/TS/ESLint/PostCSS configs, repository ignores and docs.
Root layout & global styles
landing/src/app/layout.tsx, landing/src/app/globals.css
Add Next.js root layout with metadata and font variables; introduce global Tailwind/CSS theme variables, background/noise, scrollbar/selection styling.
Sidebar, Footer, Logo
landing/src/components/Sidebar.tsx, landing/src/components/Footer.tsx, landing/src/components/Logo.tsx
New client navigation Sidebar (route/hash-aware), Footer component with links/icons, and Logo with SVG gradient hover effects.
Home page & hero
landing/src/app/page.tsx, landing/src/components/FeaturesBento.tsx
Create the main landing page: 3D hero with animated headline, floating bottom cards, visualizer previews, FeaturesBento section, and download banner.
Secondary pages
landing/src/app/faq/page.tsx, landing/src/app/installation/page.tsx, landing/src/app/privacy/page.tsx, landing/src/app/requirements/page.tsx, landing/src/app/settings/page.tsx, landing/src/app/terms/page.tsx, landing/src/app/themes/page.tsx
Add FAQ accordion, Installation timeline, Privacy Policy, System Requirements bento, Settings toggles, Terms page, and Themes page wrapper.
Download API & component
landing/src/app/api/download/route.ts, landing/src/components/DownloadButton.tsx
API GET route fetches latest GitHub release and returns .exe asset; DownloadButton manages lifecycle (connect → download → done), validates URL, and falls back to GitHub releases page on error.
Theme showcase & comparison
landing/src/components/ThemeShowcase.tsx, landing/src/components/ThemeComparisonModal.tsx
Theme grid with hover previews, click-to-apply POST, compare selection (max 3) and portal modal rendering side-by-side comparisons with badge-styled metrics.
Visualizer components
landing/src/components/visualizers/*
Add many client visualizers (AmbientWave, AuroraDrift, DotParticles, EdgeCrystals, FlowBorder, PulseLines, ReactiveBorder, RippleFlow, SideBars, SideBraids, SnowParticles) for animated previews controlled by an active prop.
Shared utilities
landing/src/lib/paraline-api.ts, landing/src/lib/utils.ts
Add GITHUB_URL and endpoint helpers plus cn() helper combining clsx with tailwind-merge.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

gssoc26, gssoc:approved, level:advanced, type:feature, type:design, quality:clean

Suggested reviewers

  • SamXop123

Poem

🐇 A rabbit coded through the night,
Sprung Vite to Next with joyous might.
Themes shimmer, visualizers hum,
Downloads ready — click and come.
Hops of code — a landing bright!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/landing page redesign' accurately captures the main objective of migrating from Vite SPA to Next.js and redesigning the landing UI.
Linked Issues check ✅ Passed The PR comprehensively implements all coding objectives from issue #4: improved layout consistency, refined typography, enhanced animations with Framer Motion, improved component consistency, smoother interactions, better responsiveness, and maintained tech stack (React/Next.js, Tailwind, Framer Motion).
Out of Scope Changes check ✅ Passed All changes directly support the landing page redesign and modernization goal; the migration from Vite to Next.js, component refactoring, and new visualizer/theme showcase components are all aligned with issue #4 requirements.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🧹 Nitpick comments (5)
landing/src/components/visualizers/DotParticlesPreview.tsx (1)

43-53: ⚡ Quick win

Avoid Math.random() inside render-time animation props

Randomizing on each render (Line 46 and Line 49) makes animation behavior unstable and can trigger unnecessary motion reconfiguration. Precompute per-dot color chance/duration in the generated dot state.

🤖 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 `@landing/src/components/visualizers/DotParticlesPreview.tsx` around lines 43 -
53, The animate props use Math.random() during render (backgroundColor and
duration) causing unstable re-renders; instead, precompute per-dot randomness
when creating the dot state (e.g., in the dots generator that produces the "dot"
objects) by adding fields like dot.isFlash or dot.color and
dot.precomputedDuration, then update DotParticlesPreview to read
backgroundColor: dot.color (or conditional on dot.isFlash) and
transition.duration: dot.precomputedDuration and remove all Math.random() calls
from the render/animate block so each dot's color/duration is stable across
renders.
landing/src/components/ThemeComparisonModal.tsx (1)

50-84: ⚡ Quick win

Add core dialog accessibility semantics and Escape-to-close

The modal container should expose dialog semantics (role="dialog", aria-modal="true", accessible label) and support Escape key close. Current behavior is mouse-friendly but incomplete for keyboard/screen-reader users.

🤖 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 `@landing/src/components/ThemeComparisonModal.tsx` around lines 50 - 84, The
modal in ThemeComparisonModal is missing dialog semantics and Escape-key
support; update the modal container (the inner motion.div that renders the modal
content) to include role="dialog", aria-modal="true", and an accessible label by
adding an aria-labelledby that points to the heading element (give the h3 a
unique id), and add an onKeyDown handler on that same container (or a focusable
wrapper) to call the existing onClose when the Escape key is pressed; ensure
focus is moved into the dialog when opened (e.g., focus the container or first
focusable element) so the Escape handler receives key events.
landing/src/components/visualizers/SideBarsPreview.tsx (1)

13-35: 💤 Low value

Math.random() in the animate/transition props makes render impure.

baseWidth + Math.random() * 30 (Lines 23, 49) and the random duration/delay are evaluated on every render. Each re-render reseeds the keyframe targets and can restart/jitter the animation. Since the left and right groups duplicate the identical bar logic, consider extracting a small EqualizerBar (or precomputing the random targets once via useMemo/useState) to keep render pure and remove the duplication.

Also applies to: 40-62

🤖 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 `@landing/src/components/visualizers/SideBarsPreview.tsx` around lines 13 - 35,
The animate/transition props use Math.random() inside the bars.map which makes
rendering impure and causes jitter; extract the bar into a stable component
(e.g., EqualizerBar) or precompute per-bar random values with useMemo/useState
and reference those stable values inside the motion.div (replace occurrences of
baseWidth + Math.random() * 30 and the random duration with the memoized random
targets/duration) so the keyframe targets stay constant across re-renders and
remove duplication between left and right groups.
landing/src/components/visualizers/SnowParticlesPreview.tsx (1)

51-60: 💤 Low value

Math.random() inside the animate.x keyframes (Line 53) re-rolls on every render.

The horizontal drift targets are recomputed on each render, so any re-render restarts the motion with new values. Since these values are per-flake and stable by intent, fold the x-trajectory into the flake object generated in the effect (alongside left/top/size) and read it here.

🤖 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 `@landing/src/components/visualizers/SnowParticlesPreview.tsx` around lines 51
- 60, The animate.x uses Math.random() directly so targets change on every
render; instead generate and store stable horizontal targets on each flake when
you create them (in the effect that builds the flakes array) e.g. add a property
like xTargets or xTrajectory to each flake object alongside left/top/size,
update any flake type/interface accordingly, and replace the inline
Math.random() in SnowParticlesPreview's animate.x with flake.xTargets so each
flake's horizontal keyframes remain stable across renders.
landing/src/components/visualizers/EdgeCrystalsPreview.tsx (1)

23-33: ⚖️ Poor tradeoff

Accessibility: honor prefers-reduced-motion in visualizer animations (landing/src/components/visualizers/EdgeCrystalsPreview.tsx:23-33)

Motion v12 exposes useReducedMotion (import from motion/react) which returns whether the user enabled “Reduce motion”. Gate the looping repeat: Infinity animation (e.g., fall back to the static active === false state) when it’s enabled; ideally apply this across the whole visualizer cohort (e.g., via MotionConfig with a reducedMotion policy).

🤖 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 `@landing/src/components/visualizers/EdgeCrystalsPreview.tsx` around lines 23 -
33, The animation in EdgeCrystalsPreview uses infinite looping
(transition.repeat = Infinity) and does not respect user's
"prefers-reduced-motion"; import and call useReducedMotion from 'motion/react'
inside the EdgeCrystalsPreview component, and when reducedMotion is true,
disable looping by setting transition.repeat to 0 (or remove the repeat) and set
animate to the non-animated/static values (e.g., use the active === false/steady
arrays or a single value) so the visualizer falls back to a static presentation;
alternatively wrap the visualizer cohort with MotionConfig and set reducedMotion
policy to "always" when useReducedMotion is true to apply this behavior across
all child components.
🤖 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 `@landing/README.md`:
- Line 19: Update the README line that points to the editable page path: replace
the incorrect `app/page.tsx` reference with the correct `src/app/page.tsx` so
contributors edit the actual project layout; locate the string in the README
(the sentence mentioning "You can start editing the page by modifying
`app/page.tsx`.") and modify it to reference `src/app/page.tsx`.

In `@landing/src/app/api/download/route.ts`:
- Around line 9-11: The fetch in landing/src/app/api/download/route.ts that
requests the GitHub releases (the const response = await fetch(...)) needs a
timeout guard to avoid hanging; wrap the fetch in an AbortController, start a
setTimeout that calls controller.abort() after a short interval (e.g. a few
seconds), pass signal: controller.signal into fetch, clear the timer on success,
and handle the abort error in the surrounding async function (response variable)
to return/throw a sensible timeout result (e.g., 504 or a JSON error) instead of
letting the route hang.

In `@landing/src/app/faq/page.tsx`:
- Around line 94-97: The accordion toggle button in page.tsx (the <button> that
calls setOpenIndex with isOpen/idx) removes visible keyboard focus and lacks
ARIA state; restore keyboard focus styling (remove or replace the
"focus:outline-none" utility with a visible focus style such as a focus-visible
ring class) and add accessibility attributes: set aria-expanded={isOpen} on the
button, provide aria-controls pointing to the associated panel id (ensure the
panel element has a matching id), and ensure the panel uses appropriate
hidden/aria-hidden or role="region" with correct visibility toggling so
assistive tech sees the expanded/collapsed state.

In `@landing/src/app/globals.css`:
- Around line 54-69: The stylesheet only targets WebKit/Blink using
::-webkit-scrollbar* rules so Firefox won't get the same styling; add a
progressive-enhancement fallback by specifying the standardized Firefox
properties (e.g., add scrollbar-color and scrollbar-width declarations)
alongside the existing ::-webkit-scrollbar, ::-webkit-scrollbar-track, and
::-webkit-scrollbar-thumb rules in globals.css so Firefox users receive the same
thumb color and width; ensure values match the rgba thumb colors (use a
semi-transparent foreground and transparent track) and set an appropriate
scrollbar-width (e.g., thin) to mirror the 6px width.

In `@landing/src/app/settings/page.tsx`:
- Around line 96-103: The toggle button removes the visible focus outline and
lacks an ARIA pressed state; update the button rendered in the toggleSetting
flow to include aria-pressed={setting.active}, remove the plain
focus:outline-none and replace it with a keyboard-visible focus ring (e.g. add
classes like focus-visible:ring-2 focus-visible:ring-cyan-400
focus-visible:ring-offset-2 focus-visible:ring-offset-black/20) and add a
pressed/active visual (e.g. active:scale-95 or active:translate-y-0.5 and an
active:bg variant) so keyboard users get a clear focus ring and a pressed state
while keeping the existing conditional bg/border classes tied to setting.active
and the onClick handler toggleSetting.
- Around line 29-33: toggleSetting currently shallow-copies groups then mutates
newGroups[groupIdx].settings[settingIdx].active in place; change it to use the
functional form setGroups(prev => prev.map((g, gi) => gi === groupIdx ? { ...g,
settings: g.settings.map((s, si) => si === settingIdx ? { ...s, active:
!s.active } : s) } : g )) to ensure full immutability and avoid nested mutation
(refer to toggleSetting, setGroups, groups, settings); also restore keyboard
focus styling on the toggle button by removing focus:outline-none and adding an
accessible focus-visible utility (e.g., focus-visible:ring or
focus-visible:outline) so keyboard users retain a visible focus indicator (refer
to the toggle button classes where focus:outline-none is used).

In `@landing/src/components/DownloadButton.tsx`:
- Around line 26-30: The fetch in DownloadButton.tsx currently has no timeout;
replace the direct call to const res = await fetch("/api/download") with an
AbortController-based timeout: create const controller = new AbortController(),
pass { signal: controller.signal } to fetch, start a setTimeout that calls
controller.abort() after a reasonable timeout (e.g., 10_000 ms) and clear that
timer on success, then await fetch and handle aborts in the catch (check for
error.name === 'AbortError') to re-enable the button and surface an appropriate
error message; update the code paths around the fetch (the block containing
res/json) to use this pattern so hung requests are aborted and the UI exits the
disabled state.
- Around line 38-43: The code in DownloadButton.tsx blindly sets a.href =
data.url and clicks the anchor; validate and allowlist the URL before using it
by parsing data.url with the URL constructor (wrap in try/catch), ensuring the
protocol is https (or another allowed protocol) and the hostname is in an
allowlist of trusted hosts (or matches same-origin) and only then append/click
the anchor; if validation fails, abort the download flow and surface/log an
error instead of navigating to the untrusted URL.
- Around line 68-72: The statusStyles assignments in the DownloadButton
component currently use Tailwind v3 important-prefix syntax (e.g., "!bg-white",
"!text-black"); update each assignment where statusStyles is set (the block
handling status === "idle"/"downloading"/"done") to use Tailwind v4
important-suffix syntax by moving the "!" to the end of each utility (e.g.,
"!bg-white" -> "bg-white!", "!text-black" -> "text-black!") and ensure any
shadow or other utilities that need importance also get the trailing "!"; keep
the same class names and spacing otherwise so statusStyles semantics remain
unchanged.

In `@landing/src/components/Logo.tsx`:
- Around line 42-54: The SVG gradients in the Logo component use hardcoded IDs
("sweep-1", "sweep-2", "sweep-3") which will clash when multiple Logo instances
are rendered; update the Logo component to generate stable, instance-unique IDs
(e.g., via React's useId() or a passed-in id prop) and use those generated IDs
both in the <linearGradient id="..."> definitions and in any fill="url(#...)"
references so each instance binds to its own gradients (update references where
"sweep-1/2/3" are used).

In `@landing/src/components/ThemeShowcase.tsx`:
- Around line 199-213: The handleApply function treats any fetch completion as
success but fetch only throws on network errors; update handleApply to inspect
the POST response from getThemesEndpoint(), check response.ok (and optionally
response.status) before calling setAppliedTheme/theme success UI, and handle
non-OK responses by logging or showing an error and not setting the applied
state; keep the existing catch for network errors but ensure
setAppliedTheme(themeName) and the timeout run only when the response is ok (or
when you intentionally simulate success).

In `@landing/src/components/visualizers/AmbientWavePreview.tsx`:
- Around line 34-41: The shadowBlur/shadowColor are set after the drawWave calls
so the glow doesn't affect the strokes; move the glow setup (ctx.shadowBlur and
ctx.shadowColor) before invoking drawWave so the canvas context has the shadow
configured when the wave paths are drawn (adjust the block around drawWave(...)
and the ctx shadow assignments and ensure drawWave uses the same ctx and canvas
variables and the active flag).

In `@landing/src/components/visualizers/AuroraDriftPreview.tsx`:
- Around line 35-56: The SVG gradient ids (id={`aurora-grad-${i}`} and the
corresponding fill={`url(`#aurora-grad-`${i})`} in AuroraDriftPreview) can collide
across component instances; generate a per-instance unique prefix (e.g., using
React's useId() inside AuroraDriftPreview) and prepend it to the gradient id and
fill refs (e.g., `${instanceId}-aurora-grad-${i}`) so each <defs> id and its
url(#...) reference are globally unique across mounts.

In `@landing/src/components/visualizers/EdgeCrystalsPreview.tsx`:
- Around line 7-36: The fan rotation is hardcoded to center at index 2 but the
crystals array is length 10; compute a midpoint and use it for rotation so both
left and right strips fan symmetrically. Define midpoint = (crystals.length - 1)
/ 2 (or similar) in EdgeCrystalsPreview and replace rotate: (i - 2) * -15 with
rotate: (i - midpoint) * -15 for the left strip (and apply the analogous change
for the right strip), ensuring the midpoint calculation uses the same crystals
array so the fan is centered regardless of length.

In `@landing/src/components/visualizers/ReactiveBorderPreview.tsx`:
- Around line 35-39: ReactiveBorderPreview currently uses a hardcoded SVG
gradient id ("reactive-gradient") which will clash when multiple instances
mount; update the component to generate a unique id (e.g., via React's useId
hook) and use that id for the linearGradient id and the matching stroke URL
(stroke={`url(#${gradientId})`}) so each instance resolves its own gradient;
ensure the generated id is used consistently wherever "reactive-gradient"
appears (linearGradient id and any stroke/fill references).

---

Nitpick comments:
In `@landing/src/components/ThemeComparisonModal.tsx`:
- Around line 50-84: The modal in ThemeComparisonModal is missing dialog
semantics and Escape-key support; update the modal container (the inner
motion.div that renders the modal content) to include role="dialog",
aria-modal="true", and an accessible label by adding an aria-labelledby that
points to the heading element (give the h3 a unique id), and add an onKeyDown
handler on that same container (or a focusable wrapper) to call the existing
onClose when the Escape key is pressed; ensure focus is moved into the dialog
when opened (e.g., focus the container or first focusable element) so the Escape
handler receives key events.

In `@landing/src/components/visualizers/DotParticlesPreview.tsx`:
- Around line 43-53: The animate props use Math.random() during render
(backgroundColor and duration) causing unstable re-renders; instead, precompute
per-dot randomness when creating the dot state (e.g., in the dots generator that
produces the "dot" objects) by adding fields like dot.isFlash or dot.color and
dot.precomputedDuration, then update DotParticlesPreview to read
backgroundColor: dot.color (or conditional on dot.isFlash) and
transition.duration: dot.precomputedDuration and remove all Math.random() calls
from the render/animate block so each dot's color/duration is stable across
renders.

In `@landing/src/components/visualizers/EdgeCrystalsPreview.tsx`:
- Around line 23-33: The animation in EdgeCrystalsPreview uses infinite looping
(transition.repeat = Infinity) and does not respect user's
"prefers-reduced-motion"; import and call useReducedMotion from 'motion/react'
inside the EdgeCrystalsPreview component, and when reducedMotion is true,
disable looping by setting transition.repeat to 0 (or remove the repeat) and set
animate to the non-animated/static values (e.g., use the active === false/steady
arrays or a single value) so the visualizer falls back to a static presentation;
alternatively wrap the visualizer cohort with MotionConfig and set reducedMotion
policy to "always" when useReducedMotion is true to apply this behavior across
all child components.

In `@landing/src/components/visualizers/SideBarsPreview.tsx`:
- Around line 13-35: The animate/transition props use Math.random() inside the
bars.map which makes rendering impure and causes jitter; extract the bar into a
stable component (e.g., EqualizerBar) or precompute per-bar random values with
useMemo/useState and reference those stable values inside the motion.div
(replace occurrences of baseWidth + Math.random() * 30 and the random duration
with the memoized random targets/duration) so the keyframe targets stay constant
across re-renders and remove duplication between left and right groups.

In `@landing/src/components/visualizers/SnowParticlesPreview.tsx`:
- Around line 51-60: The animate.x uses Math.random() directly so targets change
on every render; instead generate and store stable horizontal targets on each
flake when you create them (in the effect that builds the flakes array) e.g. add
a property like xTargets or xTrajectory to each flake object alongside
left/top/size, update any flake type/interface accordingly, and replace the
inline Math.random() in SnowParticlesPreview's animate.x with flake.xTargets so
each flake's horizontal keyframes remain stable across renders.
🪄 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

Run ID: 3fb7858f-23d5-40d4-bedd-057fe6ca11b0

📥 Commits

Reviewing files that changed from the base of the PR and between 2db55a0 and 1cd0c5f.

⛔ Files ignored due to path filters (28)
  • landing/package-lock.json is excluded by !**/package-lock.json
  • landing/public/appicon.png is excluded by !**/*.png
  • landing/public/file.svg is excluded by !**/*.svg
  • landing/public/globe.svg is excluded by !**/*.svg
  • landing/public/next.svg is excluded by !**/*.svg
  • landing/public/previews/ambient-wave-preview.svg is excluded by !**/*.svg
  • landing/public/previews/aurora-drift-preview.svg is excluded by !**/*.svg
  • landing/public/previews/dot-particles-preview.svg is excluded by !**/*.svg
  • landing/public/previews/edge-crystals-preview.svg is excluded by !**/*.svg
  • landing/public/previews/flow-border-preview.svg is excluded by !**/*.svg
  • landing/public/previews/pulse-lines-preview.svg is excluded by !**/*.svg
  • landing/public/previews/reactive-border-preview.svg is excluded by !**/*.svg
  • landing/public/previews/ripple-flow-preview.svg is excluded by !**/*.svg
  • landing/public/previews/side-bars-preview.svg is excluded by !**/*.svg
  • landing/public/previews/side-braids-preview.svg is excluded by !**/*.svg
  • landing/public/previews/snow-particles-preview.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/customer-service.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/faq.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/github-svgrepo-com.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/home.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/menu.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/settings.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/sidebar.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/theme.svg is excluded by !**/*.svg
  • landing/public/sidebar-icons/tools.svg is excluded by !**/*.svg
  • landing/public/vercel.svg is excluded by !**/*.svg
  • landing/public/window.svg is excluded by !**/*.svg
  • landing/src/app/favicon.ico is excluded by !**/*.ico
📒 Files selected for processing (65)
  • landing/.gitignore
  • landing/AGENTS.md
  • landing/CLAUDE.md
  • landing/README.md
  • landing/eslint.config.mjs
  • landing/index.html
  • landing/next.config.ts
  • landing/package.json
  • landing/postcss.config.js
  • landing/postcss.config.mjs
  • landing/public/robots.txt
  • landing/public/sitemap.xml
  • landing/src/App.jsx
  • landing/src/app/api/download/route.ts
  • landing/src/app/faq/page.tsx
  • landing/src/app/globals.css
  • landing/src/app/installation/page.tsx
  • landing/src/app/layout.tsx
  • landing/src/app/page.tsx
  • landing/src/app/privacy/page.tsx
  • landing/src/app/requirements/page.tsx
  • landing/src/app/settings/page.tsx
  • landing/src/app/terms/page.tsx
  • landing/src/app/themes/page.tsx
  • landing/src/components/DownloadButton.tsx
  • landing/src/components/EdgePulseFrame.jsx
  • landing/src/components/FeaturesBento.tsx
  • landing/src/components/Footer.jsx
  • landing/src/components/Footer.tsx
  • landing/src/components/Logo.tsx
  • landing/src/components/SectionIntro.jsx
  • landing/src/components/SectionReveal.jsx
  • landing/src/components/Sidebar.jsx
  • landing/src/components/Sidebar.tsx
  • landing/src/components/ThemeComparisonModal.tsx
  • landing/src/components/ThemeShowcase.tsx
  • landing/src/components/pages/FAQPage.jsx
  • landing/src/components/pages/InstallationGuide.jsx
  • landing/src/components/pages/PrivacyPolicy.jsx
  • landing/src/components/pages/TermsPage.jsx
  • landing/src/components/previews/PreviewStage.jsx
  • landing/src/components/previews/ThemeCard.jsx
  • landing/src/components/sections/CTASection.jsx
  • landing/src/components/sections/ExperienceSection.jsx
  • landing/src/components/sections/HeroSection.jsx
  • landing/src/components/sections/ThemeShowcaseSection.jsx
  • landing/src/components/visualizers/AmbientWavePreview.tsx
  • landing/src/components/visualizers/AuroraDriftPreview.tsx
  • landing/src/components/visualizers/DotParticlesPreview.tsx
  • landing/src/components/visualizers/EdgeCrystalsPreview.tsx
  • landing/src/components/visualizers/FlowBorderPreview.tsx
  • landing/src/components/visualizers/PulseLinesPreview.tsx
  • landing/src/components/visualizers/ReactiveBorderPreview.tsx
  • landing/src/components/visualizers/RippleFlowPreview.tsx
  • landing/src/components/visualizers/SideBarsPreview.tsx
  • landing/src/components/visualizers/SideBraidsPreview.tsx
  • landing/src/components/visualizers/SnowParticlesPreview.tsx
  • landing/src/data/themes.js
  • landing/src/index.css
  • landing/src/lib/paraline-api.ts
  • landing/src/lib/utils.ts
  • landing/src/main.jsx
  • landing/tailwind.config.js
  • landing/tsconfig.json
  • landing/vite.config.js
💤 Files with no reviewable changes (25)
  • landing/public/robots.txt
  • landing/src/components/SectionReveal.jsx
  • landing/postcss.config.js
  • landing/public/sitemap.xml
  • landing/index.html
  • landing/src/components/pages/TermsPage.jsx
  • landing/src/components/sections/CTASection.jsx
  • landing/src/components/SectionIntro.jsx
  • landing/src/main.jsx
  • landing/vite.config.js
  • landing/tailwind.config.js
  • landing/src/data/themes.js
  • landing/src/index.css
  • landing/src/components/pages/PrivacyPolicy.jsx
  • landing/src/components/pages/InstallationGuide.jsx
  • landing/src/components/EdgePulseFrame.jsx
  • landing/src/components/sections/ThemeShowcaseSection.jsx
  • landing/src/components/Sidebar.jsx
  • landing/src/components/previews/PreviewStage.jsx
  • landing/src/components/sections/HeroSection.jsx
  • landing/src/components/Footer.jsx
  • landing/src/components/sections/ExperienceSection.jsx
  • landing/src/components/previews/ThemeCard.jsx
  • landing/src/App.jsx
  • landing/src/components/pages/FAQPage.jsx

Comment thread landing/README.md Outdated
Comment thread landing/src/app/api/download/route.ts
Comment thread landing/src/app/faq/page.tsx
Comment thread landing/src/app/globals.css
Comment thread landing/src/app/settings/page.tsx
Comment thread landing/src/components/ThemeShowcase.tsx
Comment thread landing/src/components/visualizers/AmbientWavePreview.tsx Outdated
Comment thread landing/src/components/visualizers/AuroraDriftPreview.tsx Outdated
Comment thread landing/src/components/visualizers/EdgeCrystalsPreview.tsx
Comment thread landing/src/components/visualizers/ReactiveBorderPreview.tsx Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
landing/src/components/ThemeShowcase.tsx (1)

302-363: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Toast and compare bar overlap at the same fixed position.

Both the "Activated" toast (Line 309, z-[100]) and the floating compare bar (Line 332, z-[90]) are pinned to fixed bottom-10 left-1/2 -translate-x-1/2. When a user has themes selected (compare bar visible) and then clicks a card to apply a theme, both render stacked at the same spot and visually collide. Consider offsetting one (e.g., raise the toast or hide the compare bar while a toast is showing).

🎨 One option: lift the toast above the compare bar when both are visible
-            className="fixed bottom-10 left-1/2 z-[100] -translate-x-1/2 flex items-center gap-4 rounded-full border border-white/10 bg-[`#0a0d16`]/90 px-5 py-3.5 shadow-[0_10px_40px_-10px_rgba(34,211,238,0.3)] backdrop-blur-xl"
+            className={`fixed left-1/2 z-[100] -translate-x-1/2 flex items-center gap-4 rounded-full border border-white/10 bg-[`#0a0d16`]/90 px-5 py-3.5 shadow-[0_10px_40px_-10px_rgba(34,211,238,0.3)] backdrop-blur-xl ${compareList.length > 0 && !isCompareModalOpen ? "bottom-28" : "bottom-10"}`}
🤖 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 `@landing/src/components/ThemeShowcase.tsx` around lines 302 - 363, The toast
("Activated" using appliedTheme) and the floating compare bar (driven by
compareList and isCompareModalOpen) are fixed to the same position and overlap;
fix by making one yield to the other — e.g., when appliedTheme is truthy, either
raise the toast (increase its bottom offset) or hide/shift the compare bar.
Update the JSX condition around the compare bar (the motion.div that checks
compareList.length > 0 && !isCompareModalOpen) to also require !appliedTheme, or
alternatively adjust the toast's className to a larger bottom value when
compareList.length > 0, referencing appliedTheme, compareList and
isCompareModalOpen to control visibility/position so the two elements no longer
collide.
🧹 Nitpick comments (1)
landing/src/components/ThemeShowcase.tsx (1)

242-298: ⚖️ Poor tradeoff

All theme previews mount and animate simultaneously.

Every card renders its theme.Preview for all 11 themes at once, and the canvas-based previews (e.g. AmbientWavePreview) run a continuous requestAnimationFrame loop regardless of active. On lower-spec machines this means ~11 concurrent animation loops on a single page, which can degrade scroll/interaction performance. Consider pausing previews that are offscreen (e.g. gate the RAF loop on an IntersectionObserver/whileInView visibility flag) or only animating the hovered card.

🤖 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 `@landing/src/components/ThemeShowcase.tsx` around lines 242 - 298, All
previews are mounting and running their RAF loops even when offscreen; update
ThemeShowcase so theme.Preview instances only mount or run animations when
visible or hovered. Specifically, use the motion.div viewport/whileInView or an
IntersectionObserver to derive a visibility flag per item and pass that to
theme.Preview (or conditionally render it) instead of always rendering
<theme.Preview active={hoveredTheme === theme.id} />; tie the flag to
hoveredTheme as well so the hovered card stays active. Locate the map over
specificThemes, the motion.div (viewport/whileInView), the hoveredTheme state,
and the theme.Preview usage to implement this gating.
🤖 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.

Outside diff comments:
In `@landing/src/components/ThemeShowcase.tsx`:
- Around line 302-363: The toast ("Activated" using appliedTheme) and the
floating compare bar (driven by compareList and isCompareModalOpen) are fixed to
the same position and overlap; fix by making one yield to the other — e.g., when
appliedTheme is truthy, either raise the toast (increase its bottom offset) or
hide/shift the compare bar. Update the JSX condition around the compare bar (the
motion.div that checks compareList.length > 0 && !isCompareModalOpen) to also
require !appliedTheme, or alternatively adjust the toast's className to a larger
bottom value when compareList.length > 0, referencing appliedTheme, compareList
and isCompareModalOpen to control visibility/position so the two elements no
longer collide.

---

Nitpick comments:
In `@landing/src/components/ThemeShowcase.tsx`:
- Around line 242-298: All previews are mounting and running their RAF loops
even when offscreen; update ThemeShowcase so theme.Preview instances only mount
or run animations when visible or hovered. Specifically, use the motion.div
viewport/whileInView or an IntersectionObserver to derive a visibility flag per
item and pass that to theme.Preview (or conditionally render it) instead of
always rendering <theme.Preview active={hoveredTheme === theme.id} />; tie the
flag to hoveredTheme as well so the hovered card stays active. Locate the map
over specificThemes, the motion.div (viewport/whileInView), the hoveredTheme
state, and the theme.Preview usage to implement this gating.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97b4daa0-118f-40a9-808a-f1db673a8a91

📥 Commits

Reviewing files that changed from the base of the PR and between 1cd0c5f and d75d010.

📒 Files selected for processing (12)
  • landing/README.md
  • landing/src/app/api/download/route.ts
  • landing/src/app/faq/page.tsx
  • landing/src/app/globals.css
  • landing/src/app/settings/page.tsx
  • landing/src/components/DownloadButton.tsx
  • landing/src/components/Logo.tsx
  • landing/src/components/ThemeShowcase.tsx
  • landing/src/components/visualizers/AmbientWavePreview.tsx
  • landing/src/components/visualizers/AuroraDriftPreview.tsx
  • landing/src/components/visualizers/EdgeCrystalsPreview.tsx
  • landing/src/components/visualizers/ReactiveBorderPreview.tsx
✅ Files skipped from review due to trivial changes (1)
  • landing/README.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • landing/src/components/visualizers/ReactiveBorderPreview.tsx
  • landing/src/components/visualizers/EdgeCrystalsPreview.tsx
  • landing/src/components/DownloadButton.tsx
  • landing/src/app/settings/page.tsx
  • landing/src/components/visualizers/AuroraDriftPreview.tsx
  • landing/src/app/globals.css
  • landing/src/app/faq/page.tsx
  • landing/src/app/api/download/route.ts

@SamXop123
Copy link
Copy Markdown
Owner

@Aspirant200715 This is absolute insanity man 💀 I feel like merging this right away, although still i have to do a little review.

but before that could you resolve these few merge conflicts?

@Aspirant200715
Copy link
Copy Markdown
Author

Hi @SamXop123, glad that you liked it
This took me 5 days to design. I will resolve the merge conflicts .

@Aspirant200715
Copy link
Copy Markdown
Author

Hi @SamXop123, I have put a lot of time into this. Kindly ensure I get a good number of points as part of my GSSOC contribution.

@SamXop123
Copy link
Copy Markdown
Owner

Hi @SamXop123, I have put a lot of time into this. Kindly ensure I get a good number of points as part of my GSSOC contribution.

sure, you dont have to worry about that

Copy link
Copy Markdown
Owner

@SamXop123 SamXop123 left a comment

Choose a reason for hiding this comment

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

incredible work. but there are few minor tweaks absolutely required to fix before we merge this pr:

  1. There is no scroll bar functionality in the sidebar. like i am using windows os currently at 100% browser zoom level(as u can see in the image) the bottom icons/buttons dissappear and there is no way to click them without zooming-out. we could add a scrollbar which dynamically gets visible as soon as the website is zoomed in or those buttons get beyond the browser screen.
Image
  1. also use the paraline official logo in the site, next to the title.

  2. add a toggle button for the sidebar that can close/open upon user preference. if the sidebar is toggled off, move the elements to the left as well so that they are at center. keep the sidebar as active by default.

also there are a few other things as well like the mobile menu, the configuration section, etc, but i dont feel like putting too much pressure on you.., they could be fixed gradually later on.

For now just fix the mentioned things.

@Aspirant200715
Copy link
Copy Markdown
Author

Ok, sir, I will implement these. Give me some time.

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.

UI Enhancement Proposal — Modernize and Improve Overall User Experience

2 participants