Skip to content

(SP 2) [Frontend] Update Features section content and improve mobile UX#224

Merged
ViktorSvertoka merged 7 commits into
developfrom
yd/feat/about/visuals-and-content-update
Jan 28, 2026
Merged

(SP 2) [Frontend] Update Features section content and improve mobile UX#224
ViktorSvertoka merged 7 commits into
developfrom
yd/feat/about/visuals-and-content-update

Conversation

@yevheniidatsenko
Copy link
Copy Markdown
Collaborator

@yevheniidatsenko yevheniidatsenko commented Jan 28, 2026

Description

This PR overhauls the About Page visuals and content to better reflect platform capabilities, specifically upgrading the Features and Pricing sections. It introduces dynamic background effects, refines feature messaging based on recent audits, and significantly improves mobile responsiveness.


Changes

🎨 Visual & UI Enhancements

  • Pricing Section: Integrated new [ParticleCanvas]
  • Features Section:
    • Implemented smoother tab transitions and bubble animations.
    • Added GradientBadge component for consistent section labeling.
    • Improved mobile layout: Adjusted feature bubble scaling to prevent overlap on smaller screens.

🧩 New Components

  • [components/ui/particle-canvas.tsx]: Canvas-based particle animation system.
  • [components/ui/gradient-badge.tsx]: Reusable badge with gradient border.
  • [components/ui/section-heading.tsx]: Standardized heading component for About page sections.

How Has This Been Tested?

  • Locally: specific styling and animations verified on localhost:3000.
  • Mobile Check: Verified layout on mobile viewports (Chrome DevTools).
  • Content: Verified all new feature text and icons appear correctly.
  • Accessibility: Checked color contrast and tab navigation.

Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • New Features

    • New animation utilities with reduced-motion support
    • Interactive particle canvas with morphing shapes
    • Data-driven, animated Features showcase plus new GradientBadge and SectionHeading components
  • Style

    • Visual refresh across About pages: spacing, gradients, translucency, typography, responsive tweaks
    • Updated pricing visuals, testimonial card treatments, hero text sizing/flow, and sponsor CTA styling
  • Accessibility

    • Improved ARIA attributes and semantics for decorative and interactive elements

✏️ Tip: You can customize this high-level summary in your review settings.

- Features Section: Refined feature content and visuals.
- Mobile UX: Improved responsive layout and scaling for feature cards and interactive elements.
- Visual Enhancements: Added dynamic particle background effects to the Pricing section.
@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 28, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit b29bd7f
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/697a454aeb6fb40008eecc98
😎 Deploy Preview https://deploy-preview-224--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Adds global animation utilities/keyframes, three new UI primitives (GradientBadge, SectionHeading, ParticleCanvas), and refactors multiple About-page sections to a data-driven, responsive implementation with accessibility and styling updates.

Changes

