Skip to content

[FEATURE] Add Good First Issue badge for beginner-friendly issues (#181)#246

Merged
ascender1729 merged 3 commits into
masterfrom
feature/181-good-first-issue-badge
Dec 29, 2025
Merged

[FEATURE] Add Good First Issue badge for beginner-friendly issues (#181)#246
ascender1729 merged 3 commits into
masterfrom
feature/181-good-first-issue-badge

Conversation

@ascender1729
Copy link
Copy Markdown
Member

@ascender1729 ascender1729 commented Dec 29, 2025

Summary

  • Add emerald pill badge that appears when an issue has the "good first issue" or "good-first-issue" label
  • Badge displays "Beginner" on mobile and "Good First Issue" on desktop
  • Includes tooltip explaining the badge meaning for contributors
  • Visually distinct from existing "Easy" badge (solid emerald vs semi-transparent green)

Implementation Details

  • Added hasGoodFirstIssueLabel() helper function with label normalization (handles spaces/hyphens)
  • Added isGoodFirstIssue derived state for reactive badge display
  • Badge positioned next to issue number badge in both mobile and desktop layouts
  • Styling: bg-emerald-600 text-white rounded-full for solid pill appearance

Test Plan

  • Search for issues with "good first issue" label - badge should appear
  • Search for issues with "good-first-issue" label - badge should appear
  • Verify badge appears on both mobile and desktop layouts
  • Verify tooltip shows on hover (desktop)
  • Verify badge is visually distinct from "Easy" badge
  • Build passes without errors

Closes #181

Summary by CodeRabbit

  • New Features

    • Issue cards detect "good first issue" variants and show beginner-friendly badges (desktop and mobile).
    • Results view adds a card-style filter panel with custom sort dropdown, compact sort direction toggle, tag cloud show-more, Export (MD/TXT/CSV) and a "Reset all filters" control.
    • Search/token area displays rate-limit status and reset time when available.
  • Style

    • Simplified tag cloud styling and responsive adjustments for mobile.

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

- Add hasGoodFirstIssueLabel() helper to detect label variations
- Add isGoodFirstIssue derived state for reactive badge display
- Add emerald pill badge in mobile layout (text: Beginner)
- Add emerald pill badge in desktop layout (text: Good First Issue)
- Include tooltip explaining badge meaning for contributors
- Update component header documentation
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 29, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'instructions'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Adds detection for "good first issue" label variants in IssueCard and renders mobile ("Beginner") and desktop ("Good First Issue") badges. Introduces UI changes across results/search components (filter card, sort/export, rate-limit display, tag cloud styling) and new SearchForm props for rate-limit info.

Changes

Cohort / File(s) Summary
Issue card — label detection & badges
src/components/results/IssueCard.svelte
Adds hasGoodFirstIssueLabel helper and derived isGoodFirstIssue; conditionally renders a mobile "Beginner" badge and desktop "Good First Issue" badge alongside existing issue-card UI.
Results container — filters, sort, export, rate-limit props
src/components/results/ResultsContainer.svelte
Replaces inline filters with a card UI (easy-toggle, tag cloud show-more, custom sort dropdown, export buttons, reset filters); removes RateLimitDisplay re-export; passes new rate-limit props downstream and adds related CSS for the filter card.
Search form — rate-limit UI & props
src/components/results/SearchForm.svelte
Adds public props rateLimitRemaining?: number and rateLimitResetTime?: string; shows inline rate-limit status near token input when provided; preserves existing auth/search logic.
Tag cloud — styling simplification
src/components/shared/TagCloud.svelte
Removes dynamic font-size scaling and getFontSize; replaces with fixed-size tag buttons, adjusted opacity/border, reduced padding/gaps, and mobile-specific compact sizing.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Pull request includes substantial out-of-scope changes: complete filter card UI redesign in ResultsContainer.svelte with label cloud collapse/expand, custom sort dropdown, export controls, and CSS-heavy modifications not requested in issue #181. Remove non-essential UI redesigns (filter card, sort dropdown, export controls, tag cloud modifications) from this PR and address them in separate feature requests or future PRs. Keep only IssueCard.svelte badge implementation changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature: adding a Good First Issue badge for beginner-friendly issues, directly matching the primary changeset.
Description check ✅ Passed The description covers all key template sections: summary of changes, implementation details, test plan checklist, and links to issue #181. All required information is present.
Linked Issues check ✅ Passed Changes fully satisfy issue #181 requirements: detects both 'good first issue' and 'good-first-issue' labels, displays distinctive emerald badge, positions it prominently, includes tooltip, modified IssueCard.svelte, and provides visual distinction.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/181-good-first-issue-badge

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

@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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 413f00e and fa6605a.

📒 Files selected for processing (1)
  • src/components/results/IssueCard.svelte
🧰 Additional context used
📓 Path-based instructions (4)
**/*.svelte

📄 CodeRabbit inference engine (CLAUDE.md)

Use Svelte 5 runes ($state, $derived, $effect) for reactive state management

Files:

  • src/components/results/IssueCard.svelte
**/*.{svelte,astro,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use UnoCSS with Tailwind-compatible syntax for styling

Files:

  • src/components/results/IssueCard.svelte
**/*.{js,ts,tsx,svelte,astro}

📄 CodeRabbit inference engine (CLAUDE.md)

Ensure ESLint linting passes with 0 errors (run npm run lint)

Files:

  • src/components/results/IssueCard.svelte
**/*.{js,ts,tsx,svelte,astro,json,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Format all code with Prettier including Svelte/Astro plugins (run npm run format)

Files:

  • src/components/results/IssueCard.svelte
🪛 GitHub Actions: CI
src/components/results/IssueCard.svelte

[error] 139-139: Prettier formatting issue. Delete extra line break/whitespace (prettier/prettier)

🪛 GitHub Check: lint
src/components/results/IssueCard.svelte

[failure] 139-139:
Delete ⏎··················


[failure] 263-263:
Delete ⏎··················

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (2)
src/components/results/IssueCard.svelte (2)

56-66: LGTM! Label normalization logic is sound.

The helper function correctly handles label variations by normalizing spaces and hyphens, and includes proper null safety checks. The implementation aligns well with the PR objectives to detect both 'good first issue' and 'good-first-issue' variants.


70-70: LGTM! Correctly implements Svelte 5 reactive state.

The derived state properly uses the $derived rune for reactive computation, consistent with the coding guidelines and other derived states in the component.

Comment thread src/components/results/IssueCard.svelte
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Dec 29, 2025

Deploying issueflow with  Cloudflare Pages  Cloudflare Pages

Latest commit: a4c681c
Status: ✅  Deploy successful!
Preview URL: https://98445498.issueflow.pages.dev
Branch Preview URL: https://feature-181-good-first-issue.issueflow.pages.dev

View logs

- Redesign filter card with improved visual hierarchy
- Add custom dropdown replacing native select for consistent theme
- Make TagCloud tags compact like GitHub issue labels (0.7rem, pill style)
- Move rate limit display inline with Token label for cleaner layout
- Add show more/less functionality for Labels section
- Compact Sort and Export controls into single-line layouts
- Add proper dividers between filter card sections
- Clean up unused imports (RateLimitDisplay, isRateLimitError)
Copy link
Copy Markdown

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

🧹 Nitpick comments (4)
src/components/results/SearchForm.svelte (1)

507-511: Rate limit exhaustion state not displayed.

When rateLimitRemaining is exactly 0, the rate limit info is hidden entirely. Users won't see any indication that they've exhausted their rate limit, which could lead to confusion when requests start failing.

Consider also displaying when rateLimitRemaining === 0:

🔎 Proposed fix
-        {#if rateLimitRemaining !== undefined && rateLimitRemaining > 0}
-          <span class="text-[10px] {rateLimitRemaining < 10 ? 'text-amber-400' : 'text-slate-500'}">
-            {rateLimitRemaining} left{#if rateLimitResetTime}
+        {#if rateLimitRemaining !== undefined}
+          <span class="text-[10px] {rateLimitRemaining === 0 ? 'text-red-400' : rateLimitRemaining < 10 ? 'text-amber-400' : 'text-slate-500'}">
+            {rateLimitRemaining === 0 ? 'Rate limit exhausted' : `${rateLimitRemaining} left`}{#if rateLimitResetTime}
               · {rateLimitResetTime}{/if}
           </span>
         {/if}
src/components/shared/TagCloud.svelte (1)

51-53: Redundant border: none declaration.

Line 81 sets border: none in CSS, but the inline style on line 53 sets border: 1px solid #{label.color}60;. Since inline styles take precedence, the CSS rule is ineffective. Consider removing it for clarity.

🔎 Proposed fix
   .tag-button {
     display: inline-flex;
     align-items: center;
     gap: 0.2rem;
     padding: 0.125rem 0.5rem;
     border-radius: 9999px;
-    border: none;
     cursor: pointer;

Also applies to: 81-81

src/components/results/ResultsContainer.svelte (2)

639-684: Dropdown lacks keyboard navigation.

The sort dropdown has good ARIA attributes (role="listbox", aria-selected), but is missing keyboard interaction patterns expected for a listbox:

  • Arrow keys to navigate options
  • Escape to close dropdown
  • Enter/Space to select when focused

For better accessibility, consider adding onkeydown handlers to support keyboard-only users.

🔎 Example keyboard handler pattern
<button
  type="button"
  onclick={() => (sortDropdownOpen = !sortDropdownOpen)}
  onblur={() => setTimeout(() => (sortDropdownOpen = false), 150)}
  onkeydown={(e) => {
    if (e.key === 'Escape') {
      sortDropdownOpen = false;
    } else if (e.key === 'ArrowDown' && !sortDropdownOpen) {
      sortDropdownOpen = true;
      e.preventDefault();
    }
  }}
  class="dropdown-trigger"
  ...
>

For the options, consider using roving tabindex or aria-activedescendant pattern for keyboard navigation within the listbox.


642-642: Minor: Timeout not cleaned up on unmount.

The setTimeout in onblur isn't cleared if the component unmounts. In practice, Svelte's reactivity handles this gracefully (setting state on an unmounted component is a no-op), but for strictness you could track and clear the timeout in onDestroy.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd24208 and a4c681c.

📒 Files selected for processing (3)
  • src/components/results/ResultsContainer.svelte
  • src/components/results/SearchForm.svelte
  • src/components/shared/TagCloud.svelte
🧰 Additional context used
📓 Path-based instructions (4)
**/*.svelte

📄 CodeRabbit inference engine (CLAUDE.md)

Use Svelte 5 runes ($state, $derived, $effect) for reactive state management

Files:

  • src/components/shared/TagCloud.svelte
  • src/components/results/SearchForm.svelte
  • src/components/results/ResultsContainer.svelte
**/*.{svelte,astro,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use UnoCSS with Tailwind-compatible syntax for styling

Files:

  • src/components/shared/TagCloud.svelte
  • src/components/results/SearchForm.svelte
  • src/components/results/ResultsContainer.svelte
**/*.{js,ts,tsx,svelte,astro}

📄 CodeRabbit inference engine (CLAUDE.md)

Ensure ESLint linting passes with 0 errors (run npm run lint)

Files:

  • src/components/shared/TagCloud.svelte
  • src/components/results/SearchForm.svelte
  • src/components/results/ResultsContainer.svelte
**/*.{js,ts,tsx,svelte,astro,json,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Format all code with Prettier including Svelte/Astro plugins (run npm run format)

Files:

  • src/components/shared/TagCloud.svelte
  • src/components/results/SearchForm.svelte
  • src/components/results/ResultsContainer.svelte
🧠 Learnings (1)
📚 Learning: 2025-12-27T04:07:21.626Z
Learnt from: CR
Repo: VibeTensor/IssueFlow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-27T04:07:21.626Z
Learning: Applies to src/lib/search-history.ts : Use localStorage-based utility for search history management as implemented in `src/lib/search-history.ts`

Applied to files:

  • src/components/results/ResultsContainer.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (6)
src/components/results/SearchForm.svelte (1)

48-52: LGTM!

Props are appropriately typed as optional, maintaining backwards compatibility with existing usages.

src/components/shared/TagCloud.svelte (1)

111-122: LGTM!

Mobile-specific styling with reduced gaps and font sizes provides a good responsive experience. The @media (max-width: 640px) breakpoint aligns with the Tailwind sm breakpoint convention.

src/components/results/ResultsContainer.svelte (4)

516-518: LGTM!

Clean integration of rate limit props with SearchForm using derived values from rateLimit state.


559-587: LGTM!

The "Easy to Start" toggle is well-implemented with:

  • Clear visual states (active/inactive)
  • Proper aria-pressed for accessibility
  • Checkbox-style visual indicator with checkmark

707-736: LGTM!

The export row provides a clean, compact UI for exporting issues in multiple formats. The button group styling with shared container background is visually cohesive.


1248-1258: LGTM!

The filter card container styles provide a polished, consistent look with appropriate backdrop blur and shadow for depth.

@ascender1729 ascender1729 merged commit 8b2d8e3 into master Dec 29, 2025
8 checks passed
@ascender1729 ascender1729 deleted the feature/181-good-first-issue-badge branch December 29, 2025 08:46
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.

[FEATURE] Add colored badge for good-first-issue labels

1 participant