mirror of
https://github.com/LucasVbr/todo-list.git
synced 2026-05-16 17:22:02 +00:00
Use TailWindCSS with DaisyUi instead of Bulma for styles
Add navbar and footer Improve design of the List Add MIT LICENCE
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Lucàs Vabre
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/bulma/bulma.sass",
|
||||
"node_modules/daisyui/dist/full.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
|
||||
Generated
+607
-162
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -18,7 +18,7 @@
|
||||
"@angular/platform-browser": "^14.1.0",
|
||||
"@angular/platform-browser-dynamic": "^14.1.0",
|
||||
"@angular/router": "^14.1.0",
|
||||
"bulma": "^0.9.4",
|
||||
"daisyui": "^2.24.0",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
@@ -28,12 +28,15 @@
|
||||
"@angular/cli": "~14.1.2",
|
||||
"@angular/compiler-cli": "^14.1.0",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"jasmine-core": "~4.2.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"postcss": "^8.4.16",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"typescript": "~4.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,9 @@
|
||||
<div class="container">
|
||||
<h1 class="title has-text-centered mt-5">{{ title }}</h1>
|
||||
<div class="w-screen h-screen justify-between flex flex-col">
|
||||
<app-navbar></app-navbar>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<table class="table is-striped is-narrow is-fullwidth">
|
||||
<tr *ngFor="let todoItem of todoList">
|
||||
<td>
|
||||
<input class="checkbox is-primary" type="checkbox" (change)="saveList()"
|
||||
[checked]="todoItem.completed" name="task-{{ todoItem.id }}"
|
||||
id="task-{{ todoItem.id }}">
|
||||
</td>
|
||||
<td>
|
||||
<label for="task-{{ todoItem.id }}">{{ todoItem.task }}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input class="button is-danger is-primary is-pulled-right" type="button"
|
||||
value="remove" (click)="removeItem(todoItem.id)">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input class="input is-primary" type="text" [(ngModel)]="todoInput"
|
||||
(keydown.enter)="addItem()">
|
||||
</div>
|
||||
<div class="container mx-auto">
|
||||
<app-todolist class="mx-2"></app-todolist>
|
||||
</div>
|
||||
|
||||
|
||||
<app-footer></app-footer>
|
||||
</div>
|
||||
|
||||
@@ -1,57 +1,8 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import TodoItem from '../models/TodoItem';
|
||||
|
||||
const LOCAL_STORAGE_KEY: string = "todoList";
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit{
|
||||
public title = 'Todo List App';
|
||||
public todoInput!: string;
|
||||
public todoList!: TodoItem[];
|
||||
|
||||
ngOnInit() {
|
||||
this.todoInput = "";
|
||||
this.todoList = this.getSavedList();
|
||||
}
|
||||
|
||||
private getSavedList(): TodoItem[] {
|
||||
console.info("Load TodoList");
|
||||
|
||||
const loadedValues: string|null = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
|
||||
if (loadedValues) return JSON.parse(loadedValues) as TodoItem[];
|
||||
return [];
|
||||
}
|
||||
|
||||
public saveList() {
|
||||
console.info("Save todoList");
|
||||
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.todoList))
|
||||
}
|
||||
|
||||
public addItem(): void {
|
||||
if (!this.todoInput) return;
|
||||
|
||||
const newItem: TodoItem = new TodoItem(this.getNextIndex(), this.todoInput);
|
||||
this.todoList.push(newItem);
|
||||
this.todoInput = "";
|
||||
|
||||
this.saveList();
|
||||
}
|
||||
|
||||
public removeItem(index: number): void {
|
||||
this.todoList = this.todoList.filter(item => {
|
||||
return item.id !== index;
|
||||
});
|
||||
this.saveList();
|
||||
}
|
||||
|
||||
private getNextIndex() {
|
||||
if (this.todoList.length === 0) return 1;
|
||||
return Math.max(...this.todoList.map(item => item.id)) + 1
|
||||
}
|
||||
}
|
||||
export class AppComponent {}
|
||||
|
||||
@@ -3,10 +3,16 @@ import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import { NavbarComponent } from './navbar/navbar.component';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
import { TodolistComponent } from './todolist/todolist.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
AppComponent,
|
||||
NavbarComponent,
|
||||
FooterComponent,
|
||||
TodolistComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<footer class="footer footer-center p-4 bg-base-300 text-base-content">
|
||||
<div>
|
||||
<p>MIT Licence © 2022 -
|
||||
<a href="https://github.com/LucasVbr/todo-list" class="link link-hover"
|
||||
target="_blank">See code on GitHub
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
describe('FooterComponent', () => {
|
||||
let component: FooterComponent;
|
||||
let fixture: ComponentFixture<FooterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FooterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(FooterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.css']
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="navbar bg-base-100">
|
||||
<a class="btn btn-ghost normal-case text-xl">Todo List App</a>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NavbarComponent } from './navbar.component';
|
||||
|
||||
describe('NavbarComponent', () => {
|
||||
let component: NavbarComponent;
|
||||
let fixture: ComponentFixture<NavbarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ NavbarComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(NavbarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
templateUrl: './navbar.component.html',
|
||||
styleUrls: ['./navbar.component.css']
|
||||
})
|
||||
export class NavbarComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="card m-auto w-96 bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Input-->
|
||||
<div class="form-control">
|
||||
<div class="input-group justify-center">
|
||||
<input type="text" placeholder="Type here your task..."
|
||||
class="input input-bordered w-full"
|
||||
[(ngModel)]="todoInput" (keydown.enter)="addItem()"/>
|
||||
<button class="btn btn-square" (click)="addItem()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M12 4v16m8-8H4"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List-->
|
||||
<div class="form-control" *ngFor="let todoItem of todoList">
|
||||
<label class="label cursor-pointer" for="task-{{ todoItem.id }}">
|
||||
<input type="checkbox" checked="checked"
|
||||
class="checkbox checkbox-primary"
|
||||
id="task-{{ todoItem.id }}" name="task-{{ todoItem.id }}"
|
||||
[(ngModel)]="todoItem.completed" (change)="saveList()"/>
|
||||
|
||||
<span class="label-text">{{ todoItem.task }}</span>
|
||||
|
||||
<button class="btn btn-error btn-square btn-outline"
|
||||
(click)="removeItem(todoItem.id)">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none"
|
||||
viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-actions justify-between">
|
||||
You have {{ todoList.length }} pending task(s)
|
||||
<button class="btn btn-error" (click)="clearList()">Clear All</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TodolistComponent } from './todolist.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();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import TodoItem from '../../models/TodoItem';
|
||||
|
||||
const LOCAL_STORAGE_KEY: string = "todoList";
|
||||
|
||||
@Component({
|
||||
selector: 'app-todolist',
|
||||
templateUrl: './todolist.component.html',
|
||||
styleUrls: ['./todolist.component.css']
|
||||
})
|
||||
export class TodolistComponent implements OnInit {
|
||||
public todoInput!: string;
|
||||
public todoList!: TodoItem[];
|
||||
|
||||
ngOnInit() {
|
||||
this.todoInput = "";
|
||||
this.todoList = this.getSavedList();
|
||||
}
|
||||
|
||||
public addItem(): void {
|
||||
if (!this.todoInput) return;
|
||||
|
||||
const newItem: TodoItem = new TodoItem(this.getNextIndex(), this.todoInput);
|
||||
this.todoList.push(newItem);
|
||||
this.todoInput = "";
|
||||
|
||||
this.saveList();
|
||||
}
|
||||
|
||||
public removeItem(index: number): void {
|
||||
this.todoList = this.todoList.filter(item => {
|
||||
return item.id !== index;
|
||||
});
|
||||
this.saveList();
|
||||
}
|
||||
|
||||
public clearList(): void {
|
||||
this.todoList = [];
|
||||
this.saveList();
|
||||
}
|
||||
|
||||
public saveList() {
|
||||
console.info("Save todoList");
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.todoList))
|
||||
}
|
||||
|
||||
private getSavedList(): TodoItem[] {
|
||||
console.info("Load TodoList");
|
||||
const loadedValues: string|null = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (loadedValues) return JSON.parse(loadedValues) as TodoItem[];
|
||||
return [];
|
||||
}
|
||||
|
||||
private getNextIndex() {
|
||||
if (this.todoList.length === 0) return 1;
|
||||
return Math.max(...this.todoList.map(item => item.id)) + 1
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1 +1,3 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*{html, ts}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
Reference in New Issue
Block a user