feat(ui): improve AI answer discoverability in PYQs#57
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds a ChangesCompact answer UI and question card redesign
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
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎉 Congratulations @imuniqueshiv!Thank you for contributing to HyperLearningTech. Your pull request has been successfully merged into main. 📦 Merge Summary
🚀 Keep Contributing
Thank you for helping make HyperLearningTech better. Happy Coding! 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
components/ai/answer-viewer.tsx (1)
281-415: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winProse 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 increateMarkdownComponentsand once asprose-*utility variants on the wrapperdiv. 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 bycompact, or dropping the redundantprose-*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
📒 Files selected for processing (3)
app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsxcomponents/ai/answer-viewer.tsxcomponents/ai/generate-answer-button.tsx
| <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> |
There was a problem hiding this comment.
🎯 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.
| <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.
| 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> | ||
| ); | ||
| }, |
There was a problem hiding this comment.
🎯 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.
| 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.
| <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> | ||
| )} |
There was a problem hiding this comment.
🎯 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.
| <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.
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
What Changed?
Screenshots (UI Changes Only)
Screenshots demonstrating the updated PYQ interface and AI answer interaction have been attached to this Pull Request.
Testing
npm run format:check.npm run lint.npm run typecheck.npm run build.Checklist
main.npm run format:checkpasses.npm run lintpasses.npm run typecheckpasses.npm run buildpasses.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
Style