This commit is contained in:
Andras Schmelczer 2019-09-21 11:51:53 +02:00
parent 674f07f5f1
commit 19aad2b2af
23 changed files with 231 additions and 10012 deletions

9896
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@
"core-js": "^2.5.4", "core-js": "^2.5.4",
"rxjs": "~6.3.3", "rxjs": "~6.3.3",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"uuid": "^3.3.3",
"zone.js": "~0.8.26" "zone.js": "~0.8.26"
}, },
"devDependencies": { "devDependencies": {

View file

@ -20,6 +20,7 @@ import { ToggleComponent } from './components/shared/toggle/toggle.component';
import { TasksComponent } from './components/pages/page/tower/tasks/tasks.component'; import { TasksComponent } from './components/pages/page/tower/tasks/tasks.component';
import { ColorPipe } from './pipes/color.pipe'; import { ColorPipe } from './pipes/color.pipe';
import { BlocksComponent } from './components/modal/modals/blocks/blocks.component'; import { BlocksComponent } from './components/modal/modals/blocks/blocks.component';
import { FormatDatePipe } from './pipes/format-date.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -39,7 +40,8 @@ import { BlocksComponent } from './components/modal/modals/blocks/blocks.compone
ToggleComponent, ToggleComponent,
TasksComponent, TasksComponent,
ColorPipe, ColorPipe,
BlocksComponent BlocksComponent,
FormatDatePipe
], ],
imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule], imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule],
providers: [], providers: [],

View file

