Skip to content

feat(ui): improve AI answer discoverability in PYQs#57

Merged
imuniqueshiv merged 1 commit into
mainfrom
feature/pyq-ai-discoverability
Jul 6, 2026
Merged

feat(ui): improve AI answer discoverability in PYQs#57
imuniqueshiv merged 1 commit into
mainfrom
feature/pyq-ai-discoverability

Conversation

@imuniqueshiv

@imuniqueshiv imuniqueshiv commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Pull Request

Summary

Improve the discoverability and user experience of AI-generated answers on the Previous Year Question (PYQ) page by introducing a more prominent and intuitive UI while preserving all existing functionality.


Related Issue

N/A


Type of Change

  • Feature
  • Bug Fix
  • Documentation
  • Refactor
  • Performance Improvement
  • CI / Build
  • Other

What Changed?

  • Redesigned the PYQ question cards to make AI answer generation easier to discover.
  • Improved the visual hierarchy, spacing, and interactive states for expandable questions.
  • Enhanced the AI answer CTA with a clearer, more engaging interface while preserving the existing AI generation workflow.
  • Refined related AI components to provide a smoother and more consistent user experience.

Screenshots (UI Changes Only)

Screenshots demonstrating the updated PYQ interface and AI answer interaction have been attached to this Pull Request.


Testing

  • Verified the updated UI on the PYQ page.
  • Confirmed question expand/collapse behavior works correctly.
  • Confirmed AI answer generation continues to function as expected.
  • Ran npm run format:check.
  • Ran npm run lint.
  • Ran npm run typecheck.
  • Ran npm run build.

Checklist

  • My branch is up to date with the latest main.
  • My code follows the project's coding standards.
  • I have formatted the modified files.
  • npm run format:check passes.
  • npm run lint passes.
  • npm run typecheck passes.
  • npm run build passes.
  • Documentation updates were not required.
  • I have tested my changes locally.
  • This Pull Request focuses on a single feature.

Additional Notes

This Pull Request is focused on improving UI/UX only. No backend logic, AI generation logic, routing, or API behavior has been modified.

Summary by CodeRabbit

  • New Features

    • Improved the question and sub-question display with clearer cards, labels, and expandable sections.
    • Added a more polished AI answer experience, including a compact mobile layout and clearer expand/collapse feedback.
  • Style

    • Updated spacing, typography, and icon treatments for better readability on smaller and larger screens.
    • Refined markdown rendering in AI answers for a cleaner, more compact presentation.

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyper-learning-tech Ready Ready Preview, Comment Jul 6, 2026 3:11am

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a compact/compactMobile styling mode to AnswerViewer and GenerateAnswerButton, converting static markdown/prose class strings into conditional factories. The PYQ paper page is restructured with new icons, updated padding, and redesigned question/sub-question cards with an expandable AI-answer toggle bar.

Changes

Compact answer UI and question card redesign

Layer / File(s) Summary
AnswerViewer compact mode
components/ai/answer-viewer.tsx
Adds compact?: boolean to AnswerViewerProps, converts markdown component styling into a createMarkdownComponents(compact) factory, and makes prose wrapper classes (headings, lists, tables, blockquotes, hr, KaTeX) conditional on compact.
GenerateAnswerButton compactMobile wiring
components/ai/generate-answer-button.tsx
Adds compactMobile?: boolean prop with default false, applies conditional classNames to the wrapper and action bar, and passes compact={compactMobile} to AnswerViewer.
PYQ page question card redesign
app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx
Adds Sparkles/ChevronDown icons, adjusts container padding, restructures question items into <article> with badges, redesigns sub-question <details> summary with label/unit pills and split text, adds a gradient "AI Answer Available" toggle bar, and renders GenerateAnswerButton with compactMobile.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant QuestionCard as PYQ page details
  participant GenerateAnswerButton
  participant AnswerViewer

  User->>QuestionCard: click summary bar to expand
  QuestionCard->>GenerateAnswerButton: render with compactMobile=true
  GenerateAnswerButton->>AnswerViewer: pass compact={compactMobile}
  AnswerViewer-->>GenerateAnswerButton: render compact markdown answer
  GenerateAnswerButton-->>QuestionCard: display answer content
Loading

Suggested reviewers: RamuuXfree

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main UI goal of improving AI answer discoverability in PYQs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/pyq-ai-discoverability

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.

@imuniqueshiv imuniqueshiv merged commit 74898ad into main Jul 6, 2026
5 checks passed
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🎉 Congratulations @imuniqueshiv!

Thank you for contributing to HyperLearningTech.

Your pull request has been successfully merged into main.

📦 Merge Summary

