Browse Source

login page

features/login
PhamY0601 1 year ago
parent
commit
6736c79c56
27 changed files with 378 additions and 24 deletions
  1. +9
    -1
      package.json
  2. +9
    -0
      sprite.config.json
  3. +13
    -1
      src/app/app-routing.module.ts
  4. +22
    -3
      src/app/app.component.ts
  5. +5
    -0
      src/app/app.module.ts
  6. +15
    -0
      src/app/core/guards/auth.guard.ts
  7. +14
    -0
      src/app/core/guards/unAuth.guard.ts
  8. +1
    -1
      src/app/modules/homepage/hotel-management/hotel-management.component.html
  9. +8
    -8
      src/app/modules/homepage/hotel-management/hotel-management.component.ts
  10. +1
    -1
      src/app/modules/homepage/security-atm-details/security-atm-details.component.ts
  11. +94
    -0
      src/app/modules/session/session.component.html
  12. +5
    -0
      src/app/modules/session/session.component.scss
  13. +21
    -0
      src/app/modules/session/session.component.spec.ts
  14. +72
    -0
      src/app/modules/session/session.component.ts
  15. +32
    -4
      src/app/shared/component/layout/layout.component.html
  16. +1
    -4
      src/app/shared/component/layout/layout.component.scss
  17. +14
    -1
      src/app/shared/component/layout/layout.component.ts
  18. +5
    -0
      src/app/shared/utils/route.utils.ts
  19. BIN
      src/assets/images/login-bg.jpg
  20. BIN
      src/assets/images/login-bg.png
  21. +1
    -0
      src/assets/images/svg/bold--user.svg
  22. +11
    -0
      src/assets/images/svg/outline--eye-slash.svg
  23. +8
    -0
      src/assets/images/svg/outline--eye.svg
  24. +4
    -0
      src/assets/images/svg/outline--logout.svg
  25. +1
    -0
      src/assets/images/svg/sprite/sprite.svg
  26. +4
    -0
      src/styles.scss
  27. +8
    -0
      tailwind.config.js

+ 9
- 1
package.json View File

"test": "ng test", "test": "ng test",
"camera-server": "node dist/lot-web-ui/server/server.js", "camera-server": "node dist/lot-web-ui/server/server.js",
"prettier:write": "prettier --write src", "prettier:write": "prettier --write src",
"prettier:check": "prettier --check src"
"prettier:check": "prettier --check src",
"sprite": "svg-sprite --config sprite.config.json src/assets/images/svg/*.svg"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@asymmetrik/ngx-leaflet": "^16.0.1", "@asymmetrik/ngx-leaflet": "^16.0.1",
"@asymmetrik/ngx-leaflet-markercluster": "^16.0.0", "@asymmetrik/ngx-leaflet-markercluster": "^16.0.0",
"@types/leaflet.markercluster": "^1.5.4", "@types/leaflet.markercluster": "^1.5.4",
"aos": "^2.3.4",
"express": "^4.19.2", "express": "^4.19.2",
"express-ws": "^5.0.2", "express-ws": "^5.0.2",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"moment": "^2.30.1", "moment": "^2.30.1",
"ngx-mqtt": "^17.0.0", "ngx-mqtt": "^17.0.0",
"ngx-toastr": "^17.0.2", "ngx-toastr": "^17.0.2",
"ngx-webstorage": "^12.0.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"rtsp-relay": "^1.8.0", "rtsp-relay": "^1.8.0",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"rxjs-websockets": "^9.0.0", "rxjs-websockets": "^9.0.0",
"svg-sprite": "^2.0.4",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.13.0" "zone.js": "~0.13.0"
}, },
"@angular-devkit/build-angular": "^16.2.14", "@angular-devkit/build-angular": "^16.2.14",
"@angular/cli": "^16.2.14", "@angular/cli": "^16.2.14",
"@angular/compiler-cli": "^16.2.0", "@angular/compiler-cli": "^16.2.0",
"@types/aos": "^3.0.7",
"@types/jasmine": "~4.3.0", "@types/jasmine": "~4.3.0",
"@types/leaflet": "^1.9.12", "@types/leaflet": "^1.9.12",
"autoprefixer": "^10.4.20",
"jasmine-core": "~4.6.0", "jasmine-core": "~4.6.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0", "karma-jasmine-html-reporter": "~2.1.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.14",
"typescript": "~5.1.3" "typescript": "~5.1.3"
} }
} }

