Skip to content

(SP: 2) [Frontend] Q&A UI refresh#169

Merged
ViktorSvertoka merged 5 commits into
developfrom
feature/qa-ui
Jan 20, 2026
Merged

(SP: 2) [Frontend] Q&A UI refresh#169
ViktorSvertoka merged 5 commits into
developfrom
feature/qa-ui

Conversation

@ViktorSvertoka
Copy link
Copy Markdown
Member

@ViktorSvertoka ViktorSvertoka commented Jan 20, 2026

Summary

  • Reused the About dynamic grid background for the Q&A page.
  • Introduced reusable Q&A tab buttons with icons, hover effects, and category styling.
  • Synced pagination accents with the active category and improved pagination UI/UX.
  • Smoothed Q&A content transitions on pagination change.
  • Tweaked responsive behavior for pagination on mobile.

Changes

  • Added shared DynamicGridBackground and wired it into About + Q&A.
  • Built Q&A tab UI with icon assets + category-specific color/glow configs.
  • Updated Q&A pagination styling and responsive layout.
  • Simplified Q&A search logic (search removed from Q&A).

CLOSES: #168

Screenshot 2026-01-20 at 15 48 22

Summary by CodeRabbit

  • New Features

    • Dynamic grid background across Q&A and hero; new styled category tab buttons and accent-driven pagination
    • New hero stats widgets and improved hero layout
  • Changes

    • Search removed from Q&A; simplified tabbed layout, loading states, and pagination behavior (mobile-aware)
    • Accent color now drives pagination visuals and tab highlighting
  • Documentation

    • Added Q&A pretitle and subtitle translations (EN, PL, UK)

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

@ViktorSvertoka ViktorSvertoka self-assigned this Jan 20, 2026
@ViktorSvertoka ViktorSvertoka added performance Performance and efficiency optimizations without functional changes. UI Visual components, styling, layout changes labels Jan 20, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 20, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit 8814fc3
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/696f95a099a08e00085eac73
😎 Deploy Preview https://deploy-preview-169--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 20, 2026

📝 Walkthrough

Walkthrough

This PR adds a DynamicGridBackground component, introduces typed qaTabStyles and a QaTabButton, converts the Q&A page to async locale-aware rendering with header text, removes debounced search from useQaTabs, updates QaSection to use QaTabButton and simplified loading logic, and surfaces accentColor to Pagination for themed styling.

Changes

Cohort / File(s) Summary
New shared visual
frontend/components/shared/DynamicGridBackground.tsx
New client component that tracks cursor and renders a radial mask/highlight over a grid background; accepts children and className.
Q&A tab UI
frontend/components/q&a/QaTabButton.tsx, frontend/data/qaTabs.ts
Adds QaTabButton component and typed qaTabStyles (QaTabStyle) mapping with icons, colors, glows, and accents for categories.
Q&A page layout
frontend/app/[locale]/q&a/page.tsx
Makes QAPage async, resolves params for locale, loads translations, and wraps content with DynamicGridBackground; renders pretitle/title/subtitle above QaSection.
QaSection & tabs hook
frontend/components/q&a/QaSection.tsx, frontend/components/q&a/useQaTabs.ts
Removes search UI and debounced search state; replaces tab triggers with QaTabButton; useQaTabs simplified (no search state, URL sync reduced, fetch uses AbortController).
Pagination behavior & theming
frontend/components/q&a/Pagination.tsx
Pagination now accepts accentColor: string, computes soft/glow variants, exposes CSS vars, and adapts visible pages for mobile with accent-driven styling.
HeroSection visual update
frontend/components/about/HeroSection.tsx
Replaces previous mouse-tracking mask with DynamicGridBackground; removes motion-based mouse logic; adds GlassWidget/MobileStatItem usage and new stats fields.
Locales
frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Adds qa.pretitle and qa.subtitle translation keys for English, Polish, and Ukrainian.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QAPage
    participant DynamicGridBackground
    participant QaSection
    participant useQaTabs
    participant API
    participant Pagination

    User->>QAPage: Request Q&A page
    QAPage->>QAPage: Resolve async params (locale) and load translations
    QAPage->>DynamicGridBackground: Render wrapper + headers
    DynamicGridBackground->>QaSection: Mount child content
    QaSection->>useQaTabs: Init (category, page, locale)
    useQaTabs->>API: Fetch items (active, currentPage, locale)
    API-->>useQaTabs: Return items + totalPages
    useQaTabs-->>QaSection: Provide items, isLoading, totalPages
    QaSection->>Pagination: Pass accentColor from qaTabStyles[active]
    Pagination-->>QaSection: Render pages with accent styling

    User->>QaSection: Click category tab
    QaSection->>useQaTabs: handleCategoryChange(category)
    useQaTabs->>useQaTabs: Reset currentPage -> 1
    useQaTabs->>API: Fetch new category items
    API-->>useQaTabs: Return items
    useQaTabs-->>QaSection: Update items, Pagination accent updates
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • AM1007