🚀 Keep Contributing

  • Follow the CONTRIBUTING.md guidelines.
  • Keep each Pull Request focused on a single feature or fix.
  • Run formatting, linting, type checking, and a production build before opening a PR.

Thank you for helping make HyperLearningTech better.

Happy Coding! 🚀

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
components/ai/answer-viewer.tsx (1)

281-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prose wrapper compact classes duplicate the per-element renderer classes.

Every element (heading levels, p, li, ul/ol, blockquote, pre, table, hr, KaTeX) now has its compact-aware spacing defined twice: once in createMarkdownComponents and once as prose-* utility variants on the wrapper div. Both sets of classes need to be kept in sync for every future spacing tweak (as the Line 253 issue above demonstrates), which is a maintenance risk. Consider deriving both sets from a single shared spacing map keyed by compact, or dropping the redundant prose-* wrapper classes for elements that already have dedicated custom renderers.

🤖 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 `@components/ai/answer-viewer.tsx` around lines 281 - 415, The compact spacing
rules are duplicated between the wrapper div styles in AnswerViewer and the
element-specific renderers created by createMarkdownComponents, which creates a
sync risk. Refactor AnswerViewer so compact-aware spacing comes from a single
source of truth, either by deriving both the wrapper prose-* classes and the
custom markdown component styles from one shared spacing map keyed by compact,
or by removing the redundant prose-* wrapper classes for elements already
handled by the custom renderers.
🤖 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 `@app/rgpv/`[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx:
- Around line 202-223: The AI-answer indicator is hidden from assistive tech by
`aria-hidden="true"` on the disclosure bar in the `page.tsx` summary, which
removes the “AI Answer Available” cue from screen readers. Update the `summary`
markup so the `Sparkles`/label area is exposed to accessibility, or provide an
equivalent accessible label on the disclosure widget in this component. Keep the
visible affordance but ensure the `summary` for the AI-answer section in
`page.tsx` announces that expanding it reveals an AI answer.

In `@components/ai/answer-viewer.tsx`:
- Around line 248-261: The compact branch in the p renderer inside answer-viewer
has conflicting sm:leading-* utilities, so remove the stray sm:leading-[1.9] and
keep only the intended compact breakpoint line-height from the p component.
Update the p({ children, ...props }) className logic so it matches the compact
behavior used elsewhere in the component, avoiding duplicate line-height classes
on the same element.

In `@components/ai/generate-answer-button.tsx`:
- Around line 156-165: The compact branch of the answer container in
generate-answer-button.tsx is missing top/bottom border utilities, so it never
renders a full border like the non-compact path. Update the compact class list
in the conditional wrapping AnswerViewer to include a border width utility for
the vertical edges while preserving the intended horizontal behavior, using the
existing compactMobile styling branch as the place to fix it.

---

Nitpick comments:
In `@components/ai/answer-viewer.tsx`:
- Around line 281-415: The compact spacing rules are duplicated between the
wrapper div styles in AnswerViewer and the element-specific renderers created by
createMarkdownComponents, which creates a sync risk. Refactor AnswerViewer so
compact-aware spacing comes from a single source of truth, either by deriving
both the wrapper prose-* classes and the custom markdown component styles from
one shared spacing map keyed by compact, or by removing the redundant prose-*
wrapper classes for elements already handled by the custom renderers.
🪄 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: d510f0f8-3db4-401a-bee3-36e5571e2cbb

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba8506 and e9d688c.

📒 Files selected for processing (3)
  • app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx
  • components/ai/answer-viewer.tsx
  • components/ai/generate-answer-button.tsx

Comment on lines +202 to 223
<div
aria-hidden="true"
className="flex items-center justify-between gap-3 border-t border-blue-500/10 bg-gradient-to-r from-blue-500/5 via-indigo-500/5 to-blue-500/10 px-4 py-3 transition-all duration-300 group-open/sub:border-blue-500/25 group-open/sub:from-blue-500/10 group-open/sub:via-blue-500/15 group-open/sub:to-indigo-500/10 sm:px-5 sm:py-3.5"
>
<div className="flex min-w-0 items-center gap-2">
<Sparkles className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" />
<span className="truncate text-sm font-medium text-blue-600 dark:text-blue-400">
AI Answer Available
</span>
</div>

<div className="flex shrink-0 items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors duration-300 group-open/sub:text-blue-600 dark:group-open/sub:text-blue-400">
<span className="group-open/sub:hidden">
Click to expand
</span>
<span className="hidden group-open/sub:inline">
Expanded
</span>
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-300 group-open/sub:rotate-180" />
</div>
</div>
</summary>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

aria-hidden on the AI-answer indicator undermines this PR's discoverability goal.

This bar is the primary visual cue that an AI answer is available ("AI Answer Available" text, Sparkles icon, expand/collapse hint), but it's wrapped in aria-hidden="true". Screen-reader users get no indication that expanding the <summary> reveals an AI-answer feature — their accessible name for the disclosure widget is just the question text (lines 188-199), which isn't hidden. Since the PR's stated purpose is "improve AI answer discoverability," this regresses that goal specifically for assistive-tech users.

♿ Proposed fix — expose an equivalent accessible label
-                            <div
-                              aria-hidden="true"
-                              className="flex items-center justify-between gap-3 border-t border-blue-500/10 bg-gradient-to-r from-blue-500/5 via-indigo-500/5 to-blue-500/10 px-4 py-3 transition-all duration-300 group-open/sub:border-blue-500/25 group-open/sub:from-blue-500/10 group-open/sub:via-blue-500/15 group-open/sub:to-indigo-500/10 sm:px-5 sm:py-3.5"
-                            >
+                            <div
+                              className="flex items-center justify-between gap-3 border-t border-blue-500/10 bg-gradient-to-r from-blue-500/5 via-indigo-500/5 to-blue-500/10 px-4 py-3 transition-all duration-300 group-open/sub:border-blue-500/25 group-open/sub:from-blue-500/10 group-open/sub:via-blue-500/15 group-open/sub:to-indigo-500/10 sm:px-5 sm:py-3.5"
+                            >
                               <div className="flex min-w-0 items-center gap-2">
-                                <Sparkles className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" />
+                                <Sparkles className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" aria-hidden="true" />
                                 <span className="truncate text-sm font-medium text-blue-600 dark:text-blue-400">
                                   AI Answer Available
                                 </span>
                               </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
aria-hidden="true"
className="flex items-center justify-between gap-3 border-t border-blue-500/10 bg-gradient-to-r from-blue-500/5 via-indigo-500/5 to-blue-500/10 px-4 py-3 transition-all duration-300 group-open/sub:border-blue-500/25 group-open/sub:from-blue-500/10 group-open/sub:via-blue-500/15 group-open/sub:to-indigo-500/10 sm:px-5 sm:py-3.5"
>
<div className="flex min-w-0 items-center gap-2">
<Sparkles className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" />
<span className="truncate text-sm font-medium text-blue-600 dark:text-blue-400">
AI Answer Available
</span>
</div>
<div className="flex shrink-0 items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors duration-300 group-open/sub:text-blue-600 dark:group-open/sub:text-blue-400">
<span className="group-open/sub:hidden">
Click to expand
</span>
<span className="hidden group-open/sub:inline">
Expanded
</span>
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-300 group-open/sub:rotate-180" />
</div>
</div>
</summary>
<div
className="flex items-center justify-between gap-3 border-t border-blue-500/10 bg-gradient-to-r from-blue-500/5 via-indigo-500/5 to-blue-500/10 px-4 py-3 transition-all duration-300 group-open/sub:border-blue-500/25 group-open/sub:from-blue-500/10 group-open/sub:via-blue-500/15 group-open/sub:to-indigo-500/10 sm:px-5 sm:py-3.5"
>
<div className="flex min-w-0 items-center gap-2">
<Sparkles className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" aria-hidden="true" />
<span className="truncate text-sm font-medium text-blue-600 dark:text-blue-400">
AI Answer Available
</span>
</div>
<div className="flex shrink-0 items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors duration-300 group-open/sub:text-blue-600 dark:group-open/sub:text-blue-400">
<span className="group-open/sub:hidden">
Click to expand
</span>
<span className="hidden group-open/sub:inline">
Expanded
</span>
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-300 group-open/sub:rotate-180" />
</div>
</div>
</summary>
🤖 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 `@app/rgpv/`[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx around lines
202 - 223, The AI-answer indicator is hidden from assistive tech by
`aria-hidden="true"` on the disclosure bar in the `page.tsx` summary, which
removes the “AI Answer Available” cue from screen readers. Update the `summary`
markup so the `Sparkles`/label area is exposed to accessibility, or provide an
equivalent accessible label on the disclosure widget in this component. Keep the
visible affordance but ensure the `summary` for the AI-answer section in
`page.tsx` announces that expanding it reveals an AI answer.

Comment on lines +248 to +261
p({ children, ...props }: React.HTMLAttributes<HTMLParagraphElement>) {
return (
<p
className={`text-base sm:text-lg text-foreground ${
compact
? "mb-4 leading-[1.7] sm:mb-5 sm:leading-[1.8] sm:leading-[1.9]"
: "mb-5 leading-[1.8] sm:leading-[1.9]"
}`}
{...props}
>
{children}
</p>
);
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Conflicting leading-* classes in compact p renderer.

The compact branch sets both sm:leading-[1.8] and sm:leading-[1.9] on the same element — two utilities targeting the same line-height property. Only one wins, and per Tailwind's resolution rule the winner depends on CSS generation order, not class order in the string, making the rendered line-height unpredictable across builds. Compare with the wrapper's compact prose-p classes (Line 327), which correctly only set sm:prose-p:leading-[1.8] for the sm+ breakpoint — the stray sm:leading-[1.9] here looks like a leftover from the non-compact branch that wasn't removed.

🐛 Proposed fix
         <p
           className={`text-base sm:text-lg text-foreground ${
             compact
-              ? "mb-4 leading-[1.7] sm:mb-5 sm:leading-[1.8] sm:leading-[1.9]"
+              ? "mb-4 leading-[1.7] sm:mb-5 sm:leading-[1.8]"
               : "mb-5 leading-[1.8] sm:leading-[1.9]"
           }`}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
p({ children, ...props }: React.HTMLAttributes<HTMLParagraphElement>) {
return (
<p
className={`text-base sm:text-lg text-foreground ${
compact
? "mb-4 leading-[1.7] sm:mb-5 sm:leading-[1.8] sm:leading-[1.9]"
: "mb-5 leading-[1.8] sm:leading-[1.9]"
}`}
{...props}
>
{children}
</p>
);
},
p({ children, ...props }: React.HTMLAttributes<HTMLParagraphElement>) {
return (
<p
className={`text-base sm:text-lg text-foreground ${
compact
? "mb-4 leading-[1.7] sm:mb-5 sm:leading-[1.8]"
: "mb-5 leading-[1.8] sm:leading-[1.9]"
}`}
{...props}
>
{children}
</p>
);
},
🤖 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 `@components/ai/answer-viewer.tsx` around lines 248 - 261, The compact branch
in the p renderer inside answer-viewer has conflicting sm:leading-* utilities,
so remove the stray sm:leading-[1.9] and keep only the intended compact
breakpoint line-height from the p component. Update the p({ children, ...props
}) className logic so it matches the compact behavior used elsewhere in the
component, avoiding duplicate line-height classes on the same element.

Comment on lines +156 to 165
<div
className={
compactMobile
? "mt-2 rounded-lg border-x-0 border-border bg-card p-2 shadow-sm sm:mt-4 sm:rounded-2xl sm:border-x sm:p-6"
: "mt-4 rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6"
}
>
<AnswerViewer answer={answer} compact={compactMobile} />
</div>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Compact answer container never gets a top/bottom border.

The compact class list only includes border-x-0 (mobile) and sm:border-x (desktop) plus border-border for color — there's no border, border-y, border-t, or border-b utility present, so border-top-width/border-bottom-width stay at their default 0. The container renders with no border on any breakpoint at the top/bottom, unlike the non-compact branch which uses the full border border-border.

🐛 Proposed fix
           className={
             compactMobile
-              ? "mt-2 rounded-lg border-x-0 border-border bg-card p-2 shadow-sm sm:mt-4 sm:rounded-2xl sm:border-x sm:p-6"
+              ? "mt-2 rounded-lg border-y border-x-0 border-border bg-card p-2 shadow-sm sm:mt-4 sm:rounded-2xl sm:border-x sm:p-6"
               : "mt-4 rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6"
           }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
className={
compactMobile
? "mt-2 rounded-lg border-x-0 border-border bg-card p-2 shadow-sm sm:mt-4 sm:rounded-2xl sm:border-x sm:p-6"
: "mt-4 rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6"
}
>
<AnswerViewer answer={answer} compact={compactMobile} />
</div>
)}
<div
className={
compactMobile
? "mt-2 rounded-lg border-y border-x-0 border-border bg-card p-2 shadow-sm sm:mt-4 sm:rounded-2xl sm:border-x sm:p-6"
: "mt-4 rounded-2xl border border-border bg-card p-4 shadow-sm sm:p-6"
}
>
<AnswerViewer answer={answer} compact={compactMobile} />
</div>
)}
🤖 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 `@components/ai/generate-answer-button.tsx` around lines 156 - 165, The compact
branch of the answer container in generate-answer-button.tsx is missing
top/bottom border utilities, so it never renders a full border like the
non-compact path. Update the compact class list in the conditional wrapping
AnswerViewer to include a border width utility for the vertical edges while
preserving the intended horizontal behavior, using the existing compactMobile
styling branch as the place to fix it.

@imuniqueshiv imuniqueshiv deleted the feature/pyq-ai-discoverability branch July 6, 2026 03:22
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.

1 participant