diff --git a/src/addons/messages/pages/discussion/discussion.html b/src/addons/messages/pages/discussion/discussion.html index b3de76af9..2eb15f375 100644 --- a/src/addons/messages/pages/discussion/discussion.html +++ b/src/addons/messages/pages/discussion/discussion.html @@ -129,8 +129,8 @@ [attr.aria-label]="'addon.messages.newmessages' | translate"> {{ 'addon.messages.newmessages' | translate }} - {{ newMessages }} + {{ newMessages }} diff --git a/src/addons/messages/pages/discussion/discussion.page.ts b/src/addons/messages/pages/discussion/discussion.page.ts index 7c4176af1..d2823438f 100644 --- a/src/addons/messages/pages/discussion/discussion.page.ts +++ b/src/addons/messages/pages/discussion/discussion.page.ts @@ -499,13 +499,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView */ protected setNewMessagesBadge(addMessages: number): void { if (this.newMessages == 0 && addMessages > 0) { - // Setup scrolling. - this.content!.scrollEvents = true; - this.scrollFunction(); - } else if (this.newMessages > 0 && addMessages == 0) { - // Remove scrolling. - this.content!.scrollEvents = false; } this.newMessages = addMessages; @@ -1098,8 +1092,8 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView // Leave time for the view to be rendered. await CoreUtils.nextTicks(5); - if (!this.viewDestroyed) { - this.content!.scrollToBottom(0); + if (!this.viewDestroyed && this.content) { + this.content.scrollToBottom(0); } if (force) { @@ -1112,10 +1106,10 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView * Scroll to the first new unread message. */ scrollToFirstUnreadMessage(): void { - if (this.newMessages > 0) { + if (this.newMessages > 0 && this.content) { const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine')); - CoreDomUtils.scrollToElement(this.content!, messages[messages.length - this.newMessages]); + CoreDomUtils.scrollToElement(this.content, messages[messages.length - this.newMessages]); } } diff --git a/src/addons/messages/pages/discussion/discussion.scss b/src/addons/messages/pages/discussion/discussion.scss index 57320a0c6..2db2276f0 100644 --- a/src/addons/messages/pages/discussion/discussion.scss +++ b/src/addons/messages/pages/discussion/discussion.scss @@ -19,19 +19,12 @@ padding-bottom: 0; } - ion-fab ion-fab-button { - &::part(native) { - contain: unset; - overflow: visible; - } - - .core-discussion-messages-badge { - position: absolute; - color: var(--addon-messages-discussion-badge-text); - background-color: var(--addon-messages-discussion-badge); - display: block; - @include position(-6px, -6px, null, null); - } + ion-fab .core-discussion-messages-badge { + position: absolute; + color: var(--addon-messages-discussion-badge-text); + background-color: var(--addon-messages-discussion-badge); + display: block; + @include position(0, 0, null, null); } ion-header ion-toolbar h1 { diff --git a/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html b/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html index 413cb3751..3a61b78e2 100644 --- a/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html +++ b/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html @@ -8,7 +8,7 @@ {{ 'addon.mod_assign.feedbacknotsupported' | translate }}

-

diff --git a/src/addons/mod/assign/components/submission-plugin/addon-mod-assign-submission-plugin.html b/src/addons/mod/assign/components/submission-plugin/addon-mod-assign-submission-plugin.html index e466eb7b5..29818a878 100644 --- a/src/addons/mod/assign/components/submission-plugin/addon-mod-assign-submission-plugin.html +++ b/src/addons/mod/assign/components/submission-plugin/addon-mod-assign-submission-plugin.html @@ -8,7 +8,7 @@ {{ 'addon.mod_assign.submissionnotsupported' | translate }}

-

diff --git a/src/addons/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html b/src/addons/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html index 3bcfbbb0f..e30f369a0 100644 --- a/src/addons/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html +++ b/src/addons/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html @@ -3,8 +3,8 @@

{{ plugin.name }}

- +

diff --git a/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html b/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html index fe1dc1a17..549976d19 100644 --- a/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html +++ b/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html @@ -4,8 +4,8 @@

{{ plugin.name }}

{{ 'addon.mod_assign.numwords' | translate: {'$a': words} }}

- +

diff --git a/src/addons/mod/book/pages/contents/contents.html b/src/addons/mod/book/pages/contents/contents.html index 5089297cf..0f7605f0c 100644 --- a/src/addons/mod/book/pages/contents/contents.html +++ b/src/addons/mod/book/pages/contents/contents.html @@ -45,8 +45,8 @@ - + diff --git a/src/addons/mod/data/pages/entry/entry.html b/src/addons/mod/data/pages/entry/entry.html index a4a1fccdb..ce14704a3 100644 --- a/src/addons/mod/data/pages/entry/entry.html +++ b/src/addons/mod/data/pages/entry/entry.html @@ -61,7 +61,7 @@ (onLoading)="setLoadingComments($event)" [showItem]="true"> -
+
-
+
diff --git a/src/addons/mod/imscp/pages/view/view.html b/src/addons/mod/imscp/pages/view/view.html index 548cf095c..0611d34f8 100644 --- a/src/addons/mod/imscp/pages/view/view.html +++ b/src/addons/mod/imscp/pages/view/view.html @@ -33,7 +33,7 @@
- diff --git a/src/addons/mod/lesson/pages/user-retake/user-retake.html b/src/addons/mod/lesson/pages/user-retake/user-retake.html index 428f88da9..6c8bcc2df 100644 --- a/src/addons/mod/lesson/pages/user-retake/user-retake.html +++ b/src/addons/mod/lesson/pages/user-retake/user-retake.html @@ -87,7 +87,7 @@

{{ 'addon.mod_lesson.question' | translate }}

- diff --git a/src/addons/mod/quiz/pages/attempt/attempt.html b/src/addons/mod/quiz/pages/attempt/attempt.html index 7d4dc6879..3df9ad96f 100644 --- a/src/addons/mod/quiz/pages/attempt/attempt.html +++ b/src/addons/mod/quiz/pages/attempt/attempt.html @@ -61,7 +61,7 @@ -

+
diff --git a/src/addons/mod/quiz/pages/player/player.html b/src/addons/mod/quiz/pages/player/player.html index f34cf4c47..9e787ecaf 100644 --- a/src/addons/mod/quiz/pages/player/player.html +++ b/src/addons/mod/quiz/pages/player/player.html @@ -149,7 +149,7 @@ -
diff --git a/src/addons/mod/quiz/pages/review/review.html b/src/addons/mod/quiz/pages/review/review.html index 2e3f97232..43fc2206f 100644 --- a/src/addons/mod/quiz/pages/review/review.html +++ b/src/addons/mod/quiz/pages/review/review.html @@ -105,7 +105,7 @@
-
+
{{ errorMessage | translate }}

- diff --git a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html index 5dd51d9ff..9ccdc53bc 100644 --- a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html +++ b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html @@ -58,8 +58,8 @@

{{ 'addon.mod_workshop.conclusion' | translate }}

- +
@@ -91,8 +91,8 @@

{{ 'addon.mod_workshop.areainstructauthors' | translate }}

- +
@@ -141,7 +141,7 @@

{{ 'addon.mod_workshop.areainstructreviewers' | translate }}

- diff --git a/src/addons/notifications/pages/list/list.html b/src/addons/notifications/pages/list/list.html index 965a5158d..d3b9fe72e 100644 --- a/src/addons/notifications/pages/list/list.html +++ b/src/addons/notifications/pages/list/list.html @@ -64,7 +64,7 @@ + collapsible-item> diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5df6a4cb0..7c361804a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -14,7 +14,7 @@ import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { IonRouterOutlet } from '@ionic/angular'; -import { BackButtonEvent } from '@ionic/core'; +import { BackButtonEvent, ScrollDetail } from '@ionic/core'; import { CoreLang } from '@services/lang'; import { CoreLoginHelper } from '@features/login/services/login-helper'; @@ -89,6 +89,12 @@ export class AppComponent implements OnInit, AfterViewInit { } }); + // Listen to scroll to add style when scroll is not 0. + win.addEventListener('ionScroll', ({ detail, target }: CustomEvent) => { + const header = (target as HTMLElement).closest('.ion-page')?.querySelector('ion-header'); + header?.classList.toggle('core-header-shadow', detail.scrollTop > 0); + }); + // Listen for session expired events. CoreEvents.on(CoreEvents.SESSION_EXPIRED, (data) => { CoreLoginHelper.sessionExpired(data); diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts index e9fcb9d6b..47fe99439 100644 --- a/src/core/directives/collapsible-footer.ts +++ b/src/core/directives/collapsible-footer.ts @@ -42,9 +42,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { protected initialPaddingBottom = '0px'; protected previousTop = 0; protected previousHeight = 0; - protected endAnimationTimeout?: number; protected content?: HTMLIonContentElement | null; protected loadingChangedListener?: CoreEventObserver; + protected contentScrollListener?: EventListener; + protected endContentScrollListener?: EventListener; constructor(el: ElementRef, protected ionContent: IonContent) { this.element = el.nativeElement; @@ -105,7 +106,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { const scroll = await this.content.getScrollElement(); this.content.scrollEvents = true; - this.content.addEventListener('ionScroll', (e: CustomEvent): void => { + this.content.addEventListener('ionScroll', this.contentScrollListener = (e: CustomEvent): void => { if (!this.content) { return; } @@ -113,6 +114,23 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { this.onScroll(e.detail, scroll); }); + this.content.addEventListener('ionScrollEnd', this.endContentScrollListener = (): void => { + if (!this.content) { + return; + } + + const height = this.previousHeight; + const collapsed = height <= this.finalHeight; + const expanded = height >= this.initialHeight; + + if (!collapsed && !expanded) { + // Finish opening or closing the bar. + const newHeight = (height - this.finalHeight) < (this.initialHeight - this.finalHeight) / 2 + ? this.finalHeight + : this.initialHeight; + + this.setBarHeight(newHeight); } + }); } /** @@ -154,34 +172,12 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { * @param height The new bar height. */ protected setBarHeight(height: number): void { - if (this.endAnimationTimeout) { - clearTimeout(this.endAnimationTimeout); - } - const collapsed = height <= this.finalHeight; const expanded = height >= this.initialHeight; this.element.classList.toggle('footer-collapsed', collapsed); this.element.classList.toggle('footer-expanded', expanded); this.content?.style.setProperty('--core-collapsible-footer-height', height + 'px'); this.previousHeight = height; - - if (!collapsed && !expanded) { - // Finish opening or closing the bar. - this.endAnimationTimeout = window.setTimeout(() => this.endAnimation(height), 500); - } - } - - /** - * End of animation when not scrolling. - * - * @param height Last height used. - */ - protected endAnimation(height: number): void { - const newHeight = (height - this.finalHeight) < (this.initialHeight - this.finalHeight) / 2 - ? this.finalHeight - : this.initialHeight; - - this.setBarHeight(newHeight); } /** @@ -213,6 +209,13 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { */ async ngOnDestroy(): Promise { this.content?.style.setProperty('--padding-bottom', this.initialPaddingBottom); + + if (this.content && this.contentScrollListener) { + this.content.removeEventListener('ionScroll', this.contentScrollListener); + } + if (this.content && this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + } } } diff --git a/src/core/directives/collapsible-header.ts b/src/core/directives/collapsible-header.ts index 9bb83a3ca..01f7b0470 100644 --- a/src/core/directives/collapsible-header.ts +++ b/src/core/directives/collapsible-header.ts @@ -62,11 +62,12 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest protected expandedFontStyles?: Partial; protected content?: HTMLIonContentElement; protected contentScrollListener?: EventListener; + protected endContentScrollListener?: EventListener; protected floatingTitle?: HTMLElement; protected scrollingHeight?: number; protected subscriptions: Subscription[] = []; protected enabled = true; - protected endAnimationTimeout?: number; + protected isWithinContent = false; constructor(protected el: ElementRef) {} @@ -107,6 +108,9 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest if (this.content && this.contentScrollListener) { this.content.removeEventListener('ionScroll', this.contentScrollListener); } + if (this.content && this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + } } /** @@ -280,11 +284,17 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest * @param content Content element. */ protected updateContent(content?: HTMLIonContentElement | null): void { - if (this.content && this.contentScrollListener) { - this.content.removeEventListener('ionScroll', this.contentScrollListener); + if (this.content) { + if (this.contentScrollListener) { + this.content.removeEventListener('ionScroll', this.contentScrollListener); + delete this.contentScrollListener; + } + if (this.endContentScrollListener) { + this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener); + delete this.endContentScrollListener; + } delete this.content; - delete this.contentScrollListener; } content && this.trackContentScroll(content); @@ -346,27 +356,32 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest throw new Error('[collapsible-header] Couldn\'t set up scrolling'); } - page.classList.toggle('is-within-content', content.contains(expandedHeader)); + this.isWithinContent = content.contains(expandedHeader); + page.classList.toggle('is-within-content', this.isWithinContent); this.setEnabled(this.enabled); Object .entries(expandedFontStyles) .forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); + this.content.scrollEvents = true; this.content.addEventListener('ionScroll', this.contentScrollListener = ({ target }: CustomEvent): void => { if (target !== this.content || !this.enabled) { return; } - if (this.endAnimationTimeout) { - clearTimeout(this.endAnimationTimeout); - } - const scrollableHeight = contentScroll.scrollHeight - contentScroll.clientHeight; - const frozen = scrollableHeight <= scrollingHeight; + + let frozen = false; + if (this.isWithinContent) { + frozen = scrollableHeight <= scrollingHeight; + } else { + const collapsedHeight = expandedHeaderHeight - (expandedHeader.clientHeight ?? 0); + frozen = scrollableHeight + collapsedHeight <= 2 * expandedHeaderHeight; + } const progress = frozen ? 0 - : CoreMath.clamp(contentScroll.scrollTop / scrollingHeight, 0, 1); + : CoreMath.clamp(contentScroll.scrollTop / scrollingHeight, 0, 1); page.style.setProperty('--collapsible-header-progress', `${progress}`); page.classList.toggle('is-frozen', frozen); @@ -375,37 +390,31 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest Object .entries(progress > .5 ? collapsedFontStyles : expandedFontStyles) .forEach(([property, value]) => floatingTitle.style.setProperty(property, value as string)); - - if (progress > 0 && progress < 1) { - // Finish opening or closing the bar. - this.endAnimationTimeout = window.setTimeout(() => this.endAnimation(progress, contentScroll.scrollTop), 500); - } }); - } - /** - * End of animation when stop scrolling. - * - * @param progress Progress. - * @param scrollTop Current ScrollTop position. - */ - protected endAnimation(progress: number, scrollTop: number): void { - if(!this.page) { - return; - } + this.content.addEventListener( + 'ionScrollEnd', + this.endContentScrollListener = ({ target }: CustomEvent): void => { + if (target !== this.content || !this.enabled) { + return; + } - const collapse = progress > 0.5; + const progress = parseFloat(page.style.getPropertyValue('--collapsible-header-progress')); + const scrollTop = contentScroll.scrollTop; + const collapse = progress > 0.5; - this.page.style.setProperty('--collapsible-header-progress', collapse ? '1' : '0'); - this.page.classList.toggle('is-collapsed', collapse); + page.style.setProperty('--collapsible-header-progress', collapse ? '1' : '0'); + page.classList.toggle('is-collapsed', collapse); - if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) { - this.content?.scrollToPoint(null, this.scrollingHeight); - } + if (collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop < this.scrollingHeight) { + this.content?.scrollToPoint(null, this.scrollingHeight); + } - if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) { - this.content?.scrollToPoint(null, 0); - } + if (!collapse && this.scrollingHeight && this.scrollingHeight > 0 && scrollTop > 0) { + this.content?.scrollToPoint(null, 0); + } + }, + ); } } diff --git a/src/core/directives/collapsible-item.ts b/src/core/directives/collapsible-item.ts index 32db35299..e0c9b15b9 100644 --- a/src/core/directives/collapsible-item.ts +++ b/src/core/directives/collapsible-item.ts @@ -20,8 +20,8 @@ import { CoreComponentsRegistry } from '@singletons/components-registry'; import { CoreEventLoadingChangedData, CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreFormatTextDirective } from './format-text'; -const defaultMaxHeight = 64; -const buttonHeight = 44; +const defaultMaxHeight = 80; +const minMaxHeight = 56; /** * Directive to make an element collapsible. @@ -59,6 +59,10 @@ export class CoreCollapsibleItemDirective implements OnInit { * @inheritdoc */ async ngOnInit(): Promise { + if (this.height === null) { + return; + } + if (typeof this.height === 'string') { this.maxHeight = this.height === '' ? defaultMaxHeight @@ -66,7 +70,7 @@ export class CoreCollapsibleItemDirective implements OnInit { } else { this.maxHeight = this.height; } - this.maxHeight = this.maxHeight < defaultMaxHeight ? defaultMaxHeight : this.maxHeight; + this.maxHeight = this.maxHeight < minMaxHeight ? defaultMaxHeight : this.maxHeight; if (!this.maxHeight) { // Do not collapse. @@ -141,7 +145,7 @@ export class CoreCollapsibleItemDirective implements OnInit { this.element.classList.toggle('collapsible-enabled', enable); if (!enable || this.element.querySelector('ion-button.collapsible-toggle')) { - this.setMaxHeight(!enable || this.expanded? undefined : this.maxHeight); + this.setHeight(!enable || this.expanded ? undefined : this.maxHeight); return; } @@ -168,15 +172,15 @@ export class CoreCollapsibleItemDirective implements OnInit { /** * Set max height to element. * - * @param maxHeight Max height if collapsed or undefined if expanded. + * @param height Max height if collapsed or undefined if expanded. */ - protected setMaxHeight(maxHeight?: number): void { - if (maxHeight) { - this.element.style.setProperty('--max-height', maxHeight + buttonHeight + 'px'); + protected setHeight(height?: number): void { + if (height) { + this.element.style.setProperty('--collapsible-height', height + 'px'); } else if (this.expandedHeight) { - this.element.style.setProperty('--max-height', this.expandedHeight + 'px'); + this.element.style.setProperty('--collapsible-height', this.expandedHeight + 'px'); } else { - this.element.style.removeProperty('--max-height'); + this.element.style.removeProperty('--collapsible-height'); } } @@ -192,7 +196,7 @@ export class CoreCollapsibleItemDirective implements OnInit { } this.expanded = expand; this.element.classList.toggle('collapsible-collapsed', !expand); - this.setMaxHeight(!expand? this.maxHeight: undefined); + this.setHeight(!expand ? this.maxHeight: undefined); const toggleButton = this.element.querySelector('ion-button.collapsible-toggle'); const toggleText = toggleButton?.querySelector('.collapsible-toggle-text'); diff --git a/src/core/directives/content.ts b/src/core/directives/content.ts new file mode 100644 index 000000000..e214062bd --- /dev/null +++ b/src/core/directives/content.ts @@ -0,0 +1,46 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Directive, ElementRef, OnInit } from '@angular/core'; + +/** + * Directive to enabled scroll events on ALL scrollable ion-content. + * + * Example usage: + * + * + */ +@Directive({ + selector: 'ion-content', +}) +export class CoreContentDirective implements OnInit { + + protected element: HTMLIonContentElement; + + constructor(el: ElementRef) { + this.element = el.nativeElement; + } + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + if (this.element.classList.contains('disable-scroll-y')) { + return; + } + + this.element.scrollEvents = true; + } + +} diff --git a/src/core/directives/directives.module.ts b/src/core/directives/directives.module.ts index 9f518532f..9350f14eb 100644 --- a/src/core/directives/directives.module.ts +++ b/src/core/directives/directives.module.ts @@ -31,6 +31,7 @@ import { CoreCollapsibleHeaderDirective } from './collapsible-header'; import { CoreSwipeNavigationDirective } from './swipe-navigation'; import { CoreCollapsibleItemDirective } from './collapsible-item'; import { CoreCollapsibleFooterDirective } from './collapsible-footer'; +import { CoreContentDirective } from './content'; @NgModule({ declarations: [ @@ -51,6 +52,7 @@ import { CoreCollapsibleFooterDirective } from './collapsible-footer'; CoreSwipeNavigationDirective, CoreCollapsibleItemDirective, CoreCollapsibleFooterDirective, + CoreContentDirective, ], exports: [ CoreAutoFocusDirective, @@ -70,6 +72,7 @@ import { CoreCollapsibleFooterDirective } from './collapsible-footer'; CoreSwipeNavigationDirective, CoreCollapsibleItemDirective, CoreCollapsibleFooterDirective, + CoreContentDirective, ], }) export class CoreDirectivesModule {} diff --git a/src/core/features/course/components/course-format/course-format.html b/src/core/features/course/components/course-format/course-format.html index a8ca2b304..14cc14669 100644 --- a/src/core/features/course/components/course-format/course-format.html +++ b/src/core/features/course/components/course-format/course-format.html @@ -24,7 +24,7 @@
-
+
diff --git a/src/core/features/course/components/module-description/core-course-module-description.html b/src/core/features/course/components/module-description/core-course-module-description.html index 1476d7476..0ada00665 100644 --- a/src/core/features/course/components/module-description/core-course-module-description.html +++ b/src/core/features/course/components/module-description/core-course-module-description.html @@ -1,7 +1,7 @@ - diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index aea829834..2ff034ce9 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -46,7 +46,7 @@ + [contextInstanceId]="module.id" [courseId]="courseId" [collapsible-item]="expandDescription ? null : ''"> diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss index 75e76aedd..6091e0b2f 100644 --- a/src/core/features/course/components/module-info/course-module-info.scss +++ b/src/core/features/course/components/module-info/course-module-info.scss @@ -46,6 +46,23 @@ padding-top: 8px; } + core-course-module-completion ::ng-deep ion-button { + min-height: 28px; + margin: 0; + font-size: 12px; + text-transform: none; + font-weight: normal; + + ion-icon { + font-size: 16px; + min-width: 16px; + @include margin(0, 8px, 0, 0); + } + + ion-label { + white-space: normal !important; + } + } } diff --git a/src/core/features/course/components/module-summary/module-summary.html b/src/core/features/course/components/module-summary/module-summary.html index a510cf893..11bb659c0 100644 --- a/src/core/features/course/components/module-summary/module-summary.html +++ b/src/core/features/course/components/module-summary/module-summary.html @@ -49,7 +49,7 @@ {{ 'core.description' | translate}}

+ [contextInstanceId]="module.id" [courseId]="courseId" collapsible-item>
@@ -169,7 +169,7 @@

{{ 'core.grades.feedback' | translate}}

-

diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html index 60e2ece03..b9449db96 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -66,7 +66,7 @@ class="ion-text-wrap core-course-module-handler core-course-module-info {{module.handlerData.class}}" [ngClass]="{ 'item-dimmed': module.visible === 0 || module.uservisible === false }"> - + diff --git a/src/core/features/course/pages/course-summary/course-summary.html b/src/core/features/course/pages/course-summary/course-summary.html index 9fbfb57a4..625e360ae 100644 --- a/src/core/features/course/pages/course-summary/course-summary.html +++ b/src/core/features/course/pages/course-summary/course-summary.html @@ -72,8 +72,7 @@

{{'core.summary' | translate}}

- +
@@ -105,7 +104,7 @@ : - diff --git a/src/core/features/courses/pages/categories/categories.html b/src/core/features/courses/pages/categories/categories.html index fa208cdca..da1c214e4 100644 --- a/src/core/features/courses/pages/categories/categories.html +++ b/src/core/features/courses/pages/categories/categories.html @@ -34,7 +34,7 @@

-

diff --git a/src/core/features/grades/pages/course/course.html b/src/core/features/grades/pages/course/course.html index 2c237cf64..30e043ec3 100644 --- a/src/core/features/grades/pages/course/course.html +++ b/src/core/features/grades/pages/course/course.html @@ -55,7 +55,7 @@ - @@ -124,7 +124,7 @@

{{ 'core.grades.feedback' | translate}}

-

diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.html b/src/core/features/mainmenu/components/user-menu/user-menu.html index 3932978ae..d6e138a39 100644 --- a/src/core/features/mainmenu/components/user-menu/user-menu.html +++ b/src/core/features/mainmenu/components/user-menu/user-menu.html @@ -13,59 +13,61 @@ - - - - - -

- - -

- {{ siteUrl }} -
-
- - - -

{{ siteInfo.fullname }}

-
-
+ + + + + + +

+ + +

+ {{ siteUrl }} +
+
+ + + +

{{ siteInfo.fullname }}

+
+
- - - - - + + + + + - - - -

{{ handler.title | translate }}

-
- - - {{ handler.badgeA11yText | translate: {$a : handler.badge } }} - - - -
+ + + +

{{ handler.title | translate }}

+
+ + + {{ handler.badgeA11yText | translate: {$a : handler.badge } }} + + + +
- - - -

{{ 'core.settings.preferences' | translate }}

-
-
-
+ + + +

{{ 'core.settings.preferences' | translate }}

+
+
+
+
diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.ts b/src/core/features/mainmenu/components/user-menu/user-menu.ts index 87cd958f9..c84bc642a 100644 --- a/src/core/features/mainmenu/components/user-menu/user-menu.ts +++ b/src/core/features/mainmenu/components/user-menu/user-menu.ts @@ -49,7 +49,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy { siteUrl?: string; handlers: CoreUserProfileHandlerData[] = []; handlersLoaded = false; - loaded = false; user?: CoreUserProfile; displaySwitchAccount = true; removeAccountOnLogout = false; @@ -68,8 +67,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy { this.displaySwitchAccount = !currentSite.isFeatureDisabled('NoDelegate_SwitchAccount'); this.removeAccountOnLogout = !!CoreConstants.CONFIG.removeaccountonlogout; - this.loaded = true; - this.loadSiteLogo(currentSite); // Load the handlers. diff --git a/src/theme/components/collapsible-header.scss b/src/theme/components/collapsible-header.scss index f9993274d..c0650635a 100644 --- a/src/theme/components/collapsible-header.scss +++ b/src/theme/components/collapsible-header.scss @@ -8,6 +8,9 @@ --collapsible-header-floating-title-width: 0px; --collapsible-header-floating-title-x-delta: 0px; --collapsible-header-floating-title-width-delta: 0px; + ion-header.core-header-shadow { + --core-header-shadow: none; + } .collapsible-header-expanded { overflow: hidden; @@ -24,7 +27,9 @@ &:not(.is-collapsed) .collapsible-header-collapsed { --core-header-toolbar-border-width: 0; - --core-header-toolbar-background: transparent; + ion-toolbar { + --background: transparent; + } h1 { opacity: 0; @@ -32,6 +37,10 @@ } + &.is-active.is-collapsed.is-within-content ion-header.core-header-shadow { + --core-header-shadow: var(--drop-shadow-bottom, none); + } + &.is-active { .collapsible-header-expanded { diff --git a/src/theme/components/collapsible-item.scss b/src/theme/components/collapsible-item.scss index 979f5854a..3aad02e3e 100644 --- a/src/theme/components/collapsible-item.scss +++ b/src/theme/components/collapsible-item.scss @@ -1,12 +1,14 @@ .collapsible-item { --display-toggle: none; - --max-height: none; + --collapsible-height: none; + --toggle-size: 24px; + --gradient-size: 44px; &.collapsible-loading-height { display: block !important; height: auto !important; - --max-height: none !important; + --collapsible-height: auto !important; --display-toggle: none !important; } @@ -15,12 +17,12 @@ } @include media-breakpoint-down(sm) { - &.collapsible-enabled { + &.collapsible-enabled:not(.collapsible-loading-height) { position: relative; - padding-bottom: var(--collapsible-min-button-height); // So the Show less button can fit. + padding-bottom: var(--toggle-size); // So the Show less button can fit. --display-toggle: block; - @include core-transition(height max-height, 500ms); - height: calc(var(--max-height, auto)); + @include core-transition(height, 300ms); + height: calc(var(--collapsible-height, auto) + var(--toggle-size)); .collapsible-toggle { position: absolute; @@ -28,12 +30,12 @@ text-align: center; z-index: 7; text-transform: none; - font-size: 14px; + font-size: 11px; font-weight: normal; background-color: var(--collapsible-toggle-background); color: var(--collapsible-toggle-text); - min-height: var(--a11y-min-target-size); - min-width: var(--a11y-min-target-size); + min-height: var(--toggle-size); + min-width: var(--toggle-size); --border-radius: var(--huge-radius); border-radius: var(--border-radius); --padding-start: 0px; @@ -41,8 +43,8 @@ margin: 0px; .collapsible-toggle-arrow { - width: var(--a11y-min-target-size); - height: var(--a11y-min-target-size); + width: var(--toggle-size); + height: var(--toggle-size); background-position: center; background-repeat: no-repeat; @@ -61,7 +63,8 @@ &.collapsible-collapsed { overflow: hidden; - min-height: calc(var(--collapsible-min-button-height) + 12px); + min-height: calc(var(--toggle-size) + 12px); + height: var(--collapsible-height, auto); .collapsible-toggle-arrow { transform: rotate(90deg); @@ -69,11 +72,11 @@ &:before { content: ''; - height: 100%; + height: 60px; position: absolute; @include position(null, 0, 0, 0); - background: -webkit-linear-gradient(top, rgba(var(--background-gradient-rgb), 0) calc(100% - 56px), rgba(var(--background-gradient-rgb), 1) calc(100% - 5px)); - background: linear-gradient(to bottom, rgba(var(--background-gradient-rgb), 0) calc(100% - 56px), rgba(var(--background-gradient-rgb), 1) calc(100% - 5px)); + background: -webkit-linear-gradient(top, rgba(var(--background-gradient-rgb), 0) calc(100% - var(--gradient-size)), rgba(var(--background-gradient-rgb), 1) calc(100% - 4px)); + background: linear-gradient(to bottom, rgba(var(--background-gradient-rgb), 0) calc(100% - var(--gradient-size)), rgba(var(--background-gradient-rgb), 1) calc(100% - 4px)); z-index: 6; } } diff --git a/src/theme/components/discussion.scss b/src/theme/components/discussion.scss index d6756b142..540188a0e 100644 --- a/src/theme/components/discussion.scss +++ b/src/theme/components/discussion.scss @@ -57,6 +57,7 @@ ion-item.addon-message { } &:hover { + -webkit-filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3)); filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3)); } diff --git a/src/theme/components/format-text.scss b/src/theme/components/format-text.scss index 7cca7ef2c..2bd618242 100644 --- a/src/theme/components/format-text.scss +++ b/src/theme/components/format-text.scss @@ -70,10 +70,22 @@ core-format-text { display: block; } + &.collapsible-enabled { + .core-format-text-content { + display: block; + max-height: none; + } + &.collapsible-collapsed .core-format-text-content { + overflow: hidden; + height: var(--collapsible-height); + @include core-transition(height, 300ms); + } + } + @if ($core-format-text-never-shorten) { &.collapsible-enabled { --display-toggle: none !important; - --max-height: none !important; + --collapsible-height: auto !important; .collapsible-toggle { display: none !important; @@ -85,6 +97,12 @@ core-format-text { } } } + &.collapsible-item.inline { + display: inline-block; + &.collapsible-enabled .core-format-text-content { + display: inline-block; + } + } .core-adapted-img-container { position: relative; diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index a08dc3fa9..732686dd3 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -161,6 +161,7 @@ ion-header { ion-back-button, .in-toolbar.button-clear { --color: var(--core-header-toolbar-color); + --background: var(--core-header-toolbar-background); --ion-toolbar-color: var(--core-header-toolbar-color); --border-radius: var(--huge-radius); } @@ -170,7 +171,7 @@ ion-header { .button.button-clear, .button.button-solid { - --background: transparent; + --background: var(--core-header-toolbar-background); --color: var(--core-header-toolbar-color); --primary: var(--core-header-toolbar-color); } @@ -509,7 +510,6 @@ ion-toast { // Ionic list. ion-list { padding: 0 !important; - --ion-item-background: transparent; } // Safe areas @@ -739,7 +739,7 @@ body.core-iframe-fullscreen ion-router-outlet { ion-label { white-space: normal !important; } - ion-item > ion-icon { + ion-item > ion-icon[slot] { color: var(--color-shade); @include margin-horizontal(null, 16px); } @@ -752,7 +752,7 @@ body.core-iframe-fullscreen ion-router-outlet { --border-width: 0 0 3px 0; --border-color: var(--color-base); --inner-border-width: 0px; - ion-icon { + > ion-icon[slot] { color: var(--color-base); } } @@ -835,8 +835,7 @@ ion-toolbar h1 .core-bar-button-image img { // Action sheet. .md ion-action-sheet { .action-sheet-group-cancel { - -webkit-filter: drop-shadow(0px 3px 6px rgba(var(--drop-shadow))); - filter: drop-shadow(0px 3px 6px rgba(var(--drop-shadow))); + box-shadow: var(--drop-shadow-top, none); } .action-sheet-title { @@ -1347,7 +1346,10 @@ ion-item.item.divider { ion-label h2.big { font-size: var(--item-divider-font-size-big); } +} +ion-item-divider.item, +ion-item.item { .expandable-status-icon { font-size: 18px; @include core-transition(transform, 200ms); @@ -1443,8 +1445,7 @@ ion-grid.core-no-grid > ion-row { margin-bottom: 8px; } - filter: var(--scroll-shadow-top, none); - -webkit-filter: var(--scroll-shadow-top, none); + box-shadow: var(--drop-shadow-top, none); width: 100%; bottom: 0; z-index: 3; @@ -1472,6 +1473,7 @@ ion-grid.core-no-grid > ion-row { ion-header.no-title { --core-header-toolbar-border-width: 0; --core-header-toolbar-background: transparent; + --core-header-shadow: none !important; ion-toolbar .button.button-clear, ion-toolbar .button.button-solid { diff --git a/src/theme/theme.dark.scss b/src/theme/theme.dark.scss index ab278951a..15d9b7e14 100644 --- a/src/theme/theme.dark.scss +++ b/src/theme/theme.dark.scss @@ -39,7 +39,11 @@ --subdued-text-color: var(--medium); --stroke: var(--gray-700); - --contrast-background: black; + --contrast-background: var(--gray-900); + + --drop-shadow-color: 0, 0, 0, 1; + --drop-shadow-top: 0px 2px 5px rgba(var(--drop-shadow-color)); + --drop-shadow-bottom: 0px -2px 5px rgba(var(--drop-shadow-color)); --ion-card-color: var(--text-color); --ion-card-background: var(--ion-item-background); @@ -73,7 +77,7 @@ --core-header-toolbar-color: var(--text-color); --core-header-toolbar-border-color: var(--stroke); - --core-tabs-background: var(--gray-800); + --core-tabs-background: var(--gray-900); --core-tab-background: var(--core-tabs-background); --core-tab-color: var(--subdued-text-color); --core-tab-border-color: var(--gray-200); @@ -104,7 +108,7 @@ --core-combobox-color: var(--text-color); --core-combobox-border-color: var(--core-input-stroke); - --collapsible-toggle-background: var(--light); + --collapsible-toggle-text: var(--medium); --background-gradient-rgb: #{$ion-item-background-dark-rgb}; diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss index 2d0a532aa..8d0d29859 100644 --- a/src/theme/theme.light.scss +++ b/src/theme/theme.light.scss @@ -85,6 +85,10 @@ --contrast-background: white; + --drop-shadow-color: 0, 0, 0, 0.5; + --drop-shadow-top: 0px 2px 5px rgba(var(--drop-shadow-color)); + --drop-shadow-bottom: 0px -2px 5px rgba(var(--drop-shadow-color)); + --ion-text-color: var(--text-color); --ion-text-color-rgb: #{$text-color-rgb}; --subdued-text-color: var(--medium); @@ -138,25 +142,33 @@ --core-header-toolbar-border-color: var(--stroke); --core-header-toolbar-color: var(--text-color); --core-header-toolbar-height: 48px; - html.ios { - --core-header-toolbar-height: 48px; + --core-header-shadow: none; + + ion-header { + box-shadow: var(--core-header-shadow, none); + transition: box-shadow 0.5s; + + ion-toolbar { + --color: var(--core-header-toolbar-color); + --background: var(--core-header-toolbar-background); + --border-width: 0 0 var(--core-header-toolbar-border-width) 0; + --border-color: var(--core-header-toolbar-border-color); + + ion-button { + --ion-toolbar-color: var(--core-header-toolbar-color); + --color: var(--core-header-toolbar-color); + } + + ion-spinner { + --ion-color-base: var(--core-header-toolbar-color); + --color: var(--core-header-toolbar-color); + } + } } - ion-header ion-toolbar { - --color: var(--core-header-toolbar-color); - --background: var(--core-header-toolbar-background); - --border-width: 0 0 var(--core-header-toolbar-border-width) 0; - --border-color: var(--core-header-toolbar-border-color); - ion-button { - --ion-toolbar-color: var(--core-header-toolbar-color); - --color: var(--core-header-toolbar-color); - } - - ion-spinner { - --ion-color-base: var(--core-header-toolbar-color); - --color: var(--core-header-toolbar-color); - } + ion-header.core-header-shadow { + --core-header-shadow: var(--drop-shadow-bottom, none); } ion-header::after { @@ -300,9 +312,8 @@ --selected-item-color: var(--primary); --selected-item-border-width: 5px; - --collapsible-toggle-background: var(--light); - --collapsible-min-button-height: 44px; - --collapsible-toggle-text: var(--text-color); + --collapsible-toggle-background: transparent; + --collapsible-toggle-text: var(--medium); --background-gradient-rgb: #{$ion-item-background-rgb}; @@ -343,10 +354,6 @@ --addon-forum-border-color: var(--stroke); --addon-forum-highlight-color: var(--light); - --drop-shadow: 0, 0, 0, 0.5; - --scroll-shadow-bottom: drop-shadow(0px 3px 3px rgba(var(--drop-shadow))); - --scroll-shadow-top: drop-shadow(0px 3px 3px rgba(var(--drop-shadow))); - --core-question-correct-color: var(--success-shade); --core-question-correct-color-bg: var(--success-tint); --core-question-incorrect-color: var(--danger);