+ 9
- 0
sprite.config.json View File

{
"mode": {
"symbol": {
"dest": "src/assets/images/svg/sprite",
"sprite": "sprite.svg",
"prefix": "svg-%s"
}
}
}

+ 13
- 1
src/app/app-routing.module.ts View File

import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { LayoutComponent } from './shared/component/layout/layout.component'; import { LayoutComponent } from './shared/component/layout/layout.component';
import { authGuard } from './core/guards/auth.guard';
import { RouteUtils } from './shared/utils/route.utils';
import { unAuthGuard } from './core/guards/unAuth.guard';


const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: '/homepage', pathMatch: 'full' },
{
path: RouteUtils.Session.LOGIN,
loadComponent: () =>
import('./modules/session/session.component').then(
(m) => m.SessionComponent,
),
canActivate: [unAuthGuard],
},
{ {
path: '', path: '',
component: LayoutComponent, component: LayoutComponent,
canActivate: [authGuard],
children: [ children: [
{ {
path: 'homepage', path: 'homepage',
}, },
], ],
}, },
{ path: '', redirectTo: '/homepage', pathMatch: 'full' },
]; ];


@NgModule({ @NgModule({

+ 22
- 3
src/app/app.component.ts View File

import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MqttClientService } from './shared/services/mqtt-client.service'; import { MqttClientService } from './shared/services/mqtt-client.service';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { filter, Subject } from 'rxjs'; import { filter, Subject } from 'rxjs';
import { TOPIC_GETTING, TOPIC_SETTING } from './app.constants'; import { TOPIC_GETTING, TOPIC_SETTING } from './app.constants';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import * as AOS from 'aos';


@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'], styleUrls: ['./app.component.scss'],
}) })
export class AppComponent implements OnInit {
export class AppComponent implements OnInit, OnDestroy {
title = 'Iot-web-ui'; title = 'Iot-web-ui';
private unsubscribeAll = new Subject(); private unsubscribeAll = new Subject();
isConnected = false; isConnected = false;
constructor(private mqtt$: MqttClientService) {}
constructor(
private mqtt$: MqttClientService,
private matIcon: MatIconRegistry,
private domSanitizer: DomSanitizer,
) {
this.matIcon.addSvgIconSet(
this.domSanitizer.bypassSecurityTrustResourceUrl(
'assets/images/svg/sprite/sprite.svg',
),
);
}


ngOnInit() { ngOnInit() {
this.mqtt$.createConnection(); this.mqtt$.createConnection();
} }
}); });
}); });
AOS.init({ once: true, offset: -10000 });
}

ngOnDestroy() {
this.unsubscribeAll.next('');
this.unsubscribeAll.complete();
} }
} }

+ 5
- 0
src/app/app.module.ts View File

import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { ToastrModule } from 'ngx-toastr'; import { ToastrModule } from 'ngx-toastr';
import { IMqttServiceOptions, MqttModule } from 'ngx-mqtt'; import { IMqttServiceOptions, MqttModule } from 'ngx-mqtt';
import { NgxWebstorageModule } from 'ngx-webstorage';
import { MatIconModule } from '@angular/material/icon';

export const connection: IMqttServiceOptions = { export const connection: IMqttServiceOptions = {
hostname: 'test.mosquitto.org', hostname: 'test.mosquitto.org',
port: 1883, port: 1883,
autoDismiss: true, autoDismiss: true,
}), // ToastrModule added }), // ToastrModule added
MqttModule.forRoot(connection), MqttModule.forRoot(connection),
NgxWebstorageModule.forRoot(),
MatIconModule,
], ],
providers: [], providers: [],
bootstrap: [AppComponent], bootstrap: [AppComponent],

+ 15
- 0
src/app/core/guards/auth.guard.ts View File

import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { LocalStorageService } from 'ngx-webstorage';
import { RouteUtils } from '../../shared/utils/route.utils';

export const authGuard: CanActivateFn = () => {
const localStorage = inject(LocalStorageService);
const token = localStorage.retrieve('token');
if (token) {
return true;
}
const router = inject(Router);
router.navigate(['/', RouteUtils.Session.LOGIN]).then();
return false;
};

