diff --git a/cspell.json b/cspell.json index d922314af..bd0cb40a9 100644 --- a/cspell.json +++ b/cspell.json @@ -49,8 +49,7 @@ "cardview", "webm", "keycodes", - "denysvuika", - "fdescribe" + "denysvuika" ], "dictionaries": ["html", "en-gb", "en_US"] } diff --git a/docs/extending.md b/docs/extending.md index 8ccffc552..aa5c50fd2 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -612,6 +612,7 @@ Below is the list of public actions types you can use in the plugin definitions | NAVIGATE_ROUTE | any[] | Navigate to a particular Route (supports parameters) | | NAVIGATE_FOLDER | MinimalNodeEntity | Navigate to a folder based on the Node properties. | | NAVIGATE_PARENT_FOLDER | MinimalNodeEntity | Navigate to a containing folder based on the Node properties. | +| NAVIGATE_LIBRARY | string | Navigate to library | | SEARCH_BY_TERM | string | Perform a simple search by the term and navigate to Search results. | | SNACKBAR_INFO | string | Show information snackbar with the message provided. | | SNACKBAR_WARNING | string | Show warning snackbar with the message provided. | diff --git a/e2e/components/sidenav/sidenav.ts b/e2e/components/sidenav/sidenav.ts index 3c14615b6..429ec7754 100755 --- a/e2e/components/sidenav/sidenav.ts +++ b/e2e/components/sidenav/sidenav.ts @@ -33,7 +33,7 @@ export class Sidenav extends Component { link: '.sidenav-menu__item', label: '.menu__item--label', activeLink: '.menu__item--active', - newButton: '.adf-sidebar-action-menu-button' + newButton: '[data-automation-id="create-button"]' }; links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link)); diff --git a/src/app/components/create-menu/create-menu.component.html b/src/app/components/create-menu/create-menu.component.html index f111cbae7..38f7b924e 100644 --- a/src/app/components/create-menu/create-menu.component.html +++ b/src/app/components/create-menu/create-menu.component.html @@ -1,14 +1,26 @@ - - arrow_drop_down -
- queue -
-
- - - -
-
+ + + + + + + + + + + + + diff --git a/src/app/components/create-menu/create-menu.component.scss b/src/app/components/create-menu/create-menu.component.scss index 3482e076b..47efa8e92 100644 --- a/src/app/components/create-menu/create-menu.component.scss +++ b/src/app/components/create-menu/create-menu.component.scss @@ -1,3 +1,87 @@ -.app-create-menu { - width: 100%; +@mixin app-create-menu-theme($theme) { + $foreground: map-get($theme, foreground); + $accent: map-get($theme, accent); + $primary: map-get($theme, primary); + + .app-create-menu { + width: 100%; + + .mat-raised-button { + width: 100%; + display: block; + box-shadow: none !important; + height: 37.5px; + background-color: mat-color($accent); + color: mat-color($primary, default-contrast) !important; + border-radius: 4px; + font-size: 12.7px; + font-weight: normal; + text-transform: uppercase; + + .mat-icon { + width: 24px; + height: 25px; + color: mat-color($primary, default-contrast) !important; + } + + &__text { + width: 100%; + height: 20px; + text-align: left; + } + } + + &__root-menu { + max-width: 290px !important; + width: 290px; + display: flex; + align-items: center; + justify-content: center; + + & > .mat-menu-content { + width: 100%; + } + } + + &--collapsed { + color: mat-color($foreground, text, 0.54); + cursor: pointer; + &:hover { + color: mat-color($primary); + } + margin: 0; + border: none; + background: none; + } + + &__sub-menu { + .mat-menu-item { + display: flex; + flex-direction: row; + align-items: center; + font-size: 14px; + color: mat-color($foreground, text, 0.54); + line-height: 48px; + box-shadow: none; + transform: none; + transition: unset; + font-weight: normal; + text-transform: capitalize; + color: mat-color($primary); + + &:hover { + color: mat-color($accent); + } + } + + .mat-menu-item[disabled], + .mat-menu-item[disabled]:hover { + color: mat-color($foreground, text, 0.38); + + .mat-icon { + color: mat-color($foreground, text, 0.38); + } + } + } + } } diff --git a/src/app/components/create-menu/create-menu.component.ts b/src/app/components/create-menu/create-menu.component.ts index 4edbf01a9..a00d69215 100644 --- a/src/app/components/create-menu/create-menu.component.ts +++ b/src/app/components/create-menu/create-menu.component.ts @@ -52,6 +52,9 @@ export class CreateMenuComponent implements OnInit, OnDestroy { @Input() showLabel: boolean; + @Input() + expanded: boolean; + constructor( private store: Store, private extensions: AppExtensionService diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index 2c31f6d39..1fab3f347 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -41,6 +41,8 @@ import { LibrariesComponent } from './libraries.component'; import { AppTestingModule } from '../../testing/app-testing.module'; import { ContentApiService } from '../../services/content-api.service'; import { ExperimentalDirective } from '../../directives/experimental.directive'; +import { EffectsModule } from '@ngrx/effects'; +import { LibraryEffects } from 'src/app/store/effects'; describe('LibrariesComponent', () => { let fixture: ComponentFixture; @@ -69,7 +71,7 @@ describe('LibrariesComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [AppTestingModule], + imports: [AppTestingModule, EffectsModule.forRoot([LibraryEffects])], declarations: [ DataTableComponent, TimeAgoPipe, @@ -153,13 +155,8 @@ describe('LibrariesComponent', () => { }); describe('Node navigation', () => { - let routerSpy; - - beforeEach(() => { - routerSpy = spyOn(router, 'navigate'); - }); - it('does not navigate when id is not passed', () => { + spyOn(router, 'navigate').and.stub(); component.navigate(null); expect(router.navigate).not.toHaveBeenCalled(); @@ -167,11 +164,12 @@ describe('LibrariesComponent', () => { it('navigates to node id', () => { const document = { id: 'documentId' }; + spyOn(router, 'navigate').and.stub(); spyOn(contentApi, 'getNode').and.returnValue(of({ entry: document })); component.navigate(node.id); - expect(routerSpy.calls.argsFor(0)[0]).toEqual(['./', document.id]); + expect(router.navigate).toHaveBeenCalledWith(['libraries', 'documentId']); }); }); diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 39191fb27..d339b772a 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -24,18 +24,15 @@ */ import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; import { ShareDataRow } from '@alfresco/adf-content-services'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; - import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { SiteEntry } from 'alfresco-js-api'; import { ContentManagementService } from '../../services/content-management.service'; -import { ContentApiService } from '../../services/content-api.service'; import { AppExtensionService } from '../../extensions/extension.service'; -import { map } from 'rxjs/operators'; +import { NavigateLibraryAction } from 'src/app/store/actions'; @Component({ templateUrl: './libraries.component.html' @@ -44,12 +41,9 @@ export class LibrariesComponent extends PageComponent implements OnInit { isSmallScreen = false; constructor( - private route: ActivatedRoute, content: ContentManagementService, - private contentApi: ContentApiService, store: Store, extensions: AppExtensionService, - private router: Router, private breakpointObserver: BreakpointObserver ) { super(store, extensions, content); @@ -60,9 +54,6 @@ export class LibrariesComponent extends PageComponent implements OnInit { this.subscriptions.push( this.content.libraryDeleted.subscribe(() => this.reload()), - this.content.libraryCreated.subscribe((node: SiteEntry) => { - this.navigate(node.entry.guid); - }), this.breakpointObserver .observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape]) @@ -101,15 +92,6 @@ export class LibrariesComponent extends PageComponent implements OnInit { } navigate(libraryId: string) { - if (libraryId) { - this.contentApi - .getNode(libraryId, { relativePath: '/documentLibrary' }) - .pipe(map(node => node.entry)) - .subscribe(documentLibrary => { - this.router.navigate(['./', documentLibrary.id], { - relativeTo: this.route - }); - }); - } + this.store.dispatch(new NavigateLibraryAction(libraryId)); } } diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 6b9cab8d5..101ad1bda 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -1,6 +1,6 @@
- +
- {{ actionRef.icon }} - {{ actionRef.title | translate }} - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.ts b/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.ts index b822e59c1..5bbc9f7a2 100644 --- a/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.ts +++ b/src/app/components/toolbar/toolbar-menu-item/toolbar-menu-item.component.ts @@ -51,4 +51,8 @@ export class ToolbarMenuItemComponent { } return false; } + + trackById(index: number, obj: { id: string }) { + return obj.id; + } } diff --git a/src/app/extensions/extension.service.ts b/src/app/extensions/extension.service.ts index 41b7e5c38..57c3ce2b6 100644 --- a/src/app/extensions/extension.service.ts +++ b/src/app/extensions/extension.service.ts @@ -196,7 +196,8 @@ export class AppExtensionService implements RuleContext { getCreateActions(): Array { return this.createActions - .filter(action => this.filterByRules(action)) + .map(action => this.copyAction(action)) + .map(action => this.buildMenu(action)) .map(action => { let disabled = false; @@ -211,6 +212,39 @@ export class AppExtensionService implements RuleContext { }); } + private buildMenu(actionRef: ContentActionRef): ContentActionRef { + if ( + actionRef.type === ContentActionType.menu && + actionRef.children && + actionRef.children.length > 0 + ) { + const children = actionRef.children + .filter(action => this.filterByRules(action)) + .map(action => this.buildMenu(action)); + + actionRef.children = children + .map(action => { + let disabled = false; + + if (action.rules && action.rules.enabled) { + disabled = !this.extensions.evaluateRule( + action.rules.enabled, + this + ); + } + + return { + ...action, + disabled + }; + }) + .reduce(reduceEmptyMenus, []) + .reduce(reduceSeparators, []); + } + + return actionRef; + } + // evaluates content actions for the selection and parent folder node getAllowedToolbarActions(): Array { return this.toolbarActions diff --git a/src/app/services/content-management.service.ts b/src/app/services/content-management.service.ts index 66a4ccb58..d2bdfc173 100644 --- a/src/app/services/content-management.service.ts +++ b/src/app/services/content-management.service.ts @@ -234,7 +234,7 @@ export class ContentManagementService { }); } - createLibrary() { + createLibrary(): Observable { const dialogInstance = this.dialogRef.open(LibraryDialogComponent, { width: '400px' }); @@ -243,11 +243,9 @@ export class ContentManagementService { this.store.dispatch(new SnackbarErrorAction(message)); }); - dialogInstance.afterClosed().subscribe((node: SiteEntry) => { - if (node) { - this.libraryCreated.next(node); - } - }); + return dialogInstance + .afterClosed() + .pipe(tap(node => this.libraryCreated.next(node))); } deleteLibrary(id: string): void { diff --git a/src/app/store/actions/library.actions.ts b/src/app/store/actions/library.actions.ts index c68945edd..730819412 100644 --- a/src/app/store/actions/library.actions.ts +++ b/src/app/store/actions/library.actions.ts @@ -27,6 +27,7 @@ import { Action } from '@ngrx/store'; export const DELETE_LIBRARY = 'DELETE_LIBRARY'; export const CREATE_LIBRARY = 'CREATE_LIBRARY'; +export const NAVIGATE_LIBRARY = 'NAVIGATE_LIBRARY'; export class DeleteLibraryAction implements Action { readonly type = DELETE_LIBRARY; @@ -37,3 +38,8 @@ export class CreateLibraryAction implements Action { readonly type = CREATE_LIBRARY; constructor() {} } + +export class NavigateLibraryAction implements Action { + readonly type = NAVIGATE_LIBRARY; + constructor(public payload?: string) {} +} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index ff84a2c94..f2eed74e9 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -39,7 +39,7 @@ import { DownloadEffects, ViewerEffects, SearchEffects, - SiteEffects, + LibraryEffects, UploadEffects, FavoriteEffects, ModalsEffects @@ -57,7 +57,7 @@ import { DownloadEffects, ViewerEffects, SearchEffects, - SiteEffects, + LibraryEffects, UploadEffects, FavoriteEffects, ModalsEffects diff --git a/src/app/store/effects/library.effects.ts b/src/app/store/effects/library.effects.ts index 62372ee45..e209e7f05 100644 --- a/src/app/store/effects/library.effects.ts +++ b/src/app/store/effects/library.effects.ts @@ -25,24 +25,30 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; -import { map, take } from 'rxjs/operators'; +import { map, take, switchMap } from 'rxjs/operators'; import { DeleteLibraryAction, DELETE_LIBRARY, CreateLibraryAction, - CREATE_LIBRARY + CREATE_LIBRARY, + NavigateLibraryAction, + NAVIGATE_LIBRARY } from '../actions'; import { ContentManagementService } from '../../services/content-management.service'; import { Store } from '@ngrx/store'; import { AppStore } from '../states'; import { appSelection } from '../selectors/app.selectors'; +import { ContentApiService } from '../../services/content-api.service'; +import { Router } from '@angular/router'; @Injectable() -export class SiteEffects { +export class LibraryEffects { constructor( private store: Store, private actions$: Actions, - private content: ContentManagementService + private content: ContentManagementService, + private contentApi: ContentApiService, + private router: Router ) {} @Effect({ dispatch: false }) @@ -64,11 +70,26 @@ export class SiteEffects { }) ); - @Effect({ dispatch: false }) + @Effect() createLibrary$ = this.actions$.pipe( ofType(CREATE_LIBRARY), + switchMap(() => this.content.createLibrary()), + map(node => new NavigateLibraryAction(node.entry.guid)) + ); + + @Effect({ dispatch: false }) + navigateLibrary$ = this.actions$.pipe( + ofType(NAVIGATE_LIBRARY), map(action => { - this.content.createLibrary(); + const libraryId = action.payload; + if (libraryId) { + this.contentApi + .getNode(libraryId, { relativePath: '/documentLibrary' }) + .pipe(map(node => node.entry)) + .subscribe(documentLibrary => { + this.router.navigate(['libraries', documentLibrary.id]); + }); + } }) ); } diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 5ef35cd2d..2c20d22ac 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -10,12 +10,12 @@ @import '../components/permissions/permission-manager/permission-manager.component.theme'; @import '../components/context-menu/context-menu.component.theme'; @import '../dialogs/node-versions/node-versions.dialog.theme'; +@import '../components/create-menu/create-menu.component.scss'; @import './overrides/adf-toolbar.theme'; @import './overrides/adf-search-filter.theme'; @import './overrides/adf-info-drawer.theme'; @import './overrides/adf-upload-button.theme'; -@import './overrides/adf-sidebar-action-menu.theme'; @import './overrides/adf-upload-dialog.theme'; @import './overrides/adf-pagination.theme'; @import './overrides/adf-sidenav-layout.theme'; @@ -74,7 +74,6 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @include adf-search-filter-theme($theme); @include adf-info-drawer-theme($theme); @include adf-upload-button-theme($theme); - @include adf-sidebar-action-menu-theme($theme); @include adf-pagination-theme($theme); @include adf-sidenav-layout-theme($theme); @include adf-document-list-theme($theme); @@ -95,4 +94,5 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @include aca-about-component-theme($theme); @include aca-current-user-theme($theme); @include aca-context-menu-theme($theme); + @include app-create-menu-theme($theme); } diff --git a/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss b/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss deleted file mode 100644 index 0a56299f9..000000000 --- a/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss +++ /dev/null @@ -1,74 +0,0 @@ -@mixin adf-sidebar-action-menu-theme($theme) { - $foreground: map-get($theme, foreground); - $accent: map-get($theme, accent); - $primary: map-get($theme, primary); - - .adf-sidebar-action-menu { - .adf-sidebar-action-menu-button { - font-size: 12.7px; - font-weight: normal; - text-transform: uppercase; - } - } - - .mat-menu-panel.adf-sidebar-action-menu-panel { - max-width: 290px !important; - } - - .adf-sidebar-action-menu-panel { - width: 290px; - display: flex; - align-items: center; - justify-content: center; - } - - .adf-sidebar-action-menu-panel .mat-menu-content { - width: 100%; - } - - .adf-sidebar-action-menu-icon { - margin: 0; - } - - .adf-sidebar-action-menu-icon div[sidebar-menu-expand-icon] { - display: flex; - align-items: center; - justify-content: center; - } - - .adf-sidebar-action-menu { - width: 100%; - } - - .adf-sidebar-action-menu-options { - width: 100% !important; - - .mat-menu-item { - display: flex; - flex-direction: row; - align-items: center; - font-size: 14px; - color: mat-color($foreground, text, 0.54); - line-height: 48px; - box-shadow: none; - transform: none; - transition: unset; - font-weight: normal; - text-transform: capitalize; - color: mat-color($primary); - - &:hover { - color: mat-color($accent); - } - } - - .mat-menu-item[disabled], - .mat-menu-item[disabled]:hover { - color: mat-color($foreground, text, 0.38); - - .mat-icon { - color: mat-color($foreground, text, 0.38); - } - } - } -} diff --git a/src/assets/app.extensions.json b/src/assets/app.extensions.json index aa81b09e7..8afaa93b1 100644 --- a/src/assets/app.extensions.json +++ b/src/assets/app.extensions.json @@ -2,7 +2,12 @@ "$schema": "../../extension.schema.json", "$name": "app", "$version": "1.0.0", - "$references": ["plugin1.json", "dev.tools.json", "app.header.json"], + "$references": [ + "plugin1.json", + "dev.tools.json", + "app.header.json", + "app.create.json" + ], "rules": [ { @@ -132,23 +137,9 @@ "features": { "create": [ - { - "id": "app.create.folder", - "order": 100, - "icon": "create_new_folder", - "title": "APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER", - "description": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER", - "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED", - "actions": { - "click": "CREATE_FOLDER" - }, - "rules": { - "enabled": "app.navigation.folder.canCreate" - } - }, { "id": "app.create.uploadFile", - "order": 200, + "order": 100, "icon": "file_upload", "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE", "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES", @@ -162,7 +153,7 @@ }, { "id": "app.create.uploadFolder", - "order": 300, + "order": 200, "icon": "file_upload", "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER", "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS", @@ -173,6 +164,35 @@ "rules": { "enabled": "app.navigation.folder.canUpload" } + }, + { + "id": "app.create.separator.1", + "type": "separator", + "order": 300 + }, + { + "id": "app.create.folder", + "order": 400, + "icon": "create_new_folder", + "title": "APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER", + "description": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED", + "actions": { + "click": "CREATE_FOLDER" + }, + "rules": { + "enabled": "app.navigation.folder.canCreate" + } + }, + { + "id": "app.create.library", + "order": 600, + "title": "APP.NEW_MENU.MENU_ITEMS.CREATE_LIBRARY", + "description": "APP.NEW_MENU.TOOLTIPS.CREATE_LIBRARY", + "icon": "create_new_folder", + "actions": { + "click": "CREATE_LIBRARY" + } } ], "navbar": [ @@ -296,18 +316,6 @@ "visible": "app.trashcan.hasSelection" } }, - { - "id": "app.toolbar.createLibrary", - "order": 600, - "title": "Create Library", - "icon": "create_new_folder", - "actions": { - "click": "CREATE_LIBRARY" - }, - "rules": { - "visible": "app.navigation.isLibraries" - } - }, { "id": "app.toolbar.info", "type": "custom", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index f3e480fbf..e5c92f739 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -22,7 +22,8 @@ "MENU_ITEMS": { "CREATE_FOLDER": "Create folder", "UPLOAD_FILE": "Upload file", - "UPLOAD_FOLDER": "Upload folder" + "UPLOAD_FOLDER": "Upload folder", + "CREATE_LIBRARY": "Create Library" }, "TOOLTIPS": { "CREATE_FOLDER": "Create new folder", @@ -30,7 +31,8 @@ "UPLOAD_FILES": "Select files to upload", "UPLOAD_FILES_NOT_ALLOWED": "Files cannot be uploaded whilst viewing the current items", "UPLOAD_FOLDERS": "Select folders to upload", - "UPLOAD_FOLDERS_NOT_ALLOWED": "Folders cannot be uploaded whilst viewing the current items" + "UPLOAD_FOLDERS_NOT_ALLOWED": "Folders cannot be uploaded whilst viewing the current items", + "CREATE_LIBRARY": "Create a new File Library" } }, "BROWSE": { diff --git a/src/assets/plugins/app.create.json b/src/assets/plugins/app.create.json new file mode 100644 index 000000000..28ebe9731 --- /dev/null +++ b/src/assets/plugins/app.create.json @@ -0,0 +1,50 @@ +{ + "$schema": "../../../extension.schema.json", + "$name": "app.create", + "$version": "1.0.0", + + + "features": { + "create": [ + { + "id": "app.test.create1", + "order": 10, + "icon": "extension", + "title": "Custom Create", + "type": "menu", + "children": [ + { + "id": "level1.1", + "icon": "extension", + "title": "Level 1.1" + }, + { + "id": "level1.separator", + "type": "separator" + }, + { + "id": "level1.2", + "icon": "extension", + "title": "Level 1.2", + "type": "menu", + "children": [ + { + "id": "level2.1", + "icon": "extension", + "title": "Level 2.1" + } + ], + "rules": { + "enabled": "app.navigation.folder.canCreate" + } + } + ] + }, + { + "id": "app.create.separator", + "order": 20, + "type": "separator" + } + ] + } +} diff --git a/src/styles.scss b/src/styles.scss index 6bbb805c3..82ee99082 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -3,9 +3,10 @@ @import '~@alfresco/adf-core/prebuilt-themes/adf-blue-orange.css'; @import 'app/ui/application'; -body, html { +body, +html { height: 100%; - font-family: 'Muli', "Helvetica", "Arial", sans-serif !important; + font-family: 'Muli', 'Helvetica', 'Arial', sans-serif !important; } body {