commit
						56a3287aff
					
				| @ -0,0 +1,13 @@ | ||||
| :host { | ||||
|     --mod-icon-filter: brightness(0); | ||||
| 
 | ||||
|     core-mod-icon { | ||||
|         background: transparent; | ||||
|         margin: 0; | ||||
|         --filter: var(--mod-icon-filter); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| :host-context(body.dark) { | ||||
|     --mod-icon-filter: brightness(0) invert(1); | ||||
| } | ||||
| @ -28,6 +28,7 @@ import { CoreNavigator } from '@services/navigator'; | ||||
| @Component({ | ||||
|     selector: 'addon-block-activitymodules', | ||||
|     templateUrl: 'addon-block-activitymodules.html', | ||||
|     styleUrls: ['activitymodules.scss'], | ||||
| }) | ||||
| export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent implements OnInit { | ||||
| 
 | ||||
| @ -96,16 +97,13 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i | ||||
|         // Sort the modnames alphabetically.
 | ||||
|         modFullNames = CoreUtils.sortValues(modFullNames); | ||||
|         for (const modName in modFullNames) { | ||||
|             let icon: string; | ||||
|             const iconModName = modName === 'resources' ? 'page' : modName; | ||||
| 
 | ||||
|             if (modName === 'resources') { | ||||
|                 icon = await CoreCourse.getModuleIconSrc('page', modIcons['page']); | ||||
|             } else { | ||||
|                 icon = await CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]); | ||||
|             } | ||||
|             const icon = await CoreCourseModuleDelegate.getModuleIconSrc(iconModName, modIcons[iconModName]); | ||||
| 
 | ||||
|             this.entries.push({ | ||||
|                 icon: icon, | ||||
|                 icon, | ||||
|                 iconModName, | ||||
|                 name: modFullNames[modName], | ||||
|                 modName, | ||||
|             }); | ||||
| @ -145,4 +143,5 @@ type AddonBlockActivityModuleEntry = { | ||||
|     icon: string; | ||||
|     name: string; | ||||
|     modName: string; | ||||
|     iconModName: string; | ||||
| }; | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
|     <ion-item class="ion-text-wrap" *ngFor="let entry of entries" detail="true" button (click)="gotoCoureListModType(entry)"> | ||||
|         <core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.modName" [showAlt]="false"> | ||||
|         <core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.iconModName" [showAlt]="false"> | ||||
|         </core-mod-icon> | ||||
|         <ion-label>{{ entry.name }}</ion-label> | ||||
|     </ion-item> | ||||
|  | ||||
| @ -23,6 +23,7 @@ import { CoreConstants, ModPurpose } from '@/core/constants'; | ||||
| import { AddonModForumIndexComponent } from '../../components/index'; | ||||
| import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; | ||||
| import { CoreCourseModuleData } from '@features/course/services/course-helper'; | ||||
| import { CoreIonicColorNames } from '@singletons/colors'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support forum modules. | ||||
| @ -58,7 +59,7 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp | ||||
|         const data = await super.getData(module, courseId); | ||||
| 
 | ||||
|         if ('afterlink' in module && !!module.afterlink) { | ||||
|             data.extraBadgeColor = ''; | ||||
|             data.extraBadgeColor = undefined; | ||||
|             const match = />(\d+)[^<]+/.exec(module.afterlink); | ||||
|             data.extraBadge = match ? Translate.instant('addon.mod_forum.unreadpostsnumber', { $a : match[1] }) : ''; | ||||
|         } else { | ||||
| @ -112,7 +113,7 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp | ||||
|         } | ||||
| 
 | ||||
|         data.extraBadge = Translate.instant('core.loading'); | ||||
|         data.extraBadgeColor = 'light'; | ||||
|         data.extraBadgeColor = CoreIonicColorNames.DARK; | ||||
| 
 | ||||
|         await CoreUtils.ignoreErrors(AddonModForum.invalidateForumData(courseId)); | ||||
| 
 | ||||
| @ -120,7 +121,7 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp | ||||
|             // Handle unread posts.
 | ||||
|             const forum = await AddonModForum.getForum(courseId, moduleId, { siteId }); | ||||
| 
 | ||||
|             data.extraBadgeColor = ''; | ||||
|             data.extraBadgeColor = undefined; | ||||
|             data.extraBadge = forum.unreadpostscount | ||||
|                 ? Translate.instant( | ||||
|                     'addon.mod_forum.unreadpostsnumber', | ||||
| @ -129,7 +130,7 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp | ||||
|                 : ''; | ||||
|         } catch { | ||||
|             // Ignore errors.
 | ||||
|             data.extraBadgeColor = ''; | ||||
|             data.extraBadgeColor = undefined; | ||||
|             data.extraBadge = ''; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -109,7 +109,7 @@ | ||||
|                         <ion-item class="ion-text-wrap addon-mod_h5pactivity-result-table-header"> | ||||
|                             <ion-label> | ||||
|                                 <ion-row class="ion-align-items-center"> | ||||
|                                     <ion-col class="ion-text-center">{{ result.optionslabel }}</ion-col> | ||||
|                                     <ion-col class="ion-text-start">{{ result.optionslabel }}</ion-col> | ||||
|                                     <ion-col class="ion-text-center">{{ result.correctlabel }}</ion-col> | ||||
|                                     <ion-col class="ion-text-center">{{ result.answerlabel }}</ion-col> | ||||
|                                 </ion-row> | ||||
| @ -118,7 +118,7 @@ | ||||
|                         <ion-item *ngFor="let option of result.options" class="ion-text-wrap addon-mod_h5pactivity-result-table-row"> | ||||
|                             <ion-label> | ||||
|                                 <ion-row class="ion-align-items-center"> | ||||
|                                     <ion-col class="ion-text-center"> | ||||
|                                     <ion-col class="ion-text-start"> | ||||
|                                         <core-format-text [text]="option.description" [component]="component" [componentId]="cmId" | ||||
|                                             contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|  | ||||
| @ -20,6 +20,7 @@ import { CoreCourseModuleData } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { CoreFileHelper } from '@services/file-helper'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreMimetypeUtils } from '@services/utils/mimetype'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreTimeUtils } from '@services/utils/time'; | ||||
| @ -95,7 +96,14 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase | ||||
| 
 | ||||
|         this.getResourceData(module, courseId, handlerData).then((extra) => { | ||||
|             handlerData.extraBadge = extra; | ||||
|             handlerData.extraBadgeColor = ''; | ||||
| 
 | ||||
|             return; | ||||
|         }).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
| 
 | ||||
|         this.getIconSrc(module).then((icon) => { | ||||
|             handlerData.icon = icon; | ||||
| 
 | ||||
|             return; | ||||
|         }).catch(() => { | ||||
| @ -214,6 +222,36 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase | ||||
|         return extra.join(' '); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     async getIconSrc(module?: CoreCourseModuleData): Promise<string | undefined> { | ||||
|         if (!module) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.0')) { | ||||
|             return await CoreCourse.getModuleIconSrc(module.modname, module.modicon); | ||||
|         } | ||||
|         let mimetypeIcon = ''; | ||||
| 
 | ||||
|         if (module.contentsinfo) { | ||||
|             // No need to use the list of files.
 | ||||
|             const mimetype = module.contentsinfo.mimetypes[0]; | ||||
|             if (mimetype) { | ||||
|                 mimetypeIcon = CoreMimetypeUtils.getMimetypeIcon(mimetype); | ||||
|             } | ||||
| 
 | ||||
|         } else if (module.contents && module.contents[0]) { | ||||
|             const files = module.contents; | ||||
|             const file = files[0]; | ||||
| 
 | ||||
|             mimetypeIcon = CoreMimetypeUtils.getFileIcon(file.filename || ''); | ||||
|         } | ||||
| 
 | ||||
|         return await CoreCourse.getModuleIconSrc(module.modname, module.modicon, mimetypeIcon); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| @import "~theme/globals"; | ||||
| 
 | ||||
| :host { | ||||
|     --core-format-text-background-gradient-rgb: var(--background-rgb, #{$ion-item-background-rgb}); | ||||
|     --course-storage-max-activity-height: 120px; | ||||
| 
 | ||||
|     ion-card.section ion-card-header { | ||||
| @ -23,8 +22,8 @@ | ||||
|             min-height: var(--course-storage-max-activity-height); | ||||
|             position: absolute; | ||||
|             @include position(0, 0, null, 0); | ||||
|             background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 30px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 20px)); | ||||
|             background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 30px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 20px)); | ||||
|             background: -webkit-linear-gradient(top, rgba(var(--background-gradient-rgb), 0) calc(100% - 30px), rgba(var(--background-gradient-rgb), 1) calc(100% - 20px)); | ||||
|             background: linear-gradient(to bottom, rgba(var(--background-gradient-rgb), 0) calc(100% - 30px), rgba(var(--background-gradient-rgb), 1) calc(100% - 20px)); | ||||
|             z-index: 6; | ||||
|             pointer-events: none; | ||||
|         } | ||||
|  | ||||
| @ -1,62 +0,0 @@ | ||||
| // (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 { Injectable } from '@angular/core'; | ||||
| import { CoreCourseOptionsMenuHandler, CoreCourseOptionsMenuHandlerData } from '@features/course/services/course-options-delegate'; | ||||
| import { CoreCourseAnyCourseDataWithOptions } from '@features/courses/services/courses'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to inject an option into course menu so that user can get to the manage storage page. | ||||
|  */ | ||||
| @Injectable( { providedIn: 'root' }) | ||||
| export class AddonStorageManagerCourseMenuHandlerService implements CoreCourseOptionsMenuHandler { | ||||
| 
 | ||||
|     name = 'AddonStorageManager'; | ||||
|     priority = 500; | ||||
|     isMenuHandler = true; | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     async isEnabledForCourse(): Promise<boolean> { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     async isEnabled(): Promise<boolean> { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     getMenuDisplayData( | ||||
|         course: CoreCourseAnyCourseDataWithOptions, | ||||
|     ): CoreCourseOptionsMenuHandlerData { | ||||
|         return { | ||||
|             icon: 'fas-cloud-download-alt', | ||||
|             title: 'addon.storagemanager.coursedownloads', | ||||
|             page: 'storage/' + course.id, | ||||
|             pageParams: { | ||||
|                 title: course.displayname ?? course.fullname, | ||||
|             }, | ||||
|             class: 'addon-storagemanager-coursemenu-handler', | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export const AddonStorageManagerCourseMenuHandler = makeSingleton(AddonStorageManagerCourseMenuHandlerService); | ||||
| @ -14,12 +14,10 @@ | ||||
| 
 | ||||
| import { NgModule, APP_INITIALIZER } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate'; | ||||
| import { CoreMainMenuRoutingModule } from '@features/mainmenu/mainmenu-routing.module'; | ||||
| import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module'; | ||||
| import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing'; | ||||
| import { CoreSettingsDelegate } from '@features/settings/services/settings-delegate'; | ||||
| import { AddonStorageManagerCourseMenuHandler } from './services/handlers/course-menu'; | ||||
| import { AddonStorageManagerSettingsHandler } from './services/handlers/settings'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
| @ -41,7 +39,6 @@ const routes: Routes = [ | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             useValue: () => { | ||||
|                 CoreCourseOptionsDelegate.registerHandler(AddonStorageManagerCourseMenuHandler.instance); | ||||
|                 CoreSettingsDelegate.registerHandler(AddonStorageManagerSettingsHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <div [class.core-loading-container]="loading || !safeUrl" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"> | ||||
| 
 | ||||
|     <core-navbar-buttons slot="end" append *ngIf="initialized && showFullscreenOnToolbar"> | ||||
|     <core-navbar-buttons slot="end" prepend *ngIf="initialized && showFullscreenOnToolbar"> | ||||
|         <ion-button fill="clear" (click)="toggleFullscreen()" | ||||
|             [attr.aria-label]="(fullscreen ? 'core.disablefullscreen' : 'core.fullscreen') | translate"> | ||||
|             <ion-icon *ngIf="!fullscreen" name="fas-expand" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -64,8 +64,8 @@ export class CoreCollapsibleItemDirective implements OnInit { | ||||
|         } | ||||
|         this.maxHeight = this.maxHeight < defaultMaxHeight ? defaultMaxHeight : this.maxHeight; | ||||
| 
 | ||||
|         if (!this.maxHeight || (window.innerWidth > 576 && window.innerHeight > 576)) { | ||||
|             // Do not collapse on big screens.
 | ||||
|         if (!this.maxHeight) { | ||||
|             // Do not collapse.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -91,9 +91,6 @@ export class CoreCollapsibleItemDirective implements OnInit { | ||||
|      */ | ||||
|     protected calculateHeight(): void { | ||||
|         // @todo: Work on calculate this height better.
 | ||||
|         if (!this.maxHeight) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Remove max-height (if any) to calculate the real height.
 | ||||
|         const initialMaxHeight = this.element.style.maxHeight; | ||||
| @ -117,7 +114,11 @@ export class CoreCollapsibleItemDirective implements OnInit { | ||||
|         this.toggleExpandEnabled = enable; | ||||
|         this.element.classList.toggle('collapsible-enabled', enable); | ||||
| 
 | ||||
|         if (!enable || this.element.querySelector('ion-button.collapsible-toggle'))  { | ||||
|         if (!enable || this.element.querySelector('ion-button.collapsible-toggle')) { | ||||
|             this.element.style.maxHeight = !enable || this.expanded | ||||
|                 ? '' | ||||
|                 : this.maxHeight + 'px'; | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -128,6 +129,7 @@ export class CoreCollapsibleItemDirective implements OnInit { | ||||
| 
 | ||||
|         const toggleText = document.createElement('span'); | ||||
|         toggleText.classList.add('collapsible-toggle-text'); | ||||
|         toggleText.classList.add('sr-only'); | ||||
|         toggleButton.appendChild(toggleText); | ||||
| 
 | ||||
|         const expandArrow = document.createElement('span'); | ||||
|  | ||||
| @ -279,23 +279,28 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|      */ | ||||
|     protected setExpandButtonEnabled(enable: boolean): void { | ||||
|         this.toggleExpandEnabled = enable; | ||||
|         this.element.classList.toggle('core-text-formatted', enable); | ||||
|         this.element.classList.toggle('collapsible-enabled', enable); | ||||
| 
 | ||||
|         if (!enable || this.element.querySelector('ion-button.collapsible-toggle'))  { | ||||
|             this.element.style.maxHeight = !enable || this.expanded | ||||
|                 ? '' | ||||
|                 : this.maxHeight + 'px'; | ||||
| 
 | ||||
|         if (!enable || this.element.querySelector('ion-button.core-format-text-toggle'))  { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Add expand/collapse buttons
 | ||||
|         const toggleButton = document.createElement('ion-button'); | ||||
|         toggleButton.classList.add('core-format-text-toggle'); | ||||
|         toggleButton.classList.add('collapsible-toggle'); | ||||
|         toggleButton.setAttribute('fill', 'clear'); | ||||
| 
 | ||||
|         const toggleText = document.createElement('span'); | ||||
|         toggleText.classList.add('core-format-text-toggle-text'); | ||||
|         toggleText.classList.add('collapsible-toggle-text'); | ||||
|         toggleText.classList.add('sr-only'); | ||||
|         toggleButton.appendChild(toggleText); | ||||
| 
 | ||||
|         const expandArrow = document.createElement('span'); | ||||
|         expandArrow.classList.add('core-format-text-arrow'); | ||||
|         expandArrow.classList.add('collapsible-toggle-arrow'); | ||||
|         toggleButton.appendChild(expandArrow); | ||||
| 
 | ||||
|         this.element.appendChild(toggleButton); | ||||
| @ -313,12 +318,12 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|             expand = !this.expanded; | ||||
|         } | ||||
|         this.expanded = expand; | ||||
|         this.element.classList.toggle('core-text-format-expanded', expand); | ||||
|         this.element.classList.toggle('core-text-format-collapsed', !expand); | ||||
|         this.element.classList.toggle('collapsible-expanded', expand); | ||||
|         this.element.classList.toggle('collapsible-collapsed', !expand); | ||||
|         this.element.style.maxHeight = expand ? '' : this.maxHeight + 'px'; | ||||
| 
 | ||||
|         const toggleButton = this.element.querySelector('ion-button.core-format-text-toggle'); | ||||
|         const toggleText = toggleButton?.querySelector('.core-format-text-toggle-text'); | ||||
|         const toggleButton = this.element.querySelector('ion-button.collapsible-toggle'); | ||||
|         const toggleText = toggleButton?.querySelector('.collapsible-toggle-text'); | ||||
|         if (!toggleButton || !toggleText) { | ||||
|             return; | ||||
|         } | ||||
| @ -396,8 +401,7 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|         this.element.classList.add('core-disable-media-adapt'); | ||||
| 
 | ||||
|         this.contentSpan.innerHTML = ''; // Remove current contents.
 | ||||
|         if (this.maxHeight && result.div.innerHTML != '' && | ||||
|                 (window.innerWidth < 576 || window.innerHeight < 576)) { // Don't collapse in big screens.
 | ||||
|         if (this.maxHeight && result.div.innerHTML != '') { | ||||
| 
 | ||||
|             // Move the children to the current element to be able to calculate the height.
 | ||||
|             CoreDomUtils.moveChildren(result.div, this.contentSpan); | ||||
|  | ||||
| @ -33,16 +33,35 @@ ion-item.item.item-current { | ||||
|     --background: var(--primary); | ||||
|     --color: var(--primary-contrast); | ||||
|     border: 0; | ||||
| 
 | ||||
|     ion-badge { | ||||
|         border: 1px solid var(--primary-contrast); | ||||
|     } | ||||
| 
 | ||||
|     ::ng-deep ion-icon { | ||||
|         color: var(--primary-contrast); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ion-icon.restricted { | ||||
|     font-size: 14px; | ||||
| } | ||||
| 
 | ||||
| ion-item.item.divider.section { | ||||
|     --padding-start: 0px; | ||||
| 
 | ||||
|     &.item-current { | ||||
|         ion-badge { | ||||
|             border: 1px solid var(--primary-contrast); | ||||
|         } | ||||
| 
 | ||||
|         ion-icon.expandable-status-icon { | ||||
|             color: var(--primary-contrast); | ||||
| 
 | ||||
|             &:hover { | ||||
|                 background: var(--primary-shade); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ion-icon.expandable-status-icon { | ||||
|         padding: 13px; | ||||
|         margin: 3px; | ||||
|         border-radius: 50%; | ||||
|         &:hover { | ||||
|             background: var(--gray-300); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -5,21 +5,24 @@ | ||||
| 
 | ||||
|             <ng-container *ngIf="completion.istrackeduser"> | ||||
|                 <ng-container *ngFor="let rule of details"> | ||||
|                     <ion-chip *ngIf="rule.statuscomplete" color="success" role="listitem" [attr.aria-label]="rule.accessibleDescription"> | ||||
|                     <ion-chip *ngIf="rule.statuscomplete" color="success" role="listitem" [attr.aria-label]="rule.accessibleDescription" | ||||
|                         class="completioninfo completion_complete"> | ||||
|                         <ion-icon name="fas-check" [attr.aria-label]="'core.course.completion_automatic:done' | translate "></ion-icon> | ||||
|                         <ion-label> | ||||
|                             {{ rule.rulevalue.description }} | ||||
|                         </ion-label> | ||||
|                     </ion-chip> | ||||
| 
 | ||||
|                     <ion-chip *ngIf="rule.statuscompletefail" color="danger" role="listitem" [attr.aria-label]="rule.accessibleDescription"> | ||||
|                     <ion-chip *ngIf="rule.statuscompletefail" color="danger" role="listitem" [attr.aria-label]="rule.accessibleDescription" | ||||
|                         class="completioninfo completion_fail"> | ||||
|                         <ion-icon name="fas-times" [attr.aria-label]="'core.course.completion_automatic:failed' | translate "></ion-icon> | ||||
|                         <ion-label> | ||||
|                             {{ rule.rulevalue.description }} | ||||
|                         </ion-label> | ||||
|                     </ion-chip> | ||||
| 
 | ||||
|                     <ion-chip *ngIf="rule.statusincomplete" color="dark" role="listitem" [attr.aria-label]="rule.accessibleDescription"> | ||||
|                     <ion-chip *ngIf="rule.statusincomplete" color="dark" role="listitem" [attr.aria-label]="rule.accessibleDescription" | ||||
|                         class="completioninfo completion_incomplete"> | ||||
|                         <ion-icon name="fas-edit" [attr.aria-label]="'core.course.completion_automatic:todo' | translate "></ion-icon> | ||||
|                         <ion-label> | ||||
|                             {{ rule.rulevalue.description }} | ||||
| @ -29,7 +32,7 @@ | ||||
|             </ng-container> | ||||
| 
 | ||||
|             <ng-container *ngIf="!completion.istrackeduser"> | ||||
|                 <ion-chip *ngFor="let rule of details" role="listitem"> | ||||
|                 <ion-chip *ngFor="let rule of details" role="listitem" class="core-module-completion-todo"> | ||||
|                     <ion-icon name="fas-edit" [attr.aria-label]="'core.course.completion_automatic:todo' | translate "></ion-icon> | ||||
|                     <ion-label> | ||||
|                         {{ rule.rulevalue.description }} | ||||
|  | ||||
| @ -1,12 +0,0 @@ | ||||
| :host { | ||||
|     .core-module-automatic-completion-conditions { | ||||
|         ion-badge { | ||||
|             font-weight: normal; | ||||
|             margin-right: 5px; | ||||
| 
 | ||||
|             &[color="medium"] { | ||||
|                 color: black; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -36,7 +36,6 @@ import { Translate } from '@singletons'; | ||||
| @Component({ | ||||
|     selector: 'core-course-module-completion', | ||||
|     templateUrl: 'core-course-module-completion.html', | ||||
|     styleUrls: ['module-completion.scss'], | ||||
| }) | ||||
| export class CoreCourseModuleCompletionComponent extends CoreCourseModuleCompletionBaseComponent { | ||||
| 
 | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
|                     {{ 'core.course' | translate}} | ||||
|                 </p> | ||||
|                 <p> | ||||
|                     <core-format-text [text]="course.displayname || course.fullname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                     <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </p> | ||||
|             </ion-label> | ||||
| @ -58,7 +58,7 @@ | ||||
|             <ion-item lines="full" class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <h2> | ||||
|                         <ion-icon name="fam-cloud-done" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-cloud-download-alt" aria-hidden="true"></ion-icon> | ||||
|                         {{ 'addon.storagemanager.downloads' | translate }} | ||||
|                     </h2> | ||||
|                 </ion-label> | ||||
| @ -81,7 +81,7 @@ | ||||
|             </ion-item> | ||||
|             <ion-button fill="outline" expand="block" *ngIf="canPrefetch && displayOptions.displayPrefetch" class="ion-text-wrap" | ||||
|                 (click)="prefetch()" color="primary" [disabled]="prefetchDisabled"> | ||||
|                 <ion-icon *ngIf="!prefetchLoading" name="fam-cloud-done" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon *ngIf="!prefetchLoading" name="fas-cloud-download-alt" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-spinner *ngIf="prefetchLoading" slot="start" aria-hidden="true"></ion-spinner> | ||||
|                 <ion-label> | ||||
|                     {{ 'core.download' | translate }} | ||||
|  | ||||
| @ -249,7 +249,13 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { | ||||
|      * Fetch course. | ||||
|      */ | ||||
|     protected async fetchCourse(): Promise<void> { | ||||
|         this.course = await CoreCourses.getUserCourse(this.courseId, true); | ||||
|         // Fix that.
 | ||||
|         try { | ||||
|             this.course = await CoreCourses.getUserCourse(this.courseId, true); | ||||
|         } catch { | ||||
|             // The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course.
 | ||||
|             this.course = await CoreCourses.getCourse(this.courseId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -71,7 +71,7 @@ | ||||
|                 </core-format-text> | ||||
| 
 | ||||
|                 <!-- Module completion. Only auto conditions--> | ||||
|                 <core-course-module-completion *ngIf="module.completiondata && module.uservisible" [completion]="module.completiondata" | ||||
|                 <core-course-module-completion *ngIf="autoCompletionTodo && module.uservisible" [completion]="module.completiondata" | ||||
|                     [moduleName]="module.name" [moduleId]="module.id" [showCompletionConditions]="showCompletionConditions"> | ||||
|                 </core-course-module-completion> | ||||
| 
 | ||||
|  | ||||
| @ -2,10 +2,14 @@ | ||||
| 
 | ||||
| :host { | ||||
|     --horizontal-margin: 10px; | ||||
|     --vertical-margin: 10px; | ||||
| 
 | ||||
|     ion-card { | ||||
|         margin-left: var(--horizontal-margin); | ||||
|         margin-right: var(--horizontal-margin); | ||||
|         margin: var(--vertical-margin) var(--horizontal-margin); | ||||
|     } | ||||
| 
 | ||||
|     ion-item { | ||||
|         --padding-start: 12px; | ||||
|     } | ||||
| 
 | ||||
|     ion-item.core-module-main-item { | ||||
| @ -84,4 +88,7 @@ | ||||
|         @include margin-horizontal(null, 8px); | ||||
|     } | ||||
| 
 | ||||
|     .core-course-module-info ::ng-deep core-course-module-completion .core-module-automatic-completion-conditions .completioninfo.completion_complete { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -20,7 +20,7 @@ import { | ||||
|     CoreCourseModuleCompletionData, | ||||
|     CoreCourseSection, | ||||
| } from '@features/course/services/course-helper'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseModuleCompletionTracking } from '@features/course/services/course'; | ||||
| import { CoreCourseModuleDelegate, CoreCourseModuleHandlerButton } from '@features/course/services/module-delegate'; | ||||
| import { | ||||
|     CoreCourseModulePrefetchDelegate, | ||||
| @ -55,6 +55,8 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|     showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled.
 | ||||
|     prefetchStatusIcon = ''; // Module prefetch status icon.
 | ||||
|     prefetchStatusText = ''; // Module prefetch status text.
 | ||||
|     autoCompletionTodo = false; | ||||
| 
 | ||||
|     protected prefetchHandler?: CoreCourseModulePrefetchHandler; | ||||
| 
 | ||||
|     protected moduleStatusObserver?: CoreEventObserver; | ||||
| @ -73,10 +75,18 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title; | ||||
| 
 | ||||
|         const completionStatus = this.showCompletionConditions && this.module.completiondata?.isautomatic && | ||||
|             this.module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC | ||||
|             ? this.module.completiondata.state | ||||
|             : undefined; | ||||
| 
 | ||||
|         this.autoCompletionTodo = completionStatus == CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE || | ||||
|             completionStatus == CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL; | ||||
| 
 | ||||
|         this.hasInfo = !!( | ||||
|             this.module.description || | ||||
|             (this.showActivityDates && this.module.dates && this.module.dates.length) || | ||||
|             (this.module.completiondata && this.showCompletionConditions && this.module.completiondata.isautomatic) || | ||||
|             (this.autoCompletionTodo) || | ||||
|             (this.module.visible === 0 && (!this.section || this.section.visible)) || | ||||
|             (this.module.visible !== 0 && this.module.isStealth) || | ||||
|             (this.module.availabilityinfo) | ||||
|  | ||||
| @ -1,4 +1,7 @@ | ||||
| <core-navbar-buttons slot="end"> | ||||
| <core-navbar-buttons slot="end" prepend> | ||||
|     <ion-button fill="clear" (click)="gotoCourseDownloads()" [attr.aria-label]="'addon.storagemanager.coursedownloads' | translate"> | ||||
|         <ion-icon name="fas-cloud-download-alt" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!dataLoaded || !displayRefresher" (ionRefresh)="doRefresh($event.target)"> | ||||
|  | ||||
| @ -29,7 +29,6 @@ import { | ||||
| } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { CoreCourseOptionsMenuHandlerToDisplay } from '@features/course/services/course-options-delegate'; | ||||
| import { CoreCourseSync, CoreCourseSyncProvider } from '@features/course/services/sync'; | ||||
| import { CoreCourseFormatComponent } from '../../components/course-format/course-format'; | ||||
| import { | ||||
| @ -54,7 +53,6 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|     sections?: CoreCourseSection[]; | ||||
|     sectionId?: number; | ||||
|     sectionNumber?: number; | ||||
|     courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = []; | ||||
|     dataLoaded = false; | ||||
|     downloadCourseEnabled = false; | ||||
|     moduleId?: number; | ||||
| @ -368,8 +366,16 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     gotoCourseDownloads(): void { | ||||
|         CoreNavigator.navigateToSitePath( | ||||
|             `storage/${this.course.id}`, | ||||
|             { params: { title: this.course.fullname } }, | ||||
|         ); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Page destroyed. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         this.isDestroyed = true; | ||||
|  | ||||
| @ -26,14 +26,23 @@ | ||||
|         <ng-container *ngIf="course"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <p *ngIf="course.categoryname"> | ||||
|                         <core-format-text [text]="course.categoryname" contextLevel="coursecat" [contextInstanceId]="course.categoryid"> | ||||
|                     <p *ngIf="course.displayname && course.shortname && course.fullname != course.displayname" | ||||
|                         class="core-course-shortname"> | ||||
|                         <core-format-text [text]="course.shortname" contextLevel="course" [contextInstanceId]="course.id"> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                     <h2> | ||||
|                         <span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span> | ||||
|                         <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"> | ||||
|                         </core-format-text> | ||||
|                     </h2> | ||||
|                     <ion-chip color="brand" *ngIf="course.categoryname" class="core-course-category ion-text-nowrap"> | ||||
|                         <span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span> | ||||
|                         <ion-label> | ||||
|                             <core-format-text [text]="course.categoryname" contextLevel="coursecat" [contextInstanceId]="course.categoryid"> | ||||
|                             </core-format-text> | ||||
|                         </ion-label> | ||||
|                     </ion-chip> | ||||
| 
 | ||||
|                     <div class="core-course-progress" *ngIf="progress !== undefined"> | ||||
|                         <core-progress-bar [progress]="progress" a11yText="core.course.aria:sectionprogress"> | ||||
|  | ||||
| @ -21,10 +21,6 @@ | ||||
|         <img [src]="imageThumb" core-external-content alt="" /> | ||||
|     </ion-avatar> | ||||
|     <ion-label> | ||||
|         <p *ngIf="category"> | ||||
|             <core-format-text [text]="category" contextLevel="coursecat" [contextInstanceId]="course!.categoryid"> | ||||
|             </core-format-text> | ||||
|         </p> | ||||
|         <h1>{{ title }}</h1> | ||||
|         <div class="core-course-progress" *ngIf="progress !== undefined"> | ||||
|             <core-progress-bar [progress]="progress" a11yText="core.course.aria:sectionprogress"> | ||||
|  | ||||
| @ -238,7 +238,6 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         // Get the title to display initially.
 | ||||
|         this.title = CoreCourseFormatDelegate.getCourseTitle(this.course); | ||||
|         this.category = 'categoryname' in this.course ? this.course.categoryname : ''; | ||||
| 
 | ||||
|         if ('overviewfiles' in this.course) { | ||||
|             this.imageThumb = this.course.overviewfiles?.[0]?.fileurl; | ||||
|  | ||||
| @ -25,6 +25,7 @@ import { CoreSites } from '@services/sites'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreCourseModuleData } from './course-helper'; | ||||
| import { CoreNavigationOptions } from '@services/navigator'; | ||||
| import { CoreIonicColorNames } from '@singletons/colors'; | ||||
| 
 | ||||
| /** | ||||
|  * Interface that all course module handlers must implement. | ||||
| @ -146,7 +147,7 @@ export interface CoreCourseModuleHandlerData { | ||||
|     /** | ||||
|      * The color of the extra badge. Default: primary. | ||||
|      */ | ||||
|     extraBadgeColor?: string; | ||||
|     extraBadgeColor?: CoreIonicColorNames; | ||||
| 
 | ||||
|     /** | ||||
|      * Whether to display a button to download/refresh the module if it's downloadable. | ||||
|  | ||||
| @ -70,7 +70,8 @@ | ||||
|                     class="core-course-category core-course-additional-info ion-text-nowrap"> | ||||
|                     <span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="course.categoryname"></core-format-text> | ||||
|                         <core-format-text [text]="course.categoryname" contextLevel="coursecat" [contextInstanceId]="course.categoryid"> | ||||
|                         </core-format-text> | ||||
|                     </ion-label> | ||||
|                 </ion-chip> | ||||
|             </div> | ||||
|  | ||||
| @ -34,6 +34,10 @@ | ||||
|         margin-bottom: 16px; | ||||
|     } | ||||
| 
 | ||||
|     form .core-username.ios { | ||||
|         --inner-border-width: 0 0 1px 0; | ||||
|     } | ||||
| 
 | ||||
|     form .item, | ||||
|     form .item ion-label { | ||||
|         --background: var(--core-login-input-background); | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|     <core-loading [hideUntil]="userLoaded"> | ||||
|         <ion-list *ngIf="user"> | ||||
|             <ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap" lines="full"> | ||||
|                 <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true"> | ||||
|                 <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="!canChangeProfilePicture"> | ||||
|                     <ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()" | ||||
|                         [attr.aria-label]="'core.user.newpicture' | translate" fill="clear" color="dark"> | ||||
|                         <ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -4,13 +4,11 @@ | ||||
| 
 | ||||
| core-format-text { | ||||
|     --core-format-text-background: var(--background, var(--ion-item-background)); | ||||
|     --core-format-text-background-gradient-rgb: var(--background-rgb, #{$ion-item-background-rgb}); | ||||
|     --core-format-text-viewer-icon-background: rgba(255, 255, 255, .5); | ||||
|     --core-format-text-loader-shine: 251,251,251; | ||||
| } | ||||
| 
 | ||||
| body.dark core-format-text { | ||||
|     --core-format-text-background-gradient-rgb: var(--background-rgb, #{$ion-item-background-dark-rgb}); | ||||
|     --core-format-text-viewer-icon-background: rgba(0, 0, 0, .5); | ||||
|     --core-format-text-loader-shine: 90,90,90; | ||||
| } | ||||
| @ -51,12 +49,12 @@ core-format-text { | ||||
|             display: inline; | ||||
|         } | ||||
| 
 | ||||
|         .core-format-text-toggle { | ||||
|         .collapsible-toggle { | ||||
|             display: none !important; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .core-format-text-toggle { | ||||
|     .collapsible-toggle { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
| @ -84,81 +82,21 @@ core-format-text { | ||||
|         } | ||||
| 
 | ||||
|         // This is to allow clicks in radio/checkbox content. | ||||
|         &.core-text-formatted { | ||||
|         &.collapsible-enabled { | ||||
|             cursor: pointer; | ||||
|             pointer-events: auto; | ||||
| 
 | ||||
|             .core-format-text-toggle { | ||||
|                 display: block; | ||||
|                 position: absolute; | ||||
|                 bottom: 0; | ||||
|                 left: 0; | ||||
|                 right: 0; | ||||
|                 text-align: center; | ||||
|                 z-index: 7; | ||||
|                 text-transform: none; | ||||
|                 text-align: end; | ||||
|                 font-size: 14px; | ||||
|                 background-color: var(--core-format-text-background); | ||||
|                 color: var(--text-color); | ||||
|                 margin: 0; | ||||
| 
 | ||||
| 
 | ||||
|                 .core-format-text-arrow { | ||||
|                     width: var(--a11y-min-target-size); | ||||
|                     height: var(--a11y-min-target-size); | ||||
| 
 | ||||
|                     background-position: center; | ||||
|                     background-repeat: no-repeat; | ||||
|                     background-size: 14px 14px; | ||||
|                     @include core-transition(transform, 500ms); | ||||
| 
 | ||||
|                     @include push-arrow-color(626262, true); | ||||
| 
 | ||||
|                     @include darkmode() { | ||||
|                         @include push-arrow-color(ffffff, true); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             &.core-text-format-collapsed { | ||||
|                 overflow: hidden; | ||||
|                 min-height: 50px; | ||||
| 
 | ||||
|                 .core-format-text-arrow { | ||||
|                     transform: rotate(90deg); | ||||
|                 } | ||||
| 
 | ||||
|                 &:before { | ||||
|                     content: ''; | ||||
|                     height: 100%; | ||||
|                     position: absolute; | ||||
|                     @include position(null, 0, 0, 0); | ||||
|                     background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); | ||||
|                     background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); | ||||
|                     z-index: 6; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             &.core-text-format-expanded { | ||||
|                 max-height: none !important; | ||||
| 
 | ||||
|                 padding-bottom: 50px; // So the Show less button can fit. | ||||
| 
 | ||||
|                 .core-format-text-arrow { | ||||
|                     transform: rotate(-90deg); | ||||
|                 } | ||||
|             } | ||||
|             @include collapsible-item(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @if ($core-format-text-never-shorten) { | ||||
|         &[maxHeight], | ||||
|         &[ng-reflect-max-height] { | ||||
|             &.core-text-formatted.core-text-format-expanded { | ||||
|             &.collapsible-enabled.collapsible-expanded { | ||||
|                 max-height: none !important; | ||||
| 
 | ||||
|                 .core-format-text-toggle { | ||||
|                 .collapsible-toggle { | ||||
|                     display: none !important; | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -219,9 +219,84 @@ | ||||
|             --horizontal-margin: 6px; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @mixin collapsible-item() { | ||||
|     --display-toggle: none; | ||||
|     .collapsible-toggle { | ||||
|         display: var(--display-toggle); | ||||
|     } | ||||
| 
 | ||||
|     @include media-breakpoint-down(sm) { | ||||
|         &.collapsible-enabled { | ||||
|             position:relative; | ||||
|             --display-toggle: block; | ||||
| 
 | ||||
|             .collapsible-toggle { | ||||
|                 position: absolute; | ||||
|                 @include position (null, 0, 0, null); | ||||
|                 text-align: center; | ||||
|                 z-index: 7; | ||||
|                 text-transform: none; | ||||
|                 font-size: 14px; | ||||
|                 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); | ||||
|                 --border-radius: var(--huge-radius); | ||||
|                 border-radius: var(--border-radius); | ||||
|                 --padding-start: 0px; | ||||
|                 --padding-end: 0px; | ||||
|                 margin: 0px; | ||||
| 
 | ||||
|                 .collapsible-toggle-arrow { | ||||
|                     width: var(--a11y-min-target-size); | ||||
|                     height: var(--a11y-min-target-size); | ||||
| 
 | ||||
|                     background-position: center; | ||||
|                     background-repeat: no-repeat; | ||||
|                     background-size: 14px 14px; | ||||
|                     @include core-transition(transform, 500ms); | ||||
| 
 | ||||
|                     @include push-arrow-color(626262, true); | ||||
| 
 | ||||
|                     @include darkmode() { | ||||
|                         @include push-arrow-color(ffffff, true); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             &.collapsible-collapsed { | ||||
|                 overflow: hidden; | ||||
|                 min-height: calc(var(--collapsible-min-button-height) + 12px); | ||||
| 
 | ||||
|                 .collapsible-toggle-arrow { | ||||
|                     transform: rotate(90deg); | ||||
|                 } | ||||
| 
 | ||||
|                 &:before { | ||||
|                     content: ''; | ||||
|                     height: 100%; | ||||
|                     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)); | ||||
|                     z-index: 6; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             &.collapsible-expanded { | ||||
|                 max-height: none !important; | ||||
|                 padding-bottom: var(--collapsible-min-button-height); // So the Show less button can fit. | ||||
| 
 | ||||
|                 .collapsible-toggle-arrow { | ||||
|                     transform: rotate(-90deg); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Color mixins. | ||||
| @function get_brightness($color) { | ||||
|  | ||||
| @ -164,6 +164,9 @@ ion-header { | ||||
|             --ion-toolbar-color: var(--core-header-toolbar-color); | ||||
|             --border-radius: var(--huge-radius); | ||||
|         } | ||||
|         ion-back-button::part(text) { | ||||
|             display: none; | ||||
|         } | ||||
| 
 | ||||
|         .button.button-clear, | ||||
|         .button.button-solid { | ||||
| @ -813,6 +816,7 @@ ion-card { | ||||
|     border-color: var(--border-color); | ||||
|     box-shadow: var(--box-shadow); | ||||
|     border-radius: var(--border-radius); | ||||
|     margin: var(--ion-card-vertical-margin) var(--ion-card-horizontal-margin); | ||||
| 
 | ||||
|     ion-item:only-child { | ||||
|         --inner-border-width: 0px; | ||||
| @ -983,6 +987,12 @@ ion-chip { | ||||
|     min-height: 24px; | ||||
|     height: auto; | ||||
| 
 | ||||
|     // Chips are not currently clickable. | ||||
|     &.ion-activatable { | ||||
|         cursor: auto; | ||||
|         pointer-events: none; | ||||
|     } | ||||
| 
 | ||||
|     &.ion-color { | ||||
|         background: var(--ion-color-tint); | ||||
|         &.chip-outline { | ||||
| @ -1145,6 +1155,10 @@ ion-item.item-lines-inset { | ||||
|     --border-width: 0px; | ||||
| } | ||||
| 
 | ||||
| ion-item.item-input.ios { | ||||
|     --inner-border-width: 0 0 1px 0; | ||||
| } | ||||
| 
 | ||||
| // Fake item. | ||||
| div.fake-ion-item { | ||||
|     position: relative; | ||||
| @ -1425,77 +1439,7 @@ ion-grid.core-no-grid > ion-row { | ||||
| } | ||||
| 
 | ||||
| [collapsible-item] { | ||||
|     --collapsible-display-toggle: none; | ||||
|     --collapsible-toggle-background: var(--ion-item-background); | ||||
|     --collapsible-min-button-height: 44px; | ||||
| 
 | ||||
|     .collapsible-toggle { | ||||
|         display: var(--collapsible-display-toggle); | ||||
|     } | ||||
| 
 | ||||
|     &.collapsible-enabled { | ||||
|         --collapsible-display-toggle: block; | ||||
| 
 | ||||
|         .collapsible-toggle { | ||||
|             display: var(--collapsible-display-toggle); | ||||
|             position: absolute; | ||||
|             bottom: 0; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|             text-align: center; | ||||
|             z-index: 7; | ||||
|             text-transform: none; | ||||
|             text-align: end; | ||||
|             font-size: 14px; | ||||
|             background-color: var(--collapsible-toggle-background); | ||||
|             color: var(--text-color); | ||||
|             margin: 0; | ||||
| 
 | ||||
|             .collapsible-toggle-arrow { | ||||
|                 width: var(--a11y-min-target-size); | ||||
|                 height: var(--a11y-min-target-size); | ||||
| 
 | ||||
|                 background-position: center; | ||||
|                 background-repeat: no-repeat; | ||||
|                 background-size: 14px 14px; | ||||
|                 @include core-transition(transform, 500ms); | ||||
| 
 | ||||
|                 @include push-arrow-color(626262, true); | ||||
| 
 | ||||
|                 @include darkmode() { | ||||
|                     @include push-arrow-color(ffffff, true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         &.collapsible-collapsed { | ||||
|             overflow: hidden; | ||||
|             min-height: calc(var(--collapsible-min-button-height) + 12); | ||||
| 
 | ||||
|             .collapsible-toggle-arrow { | ||||
|                 transform: rotate(90deg); | ||||
|             } | ||||
| 
 | ||||
|             &:before { | ||||
|                 content: ''; | ||||
|                 height: 100%; | ||||
|                 position: absolute; | ||||
|                 @include position(null, 0, 0, 0); | ||||
|                 background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); | ||||
|                 background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); | ||||
|                 z-index: 6; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         &.collapsible-expanded { | ||||
|             max-height: none !important; | ||||
|             padding-bottom: var(--collapsible-min-button-height); // So the Show less button can fit. | ||||
| 
 | ||||
|             .collapsible-toggle-arrow { | ||||
|                 transform: rotate(-90deg); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     @include collapsible-item(); | ||||
| } | ||||
| 
 | ||||
| ion-header.no-title { | ||||
|  | ||||
| @ -97,6 +97,10 @@ | ||||
|     --core-combobox-color: var(--text-color); | ||||
|     --core-combobox-border-color: var(--core-input-stroke); | ||||
| 
 | ||||
|     --collapsible-toggle-background: var(--light); | ||||
| 
 | ||||
|     --background-gradient-rgb: #{$ion-item-background-dark-rgb}; | ||||
| 
 | ||||
|     --core-login-background: var(--gray-900); | ||||
|     --core-login-text-color: var(--white); | ||||
|     --core-login-input-background: var(--core-login-background); | ||||
|  | ||||
| @ -88,6 +88,8 @@ | ||||
|     --subdued-text-color: var(--gray-700); | ||||
| 
 | ||||
|     --ion-card-color: var(--text-color); | ||||
|     --ion-card-vertical-margin: 10px; | ||||
|     --ion-card-horizontal-margin: 10px; | ||||
|     ion-card { | ||||
|         --border-width: 1px; | ||||
|         --border-style: solid; | ||||
| @ -286,6 +288,12 @@ | ||||
|     --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); | ||||
| 
 | ||||
|     --background-gradient-rgb: #{$ion-item-background-rgb}; | ||||
| 
 | ||||
|     --core-login-background: var(--white); | ||||
|     --core-login-text-color: var(--gray-900); | ||||
|     --core-login-input-background: var(--white); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user