| "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" | ||||
| } | } | ||||
| } | } |
| { | |||||
| "mode": { | |||||
| "symbol": { | |||||
| "dest": "src/assets/images/svg/sprite", | |||||
| "sprite": "sprite.svg", | |||||
| "prefix": "svg-%s" | |||||
| } | |||||
| } | |||||
| } |
| 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({ |
| 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(); | |||||
| } | } | ||||
| } | } |
| 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], |
| 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; | |||||
| }; |
| 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; | |||||
| }; |
| [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> |
| 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; | |||||
| } | } | ||||
| } | } |
| 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'; |
| <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> |
| .bg-container { | |||||
| background-image: url("/assets/images/login-bg.png"); | |||||
| background-repeat: no-repeat; | |||||
| background-size: cover; | |||||
| } |
| 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(); | |||||
| }); | |||||
| }); |
| 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; | |||||
| }); | |||||
| } | |||||
| } |
| <div class="layout-container"> | <div class="layout-container"> | ||||
| <div class="header mat-elevation-z1"> | |||||
| <div class="header mat-elevation-z1 flex justify-between"> | |||||
| <div class="flex gap-2 items-center"> | |||||
| <img src="../../../../../../assets/images/logo.png" /> | <img src="../../../../../../assets/images/logo.png" /> | ||||
| <div> | |||||
| <button mat-button routerLink="/homepage" routerLinkActive="active"> | |||||
| <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--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> |
| 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; | ||||
| } | } |
| 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]); | |||||
| } | |||||
| } |
| export class RouteUtils { | |||||
| public static Session = { | |||||
| LOGIN: 'login', | |||||
| }; | |||||
| } |
| <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> |
| <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> |
| <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> |
| <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> |
| <?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> |
| /* 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%; |
| /** @type {import('tailwindcss').Config} */ | |||||
| module.exports = { | |||||
| content: ["./src/**/*.{html,ts}"], | |||||
| theme: { | |||||
| extend: {}, | |||||
| }, | |||||
| plugins: [], | |||||
| }; |