mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
refactor: convert to signals
This commit is contained in:
parent
1d2e80e552
commit
6edff77bb4
2 changed files with 76 additions and 77 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<div
|
||||
#gridContainer
|
||||
class="week-grid-container {{ containerExtraClass }}"
|
||||
[class.isCtrlKeyPressed]="isCtrlPressed"
|
||||
class="week-grid-container {{ containerExtraClass() }}"
|
||||
[class.isCtrlKeyPressed]="isCtrlPressed()"
|
||||
(click)="onGridClick($event)"
|
||||
(mousemove)="onMoveOverGrid($event)"
|
||||
>
|
||||
|
|
@ -24,12 +24,12 @@
|
|||
}
|
||||
|
||||
<!-- Grid Cols -->
|
||||
@for (day of daysToShow; track $index) {
|
||||
@for (day of daysToShow(); track $index) {
|
||||
<div
|
||||
class="col"
|
||||
[attr.data-day]="day"
|
||||
style="grid-column: {{ $index + 2 }}; grid-row: 1 / span {{
|
||||
($index === 0 ? currentTimeRow : endOfDayColRowStart) - 1
|
||||
($index === 0 ? currentTimeRow() : endOfDayColRowStart()) - 1
|
||||
}}"
|
||||
>
|
||||
<div class="drop-label">{{ T.F.SCHEDULE.PLAN_START_DAY | translate }}</div>
|
||||
|
|
@ -38,24 +38,26 @@
|
|||
class="col end-of-day"
|
||||
[attr.data-day]="day"
|
||||
style="grid-column: {{ $index + 2 }}; grid-row: {{
|
||||
$index === 0 ? currentTimeRow : endOfDayColRowStart
|
||||
}} / span {{ totalRows - ($index === 0 ? currentTimeRow : endOfDayColRowStart) }}"
|
||||
$index === 0 ? currentTimeRow() : endOfDayColRowStart()
|
||||
}} / span {{
|
||||
totalRows - ($index === 0 ? currentTimeRow() : endOfDayColRowStart())
|
||||
}}"
|
||||
>
|
||||
<div class="drop-label">{{ T.F.SCHEDULE.PLAN_END_DAY | translate }}</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Work Start and End -->
|
||||
@if (workStartEnd) {
|
||||
@if (workStartEnd()) {
|
||||
<div
|
||||
class="work-start"
|
||||
style="grid-row: {{ workStartEnd.workStartRow }}"
|
||||
style="grid-row: {{ workStartEnd()!.workStartRow }}"
|
||||
>
|
||||
<div>{{ T.F.SCHEDULE.START | translate }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="work-end"
|
||||
style="grid-row: {{ workStartEnd.workEndRow }}"
|
||||
style="grid-row: {{ workStartEnd()!.workEndRow }}"
|
||||
>
|
||||
<div>{{ T.F.SCHEDULE.END | translate }}</div>
|
||||
</div>
|
||||
|
|
@ -63,13 +65,13 @@
|
|||
|
||||
<div
|
||||
class="current-time"
|
||||
style="grid-column: 2; grid-row: {{ currentTimeRow }} / span 1"
|
||||
style="grid-column: 2; grid-row: {{ currentTimeRow() }} / span 1"
|
||||
>
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
|
||||
<!-- Events -->
|
||||
@for (ev of safeEvents; track ev.id) {
|
||||
@for (ev of safeEvents(); track ev.id) {
|
||||
@if (
|
||||
ev.type === SVEType.Task ||
|
||||
ev.type === SVEType.SplitTask ||
|
||||
|
|
@ -92,7 +94,7 @@
|
|||
}
|
||||
|
||||
<!-- Excess tasks planned for day -->
|
||||
@for (beyondBudgetDay of safeBeyondBudget; track i; let i = $index) {
|
||||
@for (beyondBudgetDay of safeBeyondBudget(); track i; let i = $index) {
|
||||
@if (beyondBudgetDay.length > 0) {
|
||||
<div
|
||||
class="excess-entries"
|
||||
|
|
@ -124,12 +126,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
@if (newTaskPlaceholder$ | async; as newTaskPlaceholder) {
|
||||
@if (newTaskPlaceholder(); as newTaskPlaceholder) {
|
||||
<create-task-placeholder
|
||||
[isEditMode]="isCreateTaskActive"
|
||||
[isEditMode]="isCreateTaskActive()"
|
||||
[time]="newTaskPlaceholder.time"
|
||||
[date]="newTaskPlaceholder.date"
|
||||
(editEnd)="isCreateTaskActive = false; this.newTaskPlaceholder$.next(null)"
|
||||
(editEnd)="isCreateTaskActive.set(false); this.newTaskPlaceholder.set(null)"
|
||||
[style]="newTaskPlaceholder.style"
|
||||
>
|
||||
</create-task-placeholder>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
inject,
|
||||
Input,
|
||||
input,
|
||||
LOCALE_ID,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
viewChild,
|
||||
signal,
|
||||
computed,
|
||||
} from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ScheduleEvent } from '../schedule.model';
|
||||
import {
|
||||
CdkDrag,
|
||||
|
|
@ -24,14 +24,12 @@ import { FH, SVEType, T_ID_PREFIX } from '../schedule.const';
|
|||
import { throttle } from 'helpful-decorators';
|
||||
import { CreateTaskPlaceholderComponent } from '../create-task-placeholder/create-task-placeholder.component';
|
||||
import { ScheduleEventComponent } from '../schedule-event/schedule-event.component';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { T } from '../../../t.const';
|
||||
import { IS_TOUCH_PRIMARY } from '../../../util/is-mouse-primary';
|
||||
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { ShortcutService } from '../../../core-ui/shortcut/shortcut.service';
|
||||
import { Log } from '../../../core/log';
|
||||
|
||||
const D_HOURS = 24;
|
||||
|
|
@ -43,7 +41,6 @@ const IS_NOT_DRAGGING_CLASS = 'is-not-dragging';
|
|||
@Component({
|
||||
selector: 'schedule-week',
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
ScheduleEventComponent,
|
||||
CdkDrag,
|
||||
CreateTaskPlaceholderComponent,
|
||||
|
|
@ -58,16 +55,14 @@ const IS_NOT_DRAGGING_CLASS = 'is-not-dragging';
|
|||
})
|
||||
export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
||||
private _store = inject(Store);
|
||||
shortcutService = inject(ShortcutService);
|
||||
private locale = inject(LOCALE_ID);
|
||||
destroyRef = inject(DestroyRef);
|
||||
|
||||
@Input() events: ScheduleEvent[] | null = [];
|
||||
@Input() beyondBudget: ScheduleEvent[][] | null = [];
|
||||
@Input() daysToShow: string[] = [];
|
||||
@Input() workStartEnd: { workStartRow: number; workEndRow: number } | null = null;
|
||||
@Input() currentTimeRow: number = 0;
|
||||
@Input() isCtrlPressed: boolean = false;
|
||||
events = input<ScheduleEvent[] | null>([]);
|
||||
beyondBudget = input<ScheduleEvent[][] | null>([]);
|
||||
daysToShow = input<string[]>([]);
|
||||
workStartEnd = input<{ workStartRow: number; workEndRow: number } | null>(null);
|
||||
currentTimeRow = input<number>(0);
|
||||
isCtrlPressed = input<boolean>(false);
|
||||
|
||||
FH = FH;
|
||||
IS_TOUCH_PRIMARY = IS_TOUCH_PRIMARY;
|
||||
|
|
@ -76,13 +71,13 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
T: typeof T = T;
|
||||
|
||||
rowsByNr = Array.from({ length: D_HOURS * FH }, (_, index) => index).filter(
|
||||
(v, index) => index % FH === 0,
|
||||
(_, index) => index % FH === 0,
|
||||
);
|
||||
|
||||
is12HourFormat = Intl.DateTimeFormat(this.locale, { hour: 'numeric' }).resolvedOptions()
|
||||
.hour12;
|
||||
|
||||
times: string[] = this.rowsByNr.map((rowVal, index) => {
|
||||
times: string[] = this.rowsByNr.map((_, index) => {
|
||||
return this.is12HourFormat
|
||||
? index >= 13
|
||||
? (index - 12).toString() + ':00 PM'
|
||||
|
|
@ -90,36 +85,32 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
: index.toString() + ':00';
|
||||
});
|
||||
|
||||
endOfDayColRowStart: number = D_HOURS * 0.5 * FH;
|
||||
endOfDayColRowStart = signal<number>(D_HOURS * 0.5 * FH);
|
||||
totalRows: number = D_HOURS * FH;
|
||||
|
||||
get safeEvents(): ScheduleEvent[] {
|
||||
return this.events || [];
|
||||
}
|
||||
safeEvents = computed(() => this.events() || []);
|
||||
safeBeyondBudget = computed(() => this.beyondBudget() || []);
|
||||
|
||||
get safeBeyondBudget(): ScheduleEvent[][] {
|
||||
return this.beyondBudget || [];
|
||||
}
|
||||
|
||||
newTaskPlaceholder$ = new BehaviorSubject<{
|
||||
newTaskPlaceholder = signal<{
|
||||
style: string;
|
||||
time: string;
|
||||
date: string;
|
||||
} | null>(null);
|
||||
|
||||
isDragging = false;
|
||||
isDraggingDelayed = false;
|
||||
isCreateTaskActive = false;
|
||||
containerExtraClass = IS_NOT_DRAGGING_CLASS;
|
||||
prevDragOverEl: HTMLElement | null = null;
|
||||
dragCloneEl: HTMLElement | null = null;
|
||||
isDragging = signal(false);
|
||||
isDraggingDelayed = signal(false);
|
||||
isCreateTaskActive = signal(false);
|
||||
containerExtraClass = signal(IS_NOT_DRAGGING_CLASS);
|
||||
prevDragOverEl = signal<HTMLElement | null>(null);
|
||||
dragCloneEl = signal<HTMLElement | null>(null);
|
||||
|
||||
readonly gridContainer = viewChild.required<ElementRef>('gridContainer');
|
||||
|
||||
private _currentAniTimeout: number | undefined;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.endOfDayColRowStart = this.workStartEnd?.workStartRow || D_HOURS * 0.5 * FH;
|
||||
const workStartEnd = this.workStartEnd();
|
||||
this.endOfDayColRowStart.set(workStartEnd?.workStartRow || D_HOURS * 0.5 * FH);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
|
@ -129,17 +120,17 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
onGridClick(ev: MouseEvent): void {
|
||||
if (ev.target instanceof HTMLElement) {
|
||||
if (ev.target.classList.contains('col')) {
|
||||
this.isCreateTaskActive = true;
|
||||
this.isCreateTaskActive.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@throttle(30)
|
||||
onMoveOverGrid(ev: MouseEvent): void {
|
||||
if (this.isDragging || this.isDraggingDelayed) {
|
||||
if (this.isDragging() || this.isDraggingDelayed()) {
|
||||
return;
|
||||
}
|
||||
if (this.isCreateTaskActive) {
|
||||
if (this.isCreateTaskActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -173,19 +164,19 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
const minutes = Math.floor(((row - 1) % FH) * (60 / FH));
|
||||
const time = `${hours}:${minutes.toString().padStart(2, '0')}`;
|
||||
|
||||
this.newTaskPlaceholder$.next({
|
||||
this.newTaskPlaceholder.set({
|
||||
style: `grid-row: ${row} / span 6; grid-column: ${targetColColOffset} / span 1`,
|
||||
time,
|
||||
date: this.daysToShow[targetColColOffset - 2],
|
||||
date: this.daysToShow()[targetColColOffset - 2],
|
||||
});
|
||||
} else {
|
||||
this.newTaskPlaceholder$.next(null);
|
||||
this.newTaskPlaceholder.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
@throttle(30)
|
||||
dragMoved(ev: CdkDragMove<ScheduleEvent>): void {
|
||||
if (!this.isDragging) {
|
||||
if (!this.isDragging()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -201,13 +192,14 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
|
||||
if (targetEl !== this.prevDragOverEl) {
|
||||
const prevEl = this.prevDragOverEl();
|
||||
if (targetEl !== prevEl) {
|
||||
Log.log('dragMoved targetElChanged', targetEl);
|
||||
|
||||
if (this.prevDragOverEl) {
|
||||
this.prevDragOverEl.classList.remove(DRAG_OVER_CLASS);
|
||||
if (prevEl) {
|
||||
prevEl.classList.remove(DRAG_OVER_CLASS);
|
||||
}
|
||||
this.prevDragOverEl = targetEl;
|
||||
this.prevDragOverEl.set(targetEl);
|
||||
|
||||
if (
|
||||
targetEl.classList.contains(SVEType.Task) ||
|
||||
|
|
@ -224,38 +216,43 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
|
||||
dragStarted(ev: CdkDragStart<ScheduleEvent>): void {
|
||||
Log.log('dragStart', ev);
|
||||
this.isDragging = this.isDraggingDelayed = true;
|
||||
this.containerExtraClass = IS_DRAGGING_CLASS + ' ' + ev.source.data.type;
|
||||
this.isDragging.set(true);
|
||||
this.isDraggingDelayed.set(true);
|
||||
this.containerExtraClass.set(IS_DRAGGING_CLASS + ' ' + ev.source.data.type);
|
||||
|
||||
const cur = ev.source.element.nativeElement;
|
||||
if (this.dragCloneEl) {
|
||||
this.dragCloneEl.remove();
|
||||
const cloneEl = this.dragCloneEl();
|
||||
if (cloneEl) {
|
||||
cloneEl.remove();
|
||||
}
|
||||
this.dragCloneEl = cur.cloneNode(true) as HTMLElement;
|
||||
this.dragCloneEl.style.transform = 'translateY(0)';
|
||||
this.dragCloneEl.style.opacity = '.1';
|
||||
this.dragCloneEl.classList.add(DRAG_CLONE_CLASS);
|
||||
cur.parentNode?.insertBefore(this.dragCloneEl, cur);
|
||||
const newCloneEl = cur.cloneNode(true) as HTMLElement;
|
||||
newCloneEl.style.transform = 'translateY(0)';
|
||||
newCloneEl.style.opacity = '.1';
|
||||
newCloneEl.classList.add(DRAG_CLONE_CLASS);
|
||||
cur.parentNode?.insertBefore(newCloneEl, cur);
|
||||
this.dragCloneEl.set(newCloneEl);
|
||||
}
|
||||
|
||||
dragReleased(ev: CdkDragRelease): void {
|
||||
const prevEl = this.prevDragOverEl();
|
||||
Log.log('dragReleased', {
|
||||
target: ev.event.target,
|
||||
source: ev.source.element.nativeElement,
|
||||
ev,
|
||||
dragOverEl: this.prevDragOverEl,
|
||||
dragOverEl: prevEl,
|
||||
});
|
||||
|
||||
const target = (this.prevDragOverEl || ev.event.target) as HTMLElement;
|
||||
if (this.prevDragOverEl) {
|
||||
this.prevDragOverEl.classList.remove(DRAG_OVER_CLASS);
|
||||
this.prevDragOverEl = null;
|
||||
const target = (prevEl || ev.event.target) as HTMLElement;
|
||||
if (prevEl) {
|
||||
prevEl.classList.remove(DRAG_OVER_CLASS);
|
||||
this.prevDragOverEl.set(null);
|
||||
}
|
||||
if (this.dragCloneEl) {
|
||||
this.dragCloneEl.remove();
|
||||
const cloneEl = this.dragCloneEl();
|
||||
if (cloneEl) {
|
||||
cloneEl.remove();
|
||||
}
|
||||
|
||||
this.isDragging = false;
|
||||
this.isDragging.set(false);
|
||||
ev.source.element.nativeElement.style.pointerEvents = '';
|
||||
ev.source.element.nativeElement.style.opacity = '0';
|
||||
|
||||
|
|
@ -264,10 +261,10 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
|
|||
ev.source.element.nativeElement.style.opacity = '';
|
||||
ev.source.element.nativeElement.style.pointerEvents = '';
|
||||
}
|
||||
this.isDraggingDelayed = false;
|
||||
this.isDraggingDelayed.set(false);
|
||||
}, 100);
|
||||
|
||||
this.containerExtraClass = IS_NOT_DRAGGING_CLASS;
|
||||
this.containerExtraClass.set(IS_NOT_DRAGGING_CLASS);
|
||||
|
||||
if (target.tagName.toLowerCase() === 'div' && target.classList.contains('col')) {
|
||||
const isMoveToEndOfDay = target.classList.contains('end-of-day');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue