-
- {ALL_SKILLS.map((skill) => {
- const meta = SKILL_META[skill]
- const on = filters.skill === skill
- return (
- setSkill(on ? null : skill)}
- aria-pressed={on}
- className={cn(
- 'flex items-center gap-1.5 px-3.5 py-1.5 rounded-full text-sm font-medium',
- 'transition-all duration-150 cursor-pointer',
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
- on
- ? 'bg-primary text-white shadow-sm shadow-primary/20'
- : 'bg-muted/70 text-muted-foreground hover:bg-muted hover:text-foreground',
- )}
- >
- {meta.icon}
- {meta.label}
-
- )
- })}
-
-
-
- {active && (
-
-
- Clear
-
- )}
-
-
-
-
+
+ {hasQuery && (
+
setQuery('')}
+ aria-label="Clear search"
+ className={cn(
+ 'flex items-center justify-center rounded-full shrink-0',
+ 'bg-muted/70 text-muted-foreground hover:text-foreground hover:bg-muted',
+ 'transition-all duration-150 cursor-pointer',
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
+ 'h-8 w-8 sm:w-auto sm:px-3 sm:gap-1.5 sm:text-sm sm:font-medium',
+ )}
+ >
+
+ Clear
+
+ )}
+
+
+
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index 30451a5..747c009 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -1,41 +1,111 @@
+import type React from 'react'
+import { Code2, FlaskConical, PenLine } from 'lucide-react'
+import { cn } from '@/lib/utils'
+import type { Role } from '@/types'
-export default function Hero() {
+interface RoleMeta {
+ id: Role
+ icon: React.ReactElement
+ label: string
+ description: string
+}
+
+const ROLES: RoleMeta[] = [
+ {
+ id: 'developer',
+ icon:
,
+ label: 'Developer',
+ description: 'Write code, fix bugs, ship features in C#, TypeScript, and more.',
+ },
+ {
+ id: 'tester',
+ icon:
,
+ label: 'Tester',
+ description: 'Test pull requests, hunt bugs, and give quality feedback.',
+ },
+ {
+ id: 'writer',
+ icon:
,
+ label: 'Writer',
+ description: 'Improve docs, write blog posts, and help users understand BTCPay Server.',
+ },
+]
+
+
+interface HeroProps {
+ selectedRole: Role
+ onRoleSelect: (role: Role) => void
+}
+
+export default function Hero({ selectedRole, onRoleSelect }: HeroProps) {
return (
-
+
-
+
- Start contributing to{' '}
+ Start contributing to{' '}
- ₿itcoin.
+ ₿itcoin
-
- Find your first issue across the entire BTCPay ecosystem.
- Developer, writer, designer, or marketer. There's a spot for you.
+ Find a task matching your skillset and make a difference.
-
-
+
+ {/* Role selector */}
+
+ {ROLES.map((role) => {
+ const selected = selectedRole === role.id
+ return (
+
onRoleSelect(role.id)}
+ aria-pressed={selected}
+ className={cn(
+ 'group relative flex flex-col items-start gap-4 rounded-2xl border p-6 text-left',
+ 'transition-all duration-200 cursor-pointer',
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
+ selected
+ ? 'border-primary bg-primary/[0.06] shadow-lg shadow-primary/10'
+ : 'border-border/60 bg-card/50 hover:border-border hover:bg-card',
+ )}
+ >
+ {selected && (
+
+ )}
+
+ {role.icon}
+
+
+
+ {role.label}
+
+
+ {role.description}
+
+
+
+ )
+ })}
+
+
)
}
diff --git a/src/components/IssueCard.tsx b/src/components/IssueCard.tsx
index 7cf1ce0..a13565a 100644
--- a/src/components/IssueCard.tsx
+++ b/src/components/IssueCard.tsx
@@ -1,10 +1,9 @@
-import { GitBranch, Clock } from 'lucide-react'
+import { GitBranch, GitPullRequest, Clock } from 'lucide-react'
import type React from 'react'
import { Badge } from '@/components/ui/badge'
import IssueLabel from '@/components/IssueLabel'
import type { Issue } from '@/types'
import { cn, timeAgo, stripMarkdown } from '@/lib/utils'
-import { SKILL_META } from '@/lib/skill-map'
interface IssueCardProps {
issue: Issue
@@ -12,8 +11,7 @@ interface IssueCardProps {
}
export default function IssueCard({ issue, onClick }: IssueCardProps) {
- const skill = issue.skills[0]
- const meta = skill ? SKILL_META[skill] : null
+ const isPR = issue.type === 'pr'
return (
{issue.repo.name}
- {meta && (
-
- {meta.icon} {meta.label}
+ {isPR && (
+
+ PR
)}
diff --git a/src/components/IssueModal.tsx b/src/components/IssueModal.tsx
index a50f958..8de48a9 100644
--- a/src/components/IssueModal.tsx
+++ b/src/components/IssueModal.tsx
@@ -2,12 +2,10 @@ import { lazy, Suspense } from 'react'
import { ExternalLink, MessageCircle, Clock, GitBranch } from 'lucide-react'
const ReactMarkdown = lazy(() => import('react-markdown'))
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'
-import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import IssueLabel from '@/components/IssueLabel'
import type { Issue } from '@/types'
import { timeAgo } from '@/lib/utils'
-import { SKILL_META } from '@/lib/skill-map'
interface IssueModalProps {
issue: Issue | null
@@ -85,23 +83,6 @@ export default function IssueModal({ issue, onClose, slideFrom }: IssueModalProp