Feat/landing page redesign#166
Conversation
# 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
|
@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. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughMigrates 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. ChangesNext.js Landing Migration
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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: 15
🧹 Nitpick comments (5)
landing/src/components/visualizers/DotParticlesPreview.tsx (1)
43-53: ⚡ Quick winAvoid
Math.random()inside render-time animation propsRandomizing 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 winAdd 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 theanimate/transitionprops makes render impure.
baseWidth + Math.random() * 30(Lines 23, 49) and the randomduration/delayare 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 smallEqualizerBar(or precomputing the random targets once viauseMemo/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 theanimate.xkeyframes (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 tradeoffAccessibility: honor
prefers-reduced-motionin visualizer animations (landing/src/components/visualizers/EdgeCrystalsPreview.tsx:23-33)Motion v12 exposes
useReducedMotion(import frommotion/react) which returns whether the user enabled “Reduce motion”. Gate the loopingrepeat: Infinityanimation (e.g., fall back to the staticactive === falsestate) when it’s enabled; ideally apply this across the whole visualizer cohort (e.g., viaMotionConfigwith areducedMotionpolicy).🤖 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
⛔ Files ignored due to path filters (28)
landing/package-lock.jsonis excluded by!**/package-lock.jsonlanding/public/appicon.pngis excluded by!**/*.pnglanding/public/file.svgis excluded by!**/*.svglanding/public/globe.svgis excluded by!**/*.svglanding/public/next.svgis excluded by!**/*.svglanding/public/previews/ambient-wave-preview.svgis excluded by!**/*.svglanding/public/previews/aurora-drift-preview.svgis excluded by!**/*.svglanding/public/previews/dot-particles-preview.svgis excluded by!**/*.svglanding/public/previews/edge-crystals-preview.svgis excluded by!**/*.svglanding/public/previews/flow-border-preview.svgis excluded by!**/*.svglanding/public/previews/pulse-lines-preview.svgis excluded by!**/*.svglanding/public/previews/reactive-border-preview.svgis excluded by!**/*.svglanding/public/previews/ripple-flow-preview.svgis excluded by!**/*.svglanding/public/previews/side-bars-preview.svgis excluded by!**/*.svglanding/public/previews/side-braids-preview.svgis excluded by!**/*.svglanding/public/previews/snow-particles-preview.svgis excluded by!**/*.svglanding/public/sidebar-icons/customer-service.svgis excluded by!**/*.svglanding/public/sidebar-icons/faq.svgis excluded by!**/*.svglanding/public/sidebar-icons/github-svgrepo-com.svgis excluded by!**/*.svglanding/public/sidebar-icons/home.svgis excluded by!**/*.svglanding/public/sidebar-icons/menu.svgis excluded by!**/*.svglanding/public/sidebar-icons/settings.svgis excluded by!**/*.svglanding/public/sidebar-icons/sidebar.svgis excluded by!**/*.svglanding/public/sidebar-icons/theme.svgis excluded by!**/*.svglanding/public/sidebar-icons/tools.svgis excluded by!**/*.svglanding/public/vercel.svgis excluded by!**/*.svglanding/public/window.svgis excluded by!**/*.svglanding/src/app/favicon.icois excluded by!**/*.ico
📒 Files selected for processing (65)
landing/.gitignorelanding/AGENTS.mdlanding/CLAUDE.mdlanding/README.mdlanding/eslint.config.mjslanding/index.htmllanding/next.config.tslanding/package.jsonlanding/postcss.config.jslanding/postcss.config.mjslanding/public/robots.txtlanding/public/sitemap.xmllanding/src/App.jsxlanding/src/app/api/download/route.tslanding/src/app/faq/page.tsxlanding/src/app/globals.csslanding/src/app/installation/page.tsxlanding/src/app/layout.tsxlanding/src/app/page.tsxlanding/src/app/privacy/page.tsxlanding/src/app/requirements/page.tsxlanding/src/app/settings/page.tsxlanding/src/app/terms/page.tsxlanding/src/app/themes/page.tsxlanding/src/components/DownloadButton.tsxlanding/src/components/EdgePulseFrame.jsxlanding/src/components/FeaturesBento.tsxlanding/src/components/Footer.jsxlanding/src/components/Footer.tsxlanding/src/components/Logo.tsxlanding/src/components/SectionIntro.jsxlanding/src/components/SectionReveal.jsxlanding/src/components/Sidebar.jsxlanding/src/components/Sidebar.tsxlanding/src/components/ThemeComparisonModal.tsxlanding/src/components/ThemeShowcase.tsxlanding/src/components/pages/FAQPage.jsxlanding/src/components/pages/InstallationGuide.jsxlanding/src/components/pages/PrivacyPolicy.jsxlanding/src/components/pages/TermsPage.jsxlanding/src/components/previews/PreviewStage.jsxlanding/src/components/previews/ThemeCard.jsxlanding/src/components/sections/CTASection.jsxlanding/src/components/sections/ExperienceSection.jsxlanding/src/components/sections/HeroSection.jsxlanding/src/components/sections/ThemeShowcaseSection.jsxlanding/src/components/visualizers/AmbientWavePreview.tsxlanding/src/components/visualizers/AuroraDriftPreview.tsxlanding/src/components/visualizers/DotParticlesPreview.tsxlanding/src/components/visualizers/EdgeCrystalsPreview.tsxlanding/src/components/visualizers/FlowBorderPreview.tsxlanding/src/components/visualizers/PulseLinesPreview.tsxlanding/src/components/visualizers/ReactiveBorderPreview.tsxlanding/src/components/visualizers/RippleFlowPreview.tsxlanding/src/components/visualizers/SideBarsPreview.tsxlanding/src/components/visualizers/SideBraidsPreview.tsxlanding/src/components/visualizers/SnowParticlesPreview.tsxlanding/src/data/themes.jslanding/src/index.csslanding/src/lib/paraline-api.tslanding/src/lib/utils.tslanding/src/main.jsxlanding/tailwind.config.jslanding/tsconfig.jsonlanding/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
There was a problem hiding this comment.
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 winToast 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 tofixed 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 tradeoffAll theme previews mount and animate simultaneously.
Every card renders its
theme.Previewfor all 11 themes at once, and the canvas-based previews (e.g.AmbientWavePreview) run a continuousrequestAnimationFrameloop regardless ofactive. 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 anIntersectionObserver/whileInViewvisibility 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
📒 Files selected for processing (12)
landing/README.mdlanding/src/app/api/download/route.tslanding/src/app/faq/page.tsxlanding/src/app/globals.csslanding/src/app/settings/page.tsxlanding/src/components/DownloadButton.tsxlanding/src/components/Logo.tsxlanding/src/components/ThemeShowcase.tsxlanding/src/components/visualizers/AmbientWavePreview.tsxlanding/src/components/visualizers/AuroraDriftPreview.tsxlanding/src/components/visualizers/EdgeCrystalsPreview.tsxlanding/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
|
@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? |
|
Hi @SamXop123, glad that you liked it |
|
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 |
SamXop123
left a comment
There was a problem hiding this comment.
incredible work. but there are few minor tweaks absolutely required to fix before we merge this pr:
- 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.
-
also use the paraline official logo in the site, next to the title.
-
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.
|
Ok, sir, I will implement these. Give me some time. |
📝 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
landingdirectory has been ported to Next.js 15, utilizing React 19./,/faq,/settings,/requirements,/themes, etc.) are now statically prerendered for instantaneous time-to-interactive (TTI) and optimal SEO.index.html. Introducednext.config.tsand Next. js-specific PostCSS modules.2. State Management & Animations
framer-motionorchestration across all components. Layout transitions, modal pop-ups, and accordion expansions are now driven by spring physics (e.g.,stiffness: 400, damping: 25).createPortal): Engineered the Comparison Modal to escape local DOM hierarchies and stacking contexts by portaling directly todocument.bodywithz-[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
#060913dark-mode base, significantly elevating the brand's premium feel.blur-[120px]) radial gradients usingmix-blend-screento create dynamic, overlapping light pools in the background.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.tsxandThemeComparisonModal.tsx.3. Component Deep-Dives
/settings: Rebuilt the Configuration view. Added custom SVG icons, interactive toggle switches with smoothtranslateXtransitions, 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 anAnimatePresencedriven 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.

3. Settings & Hardware Requirements
The redesigned glassmorphic bento grids.




🔧 Upstream Sync & Testing
SamXop123/Paralineinto this branch.modify/deleteconflicts by accepting deletions for the legacy React/Vite architecture components that were replaced by the App Router.npm run buildgenerates 12/12 static pages with 0 TypeScript/ESLint errors in <4 seconds.Reviewer Notes: Please pay special attention to
ThemeComparisonModal.tsxand 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
Documentation