extract html & css
This commit is contained in:
parent
479b41cb8f
commit
df119dcc03
181
src/app/app.component.css
Normal file
181
src/app/app.component.css
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/* ── Layout ──────────────────────────────────────────── */
|
||||||
|
.container {
|
||||||
|
max-width: 640px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 0 1rem;
|
||||||
|
font-family: inherit; /* übernimmt Font aus styles.css */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Header ──────────────────────────────────────────── */
|
||||||
|
.app-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.app-header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
margin: 0.25rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Fehlermeldung ───────────────────────────────────── */
|
||||||
|
.error-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: #fee2e2;
|
||||||
|
border: 1px solid #fca5a5;
|
||||||
|
color: #b91c1c;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.close-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #b91c1c;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Formular ────────────────────────────────────────── */
|
||||||
|
.add-form {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
.add-form input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.6rem 0.8rem;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.add-form input:focus {
|
||||||
|
border-color: #2563eb;
|
||||||
|
}
|
||||||
|
.add-form button {
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
background: #2563eb;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
.add-form button:hover:not(:disabled) {
|
||||||
|
background: #1d4ed8;
|
||||||
|
}
|
||||||
|
.add-form button:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Ladeindikator ───────────────────────────────────── */
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
color: #6b7280;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── ToDo-Liste ──────────────────────────────────────── */
|
||||||
|
.todo-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
.todo-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
.todo-item:hover {
|
||||||
|
background: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abgehaktes ToDo: Text wird durchgestrichen und ausgegraut */
|
||||||
|
.todo-item.completed .todo-title {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-item input[type="checkbox"] {
|
||||||
|
width: 1.1rem;
|
||||||
|
height: 1.1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.todo-title {
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.user-badge {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: #6b7280;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border-radius: 99px;
|
||||||
|
padding: 0.15rem 0.5rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.delete-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #d1d5db;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.25rem;
|
||||||
|
line-height: 1;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
.delete-btn:hover {
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Pagination ──────────────────────────────────────── */
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
.pagination button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
.pagination button:hover:not(:disabled) {
|
||||||
|
background: #f3f4f6;
|
||||||
|
}
|
||||||
|
.pagination button:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.page-info {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
109
src/app/app.component.html
Normal file
109
src/app/app.component.html
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<header class="app-header">
|
||||||
|
<h1>ToDo-App</h1>
|
||||||
|
<p class="subtitle">Angular 21 · Vite · REST-API</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- ======================================================
|
||||||
|
FEHLERMELDUNG
|
||||||
|
*ngIf zeigt das Element nur an, wenn "error" einen Wert hat.
|
||||||
|
====================================================== -->
|
||||||
|
<div class="error-box" *ngIf="error">
|
||||||
|
<strong>Fehler:</strong> {{ error }}
|
||||||
|
<button class="close-btn" (click)="error = ''">✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ======================================================
|
||||||
|
FORMULAR – Neues ToDo hinzufügen
|
||||||
|
(ngSubmit): Ruft addTodo() beim Absenden auf.
|
||||||
|
[(ngModel)]: Two-Way-Binding – verbindet Input mit "newTitle".
|
||||||
|
[disabled]: Deaktiviert Button, wenn Feld leer ist.
|
||||||
|
====================================================== -->
|
||||||
|
<form class="add-form" (ngSubmit)="addTodo()">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="newTitle"
|
||||||
|
name="newTitle"
|
||||||
|
placeholder="Neues ToDo eingeben..."
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<button type="submit" [disabled]="!newTitle.trim() || saving">
|
||||||
|
{{ saving ? 'Speichert…' : '+ Hinzufügen' }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- ======================================================
|
||||||
|
LADEINDIKATOR
|
||||||
|
Wird angezeigt, während Daten von der API geladen werden.
|
||||||
|
====================================================== -->
|
||||||
|
<div class="loading" *ngIf="loading">Daten werden geladen…</div>
|
||||||
|
|
||||||
|
<!-- ======================================================
|
||||||
|
TODO-LISTE
|
||||||
|
*ngFor iteriert über das todos-Array und rendert ein <li> pro Eintrag.
|
||||||
|
"let todo of todos" → todo ist die aktuelle Variable im Loop.
|
||||||
|
[class.completed]: Fügt CSS-Klasse hinzu, wenn todo.completed === true.
|
||||||
|
====================================================== -->
|
||||||
|
<ul class="todo-list" *ngIf="!loading">
|
||||||
|
|
||||||
|
<!-- Meldung, wenn keine Todos vorhanden -->
|
||||||
|
<li class="empty-state" *ngIf="todos.length === 0">
|
||||||
|
Keine ToDos auf dieser Seite.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li
|
||||||
|
*ngFor="let todo of todos"
|
||||||
|
class="todo-item"
|
||||||
|
[class.completed]="todo.completed"
|
||||||
|
>
|
||||||
|
<!-- Checkbox: (change) reagiert auf Änderung und ruft toggleTodo() auf -->
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
[checked]="todo.completed"
|
||||||
|
(change)="toggleTodo(todo)"
|
||||||
|
[id]="'todo-' + todo.id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Label verknüpft Text mit der Checkbox über das id-Attribut -->
|
||||||
|
<label [for]="'todo-' + todo.id" class="todo-title">
|
||||||
|
{{ todo.title }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Badge zeigt die User-ID an -->
|
||||||
|
<span class="user-badge">User {{ todo.userId }}</span>
|
||||||
|
|
||||||
|
<!-- Löschen-Button: (click) ruft deleteTodo() mit der ID auf -->
|
||||||
|
<button
|
||||||
|
class="delete-btn"
|
||||||
|
(click)="deleteTodo(todo.id)"
|
||||||
|
title="ToDo löschen"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- ======================================================
|
||||||
|
PAGINATION
|
||||||
|
[disabled]: Deaktiviert Buttons an den Rändern der Liste.
|
||||||
|
====================================================== -->
|
||||||
|
<div class="pagination" *ngIf="!loading">
|
||||||
|
<button
|
||||||
|
(click)="prevPage()"
|
||||||
|
[disabled]="currentPage === 1"
|
||||||
|
>
|
||||||
|
← Zurück
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span class="page-info">Seite {{ currentPage }}</span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="nextPage()"
|
||||||
|
[disabled]="todos.length < pageSize"
|
||||||
|
>
|
||||||
|
Weiter →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@ -25,303 +25,9 @@ import { Todo } from './todo.model';
|
|||||||
// imports: Andere Angular-Module/Komponenten, die im Template verwendet werden
|
// imports: Andere Angular-Module/Komponenten, die im Template verwendet werden
|
||||||
imports: [CommonModule, FormsModule],
|
imports: [CommonModule, FormsModule],
|
||||||
|
|
||||||
// template: Das HTML-Template der Komponente (inline, kein separates File)
|
// Template und Styles sind ausgelagert für bessere Wartbarkeit
|
||||||
template: `
|
templateUrl: './app.component.html',
|
||||||
<div class="container">
|
styleUrl: './app.component.css',
|
||||||
|
|
||||||
<header class="app-header">
|
|
||||||
<h1>ToDo-App</h1>
|
|
||||||
<p class="subtitle">Angular 21 · Vite · REST-API</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- ======================================================
|
|
||||||
FEHLERMELDUNG
|
|
||||||
*ngIf zeigt das Element nur an, wenn "error" einen Wert hat.
|
|
||||||
====================================================== -->
|
|
||||||
<div class="error-box" *ngIf="error">
|
|
||||||
<strong>Fehler:</strong> {{ error }}
|
|
||||||
<button class="close-btn" (click)="error = ''">✕</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ======================================================
|
|
||||||
FORMULAR – Neues ToDo hinzufügen
|
|
||||||
(ngSubmit): Ruft addTodo() beim Absenden auf.
|
|
||||||
[(ngModel)]: Two-Way-Binding – verbindet Input mit "newTitle".
|
|
||||||
[disabled]: Deaktiviert Button, wenn Feld leer ist.
|
|
||||||
====================================================== -->
|
|
||||||
<form class="add-form" (ngSubmit)="addTodo()">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
[(ngModel)]="newTitle"
|
|
||||||
name="newTitle"
|
|
||||||
placeholder="Neues ToDo eingeben..."
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
<button type="submit" [disabled]="!newTitle.trim() || saving">
|
|
||||||
{{ saving ? 'Speichert…' : '+ Hinzufügen' }}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- ======================================================
|
|
||||||
LADEINDIKATOR
|
|
||||||
Wird angezeigt, während Daten von der API geladen werden.
|
|
||||||
====================================================== -->
|
|
||||||
<div class="loading" *ngIf="loading">Daten werden geladen…</div>
|
|
||||||
|
|
||||||
<!-- ======================================================
|
|
||||||
TODO-LISTE
|
|
||||||
*ngFor iteriert über das todos-Array und rendert ein <li> pro Eintrag.
|
|
||||||
"let todo of todos" → todo ist die aktuelle Variable im Loop.
|
|
||||||
[class.completed]: Fügt CSS-Klasse hinzu, wenn todo.completed === true.
|
|
||||||
====================================================== -->
|
|
||||||
<ul class="todo-list" *ngIf="!loading">
|
|
||||||
|
|
||||||
<!-- Meldung, wenn keine Todos vorhanden -->
|
|
||||||
<li class="empty-state" *ngIf="todos.length === 0">
|
|
||||||
Keine ToDos auf dieser Seite.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li
|
|
||||||
*ngFor="let todo of todos"
|
|
||||||
class="todo-item"
|
|
||||||
[class.completed]="todo.completed"
|
|
||||||
>
|
|
||||||
<!-- Checkbox: (change) reagiert auf Änderung und ruft toggleTodo() auf -->
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
[checked]="todo.completed"
|
|
||||||
(change)="toggleTodo(todo)"
|
|
||||||
[id]="'todo-' + todo.id"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Label verknüpft Text mit der Checkbox über das id-Attribut -->
|
|
||||||
<label [for]="'todo-' + todo.id" class="todo-title">
|
|
||||||
{{ todo.title }}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<!-- Badge zeigt die User-ID an -->
|
|
||||||
<span class="user-badge">User {{ todo.userId }}</span>
|
|
||||||
|
|
||||||
<!-- Löschen-Button: (click) ruft deleteTodo() mit der ID auf -->
|
|
||||||
<button
|
|
||||||
class="delete-btn"
|
|
||||||
(click)="deleteTodo(todo.id)"
|
|
||||||
title="ToDo löschen"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- ======================================================
|
|
||||||
PAGINATION
|
|
||||||
[disabled]: Deaktiviert Buttons an den Rändern der Liste.
|
|
||||||
====================================================== -->
|
|
||||||
<div class="pagination" *ngIf="!loading">
|
|
||||||
<button
|
|
||||||
(click)="prevPage()"
|
|
||||||
[disabled]="currentPage === 1"
|
|
||||||
>
|
|
||||||
← Zurück
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<span class="page-info">Seite {{ currentPage }}</span>
|
|
||||||
|
|
||||||
<button
|
|
||||||
(click)="nextPage()"
|
|
||||||
[disabled]="todos.length < pageSize"
|
|
||||||
>
|
|
||||||
Weiter →
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
|
|
||||||
// styles: Komponenten-spezifisches CSS (ist automatisch auf diese Komponente begrenzt)
|
|
||||||
styles: [`
|
|
||||||
/* ── Layout ──────────────────────────────────────────── */
|
|
||||||
.container {
|
|
||||||
max-width: 640px;
|
|
||||||
margin: 2rem auto;
|
|
||||||
padding: 0 1rem;
|
|
||||||
font-family: inherit; /* übernimmt Font aus styles.css */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Header ──────────────────────────────────────────── */
|
|
||||||
.app-header {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
.app-header h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.subtitle {
|
|
||||||
color: #888;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
margin: 0.25rem 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Fehlermeldung ───────────────────────────────────── */
|
|
||||||
.error-box {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
background: #fee2e2;
|
|
||||||
border: 1px solid #fca5a5;
|
|
||||||
color: #b91c1c;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.close-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #b91c1c;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Formular ────────────────────────────────────────── */
|
|
||||||
.add-form {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
.add-form input {
|
|
||||||
flex: 1;
|
|
||||||
padding: 0.6rem 0.8rem;
|
|
||||||
border: 1px solid #d1d5db;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1rem;
|
|
||||||
outline: none;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
.add-form input:focus {
|
|
||||||
border-color: #2563eb;
|
|
||||||
}
|
|
||||||
.add-form button {
|
|
||||||
padding: 0.6rem 1.2rem;
|
|
||||||
background: #2563eb;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
.add-form button:hover:not(:disabled) {
|
|
||||||
background: #1d4ed8;
|
|
||||||
}
|
|
||||||
.add-form button:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Ladeindikator ───────────────────────────────────── */
|
|
||||||
.loading {
|
|
||||||
text-align: center;
|
|
||||||
color: #6b7280;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── ToDo-Liste ──────────────────────────────────────── */
|
|
||||||
.todo-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
.empty-state {
|
|
||||||
text-align: center;
|
|
||||||
color: #9ca3af;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
.todo-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #e5e7eb;
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
.todo-item:hover {
|
|
||||||
background: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Abgehaktes ToDo: Text wird durchgestrichen und ausgegraut */
|
|
||||||
.todo-item.completed .todo-title {
|
|
||||||
text-decoration: line-through;
|
|
||||||
color: #9ca3af;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-item input[type="checkbox"] {
|
|
||||||
width: 1.1rem;
|
|
||||||
height: 1.1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
.todo-title {
|
|
||||||
flex: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.user-badge {
|
|
||||||
font-size: 0.7rem;
|
|
||||||
color: #6b7280;
|
|
||||||
background: #f3f4f6;
|
|
||||||
border-radius: 99px;
|
|
||||||
padding: 0.15rem 0.5rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.delete-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #d1d5db;
|
|
||||||
font-size: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.25rem;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 4px;
|
|
||||||
transition: color 0.15s;
|
|
||||||
}
|
|
||||||
.delete-btn:hover {
|
|
||||||
color: #ef4444;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Pagination ──────────────────────────────────────── */
|
|
||||||
.pagination {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
}
|
|
||||||
.pagination button {
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border: 1px solid #d1d5db;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
.pagination button:hover:not(:disabled) {
|
|
||||||
background: #f3f4f6;
|
|
||||||
}
|
|
||||||
.pagination button:disabled {
|
|
||||||
opacity: 0.4;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
.page-info {
|
|
||||||
color: #6b7280;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
`],
|
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user