@ -3,7 +3,7 @@
class="{{ modalService.active ? 'active' : '' }}" class="{{ modalService.active ? 'active' : '' }}"
[ngSwitch]="modalService.active?.type" [ngSwitch]="modalService.active?.type"
> >
<app-blocks (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.blocks"></app-blocks> <app-blocks (save)="save = $event" (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.blocks"></app-blocks>
<app-remove-tower (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.removeTower"></app-remove-tower> <app-remove-tower (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.removeTower"></app-remove-tower>
<app-settings (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.settings"></app-settings> <app-settings (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.settings"></app-settings>
<app-get-started (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.getStarted"></app-get-started> <app-get-started (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.getStarted"></app-get-started>

View file

@ -10,7 +10,16 @@ import { CancelService } from '../../services/cancel.service';
export class ModalComponent { export class ModalComponent {
ModalType = ModalType; ModalType = ModalType;
save: () => void = null;
constructor(public modalService: ModalService, private cancelService: CancelService) { constructor(public modalService: ModalService, private cancelService: CancelService) {
this.cancelService.subscribe(this, () => this.modalService.cancel()); this.cancelService.subscribe(this, () => {
if (this.save) {
this.save();
this.save = null;
} else {
this.modalService.cancel();
}
});
} }
} }

View file

@ -1,4 +1,4 @@
<section #container> <section #container *ngIf="tower">
<div class="card placeholder"></div> <div class="card placeholder"></div>
<div <div
*ngFor="let i of range({ max: blocks.length })" *ngFor="let i of range({ max: blocks.length })"
@ -12,13 +12,12 @@
<div class="header"> <div class="header">
<div class="exit" (click)="modalService.cancel()"></div> <div class="exit" (click)="modalService.cancel()"></div>
<div class="block" [ngStyle]="{ 'background-color': tower.getColorOfTag(editedValues[i].tag) | color }"></div> <div class="block" [ngStyle]="{ 'background-color': tower.getColorOfTag(editedValues[i].tag) | color }"></div>
<h1>View item</h1> <h1 [innerText]="editedValues[i]?.created | formatDate"></h1>
</div> </div>
<div class="select-add-container"> <div class="select-add-container">
<app-select-add <app-select-add
class="select" class="select"
[disabled]="!editMode"
[options]="tower.tags" [options]="tower.tags"
[default]="editedValues[i].tag" [default]="editedValues[i].tag"
[alwaysDropShadow]="true" [alwaysDropShadow]="true"
@ -28,30 +27,16 @@
></app-select-add> ></app-select-add>
</div> </div>
<textarea <textarea placeholder="Write a description here…" [(ngModel)]="editedValues[i].description"></textarea>
[disabled]="!editMode"
placeholder="{{ editMode ? 'Write a description here…' : '' }}"
[(ngModel)]="editedValues[i].description"
></textarea>
<div> <div>
<app-toggle <app-toggle
[beforeText]="'This task hasn\'t been finished yet'" [beforeText]="'This task hasn\'t been finished yet'"
[afterText]="'Goal already accomplished'" [afterText]="'Goal already accomplished'"
[default]="blocks[i].isDone" [default]="blocks[i].isDone"
[disabled]="!editMode"
(value)="editedValues[i].isDone = $event" (value)="editedValues[i].isDone = $event"
></app-toggle> ></app-toggle>
</div> </div>
<div class="bottom">
<button class="{{ editMode && i + 1 === activeChild ? '' : 'hidden' }}" (click)="submitChange()">
Save and exit
</button>
<div class="edit {{ editMode && i + 1 === activeChild ? 'active' : '' }}" (click)="editMode = !editMode">
<img src="assets/pen.svg" alt="edit" />
</div>
</div>
</div> </div>
<div <div
@ -65,7 +50,7 @@
<div class="header"> <div class="header">
<div class="exit" (click)="modalService.cancel()"></div> <div class="exit" (click)="modalService.cancel()"></div>
<div class="block" [ngStyle]="{ 'background-color': tower.getColorOfTag(top(editedValues).tag) | color }"></div> <div class="block" [ngStyle]="{ 'background-color': tower.getColorOfTag(top(editedValues).tag) | color }"></div>
<h1>Create an item</h1> <h1>Create now</h1>
</div> </div>
<div class="select-add-container"> <div class="select-add-container">
@ -75,7 +60,8 @@
[default]="tower.tags.length ? tower.tags[0] : null" [default]="tower.tags.length ? tower.tags[0] : null"
[alwaysDropShadow]="true" [alwaysDropShadow]="true"
[onlyShadowBorder]="true" [onlyShadowBorder]="true"
[placeholder]="'Tag this item…'" [placeholder]="'Set a category…'"
[newValuePlaceholder]="'Add a category…'"
(value)="top(editedValues).tag = $event" (value)="top(editedValues).tag = $event"
></app-select-add> ></app-select-add>
</div> </div>

View file

@ -70,8 +70,8 @@
&.placeholder { &.placeholder {
opacity: 0 !important; opacity: 0 !important;
width: 1000px; width: 60vw;
max-width: 1000px; max-width: 60vw;
} }
@include inner-spacing(var(--large-padding)); @include inner-spacing(var(--large-padding));

View file

@ -1,4 +1,14 @@
import { ChangeDetectorRef, Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core'; import {
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostListener,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { ModalService } from '../../../../services/modal.service'; import { ModalService } from '../../../../services/modal.service';
import { Tower } from '../../../../model/tower'; import { Tower } from '../../../../model/tower';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
@ -16,20 +26,30 @@ import { top } from 'src/app/utils/top';
export class BlocksComponent implements OnInit, OnDestroy { export class BlocksComponent implements OnInit, OnDestroy {
readonly range = range; readonly range = range;
readonly top = top; readonly top = top;
tower: Tower; tower: Tower;
editedValues: Array<Partial<IBlock>>; editedValues: Array<Partial<IBlock>>;
endOfScrollToken = 0; endOfScrollToken = 0;
editMode = false;
activeChild: number; activeChild: number;
scrollMayEnd = true; scrollMayEnd = true;
onlyDone: boolean; onlyDone: boolean;
@ViewChild('container') container: ElementRef; @ViewChild('container') container: ElementRef;
private subscription;
private intervalID: number;
constructor(
public modalService: ModalService,
private cancelService: CancelService,
private changeDetector: ChangeDetectorRef,
private component: ElementRef
) {
window.addEventListener('resize', this.onScroll.bind(this));
}
@Output() save: EventEmitter<() => void> = new EventEmitter();
get blocks(): Array<Block> {
return this.tower.blocks.filter(b => b.isDone === this.onlyDone);
}
@HostListener('click') cancel() { @HostListener('click') cancel() {
this.cancelService.cancelAll(); this.cancelService.cancelAll();
@ -45,28 +65,13 @@ export class BlocksComponent implements OnInit, OnDestroy {
} }
@HostListener('scroll') onScroll() { @HostListener('scroll') onScroll() {
console.log('scrolling');
this.animateScroll();
const newToken = ++this.endOfScrollToken; const newToken = ++this.endOfScrollToken;
setTimeout(() => { setTimeout(() => {
if (newToken === this.endOfScrollToken && this.scrollMayEnd) { if (newToken === this.endOfScrollToken && this.scrollMayEnd) {
this.adjustPosition(); this.adjustPosition();
} }
}, 120); }, 150);
} this.animateScroll();
constructor(
public modalService: ModalService,
private cancelService: CancelService,
private changeDetector: ChangeDetectorRef,
private component: ElementRef
) {
window.addEventListener('resize', this.onScroll.bind(this));
}
get blocks(): Array<Block> {
return this.tower.blocks.filter(b => b.isDone === this.onlyDone);
} }
ngOnInit() { ngOnInit() {
@ -76,18 +81,31 @@ export class BlocksComponent implements OnInit, OnDestroy {
startBlock startBlock
}: { tower$: Observable<Tower>; onlyDone: boolean; startBlock: Block } = this.modalService.active.input; }: { tower$: Observable<Tower>; onlyDone: boolean; startBlock: Block } = this.modalService.active.input;
this.save.emit(() => this.submitChange());
this.intervalID = setInterval(() => this.changeDetector.detectChanges(), 1000);
this.onlyDone = onlyDone; this.onlyDone = onlyDone;
this.subscription = tower$.subscribe(value => { const subscription = tower$.subscribe(value => {
if (value) {
this.tower = value; this.tower = value;
this.editedValues = this.blocks.map(({ isDone, description, tag }) => ({ isDone, description, tag })); this.editedValues = this.blocks.map(({ isDone, description, tag, created }) => ({
isDone,
description,
tag,
created
}));
this.editedValues.push({ this.editedValues.push({
tag: this.tower.tags.length ? this.tower.tags[0] : null,
isDone: this.onlyDone, isDone: this.onlyDone,
description: '' description: ''
}); });
setTimeout(() => setTimeout(() => {
this.scrollToChild(startBlock ? this.blocks.indexOf(startBlock) + 1 : this.blocks.length + 1, true) this.scrollToChild(startBlock ? this.blocks.indexOf(startBlock) + 1 : this.blocks.length + 1, true);
); subscription.unsubscribe();
});
}
}); });
} }
@ -113,7 +131,6 @@ export class BlocksComponent implements OnInit, OnDestroy {
animate(cardStyle, maskStyle, t: number) { animate(cardStyle, maskStyle, t: number) {
t = Math.min(2, Math.max(0, t)); t = Math.min(2, Math.max(0, t));
cardStyle.opacity = (1.33 * (1 - t / 2)).toString(); cardStyle.opacity = (1.33 * (1 - t / 2)).toString();
console.log(1 - t / 2);
t = Math.min(1, Math.max(0, t)); t = Math.min(1, Math.max(0, t));
maskStyle.opacity = Math.pow(t, 0.5).toString(); maskStyle.opacity = Math.pow(t, 0.5).toString();
maskStyle.display = t <= 0.05 ? 'none' : 'block'; maskStyle.display = t <= 0.05 ? 'none' : 'block';
@ -124,30 +141,25 @@ export class BlocksComponent implements OnInit, OnDestroy {
return; return;
} }
console.log('adjusting position');
const c = this.component.nativeElement; const c = this.component.nativeElement;
const middle = const middle =
[...this.container.nativeElement.children] [...this.container.nativeElement.children]
.slice(1, -1) .slice(1, -1)
.map(element => Math.abs(element.offsetLeft - c.scrollLeft + element.clientWidth / 2 - window.innerWidth / 2)) .map(element => Math.abs(element.offsetLeft - c.scrollLeft + element.clientWidth / 2 - window.innerWidth / 2))
.map((value, index) => .map((value, index) => (Math.abs(index + 1 - this.activeChild) === 1 ? Math.abs(value - 100) : value))
Math.abs(index + 1 - this.activeChild) === 1 ? Math.abs(value - window.innerWidth / 4) : value
)
.reduce( .reduce(
(middleIndex, current, currentIndex, list) => (list[middleIndex] < current ? middleIndex : currentIndex), (middleIndex, current, currentIndex, list) => (list[middleIndex] < current ? middleIndex : currentIndex),
0 0
) + 1; ) + 1;
this.scrollToChild(middle); this.scrollToChild(middle);
this.changeDetector.markForCheck();
} }
scrollToChild(index: number, instantly?: boolean) { scrollToChild(index: number, instantly?: boolean) {
this.activeChild = index; this.activeChild = index;
console.log('scrolling to', index);
const element = this.container.nativeElement.children[index]; const element = this.container.nativeElement.children[index];
this.component.nativeElement.scrollTo({ this.component.nativeElement.scrollTo({
left: element.offsetLeft - (window.innerWidth / 2 - element.clientWidth / 2), left: element.offsetLeft - (window.innerWidth / 2 - element.clientWidth / 2),
behavior: instantly ? 'auto' : 'smooth' behavior: instantly ? 'auto' : 'smooth'
@ -157,17 +169,15 @@ export class BlocksComponent implements OnInit, OnDestroy {
submitAdd() { submitAdd() {
top(this.editedValues).created = new Date(); top(this.editedValues).created = new Date();
this.tower.addBlock(top(this.editedValues) as IBlock); this.tower.addBlock(top(this.editedValues) as IBlock);
this.modalService.submit(); this.cancelService.cancelAll();
} }
submitChange() { submitChange() {
this.blocks[this.activeChild - 1].changeKeys(this.editedValues[this.activeChild - 1]); this.blocks.forEach((b, i) => b.changeKeys(this.editedValues[i]));
this.modalService.submit(); this.modalService.submit();
} }
ngOnDestroy() { ngOnDestroy() {
if (this.subscription) { clearInterval(this.intervalID);
this.subscription.unsubscribe();
}
} }
} }

View file

@ -40,9 +40,7 @@ export class PageComponent implements OnInit {
if (value) { if (value) {
this.towers = value.towers.map((t, index) => { this.towers = value.towers.map((t, index) => {
if (index < this.towers.length) { if (index < this.towers.length) {
if (this.towers[index].getValue() !== t) {
this.towers[index].next(t); this.towers[index].next(t);
}
return this.towers[index]; return this.towers[index];
} }
return new BehaviorSubject(t); return new BehaviorSubject(t);

View file

@ -12,7 +12,7 @@ export class BlockComponent {
@Input() block: ColoredBlock; @Input() block: ColoredBlock;
@Input() tower$: Observable<Tower>; @Input() tower$: Observable<Tower>;
constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {} constructor(private modalService: ModalService) {}
async handleClick() { async handleClick() {
try { try {
@ -23,8 +23,6 @@ export class BlockComponent {
}); });
} catch { } catch {
// pass // pass
} finally {
this.changeDetection.markForCheck();
} }
} }
} }

View file

@ -4,6 +4,7 @@ import { ModalService } from '../../../../services/modal.service';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { Range } from '../../../../interfaces/range'; import { Range } from '../../../../interfaces/range';
import { top } from '../../../../utils/top'; import { top } from '../../../../utils/top';
import { CancelService } from '../../../../services/cancel.service';
type StyledBlock = ColoredBlock & { style: { [p: string]: string }; shouldDraw: boolean; cssClass: string }; type StyledBlock = ColoredBlock & { style: { [p: string]: string }; shouldDraw: boolean; cssClass: string };
@ -35,10 +36,13 @@ export class TowerComponent implements OnInit {
return this.styledBlocks.filter(b => b.shouldDraw); return this.styledBlocks.filter(b => b.shouldDraw);
} }
public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {} public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {
console.log('oo');
}
ngOnInit() { ngOnInit() {
this.tower$.subscribe(value => { this.tower$.subscribe(value => {
console.log(this.tower, value);
if (value) { if (value) {
this.styledBlocks = value.coloredBlocks this.styledBlocks = value.coloredBlocks
.filter(b => b.isDone) .filter(b => b.isDone)
@ -65,13 +69,17 @@ export class TowerComponent implements OnInit {
const lastBlock = top(this.styledBlocks); const lastBlock = top(this.styledBlocks);
if (lastBlock) { if (lastBlock) {
lastBlock.style = { transform: 'translateY(500%)', opacity: '0' }; lastBlock.style = { transform: 'translateY(500%)', opacity: '0' };
setTimeout(() => this.makeBlockDescend(lastBlock), 0); setTimeout(() => {
this.makeBlockDescend(lastBlock);
this.changeDetection.markForCheck();
}, 0);
} }
} }
} }
this.tasks = value.coloredBlocks.filter(block => !block.isDone); this.tasks = value.coloredBlocks.filter(block => !block.isDone);
this.tower = value; this.tower = value;
this.changeDetection.markForCheck();
} }
}); });
@ -112,8 +120,6 @@ export class TowerComponent implements OnInit {
}); });
} catch { } catch {
// pass // pass
} finally {
this.changeDetection.markForCheck();
} }
} }
} }

View file

@ -1,8 +1,5 @@
<div <div class="select-add {{ onlyShadowBorder ? 'shadow-border' : '' }}" (click)="$event.stopPropagation()">
class="select-add {{ onlyShadowBorder ? 'shadow-border' : '' }} {{ disabled ? 'disabled' : '' }}" <div #top class="top" (click)="!editMode && toggle()">
(click)="$event.stopPropagation()"
>
<div #top class="top" (click)="!editMode && !disabled && toggle()">
<p [innerHTML]="selected ? selected : placeholder" *ngIf="!editMode || !selected; else editableSelected"></p> <p [innerHTML]="selected ? selected : placeholder" *ngIf="!editMode || !selected; else editableSelected"></p>
<ng-template #editableSelected> <ng-template #editableSelected>
<input type="text" [value]="selected" (change)="changeOption(selected, $event)" /> <input type="text" [value]="selected" (change)="changeOption(selected, $event)" />
@ -27,7 +24,7 @@
<input <input
type="text" type="text"
*ngIf="options.length <= maxItemCount" *ngIf="options.length <= maxItemCount"
placeholder="Add a value…" [placeholder]="newValuePlaceholder"
[(ngModel)]="newOption" [(ngModel)]="newOption"
(keyup)="handleKeys($event)" (keyup)="handleKeys($event)"
/> />

View file

@ -5,12 +5,6 @@ $inner-padding: var(--medium-padding);
width: 100%; width: 100%;
position: relative; position: relative;
&.disabled {
.top {
cursor: not-allowed !important;
}
}
.top, .top,
.bottom { .bottom {
padding: $inner-padding; padding: $inner-padding;

View file

@ -8,18 +8,15 @@ import { CancelService } from '../../../services/cancel.service';
}) })
export class SelectAddComponent { export class SelectAddComponent {
@Input() placeholder = 'Add a new value…'; @Input() placeholder = 'Add a new value…';
@Input() newValuePlaceholder = 'Add a value…';
@Input() maxItemCount = 7; @Input() maxItemCount = 7;
@Input() options: string[]; @Input() options: string[];
@Input() alwaysDropShadow = false; @Input() alwaysDropShadow = false;
@Input() onlyShadowBorder = false; @Input() onlyShadowBorder = false;
@Input() editable = false; @Input() editable = false;
@Input() disabled = false;
@Input() set default(value: string) { @Input() set default(value: string) {
this.selected = value; this.selected = value;
if (value) {
this.value.emit(value);
}
} }
backgroundHeight: string; backgroundHeight: string;

View file

@ -1,7 +1,7 @@
<span [className]="!on ? 'active' : ''" (click)="on = false" [innerText]="beforeText"></span> <span [className]="!on ? 'active' : ''" (click)="on = false" [innerText]="beforeText"></span>
<label class="{{ disabled ? 'disabled' : '' }}"> <label>
<input type="checkbox" [disabled]="disabled" [(ngModel)]="on" [className]="on ? 'on' : ''" /> <input type="checkbox" [(ngModel)]="on" [className]="on ? 'on' : ''" />
</label> </label>
<span [className]="on ? 'active' : ''" (click)="on = true" [innerText]="afterText"></span> <span [className]="on ? 'active' : ''" (click)="on = true" [innerText]="afterText"></span>

View file

@ -59,7 +59,6 @@
} }
} }
&:not(.disabled) {
input[type='checkbox'] { input[type='checkbox'] {
@media (min-width: $mobile-width) { @media (min-width: $mobile-width) {
&:hover:after { &:hover:after {
@ -74,4 +73,3 @@
} }
} }
} }
}

