import { Direction , Directionality } from '@angular/cdk/bidi' ; import { DOCUMENT } from '@angular/common' ; import { ChangeDetectionStrategy , ChangeDetectorRef , Component , Inject , Input , isDevMode , NgZone , OnDestroy , OnInit , Optional } from '@angular/core' ; import { Subject } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { Layout , SettingsService } from '@delon/theme' ; import { copy } from '@delon/util/browser' ; import { InputBoolean , ZoneOutside } from '@delon/util/decorator' ; import { deepCopy , LazyService } from '@delon/util/other' ; import type { NzSafeAny } from 'ng-zorro-antd/core/types' ; import { NzMessageService } from 'ng-zorro-antd/message' ; import { ALAINDEFAULTVAR , DEFAULT_COLORS , DEFAULT_VARS } from './setting-drawer.types' ; @ Component ( { selector : 'setting-drawer' , templateUrl : './setting-drawer.component.html' , host : { '[class.setting-drawer]' : 'true' , '[class.setting-drawer-rtl]' : `dir === 'rtl'` } , changeDetection : ChangeDetectionStrategy . OnPush } ) export class SettingDrawerComponent implements OnInit , OnDestroy { @ Input ( ) @ InputBoolean ( ) autoApplyColor = true ; @ Input ( ) compilingText = 'Compiling...' ; @ Input ( ) devTips = `When the color can't be switched, you need to run it once: npm run color-less` ; private loadedLess = false ; private destroy$ = new Subject < void > ( ) ; dir : Direction = 'ltr' ; isDev = isDevMode ( ) ; collapse = false ; get layout ( ) : Layout { return this . settingSrv . layout ; } data : NzSafeAny = { } ; color : string ; colors = DEFAULT_COLORS ; constructor ( private cdr , private msg , private settingSrv , private lazy , private ngZone , @ Inject ( DOCUMENT ) private doc , @ Optional ( ) private directionality ) { this . color = this . cachedData [ '@primary-color' ] || this . DEFAULT_PRIMARY ; this . resetData ( this . cachedData , false ) ; } private get cachedData ( ) : { [ key ] : NzSafeAny ; } { return this . settingSrv . layout [ ALAINDEFAULTVAR ] || { } ; } private get DEFAULT_PRIMARY ( ) : string { return DEFAULT_VARS [ 'primary-color' ] . default ; } ngOnInit ( ) { this . dir = this . directionality . value ; this . directionality . change ?. pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( direction ) => { this . dir = direction ; } ) ; if ( this . autoApplyColor && this . color !== this . DEFAULT_PRIMARY ) { this . changeColor ( this . color ) ; this . runLess ( ) ; } } @ ZoneOutside ( ) private async loadLess ( ) { if ( this . loadedLess ) { return Promise . resolve ( ) ; } return this . lazy . loadStyle ( './assets/color.less' , 'stylesheet/less' ) . then ( ( ) => { const lessConfigNode = this . doc . createElement ( 'script' ) ; lessConfigNode . innerHTML = `
          window.less = {
            async: true,
            env: 'production',
            javascriptEnabled: true
          };
        ` ; this . doc . body . appendChild ( lessConfigNode ) ; } ) . then ( ( ) => this . lazy . loadScript ( 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js' ) ) . then ( ( ) => { this . loadedLess = true ; } ) ; } private genVars ( ) { const { data , color , validKeys } = this ; const vars = { [ `@primary-color` ] : color } ; validKeys . filter ( key => key !== 'primary-color' ) . forEach ( key => ( vars [ `@${ key }` ] = data [ key ] . value ) ) ; this . setLayout ( ALAINDEFAULTVAR , vars ) ; return vars ; } @ ZoneOutside ( ) private runLess ( ) { const { ngZone , msg , cdr } = this ; const msgId = msg . loading ( this . compilingText , { nzDuration : 0 } ) . messageId ; setTimeout ( ( ) => { this . loadLess ( ) . then ( ( ) => { ( window as NzSafeAny ) . less . modifyVars ( this . genVars ( ) ) . then ( ( ) => { msg . success ( '成功' ) ; msg . remove ( msgId ) ; ngZone . run ( ( ) => cdr . detectChanges ( ) ) ; } ) ; } ) ; } , 200 ) ; } toggle ( ) { this . collapse = ! this . collapse ; } changeColor ( color ) { this . color = color ; Object . keys ( DEFAULT_VARS ) . filter ( key => DEFAULT_VARS [ key ] . default === '@primary-color' ) . forEach ( key => delete this . cachedData [ `@${ key }` ] ) ; this . resetData ( this . cachedData , false ) ; } setLayout ( name , value ) { this . settingSrv . setLayout ( name , value ) ; } private resetData ( nowData ? , run = true ) { nowData = nowData || { } ; const data = deepCopy ( DEFAULT_VARS ) ; Object . keys ( data ) . forEach ( key => { const value = nowData ! [ `@${ key }` ] || data [ key ] . default || '' ; data [ key ] . value = value === `@primary-color` ? this . color : value ; } ) ; this . data = data ; if ( run ) { this . cdr . detectChanges ( ) ; this . runLess ( ) ; } } private get validKeys ( ) : string [ ] { return Object . keys ( this . data ) . filter ( key => this . data [ key ] . value !== this . data [ key ] . default ) ; } apply ( ) { this . runLess ( ) ; } reset ( ) { this . color = this . DEFAULT_PRIMARY ; this . settingSrv . setLayout ( ALAINDEFAULTVAR , { } ) ; this . resetData ( { } ) ; } copyVar ( ) { const vars = this . genVars ( ) ; const copyContent = Object . keys ( vars ) . map ( key => `${ key }: ${ vars [ key ] };` ) . join ( '\n' ) ; copy ( copyContent ) ; this . msg . success ( 'Copy success' ) ; } ngOnDestroy ( ) { this . destroy$ . next ( ) ; this . destroy$ . complete ( ) ; } }