Skip to content

Commit 4319f3e

Browse files
committed
refactor(kanban): redesign header project selector and fix empty-column drop target UX
1 parent 42454a9 commit 4319f3e

2 files changed

Lines changed: 98 additions & 34 deletions

File tree

src/app/features/projects/components/project-kanban/project-kanban.component.html

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ <h2>Project Kanban Board</h2>
2626
</div>
2727

2828
<div class="project-console" *ngIf="selectedProject as project">
29-
<label for="projectPicker" class="project-console__label">Switch Project</label>
29+
<div class="project-console__top">
30+
<span class="project-console__heading">Project Context</span>
31+
<span class="project-console__counter">{{ selectedProjectIndex + 1 }} / {{ projects.length }}</span>
32+
</div>
3033

31-
<div class="project-console__controls">
32-
<button pButton type="button" icon="pi pi-angle-left" class="p-button-text p-button-sm" [disabled]="!canSelectPreviousProject || isLoadingProjects" (click)="selectPreviousProject()"></button>
34+
<div class="project-console__picker">
35+
<button pButton type="button" icon="pi pi-angle-left" class="p-button-rounded p-button-text p-button-sm project-console__nav" [disabled]="!canSelectPreviousProject || isLoadingProjects" (click)="selectPreviousProject()"></button>
3336

3437
<p-dropdown
3538
inputId="projectPicker"
@@ -41,14 +44,15 @@ <h2>Project Kanban Board</h2>
4144
filterBy="name"
4245
[showClear]="false"
4346
[disabled]="isLoadingProjects || projects.length === 0"
44-
placeholder="Switch project..."
47+
placeholder="Select project"
48+
styleClass="project-console__dropdown"
4549
(onChange)="onProjectSelected($event.value)">
4650
</p-dropdown>
4751

48-
<button pButton type="button" icon="pi pi-angle-right" class="p-button-text p-button-sm" [disabled]="!canSelectNextProject || isLoadingProjects" (click)="selectNextProject()"></button>
52+
<button pButton type="button" icon="pi pi-angle-right" class="p-button-rounded p-button-text p-button-sm project-console__nav" [disabled]="!canSelectNextProject || isLoadingProjects" (click)="selectNextProject()"></button>
4953
</div>
5054

51-
<span class="project-console__counter">{{ selectedProjectIndex + 1 }} of {{ projects.length }}</span>
55+
<span class="project-console__hint">Use arrows or search to switch project scope.</span>
5256
</div>
5357
</div>
5458
</p-card>
@@ -96,6 +100,26 @@ <h2>Project Kanban Board</h2>
96100

97101
<div class="kanban-column-body">
98102
<div class="task-stack">
103+
<div
104+
*ngIf="getColumnTaskCount(column.status) === 0"
105+
class="kanban-empty-drop-target"
106+
[class.kanban-empty-drop-target--active]="isDropSlotActive(column.status, 0)"
107+
(dragover)="onDropSlotDragOver(column.status, 0, $event)"
108+
(drop)="onDropAt(column.status, 0, $event)">
109+
<article
110+
*ngIf="isDropSlotActive(column.status, 0) && draggedTaskPreview as previewTask"
111+
class="task-card task-card--ghost"
112+
[class.task-card--todo]="column.status === 0"
113+
[class.task-card--in-progress]="column.status === 1"
114+
[class.task-card--done]="column.status === 2">
115+
<div class="task-card__header">
116+
<span class="task-card__title">{{ previewTask.title }}</span>
117+
</div>
118+
<div class="task-card__description">{{ previewTask.description || 'Drop task here' }}</div>
119+
</article>
120+
<span *ngIf="!isDropSlotActive(column.status, 0)">Drop task here</span>
121+
</div>
122+
99123
<ng-container *ngFor="let task of getTasksByStatus(column.status); let taskIndex = index; trackBy: trackByTaskId">
100124
<div
101125
class="kanban-drop-slot"

src/app/features/projects/components/project-kanban/project-kanban.component.scss

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,55 +41,75 @@
4141
}
4242

4343
.project-console {
44-
min-width: 340px;
45-
max-width: 420px;
44+
min-width: 19.5rem;
45+
max-width: 27rem;
46+
width: min(100%, 27rem);
4647
display: flex;
4748
flex-direction: column;
48-
align-items: flex-end;
49-
gap: 0.3rem;
49+
gap: 0.45rem;
50+
border: 1px solid var(--surface-border);
51+
border-radius: 12px;
52+
padding: 0.55rem 0.6rem;
53+
background: color-mix(in srgb, var(--surface-100) 70%, transparent);
5054
}
5155

