MOBILE-915 fontawesome: Add fontawesome icons

main
Pau Ferrer Ocaña 2018-06-07 11:22:51 +02:00
parent 0ec3f9fcab
commit 3bf3a71736
25 changed files with 1652 additions and 1571 deletions

View File

@ -0,0 +1,7 @@
// New copy task for font files
module.exports = {
copyFontAwesome: {
src: ['{{ROOT}}/node_modules/font-awesome/fonts/**/*'],
dest: '{{WWW}}/assets/fonts'
}
};

View File

@ -0,0 +1,9 @@
// Adding Font Awesome to includePaths
module.exports = {
includePaths: [
'node_modules/ionic-angular/themes',
'node_modules/ionicons/dist/scss',
'node_modules/ionic-angular/fonts',
'node_modules/font-awesome/scss'
]
};

3005
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,9 @@
"email": "mobile@moodle.com"
},
"config": {
"ionic_webpack": "./config/webpack.config.js"
"ionic_webpack": "./config/webpack.config.js",
"ionic_copy": "./config/copy.config.js",
"ionic_sass": "./config/sass.config.js"
},
"repository": {
"type": "git",
@ -71,6 +73,7 @@
"chart.js": "^2.7.2",
"electron-builder-squirrel-windows": "^19.3.0",
"electron-windows-notifications": "^1.1.13",
"font-awesome": "4.7.0",
"ionic-angular": "^3.9.2",
"ionicons": "3.0.0",
"jszip": "^3.1.4",

View File

@ -1,46 +0,0 @@
/** This file is intended to translate fontawesome to ionicons while the font is not supported */
.fa.icon {
@extend ion-icon;
}
/*.fa {
font-size: $button-icon-size;
width: $button-icon-size;
height: $button-icon-size;
}*/
/** Fixed width */
.fa-fw {
width: (18em / 14);
text-align: center;
}
/** Uncomment for dev purposes, it will show an asterisk in red where a missing icon is */
/*.fa:before {
color: red !important;
content: $ionicon-var-asterisk;
}*/
/** Icons translation */
.md {
.fa-search-plus:before { content: "\f375"; } // search
.fa-cog:before { content: "\f2cf"; } // cog
.fa-trash:before { content: "\f398"; } // trash
.fa-thumbs-up:before { content: "\f392"; } // thumbs-up
.fa-thumbs-down:before { content: "\f391"; } // thumbs-down
.fa-ban:before { content: "\f367"; } // remove-circle
.fa-remove:before { content: "\f2c0"; } // close
.fa-check:before { content: "\f2bc"; } // checkmark
}
.ios, .wp {
.fa-search-plus:before { content: "\f4a5"; } // search
.fa-cog:before { content: "\f412"; } // cog
.fa-trash:before { content: "\f4c5"; } // trash
.fa-thumbs-up:before { content: "\f256"; } // thumbs-up
.fa-thumbs-down:before { content: "\f254"; } // thumbs-down
.fa-ban:before { content: "\f1fb"; } // remove-circle
.fa-remove:before { content: "\f406"; } // close
.fa-check:before { content: "\f3ff"; } // checkmark
}

View File

@ -27,6 +27,7 @@ import { CoreProgressBarComponent } from './progress-bar/progress-bar';
import { CoreEmptyBoxComponent } from './empty-box/empty-box';
import { CoreSearchBoxComponent } from './search-box/search-box';
import { CoreFileComponent } from './file/file';
import { CoreIconComponent } from './icon/icon';
import { CoreContextMenuComponent } from './context-menu/context-menu';
import { CoreContextMenuItemComponent } from './context-menu/context-menu-item';
import { CoreContextMenuPopoverComponent } from './context-menu/context-menu-popover';
@ -60,6 +61,7 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreEmptyBoxComponent,
CoreSearchBoxComponent,
CoreFileComponent,
CoreIconComponent,
CoreContextMenuComponent,
CoreContextMenuItemComponent,
CoreContextMenuPopoverComponent,
@ -103,6 +105,7 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreEmptyBoxComponent,
CoreSearchBoxComponent,
CoreFileComponent,
CoreIconComponent,
CoreContextMenuComponent,
CoreContextMenuItemComponent,
CoreChronoComponent,

View File

@ -1,9 +1,9 @@
<ion-list>
<ion-list-header *ngIf="title">{{title}}</ion-list-header>
<a ion-item text-wrap *ngFor="let item of items" core-link [capture]="item.captureLink" [autoLogin]="item.autoLogin" [href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden" [attr.detail-none]="!item.href || item.iconAction">
<ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" [attr.aria-label]="item.ariaDescription" item-start></ion-icon>
<core-icon *ngIf="item.iconDescription" [name]="item.iconDescription" [attr.aria-label]="item.ariaDescription" item-start></core-icon>
<core-format-text [clean]="true" [text]="item.content"></core-format-text>
<ion-icon *ngIf="(item.href || item.action) && item.iconAction && item.iconAction != 'spinner'" [name]="item.iconAction" item-end></ion-icon>
<core-icon *ngIf="(item.href || item.action) && item.iconAction && item.iconAction != 'spinner'" [name]="item.iconAction" item-end></core-icon>
<ion-spinner *ngIf="(item.href || item.action) && item.iconAction == 'spinner'" item-end></ion-spinner>
<ion-badge class="{{item.badgeClass}}" item-end *ngIf="item.badge">{{item.badge}}</ion-badge>
</a>

View File

@ -1,4 +1,4 @@
<button [hidden]="hideMenu" ion-button clear icon-only [attr.aria-label]="ariaLabel" (click)="showContextMenu($event)">
<ion-icon [name]="icon"></ion-icon>
<core-icon [name]="icon"></core-icon>
</button>
<ng-content></ng-content>

View File

@ -1,7 +1,7 @@
<div class="core-empty-box" [class.core-empty-box-inline]="!image && !icon">
<div class="core-empty-box-content" padding>
<img *ngIf="image && !icon" [src]="image" role="presentation">
<ion-icon *ngIf="icon" [name]="icon"></ion-icon>
<core-icon *ngIf="icon" [name]="icon"></core-icon>
<p *ngIf="message" [class.padding-top]="image || icon">{{ message }}</p>
<ng-content></ng-content>
</div>

View File

@ -0,0 +1 @@
<ion-icon [name]="name" [isActive]="isActive" [md]="md" [ios]="ios" [color]="color"></ion-icon>

View File

@ -0,0 +1,6 @@
// Color icons
@each $color-name, $color-base, $color-contrast in get-colors($colors) {
.fa-#{$color-name} {
color: $color-base;
}
}

View File

@ -0,0 +1,90 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Component, Input, OnInit, ElementRef } from '@angular/core';
/**
* Core Icon is a component that enabled a posibility to add fontawesome icon to the html. It's recommended if both fontawesome
* or ionicons can be used in the name attribute. To use fontawesome just place the full icon name with the fa- prefix and
* the component will detect it.
* Check available icons https://fontawesome.com/v4.7.0/icons/.
*/
@Component({
selector: 'core-icon',
templateUrl: 'icon.html',
})
export class CoreIconComponent implements OnInit {
// Common params.
@Input() name: string;
@Input('color') color?: string;
// Ionicons params.
@Input('isActive') isActive?: boolean;
@Input('md') md?: string;
@Input('ios') ios?: string;
// FontAwesome params.
@Input('fixed-width') fixedWidth: string;
element: HTMLElement;
constructor(el: ElementRef) {
this.element = el.nativeElement;
}
/**
* Component being initialized.
*/
ngOnInit(): void {
let newElement;
if (this.name.startsWith('fa-')) {
// Use a new created element to avoid ion-icon working.
newElement = document.createElement('ion-icon');
newElement.classList.add('icon');
newElement.classList.add('fa');
newElement.classList.add(this.name);
if (this.isTrueProperty(this.fixedWidth)) {
newElement.classList.add('fa-fw');
}
if (this.color) {
newElement.classList.add('fa-' + this.color);
}
} else {
newElement = this.element.firstElementChild;
}
const attrs = this.element.attributes;
for (let i = attrs.length - 1; i >= 0; i--) {
newElement.setAttribute(attrs[i].name, attrs[i].value);
}
this.element.parentElement.replaceChild(newElement, this.element);
}
/**
* Check if the value is true or on.
*
* @param {any} val value to be checked.
* @return {boolean} If has a value equivalent to true.
*/
isTrueProperty(val: any): boolean {
if (typeof val === 'string') {
val = val.toLowerCase().trim();
return (val === 'true' || val === 'on' || val === '');
}
return !!val;
}
}

View File

@ -1,4 +1,4 @@
<ng-content></ng-content>
<a ion-button icon-only clear [attr.aria-label]="label | translate" (click)="toggle()" [core-keep-keyboard]="selector" [inButton]="true">
<ion-icon [name]="iconName"></ion-icon>
<core-icon [name]="iconName"></core-icon>
</a>

View File

@ -2,7 +2,7 @@
<div class="core-tabs-bar" #topTabs [hidden]="!tabs || tabs.length < 2">
<ng-container *ngFor="let tab of tabs; let idx = index">
<a *ngIf="tab.show" [attr.aria-selected]="selected == idx" (click)="selectTab(idx)">
<ion-icon *ngIf="tab.icon" [name]="tab.icon"></ion-icon>
<core-icon *ngIf="tab.icon" [name]="tab.icon"></core-icon>
<span *ngIf="tab.title">{{ tab.title }}</span>
<ion-badge *ngIf="tab.badge" [color]="tab.badgeStyle" class="tab-badge">{{tab.badge}}</ion-badge>
</a>

View File

@ -22,7 +22,7 @@
<!-- Buttons defined by the module handler. -->
<button ion-button icon-only clear *ngFor="let button of module.handlerData.buttons" [hidden]="button.hidden || spinner || module.handlerData.spinner" (click)="buttonClicked($event, button)" color="dark" class="core-animate-show-hide" [attr.aria-label]="button.label | translate">
<ion-icon [name]="button.icon" [ios]="button.iosIcon || ''" [md]="button.mdIcon || ''"></ion-icon>
<core-icon [name]="button.icon" [ios]="button.iosIcon || ''" [md]="button.mdIcon || ''"></core-icon>
</button>
<!-- Spinner. -->

