import { NgTemplateOutlet } from "@angular/common";
import {
booleanAttribute,
ChangeDetectionStrategy,
Component,
computed,
contentChild,
contentChildren,
forwardRef,
inject,
input,
model,
signal,
TemplateRef,
ViewEncapsulation,
} from "@angular/core";
import { SdBusyContainer } from "../../core/busy/sd-busy-container";
import { SdCheckbox } from "../../controls/checkbox/sd-checkbox";
import {
SdKanbanBoard,
type SdKanbanDropTarget,
} from "./sd-kanban-board";
import { SdKanban } from "./sd-kanban";
import { SdAnchor } from "../../controls/button/sd-anchor";
import { NgIcon } from "@ng-icons/core";
import { tablerEye, tablerEyeOff } from "@ng-icons/tabler-icons";
@Component({
selector: "sd-kanban-lane",
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
standalone: true,
imports: [SdBusyContainer, SdCheckbox, NgTemplateOutlet, SdAnchor, NgIcon],
host: {
"class": "flex-column p-default gap-default",
"[attr.data-sd-drag-over]": "dragOvered()",
"(dragover)": "onDragOver($event)",
"(dragleave)": "onDragLeave($event)",
"(drop)": "onDragDrop($event)",
},
template: `
@if (useCollapse() || titleTplRef()) {
@if (useCollapse()) {
}
@if (titleTplRef()) {
}
}
@if (selectableKanbanLength() > 0 || toolTplRef()) {
@if (selectableKanbanLength() > 0) {
}
}
@if (!collapse()) {
}
`,
styles: [
/* language=SCSS */ `
sd-kanban-lane {
> .flex-fill {
> sd-busy-container {
padding: var(--gap-xl) var(--gap-lg);
background: var(--theme-gray-lightest);
border-radius: var(--border-radius-default);
height: 100%;
> ._drop-position {
pointer-events: none;
border-radius: var(--border-radius-default);
background: var(--trans-light);
height: 0;
margin-bottom: 0;
visibility: hidden;
transition: 0.1s linear;
transition-property: height, margin-bottom, visibility;
}
}
}
&[data-sd-drag-over="true"] {
> .flex-fill > sd-busy-container > ._drop-position {
margin-bottom: var(--gap-lg);
visibility: visible;
}
}
}
`,
],
})
export class SdKanbanLane implements SdKanbanDropTarget {
private readonly _boardControl = inject>(
forwardRef(() => SdKanbanBoard),
);
busy = input(false, { transform: booleanAttribute });
useCollapse = input(false, { transform: booleanAttribute });
collapse = model(false);
value = input();
kanbanControls = contentChildren>(SdKanban, { descendants: true });
toolTplRef = contentChild>("toolTpl", { read: TemplateRef });
titleTplRef = contentChild>("titleTpl", { read: TemplateRef });
isAllSelected = computed(() => {
const selectableControls = this.kanbanControls().filter((ctrl) => ctrl.selectable());
return selectableControls.length > 0 && selectableControls.every((ctrl) => ctrl.selected());
});
dragKanban = computed(() => this._boardControl.dragKanban());
dragOvered = signal(false);
selectableKanbanLength = computed(
() => this.kanbanControls().filter((ctrl) => ctrl.selectable()).length,
);
targetLaneValue() {
return this.value();
}
onToggleCollapseButtonClick() {
this.collapse.update((v) => !v);
}
onSelectAllButtonClick(val: boolean) {
if (val) {
this._boardControl.selectedValues.update((v) => {
const r = [...v];
for (const ctrl of this.kanbanControls()) {
if (!ctrl.selectable()) continue;
if (ctrl.value() == null) continue;
if (!v.includes(ctrl.value()!)) {
r.push(ctrl.value()!);
}
}
return r.length === v.length ? v : r;
});
} else {
this._boardControl.selectedValues.update((v) => {
const kanbanValues = this.kanbanControls()
.filter((ctrl) => ctrl.selectable())
.map((ctrl) => ctrl.value())
.filter((v2): v2 is T => v2 != null);
const result = v.filter((item) => !kanbanValues.includes(item));
return result.length === v.length ? v : result;
});
}
}
onDragOver(event: DragEvent) {
if (this._boardControl.dragKanban() == null) return;
event.preventDefault();
event.stopPropagation();
this.dragOvered.set(true);
}
onDragLeave(event: DragEvent) {
event.preventDefault();
event.stopPropagation();
this.dragOvered.set(false);
}
onDragDrop(event: DragEvent) {
if (this._boardControl.dragKanban() == null) return;
this.dragOvered.set(false);
event.preventDefault();
event.stopPropagation();
this._boardControl.onDropTo(this);
}
protected readonly tablerEyeOff = tablerEyeOff;
protected readonly tablerEye = tablerEye;
}