@@ -89,6 +89,7 @@ type ManualSearchData = Pick<SearchResponse, "results">;
8989type SearchResponse = {
9090 results : Array < {
9191 id : string ;
92+ authorId ?: number ;
9293 title : string ;
9394 artist ?: string ;
9495 album ?: string ;
@@ -523,72 +524,106 @@ function DashboardPlaylistPage() {
523524 < div > Tuning / Path</ div >
524525 < div > Add</ div >
525526 </ div >
526- { manualSearchQuery . data ?. results ?. map ( ( song , index ) => (
527- < div
528- key = { song . id }
529- className = { `dashboard-playlist__manual-row grid grid-cols-[minmax(0,2.1fr)_minmax(0,1.3fr)_minmax(0,1fr)_96px] gap-4 border-t border-(--border) px-5 py-4 ${
530- index % 2 === 0
531- ? "bg-(--panel-strong)"
532- : "bg-(--panel-soft)"
533- } `}
534- >
535- < div className = "dashboard-playlist__manual-track min-w-0" >
536- < p className = "truncate font-semibold text-(--text)" >
537- { song . title }
538- </ p >
539- < p className = "mt-1 truncate text-sm text-(--brand-deep)" >
540- { song . artist ?? "Unknown artist" }
541- </ p >
542- </ div >
543- < div className = "dashboard-playlist__manual-meta min-w-0" >
544- < p className = "truncate text-sm text-(--text)" >
545- { song . album ?? "Unknown album" }
546- </ p >
547- < p className = "mt-1 truncate text-sm text-(--muted)" >
548- { song . creator
549- ? `Charted by ${ song . creator } `
550- : "Unknown creator" }
551- </ p >
552- </ div >
553- < div className = "dashboard-playlist__manual-extra min-w-0" >
554- < p className = "truncate text-sm text-(--text)" >
555- { song . tuning ?? "No tuning info" }
556- </ p >
557- < p className = "mt-1 truncate text-sm text-(--muted)" >
558- { song . parts ?. length
559- ? song . parts . join ( ", " )
560- : "No path info" }
561- </ p >
562- </ div >
563- < div className = "dashboard-playlist__manual-add flex items-center justify-end" >
564- < Button
565- size = "sm"
566- onClick = { ( ) =>
567- mutation . mutate ( {
568- action : "manualAdd" ,
569- songId : song . id ,
570- requesterLogin :
571- manualRequesterLogin . trim ( ) || undefined ,
572- title : song . title ,
573- artist : song . artist ,
574- album : song . album ,
575- creator : song . creator ,
576- tuning : song . tuning ,
577- parts : song . parts ,
578- durationText : song . durationText ,
579- source : song . source ,
580- sourceUrl : song . sourceUrl ,
581- sourceId : song . sourceId ,
582- } )
583- }
584- disabled = { isManualAddPending ( song . id ) }
585- >
586- < Plus className = "h-4 w-4" />
587- Add
588- </ Button >
527+ { manualSearchQuery . data ?. results ?. map ( ( song , index ) => {
528+ const isBlacklistedCharter =
529+ song . authorId != null &&
530+ blacklistedCharterIds . has ( song . authorId ) ;
531+
532+ return (
533+ < div
534+ key = { song . id }
535+ className = { `dashboard-playlist__manual-row grid grid-cols-[minmax(0,2.1fr)_minmax(0,1.3fr)_minmax(0,1fr)_96px] gap-4 border-t border-(--border) px-5 py-4 ${
536+ index % 2 === 0
537+ ? "bg-(--panel-strong)"
538+ : "bg-(--panel-soft)"
539+ } ${ isBlacklistedCharter ? "opacity-55" : "" } `}
540+ >
541+ < div className = "dashboard-playlist__manual-track min-w-0" >
542+ < p className = "truncate font-semibold text-(--text)" >
543+ { song . title }
544+ </ p >
545+ < p className = "mt-1 truncate text-sm text-(--brand-deep)" >
546+ { song . artist ?? "Unknown artist" }
547+ </ p >
548+ </ div >
549+ < div className = "dashboard-playlist__manual-meta min-w-0" >
550+ < p className = "truncate text-sm text-(--text)" >
551+ { song . album ?? "Unknown album" }
552+ </ p >
553+ < div className = "mt-1 flex flex-wrap items-center gap-2 text-sm text-(--muted)" >
554+ < span >
555+ { song . creator
556+ ? `Charted by ${ song . creator } `
557+ : "Unknown creator" }
558+ </ span >
559+ { isBlacklistedCharter ? (
560+ < Badge
561+ variant = "outline"
562+ className = "border-rose-400/40 bg-rose-500/10 text-rose-200"
563+ >
564+ Blacklisted
565+ </ Badge >
566+ ) : null }
567+ </ div >
568+ </ div >
569+ < div className = "dashboard-playlist__manual-extra min-w-0" >
570+ < p className = "truncate text-sm text-(--text)" >
571+ { song . tuning ?? "No tuning info" }
572+ </ p >
573+ < p className = "mt-1 truncate text-sm text-(--muted)" >
574+ { song . parts ?. length
575+ ? song . parts . join ( ", " )
576+ : "No path info" }
577+ </ p >
578+ </ div >
579+ < div className = "dashboard-playlist__manual-add flex items-center justify-end" >
580+ < Button
581+ size = "sm"
582+ onClick = { ( ) =>
583+ mutation . mutate ( {
584+ action : "manualAdd" ,
585+ songId : song . id ,
586+ requesterLogin :
587+ manualRequesterLogin . trim ( ) || undefined ,
588+ title : song . title ,
589+ authorId : song . authorId ,
590+ artist : song . artist ,
591+ album : song . album ,
592+ creator : song . creator ,
593+ tuning : song . tuning ,
594+ parts : song . parts ,
595+ durationText : song . durationText ,
596+ source : song . source ,
597+ sourceUrl : song . sourceUrl ,
598+ sourceId : song . sourceId ,
599+ candidateMatchesJson : JSON . stringify ( [
600+ {
601+ id : song . id ,
602+ authorId : song . authorId ,
603+ title : song . title ,
604+ artist : song . artist ,
605+ album : song . album ,
606+ creator : song . creator ,
607+ tuning : song . tuning ,
608+ parts : song . parts ?? [ ] ,
609+ durationText : song . durationText ,
610+ sourceUrl : song . sourceUrl ,
611+ sourceId : song . sourceId ,
612+ } ,
613+ ] ) ,
614+ } )
615+ }
616+ disabled = {
617+ isBlacklistedCharter || isManualAddPending ( song . id )
618+ }
619+ >
620+ < Plus className = "h-4 w-4" />
621+ Add
622+ </ Button >
623+ </ div >
589624 </ div >
590- </ div >
591- ) ) }
625+ ) ;
626+ } ) }
592627 </ div >
593628 ) : null }
594629 </ CardContent >
0 commit comments