Remove components and center the card

This commit is contained in:
Lucàs
2022-07-28 19:28:34 +02:00
parent 76bb4b3208
commit 8f29701973
23 changed files with 144 additions and 221 deletions
+1
View File
@@ -28,6 +28,7 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"node_modules/font-awesome/scss/font-awesome.scss",
"node_modules/bulma/bulma.sass", "node_modules/bulma/bulma.sass",
"src/styles.scss" "src/styles.scss"
], ],
+14
View File
@@ -17,6 +17,7 @@
"@angular/platform-browser-dynamic": "^14.1.0", "@angular/platform-browser-dynamic": "^14.1.0",
"@angular/router": "^14.1.0", "@angular/router": "^14.1.0",
"bulma": "^0.9.4", "bulma": "^0.9.4",
"font-awesome": "^4.7.0",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
@@ -5822,6 +5823,14 @@
} }
} }
}, },
"node_modules/font-awesome": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==",
"engines": {
"node": ">=0.10.3"
}
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -15989,6 +15998,11 @@
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"dev": true "dev": true
}, },
"font-awesome": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg=="
},
"forwarded": { "forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+1
View File
@@ -19,6 +19,7 @@
"@angular/platform-browser-dynamic": "^14.1.0", "@angular/platform-browser-dynamic": "^14.1.0",
"@angular/router": "^14.1.0", "@angular/router": "^14.1.0",
"bulma": "^0.9.4", "bulma": "^0.9.4",
"font-awesome": "^4.7.0",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
+36 -6
View File
@@ -1,10 +1,40 @@
<div class="container"> <div class="container">
<div class="card m-6"> <div class="card p-6 mt-6">
<div class="content p-6"> <h1 class="title has-text-centered">{{ title }}</h1>
<h1 class="title has-text-centered">Todo List</h1>
<app-todo-list></app-todo-list> <!-- Todolist -->
<app-todo-input></app-todo-input> <div class="m-5">
<div *ngIf="list.length == 0">
<p class="empty-list subtitle has-text-centered">Empty list</p>
</div>
<div class="columns" *ngFor="let item of list">
<input type="checkbox" [(ngModel)]="item.checked" name="{{ item.text }}" id="{{ item.text }}">
<label class="checkbox pl-2" for="{{ item.text }}">
{{ item.text }}
</label>
</div>
</div>
<!-- Input -->
<div class="columns is-multiline">
<div class="column">
<input class="input" type="text" [(ngModel)]="inputValue" (keydown.enter)="addItem()">
</div>
<div class="column is-2">
<button class="button is-primary" (click)="addItem()">
<span class="icon">
<i class="fa fa-plus"></i>
</span>
</button>
</div>
<div class="column is-2">
<button class="button is-danger" (click)="removeCheckedItems()">
<span class="icon">
<i class="fa fa-trash"></i>
</span>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
+13
View File
@@ -0,0 +1,13 @@
input[type=checkbox] + label {
transition: all 500ms;
}
input[type=checkbox]:checked + label {
text-decoration: line-through;
color: gray;
}
.empty-list {
color: gray;
font-style: italic;
}
+49 -3
View File
@@ -1,10 +1,56 @@
import { Component } from '@angular/core'; import {Component, OnInit} from '@angular/core';
import TodoItem from "../models/todo-item.model";
import LocalService from "../services/local.service";
@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 { export class AppComponent implements OnInit {
title = 'todo-list'; public title = 'Todo List App';
public list: TodoItem[] = [];
private LOCAL_STORAGE_KEY = "todoList";
inputValue: any;
ngOnInit(): void {
const savedData: null | TodoItem[] = LocalService.getData(this.LOCAL_STORAGE_KEY)
if (savedData) this.list = savedData;
}
/**
* Create a new item if input is not empty and the item doesn't exist already
*/
addItem(): void {
const listOfTodoText = this.list.map(item => item.text);
if (this.inputValue && !listOfTodoText.includes(this.inputValue)) {
this.list.push(new TodoItem(this.inputValue))
this.inputValue = "";
this.saveList();
}
}
/**
* Remove a specific item of the list
* @param toRemove TodoItem to remove
*/
removeItem(toRemove: TodoItem): void {
this.list = this.list.filter(item => item !== toRemove);
this.saveList();
}
/**
* Remove all checked items of the list
*/
removeCheckedItems(): void {
this.list = this.list.filter(item => !item.checked)
this.saveList();
}
private saveList(): void {
LocalService.saveData(this.LOCAL_STORAGE_KEY, this.list);
}
} }
+1 -7
View File
@@ -2,17 +2,11 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { TodoListComponent } from './todo-list/todo-list.component';
import { TodoItemComponent } from './todo-item/todo-item.component';
import { TodoInputComponent } from './todo-input/todo-input.component';
import {FormsModule} from "@angular/forms"; import {FormsModule} from "@angular/forms";
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent
TodoListComponent,
TodoItemComponent,
TodoInputComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@@ -1,4 +0,0 @@
<div class="mt-5">
<input class="input" type="text" [(ngModel)]="textInput" (keyup.enter)="createTodoItem()">
<input class="button is-primary mt-2 is-fullwidth" type="button" value="Create" (click)="createTodoItem()">
</div>
@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TodoInputComponent } from './todo-input.component';
describe('TodoInputComponent', () => {
let component: TodoInputComponent;
let fixture: ComponentFixture<TodoInputComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TodoInputComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TodoInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -1,21 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {TodoItemService} from "../../services/todo-item.service";
@Component({
selector: 'app-todo-input',
templateUrl: './todo-input.component.html',
styleUrls: ['./todo-input.component.scss']
})
export class TodoInputComponent implements OnInit {
textInput: string = "";
constructor(private todoItemService: TodoItemService) { }
ngOnInit(): void {}
createTodoItem(): void {
if (this.textInput) {
this.todoItemService.newItem(this.textInput);
this.textInput = "";
}
}
}
@@ -1,6 +0,0 @@
<li>
<input type="checkbox" [checked]="todoItem.checked" (change)="check()" name="checkbox"
id="checkbox-{{ todoItem.id }}">
<label class="checkbox ml-2" for="checkbox-{{ todoItem.id }}">{{ todoItem.text }}</label>
<!-- Todo add delete button -->
</li>
@@ -1,20 +0,0 @@
li {
list-style: none;
input:checked + label {
color: gray;
&::after { width: 100%; }
}
label::after {
content: '';
width: 0; // Before animation
height: 2px;
background-color: gray;
position: absolute;
top: 50%; left: 0;
transition: width 300ms ease-in-out;
}
}
@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TodoItemComponent } from './todo-item.component';
describe('TodoItemComponent', () => {
let component: TodoItemComponent;
let fixture: ComponentFixture<TodoItemComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TodoItemComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TodoItemComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
-21
View File
@@ -1,21 +0,0 @@
import {Component, Input, OnInit} from '@angular/core';
import {TodoItem} from "../../models/todo-item.model";
import {TodoItemService} from "../../services/todo-item.service";
@Component({
selector: 'app-todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.scss']
})
export class TodoItemComponent implements OnInit {
@Input() todoItem!: TodoItem
constructor(private todoItemService: TodoItemService) {}
ngOnInit(): void {}
check() {
this.todoItem.checked = !this.todoItem.checked;
this.todoItemService.checkById(this.todoItem.id, this.todoItem.checked)
}
}
@@ -1,3 +0,0 @@
<ul>
<app-todo-item *ngFor="let todoItem of todoItems" [todoItem]="todoItem"></app-todo-item>
</ul>
@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TodoListComponent } from './todo-list.component';
describe('TodoListComponent', () => {
let component: TodoListComponent;
let fixture: ComponentFixture<TodoListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TodoListComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TodoListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
-18
View File
@@ -1,18 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {TodoItem} from "../../models/todo-item.model";
import {TodoItemService} from "../../services/todo-item.service";
@Component({
selector: 'app-todo-list',
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.scss']
})
export class TodoListComponent implements OnInit {
todoItems!: TodoItem[];
constructor(private todoItemService: TodoItemService) {}
ngOnInit(): void {
this.todoItemService.loadItems();
this.todoItems = this.todoItemService.todoItems;
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
export class TodoItem { export default class TodoItem {
constructor( constructor(
public id: number,
public text: string, public text: string,
public checked: boolean = false public checked: boolean = false
) {} ) {}
+19
View File
@@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import TodoItem from "../models/todo-item.model";
@Injectable({
providedIn: 'root'
})
export default class LocalService {
static saveData(key: string, data: TodoItem[]) {
localStorage.setItem(key, JSON.stringify(data));
}
static getData(key: string): TodoItem[] | null {
const data = localStorage.getItem(key);
if (!data) return null
return JSON.parse(data) as TodoItem[];
}
}
-41
View File
@@ -1,41 +0,0 @@
import {Injectable} from "@angular/core";
import {TodoItem} from "../models/todo-item.model";
@Injectable({
providedIn: 'root'
})
export class TodoItemService {
todoItems: TodoItem[] = [];
get nextId(): number {
return this.todoItems.length + 1
}
getById(id: number): TodoItem {
const todoItem = this.todoItems.find(item => item.id === id);
if (!todoItem) throw new Error('Todo item not found!');
return todoItem;
}
newItem(text: string): void {
const newTodoItem: TodoItem = new TodoItem(this.nextId, text);
this.todoItems.push(newTodoItem);
this.saveItems()
}
checkById(id: number, checked: boolean) {
this.todoItems[id - 1].checked = checked;
this.saveItems()
}
loadItems() {
const saveDataRaw: any = localStorage.getItem("todoList");
if (saveDataRaw as string) this.todoItems = JSON.parse(saveDataRaw);
}
saveItems() {
localStorage.setItem("todoList", JSON.stringify(this.todoItems))
}
}
+8
View File
@@ -1 +1,9 @@
/* 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 */
body {
width: 100vw;
min-height: 100vh;
background-color: whitesmoke;
display: grid;
place-items: center;
}