11//import { DraftStats } from '@/lib/enhancers/draftStats'
2- import { CommentSpot } from '@/lib/enhancer'
3- import { DraftStats } from '@/lib/enhancers/draftStats'
2+
43import { GitPullRequestIcon , IssueOpenedIcon } from '@primer/octicons-react'
4+ import { cva , type VariantProps } from 'class-variance-authority'
55import { Clock , Code , Filter , Image , Link , Search , TextSelect } from 'lucide-react'
66import { useMemo , useState } from 'react'
7+ import type { CommentSpot } from '@/lib/enhancer'
8+ import type { DraftStats } from '@/lib/enhancers/draftStats'
9+
10+ // CVA configuration for stat badges
11+ const statBadge = cva ( 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs' , {
12+ defaultVariants : {
13+ type : 'text' ,
14+ } ,
15+ variants : {
16+ type : {
17+ code : 'bg-pink-50 text-pink-700' ,
18+ image : 'bg-purple-50 text-purple-700' ,
19+ link : 'bg-blue-50 text-blue-700' ,
20+ text : 'bg-gray-50 text-gray-700' ,
21+ time : 'bg-gray-50 text-gray-700' ,
22+ } ,
23+ } ,
24+ } )
25+
26+ // Map types to their icons
27+ const typeIcons = {
28+ code : Code ,
29+ image : Image ,
30+ link : Link ,
31+ text : TextSelect ,
32+ time : Clock ,
33+ } as const
34+
35+ // StatBadge component
36+ type BadgeProps = VariantProps < typeof statBadge > & {
37+ text : number | string
38+ type : keyof typeof typeIcons
39+ }
40+
41+ const Badge = ( { text, type } : BadgeProps ) => {
42+ const Icon = typeIcons [ type ]
43+ return (
44+ < span className = { statBadge ( { type } ) } >
45+ < Icon className = 'w-3 h-3' />
46+ { text }
47+ </ span >
48+ )
49+ }
750
851/*
952interface GitHubIssueAddCommentSpot extends CommentSpot {
@@ -48,8 +91,8 @@ interface RedditDraft extends BaseDraft {
4891}
4992
5093interface LatestDraft {
51- spot : BaseDraft ,
52- draft : string ,
94+ spot : BaseDraft
95+ draft : string
5396 time : number
5497 draftStats : DraftStats
5598}
@@ -70,69 +113,69 @@ const generateMockDrafts = (): Draft[] => [
70113 codeCount : 3 ,
71114 content :
72115 'This PR addresses the memory leak issue reported in #1233. The problem was caused by event listeners not being properly disposed...' ,
73- unique_key : '1' ,
74116 imageCount : 2 ,
75117 lastEdit : Date . now ( ) - 1000 * 60 * 30 ,
76118 linkCount : 2 ,
77119 number : 1234 ,
78120 slug : 'microsoft/vscode' ,
79121 title : 'Fix memory leak in extension host' ,
80122 type : 'PR' ,
123+ unique_key : '1' ,
81124 } satisfies GitHubDraft ,
82125 {
83126 charCount : 180 ,
84127 codeCount : 0 ,
85128 content :
86129 "I've been using GitLens for years and it's absolutely essential for my workflow. The inline blame annotations are incredibly helpful when..." ,
87- unique_key : '2' ,
88130 imageCount : 0 ,
89131 lastEdit : Date . now ( ) - 1000 * 60 * 60 * 2 ,
90132 linkCount : 1 ,
91133 subreddit : 'programming' ,
92134 title : "Re: What's your favorite VS Code extension?" ,
93135 type : 'REDDIT' ,
136+ unique_key : '2' ,
94137 } satisfies RedditDraft ,
95138 {
96139 charCount : 456 ,
97140 codeCount : 1 ,
98141 content :
99142 "When using useEffect with async functions, the cleanup function doesn't seem to be called correctly in certain edge cases..." ,
100- unique_key : '3' ,
101143 imageCount : 0 ,
102144 lastEdit : Date . now ( ) - 1000 * 60 * 60 * 5 ,
103145 linkCount : 0 ,
104146 number : 5678 ,
105147 slug : 'facebook/react' ,
106148 title : 'Unexpected behavior with useEffect cleanup' ,
107149 type : 'ISSUE' ,
150+ unique_key : '3' ,
108151 } satisfies GitHubDraft ,
109152 {
110153 charCount : 322 ,
111154 codeCount : 0 ,
112155 content :
113156 'LGTM! Just a few minor suggestions about the examples in the routing section. Consider adding more context about...' ,
114- unique_key : '4' ,
115157 imageCount : 4 ,
116158 lastEdit : Date . now ( ) - 1000 * 60 * 60 * 24 ,
117159 linkCount : 3 ,
118160 number : 9012 ,
119161 slug : 'vercel/next.js' ,
120162 title : 'Update routing documentation' ,
121163 type : 'PR' ,
164+ unique_key : '4' ,
122165 } satisfies GitHubDraft ,
123166 {
124167 charCount : 678 ,
125168 codeCount : 7 ,
126169 content :
127170 'This PR implements ESM support in worker threads as discussed in the last TSC meeting. The implementation follows...' ,
128- unique_key : '5' ,
129171 imageCount : 1 ,
130172 lastEdit : Date . now ( ) - 1000 * 60 * 60 * 48 ,
131173 linkCount : 5 ,
132174 number : 3456 ,
133175 slug : 'nodejs/node' ,
134176 title : 'Add support for ESM in worker threads' ,
135177 type : 'PR' ,
178+ unique_key : '5' ,
136179 } satisfies GitHubDraft ,
137180]
138181
@@ -372,10 +415,7 @@ export const ClaudePrototype = () => {
372415 onChange = { ( e ) => setHasLinkFilter ( e . target . checked ) }
373416 className = 'rounded'
374417 />
375- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-blue-50 text-blue-700' >
376- < Link className = 'w-3 h-3' />
377- links
378- </ span >
418+ < Badge type = 'link' text = 'links' />
379419 </ label >
380420 < label className = 'flex items-center gap-2 cursor-pointer' >
381421 < input
@@ -384,10 +424,7 @@ export const ClaudePrototype = () => {
384424 onChange = { ( e ) => setHasImageFilter ( e . target . checked ) }
385425 className = 'rounded'
386426 />
387- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-purple-50 text-purple-700' >
388- < Image className = 'w-3 h-3' />
389- images
390- </ span >
427+ < Badge type = 'image' text = 'images' />
391428 </ label >
392429 < label className = 'flex items-center gap-2 cursor-pointer' >
393430 < input
@@ -396,10 +433,7 @@ export const ClaudePrototype = () => {
396433 onChange = { ( e ) => setHasCodeFilter ( e . target . checked ) }
397434 className = 'rounded'
398435 />
399- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-pink-50 text-pink-700' >
400- < Code className = 'w-3 h-3' />
401- code
402- </ span >
436+ < Badge type = 'code' text = 'code' />
403437 </ label >
404438 </ div >
405439 </ div >
@@ -467,32 +501,11 @@ function commentRow(
467501 ) }
468502 </ div >
469503 < div className = 'flex items-center gap-1 flex-shrink-0' >
470- { draft . linkCount > 0 && (
471- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-blue-50 text-blue-700' >
472- < Link className = 'w-3 h-3' />
473- { draft . linkCount }
474- </ span >
475- ) }
476- { draft . imageCount > 0 && (
477- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-purple-50 text-purple-700' >
478- < Image className = 'w-3 h-3' />
479- { draft . imageCount }
480- </ span >
481- ) }
482- { draft . codeCount > 0 && (
483- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-pink-50 text-pink-700' >
484- < Code className = 'w-3 h-3' />
485- { draft . codeCount }
486- </ span >
487- ) }
488- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-gray-50 text-gray-700' >
489- < TextSelect className = 'w-3 h-3' />
490- { draft . charCount }
491- </ span >
492- < span className = 'inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-gray-50 text-gray-700' >
493- < Clock className = 'w-3 h-3' />
494- { timeAgo ( draft . lastEdit ) }
495- </ span >
504+ { draft . linkCount > 0 && < Badge type = 'link' text = { draft . linkCount } /> }
505+ { draft . imageCount > 0 && < Badge type = 'image' text = { draft . imageCount } /> }
506+ { draft . codeCount > 0 && < Badge type = 'code' text = { draft . codeCount } /> }
507+ < Badge type = 'text' text = { draft . charCount } />
508+ < Badge type = 'time' text = { timeAgo ( draft . lastEdit ) } />
496509 </ div >
497510 </ div >
498511
0 commit comments