Add rename page functionality
This commit is contained in:
parent
3101c973eb
commit
3a1accaae1
18 changed files with 201 additions and 63 deletions
|
|
@ -1,2 +1,4 @@
|
|||
<app-modal></app-modal>
|
||||
<router-outlet></router-outlet>
|
||||
<main (click)="cancelService.cancelAll()">
|
||||
<app-modal></app-modal>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
main {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -1,24 +1,18 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { InnerNode, InnerNodeState } from './store/inner-node';
|
||||
import { Root } from './store/root';
|
||||
import { ChangeDetectionStrategy, Component, DoCheck } from '@angular/core';
|
||||
import { CancelService } from './services/cancel.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
styleUrls: ['./app.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AppComponent {
|
||||
export class AppComponent implements DoCheck {
|
||||
title = 'life';
|
||||
|
||||
constructor() {
|
||||
/*const rl = new InnerNode();
|
||||
const rr = new InnerNode();
|
||||
const l = new InnerNode();
|
||||
const r = new InnerNode([rl, rr]);
|
||||
const root = new Root<InnerNode>([l, r]);
|
||||
root.log();
|
||||
constructor(public cancelService: CancelService) {}
|
||||
|
||||
rr.changeKeys<InnerNodeState>({ dummy: 8 });
|
||||
root.log();*/
|
||||
ngDoCheck() {
|
||||
console.log('app change detection');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<main class="{{ modalService.active ? 'active' : '' }}" [ngSwitch]="modalService.active?.type">
|
||||
<app-create-block *ngSwitchCase="ModalType.createBlock"></app-create-block>
|
||||
<app-edit-block *ngSwitchCase="ModalType.editBlock"></app-edit-block>
|
||||
<app-remove-block *ngSwitchCase="ModalType.removeBlock"></app-remove-block>
|
||||
<app-remove-tower *ngSwitchCase="ModalType.removeTower"></app-remove-tower>
|
||||
<app-settings *ngSwitchCase="ModalType.settings"></app-settings>
|
||||
<app-get-started *ngSwitchCase="ModalType.getStarted"></app-get-started>
|
||||
<app-remove-page *ngSwitchCase="ModalType.removePage"></app-remove-page>
|
||||
</main>
|
||||
<section class="{{ modalService.active ? 'active' : '' }}" [ngSwitch]="modalService.active?.type">
|
||||
<app-create-block (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.createBlock"></app-create-block>
|
||||
<app-edit-block (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.editBlock"></app-edit-block>
|
||||
<app-remove-block (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.removeBlock"></app-remove-block>
|
||||
<app-remove-tower (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.removeTower"></app-remove-tower>
|
||||
<app-settings (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.settings"></app-settings>
|
||||
<app-get-started (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.getStarted"></app-get-started>
|
||||
<app-remove-page (click)="$event.stopPropagation()" *ngSwitchCase="ModalType.removePage"></app-remove-page>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
@import '../../../styles';
|
||||
|
||||
main {
|
||||
section {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10000;
|
||||
|
||||
@include center-child();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component } from '@angular/core';
|
||||
import { ModalService, ModalType } from '../../services/modal.service';
|
||||
|
||||
@Component({
|
||||
|
|
@ -7,14 +7,18 @@ import { ModalService, ModalType } from '../../services/modal.service';
|
|||
styleUrls: ['./modal.component.scss']
|
||||
})
|
||||
export class ModalComponent {
|
||||
// Needed for accessing the enum from html.
|
||||
ModalType = ModalType;
|
||||
|
||||
constructor(public modalService: ModalService) {
|
||||
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();
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
:host {
|
||||
@include card();
|
||||
box-shadow: $shadow;
|
||||
|
||||
width: 66vw;
|
||||
max-width: 400px;
|
||||
|
|
@ -12,7 +11,9 @@
|
|||
|
||||
box-sizing: border-box;
|
||||
padding: var(--large-padding);
|
||||
|
||||
position: relative;
|
||||
box-shadow: $shadow;
|
||||
|
||||
@include inner-spacing(var(--large-padding));
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
@include card();
|
||||
|
||||
width: 66vw;
|
||||
max-width: 500px;
|
||||
max-width: 400px;
|
||||
@media (max-width: $mobile-width) {
|
||||
width: 300px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
[options]="pageNames"
|
||||
[default]="(selectedPage$ | async)?.name"
|
||||
(value)="selectPage($event)"
|
||||
(optionChange)="changeName($event)"
|
||||
[placeholder]="'Add a new page…'"
|
||||
[editable]="true"
|
||||
></app-select-add>
|
||||
</div>
|
||||
<!-- wrapper for easier styling -->
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectPage(name: string) {
|
||||
if (!name) {
|
||||
if (this.pages && this.pages.length > 0) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,30 @@
|
|||
<div class="select-add {{ onlyShadowBorder ? 'shadow-border' : '' }}">
|
||||
<div #top class="top" (click)="toggle()">
|
||||
<p [innerHTML]="selected ? selected : placeholder"></p>
|
||||
<img src="assets/arrow.svg" [className]="isOpen ? 'upside-down' : ''" alt="arrow" />
|
||||
<div class="select-add {{ onlyShadowBorder ? 'shadow-border' : '' }}" (click)="$event.stopPropagation()">
|
||||
<div #top class="top" (click)="!editMode && toggle()">
|
||||
<p [innerHTML]="selected ? selected : placeholder" *ngIf="!editMode || !selected; else editableSelected"></p>
|
||||
<ng-template #editableSelected>
|
||||
<input type="text" [value]="selected" (change)="changeOption(selected, $event)" />
|
||||
</ng-template>
|
||||
<img
|
||||
src="assets/arrow.svg"
|
||||
(click)="editMode && (toggle() || $event.stopPropagation())"
|
||||
[className]="isOpen ? 'upside-down' : ''"
|
||||
alt="arrow"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="bottom-container">
|
||||
<div #bottom class="bottom {{ isOpen ? 'open' : '' }}">
|
||||
<p *ngFor="let option of otherOptions" [innerHTML]="option" (click)="select(option)"></p>
|
||||
<ng-container *ngIf="!editMode; else editableOthers">
|
||||
<p *ngFor="let option of otherOptions" [innerHTML]="option" (click)="select(option)"></p>
|
||||
</ng-container>
|
||||
<ng-template #editableOthers>
|
||||
<input
|
||||
type="text"
|
||||
*ngFor="let option of otherOptions"
|
||||
[value]="option"
|
||||
(change)="changeOption(option, $event)"
|
||||
/>
|
||||
</ng-template>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -16,7 +34,12 @@
|
|||
(keyup)="handleKeys($event)"
|
||||
/>
|
||||
|
||||
<button *ngIf="options.length <= maxItemCount" (click)="addNewOption()" [disabled]="!newOption">Add</button>
|
||||
<div class="buttons">
|
||||
<button *ngIf="options.length <= maxItemCount" (click)="addNewOption()" [disabled]="!newOption">Add</button>
|
||||
<div *ngIf="editable" class="edit {{ editMode ? 'active' : '' }}" (click)="editMode = !editMode">
|
||||
<img src="assets/pen.svg" alt="edit" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ $inner-padding: var(--medium-padding);
|
|||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
p {
|
||||
p,
|
||||
input[type='text'] {
|
||||
display: inline-block;
|
||||
@include sub-title-text();
|
||||
}
|
||||
|
|
@ -36,7 +37,7 @@ $inner-padding: var(--medium-padding);
|
|||
|
||||
.bottom-container {
|
||||
width: 100%;
|
||||
height: 40vh;
|
||||
height: 300px;
|
||||
|
||||
position: absolute;
|
||||
overflow-y: hidden;
|
||||
|
|
@ -77,6 +78,75 @@ $inner-padding: var(--medium-padding);
|
|||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
height: 32px;
|
||||
@media (max-width: $mobile-width) {
|
||||
height: 24px;
|
||||
}
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
}
|
||||
|
||||
.edit {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
margin: 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export class SelectAddComponent {
|
|||
@Input() options: string[];
|
||||
@Input() alwaysDropShadow = false;
|
||||
@Input() onlyShadowBorder = false;
|
||||
@Input() editable = false;
|
||||
|
||||
@Input() set default(value: string) {
|
||||
this.selected = value;
|
||||
|
|
@ -20,7 +21,20 @@ export class SelectAddComponent {
|
|||
}
|
||||
}
|
||||
|
||||
backgroundHeight: string;
|
||||
|
||||
private _editMode = false;
|
||||
set editMode(value: boolean) {
|
||||
this._editMode = value;
|
||||
this.backgroundHeight = this.getBackgroundHeight();
|
||||
}
|
||||
|
||||
get editMode(): boolean {
|
||||
return this._editMode;
|
||||
}
|
||||
|
||||
@Output() value: EventEmitter<string> = new EventEmitter();
|
||||
@Output() optionChange: EventEmitter<{ from: string; to: string }> = new EventEmitter();
|
||||
|
||||
@ViewChild('top') top: ElementRef;
|
||||
@ViewChild('bottom') bottom: ElementRef;
|
||||
|
|
@ -32,6 +46,15 @@ export class SelectAddComponent {
|
|||
constructor(private cancelService: CancelService) {
|
||||
this.cancelService.subscribe(this, () => {
|
||||
this.isOpen = false;
|
||||
this.editMode = false;
|
||||
});
|
||||
}
|
||||
|
||||
changeOption(from: string, event) {
|
||||
console.log(event);
|
||||
this.optionChange.emit({
|
||||
from,
|
||||
to: event.target.value
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -45,15 +68,6 @@ export class SelectAddComponent {
|
|||
}
|
||||
}
|
||||
|
||||
get backgroundHeight(): string {
|
||||
if (this.isOpen && this.top && this.bottom) {
|
||||
const topHeight = this.top.nativeElement.clientHeight;
|
||||
const bottomHeight = this.bottom.nativeElement.clientHeight;
|
||||
return `${topHeight + bottomHeight}px`;
|
||||
}
|
||||
return `100%`;
|
||||
}
|
||||
|
||||
addNewOption() {
|
||||
if (this.newOption) {
|
||||
this.select(this.newOption);
|
||||
|
|
@ -69,5 +83,20 @@ export class SelectAddComponent {
|
|||
|
||||
toggle() {
|
||||
this.isOpen = !this.isOpen;
|
||||
if (!this.isOpen) {
|
||||
this.editMode = false;
|
||||
}
|
||||
this.backgroundHeight = this.getBackgroundHeight();
|
||||
console.log('editable', this.editable);
|
||||
}
|
||||
|
||||
private getBackgroundHeight(): string {
|
||||
if (this.isOpen && this.top && this.bottom) {
|
||||
const topHeight = this.top.nativeElement.clientHeight;
|
||||
const bottomHeight = this.bottom.nativeElement.clientHeight;
|
||||
console.log(topHeight, bottomHeight);
|
||||
return `${topHeight + bottomHeight}px`;
|
||||
}
|
||||
return `100%`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,12 @@ export class Page extends Serializable implements IPage, PageState {
|
|||
});
|
||||
}
|
||||
|
||||
changeName(to: string) {
|
||||
this.changeProps({
|
||||
name: to
|
||||
});
|
||||
}
|
||||
|
||||
addTower(name = '') {
|
||||
let hue;
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ interface Subscriber {
|
|||
export class CancelService {
|
||||
private subscribers: Subscriber[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
subscribe(object: object, callback: () => void) {
|
||||
this.subscribers.push({
|
||||
object,
|
||||
|
|
@ -21,10 +19,12 @@ export class CancelService {
|
|||
}
|
||||
|
||||
cancelAllExcept(except: object) {
|
||||
console.log('cancel all except', except);
|
||||
this.subscribers.filter(s => s.object !== except).map(s => s.callback());
|
||||
}
|
||||
|
||||
cancelAll() {
|
||||
console.log('cancel all');
|
||||
this.subscribers.map(s => s.callback());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 129 129" enable-background="new 0 0 129 129" width="512px" height="512px"><g><g>
|
||||
<g>
|
||||
<path d="m119.2,114.3h-109.4c-2.3,0-4.1,1.9-4.1,4.1s1.9,4.1 4.1,4.1h109.5c2.3,0 4.1-1.9 4.1-4.1s-1.9-4.1-4.2-4.1z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#5D576B"/>
|
||||
<path d="m5.7,78l-.1,19.5c0,1.1 0.4,2.2 1.2,3 0.8,0.8 1.8,1.2 2.9,1.2l19.4-.1c1.1,0 2.1-0.4 2.9-1.2l67-67c1.6-1.6 1.6-4.2 0-5.9l-19.2-19.4c-1.6-1.6-4.2-1.6-5.9-1.77636e-15l-13.4,13.5-53.6,53.5c-0.7,0.8-1.2,1.8-1.2,2.9zm71.2-61.1l13.5,13.5-7.6,7.6-13.5-13.5 7.6-7.6zm-62.9,62.9l49.4-49.4 13.5,13.5-49.4,49.3-13.6,.1 .1-13.5z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#5D576B"/>
|
||||
</g>
|
||||
</g></g> </svg>
|
||||
|
Before Width: | Height: | Size: 872 B |
4
src/assets/pen.svg
Normal file
4
src/assets/pen.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 528.899 528.899" style="enable-background:new 0 0 528.899 528.899;" xml:space="preserve"><g><g>
|
||||
<path d="M328.883,89.125l107.59,107.589l-272.34,272.34L56.604,361.465L328.883,89.125z M518.113,63.177l-47.981-47.981 c-18.543-18.543-48.653-18.543-67.259,0l-45.961,45.961l107.59,107.59l53.611-53.611 C532.495,100.753,532.495,77.559,518.113,63.177z M0.3,512.69c-1.958,8.812,5.998,16.708,14.811,14.565l119.891-29.069 L27.473,390.597L0.3,512.69z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#5D576B"/>
|
||||
</g></g> </svg>
|
||||
|
After Width: | Height: | Size: 737 B |
|
|
@ -29,9 +29,6 @@ html {
|
|||
body {
|
||||
height: 100%;
|
||||
background: $background-gradient-opaque;
|
||||
}
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
padding: var(--large-padding);
|
||||
box-sizing: border-box;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue