@@ -38,6 +38,9 @@ document.addEventListener('DOMContentLoaded', () => {
3838 { value : 'board' , label : 'Board (Stars + Downloads)' } ,
3939 { value : 'badge_stars' , label : 'Badge — Stars' } ,
4040 { value : 'badge_downloads' , label : 'Badge — Downloads' } ,
41+ { value : 'badge_followers' , label : 'Badge — Followers' } ,
42+ { value : 'badge_watchers' , label : 'Badge — Watchers' } ,
43+ { value : 'badge_workflow' , label : 'Badge — Workflow Status' } ,
4144 ] ;
4245
4346 // --- Initialization ---
@@ -50,7 +53,8 @@ document.addEventListener('DOMContentLoaded', () => {
5053 }
5154
5255 function createDefaultArtifact ( type ) {
53- if ( type === 'badge_stars' || type === 'badge_downloads' ) {
56+ // Badge types with repo + color customization
57+ if ( type === 'badge_stars' || type === 'badge_downloads' || type === 'badge_watchers' ) {
5458 return {
5559 type : type ,
5660 options : {
@@ -61,6 +65,29 @@ document.addEventListener('DOMContentLoaded', () => {
6165 }
6266 } ;
6367 }
68+ // Followers — user-level, no repo needed
69+ if ( type === 'badge_followers' ) {
70+ return {
71+ type : type ,
72+ options : {
73+ color : '#2ea44f' ,
74+ label_color : '#555555' ,
75+ text_style : 'normal'
76+ }
77+ } ;
78+ }
79+ // Workflow status — repo + optional workflow file
80+ if ( type === 'badge_workflow' ) {
81+ return {
82+ type : type ,
83+ options : {
84+ repo : '' ,
85+ workflow : '' ,
86+ label_color : '#555555' ,
87+ text_style : 'normal'
88+ }
89+ } ;
90+ }
6491 // Default: board
6592 return {
6693 type : 'board' ,
@@ -157,20 +184,15 @@ document.addEventListener('DOMContentLoaded', () => {
157184 `<option value="${ t . value } " ${ art . type === t . value ? 'selected' : '' } >${ t . label } </option>`
158185 ) . join ( '' ) ;
159186
160- const isBadge = art . type === 'badge_stars' || art . type === 'badge_downloads' ;
161-
162187 // Build type-specific options HTML
163188 let optionsHTML = '' ;
164- if ( isBadge ) {
189+
190+ // Helper: color + text style row
191+ const colorRow = ( art , index ) => {
165192 const textStyleOptions = [ 'normal' , 'bold' , 'italic' ] . map ( s =>
166193 `<option value="${ s } " ${ art . options . text_style === s ? 'selected' : '' } >${ s . charAt ( 0 ) . toUpperCase ( ) + s . slice ( 1 ) } </option>`
167194 ) . join ( '' ) ;
168-
169- optionsHTML = `
170- <div class="form-group">
171- <label>Repository Name</label>
172- <input type="text" class="art-repo" value="${ art . options . repo || '' } " data-idx="${ index } " placeholder="e.g. my-project">
173- </div>
195+ return `
174196 <div class="grid-layout" style="grid-template-columns: 1fr 1fr 1fr; gap: 1rem;">
175197 <div class="form-group">
176198 <label>Badge Color</label>
@@ -192,10 +214,10 @@ document.addEventListener('DOMContentLoaded', () => {
192214 ${ textStyleOptions }
193215 </select>
194216 </div>
195- </div>
196- ` ;
197- } else {
198- // Board options
217+ </div>` ;
218+ } ;
219+
220+ if ( art . type === 'board' ) {
199221 optionsHTML = `
200222 <div class="grid-layout" style="grid-template-columns: 1fr 1fr; gap: 1rem;">
201223 <div class="form-group">
@@ -208,6 +230,31 @@ document.addEventListener('DOMContentLoaded', () => {
208230 </div>
209231 </div>
210232 ` ;
233+ } else if ( art . type === 'badge_followers' ) {
234+ // No repo field — user-level badge
235+ optionsHTML = colorRow ( art , index ) ;
236+ } else if ( art . type === 'badge_workflow' ) {
237+ // Repo + optional workflow file
238+ optionsHTML = `
239+ <div class="grid-layout" style="grid-template-columns: 1fr 1fr; gap: 1rem;">
240+ <div class="form-group">
241+ <label>Repository Name</label>
242+ <input type="text" class="art-repo" value="${ art . options . repo || '' } " data-idx="${ index } " placeholder="e.g. my-project">
243+ </div>
244+ <div class="form-group">
245+ <label>Workflow File <small style="color:var(--text-muted)">(optional)</small></label>
246+ <input type="text" class="art-workflow" value="${ art . options . workflow || '' } " data-idx="${ index } " placeholder="e.g. ci.yml or leave blank for latest">
247+ </div>
248+ </div>
249+ ` + colorRow ( art , index ) ;
250+ } else {
251+ // stars, downloads, watchers — repo + colors
252+ optionsHTML = `
253+ <div class="form-group">
254+ <label>Repository Name</label>
255+ <input type="text" class="art-repo" value="${ art . options . repo || '' } " data-idx="${ index } " placeholder="e.g. my-project">
256+ </div>
257+ ` + colorRow ( art , index ) ;
211258 }
212259
213260 el . innerHTML = `
@@ -264,6 +311,15 @@ document.addEventListener('DOMContentLoaded', () => {
264311 } ) ;
265312 } ) ;
266313
314+ // Workflow file input
315+ document . querySelectorAll ( '.art-workflow' ) . forEach ( input => {
316+ input . addEventListener ( 'input' , ( e ) => {
317+ const idx = e . target . dataset . idx ;
318+ state . artifacts [ idx ] . options . workflow = e . target . value ;
319+ updatePreview ( ) ;
320+ } ) ;
321+ } ) ;
322+
267323 // Color pickers (sync with text inputs)
268324 document . querySelectorAll ( '.art-color' ) . forEach ( input => {
269325 input . addEventListener ( 'input' , ( e ) => {
@@ -333,15 +389,18 @@ document.addEventListener('DOMContentLoaded', () => {
333389
334390 // Map frontend types to manifest schema
335391 const typeMapping = {
336- 'board' : { type : 'board' , style : 'board_stars_downloads' } ,
337- 'badge_stars' : { type : 'badge' , style : 'badge_stars' } ,
338- 'badge_downloads' : { type : 'badge' , style : 'badge_downloads' } ,
392+ 'board' : { type : 'board' , style : 'board_stars_downloads' , badge_type : null } ,
393+ 'badge_stars' : { type : 'badge' , style : 'badge_stars' , badge_type : 'stars' } ,
394+ 'badge_downloads' : { type : 'badge' , style : 'badge_downloads' , badge_type : 'downloads' } ,
395+ 'badge_followers' : { type : 'badge' , style : 'badge_followers' , badge_type : 'followers' } ,
396+ 'badge_watchers' : { type : 'badge' , style : 'badge_watchers' , badge_type : 'watchers' } ,
397+ 'badge_workflow' : { type : 'badge' , style : 'badge_workflow' , badge_type : 'workflow_status' } ,
339398 } ;
340399
341400 // Auto-generate IDs
342401 const uniqueIds = { } ;
343402 const safeArtifacts = state . artifacts . map ( art => {
344- const mapping = typeMapping [ art . type ] || { type : art . type , style : art . type } ;
403+ const mapping = typeMapping [ art . type ] || { type : art . type , style : art . type , badge_type : null } ;
345404 let baseId = mapping . style ;
346405 if ( ! uniqueIds [ baseId ] ) uniqueIds [ baseId ] = 0 ;
347406 uniqueIds [ baseId ] ++ ;
@@ -363,12 +422,15 @@ document.addEventListener('DOMContentLoaded', () => {
363422 // Type-specific options
364423 if ( mapping . type === 'badge' ) {
365424 result . options = {
366- badge_type : art . type === 'badge_stars' ? 'stars' : 'downloads' ,
367- repo : art . options . repo || '' ,
425+ badge_type : mapping . badge_type ,
368426 color : art . options . color || '#2ea44f' ,
369427 label_color : art . options . label_color || '#555555' ,
370428 text_style : art . options . text_style || 'normal' ,
371429 } ;
430+ // Include repo if present
431+ if ( art . options . repo ) result . options . repo = art . options . repo ;
432+ // Include workflow file if present
433+ if ( art . options . workflow ) result . options . workflow = art . options . workflow ;
372434 } else {
373435 result . options = {
374436 max_repos : art . options . max_repos || 10 ,
@@ -458,15 +520,19 @@ document.addEventListener('DOMContentLoaded', () => {
458520 } ) ;
459521 apiUrl = `${ API_BASE_URL } /api/board?${ params . toString ( ) } ` ;
460522 } else if ( firstArt . type === 'badge' ) {
461- const repo = firstArt . options . repo || 'example-repo ' ;
523+ const badgeType = firstArt . options . badge_type || 'stars ' ;
462524 const params = new URLSearchParams ( {
463525 user,
464- repo,
465- type : firstArt . options . badge_type || 'stars' ,
466- color : firstArt . options . color || '#2ea44f' ,
526+ type : badgeType ,
467527 label_color : firstArt . options . label_color || '#555555' ,
468528 text_style : firstArt . options . text_style || 'normal' ,
469529 } ) ;
530+ // Add repo if applicable (not needed for followers)
531+ if ( firstArt . options . repo ) params . set ( 'repo' , firstArt . options . repo ) ;
532+ // Add color (workflow_status overrides on server, but still send user's preference)
533+ if ( firstArt . options . color ) params . set ( 'color' , firstArt . options . color ) ;
534+ // Add workflow file if set
535+ if ( firstArt . options . workflow ) params . set ( 'workflow' , firstArt . options . workflow ) ;
470536 apiUrl = `${ API_BASE_URL } /api/badge?${ params . toString ( ) } ` ;
471537 }
472538
0 commit comments