sync 0428

This commit is contained in:
Park Byung Eun 2020-04-28 22:25:53 +09:00
parent 6a0f008457
commit 4f42fc5c2d
64 changed files with 5324 additions and 4287 deletions

4410
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,7 @@
"@ucap/ng-ui": "~0.0.4", "@ucap/ng-ui": "~0.0.4",
"@ucap/ng-ui-organization": "~0.0.2", "@ucap/ng-ui-organization": "~0.0.2",
"@ucap/ng-ui-authentication": "~0.0.16", "@ucap/ng-ui-authentication": "~0.0.16",
"@ucap/ng-ui-group": "~0.0.3", "@ucap/ng-ui-group": "~0.0.4",
"@ucap/ng-ui-skin-default": "~0.0.1", "@ucap/ng-ui-skin-default": "~0.0.1",
"@ucap/pi": "~0.0.5", "@ucap/pi": "~0.0.5",
"@ucap/protocol": "~0.0.17", "@ucap/protocol": "~0.0.17",
@ -97,7 +97,7 @@
"@ucap/protocol-sync": "~0.0.4", "@ucap/protocol-sync": "~0.0.4",
"@ucap/protocol-umg": "~0.0.5", "@ucap/protocol-umg": "~0.0.5",
"@ucap/web-socket": "~0.0.10", "@ucap/web-socket": "~0.0.10",
"@ucap/web-storage": "~0.0.5", "@ucap/web-storage": "~0.0.7",
"autolinker": "^3.13.0", "autolinker": "^3.13.0",
"axios": "^0.19.2", "axios": "^0.19.2",
"classlist.js": "^1.1.20150312", "classlist.js": "^1.1.20150312",

View File

@ -16,164 +16,32 @@ $typography: mat-typography-config(
// Setup the typography // Setup the typography
@include angular-material-typography($typography); @include angular-material-typography($typography);
@mixin components-theme($theme) {
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Define the default theme // @ Define theme --LG RED
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$lgRed-app-primary: mat-palette($lg-red);
$lgRed-app-accent: mat-palette($lg-red, A200, A100, A400);
// Define the primary, accent and warn palettes // The warn palette is optional (defaults to red).
$default-primary-palette: mat-palette($mat-indigo); $lgRed-app-warn: mat-palette($lg-red);
$default-accent-palette: mat-palette($mat-light-blue, 600, 400, 700);
$default-warn-palette: mat-palette($mat-red);
// Create the Material theme object // Create the theme object (a Sass map containing all of the palettes).
$theme: mat-light-theme( $lgRed-app-theme: mat-light-theme(
$default-primary-palette, $lgRed-app-primary,
$default-accent-palette, $lgRed-app-accent,
$default-warn-palette $lgRed-app-warn
); );
// Add ".theme-default" class to the body to activate this theme. // Include theme styles for core and each component used in your app.
// Class name must start with "theme-" !!! // Alternatively, you can import and @include the theme mixins for each component
/*body.theme-default { // that you are using.
// Create an Angular Material theme from the $theme map @include angular-material-theme($lgRed-app-theme);
@include angular-material-theme($theme);
// Apply the theme to the user components // Apply the theme to the user components
@include components-theme($theme); /*
@include ucap-material-theme($theme); @include components-theme($lgRed-app-theme);
}*/ */
@include ucap-material-theme($lgRed-app-theme);
// -----------------------------------------------------------------------------------------------------
// @ Define a blue-gray dark theme
// -----------------------------------------------------------------------------------------------------
// Define the primary, accent and warn palettes
$blue-gray-dark-theme-primary-palette: mat-palette($mat-blue);
$blue-gray-dark-theme-accent-palette: mat-palette($mat-blue-gray);
$blue-gray-dark-theme-warn-palette: mat-palette($mat-red);
// Create the Material theme object
$blue-gray-dark-theme: mat-dark-theme(
$blue-gray-dark-theme-primary-palette,
$blue-gray-dark-theme-accent-palette,
$blue-gray-dark-theme-warn-palette
);
// Add ".theme-blue-gray-dark" class to the body to activate this theme.
// Class name must start with "theme-" !!!
body.theme-blue-gray-dark {
// Generate the Angular Material theme
@include angular-material-theme($blue-gray-dark-theme);
// Apply the theme to the user components
@include components-theme($blue-gray-dark-theme);
}
// -----------------------------------------------------------------------------------------------------
// @ Define a pink dark theme
// -----------------------------------------------------------------------------------------------------
// Define the primary, accent and warn palettes
$pink-dark-theme-primary-palette: mat-palette($mat-pink);
$pink-dark-theme-accent-palette: mat-palette($mat-pink);
$pink-dark-theme-warn-palette: mat-palette($mat-red);
// Create the Material theme object
$pink-dark-theme: mat-dark-theme(
$pink-dark-theme-primary-palette,
$pink-dark-theme-accent-palette,
$pink-dark-theme-warn-palette
);
// Add ".theme-pink-dark" class to the body to activate this theme.
// Class name must start with "theme-" !!!
body.theme-pink-dark {
// Generate the Angular Material theme
@include angular-material-theme($pink-dark-theme);
// Apply the theme to the user components
@include components-theme($pink-dark-theme);
}
// -----------------------------------------------------------------------------------------------------
// @ Define a pink light theme --LG RED 변경 예정(샘플링)
// -----------------------------------------------------------------------------------------------------
// Define the primary, accent and warn palettes
$lgRed-light-theme-primary-palette: mat-palette($mat-grey, 800);
$lgRed-light-theme-accent-palette: mat-palette($lg-red, 400);
$lgRed-light-theme-warn-palette: mat-palette($mat-cyan);
// Create the Material theme object
$lgRed-light-theme: mat-light-theme(
$lgRed-light-theme-primary-palette,
$lgRed-light-theme-accent-palette,
$lgRed-light-theme-warn-palette
);
// Add ".theme-pink-dark" class to the body to activate this theme.
// Class name must start with "theme-" !!!
body.theme-lgRed {
// Generate the Angular Material theme
@include angular-material-theme($lgRed-light-theme);
// Apply the theme to the user components
@include components-theme($lgRed-light-theme);
@include ucap-material-theme($lgRed-light-theme);
}
// -----------------------------------------------------------------------------------------------------
//aqua-blue-daesang
// -----------------------------------------------------------------------------------------------------
$aquaBlue-light-theme-primary-palette: mat-palette($daesang-grey, 900);
$aquaBlue-theme-accent-palette: mat-palette($aquaBlue-daesang);
$aquaBlue-theme-warn-palette: mat-palette($mat-orange);
// Create the Material theme object
$aquaBlue-light-theme: mat-light-theme(
$aquaBlue-light-theme-primary-palette,
$aquaBlue-theme-accent-palette,
$aquaBlue-theme-warn-palette
);
// Add ".theme-pink-dark" class to the body to activate this theme.
// Class name must start with "theme-" !!!
body.theme-default {
// Generate the Angular Material theme
@include angular-material-theme($aquaBlue-light-theme);
// Apply the theme to the user components
@include components-theme($aquaBlue-light-theme);
@include ucap-material-theme($aquaBlue-light-theme);
}
// -----------------------------------------------------------------------------------------------------
// @ Define a red theme --LF 변경 예정(샘플링)
// -----------------------------------------------------------------------------------------------------
// Define the primary, accent and warn palettes
$lfRed-light-theme-primary-palette: mat-palette($lf-blue-grey, 800);
$lfRed-light-theme-accent-palette: mat-palette($lf-red, 400);
$lfRed-light-theme-warn-palette: mat-palette($lf-amber);
// Create the Material theme object
$lfRed-light-theme: mat-light-theme(
$lfRed-light-theme-primary-palette,
$lfRed-light-theme-accent-palette,
$lfRed-light-theme-warn-palette
);
// Add ".theme-pink-dark" class to the body to activate this theme.
// Class name must start with "theme-" !!!
body.theme-lfRed {
// Generate the Angular Material theme
@include angular-material-theme($lfRed-light-theme);
// Apply the theme to the user components
@include components-theme($lfRed-light-theme);
@include ucap-material-theme($lfRed-light-theme);
}

View File

@ -12,6 +12,7 @@ import {
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { LogService } from '@ucap/ng-logger';
import { PiService } from '@ucap/ng-pi'; import { PiService } from '@ucap/ng-pi';
import { LoginActions } from '@ucap/ng-store-authentication'; import { LoginActions } from '@ucap/ng-store-authentication';
@ -26,7 +27,8 @@ export class AppAuthenticationGuard implements CanActivate {
private piService: PiService, private piService: PiService,
private appAuthenticationService: AppAuthenticationService, private appAuthenticationService: AppAuthenticationService,
private store: Store<any>, private store: Store<any>,
private router: Router private router: Router,
private logService: LogService
) {} ) {}
canActivate( canActivate(
@ -38,11 +40,19 @@ export class AppAuthenticationGuard implements CanActivate {
| Observable<boolean | UrlTree> | Observable<boolean | UrlTree>
| Promise<boolean | UrlTree> { | Promise<boolean | UrlTree> {
return new Promise<boolean | UrlTree>((resolve, reject) => { return new Promise<boolean | UrlTree>((resolve, reject) => {
if (this.appAuthenticationService.loggedIn()) { const loggedIn = this.appAuthenticationService.loggedIn();
if (loggedIn) {
resolve(true); resolve(true);
} else { return;
}
const userStore = this.appAuthenticationService.useAutoLogin(); const userStore = this.appAuthenticationService.useAutoLogin();
if (!!userStore) { if (!userStore) {
this.router.navigateByUrl('/account/login');
resolve(false);
return;
}
const loginSession = this.appAuthenticationService.getLoginSession(); const loginSession = this.appAuthenticationService.getLoginSession();
const onWebLoginFailure = (error: any) => { const onWebLoginFailure = (error: any) => {
@ -83,14 +93,8 @@ export class AppAuthenticationGuard implements CanActivate {
}, },
(error) => { (error) => {
onWebLoginFailure(error); onWebLoginFailure(error);
}, }
() => {}
); );
} else {
this.router.navigateByUrl('/account/login');
resolve(false);
}
}
}); });
} }
} }

View File

@ -1,4 +1,14 @@
<div class="login-page-container" fxLayout="row"> <div class="login-container">
<app-sections-account-login
[companyGroupCode]="companyGroupCode"
[fixedCompanyCode]="fixedCompanyCode"
[userStore]="userStore"
[useRememberMe]="useRememberMe"
[useAutoLogin]="useAutoLogin"
></app-sections-account-login>
</div>
<!-- <div class="login-page-container" fxLayout="row">
<div fxFlex="1 1 auto">Login</div> <div fxFlex="1 1 auto">Login</div>
<div class="login-section-container"> <div class="login-section-container">
<app-sections-account-login <app-sections-account-login
@ -9,4 +19,4 @@
[useAutoLogin]="useAutoLogin" [useAutoLogin]="useAutoLogin"
></app-sections-account-login> ></app-sections-account-login>
</div> </div>
</div> </div> -->

View File

@ -1,6 +1,61 @@
.login-page-container { @import '../../../../assets/scss/components';
.login-section-container {
width: 400px; .login-container {
margin: 40px; width: 100%;
} min-height: 100vh;
background-color: $bg-gray;
background-image: url(../../../../assets/images/bg/bg_login_circle_square01.svg),
url(../../../../assets/images/bg/bg_login_circle_stroke01.svg),
url(../../../../assets/images/bg/bg_login_circle01.svg),
url(../../../../assets/images/bg/bg_login_circle03.svg),
url(../../../../assets/images/bg/bg_login_circle_diagonal01.svg),
url(../../../../assets/images/bg/bg_login_circle_square02.svg),
url(../../../../assets/images/bg/bg_login_circle04.svg),
url(../../../../assets/images/bg/bg_login_circle05.svg),
url(../../../../assets/images/bg/bg_login_circle06.svg),
url(../../../../assets/images/bg/bg_login_circle07.svg),
url(../../../../assets/images/bg/bg_login_circle08.svg),
url(../../../../assets/images/bg/bg_login_circle_diagonal02.svg),
url(../../../../assets/images/bg/bg_login_circle_diagonal03.svg),
url(../../../../assets/images/bg/bg_login_circle_stroke02.svg),
url(../../../../assets/images/bg/bg_login_circle_stroke03.svg),
url(../../../../assets/images/bg/bg_login_circle_stroke04.svg),
url(../../../../assets/images/bg/bg_login_circle_stroke05.svg),
url(../../../../assets/images/bg/bg_login_polygon01.svg),
url(../../../../assets/images/bg/bg_login_polygon02.svg);
background-repeat: no-repeat;
background-position: unquote($login-bg-w * 323 + '%')
unquote($login-bg-h * 179 + '%'),
unquote($login-bg-w * -147 + '%') unquote($login-bg-h * 18 + '%'),
unquote($login-bg-w * 285 + '%') unquote($login-bg-h * 226 + '%'),
unquote($login-bg-w * 1235 + '%') unquote($login-bg-h * -101 + '%'),
unquote($login-bg-w * 1397 + '%') unquote($login-bg-h * 163 + '%'),
unquote($login-bg-w * 1569 + '%') unquote($login-bg-h * 580 + '%'),
unquote($login-bg-w * 426 + '%') unquote($login-bg-h * 293 + '%'),
unquote($login-bg-w * 1531 + '%') unquote($login-bg-h * 250 + '%'),
unquote($login-bg-w * 1774 + '%') unquote($login-bg-h * 166 + '%'),
unquote($login-bg-w * 1362 + '%') unquote($login-bg-h * 673 + '%'),
unquote($login-bg-w * 152 + '%') unquote($login-bg-h * 730 + '%'),
unquote($login-bg-w * 286 + '%') unquote($login-bg-h * 719 + '%'),
unquote($login-bg-w * 683 + '%') unquote($login-bg-h * 593 + '%'),
unquote($login-bg-w * 498 + '%') unquote($login-bg-h * 453 + '%'),
unquote($login-bg-w * 1709 + '%') unquote($login-bg-h * 599 + '%'),
unquote($login-bg-w * 1395 + '%') unquote($login-bg-h * 989 + '%'),
unquote(100 + $login-bg-w * 89 + '%') unquote(100 + $login-bg-h * 137 + '%'),
unquote($login-bg-w * 90 + '%') unquote($login-bg-h * 463 + '%'),
unquote($login-bg-w * 549 + '%') unquote($login-bg-h * 874 + '%');
background-size: unquote($login-bg-w * 79 + '%'),
unquote($login-bg-w * 333 + '%'), unquote($login-bg-w * 84 + '%'),
unquote($login-bg-w * 172 + '%'), unquote($login-bg-w * 210 + '%'),
unquote($login-bg-w * 94 + '%'), unquote($login-bg-w * 44 + '%'),
unquote($login-bg-w * 118 + '%'), unquote($login-bg-w * 52 + '%'),
unquote($login-bg-w * 70 + '%'), unquote($login-bg-w * 172 + '%'),
unquote($login-bg-w * 82 + '%'), unquote($login-bg-w * 135 + '%'),
unquote($login-bg-w * 102 + '%'), unquote($login-bg-w * 130 + '%'),
unquote($login-bg-w * 184 + '%'), unquote($login-bg-w * 370 + '%'),
unquote($login-bg-w * 122 + '%'), unquote($login-bg-w * 75 + '%');
padding-top: 5%;
box-sizing: border-box;
display: flex;
flex-direction: column;
} }

View File

@ -6,6 +6,8 @@ import { environment } from '@environments';
import { UserStore } from '@app/models/user-store'; import { UserStore } from '@app/models/user-store';
import { AppKey } from '@app/types/app-key.type'; import { AppKey } from '@app/types/app-key.type';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-pages-account-login', selector: 'app-pages-account-login',
@ -23,14 +25,25 @@ export class LoginPageComponent implements OnInit, OnDestroy {
readonly fixedCompanyCode = environment.companyConfig.fixedCompanyCode; readonly fixedCompanyCode = environment.companyConfig.fixedCompanyCode;
private ngOnDestroySubject = new Subject<boolean>();
constructor(private localStorageService: LocalStorageService) {} constructor(private localStorageService: LocalStorageService) {}
ngOnInit(): void { ngOnInit(): void {
this.userStore = this.localStorageService.encGet<UserStore>( this.ngOnDestroySubject = new Subject<boolean>();
this.localStorageService
.encGet$<UserStore>(
AppKey.UserStore, AppKey.UserStore,
environment.productConfig.localEncriptionKey environment.productConfig.localEncriptionKey
); )
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe((userStore) => (this.userStore = userStore));
} }
ngOnDestroy(): void {} ngOnDestroy(): void {
if (!!this.ngOnDestroySubject) {
this.ngOnDestroySubject.complete();
}
}
} }

View File

@ -13,25 +13,13 @@ import { QueryParams } from '../types/params.type';
styleUrls: ['./sidenav.page.component.scss'] styleUrls: ['./sidenav.page.component.scss']
}) })
export class SidenavPageComponent implements OnInit, OnDestroy { export class SidenavPageComponent implements OnInit, OnDestroy {
private queryParamsSubscription: Subscription;
constructor( constructor(
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private router: Router, private router: Router,
private logService: LogService private logService: LogService
) {} ) {}
ngOnInit(): void { ngOnInit(): void {}
this.queryParamsSubscription = this.activatedRoute.queryParams.subscribe(
(params: Params) => {
console.log('SidenavPageComponent', params[QueryParams.ID]);
}
);
}
ngOnDestroy(): void { ngOnDestroy(): void {}
if (!!this.queryParamsSubscription) {
this.queryParamsSubscription.unsubscribe();
}
}
} }

