This commit is contained in:
ExostFlash 2026-01-22 16:04:27 +01:00
parent 5b2f25b6bd
commit a05062f989
5 changed files with 725 additions and 604 deletions

1173
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,105 @@
ul {
list-style: none;
padding: 0;
}
li {
display: flex;
align-items: flex-start;
gap: 0.8em;
padding: 0.8em 1em;
margin: 0.5em 0;
background: #f9f9f9;
border-radius: 6px;
border: 1px solid #e0e0e0;
transition: all 0.3s ease;
}
li.validated {
opacity: 0.5;
background: #f0f0f0;
}
li.highlighted {
background: #fff8dc;
border: 2px solid #ffa500;
box-shadow: 0 2px 6px rgba(255, 165, 0, 0.3);
font-weight: 600;
}
li span {
flex: 1;
transition: all 0.2s;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-word;
min-width: 0;
}
.validated-text {
text-decoration: line-through;
color: #999;
}
input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
flex-shrink: 0;
margin-top: 0.2em;
}
.highlight-btn {
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 1.1em;
padding: 0.1em 0.3em;
border-radius: 4px;
flex-shrink: 0;
transition:
background 0.2s,
color 0.2s;
}
.highlight-btn:hover:not(:disabled) {
background: #fff8dc;
color: #ffa500;
}
.highlight-btn.active {
color: #ffa500;
}
.highlight-btn.active:hover {
background: #ffe4b3;
color: #ff8c00;
}
.highlight-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.trash-btn { .trash-btn {
background: none; background: none;
border: none; border: none;
cursor: pointer; cursor: pointer;
color: #c00; color: #666;
font-size: 1.1em; font-size: 1.1em;
padding: 0.1em 0.3em; padding: 0.1em 0.3em;
border-radius: 4px; border-radius: 4px;
transition: background 0.2s, color 0.2s; flex-shrink: 0;
transition:
background 0.2s,
color 0.2s;
} }
.trash-btn:hover { .trash-btn:hover {
background: #ffeaea; background: #ffeaea;
color: #fff; color: #c00;
} }
.trash-btn:hover svg { .trash-btn:hover svg {
color: #fff; color: #c00;
fill: #fff; fill: #c00;
} }

View file

@ -4,8 +4,16 @@
@if (tasks$ | async; as tasks) { @if (tasks$ | async; as tasks) {
<ul> <ul>
@for (task of tasks; track task) { @for (task of tasks; track task) {
<li> <li [class.validated]="task.validated" [class.highlighted]="task.highlighted">
<span>{{ task.title }}</span> <input type="checkbox" [checked]="task.validated" (change)="toggleValidated(task.id)" title="Mark as validated" />
<span [class.validated-text]="task.validated">{{ task.title }}</span>
<button class="highlight-btn" [class.active]="task.highlighted" [disabled]="task.validated" (click)="toggleHighlighted(task.id)" [title]="task.highlighted ? 'Remove highlight' : 'Highlight task'">
@if (task.highlighted) {
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="20" height="20" style="display:inline-block;vertical-align:middle;fill:currentColor;"><path d="M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39c-8.4 1.67-17.12 2.61-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z"/></svg>
} @else {
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" width="20" height="20" style="display:inline-block;vertical-align:middle;fill:currentColor;"><path d="M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z"/></svg>
}
</button>
<button class="trash-btn" (click)="removeTask(task.id)" title="Delete task"> <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> <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> </button>

View file

@ -55,4 +55,12 @@ export class TasksPageComponent {
addTask(title: string) { addTask(title: string) {
this.taskService.addTask(title); this.taskService.addTask(title);
} }
toggleValidated(id: number) {
this.taskService.toggleValidated(id);
}
toggleHighlighted(id: number) {
this.taskService.toggleHighlighted(id);
}
} }

View file

@ -5,6 +5,8 @@ import { delay } from 'rxjs/operators';
export interface TaskItem { export interface TaskItem {
id: number; id: number;
title: string; title: string;
validated: boolean;
highlighted: boolean;
} }
@Injectable({ @Injectable({
@ -12,9 +14,9 @@ export interface TaskItem {
}) })
export class TaskService { export class TaskService {
private tasks = [ private tasks = [
{ id: 1, title: 'Sample Task' }, { id: 1, title: 'Sample Task', validated: false, highlighted: false },
{ id: 2, title: 'Another Task' }, { id: 2, title: 'Another Task', validated: false, highlighted: false },
{ id: 3, title: 'More Tasks' } { id: 3, title: 'More Tasks', validated: false, highlighted: false }
]; ];
private nextId = this.tasks.length > 0 ? Math.max(...this.tasks.map(t => t.id)) + 1 : 1; private nextId = this.tasks.length > 0 ? Math.max(...this.tasks.map(t => t.id)) + 1 : 1;
@ -26,7 +28,7 @@ export class TaskService {
tasks$ = this.tasksSubject.asObservable(); tasks$ = this.tasksSubject.asObservable();
addTask(title: string) { addTask(title: string) {
const newTask: TaskItem = { id: this.nextId++, title: title.trim() }; const newTask: TaskItem = { id: this.nextId++, title: title.trim(), validated: false, highlighted: false };
this.tasks.push(newTask); this.tasks.push(newTask);
this.tasksSubject.next([...this.tasks]); this.tasksSubject.next([...this.tasks]);
} }
@ -35,4 +37,35 @@ export class TaskService {
this.tasks = this.tasks.filter(task => task.id !== id); this.tasks = this.tasks.filter(task => task.id !== id);
this.tasksSubject.next([...this.tasks]); this.tasksSubject.next([...this.tasks]);
} }
toggleValidated(id: number) {
const task = this.tasks.find(t => t.id === id);
if (task) {
task.validated = !task.validated;
// Si on valide la tâche, on retire le highlight
if (task.validated) {
task.highlighted = false;
}
this.tasksSubject.next([...this.tasks]);
}
}
toggleHighlighted(id: number) {
const task = this.tasks.find(t => t.id === id);
if (task) {
// Ne pas permettre de mettre en avant une tâche validée
if (task.validated) {
return;
}
// Retirer le highlight de toutes les autres tâches
this.tasks.forEach(t => {
if (t.id !== id) {
t.highlighted = false;
}
});
// Toggle le highlight de la tâche actuelle
task.highlighted = !task.highlighted;
this.tasksSubject.next([...this.tasks]);
}
}
} }