Add inline host options button and implement horizontal row

This commit is contained in:
garrettmills 2020-02-11 12:20:26 -06:00
parent fd76f43c7e
commit 1eda3d0b30
10 changed files with 159 additions and 12 deletions

View File

@ -31,7 +31,7 @@
</ion-content> </ion-content>
<ion-footer> <ion-footer>
<ion-searchbar placeholder="Filter pages..." (ionChange)="onFilterChange($event)"></ion-searchbar> <ion-searchbar placeholder="Filter pages..." (ionChange)="onFilterChange($event)"></ion-searchbar>
<ion-item button slot="end" lines="full" (click)="showOptions()"> <ion-item button slot="end" lines="full" (click)="showOptions($event)">
<ion-icon name="list" slot="start"></ion-icon> <ion-icon name="list" slot="start"></ion-icon>
<ion-label>Menu</ion-label> <ion-label>Menu</ion-label>
</ion-item> </ion-item>

View File

@ -70,8 +70,9 @@ export class AppComponent implements OnInit {
}); });
} }
showOptions() { showOptions($event) {
this.popover.create({ this.popover.create({
event: $event,
component: OptionPickerComponent, component: OptionPickerComponent,
componentProps: { componentProps: {
toggleDark: () => this.toggleDark(), toggleDark: () => this.toggleDark(),

View File

@ -11,11 +11,45 @@ import {CodeComponent} from './editor/code/code.component';
import {MonacoEditorModule} from 'ngx-monaco-editor'; import {MonacoEditorModule} from 'ngx-monaco-editor';
import {FilesComponent} from './editor/files/files.component'; import {FilesComponent} from './editor/files/files.component';
import {OptionPickerComponent} from './option-picker/option-picker.component'; import {OptionPickerComponent} from './option-picker/option-picker.component';
import {HostOptionsComponent} from './editor/host-options/host-options.component';
@NgModule({ @NgModule({
declarations: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent, FilesComponent, OptionPickerComponent], declarations: [
imports: [CommonModule, IonicModule, AgGridModule, FormsModule, MonacoEditorModule], HostComponent,
entryComponents: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent, FilesComponent, OptionPickerComponent], NodePickerComponent,
exports: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent, FilesComponent, OptionPickerComponent] DatabaseComponent,
ColumnsComponent,
CodeComponent,
FilesComponent,
OptionPickerComponent,
HostOptionsComponent
],
imports: [
CommonModule,
IonicModule,
AgGridModule,
FormsModule,
MonacoEditorModule
],
entryComponents: [
HostComponent,
NodePickerComponent,
DatabaseComponent,
ColumnsComponent,
CodeComponent,
FilesComponent,
OptionPickerComponent,
HostOptionsComponent
],
exports: [
HostComponent,
NodePickerComponent,
DatabaseComponent,
ColumnsComponent,
CodeComponent,
FilesComponent,
OptionPickerComponent,
HostOptionsComponent
]
}) })
export class ComponentsModule {} export class ComponentsModule {}

View File

@ -0,0 +1,6 @@
<ion-list>
<ion-item *ngFor="let menuItem of menuItems; let i = index" button (click)="onSelect(menuItems[i].value)">
<ion-icon slot="start" [name]="menuItems[i].icon"></ion-icon>
<ion-label>{{ menuItems[i].name }}</ion-label>
</ion-item>
</ion-list>

View File

@ -0,0 +1,43 @@
import {Component, Input, OnInit} from '@angular/core';
import {PopoverController} from '@ionic/angular';
import {EditorPage} from '../../../pages/editor/editor.page';
import HostRecord from '../../../structures/HostRecord';
@Component({
selector: 'editor-host-options',
templateUrl: './host-options.component.html',
styleUrls: ['./host-options.component.scss'],
})
export class HostOptionsComponent implements OnInit {
@Input() editor: EditorPage;
@Input() index: number;
@Input() event: Event;
@Input() hostRecord: HostRecord;
public menuItems: Array<{name: string, icon: string, value: string, type?: string}> = [];
protected possibleMenuItems: Array<{name: string, icon: string, value: string, type?: string}> = [
{
name: 'Delete Node',
icon: 'trash',
value: 'delete_node',
},
];
constructor(
protected popover: PopoverController,
) { }
ngOnInit() {
for ( const item of this.possibleMenuItems ) {
if ( !item.type ) {
this.menuItems.push(item);
} else if ( item.type === this.hostRecord.type ) {
this.menuItems.push(item);
}
}
}
async onSelect(value) {
await this.popover.dismiss(value);
}
}

View File

@ -61,7 +61,7 @@ export class HostComponent implements OnInit {
this.record.type = 'block_code'; this.record.type = 'block_code';
} else if ( innerText.startsWith('http') ) { } else if ( innerText.startsWith('http') ) {
this.record.type = 'click_link'; this.record.type = 'click_link';
} else if ( innerText === '---' ) { } else if ( innerText === '===' ) {
this.record.type = 'page_sep'; this.record.type = 'page_sep';
} else if ( innerText.startsWith('-') || innerText.startsWith(' -') ) { } else if ( innerText.startsWith('-') || innerText.startsWith(' -') ) {
this.record.type = 'ul'; this.record.type = 'ul';

View File

@ -16,10 +16,27 @@
<ion-content> <ion-content>
<ng-container> <ng-container>
<div class="editor-root ion-padding" style="padding: 30px 80px;"> <div class="editor-root ion-padding">
<div class="host-container ion-padding"> <div
<editor-host #editorHosts *ngFor="let record of hostRecords; let i = index" [record]="hostRecords[i]" (recordChange)="onHostRecordChange($event, i)" *ngFor="let record of hostRecords; let i = index"
(newHostRequested)="onNewHostRequested($event)" (destroyHostRequested)="onDestroyHostRequested($event)" class="host-container ion-padding" style="display: flex;"
(mouseenter)="makeVisible(i)"
(mouseleave)="makeInvisible(i)"
>
<ion-button fill="invisible" color="primary" (click)="onOptionsClick($event, i)">
<ion-icon
name="options"
color="medium"
[ngClass]="{'invisible': !buttonIsVisible(i)}"
></ion-icon>
</ion-button>
<editor-host
style="width: 100%;"
#editorHosts
[record]="hostRecords[i]"
(recordChange)="onHostRecordChange($event, i)"
(newHostRequested)="onNewHostRequested($event)"
(destroyHostRequested)="onDestroyHostRequested($event)"
(saveHostRequested)="onSaveClick()"> (saveHostRequested)="onSaveClick()">
</editor-host> </editor-host>
</div> </div>

View File

@ -0,0 +1,7 @@
ion-icon {
transition: all 0.2s linear;
}
ion-icon.invisible {
opacity: 0;
}

View File

@ -5,6 +5,7 @@ import {PageService} from '../../service/page.service';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {LoadingController, PopoverController} from '@ionic/angular'; import {LoadingController, PopoverController} from '@ionic/angular';
import {NodePickerComponent} from '../../components/editor/node-picker/node-picker.component'; import {NodePickerComponent} from '../../components/editor/node-picker/node-picker.component';
import {HostOptionsComponent} from '../../components/editor/host-options/host-options.component';
@Component({ @Component({
selector: 'app-editor', selector: 'app-editor',
@ -15,6 +16,7 @@ export class EditorPage implements OnInit {
public hostRecords: Array<HostRecord> = [new HostRecord('Click to edit page...')]; public hostRecords: Array<HostRecord> = [new HostRecord('Click to edit page...')];
public pageRecord: PageRecord = new PageRecord(); public pageRecord: PageRecord = new PageRecord();
public pageId: string; public pageId: string;
public visibleButtons: Array<number> = [];
@ViewChildren('editorHosts') editorHosts; @ViewChildren('editorHosts') editorHosts;
@ViewChild('titleBar', {static: false}) titleBar; @ViewChild('titleBar', {static: false}) titleBar;
@ -33,6 +35,20 @@ export class EditorPage implements OnInit {
ngOnInit() {} ngOnInit() {}
buttonIsVisible(index) {
return this.visibleButtons.includes(index);
}
makeVisible(index) {
if ( !this.buttonIsVisible(index) ) {
this.visibleButtons.push(index);
}
}
makeInvisible(index) {
this.visibleButtons = this.visibleButtons.filter(x => x !== index);
}
ionViewDidEnter() { ionViewDidEnter() {
if ( this.pageId ) { if ( this.pageId ) {
this.pages.load(this.pageId).subscribe(pageRecord => { this.pages.load(this.pageId).subscribe(pageRecord => {
@ -96,7 +112,7 @@ export class EditorPage implements OnInit {
} else if ( type === 'click_link' ) { } else if ( type === 'click_link' ) {
return 'https://'; return 'https://';
} else if ( type === 'page_sep' ) { } else if ( type === 'page_sep' ) {
return '---'; return '===';
} else { } else {
return ''; return '';
} }
@ -179,4 +195,27 @@ export class EditorPage implements OnInit {
}); });
} }
async onOptionsClick($event, i) {
const popover = await this.popover.create({
component: HostOptionsComponent,
event: $event,
componentProps: {
editor: this,
index: i,
event: $event,
hostRecord: this.hostRecords[i],
}
});
popover.onDidDismiss().then((result) => {
console.log({result});
if ( result.data === 'delete_node' ) {
$event.record = this.hostRecords[i];
this.onDestroyHostRequested($event);
}
})
await popover.present();
}
} }