Poem

🐰 I hop where grids of light do play,
Tabs now gleam in colors gay,
Search took rest, categories sing,
Pages glow when accents ring,
A little rabbit cheers—hip, hooray! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title '(SP: 2) [Frontend] Q&A UI refresh' clearly summarizes the main change: a UI refresh for the Q&A section, making it specific and descriptive.
Linked Issues check ✅ Passed All primary objectives from issue #168 are met: DynamicGridBackground is shared between About and Q&A [QAPage.tsx, HeroSection.tsx], reusable Q&A tab buttons with category styling are implemented [QaTabButton.tsx, qaTabs.ts], pagination accents sync with active category [Pagination.tsx, QaSection.tsx], and responsive/transition improvements are included [Pagination.tsx, QaSection.tsx].
Out of Scope Changes check ✅ Passed All changes directly support the UI refresh objectives. Translation updates provide new pretitle/subtitle for Q&A, search logic removal aligns with simplified Q&A design, and all component refactoring supports the specified goals.

✏️ 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: 3

🤖 Fix all issues with AI agents
In `@frontend/components/q`&a/useQaTabs.ts:
- Around line 112-117: In the finally block in useQaTabs.ts, remove the early
`return` that can suppress exceptions and instead guard the cleanup call:
replace the `if (!isActive) { return; } setIsLoading(false);` pattern with a
conditional that only calls `setIsLoading(false)` when `isActive` is true (e.g.,
`if (isActive) setIsLoading(false);`), ensuring no control-flow (throws/returns)
from the try/catch is overridden; keep all thrown errors intact so they
propagate normally.

In `@frontend/components/shared/DynamicGridBackground.tsx`:
- Around line 35-43: The useMotionTemplate hooks are being called inside the
style prop of the motion.div (maskImage/WebkitMaskImage), which violates rules
of hooks; move those useMotionTemplate calls to the top level of the
DynamicGridBackground component (e.g., compute maskImageTemplate and
webkitMaskImageTemplate using useMotionTemplate with mouseX and mouseY before
the return), then reference those variables in the motion.div style prop; ensure
you keep the same template string and variable names (mouseX, mouseY) so
behavior is unchanged.

In `@frontend/messages/en.json`:
- Around line 36-38: Delete the unused Q&A translation entries
qa.searchPlaceholder, qa.clearSearch, and qa.noResults from the translations
(remove the "searchPlaceholder", "clearSearch", and "noResults" keys shown in
the diff) to eliminate dead keys; after removal, run the i18n validation or
translation linting step used in the repo to ensure no references remain and
update any translation extraction artifacts if applicable.
🧹 Nitpick comments (6)
frontend/components/shared/DynamicGridBackground.tsx (1)

26-47: Consider adding aria-hidden to decorative background layers.

The background grid layers are purely decorative and don't convey meaningful content. Adding aria-hidden="true" to the decorative divs improves accessibility by ensuring screen readers skip them.

♿ Suggested improvement
-      <div className="pointer-events-none absolute inset-0">
+      <div className="pointer-events-none absolute inset-0" aria-hidden="true">
         <div className="absolute inset-0 bg-[linear-gradient(to_right,`#8080800a_1px`,transparent_1px),linear-gradient(to_bottom,`#8080800a_1px`,transparent_1px)] bg-[size:40px_40px] [mask-image:radial-gradient(ellipse_80%_80%_at_50%_50%,`#000_70`%,transparent_100%)]" />
       </div>

       <motion.div
         className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover/dynamic:opacity-100"
+        aria-hidden="true"
         style={{
frontend/components/about/HeroSection.tsx (2)

91-106: Add proper TypeScript types instead of any.

Using any for the GlassWidget props bypasses TypeScript's type checking. Define a proper interface for type safety.

🔧 Suggested type definition
+import type { LucideIcon } from 'lucide-react';

+interface StatWidgetProps {
+  icon: LucideIcon;
+  color: string;
+  bg: string;
+  label: string;
+  value: string;
+}

-function GlassWidget({ icon: Icon, color, bg, label, value }: any) {
+function GlassWidget({ icon: Icon, color, bg, label, value }: StatWidgetProps) {

108-120: Add proper TypeScript types for MobileStatItem.

Same issue as GlassWidget — define a proper interface instead of using any.

🔧 Suggested fix
-function MobileStatItem({ icon: Icon, color, bg, label, value }: any) {
+function MobileStatItem({ icon: Icon, color, bg, label, value }: StatWidgetProps) {
frontend/components/q&a/Pagination.tsx (1)

14-21: Consider handling 3-character shorthand hex codes.

The hexToRgba function only supports 6-character hex codes. If a 3-character shorthand like #FFF is passed, it will fall back to rgba(0, 0, 0, alpha), which may produce unexpected results.

🔧 Enhanced implementation
 function hexToRgba(hex: string, alpha: number): string {
   const normalized = hex.replace('#', '');
-  if (normalized.length !== 6) return `rgba(0, 0, 0, ${alpha})`;
-  const r = parseInt(normalized.slice(0, 2), 16);
-  const g = parseInt(normalized.slice(2, 4), 16);
-  const b = parseInt(normalized.slice(4, 6), 16);
+  let r: number, g: number, b: number;
+  if (normalized.length === 3) {
+    r = parseInt(normalized[0] + normalized[0], 16);
+    g = parseInt(normalized[1] + normalized[1], 16);
+    b = parseInt(normalized[2] + normalized[2], 16);
+  } else if (normalized.length === 6) {
+    r = parseInt(normalized.slice(0, 2), 16);
+    g = parseInt(normalized.slice(2, 4), 16);
+    b = parseInt(normalized.slice(4, 6), 16);
+  } else {
+    return `rgba(0, 0, 0, ${alpha})`;
+  }
   return `rgba(${r}, ${g}, ${b}, ${alpha})`;
 }
frontend/components/q&a/QaSection.tsx (1)

51-55: Consider adding accessibility attributes to the loading spinner.

The spinner lacks screen reader context. Adding an accessible label improves the experience for assistive technology users.

Suggested enhancement
             {isLoading && (
-              <div className="flex justify-center py-12">
-                <div className="animate-spin h-8 w-8 border-b-2" />
+              <div className="flex justify-center py-12" role="status" aria-label={t('common.loading')}>
+                <div className="animate-spin h-8 w-8 border-b-2" aria-hidden="true" />
+                <span className="sr-only">{t('common.loading')}</span>
               </div>
             )}
frontend/messages/uk.json (1)

36-38: Consider removing unused search-related translation keys.

Since search functionality was removed from the Q&A page, these keys (searchPlaceholder, clearSearch, noResults) are now unused. Cleaning them up would reduce translation maintenance burden.

Comment thread frontend/components/q&amp;a/useQaTabs.ts
Comment thread frontend/components/shared/DynamicGridBackground.tsx
Comment thread frontend/messages/en.json
@ViktorSvertoka ViktorSvertoka changed the title feat(qa): refresh tabs, pagination, and background (SP: 2) [Frontend] Q&A UI refresh Jan 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance and efficiency optimizations without functional changes. UI Visual components, styling, layout changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

(SP: 2) [Frontend] Q&A UI refresh

1 participant