@@ -2,8 +2,10 @@ import { CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop';
22import { Component , computed , effect , inject , signal } from '@angular/core' ;
33import { toSignal } from '@angular/core/rxjs-interop' ;
44import { FormsModule } from '@angular/forms' ;
5+ import { MatRippleModule } from '@angular/material/core' ;
56import { MatFormFieldModule } from '@angular/material/form-field' ;
67import { MatInputModule } from '@angular/material/input' ;
8+ import { RouterLink } from '@angular/router' ;
79import {
810 AuthenticatedImageDirective ,
911 IconComponent ,
@@ -39,103 +41,106 @@ type PlaylistStatus = 'expired' | 'pending' | 'awaiting_approval' | null;
3941 <div class="flex-1 overflow-auto p-2">
4042 @if (filtered_playlists()?.length) {
4143 @for (playlist of filtered_playlists(); track playlist.id) {
42- <div
43- cdkDropList
44- [id]="'playlist-' + $index"
45- [cdkDropListConnectedTo]="['media-list']"
46- [cdkDropListData]="playlist"
47- (cdkDropListDropped)="onDrop(playlist, $event)"
48- class="border-base-300 mb-2 flex items-center gap-3 rounded-lg border p-0.5 transition-colors"
49- >
44+ <a [routerLink]="['/playlists', playlist.id]">
5045 <div
51- class="border-base-200 relative h-12 w-12 shrink-0 overflow-hidden rounded-md border"
46+ cdkDropList
47+ [id]="'playlist-' + $index"
48+ [cdkDropListConnectedTo]="['media-list']"
49+ [cdkDropListData]="playlist"
50+ (cdkDropListDropped)="onDrop(playlist, $event)"
51+ class="border-base-300 mb-2 flex items-center gap-3 rounded-lg border p-0.5 transition-colors"
52+ matRipple
5253 >
53- @if (
54- playlist_thumbnail_media()[playlist.id]
55- ?.length
56- ) {
57- @for (
58- media of playlist_thumbnail_media()[
59- playlist.id
60- ];
61- track media;
62- let i = $index;
63- let len = $count
54+ <div
55+ class="border-base-200 relative h-12 w-12 shrink-0 overflow-hidden rounded-md border"
56+ >
57+ @if (
58+ playlist_thumbnail_media()[playlist.id]
59+ ?.length
6460 ) {
65- <img
66- auth
67- [source]="media"
68- class="border-base-300 bg-base-200 absolute h-9 w-9 rounded-sm border object-cover shadow"
69- [style.top]="
70- 0.3 -
71- (len - 1) * 0.125 +
72- (len - 1 - i) * 0.25 +
73- 'rem'
74- "
75- [style.left]="
76- 0.3 -
77- (len - 1) * 0.125 +
78- (len - 1 - i) * 0.25 +
79- 'rem'
80- "
81- [style.z-index]="i"
82- />
83- }
84- } @else {
85- <div
86- class="text-base-content/35 flex h-full w-full items-center justify-center"
87- >
88- <icon class="text-2xl">
89- playlist_play
90- </icon>
91- </div>
92- }
93- </div>
94- <div class="min-w-0 flex-1">
95- <div class="truncate text-sm font-medium">
96- {{ playlist.name }}
97- </div>
98- <div class="flex flex-wrap gap-1">
99- @if (!playlist.enabled) {
100- <span
101- class="bg-warning text-warning-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
61+ @for (
62+ media of playlist_thumbnail_media()[
63+ playlist.id
64+ ];
65+ track media;
66+ let i = $index;
67+ let len = $count
68+ ) {
69+ <img
70+ auth
71+ [source]="media"
72+ class="border-base-300 bg-base-200 absolute h-9 w-9 rounded-sm border object-cover shadow"
73+ [style.top]="
74+ 0.3 -
75+ (len - 1) * 0.125 +
76+ (len - 1 - i) * 0.25 +
77+ 'rem'
78+ "
79+ [style.left]="
80+ 0.3 -
81+ (len - 1) * 0.125 +
82+ (len - 1 - i) * 0.25 +
83+ 'rem'
84+ "
85+ [style.z-index]="i"
86+ />
87+ }
88+ } @else {
89+ <div
90+ class="text-base-content/35 flex h-full w-full items-center justify-center"
10291 >
103- Disabled
104- </span>
92+ <icon class="text-2xl">
93+ playlist_play
94+ </icon>
95+ </div>
10596 }
106- @switch (getStatus(playlist)) {
107- @case ('expired') {
108- <span
109- class="bg-error text-error-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
110- >
111- Expired
112- </span>
113- }
114- @case ('pending') {
97+ </div>
98+ <div class="min-w-0 flex-1">
99+ <div class="truncate text-sm font-medium">
100+ {{ playlist.name }}
101+ </div>
102+ <div class="flex flex-wrap gap-1">
103+ @if (!playlist.enabled) {
115104 <span
116- class="bg-info text-info -content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
105+ class="bg-warning text-warning -content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
117106 >
118- Pending
107+ Disabled
119108 </span>
120109 }
121- @case ('awaiting_approval') {
122- <span
123- class="bg-secondary text-secondary-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
124- >
125- Awaiting Approval
126- </span>
110+ @switch (getStatus(playlist)) {
111+ @case ('expired') {
112+ <span
113+ class="bg-error text-error-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
114+ >
115+ Expired
116+ </span>
117+ }
118+ @case ('pending') {
119+ <span
120+ class="bg-info text-info-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
121+ >
122+ Pending
123+ </span>
124+ }
125+ @case ('awaiting_approval') {
126+ <span
127+ class="bg-secondary text-secondary-content shrink-0 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase"
128+ >
129+ Awaiting Approval
130+ </span>
131+ }
127132 }
133+ </div>
134+ @if (playlist.description) {
135+ <div
136+ class="mt-0.5 truncate text-xs opacity-50"
137+ >
138+ {{ playlist.description }}
139+ </div>
128140 }
129141 </div>
130- @if (playlist.description) {
131- <div
132- class="mt-0.5 truncate text-xs opacity-50"
133- >
134- {{ playlist.description }}
135- </div>
136- }
137142 </div>
138- </div >
143+ </a >
139144 }
140145 } @else {
141146 <div
@@ -172,6 +177,8 @@ type PlaylistStatus = 'expired' | 'pending' | 'awaiting_approval' | null;
172177 MatInputModule ,
173178 AuthenticatedImageDirective ,
174179 IconComponent ,
180+ RouterLink ,
181+ MatRippleModule ,
175182 ] ,
176183} )
177184export class PlaylistSidebarComponent {
0 commit comments