View File

@ -1,5 +1,5 @@
import { Observable, forkJoin, Subject } from 'rxjs'; import { Observable, forkJoin, Subject } from 'rxjs';
import { take, filter, map, takeUntil } from 'rxjs/operators'; import { take, takeUntil } from 'rxjs/operators';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { import {
@ -13,7 +13,6 @@ import { Store } from '@ngrx/store';
import { StatusCode } from '@ucap/api'; import { StatusCode } from '@ucap/api';
import { LogService } from '@ucap/ng-logger'; import { LogService } from '@ucap/ng-logger';
import { SessionStorageService } from '@ucap/ng-web-storage';
import { PublicApiService } from '@ucap/ng-api-public'; import { PublicApiService } from '@ucap/ng-api-public';
import { ExternalApiService } from '@ucap/ng-api-external'; import { ExternalApiService } from '@ucap/ng-api-external';
import { ProtocolService } from '@ucap/ng-protocol'; import { ProtocolService } from '@ucap/ng-protocol';
@ -22,7 +21,6 @@ import { CompanyActions } from '@ucap/ng-store-organization';
import { ConfigurationActions } from '@ucap/ng-store-authentication'; import { ConfigurationActions } from '@ucap/ng-store-authentication';
import { AppAuthenticationService } from '@app/services/app-authentication.service'; import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { AppKey } from '@app/types/app-key.type';
import { LoginSession } from '@app/models/login-session'; import { LoginSession } from '@app/models/login-session';
@Injectable() @Injectable()
@ -32,7 +30,6 @@ export class AppSessionResolver implements Resolve<void> {
private externalApiService: ExternalApiService, private externalApiService: ExternalApiService,
private protocolService: ProtocolService, private protocolService: ProtocolService,
private store: Store<any>, private store: Store<any>,
private sessionStorageService: SessionStorageService,
private appAuthenticationService: AppAuthenticationService, private appAuthenticationService: AppAuthenticationService,
private logService: LogService private logService: LogService
) {} ) {}
@ -44,7 +41,6 @@ export class AppSessionResolver implements Resolve<void> {
return new Promise<void>(async (resolve, reject) => { return new Promise<void>(async (resolve, reject) => {
try { try {
const loginSession = this.appAuthenticationService.getLoginSession(); const loginSession = this.appAuthenticationService.getLoginSession();
if (loginSession.alive) { if (loginSession.alive) {
resolve(); resolve();
return; return;
@ -115,18 +111,15 @@ export class AppSessionResolver implements Resolve<void> {
}) })
); );
const destroy$ = new Subject<boolean>(); const destroySubject = new Subject<boolean>();
this.sessionStorageService.changed$ this.appAuthenticationService
.pipe( .getLoginSession$()
takeUntil(destroy$), .pipe(takeUntil(destroySubject))
filter((param) => AppKey.LoginSession === param.key),
map((param) => param.value)
)
.subscribe( .subscribe(
(v) => { (v) => {
if ((v as LoginSession).alive) { if ((v as LoginSession).alive) {
destroy$.next(true); destroySubject.next(true);
destroy$.unsubscribe(); destroySubject.complete();
resolve(); resolve();
} }
}, },

View File

@ -10,6 +10,24 @@ import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
import { AuthenticationUiModule } from '@ucap/ng-ui-authentication'; import { AuthenticationUiModule } from '@ucap/ng-ui-authentication';
import { COMPONENTS } from './components'; import { COMPONENTS } from './components';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSliderModule } from '@angular/material/slider';
import { MatTabsModule } from '@angular/material/tabs';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatFormFieldModule } from '@angular/material/form-field';
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({ @NgModule({
imports: [ imports: [
@ -17,7 +35,28 @@ import { COMPONENTS } from './components';
FlexLayoutModule, FlexLayoutModule,
MatCheckboxModule, MatCheckboxModule,
I18nModule, I18nModule,
AuthenticationUiModule AuthenticationUiModule,
ReactiveFormsModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatDatepickerModule,
MatDialogModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatCheckboxModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatTabsModule,
MatTooltipModule,
MatToolbarModule,
MatFormFieldModule,
MatSelectModule
], ],
exports: [...COMPONENTS], exports: [...COMPONENTS],
declarations: [...COMPONENTS], declarations: [...COMPONENTS],

View File

@ -0,0 +1,126 @@
<div class="login-box">
<ng-content select="[ucapAuthenticationLogin='header']"></ng-content>
<div class="login-content">
<form name="loginForm" [formGroup]="loginForm" novalidate>
<mat-form-field
[style.display]="!!fixedCompanyCode ? 'none' : 'block'"
class="login-company"
appearance="none"
>
<mat-select
[formControl]="companyCodeFormControl"
[value]="companyCode || fixedCompanyCode"
class="login-input-area login-select-form"
>
<mat-option
*ngFor="let company of companyList"
[value]="company.companyCode"
>{{ company.companyName }}
</mat-option>
</mat-select>
</mat-form-field>
<div class="login-input-area idpass-type">
<mat-form-field
class="login-idpass-txt"
appearance="none"
floatLabel=""
>
<!-- <mat-label>{{ 'login.fields.loginId' | ucapI18n }}</mat-label> -->
<input
matInput
[formControl]="loginIdFormControl"
placeholder="{{ 'login.fields.loginId' | ucapI18n }}"
/>
</mat-form-field>
</div>
<div class="login-input-area idpass-type pass-type">
<mat-form-field class="login-idpass-txt" appearance="none">
<!-- <mat-label>{{ 'login.fields.loginPw' | ucapI18n }}</mat-label> -->
<input
matInput
type="password"
[formControl]="loginPwFormControl"
placeholder="{{ 'login.fields.loginPw' | ucapI18n }}"
#loginPw
/>
</mat-form-field>
</div>
<div class="error-container">
<mat-error
*ngIf="
companyCodeFormControl.dirty &&
companyCodeFormControl.invalid &&
companyCodeFormControl.hasError('required')
"
>
{{ 'login.errors.requireCompany' | ucapI18n }}
</mat-error>
<mat-error
*ngIf="
loginIdFormControl.dirty &&
loginIdFormControl.invalid &&
loginIdFormControl.hasError('required')
"
>
{{ 'login.errors.requireLoginId' | ucapI18n }}
</mat-error>
<mat-error
*ngIf="
loginPwFormControl.dirty &&
loginPwFormControl.invalid &&
loginPwFormControl.hasError('required')
"
>
{{ 'login.errors.requireLoginPw' | ucapI18n }}
</mat-error>
<mat-error *ngIf="loginFailed">
{{ 'login.errors.failed' | ucapI18n }}
</mat-error>
</div>
<button
mat-raised-button
class="login-input-submit"
aria-label="LOG IN"
[disabled]="
loginForm.invalid ||
disable ||
(!!loginTry && !!loginTry.remainTimeForNextTry)
"
(click)="onClickLogin()"
>
<ng-container
*ngIf="!processing && (!loginTry || !loginTry.remainTimeForNextTry)"
>
{{ 'login.labels.doLogin' | ucapI18n }}
</ng-container>
<ng-container *ngIf="!!loginTry && !!loginTry.remainTimeForNextTry">
{{ 'login.errors.attemptsExceeded' | ucapI18n }}
(
{{
moment
.utc(
moment
.duration(loginTry.remainTimeForNextTry, 'seconds')
.asMilliseconds()
)
.format('mm:ss')
}}
)
</ng-container>
<mat-spinner
*ngIf="processing && (!loginTry || !loginTry.remainTimeForNextTry)"
>
</mat-spinner>
</button>
</form>
<ng-content select="[ucapAuthenticationLogin='footer']"></ng-content>
</div>
</div>

View File

@ -0,0 +1,160 @@
@import '../../../../../assets/scss/components';
.login-box {
@extend %clearfix;
padding: 0 0 45px;
width: 420px;
margin: auto;
text-align: center;
flex-basis: auto;
align-items: center;
.logo-img {
display: block;
text-align: center;
img {
margin-bottom: 7px;
vertical-align: top;
@include screen(mid) {
width: 120px;
}
@include screen(xs) {
width: 100px;
margin-bottom: 6px;
}
}
}
@extend %guideline;
.login-content {
@extend %guideline2; //Guide Line2
margin: 30px auto 0;
.login-input-area {
border: 1px solid #cccccc;
border-radius: 2px;
width: 100%;
max-width: 420px;
min-width: 150px;
height: 60px;
background-color: $white;
margin-top: 10px;
&.login-select-form {
height: 60px;
line-height: 60px;
padding: 0 16px;
@include screen(mid) {
height: 50px;
line-height: 50px;
}
@include screen(xs) {
height: 42px;
line-height: 42px;
}
}
&:first-of-type {
margin-top: 0px;
}
&.idpass-type {
padding-left: 50px;
position: relative;
&::before {
font-family: 'material Icons';
font-size: 24px;
text-align: center;
line-height: 60px;
content: 'perm_identity';
display: block;
position: absolute;
top: 0;
left: 16px;
@include screen(mid) {
line-height: 50px;
}
@include screen(xs) {
line-height: 42px;
}
}
&.pass-type {
&::before {
content: 'https';
}
}
.login-idpass-txt {
width: 368px;
height: 60px;
line-height: 60px;
font-size: 14px;
@include screen(mid) {
width: 358 - 60 + px;
height: 50px;
line-height: 50px;
font-size: 14px;
}
@include screen(xs) {
width: 308 - 60 + px;
font-size: 14px;
height: 42px;
line-height: 42px;
}
input {
font-size: 18px;
line-height: 58px;
margin-top: 0;
vertical-align: top;
background-color: $white;
padding: 0 10px 0 5px;
@include screen(mid) {
font-size: 16px;
line-height: 48px;
}
@include screen(xs) {
font-size: 14px;
line-height: 40px;
}
}
}
}
@include screen(mid) {
margin-top: 8px;
}
}
.login-input-submit {
width: 100%;
height: 60px;
background-color: $black;
border-radius: 2px;
color: $white;
font-size: 20px;
@include font-family($font-semibold);
border: 0;
margin-top: 12px;
font-weight: 600;
cursor: pointer;
@include screen(mid) {
margin-top: 8px;
font-size: 16px;
height: 50px;
}
@include screen(xs) {
font-size: 14px;
height: 42px;
}
}
@include screen(mid) {
margin-top: 23px;
width: 350px;
.login-input-area {
height: 50px;
}
}
@include screen(xs) {
margin-top: 23px;
width: 300px;
.login-input-area {
height: 42px;
}
}
}
}
.login-company {
width: 100%;
}

View File

@ -0,0 +1,92 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ChangeDetectorRef } from '@angular/core';
import { I18nService, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
import { AuthenticationUiModule } from '../authentication-ui.module';
import { MatSelectModule } from '@angular/material/select';
import { Company } from '@ucap/api-external';
import { LogService } from '@ucap/ng-logger';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
describe('ui::authentication::LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
CommonModule,
ReactiveFormsModule,
MatButtonModule,
MatCheckboxModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatProgressSpinnerModule,
MatSelectModule
],
providers: [
AuthenticationUiModule,
// { provide: FormBuilder, useValue: new FormBuilder() },
// { provide: ChangeDetectorRef, useValue: ChangeDetectorRef },
{ provide: I18nService, useValue: new I18nService(new LogService({})) },
{
provide: UCAP_I18N_NAMESPACE,
useValue: 'authentication'
}
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
component.companyList = [
{ companyName: 'LG CNS', companyCode: 'GUC100' },
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
] as Company[];
component.loginId = 'test';
component.companyCode = 'GUC100';
fixture.detectChanges();
component.ngOnInit();
expect(component).toBeTruthy();
});
it('login', (done) => {
component.companyList = [
{ companyName: 'LG CNS', companyCode: 'GUC100' },
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
] as Company[];
component.loginId = 'test';
component.companyCode = 'GUC100';
component.ngOnInit();
component.login.subscribe((value) => {
console.log(value);
done();
});
component.onClickLogin();
});
});

View File

@ -0,0 +1,110 @@
import moment from 'moment';
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef,
ChangeDetectorRef
} from '@angular/core';
import {
FormGroup,
FormBuilder,
Validators,
FormControl,
ValidatorFn
} from '@angular/forms';
import { Company } from '@ucap/api-external';
import { LoginTry } from '@ucap/pi';
@Component({
selector: 'ucap-authentication-login-local',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
@Input()
companyList: Company[];
@Input()
fixedCompanyCode: string;
@Input()
companyCode: string;
@Input()
loginId: string;
@Input()
disable = false;
@Input()
processing = false;
@Input()
loginTry: LoginTry;
@Output()
login = new EventEmitter<{
companyCode: string;
loginId: string;
loginPw: string;
notValid: () => void;
}>();
@ViewChild('loginPw', { static: true }) loginPwElementRef: ElementRef;
loginForm: FormGroup;
companyCodeFormControl = new FormControl('');
loginIdFormControl = new FormControl('');
loginPwFormControl = new FormControl('');
loginFailed = false;
moment = moment;
constructor(
private formBuilder: FormBuilder,
private changeDetectorRef: ChangeDetectorRef
) {}
ngOnInit() {
const companyCodeValidators: ValidatorFn[] = [Validators.required];
this.companyCodeFormControl.setValidators(companyCodeValidators);
if (!!this.fixedCompanyCode) {
this.companyCodeFormControl.setValue(this.fixedCompanyCode);
}
if (!!this.companyCode) {
this.companyCodeFormControl.setValue(this.companyCode);
}
const loginIdValidators: ValidatorFn[] = [Validators.required];
this.loginIdFormControl.setValidators(loginIdValidators);
if (!!this.loginId) {
this.loginIdFormControl.setValue(this.loginId);
}
const loginPwValidators: ValidatorFn[] = [Validators.required];
this.loginPwFormControl.setValidators(loginPwValidators);
this.loginForm = this.formBuilder.group({
companyCodeFormControl: this.companyCodeFormControl,
loginIdFormControl: this.loginIdFormControl,
loginPwFormControl: this.loginPwFormControl
});
this.changeDetectorRef.detectChanges();
}
onClickLogin() {
this.login.emit({
companyCode: this.loginForm.get('companyCodeFormControl').value,
loginId: this.loginForm.get('loginIdFormControl').value,
loginPw: this.loginForm.get('loginPwFormControl').value,
notValid: () => {
this.loginFailed = true;
this.loginPwElementRef.nativeElement.focus();
}
});
}
}

View File

@ -1,3 +1,4 @@
import { LoginSectionComponent } from './login.section.component'; import { LoginSectionComponent } from './login.section.component';
import { LoginComponent } from './component-ui/login.component';
export const COMPONENTS = [LoginSectionComponent]; export const COMPONENTS = [LoginSectionComponent, LoginComponent];

View File

@ -1,4 +1,4 @@
<ucap-authentication-login <ucap-authentication-login-local
[companyList]="companyList" [companyList]="companyList"
[fixedCompanyCode]="fixedCompanyCode" [fixedCompanyCode]="fixedCompanyCode"
[companyCode]="userStore?.companyCode" [companyCode]="userStore?.companyCode"
@ -8,33 +8,30 @@
[loginTry]="loginTry" [loginTry]="loginTry"
(login)="onLogin($event)" (login)="onLogin($event)"
> >
<div <div ucapAuthenticationLogin="header">
ucapAuthenticationLogin="header" <div class="logo-img">
style="background-image: url(./assets/images/logo/bg_logo_login.png);" <img src="../../../assets/images/logo_140.png" alt="" />
>
{{ 'login.labels.instructionsOfLogin' | ucapI18n }}
</div> </div>
<h1>Welcome to Messenger</h1>
</div>
<div ucapAuthenticationLogin="footer"> <div ucapAuthenticationLogin="footer">
<div <div class="login-chk-area">
class="remember-forgot-password" <div>
fxLayout="row"
fxLayout.xs="column"
fxLayoutAlign="space-between center"
>
<mat-checkbox <mat-checkbox
#chkUseRememberMe #chkUseRememberMe
*ngIf="useRememberMe" *ngIf="useRememberMe"
class="remember-me"
aria-label="Remember Me" aria-label="Remember Me"
[checked]="!!userStore && userStore.rememberMe" [checked]="!!userStore && userStore.rememberMe"
> >
{{ 'login.labels.rememberMe' | ucapI18n }} {{ 'login.labels.rememberMe' | ucapI18n }}
</mat-checkbox> </mat-checkbox>
</div>
<div>
<mat-checkbox <mat-checkbox
#chkUseAutoLogin #chkUseAutoLogin
*ngIf="useAutoLogin" *ngIf="useAutoLogin"
class="auto-login"
aria-label="Auto Login" aria-label="Auto Login"
[checked]=" [checked]="
!!userStore && !!userStore &&
@ -46,23 +43,21 @@
{{ 'login.labels.autoLogin' | ucapI18n }} {{ 'login.labels.autoLogin' | ucapI18n }}
</mat-checkbox> </mat-checkbox>
</div> </div>
<div class="register" fxLayout="column" fxLayoutAlign="center center">
<button
class="link btn-login-forgot"
(click)="onClickForgotPassword('ko')"
>
Forgot Password? KO
</button>
<button
class="link btn-login-forgot"
(click)="onClickForgotPassword('en')"
>
Forgot Password? EN
</button>
</div> </div>
<div class="login-pass-info">
<div class="policy bg-primary-light"> <ul>
<a class="link">개인정보 처리방침</a> <li>
<a href="">{{ 'login.labels.forgotPassword' | ucapI18n }}</a>
</li>
<li>
<a href="" class="fir-pass">{{
'login.labels.resetPassword' | ucapI18n
}}</a>
</li>
</ul>
</div>
<div class="login-button-area">
<button type="button">{{ 'login.labels.NotesOnUse' | ucapI18n }}</button>
</div> </div>
</div> </div>
</ucap-authentication-login> </ucap-authentication-login-local>

View File

@ -0,0 +1,111 @@
@import '../../../../assets/scss/components';
h1 {
@include font-family($font-light);
font-size: 24px;
text-align: center;
color: $txt-color01;
font-weight: 600;
line-height: 1.2;
@include screen(mid) {
font-size: 19px;
}
@include screen(xs) {
font-size: 14px;
}
}
.login-chk-area {
margin-top: 6px;
font-size: 13px;
text-align: left;
@include screen(xs) {
font-size: 12px;
}
}
.login-pass-info {
overflow: hidden;
margin-top: 83px;
ul {
display: flex;
justify-content: center;
li {
height: 24px;
position: relative;
display: inline-flex;
align-items: center;
padding: 0 12% 0 8%;
&::before {
content: '';
height: 11px;
width: 1px;
display: flex;
background-color: $gray-re4a;
position: absolute;
top: 6.5px;
left: 0;
}
&:first-child {
padding-left: 0;
&::before {
display: none;
}
}
&:last-child {
padding-right: 0;
}
a {
line-height: 24px;
font-size: 12px;
color: $gray-re4a;
padding-left: 34px;
position: relative;
white-space: nowrap;
&::before {
font-family: 'material Icons';
font-size: 18px;
text-align: center;
content: 'search';
color: $white;
display: block;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: $black;
position: absolute;
top: 0;
left: 0;
}
&.fir-pass {
&::before {
content: 'sync';
}
}
}
}
}
}
.login-button-area {
margin-top: 14px;
@include screen(xs) {
margin-top: 20px;
}
button {
border: 0;
margin: 0;
width: 100%;
height: 46px;
border-radius: 4px;
background-color: #e0e3e7;
font-size: 12px;
color: $gray-re4a;
cursor: pointer;
@include screen(mid) {
height: 38px;
}
@include screen(xs) {
height: 34px;
}
}
}

View File

@ -1,5 +1,5 @@
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { take, filter } from 'rxjs/operators'; import { take, takeUntil } from 'rxjs/operators';
import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core';
@ -56,8 +56,7 @@ export class LoginSectionComponent implements OnInit, OnDestroy {
loginProcessing = false; loginProcessing = false;
loginTry: LoginTry; loginTry: LoginTry;
private companyListSubscription: Subscription; private ngOnDestroySubject = new Subject<boolean>();
private loginTrySubscription: Subscription;
constructor( constructor(
private piService: PiService, private piService: PiService,
@ -70,9 +69,17 @@ export class LoginSectionComponent implements OnInit, OnDestroy {
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.loginSession = this.appAuthenticationService.getLoginSession(); this.ngOnDestroySubject = new Subject<boolean>();
this.loginTry = this.sessionStorageService.get<LoginTry>(AppKey.LoginTry); this.appAuthenticationService
.getLoginSession$()
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe((loginSession) => (this.loginSession = loginSession));
this.sessionStorageService
.get$<LoginTry>(AppKey.LoginTry)
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe((loginTry) => (this.loginTry = loginTry));
this.protocolService.disconnect(); this.protocolService.disconnect();
@ -82,25 +89,19 @@ export class LoginSectionComponent implements OnInit, OnDestroy {
}) })
); );
this.companyListSubscription = this.store this.store
.pipe(select(CompanySelector.companyList)) .pipe(
takeUntil(this.ngOnDestroySubject),
select(CompanySelector.companyList)
)
.subscribe((companyList) => { .subscribe((companyList) => {
this.companyList = companyList; this.companyList = companyList;
}); });
this.loginTrySubscription = this.sessionStorageService.changed$
.pipe(filter((param) => AppKey.LoginTry === param.key))
.subscribe((param) => {
this.loginTry = param.value as LoginTry;
});
} }
ngOnDestroy(): void { ngOnDestroy(): void {
if (!!this.companyListSubscription) { if (!!this.ngOnDestroySubject) {
this.companyListSubscription.unsubscribe(); this.ngOnDestroySubject.complete();
}
if (!!this.loginTrySubscription) {
this.loginTrySubscription.unsubscribe();
} }
} }

View File

@ -1,3 +1,37 @@
<div fxFlexFill class="list-container"> <div fxFlexFill class="list-container">
<ucap-group-expansion-list></ucap-group-expansion-list> <ucap-group-expansion
[displayOrder]="displayOrder"
[profile]="loginRes?.userInfo"
[favorites]="favorites"
[groupBuddies]="groupBuddies"
>
<ng-template ucapGroupExpansionNode let-node>
<ucap-organization-profile-list-item></ucap-organization-profile-list-item>
</ng-template>
<ng-template ucapGroupExpansionFavoriteHeader let-node>
<span class="header-favorite">
<span class="title-name ellipsis">즐겨찾기</span>
<span class="text-accent-color number">{{
node.node.children?.length
}}</span>
</span>
</ng-template>
<ng-template ucapGroupExpansionBuddyHeader let-node>
<span class="header-buddy">
<span class="title-name ellipsis">버디</span>
<span class="text-accent-color number">{{
node.node.children?.length
}}</span>
</span>
</ng-template>
<ng-template ucapGroupExpansionDefaultHeader let-node>
<span class="header-default">
<span class="title-name ellipsis">기본</span>
<span class="text-accent-color number">{{
node.node.children?.length
}}</span>
</span>
</ng-template>
</ucap-group-expansion>
</div> </div>

View File

@ -1,12 +1,45 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Observable, Subject, combineLatest } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import {
Component,
OnInit,
OnDestroy,
ChangeDetectionStrategy,
ChangeDetectorRef
} from '@angular/core';
import { Store, select } from '@ngrx/store';
import { LogService } from '@ucap/ng-logger';
import { import {
VirtualScrollStrategy, VirtualScrollStrategy,
FixedSizeVirtualScrollStrategy, FixedSizeVirtualScrollStrategy,
VIRTUAL_SCROLL_STRATEGY VIRTUAL_SCROLL_STRATEGY,
CdkVirtualScrollViewport
} from '@angular/cdk/scrolling'; } from '@angular/cdk/scrolling';
import { VersionInfo2Response } from '@ucap/api-public';
import { Company } from '@ucap/api-external';
import { LoginResponse } from '@ucap/protocol-authentication';
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';
import { LogService } from '@ucap/ng-logger';
import { NodeType } from '@ucap/ng-ui-group';
import { SessionStorageService } from '@ucap/ng-web-storage';
import { LoginSelector } from '@ucap/ng-store-authentication';
import { CompanySelector } from '@ucap/ng-store-organization';
import { BuddySelector, GroupSelector } from '@ucap/ng-store-group';
import { AppAuthenticationService } from '@app/services/app-authentication.service';
import { AppKey } from '@app/types/app-key.type';
import { LoginSession } from '@app/models/login-session';
export class GroupVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
constructor() {
super(60, 150, 200); // (itemSize, minBufferPx, maxBufferPx)
}
}
@Component({ @Component({
selector: 'app-sections-group-list', selector: 'app-sections-group-list',
templateUrl: './list.section.component.html', templateUrl: './list.section.component.html',
@ -14,14 +47,127 @@ import {
providers: [ providers: [
{ {
provide: VIRTUAL_SCROLL_STRATEGY, provide: VIRTUAL_SCROLL_STRATEGY,
useValue: new FixedSizeVirtualScrollStrategy(60, 3, 3) useClass: GroupVirtualScrollStrategy
} }
] ],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListSectionComponent implements OnInit, OnDestroy { export class ListSectionComponent implements OnInit, OnDestroy {
constructor(private logService: LogService) {} loginSession: LoginSession;
versionInfo2Res: VersionInfo2Response;
loginRes: LoginResponse;
companyList: Company[];
ngOnInit(): void {} displayOrder: NodeType[] = [
NodeType.Profile,
NodeType.Favorite,
NodeType.Buddy,
NodeType.Default
];
ngOnDestroy(): void {} profile: UserInfo;
favorites: UserInfo[];
groupBuddies: { group: GroupDetailData; buddyList: UserInfo[] }[];
private ngOnDestroySubject = new Subject<boolean>();
constructor(
private appAuthenticationService: AppAuthenticationService,
private sessionStorageService: SessionStorageService,
private store: Store<any>,
private changeDetectorRef: ChangeDetectorRef,
private logService: LogService
) {}
ngOnInit(): void {
this.ngOnDestroySubject = new Subject<boolean>();
this.sessionStorageService
.get$<VersionInfo2Response>(AppKey.VerInfoResponse)
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe(
(versionInfo2Response) => (this.versionInfo2Res = versionInfo2Response)
);
this.appAuthenticationService
.getLoginSession$()
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe((loginSession) => (this.loginSession = loginSession));
this.store
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
.subscribe((loginRes) => {
this.loginRes = loginRes;
});
this.store
.pipe(
takeUntil(this.ngOnDestroySubject),
select(CompanySelector.companyList)
)
.subscribe((companyList) => {
this.companyList = companyList;
});
combineLatest([
this.store.pipe(select(BuddySelector.buddies)),
this.store.pipe(select(GroupSelector.groups))
])
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe(([buddies, groups]) => {
buddies = buddies || [];
groups = groups || [];
const favorites = buddies
.filter((buddy) => buddy.isFavorit)
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
if (!!favorites && 0 < favorites.length) {
this.favorites = favorites;
this.changeDetectorRef.markForCheck();
}
const tempOrder: GroupDetailData[] = [];
let defaultGroup: GroupDetailData;
const buddyGroup: GroupDetailData[] = [];
groups.forEach((group) => {
if (0 === group.seq) {
defaultGroup = group;
} else {
buddyGroup.push(group);
}
});
tempOrder.push(
...buddyGroup.sort((a, b) =>
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
)
);
if (!!defaultGroup) {
tempOrder.push(defaultGroup);
}
groups = tempOrder;
if (!!groups && 0 < groups.length) {
this.groupBuddies = [];
for (const group of groups) {
this.groupBuddies.push({
group,
buddyList: buddies.filter((buddy) => {
return -1 < group.userSeqs.indexOf(String(buddy.seq));
})
});
}
this.changeDetectorRef.detectChanges();
}
});
}
ngOnDestroy(): void {
if (!!this.ngOnDestroySubject) {
this.ngOnDestroySubject.complete();
}
}
} }

View File

@ -0,0 +1,31 @@
import { Observable, Subject } from 'rxjs';
import {
VirtualScrollStrategy,
CdkVirtualScrollViewport
} from '@angular/cdk/scrolling';
import { distinctUntilChanged } from 'rxjs/operators';
export class GroupVirtualScrollStrategy implements VirtualScrollStrategy {
scrolledIndexChange: Observable<number>;
private indexSubject = new Subject<number>();
private viewport: CdkVirtualScrollViewport | null = null;
constructor() {
this.scrolledIndexChange = this.indexSubject.pipe(distinctUntilChanged());
}
attach(viewport: CdkVirtualScrollViewport): void {
this.viewport = viewport;
}
detach(): void {
this.indexSubject.complete();
this.viewport = null;
}
onContentScrolled(): void {}
onDataLengthChanged(): void {}
onContentRendered(): void {}
onRenderedOffsetChanged(): void {}
scrollToIndex(index: number, behavior: ScrollBehavior): void {}
}

View File

@ -7,6 +7,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n'; import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
import { GroupUiModule } from '@ucap/ng-ui-group'; import { GroupUiModule } from '@ucap/ng-ui-group';
import { COMPONENTS } from './components'; import { COMPONENTS } from './components';
@ -17,6 +18,7 @@ import { COMPONENTS } from './components';
FlexLayoutModule, FlexLayoutModule,
MatCheckboxModule, MatCheckboxModule,
I18nModule, I18nModule,
OrganizationUiModule,
GroupUiModule GroupUiModule
], ],
exports: [...COMPONENTS], exports: [...COMPONENTS],

View File

@ -1,7 +1,10 @@
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { take, concatMap, map } from 'rxjs/operators';
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { LocaleCode } from '@ucap/core'; import { LocaleCode } from '@ucap/core';
import { PasswordUtil } from '@ucap/pi'; import { PasswordUtil } from '@ucap/pi';
@ -23,8 +26,6 @@ import { UserStore } from '@app/models/user-store';
import { AppKey } from '@app/types/app-key.type'; import { AppKey } from '@app/types/app-key.type';
import { environment } from '@environments'; import { environment } from '@environments';
import { take, concatMap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -40,16 +41,22 @@ export class AppAuthenticationService {
) {} ) {}
getUserStore(): UserStore { getUserStore(): UserStore {
const userStore = this.localStorageService.encGet<UserStore>( return this.localStorageService.encGet<UserStore>(
AppKey.UserStore, AppKey.UserStore,
environment.productConfig.localEncriptionKey environment.productConfig.localEncriptionKey
); );
}
return userStore; getUserStore$(): Observable<UserStore> {
return this.localStorageService.encGet$<UserStore>(
AppKey.UserStore,
environment.productConfig.localEncriptionKey
);
} }
setUserStore(userStore: UserStore) { setUserStore(userStore: UserStore) {
const oldUserStore = this.getUserStore(); const oldUserStore = this.getUserStore();
this.localStorageService.encSet<UserStore>( this.localStorageService.encSet<UserStore>(
AppKey.UserStore, AppKey.UserStore,
{ {
@ -61,11 +68,11 @@ export class AppAuthenticationService {
} }
getLoginSession(): LoginSession { getLoginSession(): LoginSession {
const loginSession = this.sessionStorageService.get<LoginSession>( return this.sessionStorageService.get<LoginSession>(AppKey.LoginSession);
AppKey.LoginSession }
);
return loginSession; getLoginSession$(): Observable<LoginSession> {
return this.sessionStorageService.get$<LoginSession>(AppKey.LoginSession);
} }
setLoginSession(loginSession: LoginSession) { setLoginSession(loginSession: LoginSession) {
@ -81,9 +88,14 @@ export class AppAuthenticationService {
return !!loginSession && !!loginSession.loginId; return !!loginSession && !!loginSession.loginId;
} }
useAutoLogin(): UserStore | null { loggedIn$(): Observable<boolean> {
const userStore = this.getUserStore(); return this.getLoginSession$().pipe(
map((loginSession) => !!loginSession && !!loginSession.loginId)
);
}
useAutoLogin(): UserStore {
const userStore = this.getUserStore();
return !!userStore && return !!userStore &&
!!userStore.settings && !!userStore.settings &&
!!userStore.settings.general && !!userStore.settings.general &&
@ -92,6 +104,19 @@ export class AppAuthenticationService {
: null; : null;
} }
useAutoLogin$(): Observable<UserStore> {
return this.getUserStore$().pipe(
map((userStore) =>
!!userStore &&
!!userStore.settings &&
!!userStore.settings.general &&
userStore.settings.general.autoLogin
? userStore
: null
)
);
}
async postWebLogin( async postWebLogin(
loginSession: LoginSession, loginSession: LoginSession,
rememberMe: boolean, rememberMe: boolean,
@ -166,6 +191,7 @@ export class AppAuthenticationService {
loginSession: LoginSession; loginSession: LoginSession;
}>(async (resolve, reject) => { }>(async (resolve, reject) => {
const loginSession = this.getLoginSession(); const loginSession = this.getLoginSession();
const networkInfo = await this.nativeService.getNetworkInfo(); const networkInfo = await this.nativeService.getNetworkInfo();
const localIp = const localIp =
!!networkInfo && 0 < networkInfo.length && !!networkInfo[0].ip !!networkInfo && 0 < networkInfo.length && !!networkInfo[0].ip
@ -232,7 +258,6 @@ export class AppAuthenticationService {
this.sessionStorageService.remove(AppKey.AuthResponse); this.sessionStorageService.remove(AppKey.AuthResponse);
let userStore = this.getUserStore(); let userStore = this.getUserStore();
if (!!userStore) { if (!!userStore) {
userStore = { userStore = {
...userStore, ...userStore,

View File

@ -17,6 +17,7 @@ import { LoginActions } from '@ucap/ng-store-authentication';
import { environment } from '@environments'; import { environment } from '@environments';
import { AppAuthenticationService } from './app-authentication.service'; import { AppAuthenticationService } from './app-authentication.service';
import { take } from 'rxjs/operators';
@Injectable() @Injectable()
export class AppService { export class AppService {

View File

@ -1,5 +1,5 @@
import { interval, timer } from 'rxjs'; import { interval, timer } from 'rxjs';
import { map, exhaustMap, tap, takeUntil } from 'rxjs/operators'; import { map, exhaustMap, tap, takeUntil, take } from 'rxjs/operators';
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';

View File

@ -4,7 +4,10 @@
"doLogin": "Login", "doLogin": "Login",
"rememberMe": "Remember me", "rememberMe": "Remember me",
"autoLogin": "Auto login", "autoLogin": "Auto login",
"instructionsOfLogin": "LOGIN TO YOUR ACCOUNT" "instructionsOfLogin": "LOGIN TO YOUR ACCOUNT",
"forgotPassword": "Forgot Password",
"resetPassword": "Reset Password",
"NotesOnUse": "Notes on use"
}, },
"fields": { "fields": {
"company": "Company", "company": "Company",

View File

@ -4,7 +4,10 @@
"doLogin": "로그인", "doLogin": "로그인",
"rememberMe": "아이디 저장", "rememberMe": "아이디 저장",
"autoLogin": "자동 로그인", "autoLogin": "자동 로그인",
"instructionsOfLogin": "계정에 로그인 하세요." "instructionsOfLogin": "계정에 로그인 하세요.",
"forgotPassword": "비밀번호 찾기",
"resetPassword": "비밀번호 초기화",
"NotesOnUse": "이용시 주의 사항"
}, },
"fields": { "fields": {
"company": "회사명", "company": "회사명",

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="84" height="81.62" viewBox="0 0 84 81.62">
<ellipse id="prefix__bg_login_circle01" cx="42" cy="40.81" rx="42" ry="40.81" style="fill:#dfb4f1;opacity:.522">
<animateTransform attributeName="transform" attributeType="XML" type="scale" from="0" to="1"
additive="sum" begin="3s" dur="6s" fill="auto" repeatCount="indefinite" />
<animate attributeName="opacity" attributeType="CSS" from="0" to="0.522" dur="9s" repeatCount="indefinite" />
</ellipse>
</svg>

After

Width:  |  Height:  |  Size: 518 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="171.56" height="172.12" viewBox="0 0 171.56 172.12">
<ellipse id="prefix__bg_login_circle03" cx="85.78" cy="86.06" rx="85.78" ry="86.06" style="fill:rgba(241,199,199,.6)"/>
</svg>

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="43.18" height="43.18" viewBox="0 0 43.18 43.18">
<circle id="circle_4" cx="21.59" cy="21.59" r="21.59" data-name="circle 4" style="fill:#fedae8"/>
</svg>

After

Width:  |  Height:  |  Size: 205 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="118" height="116" viewBox="0 0 118 116">
<rect id="prefix__bg_login_circle04" width="118" height="116" rx="58" style="fill:rgba(255,204,204,.17)">
<animateTransform attributeName="transform" attributeType="XML" type="scale" from="1" to=".9"
additive="sum" begin=".5s" dur="1s" fill="auto" repeatCount="indefinite"/>
<animate attributeName="opacity" attributeType="CSS" from="1" to=".8" dur="1.5s" repeatCount="indefinite" />
</rect>
</svg>

After

Width:  |  Height:  |  Size: 507 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<circle id="prefix__bg_login_circle05" cx="26" cy="26" r="26" style="fill:rgba(239,223,151,.49)"/>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="70" height="68" viewBox="0 0 70 68">
<ellipse id="prefix__bg_login_circle06" cx="35" cy="34" rx="35" ry="34" style="fill:#f6e4b2"/>
</svg>

After

Width:  |  Height:  |  Size: 190 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="171.56" height="172.12" viewBox="0 0 171.56 172.12">
<ellipse id="prefix__bg_login_circle02" cx="85.78" cy="86.06" rx="85.78" ry="86.06" style="fill:rgba(222,189,209,.59)"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="209.998" height="209.998" viewBox="0 0 209.998 209.998">
<path id="prefix__bg_login_circle_diagonal01" d="M1549 373c-.472 0-.942 0-1.412-.01l111.4-111.472c.007.494.011.987.011 1.482v4.34L1553.407 373zm109.629-91.323q-.288 3.349-.792 6.626l-83.472 83.525q-3.277.505-6.625.8zm-128.969 89.454l127.458-127.539q.486 2.472.849 4.982l-123.323 123.4q-2.514-.359-4.984-.843zm-15.442-4.346l138.543-138.631q.8 2.144 1.5 4.333L1518.553 368.28c-1.453-.465-2.908-.966-4.335-1.495zm138.833-59.73a99.5 99.5 0 0 1-4.341 10.177l-45.421 45.45a99.336 99.336 0 0 1-10.174 4.347zm-152.4 53.5L1646.525 214.6c.7 1.256 1.368 2.533 2.011 3.821l-144.058 144.15q-1.937-.971-3.822-2.013zm-11.988-7.8l150.047-150.143q1.26 1.66 2.454 3.378l-149.118 149.217q-1.718-1.192-3.379-2.451zm-10.562-9.23l151.372-151.469q1.463 1.453 2.865 2.965l-151.27 151.366q-1.508-1.399-2.962-2.861zm-9.179-10.614l149.931-150.026q1.661 1.243 3.273 2.557l-150.639 150.742c-.874-1.071-1.73-2.164-2.56-3.271zm-7.748-12.045l145.628-145.721q1.879 1.024 3.706 2.125l-147.206 147.3q-1.102-1.827-2.123-3.703zm-6.164-13.629l138.158-138.247q2.12.771 4.2 1.634l-140.716 140.808q-.864-2.073-1.637-4.194zm-4.268-15.528l126.895-126.976q2.421.456 4.8 1.029L1451.779 296.51q-.573-2.378-1.032-4.8zM1449 273.658L1559.589 163c1.9.011 3.771.074 5.64.189L1449.2 279.3c-.121-1.87-.186-3.747-.2-5.642zm.452-20.25l89.891-89.948q3.088-.3 6.231-.4l-96.521 96.582q.106-3.142.401-6.234zm5.984-25.785l58.125-58.163q4.245-1.609 8.663-2.836l-69.618 69.663q1.223-4.415 2.832-8.664z" transform="translate(-1449.002 -163.002)" style="fill:rgba(255,204,204,.63)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="81.933" height="81.937" viewBox="0 0 81.933 81.937">
<path id="prefix__bg_login_circle_diagonal02" d="M322.747 850.782l45.03-45.088c.067.642.119 1.289.156 1.939l-43.247 43.3q-.975-.051-1.939-.151zm45.168-38.111q-.075 1.165-.214 2.31l-35.668 35.713q-1.146.14-2.31.217zM316.721 849.7l49.967-50.031c.146.561.279 1.124.4 1.694L318.416 850.1q-.854-.182-1.695-.4zm49.711-28.432q-.454 1.592-1.031 3.129l-23.953 23.984q-1.535.578-3.128 1.035zm-55.042 26.656l53.51-53.582c.205.5.4 1 .588 1.507L312.9 848.511q-.764-.279-1.51-.587zm-4.769-2.339l55.938-56.009c.257.446.5.9.744 1.351l-55.33 55.4q-.683-.358-1.352-.742zm-4.282-2.827l57.386-57.46q.453.6.883 1.213l-57.055 57.128q-.614-.429-1.213-.881zm55.709-5.98a41.22 41.22 0 0 1-4.231 4.237zm-59.542 2.7l57.938-58.012q.516.532 1.012 1.083L299.59 840.49c-.366-.328-.729-.666-1.083-1.009zm-3.4-3.712l57.62-57.694q.579.467 1.14.954l-57.8 57.878c-.326-.369-.646-.75-.957-1.135zm-2.955-4.155l56.416-56.489q.645.4 1.272.822l-56.866 56.939c-.273-.415-.553-.84-.819-1.269zm-2.481-4.63l54.264-54.334q.716.325 1.417.677l-55 55.073q-.351-.697-.679-1.413zm-1.944-5.168l51.038-51.1q.8.239 1.584.509L288.24 823.4q-.271-.785-.512-1.584zm-1.29-5.813l46.509-46.569q.9.131 1.793.3l-48 48.06q-.17-.891-.302-1.791zm-.436-6c0-.229 0-.46.006-.688l40.254-40.306c.246 0 .492-.007.74-.007q.672 0 1.339.021l-42.315 42.37Q286 810.7 286 810zm.931-8.729l31.289-31.329q1.271-.277 2.568-.475l-34.328 34.372q.196-1.299.471-2.568zm4.423-11.543l15.328-15.347a40.864 40.864 0 0 1 4.168-2.077l-21.568 21.6a40.843 40.843 0 0 1 2.073-4.177z" transform="translate(-286 -769)" style="fill:rgba(190,153,229,.59)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="134.288" height="134.32" viewBox="0 0 134.288 134.32">
<path id="prefix__bg_login_circle_diagonal03" d="M746.006 726.983l71.066-71.112c.07 1.2.11 2.4.117 3.617L749.621 727.1q-1.821-.011-3.615-.117zm70.568-57.943q-.309 2.276-.769 4.5l-52.131 52.164q-2.225.46-4.5.772zm-81.65 56.36l80.564-80.615c.235 1.023.447 2.059.634 3.1l-78.1 78.15q-1.564-.281-3.098-.635zm-9.662-3l87.22-87.276q.534 1.346 1.011 2.721l-85.51 85.565q-1.374-.477-2.721-1.01zm86.412-35.784a66.95 66.95 0 0 1-3.926 7.662L784.4 717.635a66.955 66.955 0 0 1-7.659 3.931zm-94.964 31.67l91.656-91.715q.682 1.192 1.316 2.415L719.125 719.6q-1.225-.631-2.415-1.314zm-7.605-5.061l94.2-94.258q.813 1.058 1.584 2.148l-93.634 93.693q-1.093-.77-2.155-1.583zm-6.738-5.928l95.005-95.066q.935.93 1.835 1.9l-94.943 95q-.964-.898-1.897-1.831zm-5.9-6.772l94.133-94.187q1.057.8 2.084 1.648l-94.564 94.623q-.846-1.027-1.649-2.083zm-5.027-7.641l91.512-91.57q1.188.67 2.346 1.386l-92.467 92.53q-.716-1.157-1.386-2.346zm-4.074-8.594l86.992-87.048q1.335.52 2.639 1.093l-88.533 88.595q-.574-1.307-1.093-2.639zm-2.955-9.714l80.234-80.285q1.509.336 2.993.738l-82.487 82.54q-.399-1.482-.735-2.993zm-1.511-11.154l70.6-70.643q1.744.089 3.464.267l-73.794 73.841q-.179-1.72-.27-3.465zm.611-13.282l56.708-56.74q2.086-.3 4.209-.479l-61.393 61.429q.172-2.123.476-4.209zm5.232-17.905l33.574-33.6q3-1.36 6.156-2.427l-42.153 42.184q1.063-3.151 2.423-6.157z" transform="translate(-682.901 -592.779)" style="fill:rgba(255,255,255,.63)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="78.22" height="66.219" viewBox="0 0 78.22 66.219">
<path id="prefix__bg_login_circle_square01" d="M394.97 242.08a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm72-12a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm72-12a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm72-12a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm72-12a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm72-12a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.11 3.11 3.11 3.11 0 0 1-3.11-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11zm-12 0a3.11 3.11 0 1 1 3.109 3.11 3.11 3.11 0 0 1-3.109-3.11z" transform="translate(-322.97 -178.97)" style="fill:#f0bd8f"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="93.85" height="79.439" viewBox="0 0 93.85 79.439">
<path id="prefix__bg_login_circle_square02" d="M1655.56 656.09a3.72 3.72 0 1 1 3.72 3.72 3.72 3.72 0 0 1-3.72-3.72zm-14.4 0a3.73 3.73 0 1 1 3.73 3.72 3.725 3.725 0 0 1-3.73-3.72zm-14.41 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.4 0a3.73 3.73 0 1 1 3.729 3.72 3.724 3.724 0 0 1-3.729-3.72zm-14.41 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.4 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.39 0a3.72 3.72 0 1 1 3.72 3.72 3.72 3.72 0 0 1-3.72-3.72zm86.41-14.39a3.72 3.72 0 1 1 3.72 3.73 3.725 3.725 0 0 1-3.72-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.729 3.73 3.729 3.729 0 0 1-3.729-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.39 0a3.72 3.72 0 1 1 3.72 3.73 3.725 3.725 0 0 1-3.72-3.73zm86.41-14.4a3.72 3.72 0 1 1 3.72 3.73 3.725 3.725 0 0 1-3.72-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.729 3.73 3.729 3.729 0 0 1-3.729-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.729 3.729 0 0 1-3.73-3.73zm-14.39 0a3.72 3.72 0 1 1 3.72 3.73 3.725 3.725 0 0 1-3.72-3.73zm86.41-14.41a3.72 3.72 0 1 1 3.72 3.73 3.726 3.726 0 0 1-3.72-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.731 3.731 0 0 1-3.73-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.729 3.73 3.73 3.73 0 0 1-3.729-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.39 0a3.72 3.72 0 1 1 3.72 3.73 3.726 3.726 0 0 1-3.72-3.73zm86.41-14.41a3.72 3.72 0 1 1 3.72 3.73 3.726 3.726 0 0 1-3.72-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.731 3.731 0 0 1-3.73-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.729 3.73 3.73 3.73 0 0 1-3.729-3.73zm-14.41 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.4 0a3.73 3.73 0 1 1 3.73 3.73 3.73 3.73 0 0 1-3.73-3.73zm-14.39 0a3.72 3.72 0 1 1 3.72 3.73 3.726 3.726 0 0 1-3.72-3.73zm86.41-14.39a3.72 3.72 0 1 1 3.72 3.72 3.72 3.72 0 0 1-3.72-3.72zm-14.4 0a3.73 3.73 0 1 1 3.73 3.72 3.725 3.725 0 0 1-3.73-3.72zm-14.41 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.4 0a3.73 3.73 0 1 1 3.729 3.72 3.724 3.724 0 0 1-3.729-3.72zm-14.41 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.4 0a3.73 3.73 0 1 1 3.73 3.72 3.724 3.724 0 0 1-3.73-3.72zm-14.39 0a3.72 3.72 0 1 1 3.72 3.72 3.72 3.72 0 0 1-3.72-3.72z" transform="translate(-1569.15 -580.37)" style="fill:#eea4d8">
<animateMotion path="M 100 100 L 0 0" begin=".4s" dur="1s" fill="auto" />
<animate attributeName="opacity" attributeType="CSS" from=".72" to="0.3" dur="2s" repeatCount="indefinite" />
</path>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="333" height="331.179" viewBox="0 0 333 331.179">
<path id="prefix__bg_login_circle_stroke01" d="M20 349.59a168.62 168.62 0 0 1-33.555-3.364 166.324 166.324 0 0 1-31.254-9.649 166.8 166.8 0 0 1-28.283-15.267 167.5 167.5 0 0 1-24.642-20.22 166.98 166.98 0 0 1-20.331-24.507 165.32 165.32 0 0 1-15.351-28.128 164.1 164.1 0 0 1-9.7-31.083 166.309 166.309 0 0 1 0-66.744 164.1 164.1 0 0 1 9.7-31.083 165.317 165.317 0 0 1 15.351-28.128A166.98 166.98 0 0 1-97.733 66.91a167.5 167.5 0 0 1 24.641-20.22 166.807 166.807 0 0 1 28.283-15.267 166.33 166.33 0 0 1 31.254-9.649 169.03 169.03 0 0 1 67.111 0 166.331 166.331 0 0 1 31.254 9.649 166.8 166.8 0 0 1 28.282 15.267 167.5 167.5 0 0 1 24.642 20.22 166.979 166.979 0 0 1 20.331 24.507 165.316 165.316 0 0 1 15.351 28.128 164.1 164.1 0 0 1 9.7 31.083 166.311 166.311 0 0 1 0 66.744 164.1 164.1 0 0 1-9.7 31.083 165.32 165.32 0 0 1-15.351 28.128 166.979 166.979 0 0 1-20.331 24.507 167.5 167.5 0 0 1-24.642 20.22 166.8 166.8 0 0 1-28.282 15.267 166.325 166.325 0 0 1-31.254 9.649A168.622 168.622 0 0 1 20 349.59zm0-273.18c-59.11 0-107.2 48.265-107.2 107.59S-39.11 291.59 20 291.59 127.2 243.325 127.2 184 79.11 76.41 20 76.41z" transform="translate(146.5 -18.41)" style="fill:rgba(255,255,255,.8)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="101.551" height="100.26" viewBox="0 0 101.551 100.26">
<path id="prefix__bg_login_circle_stroke04" d="M535.888 483.491a50.547 50.547 0 0 0-1.516-12.3l36.67.045a77.243 77.243 0 0 1 .976 12.3c-.06 48.621-45.526 87.979-101.551 87.91l.033-30.846c36.076.049 65.349-25.521 65.388-57.109z" transform="translate(-470.466 -471.186)" style="fill:rgba(204,204,204,.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 418 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="129.5" height="146.8" viewBox="0 0 129.5 146.8">
<path id="prefix__bg_login_circle_stroke05" d="M1755.623 728a84.209 84.209 0 0 0 1.955 18h-46.813a129.183 129.183 0 0 1-1.265-18c0-71.134 57.979-128.8 129.5-128.8v45.122A83.528 83.528 0 0 0 1755.623 728z" transform="translate(-1709.5 -599.2)" style="fill:rgba(147,197,215,.4)"/>
</svg>

After

Width:  |  Height:  |  Size: 386 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="183.062" height="150.874" viewBox="0 0 183.062 150.874">
<path id="prefix__bg_login_circle_stroke03" d="M1335.743 948.4a64.162 64.162 0 0 0-109.328-67.189l-29.477-18.111c28.714-46.722 89.662-61.447 136.132-32.888s60.864 89.586 32.15 136.308z" transform="translate(-1196.938 -815.644)" style="fill:#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 363 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="370" height="368" viewBox="0 0 370 368">
<path id="prefix__bg_login_circle_stroke02" d="M1824 1217a187.332 187.332 0 0 1-37.284-3.738 184.888 184.888 0 0 1-133.178-108.641 182.345 182.345 0 0 1-10.78-34.539 184.809 184.809 0 0 1 0-74.165 182.467 182.467 0 0 1 27.837-65.794 185.487 185.487 0 0 1 306.81 0 183.311 183.311 0 0 1-22.59 232.984A185.041 185.041 0 0 1 1824 1217zm0-303.539c-65.678 0-119.11 53.625-119.11 119.54s53.433 119.54 119.11 119.54 119.11-53.625 119.11-119.54S1889.678 913.46 1824 913.46z" transform="translate(-1639 -849)" style="fill:rgba(255,255,255,.6)">
<animateMotion path="M 100 100 T 0 0" begin=".8s" dur="1s" fill="auto" />
</path>
</svg>

After

Width:  |  Height:  |  Size: 720 B

View File

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="145.594" height="113.541" viewBox="0 0 121.594 113.541">
<path id="polygon_02" d="M45.545 5.923a4 4 0 0 1 6.91 0l42.036 72.062A4 4 0 0 1 91.036 84H6.964a4 4 0 0 1-3.455-6.015z" data-name="polygon_02" transform="rotate(-159 56.267 48.292)" style="fill:#20af9a;opacity:.26">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="0 50 60"
to="360 50 60"
dur="10s"
repeatCount="indefinite"/>
</path>
</svg>

After

Width:  |  Height:  |  Size: 643 B

View File

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="94.589" height="80.953" viewBox="0 0 74.589 80.953">
<path id="polygon2" d="M30.534 6.014a4 4 0 0 1 6.931 0L64.544 53a4 4 0 0 1-3.466 6H6.922a4 4 0 0 1-3.466-6z" data-name="polygon2" transform="rotate(105.01 31.433 36.247)" style="fill:#f0828c;opacity:.52">
<animateTransform attributeName="transform"
attributeType="XML"
type="rotate"
from="360 30 40"
to="0 30 40"
dur="10s"
repeatCount="indefinite"/>
</path>
</svg>

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,51 @@
@font-face {
font-family: 'LG Smart Bold';
font-display: swap;
src: local(''), url('assets/webfonts/LG_Smart_Bold.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_Bold.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LG Smart Bold';
font-display: swap;
src: local(''),
url('assets/webfonts/LG_Smart_Bold_Italic.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_Bold_Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'LG Smart Light';
font-display: swap;
src: local(''), url('assets/webfonts/LG_Smart_Light.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_Light.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LG Smart Regular';
font-display: swap;
src: local(''), url('assets/webfonts/LG_Smart_Regular.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LG Smart Regular';
font-display: swap;
src: local(''),
url('assets/webfonts/LG_Smart_Regular_Italic.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_Regular_Italic.woff') format('woff');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'LG Smart SemiBold';
font-display: swap;
src: local(''),
url('assets/webfonts/LG_Smart_SemiBold.woff2') format('woff2'),
url('assets/webfonts/LG_Smart_SemiBold.woff') format('woff');
font-weight: normal;
font-style: normal;
}

View File

@ -0,0 +1,11 @@
// Material theming tools
@import '~@angular/material/theming';
// Include core Angular Material styles
@include mat-core();
// Partials
@import 'partials/material-ui';
//creative
@import 'global/default';

View File

@ -1,697 +1,86 @@
@charset 'utf-8'; @charset 'UTF-8';
$win-min-w: 420px;
$win-min-h: 640px; @import '../setting/variables';
html {
height: 100%;
overflow: hidden;
}
body {
position: relative;
width: 100%;
height: 100%;
/*min-width: 1160px;
min-height: 800px;*/
min-width: $win-min-w !important;
min-height: $win-min-h !important;
overflow: hidden;
padding: 0;
margin: 0;
color: #333;
font-family: '나눔고딕', Malgun Gothic, '맑은고딕', Arial, Dotum, '돋움',
Gulim, '굴림';
font-size: 14px;
line-height: 18px !important;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
div,
p,
ol,
ul,
li,
h1, h1,
h2, h2,
h3, h3,
h4, h4,
h5, h5,
h6, h6 {
form, margin: 0;
iframe, }
ul,
ol,
li {
@extend %listreset;
}
div,
p,
strong,
span,
dl, dl,
dt, dt,
dd { dd {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
} }
ul,
ol {
list-style: none;
}
$lg-red: (
50: #ffffff,
100: #fff9fc,
200: #f1e1e5,
/*300: #f06292,*/ 300: #ef4c73,
400: #ec407a,
500: #ed097e,
600: #d81b60,
700: #c2185b,
800: #ad1457,
/*900: #880e4f,*/ 900: #5f2a41,
A100: #ff80ab,
A200: #ff4081,
A400: #ff3399,
A700: #c51162,
B100: #4f4f4f,
B200: #67545b,
G100: #ef4c73,
G900: #352a37,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $light-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $light-primary-text,
A400: $light-primary-text,
A700: $light-primary-text,
B100: $light-primary-text,
G100: $dark-primary-text,
G900: $light-primary-text
)
);
$aquaBlue-daesang: ( *,
50: #f9feff, *::before,
100: #ebfdff, *::after {
200: #a7f3fd, box-sizing: border-box;
300: #4dd0e1,
400: #26c6da,
500: #00bcd4,
600: #00b6d5,
700: #1ea7b9,
800: #0367a6,
900: #024873,
A100: #84ffff,
A200: #18ffff,
A400: #00e5ff,
A700: #06a6c1,
B100: #2d3a4a,
B200: #00b6d5,
G100: #0367a6,
G900: #6dd5ed,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $dark-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $dark-primary-text,
A700: $dark-primary-text,
B100: $light-primary-text,
G100: $dark-primary-text,
G900: $light-primary-text
)
);
$daesang-grey: (
50: #fafafa,
100: #f5f5f5,
200: #eeeeee,
300: #e0e0e0,
400: #bdbdbd,
500: #9e9e9e,
600: #757575,
700: #616161,
800: #424242,
900: #2d3a4a,
A100: #ffffff,
A200: #eeeeee,
A400: #bdbdbd,
A700: #1e2b3a,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $dark-primary-text,
500: $dark-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $dark-primary-text,
A700: $light-primary-text
)
);
$lf-red: (
50: #fffdfd,
100: #fffbfc,
200: #ef9a9a,
300: #e57373,
400: #ef5350,
500: #f44336,
600: #d9232e,
700: #d32f2f,
800: #c62828,
900: #b71c1c,
A100: #ff8a80,
A200: #ff5252,
A400: #ff1744,
A700: #d50000,
B100: #303e48,
B200: #603537,
G100: #ffdca1,
G900: #e2544d,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $dark-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $light-primary-text,
A400: $light-primary-text,
A700: $light-primary-text
)
);
$lf-amber: (
50: #fff8e1,
100: #ffecb3,
200: #fae999,
300: #ffd54f,
400: #ffca28,
500: #ffc107,
600: #ffb300,
700: #ffa000,
800: #ff8f00,
900: #ff6f00,
A100: #ffe57f,
A200: #ffd740,
A400: #ffc400,
A700: #ffab00,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $dark-primary-text,
500: $dark-primary-text,
600: $dark-primary-text,
700: $dark-primary-text,
800: $dark-primary-text,
900: $dark-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $dark-primary-text,
A700: $dark-primary-text
)
);
$lf-blue-grey: (
50: #eceff1,
100: #cfd8dc,
200: #eceef2,
300: #90a4ae,
400: #78909c,
500: #607d8b,
600: #546e7a,
700: #455a64,
800: #303e48,
900: #263238,
A100: #cfd8dc,
A200: #b0bec5,
A400: #78909c,
A700: #455a64,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $light-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $light-primary-text,
A700: $light-primary-text
)
);
@mixin ucap-material-theme($theme) {
@include ucap-core-theme($theme);
} }
@mixin ucap-core-theme($theme) { .blind {
$accent: map-get($theme, accent); font: 0/0 '돋움', dotum;
$warn: map-get($theme, warn);
$primary: map-get($theme, primary);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
$gradient-darkest: mat-color($accent, G900);
$gradient-light: mat-color($accent, G100);
//basic
.bg-primary-darkest {
background: mat-color($primary, 900);
color: mat-color($primary, default-contrast);
}
.bg-primary-dark {
background: mat-color($primary, 900);
color: mat-color($primary, default-contrast);
}
.bg-primary-light {
background: mat-color($primary, 300);
color: mat-color($primary, default-contrast);
}
.bg-primary-color {
background: mat-color($primary);
color: mat-color($primary, default-contrast);
}
.bg-accent-darkest {
background: mat-color($accent, B100);
color: mat-color($primary, default-contrast);
}
.bg-accent-dark {
background: mat-color($accent, 600);
color: mat-color($primary, default-contrast);
&:hover {
background: mat-color($accent, B200);
}
}
.bg-accent-light {
background: mat-color($accent, 300);
color: mat-color($primary, default-contrast);
}
.bg-accent-bright {
background-color: mat-color($accent, 100);
}
.bg-accent-brightest {
background: mat-color($accent, 50);
color: mat-color($primary, $dark-primary-text);
}
.bg-accent-color {
background: mat-color($accent);
color: mat-color($accent, default-contrast);
}
.bg-warn-color {
background-color: mat-color($warn, 300);
}
.bg-warn-darkest {
background-color: mat-color($warn, 600);
}
.text-primary-light {
color: mat-color($primary, 500);
}
.text-primary-color {
color: mat-color($primary);
}
.text-accent-dark {
color: mat-color($accent, 600);
}
.text-accent-darkest {
color: mat-color($accent, 800);
}
.text-accent-color {
color: mat-color($accent);
}
.text-warn-color {
color: mat-color($warn, 800);
}
.border-primary-color {
border-color: 1px solid mat-color($primary);
}
.border-accent-bright {
border-color: mat-color($accent, 300);
}
.border-accent-color {
border-color: 1px solid mat-color($accent);
}
.stroke-accent-darkest {
stroke: mat-color($accent, 800);
}
.border-warn-color {
border: mat-color($warn);
}
.stroke-warn-color {
stroke: mat-color($warn, 900);
}
// sass 정의
.mat-toolbar {
background-color: mat-color($accent, B100);
}
.main-container {
border-color: mat-color($accent, B100);
}
.global-menu {
background-color: mat-color($accent, B100);
} }
.ucap-clickable { // Links
cursor: pointer;
}
.policy {
color: mat-color($accent, B100);
//rgba($color: #000000, $alpha: 0.7);
}
.upload-profile .upload-profile-spinner svg circle {
stroke: inherit;
}
.mat-badge-accent .mat-badge-content,
.weblink .mat-badge-content {
background-color: mat-color($warn, 400);
}
.mat-tab-group.mat-primary .mat-ink-bar,
body.theme-default .mat-tab-nav-bar.mat-primary .mat-ink-bar {
background-color: mat-color($accent, 500);
}
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary {
background-color: mat-color($accent, 300);
cursor: pointer;
.mat-chip-remove {
opacity: 0.4;
width: 20px;
height: 20px;
justify-content: center;
align-self: center;
}
}
.login-form {
.submit-button[ng-reflect-disabled='false'] {
background-color: #333333;
color: #ffffff;
&:hover {
background-color: mat-color($accent, 600);
}
}
}
.load-container .loader:after {
background-color: mat-color($accent, 300);
}
.ps__rail-y {
& > .ps__thumb-y {
margin-right: -2px;
}
}
.cdk-virtual-scroll-orientation-vertical {
.cdk-virtual-scroll-content-wrapper {
width: 100%;
height: 100%;
contain: none;
}
}
.global-menu {
.mat-tab-label[aria-selected='true'] {
.mat-tab-label-content {
.icon-item {
background: mat-color($accent, 600);
}
}
}
}
.mat-form-field-appearance-legacy {
.mat-form-field-label {
color: mat-color($primary);
}
.mat-hint {
color: mat-color($primary);
}
.mat-form-field-underline {
background-color: mat-color($primary);
}
}
.mat-button-toggle-appearance-standard .mat-button-toggle-label-content {
height: 34px;
line-height: 34px;
padding: 0 12px;
}
.app-dialog-full .mat-dialog-container {
overflow: hidden;
padding: 0px;
background-color: rgba($color: #000000, $alpha: 0.7);
box-shadow: none;
border-radius: 0px;
}
.btn-main-float .bg-accent-dark {
background: mat-color($accent, 600);
color: mat-color($primary, default-contrast);
}
.current-head {
display: flex;
justify-content: center;
padding: 0 10px;
background-color: #eeeeee;
background: $gradient-light;
background: -webkit-linear-gradient(
to right,
$gradient-darkest,
$gradient-light
);
background: linear-gradient(to right, $gradient-darkest, $gradient-light);
color: #ffffff;
}
//탭개수에 의한 width 정의
.mat-tab-group {
&.tab_num2 {
.mat-tab-label {
width: 50%;
min-width: 50%;
}
}
&.tab_num3 {
.mat-tab-label {
width: 33%;
min-width: 33%;
}
}
.mat-ink-bar {
opacity: 1;
}
.mat-tab-body-wrapper {
height: 100%;
border: none;
}
}
//쪽지 라디오 버튼 정렬
.message-box {
.mat-radio-label {
.mat-radio-label-content {
padding-left: 4px;
}
}
}
mat-tab-group[vertical] {
display: flex;
flex-direction: row;
.mat-tab-header {
border-bottom: none;
.mat-tab-labels {
display: flex;
flex-direction: column;
align-content: flex-start;
.mat-tab-label {
justify-content: flex-start;
padding: 0;
&[aria-selected='true'] {
opacity: 1;
}
.mat-checkbox {
margin-right: 8px;
}
}
}
}
.mat-ink-bar {
opacity: 0;
}
.mat-tab-body-wrapper {
flex: 1 1 auto;
border-left: 1px solid #dddddd;
padding: 0;
}
}
mat-tab-group[vertical] {
display: flex;
flex-direction: column;
.mat-tab-header {
border-bottom: none;
.mat-tab-labels {
display: flex;
flex-direction: column;
align-content: flex-start;
.mat-tab-label {
min-width: 60px;
padding: 0 5px;
justify-content: center;
}
}
}
}
.mat-form-field-appearance-legacy[inlineEdit] .mat-form-field-underline {
background-color: transparent;
}
app-page-messenger-main mat-drawer-content {
overflow: hidden !important;
}
.mat-tab-labels .cdk-focused {
background-color: transparent !important;
}
.messages .container {
background: mat-color($accent, 50);
}
.profile-img {
.responsive-chats-button:last-child {
background-color: mat-color($accent, B100);
}
}
//대화 말풍선 global 적용
.message-row {
.message-main {
.bubble {
background-color: mat-color($accent, 100);
border: 1px solid mat-color($accent, 200);
overflow: hidden;
.bubble-main {
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-word;
a { a {
color: #0367a6; color: #000;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
&:hover {
color: #000;
text-decoration: underline; text-decoration: underline;
} }
} }
.btn-box {
min-width: 300px; a:not([href]):not([tabindex]) {
@media screen and (max-width: #{$tablet-s-width}) { color: inherit;
min-width: 250px; text-decoration: none;
}
} &:hover {
} color: inherit;
} text-decoration: none;
&.me {
.message-main {
.bubble {
background-color: #ffffff;
border: 1px solid mat-color($primary, 300);
.event-info {
border-radius: 0 0 0 6px;
}
}
} }
&:focus {
outline: 0;
} }
} }
//[s] 번역 html {
.translationForm { font-family: sans-serif;
background-color: mat-color($accent, 200, 0.4); line-height: 1.15;
.select-language { -webkit-text-size-adjust: 100%;
.mat-form-field-wrapper { -ms-text-size-adjust: 100%;
width: 100%; -ms-overflow-style: scrollbar;
line-height: 0.8em; -webkit-tap-highlight-color: rgba($black, 0);
.mat-form-field-infix {
padding: 0.2em 0 0;
}
}
.mat-form-field-underline {
bottom: 0.8em;
}
}
.mat-slide-toggle {
@media screen and (max-width: #{$tablet-s-width}) {
label {
width: 20%;
flex-flow: column;
font-size: 0.8em;
}
}
}
}
.translation-preview {
background-color: mat-color($accent, 900, 0.8);
} }
.tree-has-child { body {
li { margin: 0;
.tree-node-body { @include font-family($font-regular);
background-color: mat-color($accent, 100); font-size: $font-size-base;
border: 1px solid mat-color($accent, 200); line-height: $line-height-base;
} text-align: left;
} background-color: $body-bg;
} overflow-x: hidden;
.mat-calendar-body-selected { input::-ms-clear {
background-color: mat-color($accent); display: none;
}
.list-item {
&.selected {
background-color: mat-color($accent, 100);
border-right: 2px solid mat-color($accent, 800);
}
}
.mat-simple-snackbar-action {
button {
background-color: mat-color($accent, 500);
}
}
.chatroom-search {
.search-form {
border: 2px solid mat-color($accent, B100);
}
.btns {
background-color: mat-color($accent, B100);
}
} }
} }

View File

@ -0,0 +1,687 @@
// Fonts Family
$font-bold: 'LG Smart Bold';
$font-light: 'LG Smart Light';
$font-regular: 'LG Smart Regular';
$font-semibold: 'LG Smart SemiBold';
// Font Info
$font-size-base: 14px !default;
$line-height-base: 1.5 !default;
// Color
$black: #000 !default;
$white: #ffffff !default;
$grayf3-5: #f3f4f5 !default;
$gray-ref0: #f0f0f0 !default;
$gray-re20: #202020 !default;
$gray-re21: #212121 !default;
$gray-re3: #333333 !default;
$gray-re4: #444444 !default;
$gray-re4a: #4a4a4a !default;
$gray-re6: #666666 !default;
$gray-re70: #707070 !default;
$gray-re9: #999999 !default;
$brown: #7f5360 !default;
$lipstick: #e42f66 !default;
$dirty-purple: #5c575a !default;
$rose-pink: #f0828c !default;
$warm-pink: #fd578a !default;
// text-color
$txt-color01: $gray-re6;
// Line Color
// Bg Color
$body-bg: $white !default;
$bg-gray: $grayf3-5;
// Design size
// Screen size
$max-xs: 575;
$min-sm: 576;
$max-sm: 767;
$min-md: 768;
$max-md: 991;
$min-lg: 992;
$max-lg: 1199;
$min-xl: 1200;
$login-bg-w: 100/1920;
$login-bg-h: 100/1080;
// Extend
%clearfix {
*zoom: 1;
&:before,
&:after {
content: ' ';
display: table;
}
&:after {
clear: both;
}
}
%listreset {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
%guideline {
//border: 1px dashed red;
}
%guideline2 {
//border: 1px dotted blue;
}
%height100vh {
height: 100vh;
}
// font-family
@mixin font-family($font, $sytle: normal) {
font-family: $font, Malgun Gothic, '맑은고딕', Arial, Dotum, '돋움', Gulim,
'굴림';
@if ($font == $font-regular) or ($font == $font-bold) {
@if $sytle == italic {
font-style: italic;
} @else if $sytle == normal {
font-style: normal;
}
}
else {
font-style: normal;
}
font-weight: normal;
}
// Screen
@mixin screen($size, $type: max, $pixels: false) {
@if $size == 'xs' {
//Default min size
@media (max-width: $max-xs + px) {
@content;
}
} @else if $size == 'sm' {
@media (min-width: $min-sm + px) and (max-width: $max-sm + px) {
@content;
}
} @else if $size == 'md' {
@media (min-width: $min-md + px) and (max-width: $max-md + px) {
@content;
}
} @else if $size == 'lg' {
@media (min-width: $min-lg + px) and (max-width: $max-lg + px) {
@content;
}
} @else if $size == 'mid' {
//Default mid size
@media (max-width: $max-md + px) {
@content;
}
} @else if $size == 'xl' {
//Default max size
@media (min-width: $min-xl + px) {
@content;
}
} @else if $size == 'landscape' {
@media (orientation: landscape) {
@content;
}
} @else if $size == 'portrait' {
@media (orientation: portrait) {
@content;
}
} @else if $size == 'custom' {
@media ($type + -width: $pixels + px) {
@content;
}
} @else if $size == 'print' {
@media print {
@content;
}
}
}
$lg-red: (
50: #ffffff,
100: #fff9fc,
200: #f1e1e5,
300: #ef4c73,
400: #ec407a,
500: #ed097e,
600: #d81b60,
700: #c2185b,
800: #ad1457,
900: #5f2a41,
A100: #ff80ab,
A200: #ff4081,
A400: #ff3399,
A700: #c51162,
B100: #4f4f4f,
B200: #67545b,
G100: #ef4c73,
G900: #352a37,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $light-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $light-primary-text,
A400: $light-primary-text,
A700: $light-primary-text,
B100: $light-primary-text,
G100: $dark-primary-text,
G900: $light-primary-text
)
);
@mixin ucap-material-theme($theme) {
@include ucap-core-theme($theme);
}
@mixin ucap-core-theme($theme) {
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);
$primary: map-get($theme, primary);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
$gradient-darkest: mat-color($accent, G900);
$gradient-light: mat-color($accent, G100);
//basic
.bg-primary-darkest {
background: mat-color($primary, 900);
color: mat-color($primary, default-contrast);
}
.bg-primary-dark {
background: mat-color($primary, 900);
color: mat-color($primary, default-contrast);
}
.bg-primary-light {
background: mat-color($primary, 300);
color: mat-color($primary, default-contrast);
}
.bg-primary-color {
background: mat-color($primary);
color: mat-color($primary, default-contrast);
}
.bg-accent-darkest {
background: mat-color($accent, 800);
color: mat-color($primary, default-contrast);
}
.bg-accent-dark {
background: mat-color($accent, B200);
color: mat-color($primary, default-contrast);
}
.bg-accent-light {
background: mat-color($accent, 300);
color: mat-color($primary, default-contrast);
}
.bg-accent-bright {
background-color: mat-color($accent, 100);
}
.bg-accent-brightest {
background: mat-color($accent, 50);
color: mat-color($primary, $dark-primary-text);
}
.bg-accent-color {
background: mat-color($accent);
color: mat-color($accent, default-contrast);
}
.bg-warn-color {
background-color: mat-color($warn, 300);
}
.bg-warn-darkest {
background-color: mat-color($warn, 600);
}
.text-primary-light {
color: mat-color($primary, 500);
}
.text-primary-color {
color: mat-color($primary);
}
.text-accent-dark {
color: mat-color($accent, 600);
}
.text-accent-darkest {
color: mat-color($accent, 800);
}
.text-accent-color {
color: mat-color($accent);
}
.text-warn-color {
color: mat-color($warn, 800);
}
.border-primary-color {
border-color: 1px solid mat-color($primary);
}
.border-accent-bright {
border-color: mat-color($accent, 300);
}
.border-accent-color {
border-color: 1px solid mat-color($accent);
}
.stroke-accent-darkest {
stroke: mat-color($accent, 800);
}
.border-warn-color {
border: mat-color($warn);
}
.stroke-warn-color {
stroke: mat-color($warn, 900);
}
// sass 정의
.mat-toolbar {
background-color: mat-color($accent, B100);
}
///// gnb
.gnb .mat-toolbar {
background-color: $gray-ref0;
}
.main-container {
border-color: mat-color($accent, B100);
}
.global-menu {
background-color: mat-color($accent, B100);
}
.ucap-clickable {
cursor: pointer;
}
.policy {
color: mat-color($accent, B100);
}
.mat-badge-accent .mat-badge-content,
.weblink .mat-badge-content {
background-color: mat-color($warn, 400);
}
.mat-tab-group.mat-primary .mat-ink-bar,
body.theme-default .mat-tab-nav-bar.mat-primary .mat-ink-bar {
background-color: mat-color($accent, 500);
}
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary {
background-color: mat-color($accent, 700);
cursor: pointer;
}
.load-container .loader:after {
background-color: mat-color($accent, 300);
}
.global-menu {
.mat-tab-label[aria-selected='true'] {
.mat-tab-label-content {
.icon-item {
background: mat-color($accent, 300);
}
}
}
}
.mat-form-field-appearance-legacy {
.mat-form-field-label {
color: mat-color($primary);
}
.mat-hint {
color: mat-color($primary);
}
.mat-form-field-underline {
background-color: mat-color($primary);
}
}
$pixels-amount: 0;
.mat-form-field-infix {
padding: $pixels-amount;
border-top: $pixels-amount;
}
////login input
.idpass-type {
.mat-form-field-empty {
&.mat-form-field-label {
top: 11px;
}
}
.mat-form-field-can-float {
&.mat-form-field-should-float {
.mat-form-field-label {
top: 11px;
width: 0;
}
}
}
.mat-form-field {
&.mat-focused {
.mat-form-field-label {
opacity: 0;
}
}
}
}
//////////
.mat-button-toggle-appearance-standard .mat-button-toggle-label-content {
height: 34px;
line-height: 34px;
padding: 0 12px;
}
.app-dialog-full .mat-dialog-container {
overflow: hidden;
padding: 0px;
background-color: rgba($color: #000000, $alpha: 0.7);
box-shadow: none;
border-radius: 0px;
}
.btn-main-float .bg-accent-dark {
background: mat-color($accent, 600);
color: mat-color($primary, default-contrast);
}
.current-head {
display: flex;
justify-content: center;
padding: 0 10px;
background-color: #eeeeee;
background: $gradient-light;
background: -webkit-linear-gradient(
to right,
$gradient-darkest,
$gradient-light
);
background: linear-gradient(to right, $gradient-darkest, $gradient-light);
color: #ffffff;
}
//[S]탭개수에 의한 width 정의
.mat-tab-group {
&.tab_num2 {
.mat-tab-label {
width: 50%;
min-width: 50%;
}
}
&.tab_num3 {
.mat-tab-label {
width: 33%;
min-width: 33%;
}
}
.mat-ink-bar {
opacity: 1;
}
.mat-tab-body-wrapper {
height: 100%;
border: none;
}
}
//[E]탭개수에 의한 width 정의
//[S]쪽지 라디오 버튼 정렬
.message-box {
.mat-radio-label {
.mat-radio-label-content {
padding-left: 4px;
}
}
}
//[E]쪽지 라디오 버튼 정렬
//[S]mat-tab-group
/*mat-tab-group {
display: flex;
flex-direction: row;
.mat-tab-header {
width: 100%;
.mat-tab-label-container {
width: 100%;
}
}
}*/
mat-tab-group[vertical] {
display: flex;
flex-direction: column;
.mat-tab-header {
border-bottom: none;
.mat-tab-labels {
display: flex;
flex-direction: column;
align-content: flex-start;
.mat-tab-label {
justify-content: flex-start;
padding: 0;
&[aria-selected='true'] {
opacity: 1;
}
.mat-checkbox {
margin-right: 8px;
}
}
}
}
.mat-ink-bar {
opacity: 0;
}
.mat-tab-body-wrapper {
flex: 1 1 auto;
border-left: 1px solid #dddddd;
padding: 0;
}
}
//설정 general-theme
.theme-list {
.mat-tab-header {
width: 100%;
border: none !important;
.mat-tab-labels {
position: relative;
width: 100%;
flex-direction: row !important;
.mat-tab-label {
width: 140px;
height: 120px;
&.mat-tab-label-active {
opacity: 1;
}
.mat-tab-label-content {
position: relative;
flex-flow: column;
width: 100%;
}
}
}
}
}
//[E]mat-tab-group
nav[mat-tab-nav-bar][vertical] {
display: flex;
flex-direction: row !important;
.mat-tab-links {
display: flex;
flex-direction: column !important;
}
}
.mat-form-field-appearance-legacy[inlineEdit] .mat-form-field-underline {
background-color: transparent;
}
app-page-messenger-main mat-drawer-content {
overflow: hidden !important;
}
.mat-tab-labels .cdk-focused {
background-color: transparent !important;
}
.messages .container {
background: mat-color($accent, 50);
}
.profile-img {
.responsive-chats-button:last-child {
background-color: mat-color($accent, B100);
}
}
//[S]대화 말풍선 global 적용
.message-row {
.message-main {
.bubble {
background-color: mat-color($accent, 100);
border: 1px solid mat-color($accent, 200);
overflow: hidden;
.bubble-main {
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-word;
a {
color: #0367a6;
text-decoration: underline;
}
}
}
}
&.me {
.message-main {
.bubble {
background-color: #ffffff;
border: 1px solid mat-color($primary, 300);
.event-info {
border-radius: 0 0 0 6px;
}
}
}
}
}
//[E]대화 말풍선 global 적용
//[S]스티커
.sticker-selector {
.mat-tab-header {
}
}
//[E]스티커
//[S]번역
.translationForm {
background-color: mat-color($accent, 200, 0.4);
.select-language {
.mat-form-field-wrapper {
width: 100%;
line-height: 0.8em;
.mat-form-field-infix {
padding: 0.2em 0 0;
}
}
.mat-form-field-underline {
bottom: 0.8em;
}
}
}
.translation-preview {
background-color: mat-color($accent, 900, 0.8);
}
//[E] 번역
.tree-has-child {
li {
.tree-node-body {
background-color: mat-color($accent, 100);
border: 1px solid mat-color($accent, 200);
}
}
}
.mat-calendar {
mat-calendar-header {
.mat-calendar-header {
.mat-calendar-controls {
margin: 0;
}
}
}
}
.mat-calendar-body-selected {
background-color: mat-color($accent);
}
.list-item {
&.selected {
background-color: mat-color($accent, 100);
border-right: 2px solid mat-color($accent, 800);
}
}
.mat-simple-snackbar-action {
button {
background-color: mat-color($accent, 500);
}
}
.chatroom-search {
.search-form {
border: 2px solid mat-color($accent, B100);
}
.btns {
background-color: mat-color($accent, B100);
}
}
}
///////////////////////////////////////////////////
/////////////
// Select
@mixin selecCtrl($selec-height, $selec-width) {
.mat-select-value {
height: $selec-height + px;
line-height: $selec-height + px;
}
.mat-form-field {
height: $selec-height + px;
}
.mat-form-field-appearance-legacy .mat-form-field-wrapper {
height: $selec-height + px;
}
.mat-form-field-appearance-legacy .mat-form-field-wrapper {
padding-bottom: 0;
}
.mat-form-field-flex {
height: $selec-height + px;
}
}
//input
@mixin matinputCtrl($selec-height, $selec-width) {
.mat-form-field-appearance-legacy {
.mat-form-field-infix {
padding: 0;
border-top: 0;
width: $selec-width + px;
}
}
.mat-form-field-appearance-legacy {
.mat-form-field-underline {
display: none;
}
}
}
/////////////
////////////////////////////////////////////////////////

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,5 @@
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@import 'assets/scss/fonts';
@import '~perfect-scrollbar/css/perfect-scrollbar.css'; @import '~perfect-scrollbar/css/perfect-scrollbar.css';
@ -6,7 +7,7 @@
@import '~@ucap/ng-ui-skin-default/skin'; @import '~@ucap/ng-ui-skin-default/skin';
@import 'assets/scss/ucap'; @import 'assets/scss/components';
// Import app.theme.scss // Import app.theme.scss
@import 'app/app.theme'; @import 'app/app.theme';