diff --git a/src/core/components/split-view/split-view.html b/src/core/components/split-view/split-view.html index a585f4b0a..569af4224 100644 --- a/src/core/components/split-view/split-view.html +++ b/src/core/components/split-view/split-view.html @@ -1,5 +1,7 @@ - - + + + diff --git a/src/core/components/split-view/split-view.scss b/src/core/components/split-view/split-view.scss index d94a6efcc..13f0c2db4 100644 --- a/src/core/components/split-view/split-view.scss +++ b/src/core/components/split-view/split-view.scss @@ -1,11 +1,13 @@ -// @todo RTL layout - :host { --menu-min-width: 270px; --menu-max-width: 28%; + --menu-box-shadow: var(--core-menu-box-shadow-end); + --menu-z: 2; + --menu-border-width: 1; --menu-display: flex; --content-display: block; - --border-width: 1; + --content-outlet-display: none; + --content-placeholder-display: var(--content-display); top: 0; right: 0; @@ -17,58 +19,74 @@ flex-direction: row; flex-wrap: nowrap; contain: strict; + + .menu, + .content-outlet { + top: 0; + right: 0; + bottom: 0; + left: 0; + position: relative; + box-shadow: none; + z-index: 0; + } + + .menu { + box-shadow: var(--menu-box-shadow); + z-index: var(--menu-z); + display: var(--menu-display); + flex-shrink: 0; + order: -1; + width: 100%; + border-inline-start: 0; + border-inline-end: var(--border); + min-width: var(--menu-min-width); + max-width: var(--menu-max-width); + } + + .content-outlet { + display: var(--content-outlet-display); + flex: 1; + + ::ng-deep ion-header { + display: none; + } + + } + + .content-placeholder { + display: var(--content-placeholder-display); + flex: 1; + position: relative; + background-color: var(--ion-background); + } + } :host(.menu-only) { --menu-min-width: 0; --menu-max-width: 100%; --content-display: none; - --border-width: 0; + --menu-border-width: 0; + --menu-box-shadow: none; + --menu-z: 0; + --selected-item-border-width: 0; } :host(.content-only) { --menu-display: none; - --border-width: 0; + --menu-border-width: 0; +} + +:host(.outlet-activated) { + --content-placeholder-display: none; + --content-outlet-display: var(--content-display); } :host-context(ion-app.md) { - --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)))); + --border: calc(var(--menu-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: calc(var(--border-width) * .55px) solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, #c8c7cc))); -} - -.menu, -.content { - top: 0; - right: 0; - bottom: 0; - left: 0; - position: relative; - box-shadow: none !important; - z-index: 0; -} - -.menu { - display: var(--menu-display); - flex-shrink: 0; - order: -1; - border-left: unset; - border-right: unset; - border-inline-start: 0; - border-inline-end: var(--border); - min-width: var(--menu-min-width); - max-width: var(--menu-max-width); - width: 100%; -} - -.content { - display: var(--content-display); - flex: 1; - - ::ng-deep ion-header { - display: none; - } - + --border: calc(var(--menu-border-width) * .55px) solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, #c8c7cc))); } diff --git a/src/core/components/split-view/split-view.ts b/src/core/components/split-view/split-view.ts index 22d8b1e98..c9ab27d97 100644 --- a/src/core/components/split-view/split-view.ts +++ b/src/core/components/split-view/split-view.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { AfterViewInit, Component, ElementRef, HostBinding, OnDestroy, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, HostBinding, Input, OnDestroy, ViewChild } from '@angular/core'; import { IonRouterOutlet } from '@ionic/angular'; import { CoreScreen } from '@services/screen'; import { Subscription } from 'rxjs'; @@ -32,6 +32,7 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy { @ViewChild(IonRouterOutlet) outlet!: IonRouterOutlet; @HostBinding('class') classes = ''; + @Input() placeholderText = 'core.emptysplit'; isNested = false; private subscriptions?: Subscription[]; @@ -65,6 +66,10 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy { private updateClasses(): void { const classes: string[] = [this.getCurrentMode()]; + if (this.outlet.isActivated) { + classes.push('outlet-activated'); + } + if (this.isNested) { classes.push('nested'); } @@ -92,4 +97,13 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy { return CoreSplitViewMode.MenuAndContent; } + /** + * Check if both panels are shown. It depends on screen width. + * + * @return If split view is enabled. + */ + isOn(): boolean { + return this.outlet.isActivated; + } + } diff --git a/src/core/features/block/components/course-blocks/course-blocks.scss b/src/core/features/block/components/course-blocks/course-blocks.scss index 04f290e4f..314fa25ff 100644 --- a/src/core/features/block/components/course-blocks/course-blocks.scss +++ b/src/core/features/block/components/course-blocks/course-blocks.scss @@ -1,4 +1,6 @@ :host { + --side-blocks-box-shadow: var(--core-menu-box-shadow-start); + &.core-no-blocks .core-course-blocks-content { height: auto; } @@ -20,7 +22,7 @@ div.core-course-blocks-side { max-width: var(--side-blocks-max-width); min-width: var(--side-blocks-min-width); - box-shadow: -4px 0px 16px rgba(0, 0, 0, 0.18); + box-shadow: var(--side-blocks-box-shadow); z-index: 2; // @todo @include core-split-area-end(); } @@ -53,7 +55,7 @@ :host-context([dir="rtl"]).core-has-blocks { @media (min-width: 768px) { div.core-course-blocks-side { - box-shadow: 4px 0px 16px rgba(0, 0, 0, 0.18); + box-shadow: var(--side-blocks-box-shadow); } } } diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index f14ab895b..431ec6132 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -91,6 +91,21 @@ export class CoreNavigatorService { return matches?.[1] ?? null; } + /** + * Returns if a section is loaded on the split view (tablet mode). + * + * @param path Path, can be a glob pattern. + * @return Whether the active route is using the given path. + */ + isCurrentPathInTablet(path: string): boolean { + if (CoreScreen.instance.isMobile) { + // Split view is off. + return false; + } + + return this.isCurrent(path); + } + /** * Navigate to a new path. * @@ -213,9 +228,11 @@ export class CoreNavigatorService { * @return Previous path. */ getPreviousPath(): string { + // @todo: Remove this method and the used attributes. + // This is a quick workarround to avoid loops. Ie, in messages we can navigate to user profile and there to messages. return CoreUrlUtils.instance.removeUrlParams(this.previousPath || ''); } - + /** * Get a parameter for the current route. * Please notice that objects can only be retrieved once. You must call this function only once per page and parameter, diff --git a/src/theme/app.scss b/src/theme/app.scss index d2f65a5d1..96a30cb11 100644 --- a/src/theme/app.scss +++ b/src/theme/app.scss @@ -69,6 +69,10 @@ ion-icon { } } +[dir=rtl] ion-icon.icon-flip-rtl { + transform: scaleX(-1); +} + // Ionic alert. ion-alert.core-alert-network-error .alert-head { position: relative; diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 49093e206..30ab4fcc5 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -106,6 +106,7 @@ --color: var(--custom-bottom-tabs-color, var(--white)); } + --core-toolbar-button-image-width: var(--custom-toolbar-button-image-width, 32px); --ion-statusbar-background: var(--custom-toolbar-background, var(--ion-color-primary)); ion-toolbar { --color: var(--custom-toolbar-color, var(--ion-color-primary-contrast)); @@ -170,8 +171,6 @@ --selected-item-color: var(--custom-selected-item-color, var(--core-color)); --selected-item-border-width: var(--custom-selected-item-border-width, 5px); - --drop-shadow: var(--custom-drop-shadow, 0, 0, 0, 0.2); - --core-login-background: var(--custom-login-background, var(--white)); --core-login-text-color: var(--custom-login-text-color, var(--black)); @@ -188,11 +187,8 @@ --core-star-color: var(--custom-star-color, var(--core-color)); --core-large-avatar-size: var(--custom-large-avatar-size, 90px); - --core-avatar-size: var(--custom-avatar-size, 40px); - --core-toolbar-button-image-width: var(--custom-toolbar-button-image-width, 32px); - --core-send-message-input-background: var(--custom-send-message-input-background, var(--gray)); --core-send-message-input-color: var(--custom-send-message-input-color, var(--black)); @@ -214,6 +210,11 @@ --addon-messages-avatar-size: var(--custom-messages-avatar-size, 30px); --addon-messages-discussion-badge: var(--custom-messages-discussion-badge, var(--core-color)); --addon-messages-discussion-badge-text: var(--custom-messages-discussion-badge-text, var(--white)); + + --drop-shadow: var(--custom-drop-shadow, 0, 0, 0, 0.2); + + --core-menu-box-shadow-end: var(--custom-menu-box-shadow-end, -4px 0px 16px rgba(0, 0, 0, 0.18)); + --core-menu-box-shadow-start: var(--custom-menu-box-shadow-start, 4px 0px 16px rgba(0, 0, 0, 0.18)); } /*