MOBILE-3661 split-view: Support nested split views

main
Noel De Martin 2021-01-26 09:28:46 +01:00
parent ae76e3da02
commit 6d148229f1
4 changed files with 75 additions and 60 deletions

View File

@ -1,5 +1,5 @@
<ion-content>
<ion-content class="menu">
<ng-content></ng-content>
</ion-content>
<ion-router-outlet></ion-router-outlet>
<ion-router-outlet class="content"></ion-router-outlet>
<!-- @todo placeholder -->

View File

@ -1,11 +1,11 @@
@import "~theme/breakpoints";
// @todo RTL layout
:host {
--side-width: 100%;
--side-min-width: 270px;
--side-max-width: 28%;
--menu-min-width: 270px;
--menu-max-width: 28%;
--menu-display: flex;
--content-display: block;
--border-width: 1;
top: 0;
right: 0;
@ -19,16 +19,28 @@
contain: strict;
}
:host(.menu-only) {
--menu-min-width: 0;
--menu-max-width: 100%;
--content-display: none;
--border-width: 0;
}
:host(.content-only) {
--menu-display: none;
--border-width: 0;
}
:host-context(ion-app.md) {
--border: 1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, .13))));
--border: calc(var(--border-width) * 1px) solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, .13))));
}
:host-context(ion-app.ios) {
--border: .55px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, #c8c7cc)));
--border: calc(var(--border-width) * .55px) solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, #c8c7cc)));
}
ion-content,
ion-router-outlet {
.menu,
.content {
top: 0;
right: 0;
bottom: 0;
@ -38,49 +50,25 @@ ion-router-outlet {
z-index: 0;
}
ion-content {
display: flex;
.menu {
display: var(--menu-display);
flex-shrink: 0;
order: -1;
border-left: unset;
border-right: unset;
border-inline-start: 0;
border-inline-end: 0;
border-inline-end: var(--border);
min-width: var(--menu-min-width);
max-width: var(--menu-max-width);
width: 100%;
}
ion-router-outlet {
.content {
display: var(--content-display);
flex: 1;
display: none;
::ng-deep ion-header {
display: none;
}
}
:host(.outlet-activated) {
ion-router-outlet {
display: block;
}
ion-content {
display: none;
}
}
@media (min-width: $breakpoint-tablet) {
ion-content {
border-inline-end: var(--border);
min-width: var(--side-min-width);
max-width: var(--side-max-width);
}
:host(.outlet-activated) ion-content {
display: flex;
}
}

View File

@ -12,10 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AfterViewInit, Component, HostBinding, OnDestroy, ViewChild } from '@angular/core';
import { AfterViewInit, Component, ElementRef, HostBinding, OnDestroy, ViewChild } from '@angular/core';
import { IonRouterOutlet } from '@ionic/angular';
import { CoreScreen } from '@services/screen';
import { Subscription } from 'rxjs';
enum CoreSplitViewMode {
Default = '', // Shows both menu and content.
MenuOnly = 'menu-only', // Hides content.
ContentOnly = 'content-only', // Hides menu.
}
@Component({
selector: 'core-split-view',
templateUrl: 'split-view.html',
@ -24,19 +31,25 @@ import { Subscription } from 'rxjs';
export class CoreSplitViewComponent implements AfterViewInit, OnDestroy {
@ViewChild(IonRouterOutlet) outlet!: IonRouterOutlet;
@HostBinding('class.outlet-activated') outletActivated = false;
@HostBinding('class') classes = '';
private isNestedSplitView = false;
private subscriptions?: Subscription[];
constructor(private element: ElementRef<HTMLElement>) {}
/**
* @inheritdoc
*/
ngAfterViewInit(): void {
this.outletActivated = this.outlet.isActivated;
this.isNestedSplitView = !!this.element.nativeElement.parentElement?.closest('core-split-view');
this.subscriptions = [
this.outlet.activateEvents.subscribe(() => this.outletActivated = true),
this.outlet.deactivateEvents.subscribe(() => this.outletActivated = false),
this.outlet.activateEvents.subscribe(() => this.updateClasses()),
this.outlet.deactivateEvents.subscribe(() => this.updateClasses()),
CoreScreen.instance.layoutObservable.subscribe(() => this.updateClasses()),
];
this.updateClasses();
}
/**
@ -46,4 +59,31 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy {
this.subscriptions?.forEach(subscription => subscription.unsubscribe());
}
/**
* Update host classes.
*/
private updateClasses(): void {
this.classes = this.getCurrentMode();
}
/**
* Get the current mode. Depending on the layout, outlet status, and whether this split view
* is nested or not, this method will indicate which parts of the split view should be visible.
*
* @return Split view mode.
*/
private getCurrentMode(): CoreSplitViewMode {
if (this.isNestedSplitView) {
return CoreSplitViewMode.MenuOnly;
}
if (CoreScreen.instance.isMobile) {
return this.outlet.isActivated
? CoreSplitViewMode.ContentOnly
: CoreSplitViewMode.MenuOnly;
}
return CoreSplitViewMode.Default;
}
}

View File

@ -1,13 +0,0 @@
/*
* Layout Breakpoints
*
* https://ionicframework.com/docs/layout/grid#default-breakpoints
*/
$breakpoint-xs: 0px;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
$breakpoint-tablet: $breakpoint-lg;