|
|
|
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'; |
|
import { NgIf } from '@angular/common'; |
|
import { Component, computed, input } from '@angular/core'; |
|
import { DomSanitizer } from '@angular/platform-browser'; |
|
import { UiIconLibrary } from './icons-library'; |
|
|
|
/** |
|
* a custom lightweight implementation of fa-icon component. |
|
* https://github.com/FortAwesome/react-fontawesome/issues/232#issuecomment-115 |
|
* https://github.com/FortAwesome/angular-fontawesome/blob/main/src/lib/icon/icon.component.ts |
|
*/ |
|
|
|
@Component({ |
|
standalone: true, |
|
selector: 'ui-icon', |
|
template: ` |
|
<svg *ngIf="icon() let ico" [class]="classList()" |
|
[attr.viewBox]="'0 0 ' + ico.icon[0] + ' ' + ico.icon[1]" |
|
role="img" xmlns="http://www.w3.org/2000/svg" |
|
[innerHTML]="makeSvg(ico)" |
|
></svg> |
|
`, |
|
styles: [` |
|
svg:not(:root).svg-inline--fa, |
|
svg:not(:host).svg-inline--fa { overflow: visible; box-sizing: content-box; } |
|
.svg-inline--fa.fa-fw { width: var(--fa-fw-width, 1.25em);} |
|
.fa-fw { text-align: center; width: 1.25em; } |
|
.svg-inline--fa { display: var(--fa-display, inline-block); height: 1em; overflow: visible; vertical-align: -0.125em; } |
|
.fa-xs { font-size: 0.75em; line-height: 0.08333em; vertical-align: 0.125em; } |
|
.fa-sm { font-size: 0.875em; line-height: 0.07143em; vertical-align: 0.05357em; } |
|
.fa-lg { font-size: 1.25em; line-height: 0.05em; vertical-align: -0.075em; } |
|
.fa-xl { font-size: 1.5em; line-height: 0.04167em; vertical-align: -0.125em; } |
|
.fa-2x { font-size: 2em; } |
|
.fa-3x { font-size: 3em; } |
|
.fa-4x { font-size: 4em; } |
|
.svg-inline--fa.fa-xs { vertical-align: 0em; } |
|
.svg-inline--fa.fa-sm { vertical-align: -0.07143em; } |
|
.svg-inline--fa.fa-lg { vertical-align: -0.2em; } |
|
.svg-inline--fa.fa-xl { vertical-align: -0.25em; } |
|
.svg-inline--fa.fa-2xl { vertical-align: -0.3125em; } |
|
|
|
@keyframes fa-spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
.fa-spin { animation-name: fa-spin; |
|
animation-delay: var(--fa-animation-delay, 0s); |
|
animation-direction: var(--fa-animation-direction, normal); |
|
animation-duration: var(--fa-animation-duration, 2s); |
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite); |
|
animation-timing-function: var(--fa-animation-timing, linear); } |
|
`], |
|
imports: [NgIf], |
|
}) |
|
export class UiIconComponent { |
|
iconInput = input<IconDefinition | string | string[]>(null,{alias:'icon'}) |
|
icon = computed<IconDefinition | null>(()=>{ |
|
const input = this.iconInput(); |
|
if(Array.isArray(input)) return this.iconLib.getIconDefinition(input[0] as any,input[1] as any); |
|
if(typeof input === 'object') return input; |
|
if(typeof input === 'string') return this.iconLib.getIconDefinition('fas',input as any); |
|
return null |
|
}) |
|
size = input<"lg" | "sm" | "1x" | "2x" | "3x" | "4X">("1x") |
|
fixedWidth = input<boolean>(false) |
|
spin = input<boolean>(false) |
|
|
|
classList = computed<string>(()=>{ |
|
let list = 'svg-inline--fa'; |
|
if(this.size()) list += ` fa-${this.size()}` |
|
if(this.fixedWidth()) list += ` fa-fw` |
|
if(this.spin()) list += ` fa-spin` |
|
return list |
|
}) |
|
|
|
constructor(private iconLib:UiIconLibrary, private sanitizer: DomSanitizer) {} |
|
|
|
protected makeSvg(def: IconDefinition) { |
|
const { icon } = def; |
|
if(!Array.isArray(icon)) { |
|
console.log(def) |
|
throw new Error('invalid icon definition!') |
|
} |
|
// const [width, height, ligatures, unicode, svgPathData] = icon; |
|
const svgPathData = icon[4]; |
|
const content = Array.isArray(svgPathData) |
|
? `<g>${svgPathData.map((x) => `<path d="${x}" />`)}</g>` |
|
: `<path fill="currentColor" d="${svgPathData}" />`; |
|
return this.sanitizer.bypassSecurityTrustHtml(content); |
|
} |
|
|
|
} |