View file

@ -9,8 +9,6 @@ export class ToggleComponent {
@Input() beforeText: string; @Input() beforeText: string;
@Input() afterText: string; @Input() afterText: string;
@Input() disabled = false;
@Output() value: EventEmitter<boolean> = new EventEmitter(); @Output() value: EventEmitter<boolean> = new EventEmitter();
@Input() set default(value: boolean) { @Input() set default(value: boolean) {

View file

@ -0,0 +1,49 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'formatDate',
pure: false
})
export class FormatDatePipe implements PipeTransform {
transform(value: Date): string {
const now = new Date();
const years = Math.floor(now.getFullYear() - value.getFullYear());
const months = Math.floor(now.getMonth() - value.getMonth());
const days = Math.floor(now.getDay() - value.getDay());
const minutes = Math.floor(now.getMinutes() - value.getMinutes());
const seconds = Math.floor(now.getSeconds() - value.getSeconds());
if (years === 1) {
return 'a year ago';
} else if (years > 1) {
return `${years} years ago`;
}
if (months === 1) {
return 'a month ago';
} else if (months > 1) {
return `${months} months ago`;
}
if (days === 1) {
return 'a day ago';
} else if (days > 1) {
return `${days} days ago`;
}
if (minutes === 1) {
return 'a minute ago';
} else if (minutes > 1) {
return `${minutes} minutes ago`;
}
if (seconds === 1) {
return 'just now';
} else if (seconds > 1) {
return `${seconds} seconds ago`;
}
return 'just now';
}
}

View file

@ -0,0 +1,35 @@
import { Injectable } from '@angular/core';
const LOCAL_STORAGE_KEY = 'life-towers.data.v.3';
@Injectable({
providedIn: 'root'
})
export class MapStoreService<T> {
readonly storage: {
[id: number]: T;
} = {};
constructor() {
const localStorageData = localStorage.getItem(LOCAL_STORAGE_KEY);
if (localStorageData) {
this.storage = JSON.parse(localStorageData) as {
[id: number]: T;
};
}
}
get(id: number) {
if (this.storage.hasOwnProperty(id)) {
return this.storage[id];
}
}
add(id: number, value: T) {
if (this.storage.hasOwnProperty(id)) {
throw new Error('Key already set.');
}
this.storage[id] = value;
}
}

View file

@ -10,7 +10,7 @@ export abstract class Node extends Unique implements NodeState {
protected constructor(children: Array<InnerNode> = []) { protected constructor(children: Array<InnerNode> = []) {
super(); super();
children.map(c => (c.parent = this)); children.forEach(c => (c.parent = this));
} }
protected abstract changeKeys<T extends NodeState>(props: Partial<T>): this; protected abstract changeKeys<T extends NodeState>(props: Partial<T>): this;

29
src/app/store/store.ts Normal file
View file

@ -0,0 +1,29 @@
import { uuidv4 } from 'uuid';
class Store {
private readonly onSet: (id: string, element: any) => void;
private readonly elements: {
[id: string]: any;
};
constructor(
elements: {
[id: string]: any;
},
onSet: (id: string, element: any) => void
) {
this.elements = elements;
this.onSet = onSet;
}
add(element: any): number {
const id = uuidv4();
this.elements[id] = element;
this.onSet(id, element);
return id;
}
get(id: string): any {
return this.elements[id];
}
}

View file

@ -1,5 +1,6 @@
export class Unique { export class Unique {
protected static nextId = 0; private static nextId = 0;
private static store;
constructor() { constructor() {
this.setUniqueness(); this.setUniqueness();
@ -10,11 +11,13 @@ export class Unique {
} }
private _id: number; private _id: number;
get id(): number { get id(): number {
return this._id; return this._id;
} }
private _copies = 0; private _copies = 0;
get copies(): number { get copies(): number {
return this._copies; return this._copies;
} }

View file

@ -6433,6 +6433,11 @@ uuid@^3.0.1, uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
uuid@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
validate-npm-package-license@^3.0.1: validate-npm-package-license@^3.0.1:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"