52-
.project-console__label {
53-
font-size: 0.72rem;
54-
letter-spacing: 0.06em;
56+
.project-console__top {
57+
display: flex;
58+
align-items: center;
59+
justify-content: space-between;
60+
gap: 0.5rem;
61+
}
62+
63+
.project-console__heading {
64+
font-size: 0.69rem;
65+
letter-spacing: 0.07em;
5566
text-transform: uppercase;
5667
color: var(--text-color-secondary);
57-
font-weight: 600;
58-
opacity: 0.85;
59-
margin-right: 0.2rem;
68+
font-weight: 700;
69+
opacity: 0.9;
6070
}
6171

6272
.project-console__counter {
6373
font-size: 0.72rem;
64-
color: var(--text-color-secondary);
65-
margin-right: 0.2rem;
74+
color: var(--text-color);
75+
border: 1px solid var(--surface-border);
76+
border-radius: 999px;
77+
padding: 0.14rem 0.48rem;
78+
background: color-mix(in srgb, var(--surface-200) 78%, transparent);
6679
}
6780

68-
.project-console__controls {
81+
.project-console__picker {
6982
display: grid;
7083
grid-template-columns: auto minmax(0, 1fr) auto;
71-
gap: 0.25rem;
84+
gap: 0.35rem;
7285
align-items: center;
7386
width: 100%;
74-
border: 1px solid var(--surface-border);
75-
border-radius: 12px;
76-
padding: 0.15rem;
77-
background: color-mix(in srgb, var(--surface-100) 70%, transparent);
7887
}
7988

80-
:host ::ng-deep .project-console__controls .p-dropdown {
89+
:host ::ng-deep .project-console__picker .p-dropdown {
8190
min-width: 12rem;
8291
}
8392

84-
:host ::ng-deep .project-console__controls .p-dropdown .p-dropdown-label {
85-
padding-top: 0.42rem;
86-
padding-bottom: 0.42rem;
93+
:host ::ng-deep .project-console__picker .p-dropdown .p-dropdown-label {
94+
padding-top: 0.45rem;
95+
padding-bottom: 0.45rem;
8796
font-size: 0.82rem;
8897
}
8998

90-
:host ::ng-deep .project-console__controls .p-button.p-button-sm {
91-
width: 2rem;
92-
height: 2rem;
99+
:host ::ng-deep .project-console__picker .p-button.p-button-sm {
100+
width: 1.95rem;
101+
height: 1.95rem;
102+
}
103+
104+
.project-console__hint {
105+
font-size: 0.72rem;
106+
color: var(--text-color-secondary);
107+
line-height: 1.2;
108+
}
109+
110+
.project-console__nav {
111+
border: 1px solid var(--surface-border) !important;
112+
background: color-mix(in srgb, var(--surface-100) 80%, transparent) !important;
93113
}
94114

95115
.kanban-content {
@@ -208,6 +228,27 @@
208228
gap: 0.9rem;
209229
}
210230

231+
.kanban-empty-drop-target {
232+
min-height: 5.2rem;
233+
margin-top: 0.35rem;
234+
border: 1px dashed color-mix(in srgb, var(--primary-color) 45%, var(--surface-border));
235+
border-radius: 12px;
236+
background: color-mix(in srgb, var(--surface-100) 55%, transparent);
237+
color: var(--text-color-secondary);
238+
display: flex;
239+
align-items: center;
240+
justify-content: center;
241+
padding: 0.7rem;
242+
text-align: center;
243+
font-size: 0.86rem;
244+
transition: border-color 0.15s ease, background-color 0.15s ease;
245+
}
246+
247+
.kanban-empty-drop-target--active {
248+
border-color: color-mix(in srgb, var(--primary-color) 70%, var(--surface-border));
249+
background: color-mix(in srgb, var(--primary-color) 10%, var(--surface-100));
250+
}
251+
211252
.kanban-drop-slot {
212253
min-height: 0.35rem;
213254
border-radius: 10px;
@@ -533,14 +574,13 @@
533574
.project-console {
534575
min-width: 100%;
535576
max-width: 100%;
536-
align-items: stretch;
537577
}
538578

539-
.project-console__controls {
579+
.project-console__picker {
540580
min-width: 100%;
541581
}
542582

543-
:host ::ng-deep .project-console__controls .p-dropdown {
583+
:host ::ng-deep .project-console__picker .p-dropdown {
544584
min-width: 0;
545585
width: 100%;
546586
}

0 commit comments

Comments
 (0)