Compare commits
7 Commits
0fbc8b1392
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ebb1560ae | |||
| e845bfb27f | |||
| 863caeccf3 | |||
| 9b56dddab9 | |||
| ba11f17531 | |||
| a08f92c84c | |||
| c027357cfe |
@@ -24,7 +24,7 @@
|
||||
padding: 0 3rem;
|
||||
border-radius: .1rem;
|
||||
border-style: none;
|
||||
background-color: #444;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="row">
|
||||
<button class="raised" matRipple matTooltip="Définir une alerte dans X minutes">
|
||||
<button class="stroked secondary" [disabled]="true" matRipple matTooltip="Définir une alerte dans X minutes">
|
||||
<mat-icon>update</mat-icon>
|
||||
Rappel
|
||||
</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button class="raised alert" [disabled]="!task" (click)="delete()">
|
||||
<button class="stroked alert" [disabled]="!task" (click)="delete()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
Supprimer
|
||||
</button>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
align-items: center;
|
||||
margin-bottom: .5rem;
|
||||
flex-direction: column;
|
||||
background-color: #444;
|
||||
background-color: var(--secondary);
|
||||
border-radius: .2rem;
|
||||
|
||||
.header {
|
||||
border-radius: .1rem;
|
||||
height: 2.5rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@@ -21,10 +21,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
// padding: 0 .5rem;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
@@ -34,7 +30,7 @@
|
||||
height: 1.8rem;
|
||||
padding: 0 .8rem;
|
||||
margin: 0 .8rem;
|
||||
background-color: #444;
|
||||
background-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: .1rem;
|
||||
border-color: rgba(0,0,0, 0);
|
||||
@@ -46,7 +42,7 @@
|
||||
border-color .2s ease-out;
|
||||
|
||||
&:hover {
|
||||
border-color: rgb(53, 53, 53);
|
||||
border-color: var(--secondary-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +57,7 @@
|
||||
visibility: hidden;
|
||||
transition: height .1s ease-in-out;
|
||||
display: flex;
|
||||
border-top: .1rem solid var(--primary-border);
|
||||
|
||||
&.expanded {
|
||||
height: 20rem;
|
||||
@@ -82,10 +79,11 @@
|
||||
|
||||
textarea {
|
||||
flex-grow: 1;
|
||||
border: 1px solid #444;
|
||||
border: 1px solid var(--secondary-border);
|
||||
border-radius: .2rem;
|
||||
background-color: #4a4a4a;
|
||||
background-color: #ddd;
|
||||
resize: none;
|
||||
padding: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,10 +92,8 @@
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
|
||||
max-width: 20%;
|
||||
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -108,14 +104,15 @@
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input, textarea, mat-icon, check-box {
|
||||
color: #fff;
|
||||
mat-icon {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TaskDisplayComponent } from './task-display.component';
|
||||
|
||||
describe('TaskDisplayComponent', () => {
|
||||
let component: TaskDisplayComponent;
|
||||
let fixture: ComponentFixture<TaskDisplayComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ TaskDisplayComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TaskDisplayComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,9 @@
|
||||
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { ConfirmDialogComponent, ConfirmDialogModel } from 'src/app/core/components/confirm-dialog/confirm-dialog.component';
|
||||
import { Task } from 'src/app/core/entity/task';
|
||||
import { TaskListService } from 'src/app/core/service/task-list.service';
|
||||
|
||||
@@ -21,6 +23,7 @@ export class TaskDisplayComponent implements AfterViewInit, OnDestroy {
|
||||
private _subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
private _dialog: MatDialog,
|
||||
private _taskListService: TaskListService
|
||||
) {}
|
||||
|
||||
@@ -74,7 +77,27 @@ export class TaskDisplayComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
delete(): void {
|
||||
if (this.task) {
|
||||
const confirmData = {
|
||||
title: `Supprimer la tâche ${this.task.title} ?`,
|
||||
description: 'Une fois supprimé, sa description sera perdue définitivement.',
|
||||
confirmButtonLabel: 'Supprimer la tâche',
|
||||
confirmButtonType: 'alert'
|
||||
} as ConfirmDialogModel;
|
||||
|
||||
const dialogRef = this._dialog.open(
|
||||
ConfirmDialogComponent,
|
||||
{
|
||||
width: '30rem',
|
||||
data: confirmData
|
||||
}
|
||||
);
|
||||
|
||||
const afterDialogCloseSubscription = dialogRef.afterClosed().subscribe(result => {
|
||||
if (result && this.task) {
|
||||
this._taskListService.delete(this.task);
|
||||
}
|
||||
})
|
||||
this._subscriptions.push(afterDialogCloseSubscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<div class="description">{{data.description}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="raised" (click)="cancel()">Annuler</button>
|
||||
<button class="raised"
|
||||
<div class="dialog-actions">
|
||||
<button class="stroked" (click)="cancel()">Annuler</button>
|
||||
<button class="stroked"
|
||||
(click)="confirm()"
|
||||
[ngClass]="data.confirmButtonType">
|
||||
{{data.confirmButtonLabel}}
|
||||
|
||||
@@ -32,14 +32,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> * {
|
||||
flex: 1 1 45%;
|
||||
max-width: 45%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,35 @@
|
||||
<nav *ngIf="!selectionMode">
|
||||
<div class="left">
|
||||
<span class="title">
|
||||
<img src="../../assets/images/to-do.png" />
|
||||
To Do
|
||||
</span>
|
||||
<button *ngIf="!activeTaskList"
|
||||
(click)="openNewListForm()"
|
||||
class="raised"
|
||||
class="stroked primary"
|
||||
matRipple>
|
||||
Nouvelle liste
|
||||
</button>
|
||||
<button *ngIf="activeTaskList"
|
||||
(click)="goTaskListsPane()"
|
||||
class="icon raised"
|
||||
class="icon stroked primary"
|
||||
matRipple
|
||||
matTooltip="Retourner aux task-lists">
|
||||
<mat-icon>chevron_left</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="middle" *ngIf="activeTaskList">
|
||||
{{activeTaskList.name}}
|
||||
</div>
|
||||
<div class="right">
|
||||
<button class="icon stroked primary"
|
||||
(click)="enableSelectionMode()"
|
||||
[disabled]="isNoAnyTaskList()"
|
||||
matTooltip="Activer la sélection des task-lists"
|
||||
matTooltipPosition="left">
|
||||
<mat-icon>checklist_rtl</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
<nav *ngIf="selectionMode" class="selectionMode">
|
||||
<div></div>
|
||||
@@ -23,6 +37,6 @@
|
||||
Cliquez sur une liste pour la sélectionner
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="raised" (click)="disableSelectionMode()">Annuler</button>
|
||||
<button class="stroked primary" (click)="disableSelectionMode()">Annuler</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -6,11 +6,36 @@ nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.2rem;
|
||||
background-color: #666;
|
||||
background-color: #eee;
|
||||
|
||||
.left {
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
&.selectionMode {
|
||||
font-weight: bold;
|
||||
background-color: #185eb4;
|
||||
background-color: var(--selection);
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -21,11 +46,4 @@ nav {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
margin: 0 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@@ -13,18 +13,15 @@ import { TaskListService } from '../../service/task-list.service';
|
||||
})
|
||||
export class HeaderComponent implements OnInit, OnDestroy {
|
||||
private _storeSubscription?: Subscription;
|
||||
activeTaskList?: TaskList;
|
||||
selectionMode = false;
|
||||
|
||||
constructor(
|
||||
private _dialog: MatDialog,
|
||||
private _router: Router,
|
||||
private _taskListService: TaskListService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._storeSubscription = this._taskListService.store$.subscribe(store => {
|
||||
this.activeTaskList = store.taskLists.find(taskList => store.activeTaskListId === taskList.id);
|
||||
this.selectionMode = store.selectionMode;
|
||||
});
|
||||
}
|
||||
@@ -46,7 +43,19 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
||||
this._taskListService.removeActiveTaskList();
|
||||
}
|
||||
|
||||
enableSelectionMode(): void {
|
||||
this._taskListService.enableSelectionMode();
|
||||
}
|
||||
|
||||
disableSelectionMode(): void {
|
||||
this._taskListService.disableSelectionMode();
|
||||
}
|
||||
|
||||
isNoAnyTaskList(): boolean {
|
||||
return this._taskListService.isNoAnyTaskList();
|
||||
}
|
||||
|
||||
get activeTaskList(): TaskList | undefined {
|
||||
return this._taskListService.activeTaskList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { Store } from "../entity/store";
|
||||
import { Router } from "@angular/router";
|
||||
import { MatSnackBar } from "@angular/material/snack-bar";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -16,6 +17,7 @@ export class TaskListService {
|
||||
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _snackBar: MatSnackBar,
|
||||
private _storePersistenceService: StorePersistenceService
|
||||
) {
|
||||
this.store$.subscribe(store => {
|
||||
@@ -67,6 +69,7 @@ export class TaskListService {
|
||||
|
||||
activeTaskList?.tasks.push(newTask);
|
||||
this.saveStore(store);
|
||||
this._snackBar.open('Tâche ajoutée.', 'Fermer', {duration: 2000});
|
||||
}
|
||||
|
||||
updateTask(taskToUpdate: Task) {
|
||||
@@ -103,6 +106,7 @@ export class TaskListService {
|
||||
|
||||
activeTaskList?.tasks.splice(taskIndex, 1);
|
||||
this.saveStore(store);
|
||||
this._snackBar.open('Tâche supprimée.', 'Fermer', {duration: 2000});
|
||||
}
|
||||
|
||||
createTaskList(taskListName: string): void {
|
||||
@@ -207,4 +211,13 @@ export class TaskListService {
|
||||
get selectedTaskList(): TaskList {
|
||||
return this._store.value?.selectedTaskLists[0];
|
||||
}
|
||||
|
||||
isNoAnyTaskList(): boolean {
|
||||
return !this.store?.taskLists?.length;
|
||||
}
|
||||
|
||||
get activeTaskList(): TaskList | undefined {
|
||||
const store = this.store;
|
||||
return store.taskLists.find(taskList => taskList.id === store.activeTaskListId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button class="raised" type="button" (click)="close()">Annuler</button>
|
||||
<button class="raised" type="submit">Créer une liste</button>
|
||||
<div class="dialog-actions">
|
||||
<button class="stroked primary" type="button" (click)="close()">Annuler</button>
|
||||
<button class="stroked primary" type="submit">Créer une liste</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -4,9 +4,4 @@ form {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button class="raised" type="button" (click)="close()">Annuler</button>
|
||||
<button class="raised" type="submit">Renommer la liste</button>
|
||||
<div class="dialog-actions">
|
||||
<button class="stroked" type="button" (click)="close()">Annuler</button>
|
||||
<button class="stroked" type="submit">Renommer la liste</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -4,9 +4,4 @@ form {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="selection-actions" *ngIf="isSelectionModeEnabled()">
|
||||
<button class="raised"
|
||||
<button class="stroked"
|
||||
[disabled]="isThereMultipleTaskListsSelected()"
|
||||
(click)="renameSelectedTaskList()">
|
||||
Renommer
|
||||
</button>
|
||||
<button class="raised alert"
|
||||
<button class="stroked alert"
|
||||
(click)="deleteSelectedTaskLists()">Supprimer</button>
|
||||
</div>
|
||||
@@ -62,7 +62,7 @@ export class TaskListsComponent implements OnInit, OnDestroy {
|
||||
this._dialog.open(
|
||||
RenameTaskListComponent,
|
||||
{
|
||||
width: '20rem'
|
||||
width: '25rem'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
102
src/styles.scss
102
src/styles.scss
@@ -1,25 +1,50 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
:root {
|
||||
--primary: #fff;
|
||||
--primary-text: #444444;
|
||||
--primary-border: #ccc;
|
||||
--primary-hover: #eee;
|
||||
--secondary: #eee;
|
||||
--secondary-hover: #c9c9c9;
|
||||
--secondary-border: #bbb;
|
||||
|
||||
--disabled: #eee;
|
||||
--disabled-text: #aaa;
|
||||
|
||||
--transparent: rgba(0,0,0, 0);
|
||||
|
||||
--shadow-1: rgba(0, 0, 0, 0.2);
|
||||
--shadow-2: rgba(0, 0, 0, 0.14);
|
||||
--shadow-3: rgba(0, 0, 0, 0.12);
|
||||
--shadow-hover: #777;
|
||||
|
||||
--alert: #eb1d3f;
|
||||
--alert-text: #fff;
|
||||
--alert-hover: #c20d2b;
|
||||
--alert-border: #b91b35;
|
||||
|
||||
--selection: #185eb4;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
padding-top: 3.2rem;
|
||||
background-color: #555;
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.shadowed {
|
||||
box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2),0px 1px 1px 0px rgba(0, 0, 0, 0.14),0px 1px 3px 0px rgba(0, 0, 0, 0.12);
|
||||
box-shadow: 0px 2px 1px -1px var(--shadow-1),
|
||||
0px 1px 1px 0px var(--shadow-2),
|
||||
0px 1px 3px 0px var(--shadow-3);
|
||||
transition: box-shadow .2s ease-out;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 .2em .5em #777;
|
||||
box-shadow: 0 .2em .5em var(--shadow-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,29 +53,31 @@ a.no-style {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
button {
|
||||
border-style: solid;
|
||||
border-width: .1rem;
|
||||
border-color: rgba(0,0,0, 0);
|
||||
border-color: var(--transparent);
|
||||
border-radius: .2rem;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
padding: .5rem;
|
||||
color: #fff;
|
||||
background-color: var(--transparent);
|
||||
color: var(--primary-text);
|
||||
|
||||
transition: background-color .2s ease-out,
|
||||
border-color .2s ease-out;
|
||||
|
||||
&:hover {
|
||||
background-color: #666;
|
||||
border-color: rgb(53, 53, 53);
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #aaa;
|
||||
color: #ccc;
|
||||
background-color: var(--disabled);
|
||||
color: var(--disabled-text);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -60,20 +87,53 @@ button {
|
||||
min-width: 1rem;
|
||||
min-height: 1rem;
|
||||
padding: 0;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
&.raised {
|
||||
background-color: #4a4a4a;
|
||||
background-color: var(--primary); //#4a4a4a;
|
||||
box-shadow: 0px 2px 1px -1px var(--shadow-1),
|
||||
0px 1px 1px 0px var(--shadow-2),
|
||||
0px 1px 3px 0px var(--shadow-3);
|
||||
}
|
||||
|
||||
&.stroked {
|
||||
border-color: var(--primary-border);
|
||||
|
||||
&.primary {
|
||||
background-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: var(--secondary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--secondary-hover)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.alert {
|
||||
background: #F93154;
|
||||
color: #fff;
|
||||
background-color: var(--alert);
|
||||
color: var(--alert-text);
|
||||
|
||||
:hover {
|
||||
background-color: #f83e5d;
|
||||
border-color: #b91b35;
|
||||
&:hover {
|
||||
background-color: var(--alert-hover);
|
||||
border-color: var(--alert-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> * {
|
||||
flex: 1 1 45%;
|
||||
max-width: 45%;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user