Cohort / File(s) Summary
Global Styles
frontend/app/globals.css
Adds animation utilities (animate-float, animate-spin-slow, animate-spin-slower, animate-dash-flow), keyframes (float, dash-flow), and a prefers-reduced-motion media safeguard.
New UI Primitives
frontend/components/ui/gradient-badge.tsx, frontend/components/ui/section-heading.tsx, frontend/components/ui/particle-canvas.tsx
Adds GradientBadge and SectionHeading components; introduces ParticleCanvas (client-side particle system with precomputed shapes, morph transitions, render loop, and exported component/API).
About: Features
frontend/components/about/FeaturesSection.tsx
Replaces static visuals with data-driven Page/Feature models and modular primitives (FeatureBubble, CentralIcon, OrbitRings, DecorativeDots, ConnectingLines, TabButton); adds resize handling and keyboard navigation.
About: Pricing
frontend/components/about/PricingSection.tsx
Introduces activeShape state and integrates ParticleCanvas; hover/focus drive canvas shape transitions; swaps to GradientBadge/SectionHeading; accessibility and layout refinements.
About: Hero / Community / Sponsors / Topics
frontend/components/about/HeroSection.tsx, frontend/components/about/CommunitySection.tsx, frontend/components/about/SponsorsWall.tsx, frontend/components/about/TopicsSection.tsx
Typography, spacing, and visual token updates; replaces inline headers with GradientBadge/SectionHeading; ARIA attributes and glass/blur/hover style adjustments.
Misc About adjustments
frontend/components/about/*
Import reordering, class reorganizations, small copy edits, and accessibility refinements across several about-page subcomponents.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as "User"
  participant Pricing as "PricingSection"
  participant Canvas as "ParticleCanvas"
  participant RAF as "requestAnimationFrame"

  rect rgba(135,206,235,0.5)
  User->>Pricing: hover/focus pricing card (select shape)
  end

  Pricing->>Pricing: set activeShape state
  Pricing->>Canvas: pass updated props.activeShape
  Canvas->>Canvas: begin shape transition (easeInOutCubic)
  Canvas->>RAF: requestAnimationFrame(loop)
  RAF->>Canvas: render frame (update particle positions toward targets)
  Canvas-->>Pricing: canvas visuals update
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

UI, refactor

Suggested reviewers

  • ViktorSvertoka
  • AM1007

Poem

🐇
I hop through pixels with a merry spin,
Badges gleam and particles begin.
Brackets, hearts, in gentle flight—
The About page shimmers through the night. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly aligns with the primary changes: FeaturesSection was substantially refactored with new data-driven rendering and mobile responsiveness improvements, and multiple UI components were added to enhance the About page visuals.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
Contributor

@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: 5

Caution

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

⚠️ Outside diff range comments (2)
frontend/components/about/SponsorsWall.tsx (1)

46-62: Add rel="noopener noreferrer" to external links opened in a new tab.
This prevents reverse‑tabnabbing and is a standard security hardening step.

🔒 Proposed fix
-        <Link 
-            href="https://github.com/sponsors/DevLoversTeam" 
-            target="_blank"
+        <Link 
+            href="https://github.com/sponsors/DevLoversTeam" 
+            target="_blank"
+            rel="noopener noreferrer"
             aria-label="Become a sponsor to claim your spot"
             className="relative flex items-center justify-center w-10 h-10 rounded-full border-2 border-dashed border-gray-300 dark:border-white/20 hover:border-[`#1e5eff`] dark:hover:border-[`#ff2d55`] bg-transparent hover:bg-[`#1e5eff`]/5 dark:hover:bg-[`#ff2d55`]/5 transition-all group/cta"
         >
…
-        <Link href="https://github.com/sponsors/DevLoversTeam" target="_blank" className="hidden sm:block ml-3 mr-2 text-xs font-bold text-gray-500 hover:text-[`#1e5eff`] dark:hover:text-[`#ff2d55`] transition-colors">
+        <Link href="https://github.com/sponsors/DevLoversTeam" target="_blank" rel="noopener noreferrer" className="hidden sm:block ml-3 mr-2 text-xs font-bold text-gray-500 hover:text-[`#1e5eff`] dark:hover:text-[`#ff2d55`] transition-colors">
frontend/components/about/CommunitySection.tsx (1)

49-92: Add rel="noopener noreferrer" to external links opened in a new tab.
This prevents reverse‑tabnabbing and is a standard security hardening step.

🔒 Proposed fix
-                    <Link
-                        href="https://github.com/DevLoversTeam/devlovers.net/discussions"
-                        target="_blank"
+                    <Link
+                        href="https://github.com/DevLoversTeam/devlovers.net/discussions"
+                        target="_blank"
+                        rel="noopener noreferrer"
                         className="group inline-flex items-center gap-1.5 px-4 py-2 rounded-full
…
-                <Link
-                    href="https://github.com/DevLoversTeam/devlovers.net/discussions"
-                    target="_blank"
+                <Link
+                    href="https://github.com/DevLoversTeam/devlovers.net/discussions"
+                    target="_blank"
+                    rel="noopener noreferrer"
                     className="group relative hidden md:inline-flex items-center justify-center gap-4 p-1.5 pl-6 pr-1.5 rounded-full
🤖 Fix all issues with AI agents
In `@frontend/components/about/FeaturesSection.tsx`:
- Around line 42-44: The string for blog.description is grammatically incorrect
("Stay updated. detailed articles..."); update the user-facing copy for the
"blog.description" key so it is a single, well-formed sentence (e.g., "Stay
updated with detailed articles on tech trends, coding tutorials, and industry
insights to keep you ahead of the curve.") by editing the value in
FeaturesSection.tsx where the "blog.description" key is defined.

In `@frontend/components/about/HeroSection.tsx`:
- Around line 32-34: Remove the aria-hidden attribute from the wrapper div that
renders the InteractiveGame component so its interactive buttons and keyboard
handlers (e.g., the X exit, Retry, play area, Space/ArrowUp, Escape handlers in
InteractiveGame) remain accessible to screen readers; instead, if you need
purely decorative semantics for the wrapper, convert it to a non-hiding
decorative element (or add an appropriate aria-label/role="img" on a separate
decorative element) and ensure the wrapper does not conceal focusable children
or their event handlers.

In `@frontend/components/ui/gradient-badge.tsx`:
- Around line 9-16: The GradientBadge component is concatenating className
directly which can emit a literal "undefined" token when className is not
provided; update the GradientBadge render to guard/normalize the prop (e.g.,
default className to an empty string or use conditional concatenation) so the
template string never includes "undefined" — adjust the GradientBadge function
signature or the className interpolation to use (className || '') or similar to
ensure safe classes.

In `@frontend/components/ui/particle-canvas.tsx`:
- Around line 147-345: Effect reinitializes 800 particles every time activeShape
changes, causing visible jumps; stop recreating particles by removing
activeShape from the useEffect dependency and instead read activeShape via a
ref. Change the effect to use an empty dependency array so initParticles,
resizeCanvas and draw run only once, add a ref (e.g., activeShapeRef) that you
update inside a separate useEffect when activeShape changes, and have
draw/readers use activeShapeRef.current (and prevShapeRef.current) instead of
the activeShape prop; keep particles.current, timeRef.current,
animationFrameId.current, initParticles and draw intact to preserve the running
loop and only update shape state via the ref to avoid teardown/reinit.

In `@frontend/components/ui/section-heading.tsx`:
- Around line 9-12: The JSX in SectionHeading is concatenating className
directly which stringifies undefined into "undefined"; update the SectionHeading
signature or render logic to provide a safe default (e.g., default className =
"" in the function parameters or normalize className before use) and use that
safe value in the template string so the literal "undefined" is never emitted;
reference SectionHeading and the className prop to locate and fix the code.
🧹 Nitpick comments (2)
frontend/app/globals.css (1)

334-372: Respect prefers-reduced-motion for the new infinite animations.
These run continuously and should be disabled for users who request reduced motion.

♿ Suggested accessibility tweak
+@media (prefers-reduced-motion: reduce) {
+  .animate-float,
+  .animate-spin-slow,
+  .animate-spin-slower,
+  .animate-dash-flow {
+    animation: none !important;
+  }
+}
frontend/components/about/PricingSection.tsx (1)

45-49: Mirror hover-driven visuals for keyboard focus.
Right now only pointer hover updates activeShape. Add focus/blur handlers so keyboard users get the same visual feedback.

♿ Suggested improvement
 <motion.div 
   whileHover={{ y: -5 }}
   onMouseEnter={() => setActiveShape("brackets")}
   onMouseLeave={() => setActiveShape(null)}
+  onFocus={() => setActiveShape("brackets")}
+  onBlur={() => setActiveShape(null)}
   className="flex flex-col p-8 lg:p-10 rounded-3xl border border-gray-200 dark:border-neutral-800 bg-white/10 dark:bg-neutral-900/10 backdrop-blur-md shadow-sm relative z-10"
 >
@@
 <motion.div 
   whileHover={{ y: -5 }}
   onMouseEnter={() => setActiveShape("heart")}
   onMouseLeave={() => setActiveShape(null)}
+  onFocus={() => setActiveShape("heart")}
+  onBlur={() => setActiveShape(null)}
   className="relative flex flex-col p-8 lg:p-10 rounded-3xl overflow-hidden backdrop-blur-md z-10
     border border-[`#1e5eff`]/30 dark:border-[`#ff2d55`]/30
     bg-gradient-to-b from-[`#1e5eff`]/5 to-white/10 dark:from-[`#ff2d55`]/10 dark:to-neutral-900/10"
 >

Also applies to: 87-91

Comment thread frontend/components/about/FeaturesSection.tsx
Comment thread frontend/components/about/HeroSection.tsx Outdated
Comment thread frontend/components/ui/gradient-badge.tsx Outdated
Comment on lines +147 to +345
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return

const ctx = canvas.getContext("2d")
if (!ctx) return

const resizeCanvas = () => {
canvas.width = canvas.parentElement?.offsetWidth || window.innerWidth
canvas.height = canvas.parentElement?.offsetHeight || window.innerHeight
initParticles(canvas.width, canvas.height)
}

const initParticles = (width: number, height: number) => {
const count = 800
particles.current = []

for (let i = 0; i < count; i++) {
const floatX = Math.random() * width
const floatY = Math.random() * height

const speed = 0.2 + Math.random() * 0.3
const angle = Math.random() * Math.PI * 2

particles.current.push({
x: floatX,
y: floatY,
z: 0,
vx: 0,
vy: 0,
vz: 0,
floatX,
floatY,
floatVx: Math.cos(angle) * speed,
floatVy: Math.sin(angle) * speed,
})
}
}

const draw = () => {
if (!canvas || !ctx) return
ctx.clearRect(0, 0, canvas.width, canvas.height)

timeRef.current += 0.016

// Linear transition - no initial freeze
const inSpeed = 0.012
const outSpeed = 0.006 // Slower out
if (targetTransitionRef.current > transitionRef.current) {
// Going IN
transitionRef.current = Math.min(targetTransitionRef.current, transitionRef.current + inSpeed)
} else if (targetTransitionRef.current < transitionRef.current) {
// Going OUT - slow and smooth
transitionRef.current = Math.max(targetTransitionRef.current, transitionRef.current - outSpeed)
}

// Apply smooth easing
const rawProgress = Math.max(0, Math.min(1, transitionRef.current))
const progress = easeInOutCubic(rawProgress)

const { r, g, b, isDark } = getThemeColors()

const isMobileView = canvas.width < 768

const currentShape = activeShape || prevShapeRef.current
const shapePoints =
currentShape === "brackets"
? SHAPE_POINTS_BRACKETS
: currentShape === "heart"
? SHAPE_POINTS_HEART
: null

// 3D rotation - always moving
const angle = timeRef.current * 0.4
const cos = Math.cos(angle)
const sin = Math.sin(angle)

particles.current.forEach((p, i) => {
// Always update floating positions
p.floatX += p.floatVx
p.floatY += p.floatVy

if (p.floatX < 0 || p.floatX > canvas.width) {
p.floatVx *= -1
p.floatX = Math.max(0, Math.min(canvas.width, p.floatX))
}
if (p.floatY < 0 || p.floatY > canvas.height) {
p.floatVy *= -1
p.floatY = Math.max(0, Math.min(canvas.height, p.floatY))
}

// Calculate shape position
let shapeX = p.floatX
let shapeY = p.floatY

if (isMobileView) {
// Mobile: show both shapes - first half brackets, second half heart
const halfCount = Math.floor(particles.current.length / 2)
const isFirstHalf = i < halfCount
const localIndex = isFirstHalf ? i : i - halfCount
const mobileShapePoints = isFirstHalf ? SHAPE_POINTS_BRACKETS : SHAPE_POINTS_HEART
const shapePoint = mobileShapePoints[localIndex % mobileShapePoints.length]

const rotatedX = shapePoint.x * cos - shapePoint.z * sin
const rotatedZ = shapePoint.x * sin + shapePoint.z * cos
const rotatedY = shapePoint.y
const perspective = 3
const scale = perspective / (perspective + rotatedZ)
const shapeScale = Math.min(canvas.width, canvas.height) * 0.7

// Position: centered on each card
const centerX = canvas.width / 2
const centerY = isFirstHalf ? canvas.height * 0.32 : canvas.height * 0.68

shapeX = centerX + rotatedX * shapeScale * scale
shapeY = centerY + rotatedY * shapeScale * scale
} else if (shapePoints) {
// Desktop: original hover behavior
let centerX = canvas.width / 2
const centerY = canvas.height / 2
if (currentShape === "brackets") centerX = canvas.width * 0.25
if (currentShape === "heart") centerX = canvas.width * 0.75

const shapePoint = shapePoints[i % shapePoints.length]
const rotatedX = shapePoint.x * cos - shapePoint.z * sin
const rotatedZ = shapePoint.x * sin + shapePoint.z * cos
const rotatedY = shapePoint.y
const perspective = 3
const scale = perspective / (perspective + rotatedZ)
const shapeScale = Math.min(canvas.width, canvas.height) * 0.35
shapeX = centerX + rotatedX * shapeScale * scale
shapeY = centerY + rotatedY * shapeScale * scale
}

// Target position - on mobile always full shape, on desktop based on hover progress
const effectiveProgress = isMobileView ? 1 : progress
const targetX = p.floatX + (shapeX - p.floatX) * effectiveProgress
const targetY = p.floatY + (shapeY - p.floatY) * effectiveProgress

// Smooth spring physics - gentle force, high damping
const springForce = 0.04 // Gentle spring
const damping = 0.92 // High damping for smooth motion

// Add spring force toward target
p.vx += (targetX - p.x) * springForce
p.vy += (targetY - p.y) * springForce

// Apply damping
p.vx *= damping
p.vy *= damping

// Update position
p.x += p.vx
p.y += p.vy

// Alpha - on mobile always visible, on desktop based on progress
const alpha = isMobileView ? 0.3 : (0.15 + 0.45 * progress)

ctx.beginPath()
ctx.arc(p.x, p.y, 1.5, 0, Math.PI * 2)
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`
ctx.fill()
})

// Connecting lines when in shape
if (progress > 0.5 && shapePoints) {
const lineAlpha = (progress - 0.5) * 0.2
ctx.globalAlpha = lineAlpha
ctx.lineWidth = 0.5
ctx.strokeStyle = isDark ? "#ff2d55" : "#1e5eff"
ctx.beginPath()

for (let i = 0; i < particles.current.length; i += 4) {
const p1 = particles.current[i]
for (let j = 1; j <= 4; j++) {
const p2 = particles.current[(i + j) % particles.current.length]
const distSq = (p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2
if (distSq < 35 * 35) {
ctx.moveTo(p1.x, p1.y)
ctx.lineTo(p2.x, p2.y)
}
}
}
ctx.stroke()
ctx.globalAlpha = 1.0
}

animationFrameId.current = requestAnimationFrame(draw)
}

resizeCanvas()
window.addEventListener("resize", resizeCanvas)
draw()

return () => {
window.removeEventListener("resize", resizeCanvas)
if (animationFrameId.current) cancelAnimationFrame(animationFrameId.current)
}
}, [activeShape])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine the actual useEffect dependency array
fd "particle-canvas.tsx" -t f

Repository: DevLoversTeam/devlovers.net

Length of output: 113


🏁 Script executed:

# Get the actual file content around lines 147-345
if [ -f "frontend/components/ui/particle-canvas.tsx" ]; then
  wc -l "frontend/components/ui/particle-canvas.tsx"
fi

Repository: DevLoversTeam/devlovers.net

Length of output: 117


🏁 Script executed:

# Read the main useEffect to check the dependency array
if [ -f "frontend/components/ui/particle-canvas.tsx" ]; then
  sed -n '147,350p' "frontend/components/ui/particle-canvas.tsx" | tail -10
fi

Repository: DevLoversTeam/devlovers.net

Length of output: 328


🏁 Script executed:

# Read the full useEffect starting from line 147
sed -n '147,348p' "frontend/components/ui/particle-canvas.tsx"

Repository: DevLoversTeam/devlovers.net

Length of output: 7237


🏁 Script executed:

# Check the beginning of the file to see the component structure and refs
sed -n '1,50p' "frontend/components/ui/particle-canvas.tsx"

Repository: DevLoversTeam/devlovers.net

Length of output: 1217


🏁 Script executed:

# Verify there's no other initParticles call in the file
rg "initParticles" "frontend/components/ui/particle-canvas.tsx"

Repository: DevLoversTeam/devlovers.net

Length of output: 182


Avoid reinitializing particles on every hover change.

The effect depends on activeShape, causing teardown and reinitialization of 800 particles on each hover state change. This creates visible animation jumps. Keep the animation loop stable by using an empty dependency array and reading the current shape via a ref instead.

🛠️ Suggested fix
 export function ParticleCanvas({ activeShape, className }: ParticleCanvasProps) {
   const canvasRef = useRef<HTMLCanvasElement>(null)
   const particles = useRef<Point[]>([])
   const animationFrameId = useRef<number | undefined>(undefined)
   const timeRef = useRef(0)

   // Simple transition: 0 = floating, 1 = shape
   const transitionRef = useRef(0)
   const targetTransitionRef = useRef(0)
   const prevShapeRef = useRef<"brackets" | "heart" | null>(null)
   const justLeftShapeRef = useRef(false)
+  const activeShapeRef = useRef<"brackets" | "heart" | null>(activeShape)

   useEffect(() => {
+    activeShapeRef.current = activeShape
     const wasInShape = targetTransitionRef.current === 1
     targetTransitionRef.current = activeShape ? 1 : 0
     if (activeShape) {
       prevShapeRef.current = activeShape
       justLeftShapeRef.current = false
     } else if (wasInShape) {
       justLeftShapeRef.current = true
       // Gentle nudge instead of hard push
       particles.current.forEach(p => {
         p.vx *= 0.5
         p.vy *= 0.5
       })
     }
   }, [activeShape])

   useEffect(() => {
     const canvas = canvasRef.current
     if (!canvas) return
@@
-      const currentShape = activeShape || prevShapeRef.current
+      const currentShape = activeShapeRef.current || prevShapeRef.current
@@
-  }, [activeShape])
+  }, [])
🤖 Prompt for AI Agents
In `@frontend/components/ui/particle-canvas.tsx` around lines 147 - 345, Effect
reinitializes 800 particles every time activeShape changes, causing visible
jumps; stop recreating particles by removing activeShape from the useEffect
dependency and instead read activeShape via a ref. Change the effect to use an
empty dependency array so initParticles, resizeCanvas and draw run only once,
add a ref (e.g., activeShapeRef) that you update inside a separate useEffect
when activeShape changes, and have draw/readers use activeShapeRef.current (and
prevShapeRef.current) instead of the activeShape prop; keep particles.current,
timeRef.current, animationFrameId.current, initParticles and draw intact to
preserve the running loop and only update shape state via the ref to avoid
teardown/reinit.

Comment thread frontend/components/ui/section-heading.tsx Outdated
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/components/about/PricingSection.tsx`:
- Line 20: The section's aria-labelledby="pricing-heading" is broken because no
element with id "pricing-heading" is rendered; fix by ensuring a heading with
that id exists—either extend SectionHeading to accept and pass an id prop
through to its rendered <h2> (update SectionHeading's props to include id and
forward it) or, more simply, add a visually-hidden <h2
id="pricing-heading">Pricing</h2> inside PricingSection (use your app's existing
utility class for visually-hidden) so the aria reference resolves and
accessibility is restored.
🧹 Nitpick comments (4)
frontend/components/ui/particle-canvas.tsx (1)

349-349: Consider adding aria-hidden="true" for accessibility clarity.

Since this canvas is purely decorative, explicitly marking it as hidden from assistive technologies would be beneficial.

♻️ Suggested improvement
-  return <canvas ref={canvasRef} className={className} />
+  return <canvas ref={canvasRef} className={className} aria-hidden="true" />
frontend/components/about/PricingSection.tsx (1)

11-11: Unused import: cn utility is not used in this file.

The cn utility is imported but never referenced in the component.

♻️ Remove unused import
-import { cn } from "@/lib/utils"
frontend/components/about/FeaturesSection.tsx (2)

276-303: Consider enhancing tab accessibility with ARIA tab pattern.

The current implementation uses aria-current which is acceptable, but for a tab-like interface, the ARIA tabs pattern (role="tablist", role="tab", aria-selected) would provide better screen reader semantics.

♻️ Enhanced accessibility pattern
 function TabButton({ page, isActive, onClick }: { page: Page; isActive: boolean; onClick: () => void }) {
     return (
         <button
             onClick={onClick}
-            aria-label={t(`${page.id}.title`)}
-            aria-current={isActive ? 'true' : 'false'}
+            role="tab"
+            aria-selected={isActive}
+            aria-controls={`${page.id}-panel`}
             className={`relative p-2.5 md:px-5 md:py-2.5 rounded-full...`}
         >

And update the container in FeaturesSection:

-                    <div className="inline-flex gap-1 md:gap-2 p-1.5 rounded-full...">
+                    <div role="tablist" aria-label="Feature categories" className="inline-flex gap-1 md:gap-2 p-1.5 rounded-full...">

307-315: Potential hydration mismatch with isMobile state.

The isMobile state initializes to false on the server but may be true on the client if the viewport is narrow. This can cause a hydration mismatch warning in Next.js. Since it only affects visual scaling (not functionality), consider initializing based on a CSS approach or using a hook that handles SSR gracefully.

♻️ SSR-safe alternative using CSS

Instead of JavaScript-based detection, consider using CSS custom properties or responsive Tailwind classes directly in FeatureBubble:

// In FeatureBubble, replace isMobile prop usage with responsive classes:
const posX = feature.x  // Use base value
const posY = feature.y

// Then use CSS transforms with media queries in className or inline styles
style={{
  '--scale-x': 'var(--mobile-scale-x, 1)',
  '--scale-y': 'var(--mobile-scale-y, 1)',
}}

Or suppress the warning if the visual flash is acceptable:

-    const [isMobile, setIsMobile] = useState(false)
+    const [isMobile, setIsMobile] = useState(false)
+    const [mounted, setMounted] = useState(false)
+
+    useEffect(() => {
+        setMounted(true)
+    }, [])

Comment thread frontend/components/about/PricingSection.tsx
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/components/about/FeaturesSection.tsx`:
- Around line 276-395: The TabButton's aria-controls points to
`${page.id}-panel` but there is no corresponding panel element — update
TabButton to add an id (e.g. id={`${page.id}-tab`}) so each button has an
accessible tab id, and then update the panel container (the motion.div keyed by
activeTab inside FeaturesSection that renders the features) to include
role="tabpanel", id={`${activeTab}-panel`} and
aria-labelledby={`${activeTab}-tab`} so the tab/tabpanel ARIA relationship is
correctly wired; touch up attributes on TabButton (aria-controls remains
`${page.id}-panel`) and the panel container (role/id/aria-labelledby)
accordingly.
🧹 Nitpick comments (1)
frontend/components/ui/particle-canvas.tsx (1)

188-219: Consider using actual delta time for frame-rate independence.

The hardcoded 0.016 increment assumes 60fps. On high-refresh displays (120/144Hz), animations will appear faster. For decorative purposes this is acceptable, but using performance.now() delta would ensure consistent animation speed across devices.

Comment thread frontend/components/about/FeaturesSection.tsx Outdated
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/components/ui/particle-canvas.tsx`:
- Around line 189-199: The draw function can get a huge deltaTime after tab
backgrounding; clamp deltaTime right after it's computed in draw (where
deltaTime is derived from lastTimeRef and timestamp) to a sensible max (e.g.,
0.03–0.1s) before updating lastTimeRef.current and timeRef.current so particles
don't jump; update the code that computes deltaTime in draw to set deltaTime =
Math.min(deltaTime, MAX_DELTA) (define MAX_DELTA as a constant) and then proceed
with clearing the canvas and advancing timeRef.current.
🧹 Nitpick comments (2)
frontend/components/about/FeaturesSection.tsx (2)

136-185: Respect reduced-motion preferences for heavy animations.
This section uses multiple continuous animations; consider honoring reduced-motion settings to improve accessibility.

♿ Suggested adjustment
-import { motion, AnimatePresence } from "framer-motion"
+import { motion, AnimatePresence, useReducedMotion } from "framer-motion"
@@
 function FeatureBubble({ feature, index, href, isMobile }: { feature: Feature; index: number; href: string; isMobile: boolean }) {
+    const shouldReduceMotion = useReducedMotion()
     const Icon = feature.icon
@@
-            transition={{
-                x: { delay: 0.1 + index * 0.08, duration: 0.6, type: "spring", bounce: 0.3 },
-                y: { delay: 0.1 + index * 0.08, duration: 0.6, type: "spring", bounce: 0.3 },
-                opacity: { delay: 0.1 + index * 0.08, duration: 0.3 },
-                scale: { delay: 0.1 + index * 0.08, duration: 0.5, type: "spring", bounce: 0.4 },
-            }}
+            transition={
+                shouldReduceMotion
+                    ? { duration: 0 }
+                    : {
+                          x: { delay: 0.1 + index * 0.08, duration: 0.6, type: "spring", bounce: 0.3 },
+                          y: { delay: 0.1 + index * 0.08, duration: 0.6, type: "spring", bounce: 0.3 },
+                          opacity: { delay: 0.1 + index * 0.08, duration: 0.3 },
+                          scale: { delay: 0.1 + index * 0.08, duration: 0.5, type: "spring", bounce: 0.4 },
+                      }
+            }
@@
-            <div 
-                className="animate-float"
+            <div 
+                className="animate-float motion-reduce:animate-none"
                 style={{ animationDelay: `${floatDelay}s`, animationDuration: `${floatDuration}s` }}
             >

276-304: Add keyboard arrow navigation for the tablist.
With role="tablist", users expect left/right arrow support and roving tabIndex. Right now only clicks/Tab work.

⌨️ Suggested implementation
-function TabButton({ page, isActive, onClick }: { page: Page; isActive: boolean; onClick: () => void }) {
+function TabButton({
+    page,
+    isActive,
+    onClick,
+    onKeyDown,
+}: {
+    page: Page
+    isActive: boolean
+    onClick: () => void
+    onKeyDown: (e: React.KeyboardEvent<HTMLButtonElement>) => void
+}) {
     return (
         <button
+            type="button"
             id={`${page.id}-tab`}
             onClick={onClick}
+            onKeyDown={onKeyDown}
             role="tab"
             aria-selected={isActive}
             aria-controls={`${page.id}-panel`}
+            tabIndex={isActive ? 0 : -1}
@@
 export function FeaturesSection() {
     const [activeTab, setActiveTab] = useState("qa")
     const [isMobile, setIsMobile] = useState(false)
     const activePage = pages.find(p => p.id === activeTab) || pages[0]
+    const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, index: number) => {
+        if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return
+        event.preventDefault()
+        const dir = event.key === "ArrowRight" ? 1 : -1
+        const nextIndex = (index + dir + pages.length) % pages.length
+        const nextId = pages[nextIndex].id
+        setActiveTab(nextId)
+        document.getElementById(`${nextId}-tab`)?.focus()
+    }
@@
-                        {pages.map((page) => (
+                        {pages.map((page, index) => (
                             <TabButton
                                 key={page.id}
                                 page={page}
                                 isActive={activeTab === page.id}
                                 onClick={() => setActiveTab(page.id)}
+                                onKeyDown={(e) => onTabKeyDown(e, index)}
                             />
                         ))}

Also applies to: 307-382

Comment thread frontend/components/ui/particle-canvas.tsx
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Fix all issues with AI agents
In `@frontend/components/about/FeaturesSection.tsx`:
- Around line 327-349: The component currently returns null until the client
mount (mounted guard), removing the section from SSR output; remove the mounted
state and early return so the FeaturesSection renders on the server, and instead
initialize and update isMobile safely for both SSR and client: initialize
isMobile using a window-safe check (e.g. typeof window !== "undefined" ?
window.innerWidth < 768 : false) and keep the existing useEffect to attach the
resize listener and call checkMobile on mount; leave onTabKeyDown, pages, and
setActiveTab logic as-is but ensure DOM focus calls are guarded by the same
window/document availability (or kept inside the setTimeout as present) so no
runtime errors occur during SSR.
🧹 Nitpick comments (1)
frontend/components/ui/particle-canvas.tsx (1)

157-161: Account for devicePixelRatio to avoid blurry canvas on HiDPI.

Line 157–161 sets canvas size in CSS pixels only, so the drawing can look soft on retina displays. Scale the backing store by DPR and keep CSS size unchanged.

♻️ Proposed fix
     const resizeCanvas = () => {
-      canvas.width = canvas.parentElement?.offsetWidth || window.innerWidth
-      canvas.height = canvas.parentElement?.offsetHeight || window.innerHeight
-      initParticles(canvas.width, canvas.height)
+      const width = canvas.parentElement?.offsetWidth || window.innerWidth
+      const height = canvas.parentElement?.offsetHeight || window.innerHeight
+      const dpr = window.devicePixelRatio || 1
+      canvas.width = width * dpr
+      canvas.height = height * dpr
+      canvas.style.width = `${width}px`
+      canvas.style.height = `${height}px`
+      ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
+      initParticles(width, height)
     }

Comment thread frontend/components/about/FeaturesSection.tsx Outdated
Copy link
Copy Markdown
Contributor

@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: 2

🤖 Fix all issues with AI agents
In `@frontend/components/ui/particle-canvas.tsx`:
- Around line 246-253: Boundary checks in the draw loop compare particle logical
positions (p.floatX / p.floatY) against canvas.width / canvas.height
(device-pixel-scaled), causing particles to drift off-screen on high-DPR
displays; update the resize handler (where logical dimensions are computed) to
store logicalWidth and logicalHeight in a ref (component-level), then use those
refs inside the draw function instead of canvas.width/canvas.height when
clamping and reflecting p.floatX/p.floatY and flipping p.floatVx/p.floatVy;
alternatively ensure you consistently scale positions by DPR before
comparing—apply this change to the draw logic that handles p.floatX, p.floatY,
p.floatVx, and p.floatVy so boundary checks use the same coordinate space as
initialization.
- Line 226: The mobile detection currently uses canvas.width (which is in
physical pixels) so isMobileView is wrong on HiDPI displays; change the check to
use the logical width (e.g., compute logicalWidth = canvas.width /
window.devicePixelRatio or getBoundingClientRect().width) and replace
occurrences of canvas.width in the isMobileView computation and the draw
function with this logicalWidth (or store it in a ref like logicalDimensionsRef)
so all layout decisions use logical pixels consistently; update the isMobileView
assignment and any conditional branches in the draw method/particle-canvas
component to use that logical value.

Comment thread frontend/components/ui/particle-canvas.tsx Outdated
Comment thread frontend/components/ui/particle-canvas.tsx Outdated
@ViktorSvertoka ViktorSvertoka merged commit bec0001 into develop Jan 28, 2026
8 checks passed
@ViktorSvertoka ViktorSvertoka deleted the yd/feat/about/visuals-and-content-update branch January 28, 2026 18:34
ViktorSvertoka added a commit that referenced this pull request Jan 31, 2026
* (SP: 1) [Security] Enforce origin posture for shop APIs (admin/checkout same-origin; internal/webhooks non-browser) + docs

* (SP: 1) [DB] Align stripe_events.order_id FK CASCADE across schema and migrations

* feat(i18n): localize quiz anti-cheat, header and blog filters (#175)

* feat(Blog): Adding last published post to the blog and category page, recommended posts, Changing styles to one unified format, Bug fixes

* Update leaderboard-style

* Update leaderboard-style

* teat(Blog): fix of hover on author, fix of the line

* (SP: 3) [Observability] Extend structured logging + correlation IDs across all shop routes; purge console.*; enforce explicit error codes

* (SP: 1) [Admin][Security] Add safe product delete (PRODUCT_IN_USE) + mobile cards UI; tighten env/docs, locale normalization, cache-control, and logging semantics

* fix: npm installing

* (SP: 1) [Admin] Align products list in use checks with DB column names (order_items/inventory_moves)

* fix:Update leaderboard: fixed background

* fix: remove email from CurrentUser type to prevent PII exposure

* refactor: align leaderboard UI with brand style (fixed bg, css vars, podium glow)

* (SP: 1) [Frontend] About Us Page. Fixed game, topics, mobile layout

- Fixed mobile tabs in FeaturesSection (icon-only on mobile)
- Fixed game bugs: collision detection, animation, scoring system
- Added multiple obstacle types with level progression
- Improved game sizing for mobile while preserving desktop
- Updated TopicsSection with local SVG icons and hover borders
- Made DynamicGridBackground static grid opt-in via showStaticGrid prop
- Limited SponsorsWall to display max 10 sponsors
- Optimized CommunitySection button layout for mobile

* refactor: update accent color hover effects to Footer

- Update Footer links to use --accent-primary on hover
- Update ThemeToggle icons to use --accent-primary on hover
- Both components adapt colors to light/dark theme

* refactor: improve accessibility

- Add focus-visible styles for keyboard navigation accessibility

* (SP: 1) [Shop] Fix Stripe checkout success redirect (remove duplicate locale /uk/uk) (#186)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard  update leaderboard-style (#187)

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

* fix:leaderboard update leaderboard-style on mobile (#188)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

---------

Co-authored-by: Viktor Svertoka <victor.svertoka@gmail.com>

* (SP: 1) [Frontend] Changing hero headline on shop main page (#190)

* (SP: 1) [Shop] Fix checkout redirect 404 by removing duplicate locale in in-app routes and Stripe return_url

* (SP: 1) [Shop] Fix locale cart page and orderid page

* (SP: 1) [Frontend] Changin hero headline on shop main page

* (SP: 1) [Frontend] Fix styles shop home page, buttons (#191)

* fix: move row border to first cell to resolve CodeRabbit issue

* fix: move row border to first cell to resolve CodeRabbit issue new

* Feature/leaderboard style update (#192)

* (SP: 7) [UI] Quiz UI polish: tabs styling, category accents, color scheme (#181, #193, #194) (#195)

* Sanity (#196)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* (SP: 3) [AI] Add AI word helper with Groq integration (#200)

* (SP: 3) [AI] Add AI word helper with Groq integration

- Implement Groq API with Llama 3.1 70B model
- Add text selection detection on Q&A page
- Create floating "Explain" button
- Build draggable modal with 3-language support (uk/en/pl)
- Add localStorage caching for instant repeated lookups
- Implement guest CTA (login/signup)
- Add rate limiting (10 requests/min)
- Auth-gated feature (registered users only)

Components:
- SelectableText: Detects text selection
- FloatingExplainButton: Appears on selection
- AIWordHelper: Main modal with explanations

* (SP: 1) i18n: fix Polish locale and set EN as default

* Sanity (#202)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* Sanity (#203)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* (SP: 3) [Frontend] Refactor Header UI and navigation states (#201)

* (SP: 3) [Frontend] Refactor Header UI and navigation states

- Add icon to the language switcher

- Add GitHub icon with stars indicator (frontend only)

- Update logo styles

- Improve touch interaction styles

- Verify correct placement and alignment of all header components

- Make mobile header modal full-screen

- Disable background scroll when mobile menu is open

- Highlight active navigation item

- Update navigation styles:

- Highlight Shop link when user is on Home pages
- Highlight Home link when user is on Shop pages
- Style changes only, no routing or logic changes

* fix CodeRabbit

* update HeaderButton styles

* fix: add accessibility for HeaderButton

* (SP: 3) [Testing] Vitest config + unit + integration tests for quiz module (#204)

* feat(quiz-ui): quiz UI polish - tabs, category accents, color scheme (issues #181, #193, #194)

- Refactor QaTabButton to shared CategoryTabButton component
- Add category accent colors to QuizCard, buttons, progress indicators
- Standardize colors with CSS variables, traffic light timer
- Add DynamicGridBackground to quizzes list page
- Border-only answer feedback, semi-transparent progress styles

* docs: update .gitignore

* fix(quiz): align disqualification threshold with warning banner

Changed violationsCount > 3 to >= 3 in QuizResult points block
to match the warning banner threshold at line 124.

* feat(quiz-testing): add quiz unit tests

- Configure Vitest for quiz module
- Add test factories and setup utilities
- Add quiz-crypto tests (13 tests)
- Add quiz-session tests (12 tests)

* test(quiz): add integration tests for verify-answer API and useAntiCheat hook (#199)

- verify-answer.test.ts: 8 tests for API endpoint
  - Correct/wrong answer verification
  - Validation errors (missing fields, tampered data)
  - Security: rejects modified encrypted answers

- quiz-anticheat.test.ts: 10 tests for useAntiCheat hook
  - Detects copy, paste, context-menu, tab-switch events
  - Respects isActive flag
  - Reset and cleanup functionality

Total quiz tests: 52 (9 setup + 25 unit + 18 integration)

* test(quiz): expand test coverage to 90%+ with hooks, API routes, and UI flow

Add 28 new tests covering:
- useQuizSession hook (6 tests)
- useQuizGuards hook (8 tests)
- guest-quiz storage (5 tests)
- guest-result API route (5 tests)
- quiz-slug API route (3 tests)
- QuizContainer UI flow (1 test)

Coverage: 35% -> 90.94% (quiz scope)
Tests: 52 -> 80

* chore: remove coverage-quiz from git, add to .gitignore

* chore: add coverage-quiz to .gitignore, fix quiz guards test

* fix(leaderboard): improve table mobile

* fix(leaderboard): correct malformed shadow class syntax for avatar glow

* Feature/leaderboard style update (#206)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

* fix: move row border to first cell to resolve CodeRabbit issue

* fix: move row border to first cell to resolve CodeRabbit issue new

* fix(leaderboard): improve table mobile

* fix(leaderboard): correct malformed shadow class syntax for avatar glow

* test(q&a): add comprehensive qa tests and coverage setup (#208)

* test(q&a): add comprehensive qa tests and coverage setup

* test(q&a): align mocks and reset in qa tests

* (SP: 1) [Frontend] Remove Contacts References (#211)

* test(q&a): add comprehensive qa tests and coverage setup

* test(q&a): align mocks and reset in qa tests

* chore(nav): remove contacts page references

* Sanity (#209)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* chore(release): update changelog for v0.5.0

* chore(release): v0.5.0

* [Refactor] Code Quality Improvements: Accessibility, Mobile Support, … (#213)

* fix(leaderboard): adjust podium heights for better visibility on desktop

* Feature/leaderboard style update (#214)

* fix(leaderboard): fix layout centering

* feat(Blog) (#216)

* feat(Blog) (#218)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* feat(Blog): added tests

* feat(Blog): fix for big post on the post page, added tests

* feat(Blog): resolving comments

* feat(Blog): fixed hover for social links icins - dark theme

* (SP: 1) feat(i18n): translate 404 error page (#217)

- Add 404 translations (uk/en/pl)
- Implement [Global/Local/Combined] strategy
- Add helpful navigation links

* (SP: 2) [Frontend] Refactor Home HeroSection and Footer stylestor/home (#221)

* (SP:1) fix: 404 page layout (#219)

- 404 translations (uk/en/pl)
- Implement Global strategy

* feat(Blog) (#222)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* feat(Blog): added tests

* feat(Blog): fix for big post on the post page, added tests

* feat(Blog): resolving comments

* feat(Blog): fixed hover for social links icins - dark theme

* feat(Blog): bringing the style on the blog page to a single site style

* feat(blog): aligning syles

* feat(blog): resolving comment from CodeRabbit

* feat(blog):fix comment for deployment

* Update AI model from 'llama-3.3-70b-versatile' to 'llama3-70b-8192' (#223)

* (SP 2) [Frontend] Update Features section content and improve mobile UX (#224)

* (SP 2) [Frontend] Update Features section content and improve mobile UX

- Features Section: Refined feature content and visuals.
- Mobile UX: Improved responsive layout and scaling for feature cards and interactive elements.
- Visual Enhancements: Added dynamic particle background effects to the Pricing section.

* fix(review): address accessibility, security, and performance feedback

* fix(review): resolve accessibility and hydration issues

* fix(perf): implement frame-rate independent animations

* fix(review): address accessibility, security, and performance feedback

* fix(review): enable SSR for features section and support HiDPI canvas

* fix(review): correct HiDPI logic for particle canvas measurements

* (SP:3) feat(i18n): add UA and PL translations for shop/admin pages

Add comprehensive i18n support for shop and admin sections in 3 languages (en, uk,
  pl).

  Translation coverage:
  - Shop pages: main page, products, cart, checkout, orders
  - Admin pages: dashboard, products management, orders management
  - Navigation: header, mobile menu, category links
  - Product components: cards, filters, sort, badges (NEW/SALE)
  - Category names: Apparel, Lifestyle, Collectibles
  - All UI buttons, labels, and actions

  Key changes:
  - Added ~250+ translation keys to messages/en.json, messages/uk.json,
  messages/pl.json
  - Updated 20+ components to use useTranslations() and getTranslations()
  - Implemented color translation in cart and product detail pages
  - Translated hero message
  - Added badge translations

* fix(i18n): correct translation keys and localization in shop pages

  - Replace confusing error.order with success.orderLabel in checkout success page
  heading
  - Localize boolean stockRestored display (yes/no instead of true/false) in order
  details
  - Fix active state detection for shop category links in mobile menu using search
  params
  - Add missing translation keys (orderLabel, yes, no) to all locales (en, uk, pl)

* fix(netlify): resolve AI API crash and 404 locale/theme issues

AI fixes:
  - Extract getClientIp to separate file (avoid db import crash)
  - Add missing zod dependency to package.json

  404 page fixes:
  - Use NEXT_LOCALE cookie for locale detection on Netlify
  - Add theme detection script in root layout
  - Update styling with hero background and gradient text

* Update frontend/app/not-found.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* (SP:3) feat(i18n): translate about page and auth form validation messages

  - Add about page translations (EN, UK, PL)
  - Add auth.fields.validation translations for form errors

* fix(api): resolve Netlify 503 errors and harden AI explain endpoint

 - Use dynamic import for groq-sdk (Netlify compatibility)                                                    - Bypass rate limiting for unknown IPs (serverless safety)
  - Safe JSON parsing with request.text() + empty body check
  - Fix ReferenceError: remove undefined errorMessage variable
  - Remove sensitive debug info from client responses
  - Add i18n keys: pricing.heading, sponsors.ctaAriaLabel

* feat(api): add GET health check endpoint for ai-explain

* chore(release): v0.5.1

---------

Co-authored-by: liudmylasovetovs <milkaegik@gmail.com>
Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com>
Co-authored-by: Anna <komrakova.anna@gmail.com>
Co-authored-by: AlinaRyabova <alinavr7@gmail.com>
Co-authored-by: Yevhenii Datsenko <yevheniydatsenko@gmail.com>
Co-authored-by: YNazymko12 <yulychka12@gmail.com>
Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com>
Co-authored-by: AlinaRyabova <115992255+AlinaRyabova@users.noreply.github.com>
Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com>
Co-authored-by: Yuliia Nazymko <122815071+YNazymko12@users.noreply.github.com>
Co-authored-by: Yevhenii Datsenko <134847096+yevheniidatsenko@users.noreply.github.com>
Co-authored-by: tetiana zorii <tanyusha.zoriy@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@ViktorSvertoka ViktorSvertoka mentioned this pull request Jan 31, 2026
20 tasks
ViktorSvertoka added a commit that referenced this pull request Jan 31, 2026
* (SP: 1) [Security] Enforce origin posture for shop APIs (admin/checkout same-origin; internal/webhooks non-browser) + docs

* (SP: 1) [DB] Align stripe_events.order_id FK CASCADE across schema and migrations

* feat(i18n): localize quiz anti-cheat, header and blog filters (#175)

* feat(Blog): Adding last published post to the blog and category page, recommended posts, Changing styles to one unified format, Bug fixes

* Update leaderboard-style

* Update leaderboard-style

* teat(Blog): fix of hover on author, fix of the line

* (SP: 3) [Observability] Extend structured logging + correlation IDs across all shop routes; purge console.*; enforce explicit error codes

* (SP: 1) [Admin][Security] Add safe product delete (PRODUCT_IN_USE) + mobile cards UI; tighten env/docs, locale normalization, cache-control, and logging semantics

* fix: npm installing

* (SP: 1) [Admin] Align products list in use checks with DB column names (order_items/inventory_moves)

* fix:Update leaderboard: fixed background

* fix: remove email from CurrentUser type to prevent PII exposure

* refactor: align leaderboard UI with brand style (fixed bg, css vars, podium glow)

* (SP: 1) [Frontend] About Us Page. Fixed game, topics, mobile layout

- Fixed mobile tabs in FeaturesSection (icon-only on mobile)
- Fixed game bugs: collision detection, animation, scoring system
- Added multiple obstacle types with level progression
- Improved game sizing for mobile while preserving desktop
- Updated TopicsSection with local SVG icons and hover borders
- Made DynamicGridBackground static grid opt-in via showStaticGrid prop
- Limited SponsorsWall to display max 10 sponsors
- Optimized CommunitySection button layout for mobile

* refactor: update accent color hover effects to Footer

- Update Footer links to use --accent-primary on hover
- Update ThemeToggle icons to use --accent-primary on hover
- Both components adapt colors to light/dark theme

* refactor: improve accessibility

- Add focus-visible styles for keyboard navigation accessibility

* (SP: 1) [Shop] Fix Stripe checkout success redirect (remove duplicate locale /uk/uk) (#186)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard  update leaderboard-style (#187)

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

* fix:leaderboard update leaderboard-style on mobile (#188)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

---------



* (SP: 1) [Frontend] Changing hero headline on shop main page (#190)

* (SP: 1) [Shop] Fix checkout redirect 404 by removing duplicate locale in in-app routes and Stripe return_url

* (SP: 1) [Shop] Fix locale cart page and orderid page

* (SP: 1) [Frontend] Changin hero headline on shop main page

* (SP: 1) [Frontend] Fix styles shop home page, buttons (#191)

* fix: move row border to first cell to resolve CodeRabbit issue

* fix: move row border to first cell to resolve CodeRabbit issue new

* Feature/leaderboard style update (#192)

* (SP: 7) [UI] Quiz UI polish: tabs styling, category accents, color scheme (#181, #193, #194) (#195)

* Sanity (#196)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* (SP: 3) [AI] Add AI word helper with Groq integration (#200)

* (SP: 3) [AI] Add AI word helper with Groq integration

- Implement Groq API with Llama 3.1 70B model
- Add text selection detection on Q&A page
- Create floating "Explain" button
- Build draggable modal with 3-language support (uk/en/pl)
- Add localStorage caching for instant repeated lookups
- Implement guest CTA (login/signup)
- Add rate limiting (10 requests/min)
- Auth-gated feature (registered users only)

Components:
- SelectableText: Detects text selection
- FloatingExplainButton: Appears on selection
- AIWordHelper: Main modal with explanations

* (SP: 1) i18n: fix Polish locale and set EN as default

* Sanity (#202)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* Sanity (#203)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* (SP: 3) [Frontend] Refactor Header UI and navigation states (#201)

* (SP: 3) [Frontend] Refactor Header UI and navigation states

- Add icon to the language switcher

- Add GitHub icon with stars indicator (frontend only)

- Update logo styles

- Improve touch interaction styles

- Verify correct placement and alignment of all header components

- Make mobile header modal full-screen

- Disable background scroll when mobile menu is open

- Highlight active navigation item

- Update navigation styles:

- Highlight Shop link when user is on Home pages
- Highlight Home link when user is on Shop pages
- Style changes only, no routing or logic changes

* fix CodeRabbit

* update HeaderButton styles

* fix: add accessibility for HeaderButton

* (SP: 3) [Testing] Vitest config + unit + integration tests for quiz module (#204)

* feat(quiz-ui): quiz UI polish - tabs, category accents, color scheme (issues #181, #193, #194)

- Refactor QaTabButton to shared CategoryTabButton component
- Add category accent colors to QuizCard, buttons, progress indicators
- Standardize colors with CSS variables, traffic light timer
- Add DynamicGridBackground to quizzes list page
- Border-only answer feedback, semi-transparent progress styles

* docs: update .gitignore

* fix(quiz): align disqualification threshold with warning banner

Changed violationsCount > 3 to >= 3 in QuizResult points block
to match the warning banner threshold at line 124.

* feat(quiz-testing): add quiz unit tests

- Configure Vitest for quiz module
- Add test factories and setup utilities
- Add quiz-crypto tests (13 tests)
- Add quiz-session tests (12 tests)

* test(quiz): add integration tests for verify-answer API and useAntiCheat hook (#199)

- verify-answer.test.ts: 8 tests for API endpoint
  - Correct/wrong answer verification
  - Validation errors (missing fields, tampered data)
  - Security: rejects modified encrypted answers

- quiz-anticheat.test.ts: 10 tests for useAntiCheat hook
  - Detects copy, paste, context-menu, tab-switch events
  - Respects isActive flag
  - Reset and cleanup functionality

Total quiz tests: 52 (9 setup + 25 unit + 18 integration)

* test(quiz): expand test coverage to 90%+ with hooks, API routes, and UI flow

Add 28 new tests covering:
- useQuizSession hook (6 tests)
- useQuizGuards hook (8 tests)
- guest-quiz storage (5 tests)
- guest-result API route (5 tests)
- quiz-slug API route (3 tests)
- QuizContainer UI flow (1 test)

Coverage: 35% -> 90.94% (quiz scope)
Tests: 52 -> 80

* chore: remove coverage-quiz from git, add to .gitignore

* chore: add coverage-quiz to .gitignore, fix quiz guards test

* fix(leaderboard): improve table mobile

* fix(leaderboard): correct malformed shadow class syntax for avatar glow

* Feature/leaderboard style update (#206)

* fix:leaderboard  update leaderboard-style

* fix:leaderboard update leaderboard-style on mobile

* fix: resolve CodeRabbit issues and conflicts

* fix: move row border to first cell to resolve CodeRabbit issue

* fix: move row border to first cell to resolve CodeRabbit issue new

* fix(leaderboard): improve table mobile

* fix(leaderboard): correct malformed shadow class syntax for avatar glow

* test(q&a): add comprehensive qa tests and coverage setup (#208)

* test(q&a): add comprehensive qa tests and coverage setup

* test(q&a): align mocks and reset in qa tests

* (SP: 1) [Frontend] Remove Contacts References (#211)

* test(q&a): add comprehensive qa tests and coverage setup

* test(q&a): align mocks and reset in qa tests

* chore(nav): remove contacts page references

* Sanity (#209)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* chore(release): update changelog for v0.5.0

* chore(release): v0.5.0

* [Refactor] Code Quality Improvements: Accessibility, Mobile Support, … (#213)

* fix(leaderboard): adjust podium heights for better visibility on desktop

* Feature/leaderboard style update (#214)

* fix(leaderboard): fix layout centering

* feat(Blog) (#216)

* feat(Blog) (#218)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* feat(Blog): added tests

* feat(Blog): fix for big post on the post page, added tests

* feat(Blog): resolving comments

* feat(Blog): fixed hover for social links icins - dark theme

* (SP: 1) feat(i18n): translate 404 error page (#217)

- Add 404 translations (uk/en/pl)
- Implement [Global/Local/Combined] strategy
- Add helpful navigation links

* (SP: 2) [Frontend] Refactor Home HeroSection and Footer stylestor/home (#221)

* (SP:1) fix: 404 page layout (#219)

- 404 translations (uk/en/pl)
- Implement Global strategy

* feat(Blog) (#222)

* feat(Blog):fix for clickable link in post details, fix for author details

* feat(Blog):refactoring after removing author modal

* feat(Blog): fix unified date format

* feat(Blog): Fix for  click-outside-to-close search, recommended posts are limited to 3

* feat(Blog): selectedAuthorData fixed

* feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders

* feat(Blog): fix hover social links, fixed duplication not found search

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs

* feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations

* feat(Blog): Changed image size on the post details page

* feat(Blog): added tests

* feat(Blog): fix for big post on the post page, added tests

* feat(Blog): resolving comments

* feat(Blog): fixed hover for social links icins - dark theme

* feat(Blog): bringing the style on the blog page to a single site style

* feat(blog): aligning syles

* feat(blog): resolving comment from CodeRabbit

* feat(blog):fix comment for deployment

* Update AI model from 'llama-3.3-70b-versatile' to 'llama3-70b-8192' (#223)

* (SP 2) [Frontend] Update Features section content and improve mobile UX (#224)

* (SP 2) [Frontend] Update Features section content and improve mobile UX

- Features Section: Refined feature content and visuals.
- Mobile UX: Improved responsive layout and scaling for feature cards and interactive elements.
- Visual Enhancements: Added dynamic particle background effects to the Pricing section.

* fix(review): address accessibility, security, and performance feedback

* fix(review): resolve accessibility and hydration issues

* fix(perf): implement frame-rate independent animations

* fix(review): address accessibility, security, and performance feedback

* fix(review): enable SSR for features section and support HiDPI canvas

* fix(review): correct HiDPI logic for particle canvas measurements

* (SP:3) feat(i18n): add UA and PL translations for shop/admin pages

Add comprehensive i18n support for shop and admin sections in 3 languages (en, uk,
  pl).

  Translation coverage:
  - Shop pages: main page, products, cart, checkout, orders
  - Admin pages: dashboard, products management, orders management
  - Navigation: header, mobile menu, category links
  - Product components: cards, filters, sort, badges (NEW/SALE)
  - Category names: Apparel, Lifestyle, Collectibles
  - All UI buttons, labels, and actions

  Key changes:
  - Added ~250+ translation keys to messages/en.json, messages/uk.json,
  messages/pl.json
  - Updated 20+ components to use useTranslations() and getTranslations()
  - Implemented color translation in cart and product detail pages
  - Translated hero message
  - Added badge translations

* fix(i18n): correct translation keys and localization in shop pages

  - Replace confusing error.order with success.orderLabel in checkout success page
  heading
  - Localize boolean stockRestored display (yes/no instead of true/false) in order
  details
  - Fix active state detection for shop category links in mobile menu using search
  params
  - Add missing translation keys (orderLabel, yes, no) to all locales (en, uk, pl)

* fix(netlify): resolve AI API crash and 404 locale/theme issues

AI fixes:
  - Extract getClientIp to separate file (avoid db import crash)
  - Add missing zod dependency to package.json

  404 page fixes:
  - Use NEXT_LOCALE cookie for locale detection on Netlify
  - Add theme detection script in root layout
  - Update styling with hero background and gradient text

* Update frontend/app/not-found.tsx



* (SP:3) feat(i18n): translate about page and auth form validation messages

  - Add about page translations (EN, UK, PL)
  - Add auth.fields.validation translations for form errors

* fix(api): resolve Netlify 503 errors and harden AI explain endpoint

 - Use dynamic import for groq-sdk (Netlify compatibility)                                                    - Bypass rate limiting for unknown IPs (serverless safety)
  - Safe JSON parsing with request.text() + empty body check
  - Fix ReferenceError: remove undefined errorMessage variable
  - Remove sensitive debug info from client responses
  - Add i18n keys: pricing.heading, sponsors.ctaAriaLabel

* feat(api): add GET health check endpoint for ai-explain

* chore(release): v0.5.1

---------

Co-authored-by: liudmylasovetovs <milkaegik@gmail.com>
Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com>
Co-authored-by: Anna <komrakova.anna@gmail.com>
Co-authored-by: AlinaRyabova <alinavr7@gmail.com>
Co-authored-by: Yevhenii Datsenko <yevheniydatsenko@gmail.com>
Co-authored-by: YNazymko12 <yulychka12@gmail.com>
Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com>
Co-authored-by: AlinaRyabova <115992255+AlinaRyabova@users.noreply.github.com>
Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com>
Co-authored-by: Yuliia Nazymko <122815071+YNazymko12@users.noreply.github.com>
Co-authored-by: Yevhenii Datsenko <134847096+yevheniidatsenko@users.noreply.github.com>
Co-authored-by: tetiana zorii <tanyusha.zoriy@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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.

2 participants