Loazing
This commit is contained in:
parent
17179b95f0
commit
587b979ff2
17 changed files with 208 additions and 58 deletions
|
|
@ -1,9 +1,17 @@
|
||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { HomeComponent } from './component/home/home.component';
|
import { HomeComponent } from './component/home/home.component';
|
||||||
import { AboutComponent } from './component/about/about.component';
|
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: '', component: HomeComponent },
|
{ path: '', component: HomeComponent },
|
||||||
{ path: 'home', component: HomeComponent },
|
{ path: 'home', component: HomeComponent },
|
||||||
{ path: 'about', component: AboutComponent }
|
|
||||||
|
{
|
||||||
|
path: 'tasks',
|
||||||
|
loadChildren: () => import('./module/task/task.component').then(m => m.TASKS_ROUTES)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'about',
|
||||||
|
loadChildren: () => import('./module/about/about.component').then(m => m.ABOUT_ROUTES)
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<a routerLink="/" [class.active]="isHomeActive()">Home</a>
|
<a routerLink="/" [class.active]="isHomeActive()">Home</a>
|
||||||
|
|
|
|
||||||
|
<a routerLink="/tasks" routerLinkActive="active">Tasks</a>
|
||||||
<a routerLink="/about" routerLinkActive="active">About</a>
|
<a routerLink="/about" routerLinkActive="active">About</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1 @@
|
||||||
<h1>Home works!</h1>
|
<p>Home works!</p>
|
||||||
|
|
||||||
<h2>Task List</h2>
|
|
||||||
@if (tasks$ | async; as tasks) {
|
|
||||||
<ul>
|
|
||||||
@for (task of tasks; track task) {
|
|
||||||
<li>
|
|
||||||
{{ task.title }}
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
} @else {
|
|
||||||
<p>Loading tasks...</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
<p>Elapsed time: <span style="font-family:monospace;font-size:1.2em">{{ elapsedClock }}</span></p>
|
|
||||||
|
|
||||||
<!-- Add a task -->
|
|
||||||
<button (click)="addTask('New Task')">+ Add a task</button>
|
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,13 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
import { Component, inject } from '@angular/core';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
||||||
import { TaskService } from '../../service/task.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
imports: [CommonModule, AsyncPipe],
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
templateUrl: './home.component.html',
|
templateUrl: './home.component.html',
|
||||||
styleUrl: './home.component.css'
|
styleUrl: './home.component.css'
|
||||||
})
|
})
|
||||||
export class HomeComponent {
|
export class HomeComponent {
|
||||||
protected count = 0;
|
|
||||||
private intervalId: any;
|
|
||||||
public elapsedClock: string = '';
|
|
||||||
|
|
||||||
private taskService = inject(TaskService);
|
|
||||||
tasks$ = this.taskService.tasks$;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.updateElapsedClock();
|
|
||||||
this.intervalId = setInterval(() => {
|
|
||||||
this.count++;
|
|
||||||
this.updateElapsedClock();
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
if (this.intervalId) {
|
|
||||||
clearInterval(this.intervalId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateElapsedClock() {
|
|
||||||
const totalSeconds = Math.floor(this.count / 2);
|
|
||||||
const h = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
|
|
||||||
const m = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
|
|
||||||
const s = String(totalSeconds % 60).padStart(2, '0');
|
|
||||||
this.elapsedClock = `${h}:${m}:${s}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
addTask(title: string) {
|
|
||||||
this.taskService.addTask(title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
18
src/app/component/tasks-page/tasks-page.component.css
Normal file
18
src/app/component/tasks-page/tasks-page.component.css
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
.trash-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #c00;
|
||||||
|
font-size: 1.1em;
|
||||||
|
padding: 0.1em 0.3em;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.2s, color 0.2s;
|
||||||
|
}
|
||||||
|
.trash-btn:hover {
|
||||||
|
background: #ffeaea;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.trash-btn:hover svg {
|
||||||
|
color: #fff;
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
25
src/app/component/tasks-page/tasks-page.component.html
Normal file
25
src/app/component/tasks-page/tasks-page.component.html
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<h1>tasks-page works!</h1>
|
||||||
|
|
||||||
|
<h2>Task List</h2>
|
||||||
|
@if (tasks$ | async; as tasks) {
|
||||||
|
<ul>
|
||||||
|
@for (task of tasks; track task) {
|
||||||
|
<li>
|
||||||
|
<span>{{ task.title }}</span>
|
||||||
|
<button class="trash-btn" (click)="removeTask(task.id)" title="Delete task">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="20" height="20" style="display:inline-block;vertical-align:middle;fill:currentColor;"><path d="M268 416h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12zM432 80h-82.41l-34-56.7A48 48 0 0 0 274.41 0H173.59a48 48 0 0 0-41.16 23.3L98.41 80H16A16 16 0 0 0 0 96v16a16 16 0 0 0 16 16h16v336a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128h16a16 16 0 0 0 16-16V96a16 16 0 0 0-16-16zM171.84 50.91A6 6 0 0 1 177 48h94a6 6 0 0 1 5.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12z"/></svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
} @else {
|
||||||
|
<p>Loading tasks...</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>Elapsed time: <span style="font-family:monospace;font-size:1.2em">{{ elapsedClock }}</span></p>
|
||||||
|
|
||||||
|
<!-- Add a task -->
|
||||||
|
<form (submit)="onAddTaskSubmit($event)" style="margin-top:1em;display:flex;gap:0.5em;align-items:center;">
|
||||||
|
<input type="text" name="taskTitle" placeholder="Task name" required style="padding:0.3em 0.7em;border-radius:4px;border:1px solid #ccc;min-width:120px;" />
|
||||||
|
<button type="submit">+ Add a task</button>
|
||||||
|
</form>
|
||||||
23
src/app/component/tasks-page/tasks-page.component.spec.ts
Normal file
23
src/app/component/tasks-page/tasks-page.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TasksPageComponent } from './tasks-page.component';
|
||||||
|
|
||||||
|
describe('TasksPageComponent', () => {
|
||||||
|
let component: TasksPageComponent;
|
||||||
|
let fixture: ComponentFixture<TasksPageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [TasksPageComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(TasksPageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
58
src/app/component/tasks-page/tasks-page.component.ts
Normal file
58
src/app/component/tasks-page/tasks-page.component.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { CommonModule, AsyncPipe } from '@angular/common';
|
||||||
|
import { TaskService } from '../../service/task.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tasks-page',
|
||||||
|
imports: [CommonModule, AsyncPipe],
|
||||||
|
templateUrl: './tasks-page.component.html',
|
||||||
|
styleUrl: './tasks-page.component.css',
|
||||||
|
})
|
||||||
|
export class TasksPageComponent {
|
||||||
|
protected count = 0;
|
||||||
|
private intervalId: any;
|
||||||
|
public elapsedClock: string = '';
|
||||||
|
|
||||||
|
private taskService = inject(TaskService);
|
||||||
|
tasks$ = this.taskService.tasks$;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.updateElapsedClock();
|
||||||
|
this.intervalId = setInterval(() => {
|
||||||
|
this.count++;
|
||||||
|
this.updateElapsedClock();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.intervalId) {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateElapsedClock() {
|
||||||
|
const totalSeconds = Math.floor(this.count / 2);
|
||||||
|
const h = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
|
||||||
|
const m = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
|
||||||
|
const s = String(totalSeconds % 60).padStart(2, '0');
|
||||||
|
this.elapsedClock = `${h}:${m}:${s}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeTask(id: number) {
|
||||||
|
this.taskService.removeTask(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddTaskSubmit(event: SubmitEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
const form = event.target as HTMLFormElement;
|
||||||
|
const input = form.elements.namedItem('taskTitle') as HTMLInputElement | null;
|
||||||
|
if (input && input.value.trim()) {
|
||||||
|
this.addTask(input.value.trim());
|
||||||
|
form.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addTask(title: string) {
|
||||||
|
this.taskService.addTask(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/app/module/about/about.component.css
Normal file
0
src/app/module/about/about.component.css
Normal file
1
src/app/module/about/about.component.html
Normal file
1
src/app/module/about/about.component.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<p>about works!</p>
|
||||||
23
src/app/module/about/about.component.spec.ts
Normal file
23
src/app/module/about/about.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AboutComponent } from './about.component';
|
||||||
|
|
||||||
|
describe('AboutComponent', () => {
|
||||||
|
let component: AboutComponent;
|
||||||
|
let fixture: ComponentFixture<AboutComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AboutComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AboutComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
7
src/app/module/about/about.component.ts
Normal file
7
src/app/module/about/about.component.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Routes } from '@angular/router';
|
||||||
|
|
||||||
|
import { AboutComponent } from '../../component/about/about.component';
|
||||||
|
|
||||||
|
export const ABOUT_ROUTES: Routes = [
|
||||||
|
{ path: '', component: AboutComponent },
|
||||||
|
];
|
||||||
0
src/app/module/task/task.component.css
Normal file
0
src/app/module/task/task.component.css
Normal file
1
src/app/module/task/task.component.html
Normal file
1
src/app/module/task/task.component.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<p>task works!</p>
|
||||||
23
src/app/module/task/task.component.spec.ts
Normal file
23
src/app/module/task/task.component.spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskComponent } from './task.component';
|
||||||
|
|
||||||
|
describe('TaskComponent', () => {
|
||||||
|
let component: TaskComponent;
|
||||||
|
let fixture: ComponentFixture<TaskComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [TaskComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(TaskComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
7
src/app/module/task/task.component.ts
Normal file
7
src/app/module/task/task.component.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Routes } from '@angular/router';
|
||||||
|
|
||||||
|
import { TasksPageComponent } from '../../component/tasks-page/tasks-page.component';
|
||||||
|
|
||||||
|
export const TASKS_ROUTES: Routes = [
|
||||||
|
{ path: '', component: TasksPageComponent },
|
||||||
|
];
|
||||||
|
|
@ -25,4 +25,9 @@ export class TaskService {
|
||||||
this.tasks.push(newTask);
|
this.tasks.push(newTask);
|
||||||
this.tasksSubject.next([...this.tasks]);
|
this.tasksSubject.next([...this.tasks]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeTask(id: number) {
|
||||||
|
this.tasks = this.tasks.filter(task => task.id !== id);
|
||||||
|
this.tasksSubject.next([...this.tasks]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue