From fc0d64fce76283b16f1f04e2933fb64c46777d06 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 15 Sep 2019 16:45:28 +0200 Subject: [PATCH] Add basic scroll for blocks details --- src/app/app.component.ts | 10 +- src/app/app.module.ts | 14 +- src/app/components/modal/modal.component.html | 10 +- src/app/components/modal/modal.component.ts | 16 +- .../modal/modals/blocks/blocks.component.html | 81 +++++++++ .../modal/modals/blocks/blocks.component.scss | 134 +++++++++++++++ .../modal/modals/blocks/blocks.component.ts | 154 ++++++++++++++++++ .../create-block/create-block.component.html | 33 ---- .../create-block/create-block.component.scss | 30 ---- .../create-block/create-block.component.ts | 27 --- .../edit-block/edit-block.component.html | 33 ---- .../edit-block/edit-block.component.scss | 29 ---- .../modals/edit-block/edit-block.component.ts | 21 --- .../remove-block/remove-block.component.html | 3 - .../remove-block/remove-block.component.scss | 0 .../remove-block/remove-block.component.ts | 12 -- .../modals/settings/settings.component.html | 4 +- .../page/tower/block/block.component.html | 2 +- .../pages/page/tower/block/block.component.ts | 24 ++- .../page/tower/tasks/tasks.component.html | 3 +- .../pages/page/tower/tasks/tasks.component.ts | 52 ++---- .../pages/page/tower/tower.component.html | 10 +- .../pages/page/tower/tower.component.ts | 55 ++++--- src/app/components/pages/pages.component.html | 4 +- src/app/components/pages/pages.component.ts | 16 +- .../shared/select-add/select-add.component.ts | 5 +- src/app/services/modal.service.ts | 33 ++-- src/app/utils/range.ts | 2 +- src/library/main.scss | 1 + 29 files changed, 489 insertions(+), 329 deletions(-) create mode 100644 src/app/components/modal/modals/blocks/blocks.component.html create mode 100644 src/app/components/modal/modals/blocks/blocks.component.scss create mode 100644 src/app/components/modal/modals/blocks/blocks.component.ts delete mode 100644 src/app/components/modal/modals/create-block/create-block.component.html delete mode 100644 src/app/components/modal/modals/create-block/create-block.component.scss delete mode 100644 src/app/components/modal/modals/create-block/create-block.component.ts delete mode 100644 src/app/components/modal/modals/edit-block/edit-block.component.html delete mode 100644 src/app/components/modal/modals/edit-block/edit-block.component.scss delete mode 100644 src/app/components/modal/modals/edit-block/edit-block.component.ts delete mode 100644 src/app/components/modal/modals/remove-block/remove-block.component.html delete mode 100644 src/app/components/modal/modals/remove-block/remove-block.component.scss delete mode 100644 src/app/components/modal/modals/remove-block/remove-block.component.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 6c3b288..8249202 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -10,9 +10,15 @@ import { CancelService } from './services/cancel.service'; export class AppComponent implements DoCheck { title = 'life'; - constructor(public cancelService: CancelService) {} + constructor(public cancelService: CancelService) { + window.addEventListener('keydown', (event: KeyboardEvent) => { + if (event.key === 'Escape') { + this.cancelService.cancelAll(); + } + }); + } ngDoCheck() { - console.log('app change detection'); + // console.log('app change detection'); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a9173db..e739aff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,6 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; - import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { PageComponent } from './components/pages/page/page.component'; @@ -13,39 +12,34 @@ import { FormsModule } from '@angular/forms'; import { BlockComponent } from './components/pages/page/tower/block/block.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { DragDropModule } from '@angular/cdk/drag-drop'; -import { EditBlockComponent } from './components/modal/modals/edit-block/edit-block.component'; import { SettingsComponent } from './components/modal/modals/settings/settings.component'; import { RemoveTowerComponent } from './components/modal/modals/remove-tower/remove-tower.component'; import { RemovePageComponent } from './components/modal/modals/remove-page/remove-page.component'; import { GetStartedComponent } from './components/modal/modals/get-started/get-started.component'; -import { CreateBlockComponent } from './components/modal/modals/create-block/create-block.component'; -import { RemoveBlockComponent } from './components/modal/modals/remove-block/remove-block.component'; import { ToggleComponent } from './components/shared/toggle/toggle.component'; import { TasksComponent } from './components/pages/page/tower/tasks/tasks.component'; import { ColorPipe } from './pipes/color.pipe'; -import { Root } from './store/root'; -import { InnerNode, InnerNodeState } from './store/inner-node'; +import { BlocksComponent } from './components/modal/modals/blocks/blocks.component'; @NgModule({ declarations: [ AppComponent, PageComponent, + BlockComponent, TowerComponent, DoubleSliderComponent, PagesComponent, SelectAddComponent, ModalComponent, BlockComponent, - EditBlockComponent, SettingsComponent, RemoveTowerComponent, RemovePageComponent, GetStartedComponent, - CreateBlockComponent, - RemoveBlockComponent, ToggleComponent, TasksComponent, - ColorPipe + ColorPipe, + BlocksComponent ], imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule], providers: [], diff --git a/src/app/components/modal/modal.component.html b/src/app/components/modal/modal.component.html index 27d4714..43fead8 100644 --- a/src/app/components/modal/modal.component.html +++ b/src/app/components/modal/modal.component.html @@ -1,7 +1,9 @@ -
- - - +
+ diff --git a/src/app/components/modal/modal.component.ts b/src/app/components/modal/modal.component.ts index f296a20..a00bb0c 100644 --- a/src/app/components/modal/modal.component.ts +++ b/src/app/components/modal/modal.component.ts @@ -1,5 +1,6 @@ -import { ChangeDetectorRef, Component } from '@angular/core'; +import { Component } from '@angular/core'; import { ModalService, ModalType } from '../../services/modal.service'; +import { CancelService } from '../../services/cancel.service'; @Component({ selector: 'app-modal', @@ -9,16 +10,7 @@ import { ModalService, ModalType } from '../../services/modal.service'; export class ModalComponent { ModalType = ModalType; - constructor(public modalService: ModalService, private changeDetectionRef: ChangeDetectorRef) { - window.addEventListener('keydown', (event: KeyboardEvent) => { - if (event.key === 'Escape') { - this.modalService.cancel(); - } - }); - - /*window.addEventListener('resize', (_: UIEvent) => { - console.log('resize'); - this.changeDetectionRef.markForCheck(); - });*/ + constructor(public modalService: ModalService, private cancelService: CancelService) { + this.cancelService.subscribe(this, () => this.modalService.cancel()); } } diff --git a/src/app/components/modal/modals/blocks/blocks.component.html b/src/app/components/modal/modals/blocks/blocks.component.html new file mode 100644 index 0000000..425c480 --- /dev/null +++ b/src/app/components/modal/modals/blocks/blocks.component.html @@ -0,0 +1,81 @@ +
+
+
+
+ +
+
+

View item

+
+ +
+ +
+ + + +
+ +
+ +
+ edit +
+
+ +
+
+ +
+
+

Create an item

+
+ +
+ +
+ + + +
+ +
+ + +
+
+
diff --git a/src/app/components/modal/modals/blocks/blocks.component.scss b/src/app/components/modal/modals/blocks/blocks.component.scss new file mode 100644 index 0000000..2ad1eb7 --- /dev/null +++ b/src/app/components/modal/modals/blocks/blocks.component.scss @@ -0,0 +1,134 @@ +@import '../../../../../styles'; + +:host { + @include center-child(); + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + overflow-x: auto; + + &::-webkit-scrollbar { + width: 0; + height: 0; + } + + section { + width: 100%; + height: 100%; + + display: flex; + align-items: center; + + box-sizing: border-box; + } +} + +.card { + @include card(); + box-shadow: $shadow; + display: block; + + transform-origin: center center; + + flex: 0 0 auto; + width: 66vw; + max-width: 400px; + @media (max-width: $mobile-width) { + width: 300px; + } + + box-sizing: border-box; + padding: var(--large-padding); + margin: calc(var(--large-padding) / 2); + position: relative; + + .mask { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + z-index: 100; + + @include card(); + } + + &:first-child { + margin-left: var(--large-padding); + } + + &.transparent { + opacity: 0; + } + + @include inner-spacing(var(--large-padding)); + + .header { + @include center-child(); + + .exit { + position: absolute; + left: var(--large-padding); + + @include exit(); + } + } + + .edit { + position: relative; + display: inline-block; + float: right; + opacity: 0.25; + cursor: pointer; + + img { + @include square(16px); + } + + transition: opacity $short-animation-time; + + &:before { + content: ''; + display: block; + position: absolute; + bottom: calc(-1 * #{$line-height}); + left: 0; + height: $line-height; + background-color: $text-color; + width: 0; + transition: width $long-animation-time; + } + + @media (min-width: $mobile-width) { + &:hover { + opacity: 0.5; + } + &:hover { + &:before { + width: 100% !important; + } + } + } + + &.active { + &:before { + width: 100% !important; + } + } + + &.active { + opacity: 1; + } + } +} + +.card:last-child:after { + content: ''; + height: 1px; + width: var(--large-padding); + right: calc(-1 * var(--large-padding)); + display: block; + position: absolute; +} diff --git a/src/app/components/modal/modals/blocks/blocks.component.ts b/src/app/components/modal/modals/blocks/blocks.component.ts new file mode 100644 index 0000000..64f0671 --- /dev/null +++ b/src/app/components/modal/modals/blocks/blocks.component.ts @@ -0,0 +1,154 @@ +import { ChangeDetectorRef, Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ModalService } from '../../../../services/modal.service'; +import { Tower } from '../../../../model/tower'; +import { Observable } from 'rxjs/internal/Observable'; +import { Block } from '../../../../model/block'; +import { IBlock } from '../../../../interfaces/persistance/block'; +import { CancelService } from '../../../../services/cancel.service'; +import { range } from 'src/app/utils/range'; +import { el } from '@angular/platform-browser/testing/src/browser_util'; + +const SWIPE_LIMIT = 0.35; + +@Component({ + selector: 'app-blocks', + templateUrl: './blocks.component.html', + styleUrls: ['./blocks.component.scss'] +}) +export class BlocksComponent implements OnInit, OnDestroy { + readonly range = range; + + tower: Tower; + + editedValues: Partial; + + endOfScrollToken = 0; + editMode = false; + activeChild: number; + scrollMayEnd = true; + + @ViewChild('container') container: ElementRef; + + private subscription; + private onlyDone: boolean; + + @HostListener('click') cancel() { + this.cancelService.cancelAll(); + } + + @HostListener('touchstart') fingerDown() { + this.scrollMayEnd = false; + } + + @HostListener('touchend') fingerUp() { + this.scrollMayEnd = true; + this.onScroll(); + } + + @HostListener('scroll') onScroll() { + this.animateScroll(); + const newToken = ++this.endOfScrollToken; + setTimeout(() => { + if (newToken === this.endOfScrollToken && this.scrollMayEnd) { + this.adjustPosition(); + } + }, 120); + } + + constructor( + private modalService: ModalService, + private cancelService: CancelService, + private changeDetector: ChangeDetectorRef, + private component: ElementRef + ) {} + + get blocks(): Array { + return this.tower.blocks.filter(b => b.isDone === this.onlyDone); + } + + ngOnInit() { + const { + tower$, + onlyDone, + startBlock + }: { tower$: Observable; onlyDone: boolean; startBlock: Block } = this.modalService.active.input; + + this.onlyDone = onlyDone; + this.subscription = tower$.subscribe(value => { + this.tower = value; + setTimeout(() => this.scrollToChild(this.blocks.indexOf(startBlock) + 1, true)); + }); + + this.editedValues = { + isDone: onlyDone, + description: '' + }; + } + + animateScroll() { + if (!this.container || !this.component) { + return; + } + + const c = this.component.nativeElement; + + [...this.container.nativeElement.children] + .slice(1, -1) + .forEach(element => + this.animate( + element.style, + element.querySelector('.mask').style, + Math.abs(element.offsetLeft - c.scrollLeft + element.clientWidth / 2 - window.innerWidth / 2) / + element.clientWidth + ) + ); + } + + animate(cardStyle, maskStyle, t: number) { + t = Math.min(1, Math.max(0, t)); + maskStyle.opacity = Math.pow(t, 0.5).toString(); + maskStyle.display = t === 0 ? 'none' : 'block'; + } + + adjustPosition() { + if (!this.container || !this.component) { + return; + } + + const c = this.component.nativeElement; + + const middle = + [...this.container.nativeElement.children] + .slice(1, -1) + .map(element => Math.abs(element.offsetLeft - c.scrollLeft + element.clientWidth / 2 - window.innerWidth / 2)) + .map((value, index) => (Math.abs(index + 1 - this.activeChild) === 1 ? value / 1.5 : value)) + .reduce( + (middleIndex, current, currentIndex, list) => (list[middleIndex] < current ? middleIndex : currentIndex), + 0 + ) + 1; + + this.scrollToChild(middle); + this.changeDetector.markForCheck(); + } + + scrollToChild(index: number, instantly?: boolean) { + this.activeChild = index; + const element = this.container.nativeElement.children[index]; + this.component.nativeElement.scrollTo({ + left: element.offsetLeft - (window.innerWidth / 2 - element.clientWidth / 2), + behavior: instantly ? 'auto' : 'smooth' + }); + } + + submitAdd() { + this.editedValues.created = new Date(); + this.tower.addBlock(this.editedValues as IBlock); + this.modalService.submit(); + } + + ngOnDestroy() { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } +} diff --git a/src/app/components/modal/modals/create-block/create-block.component.html b/src/app/components/modal/modals/create-block/create-block.component.html deleted file mode 100644 index cf5a62b..0000000 --- a/src/app/components/modal/modals/create-block/create-block.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
-

Create an item

-
- -
- - -
- - - - -
- - -
- - - diff --git a/src/app/components/modal/modals/create-block/create-block.component.scss b/src/app/components/modal/modals/create-block/create-block.component.scss deleted file mode 100644 index 2d8d57c..0000000 --- a/src/app/components/modal/modals/create-block/create-block.component.scss +++ /dev/null @@ -1,30 +0,0 @@ -@import '../../../../../styles'; - -:host { - @include card(); - - width: 66vw; - max-width: 400px; - @media (max-width: $mobile-width) { - width: 300px; - } - - box-sizing: border-box; - padding: var(--large-padding); - - position: relative; - box-shadow: $shadow; - - @include inner-spacing(var(--large-padding)); - - .header { - @include center-child(); - - .exit { - position: absolute; - left: var(--large-padding); - - @include exit(); - } - } -} diff --git a/src/app/components/modal/modals/create-block/create-block.component.ts b/src/app/components/modal/modals/create-block/create-block.component.ts deleted file mode 100644 index 5f9fed9..0000000 --- a/src/app/components/modal/modals/create-block/create-block.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Component } from '@angular/core'; -import { ModalService } from '../../../../services/modal.service'; - -@Component({ - selector: 'app-create-block', - templateUrl: './create-block.component.html', - styleUrls: ['./create-block.component.scss'] -}) -export class CreateBlockComponent { - selected: string; - description: string = null; - isDone: boolean = !this.modalService.active.input.isTask; - - constructor(public modalService: ModalService) {} - - submit() { - if (!this.selected) { - return; - } - - this.modalService.submit({ - selected: this.selected, - description: this.description, - isDone: this.isDone - }); - } -} diff --git a/src/app/components/modal/modals/edit-block/edit-block.component.html b/src/app/components/modal/modals/edit-block/edit-block.component.html deleted file mode 100644 index 8e967c6..0000000 --- a/src/app/components/modal/modals/edit-block/edit-block.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
-

View item

-
- -
- - -
- - - - -
- - -
- - - diff --git a/src/app/components/modal/modals/edit-block/edit-block.component.scss b/src/app/components/modal/modals/edit-block/edit-block.component.scss deleted file mode 100644 index 03d331a..0000000 --- a/src/app/components/modal/modals/edit-block/edit-block.component.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import '../../../../../styles'; - -:host { - @include card(); - box-shadow: $shadow; - - width: 66vw; - max-width: 400px; - @media (max-width: $mobile-width) { - width: 300px; - } - - box-sizing: border-box; - padding: var(--large-padding); - position: relative; - - @include inner-spacing(var(--large-padding)); - - .header { - @include center-child(); - - .exit { - position: absolute; - left: var(--large-padding); - - @include exit(); - } - } -} diff --git a/src/app/components/modal/modals/edit-block/edit-block.component.ts b/src/app/components/modal/modals/edit-block/edit-block.component.ts deleted file mode 100644 index e6c8c28..0000000 --- a/src/app/components/modal/modals/edit-block/edit-block.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component } from '@angular/core'; -import { ModalService } from '../../../../services/modal.service'; - -@Component({ - selector: 'app-edit-block', - templateUrl: './edit-block.component.html', - styleUrls: ['./edit-block.component.scss'] -}) -export class EditBlockComponent { - selected: string; - - constructor(public modalService: ModalService) {} - - submit() { - this.modalService.submit({ - selected: this.selected, - description: this.modalService.active.input.description, - isDone: this.modalService.active.input.isDone - }); - } -} diff --git a/src/app/components/modal/modals/remove-block/remove-block.component.html b/src/app/components/modal/modals/remove-block/remove-block.component.html deleted file mode 100644 index f95c8a3..0000000 --- a/src/app/components/modal/modals/remove-block/remove-block.component.html +++ /dev/null @@ -1,3 +0,0 @@ -

- remove-block works! -

diff --git a/src/app/components/modal/modals/remove-block/remove-block.component.scss b/src/app/components/modal/modals/remove-block/remove-block.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/components/modal/modals/remove-block/remove-block.component.ts b/src/app/components/modal/modals/remove-block/remove-block.component.ts deleted file mode 100644 index 44ad3e0..0000000 --- a/src/app/components/modal/modals/remove-block/remove-block.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-remove-block', - templateUrl: './remove-block.component.html', - styleUrls: ['./remove-block.component.scss'] -}) -export class RemoveBlockComponent implements OnInit { - constructor() {} - - ngOnInit() {} -} diff --git a/src/app/components/modal/modals/settings/settings.component.html b/src/app/components/modal/modals/settings/settings.component.html index 3d893ae..72f00b5 100644 --- a/src/app/components/modal/modals/settings/settings.component.html +++ b/src/app/components/modal/modals/settings/settings.component.html @@ -4,7 +4,6 @@
-
-

There can be a maximum of 5 towers on each page.

- + diff --git a/src/app/components/pages/page/tower/block/block.component.html b/src/app/components/pages/page/tower/block/block.component.html index 59c0d82..899c757 100644 --- a/src/app/components/pages/page/tower/block/block.component.html +++ b/src/app/components/pages/page/tower/block/block.component.html @@ -1 +1 @@ -
+
diff --git a/src/app/components/pages/page/tower/block/block.component.ts b/src/app/components/pages/page/tower/block/block.component.ts index 0fd1d61..c3a60b4 100644 --- a/src/app/components/pages/page/tower/block/block.component.ts +++ b/src/app/components/pages/page/tower/block/block.component.ts @@ -1,7 +1,7 @@ -import { Component, Input } from '@angular/core'; -import { Block, BlockState } from '../../../../../model/block'; +import { ChangeDetectorRef, Component, Input } from '@angular/core'; import { ModalService } from '../../../../../services/modal.service'; import { ColoredBlock, Tower } from '../../../../../model/tower'; +import { Observable } from 'rxjs/internal/Observable'; @Component({ selector: 'app-block', @@ -10,25 +10,21 @@ import { ColoredBlock, Tower } from '../../../../../model/tower'; }) export class BlockComponent { @Input() block: ColoredBlock; - @Input() tower: Tower; + @Input() tower$: Observable; - constructor(private modalService: ModalService) {} + constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {} async handleClick() { try { - const { selected, description, isDone } = await this.modalService.showEditBlock({ - options: this.tower.tags, - default: this.block.tag, - description: this.block.description, - isDone: this.block.isDone - }); - this.block.changeKeys({ - tag: selected, - description, - isDone + await this.modalService.showBlocks({ + tower$: this.tower$, + startBlock: this.block, + onlyDone: true }); } catch { // pass + } finally { + this.changeDetection.markForCheck(); } } } diff --git a/src/app/components/pages/page/tower/tasks/tasks.component.html b/src/app/components/pages/page/tower/tasks/tasks.component.html index 4355c5f..4c05c0c 100644 --- a/src/app/components/pages/page/tower/tasks/tasks.component.html +++ b/src/app/components/pages/page/tower/tasks/tasks.component.html @@ -1,8 +1,9 @@ -
+

{{ tasks.length == 0 ? '' : tasks.length }} + {{ tasks.length == 0 ? '​' : tasks.length == 1 ? 'task' : 'tasks' }}

diff --git a/src/app/components/pages/page/tower/tasks/tasks.component.ts b/src/app/components/pages/page/tower/tasks/tasks.component.ts index d8fa365..d2bfdc1 100644 --- a/src/app/components/pages/page/tower/tasks/tasks.component.ts +++ b/src/app/components/pages/page/tower/tasks/tasks.component.ts @@ -1,19 +1,19 @@ -import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { Block, BlockState } from '../../../../../model/block'; +import { ChangeDetectorRef, Component, ElementRef, Input, ViewChild } from '@angular/core'; +import { Block } from '../../../../../model/block'; import { Tower } from '../../../../../model/tower'; import { ModalService } from '../../../../../services/modal.service'; import { CancelService } from '../../../../../services/cancel.service'; import { IColor } from '../../../../../interfaces/color'; -import { IBlock } from '../../../../../interfaces/persistance/block'; +import { Observable } from 'rxjs/internal/Observable'; @Component({ selector: 'app-tasks', templateUrl: './tasks.component.html', styleUrls: ['./tasks.component.scss'] }) -export class TasksComponent implements OnInit { +export class TasksComponent { @Input() tasks: Array; - @Input() tower: Tower; + @Input() tower$: Observable; private _isOpen = false; @Input() set isOpen(value: boolean) { @@ -29,47 +29,27 @@ export class TasksComponent implements OnInit { @ViewChild('allTask') allTask: ElementRef; - constructor(private modalService: ModalService, private cancelService: CancelService) { + constructor( + private modalService: ModalService, + private cancelService: CancelService, + private changeDetection: ChangeDetectorRef + ) { this.cancelService.subscribe(this, () => { this.isOpen = false; }); } - ngOnInit() {} - async handleClick(block: Block) { try { - const { selected, description, isDone } = await this.modalService.showEditBlock({ - options: this.tower.tags, - default: block.tag, - description: block.description, - isDone: block.isDone + await this.modalService.showBlocks({ + tower$: this.tower$, + startBlock: block, + onlyDone: false }); - - const change: Partial = { - tag: selected, - description, - isDone - }; - if (!block.isDone && isDone) { - change.created = new Date(); - } - - block.changeKeys(change); } catch { // pass - } - } - - public async addTask() { - try { - const { selected: tag, description, isDone } = await this.modalService.showCreateBlock({ - options: this.tower.tags, - isTask: true - }); - this.tower.addBlock({ tag, description, isDone }); - } catch (e) { - // pass + } finally { + this.changeDetection.markForCheck(); } } } diff --git a/src/app/components/pages/page/tower/tower.component.html b/src/app/components/pages/page/tower/tower.component.html index 3bcad7e..e795351 100644 --- a/src/app/components/pages/page/tower/tower.component.html +++ b/src/app/components/pages/page/tower/tower.component.html @@ -1,19 +1,19 @@
- +
- add item + add item
-
+
diff --git a/src/app/components/pages/page/tower/tower.component.ts b/src/app/components/pages/page/tower/tower.component.ts index afda1d4..71d0fd1 100644 --- a/src/app/components/pages/page/tower/tower.component.ts +++ b/src/app/components/pages/page/tower/tower.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { ColoredBlock, Tower } from '../../../../model/tower'; import { ModalService } from '../../../../services/modal.service'; import { Observable } from 'rxjs/internal/Observable'; @@ -14,9 +14,9 @@ type StyledBlock = ColoredBlock & { style: { [p: string]: string }; shouldDraw: }) export class TowerComponent implements OnInit { @Input() dateRange$: Observable>; - private dateRange: Range; - @Input() tower$: Observable; + + private dateRange: Range; private tower: Tower; get towerName(): string { @@ -28,18 +28,19 @@ export class TowerComponent implements OnInit { } tasks: Array; - blocks: Array = []; + + styledBlocks: Array = []; + get drawableBlocks(): Array { - return this.blocks.filter(b => b.shouldDraw); + return this.styledBlocks.filter(b => b.shouldDraw); } - public constructor(private modalService: ModalService) {} + public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {} ngOnInit() { this.tower$.subscribe(value => { if (value) { - console.log('update'); - this.blocks = value.coloredBlocks + this.styledBlocks = value.coloredBlocks .filter(b => b.isDone) .map(b => { const classedBlock = b as StyledBlock; @@ -59,11 +60,10 @@ export class TowerComponent implements OnInit { (this.tower.blocks.length === value.blocks.length && this.tower.blocks.filter(b => b.isDone).length + 1 === value.blocks.filter(b => b.isDone).length) ) { - const lastBlock = top(this.blocks); + const lastBlock = top(this.styledBlocks); if (lastBlock) { lastBlock.style = { transform: 'translateY(500%)', opacity: '0' }; - lastBlock.cssClass = 'descend'; - setTimeout(() => (lastBlock.style = { transform: 'translateY(0)', opacity: '1' }), 0); + setTimeout(() => this.makeBlockDescend(lastBlock), 0); } } } @@ -79,30 +79,39 @@ export class TowerComponent implements OnInit { }); } + makeBlockDescend(block: StyledBlock) { + block.cssClass = 'descend'; + block.style = { transform: 'translateY(0)', opacity: '1' }; + } + + makeBlockAscend(block: StyledBlock) { + block.cssClass = 'ascend'; + block.style = { transform: 'translateY(500%)', opacity: '0' }; + } + initData(newDateRange: Range) { - for (const block of this.blocks) { + for (const block of this.styledBlocks) { block.shouldDraw = newDateRange.from <= block.created; - if ((block.cssClass === '' || block.cssClass === 'descend') && newDateRange.to < block.created) { - block.cssClass = 'ascend'; - block.style = { transform: 'translateY(500%)', opacity: '0' }; + if (newDateRange.to < block.created) { + this.makeBlockAscend(block); } - if (block.shouldDraw && block.cssClass === 'ascend' && block.created <= newDateRange.to) { - block.cssClass = 'descend'; - block.style = { transform: 'translateY(0)', opacity: '1' }; + if (block.shouldDraw && block.created <= newDateRange.to) { + this.makeBlockDescend(block); } } } public async addBlock() { try { - const { selected: tag, description, isDone } = await this.modalService.showCreateBlock({ - options: this.tower.tags, - isTask: false + await this.modalService.showBlocks({ + tower$: this.tower$, + onlyDone: true }); - this.tower.addBlock({ tag, description, isDone }); - } catch (e) { + } catch { // pass + } finally { + this.changeDetection.markForCheck(); } } } diff --git a/src/app/components/pages/pages.component.html b/src/app/components/pages/pages.component.html index eea310e..81a7278 100644 --- a/src/app/components/pages/pages.component.html +++ b/src/app/components/pages/pages.component.html @@ -17,4 +17,6 @@
- + diff --git a/src/app/components/pages/pages.component.ts b/src/app/components/pages/pages.component.ts index ba2eddd..30f0312 100644 --- a/src/app/components/pages/pages.component.ts +++ b/src/app/components/pages/pages.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { Page } from '../../model/page'; import { DataService } from '../../services/data.service'; import { ModalService } from '../../services/modal.service'; @@ -32,7 +32,11 @@ export class PagesComponent implements OnInit { private readonly _selectedPage: BehaviorSubject = new BehaviorSubject(null); readonly selectedPage$: Observable = this._selectedPage.asObservable(); - constructor(public dataService: DataService, private modalService: ModalService) { + constructor( + public dataService: DataService, + private modalService: ModalService, + private changeDetection: ChangeDetectorRef + ) { const userData = JSON.parse(window.localStorage.getItem(USER_DATA_KEY)); if (userData !== null) { this.selectedPageName = userData.selectedPage; @@ -42,7 +46,7 @@ export class PagesComponent implements OnInit { ngOnInit() { this.dataService.children$.subscribe(pages => { if (pages) { - if (this.pages && this.pages.length - 1 === pages.length) { + if (this.pages && !pages.includes(this._selectedPage.getValue().latestVersion)) { this.selectedPageName = null; } this.pages = pages; @@ -54,10 +58,10 @@ export class PagesComponent implements OnInit { changeName({ from, to }: { from: string; to: string }) { const page = this.pages.find(p => p.name === from); if (page) { - page.changeName(to); if (from === this.selectedPageName) { - this.selectPage(to); + this.selectedPageName = to; } + page.changeName(to); } } @@ -94,6 +98,8 @@ export class PagesComponent implements OnInit { await this.modalService.showSettings(this.selectedPage$); } catch { // pass + } finally { + this.changeDetection.markForCheck(); } } } diff --git a/src/app/components/shared/select-add/select-add.component.ts b/src/app/components/shared/select-add/select-add.component.ts index fb39622..11cb8eb 100644 --- a/src/app/components/shared/select-add/select-add.component.ts +++ b/src/app/components/shared/select-add/select-add.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; +import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core'; import { CancelService } from '../../../services/cancel.service'; @Component({ @@ -43,10 +43,11 @@ export class SelectAddComponent { newOption: string; isOpen = false; - constructor(private cancelService: CancelService) { + constructor(private cancelService: CancelService, private changeDetection: ChangeDetectorRef) { this.cancelService.subscribe(this, () => { this.isOpen = false; this.editMode = false; + this.changeDetection.markForCheck(); }); } diff --git a/src/app/services/modal.service.ts b/src/app/services/modal.service.ts index 5054bf0..c376087 100644 --- a/src/app/services/modal.service.ts +++ b/src/app/services/modal.service.ts @@ -4,11 +4,10 @@ import { top } from '../utils/top'; import { CancelService } from './cancel.service'; import { Page } from '../model/page'; import { Observable } from 'rxjs/internal/Observable'; +import { Block } from '../model/block'; export enum ModalType { - createBlock, - editBlock, - removeBlock, + blocks, settings, removeTower, removePage, @@ -30,20 +29,8 @@ export class ModalService { constructor(private cancelService: CancelService) {} - showCreateBlock(input: { - options: string[]; - isTask: boolean; - }): Promise<{ selected: string; description: string; isDone: boolean }> { - return this.createPromiseAndPushToStack(input, ModalType.createBlock); - } - - showEditBlock(data: { - default: string; - options: string[]; - description: string; - isDone: boolean; - }): Promise<{ selected: string; description: string; isDone: boolean }> { - return this.createPromiseAndPushToStack(data, ModalType.editBlock); + showBlocks(input: { tower$: Observable; onlyDone: boolean; startBlock?: Block }): Promise { + return this.createPromiseAndPushToStack(input, ModalType.blocks); } showSettings(selectedPage: Observable): Promise { @@ -63,13 +50,17 @@ export class ModalService { } submit(output?: any) { - const { resolve } = this.modalStack.pop(); - resolve(output); + const modal = this.modalStack.pop(); + if (modal) { + modal.resolve(output); + } } cancel() { - const { reject } = this.modalStack.pop(); - reject(); + const modal = this.modalStack.pop(); + if (modal) { + modal.reject(); + } } private createPromiseAndPushToStack(input: any, type: ModalType): Promise { diff --git a/src/app/utils/range.ts b/src/app/utils/range.ts index 5990ba9..023f8be 100644 --- a/src/app/utils/range.ts +++ b/src/app/utils/range.ts @@ -1,7 +1,7 @@ export const range = ({ min = 0, max = Infinity, step = 1 }: { min?: number; max?: number; step?: number }) => { return { *[Symbol.iterator]() { - for (let i = min; i < max; yield i, i += step); + for (let i = min; i < max; yield i, i += step) {} } }; }; diff --git a/src/library/main.scss b/src/library/main.scss index 47bddb0..0156b7f 100644 --- a/src/library/main.scss +++ b/src/library/main.scss @@ -48,6 +48,7 @@ img { *::-webkit-scrollbar { width: 4px; + height: 4px; } *::-webkit-scrollbar-track {