View File

@ -1,10 +1,10 @@
<a ion-item text-wrap (click)="openCourse(course)" [attr.disabled]="course.visible == 0 ? true : null" [attr.detail-none]="course.visible == 0 ? true : null" [title]="course.fullname">
<ion-icon name="ionic" item-start></ion-icon>
<core-icon name="fa-graduation-cap" fixed-width item-start></core-icon>
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
<div item-end>
<span *ngIf="!course.isEnrolled">
<span ion-button icon-only clear color="gray" *ngFor="let instance of course.enrollment" [attr.aria-label]=" instance.name | translate">
<ion-icon *ngIf="instance.icon" [name]="instance.icon"></ion-icon>
<core-icon *ngIf="instance.icon" [name]="instance.icon"></core-icon>
<img *ngIf="instance.img && !instance.icon" [src]="instance.img" class="core-course-enrollment-img">
</span>
</span>

View File

@ -5,7 +5,7 @@
<div class="core-button-spinner" *ngIf="downloadCourseEnabled">
<!-- Download course. -->
<button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourse($event)" [attr.aria-label]="prefetchCourseData.title | translate">
<ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon>
<core-icon [name]="prefetchCourseData.prefetchCourseIcon"></core-icon>
</button>
<!-- Download course spinner. -->
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'"></ion-spinner>

View File

@ -11,7 +11,7 @@
<ion-list *ngIf="course">
<a ion-item text-wrap (click)="openCourse()" [title]="course.fullname" [attr.detail-none]="!canAccessCourse">
<ion-icon name="ionic" item-start></ion-icon>
<core-icon name="fa-graduation-cap" fixed-width item-start></core-icon>
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
<p *ngIf="course.categoryname"><core-format-text [text]="course.categoryname"></core-format-text></p>
<p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"dfdaymonthyear"}} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"dfdaymonthyear"}}</span></p>
@ -42,7 +42,7 @@
<p>{{ 'core.courses.notenrollable' | translate }}</p>
</ion-item>
<a ion-item *ngIf="canAccessCourse && downloadCourseEnabled" (click)="prefetchCourse()" detail-none [attr.aria-label]="prefetchCourseData.title | translate">
<ion-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></ion-icon>
<core-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></core-icon>
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" item-start></ion-spinner>
<h2>{{ 'core.course.downloadcourse' | translate }}</h2>
</a>

View File

@ -73,7 +73,7 @@
<!-- Download all courses. -->
<div *ngIf="downloadAllCoursesEnabled && courses[courses.selected] && courses[courses.selected].length > 1" class="core-button-spinner" float-end>
<button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon>
<core-icon [name]="prefetchCoursesData[courses.selected].icon"></core-icon>
</button>
<ion-spinner *ngIf="!prefetchCoursesData[courses.selected].icon || prefetchCoursesData[courses.selected].icon == 'spinner'"></ion-spinner>
<span float-end *ngIf="prefetchCoursesData[courses.selected].badge">{{prefetchCoursesData[courses.selected].badge}}</span>

View File