+ 14
- 0
src/app/core/guards/unAuth.guard.ts View File

import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { LocalStorageService } from 'ngx-webstorage';

export const unAuthGuard: CanActivateFn = () => {
const localStorage = inject(LocalStorageService);
const token = localStorage.retrieve('token');
if (!token) {
return true;
}
const router = inject(Router);
router.navigate(['/homepage']).then();
return false;
};

+ 1
- 1
src/app/modules/homepage/hotel-management/hotel-management.component.html View File

[ngClass]="room.status" [ngClass]="room.status"
> >
<span class="time-checkin" *ngIf="room.checkInTime"> <span class="time-checkin" *ngIf="room.checkInTime">
{{ room.checkInTime }} {{clock}}
{{ room.checkInTime }} {{ clock }}
</span> </span>
{{ room?.roomNumber }} {{ room?.roomNumber }}
</div> </div>

+ 8
- 8
src/app/modules/homepage/hotel-management/hotel-management.component.ts View File

import {Component, OnInit} from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { hotelData } from '../data/fake-data'; import { hotelData } from '../data/fake-data';
import {timer} from "rxjs";
import { timer } from 'rxjs';


@Component({ @Component({
selector: 'app-hotel-management', selector: 'app-hotel-management',
}) })
export class HotelManagementComponent implements OnInit { export class HotelManagementComponent implements OnInit {
data = hotelData.reverse(); data = hotelData.reverse();
public clock:any = null;
public clock: any = null;
constructor() {} constructor() {}


ngOnInit() { ngOnInit() {


time() { time() {
let date = new Date(); let date = new Date();
let second:number | string = date.getSeconds();
let minute:number | string = date.getMinutes();
let hour:number | string = date.getHours();
let second: number | string = date.getSeconds();
let minute: number | string = date.getMinutes();
let hour: number | string = date.getHours();
if (second < 10) { if (second < 10) {
second = '0' + second
second = '0' + second;
} }
if (minute < 0) { if (minute < 0) {
minute = '0' + minute; minute = '0' + minute;
} }
this.clock = hour + ":" + minute + ":" + second;
this.clock = hour + ':' + minute + ':' + second;
} }
} }

+ 1
- 1
src/app/modules/homepage/security-atm-details/security-atm-details.component.ts View File

this.status2 = message.status2 == '1'; // 0 not, 1 ready, 2 error, 3 bypass this.status2 = message.status2 == '1'; // 0 not, 1 ready, 2 error, 3 bypass
this.state3 = message.state3 == '1' ? 'ON' : 'OFF'; this.state3 = message.state3 == '1' ? 'ON' : 'OFF';
this.state4 = message.state4 == '1' ? 'ON' : 'OFF'; this.state4 = message.state4 == '1' ? 'ON' : 'OFF';
this.state5 = true;//message.state5 == '1'; // alarm 9h && 6h // 1 ON, 0 OFF
this.state5 = true; //message.state5 == '1'; // alarm 9h && 6h // 1 ON, 0 OFF
this.state6 = message.state6 == '1'; // ? 'ON' : 'OFF'; this.state6 = message.state6 == '1'; // ? 'ON' : 'OFF';
this.switchArm = message.state5 == '1'; // alarm 9h && 6h // 1 ON, 0 OFF this.switchArm = message.state5 == '1'; // alarm 9h && 6h // 1 ON, 0 OFF
this.isReady = message.ready == '1'; this.isReady = message.ready == '1';

+ 94
- 0
src/app/modules/session/session.component.html View File

<div class="flex h-full bg-container items-center">
<div class="w-[28.75rem] rounded-md p-5 mx-auto bg-orange-50/75">
<div class="flex items-center mb-6">
<img
data-aos="fade-up"
class="h-10"
src="assets/images/logo.png"
alt="logo-with-text"
/>
<div>
<h1
data-aos="fade-up"
data-aos-delay="50"
class="text-24px font-medium mb-2"
>
Login to your account
</h1>
<p data-aos="fade-up" data-aos-delay="100" class="opacity-60">
Enter your username and password to log in.
</p>
</div>
</div>
<form [formGroup]="form" (ngSubmit)="submit()" class="flex flex-col gap-5">
<div data-aos="fade-up" data-aos-delay="150">
<mat-label class="block">User name</mat-label>
<mat-form-field
class="w-full"
appearance="outline"
floatLabel="always"
subscriptSizing="dynamic"
>
<input
formControlName="username"
matInput
placeholder="Username"
autocomplete="username"
/>
</mat-form-field>
<ng-container
*ngIf="
form.get('username')?.hasError('required') &&
form.get('username')?.touched
"
>
<mat-error>This is a required field.</mat-error>
</ng-container>
</div>
<div data-aos="fade-up" data-aos-delay="200">
<mat-label class="block">Password</mat-label>
<mat-form-field
class="w-full"
appearance="outline"
floatLabel="always"
subscriptSizing="dynamic"
>
<input
formControlName="password"
matInput
placeholder="Password"
[type]="isShow ? 'text' : 'password'"
autocomplete="current-password"
/>
<mat-icon
[matTooltip]="isShow ? 'Hide password' : 'Show password'"
class="cursor-pointer text-gray-500"
matSuffix
[svgIcon]="isShow ? 'outline--eye' : 'outline--eye-slash'"
(click)="isShow = !isShow"
></mat-icon>
</mat-form-field>
<ng-container
*ngIf="
form.get('password')?.hasError('required') &&
form.get('password')?.touched
"
>
<mat-error>This is a required field.</mat-error>
</ng-container>
</div>
<mat-error *ngIf="loginError" class="text-center"
>Login failed. Please check your username and password.</mat-error
>
<button
data-aos="fade-up"
data-aos-delay="250"
mat-flat-button
class="w-full !bg-[#ff7723] !text-white py-2"
[disabled]="isLoading"
>
Login
</button>
</form>
</div>
</div>

+ 5
- 0
src/app/modules/session/session.component.scss View File

.bg-container {
background-image: url("/assets/images/login-bg.png");
background-repeat: no-repeat;
background-size: cover;
}

+ 21
- 0
src/app/modules/session/session.component.spec.ts View File

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SessionComponent } from './session.component';

describe('SessionComponent', () => {
let component: SessionComponent;
let fixture: ComponentFixture<SessionComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [SessionComponent],
});
fixture = TestBed.createComponent(SessionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 72
- 0
src/app/modules/session/session.component.ts View File

import { Component } from '@angular/core';
import {
FormControl,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { Router } from '@angular/router';
import { map, timer } from 'rxjs';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { NgIf } from '@angular/common';

@Component({
selector: 'app-session',
standalone: true,
templateUrl: './session.component.html',
styleUrls: ['./session.component.scss'],
imports: [
ReactiveFormsModule,
MatInputModule,
MatButtonModule,
MatIconModule,
MatTooltipModule,
NgIf,
],
})
export class SessionComponent {
readonly token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.1Jy-gGjEJVq6me2f6YMguG5Pgjtmgkw1E7Qucttkbbs`;
form: FormGroup = new FormGroup({
username: new FormControl<string>('', [Validators.required]),
password: new FormControl<string>('', [Validators.required]),
});
isLoading = false;
isShow = false;
loginError: boolean = false;

constructor(
private localStorageService: LocalStorageService,
private router: Router,
) {}

submit(): void {
if (this.form.invalid) {
this.form.markAllAsTouched();
return;
}

this.isLoading = true;
this.loginError = false;

timer(200)
.pipe(
map(() => {
const { username, password } = this.form.value;
return username === 'admin' && password === 'Admin@123';
}),
)
.subscribe((isSuccess) => {
if (isSuccess) {
this.localStorageService.store('token', this.token);
this.router.navigate(['/homepage']).then();
} else {
this.loginError = true; // Nếu sai, hiển thị lỗi
}
this.isLoading = false;
});
}
}

+ 32
- 4
src/app/shared/component/layout/layout.component.html View File

<div class="layout-container"> <div class="layout-container">
<div class="header mat-elevation-z1">
<img src="../../../../../../assets/images/logo.png" />
<div>
<button mat-button routerLink="/homepage" routerLinkActive="active">
<div class="header mat-elevation-z1 flex justify-between">
<div class="flex gap-2 items-center">
<img src="../../../../../../assets/images/logo.png" />
<button
class="w-[5rem]"
mat-button
routerLink="/homepage"
routerLinkActive="active"
>
Home Home
</button> </button>
</div> </div>
<div
data-aos="fade-left"
data-aos-delay="250"
class="inline-flex justify-end items-center gap-2"
>
<button
[matMenuTriggerFor]="menu"
mat-mini-fab
class="rounded-full inline-flex justify-center items-center cursor-pointer !bg-orange-50"
>
<mat-icon svgIcon="bold--user" class="size-4"></mat-icon>
</button>
<mat-menu #menu="matMenu" class="mt-2">
<!-- <button mat-menu-item>-->
<!-- <mat-icon svgIcon="outline&#45;&#45;lock" class="size-6"></mat-icon>-->
<!-- <span>Change password</span>-->
<!-- </button>-->
<button mat-menu-item (click)="logout()">
<mat-icon svgIcon="outline--logout" class="size-6"></mat-icon>
<span>Logout</span>
</button>
</mat-menu>
</div>
</div> </div>
<div style="flex: 1"> <div style="flex: 1">
<router-outlet></router-outlet> <router-outlet></router-outlet>

+ 1
- 4
src/app/shared/component/layout/layout.component.scss View File

justify-content: space-between; justify-content: space-between;
height: 100%; height: 100%;
.header { .header {
height: 3rem;
height: 3.5rem;
padding: 0.25rem 2rem; padding: 0.25rem 2rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
width: 7rem; width: 7rem;
height: 3rem; height: 3rem;
} }
button {
width: 5rem;
}
.active { .active {
color: #ff7723 !important; color: #ff7723 !important;
} }

+ 14
- 1
src/app/shared/component/layout/layout.component.ts View File

import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { LocalStorageService } from 'ngx-webstorage';
import { Router } from '@angular/router';
import { RouteUtils } from '../../utils/route.utils';


@Component({ @Component({
selector: 'app-layout', selector: 'app-layout',
templateUrl: './layout.component.html', templateUrl: './layout.component.html',
styleUrls: ['./layout.component.scss'], styleUrls: ['./layout.component.scss'],
}) })
export class LayoutComponent {}
export class LayoutComponent {
constructor(
private localStorage: LocalStorageService,
private router: Router,
) {}

logout() {
this.localStorage.clear('token');
this.router.navigate(['/', RouteUtils.Session.LOGIN]);
}
}

+ 5
- 0
src/app/shared/utils/route.utils.ts View File

export class RouteUtils {
public static Session = {
LOGIN: 'login',
};
}

BIN
src/assets/images/login-bg.jpg View File

Before After
Width: 900  |  Height: 600  |  Size: 92KB

BIN
src/assets/images/login-bg.png View File

Before After
Width: 1280  |  Height: 800  |  Size: 1.1MB

+ 1
- 0
src/assets/images/svg/bold--user.svg View File

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none"><path d="M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10ZM12 14.5c-5.01 0-9.09 3.36-9.09 7.5 0 .28.22.5.5.5h17.18c.28 0 .5-.22.5-.5 0-4.14-4.08-7.5-9.09-7.5Z" fill="#FF8A65"></path></svg>

+ 11
- 0
src/assets/images/svg/outline--eye-slash.svg View File

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none">
<path
d="M9.472 15.282c-.19 0-.38-.07-.53-.22a4.305 4.305 0 0 1-1.27-3.06c0-2.39 1.94-4.33 4.33-4.33 1.15 0 2.24.45 3.06 1.27a.75.75 0 0 1 0 1.06l-5.06 5.06c-.15.15-.34.22-.53.22Zm2.53-6.11a2.834 2.834 0 0 0-2.46 4.23l3.86-3.86c-.42-.24-.9-.37-1.4-.37Z"
fill="currentColor"></path>
<path
d="M5.6 18.51c-.17 0-.35-.06-.49-.18-1.07-.91-2.03-2.03-2.85-3.33-1.06-1.65-1.06-4.34 0-6C4.7 5.18 8.25 2.98 12 2.98c2.2 0 4.37.76 6.27 2.19a.75.75 0 0 1-.9 1.2c-1.64-1.24-3.5-1.89-5.37-1.89-3.23 0-6.32 1.94-8.48 5.33-.75 1.17-.75 3.21 0 4.38s1.61 2.18 2.56 3c.31.27.35.74.08 1.06-.14.17-.35.26-.56.26ZM11.999 21.02c-1.33 0-2.63-.27-3.88-.8a.75.75 0 0 1-.4-.98c.16-.38.6-.56.98-.4 1.06.45 2.17.68 3.29.68 3.23 0 6.32-1.94 8.48-5.33.75-1.17.75-3.21 0-4.38-.31-.49-.65-.96-1.01-1.4a.76.76 0 0 1 .11-1.06.75.75 0 0 1 1.06.11c.39.48.77 1 1.11 1.54 1.06 1.65 1.06 4.34 0 6-2.44 3.82-5.99 6.02-9.74 6.02Z"
fill="currentColor"></path>
<path
d="M12.691 16.268c-.35 0-.67-.25-.74-.61-.08-.41.19-.8.6-.87 1.1-.2 2.02-1.12 2.22-2.22.08-.41.47-.67.88-.6.41.08.68.47.6.88-.32 1.73-1.7 3.1-3.42 3.42-.05-.01-.09 0-.14 0ZM2.001 22.749c-.19 0-.38-.07-.53-.22a.755.755 0 0 1 0-1.06l7.47-7.47c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-7.47 7.47c-.15.15-.34.22-.53.22ZM14.529 10.221c-.19 0-.38-.07-.53-.22a.754.754 0 0 1 0-1.06l7.47-7.47c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-7.47 7.47c-.15.15-.34.22-.53.22Z"
fill="currentColor"></path>
</svg>

+ 8
- 0
src/assets/images/svg/outline--eye.svg View File

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none">
<path
d="M12.002 16.332c-2.39 0-4.33-1.94-4.33-4.33s1.94-4.33 4.33-4.33 4.33 1.94 4.33 4.33-1.94 4.33-4.33 4.33Zm0-7.16c-1.56 0-2.83 1.27-2.83 2.83s1.27 2.83 2.83 2.83 2.83-1.27 2.83-2.83-1.27-2.83-2.83-2.83Z"
fill="currentColor"></path>
<path
d="M11.998 21.02c-3.76 0-7.31-2.2-9.75-6.02-1.06-1.65-1.06-4.34 0-6 2.45-3.82 6-6.02 9.75-6.02s7.3 2.2 9.74 6.02c1.06 1.65 1.06 4.34 0 6-2.44 3.82-5.99 6.02-9.74 6.02Zm0-16.54c-3.23 0-6.32 1.94-8.48 5.33-.75 1.17-.75 3.21 0 4.38 2.16 3.39 5.25 5.33 8.48 5.33 3.23 0 6.32-1.94 8.48-5.33.75-1.17.75-3.21 0-4.38-2.16-3.39-5.25-5.33-8.48-5.33Z"
fill="currentColor"></path>
</svg>

+ 4
- 0
src/assets/images/svg/outline--logout.svg View File

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none">
<path stroke="#FF8A65" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="1.5"
d="M17.44 14.62L20 12.06 17.44 9.5M9.76 12.06h10.17M11.76 20c-4.42 0-8-3-8-8s3.58-8 8-8"></path>
</svg>

+ 1
- 0
src/assets/images/svg/sprite/sprite.svg View File

<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 24 24" fill="none" id="bold--user" xmlns="http://www.w3.org/2000/svg"><path d="M12 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0 2.5c-5.01 0-9.09 3.36-9.09 7.5 0 .28.22.5.5.5h17.18c.28 0 .5-.22.5-.5 0-4.14-4.08-7.5-9.09-7.5Z" fill="#FF8A65"/></symbol><symbol viewBox="0 0 24 24" fill="none" id="outline--eye" xmlns="http://www.w3.org/2000/svg"><path d="M12.002 16.332c-2.39 0-4.33-1.94-4.33-4.33s1.94-4.33 4.33-4.33 4.33 1.94 4.33 4.33-1.94 4.33-4.33 4.33Zm0-7.16c-1.56 0-2.83 1.27-2.83 2.83s1.27 2.83 2.83 2.83 2.83-1.27 2.83-2.83-1.27-2.83-2.83-2.83Z" fill="currentColor"/><path d="M11.998 21.02c-3.76 0-7.31-2.2-9.75-6.02-1.06-1.65-1.06-4.34 0-6 2.45-3.82 6-6.02 9.75-6.02s7.3 2.2 9.74 6.02c1.06 1.65 1.06 4.34 0 6-2.44 3.82-5.99 6.02-9.74 6.02Zm0-16.54c-3.23 0-6.32 1.94-8.48 5.33-.75 1.17-.75 3.21 0 4.38 2.16 3.39 5.25 5.33 8.48 5.33 3.23 0 6.32-1.94 8.48-5.33.75-1.17.75-3.21 0-4.38-2.16-3.39-5.25-5.33-8.48-5.33Z" fill="currentColor"/></symbol><symbol viewBox="0 0 24 24" fill="none" id="outline--eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M9.472 15.282c-.19 0-.38-.07-.53-.22a4.305 4.305 0 0 1-1.27-3.06c0-2.39 1.94-4.33 4.33-4.33 1.15 0 2.24.45 3.06 1.27a.75.75 0 0 1 0 1.06l-5.06 5.06c-.15.15-.34.22-.53.22Zm2.53-6.11a2.834 2.834 0 0 0-2.46 4.23l3.86-3.86c-.42-.24-.9-.37-1.4-.37Z" fill="currentColor"/><path d="M5.6 18.51c-.17 0-.35-.06-.49-.18-1.07-.91-2.03-2.03-2.85-3.33-1.06-1.65-1.06-4.34 0-6C4.7 5.18 8.25 2.98 12 2.98c2.2 0 4.37.76 6.27 2.19a.75.75 0 0 1-.9 1.2c-1.64-1.24-3.5-1.89-5.37-1.89-3.23 0-6.32 1.94-8.48 5.33-.75 1.17-.75 3.21 0 4.38s1.61 2.18 2.56 3c.31.27.35.74.08 1.06-.14.17-.35.26-.56.26Zm6.399 2.51c-1.33 0-2.63-.27-3.88-.8a.75.75 0 0 1-.4-.98c.16-.38.6-.56.98-.4 1.06.45 2.17.68 3.29.68 3.23 0 6.32-1.94 8.48-5.33.75-1.17.75-3.21 0-4.38-.31-.49-.65-.96-1.01-1.4a.76.76 0 0 1 .11-1.06.75.75 0 0 1 1.06.11c.39.48.77 1 1.11 1.54 1.06 1.65 1.06 4.34 0 6-2.44 3.82-5.99 6.02-9.74 6.02Z" fill="currentColor"/><path d="M12.691 16.268c-.35 0-.67-.25-.74-.61-.08-.41.19-.8.6-.87 1.1-.2 2.02-1.12 2.22-2.22.08-.41.47-.67.88-.6.41.08.68.47.6.88-.32 1.73-1.7 3.1-3.42 3.42-.05-.01-.09 0-.14 0Zm-10.69 6.481c-.19 0-.38-.07-.53-.22a.755.755 0 0 1 0-1.06l7.47-7.47c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-7.47 7.47c-.15.15-.34.22-.53.22Zm12.528-12.528c-.19 0-.38-.07-.53-.22a.754.754 0 0 1 0-1.06l7.47-7.47c.29-.29.77-.29 1.06 0 .29.29.29.77 0 1.06l-7.47 7.47c-.15.15-.34.22-.53.22Z" fill="currentColor"/></symbol><symbol viewBox="0 0 24 24" fill="none" id="outline--logout" xmlns="http://www.w3.org/2000/svg"><path stroke="#FF8A65" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="1.5" d="M17.44 14.62 20 12.06 17.44 9.5m-7.68 2.56h10.17M11.76 20c-4.42 0-8-3-8-8s3.58-8 8-8"/></symbol></svg>

+ 4
- 0
src/styles.scss View File

/* 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/style/scss/common"; @import "assets/style/scss/common";
@tailwind base;
@tailwind components;
@tailwind utilities;

html, html,
body { body {
height: 100%; height: 100%;

+ 8
- 0
tailwind.config.js View File

/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,ts}"],
theme: {
extend: {},
},
plugins: [],
};

Loading…
Cancel
Save