@ -16,18 +16,18 @@
<ion-spinner></ion-spinner>
</ion-item>
<ion-item *ngFor="let handler of handlers" [ngClass]="['core-moremenu-handler', handler.class]" (click)="openHandler(handler)" title="{{ handler.title | translate }}" detail-push>
<ion-icon [name]="handler.icon" item-start></ion-icon>
<core-icon [name]="handler.icon" item-start></core-icon>
<p>{{ handler.title | translate}}</p>
<ion-badge item-end *ngIf="handler.showBadge" [hidden]="handler.loading || !handler.badge">{{badge}}</ion-badge>
<ion-spinner item-end *ngIf="handler.showBadge && handler.loading"></ion-spinner>
</ion-item>
<div *ngFor="let item of customItems" class="core-moremenu-customitem">
<a ion-item *ngIf="item.type != 'embedded'" [href]="item.url" core-link [capture]="item.type == 'app'" [inApp]="item.type == 'inappbrowser'" title="{{item.label}}">
<ion-icon [name]="item.icon" item-start></ion-icon>
<core-icon [name]="item.icon" item-start></core-icon>
<p>{{item.label}}</p>
</a>
<a ion-item *ngIf="item.type == 'embedded'" (click)="openItem(item)" title="{{item.label}}">
<ion-icon [name]="item.icon" item-start></ion-icon>
<core-icon [name]="item.icon" item-start></core-icon>
<p>{{item.label}}</p>
</a>
</div>

View File

@ -26,7 +26,7 @@
</ion-item>
<ion-item *ngFor="let handler of handlers" [ngClass]="['core-settings-handler', handler.class]" (click)="openHandler(handler.page, handler.params)" [title]="handler.title | translate" detail-push [class.core-split-item-selected]="handler.page == selectedPage">
<ion-icon [name]="handler.icon" item-start *ngIf="handler.icon"></ion-icon>
<core-icon [name]="handler.icon" item-start *ngIf="handler.icon"></core-icon>
<p>{{ handler.title | translate}}</p>
</ion-item>

View File

@ -1,4 +1,4 @@
<a *ngIf="show" ion-item text-wrap [navPush]="'CoreCoursesAvailableCoursesPage'">
<ion-icon name="ionic" item-start></ion-icon>
<core-icon name="fa-graduation-cap" fixed-width item-start></core-icon>
<h2>{{ 'core.courses.availablecourses' | translate}}</h2>
</a>

View File

@ -1,4 +1,4 @@
<a *ngIf="show" ion-item text-wrap [navPush]="'CoreCoursesMyCoursesPage'">
<ion-icon name="ionic" item-start></ion-icon>
<core-icon name="fa-graduation-cap" fixed-width item-start></core-icon>
<h2>{{ 'core.courses.mycourses' | translate}}</h2>
</a>

View File

@ -26,7 +26,7 @@
<ion-row no-padding justify-content-between *ngIf="communicationHandlers && communicationHandlers.length">
<ion-col align-self-center *ngFor="let comHandler of communicationHandlers" text-center>
<a (click)="handlerClicked($event, comHandler)" [ngClass]="['core-user-profile-handler', comHandler.class]" title="{{comHandler.title | translate}}" tappable>
<ion-icon [name]="comHandler.icon"></ion-icon>
<core-icon [name]="comHandler.icon"></core-icon>
<p>{{comHandler.title | translate}}</p>
</a>
</ion-col>
@ -47,13 +47,13 @@
</ion-item>
<a *ngFor="let npHandler of newPageHandlers" ion-item text-wrap [ngClass]="['core-user-profile-handler', npHandler.class]" (click)="handlerClicked($event, npHandler)" [hidden]="npHandler.hidden" title="{{ npHandler.title | translate }}">
<ion-icon *ngIf="npHandler.icon" [name]="npHandler.icon" item-start></ion-icon>
<core-icon *ngIf="npHandler.icon" [name]="npHandler.icon" item-start></core-icon>
<h2>{{ npHandler.title | translate }}</h2>
</a>
<ion-item *ngIf="actionHandlers && actionHandlers.length">
<button *ngFor="let actHandler of actionHandlers" ion-button block outline [ngClass]="['core-user-profile-handler', actHandler.class]" (click)="handlerClicked($event, actHandler)" [hidden]="actHandler.hidden" title="{{ actHandler.title | translate }}" icon-start [disabled]="actHandler.spinner">
<ion-icon *ngIf="actHandler.icon" [name]="actHandler.icon" start></ion-icon>
<core-icon *ngIf="actHandler.icon" [name]="actHandler.icon" start></core-icon>
<span>{{ actHandler.title | translate }}</span>
<ion-spinner *ngIf="actHandler.spinner"></ion-spinner>
</button>

View File

@ -5,7 +5,6 @@
// roboto, and noto sans fonts
$font-path: "../assets/fonts";
// The app direction is used to include
// rtl styles in your app. For more info, please see:
// http://ionicframework.com/docs/theming/rtl-support/
@ -236,4 +235,8 @@ $core-question-state-incorrect-color: $red-light !default;
-ms-transition: $where $time ease-in-out;
-o-transition: $where $time ease-in-out;
transition: $where $time ease-in-out;
}
}
// Font Awesome
$fa-font-path: $font-path;
@import "font-awesome";