mirror of
https://github.com/opelly27/WinStudentGoalTracker.git
synced 2026-05-20 05:17:41 +00:00
visual cleanup
This commit is contained in:
@@ -29,13 +29,13 @@
|
||||
<span class="student-iep">IEP {{ formatDate(student()!.nextIepDate) }}</span>
|
||||
</div>
|
||||
<div class="goal-tabs">
|
||||
<button class="goal-tab add-goal" (click)="onAddGoal()">+ Goal</button>
|
||||
@for (g of goals(); track g.goalId) {
|
||||
<button class="goal-tab" [class.active]="selectedGoalId() === g.goalId || (selectedGoal()?.goalId === g.goalId)"
|
||||
(click)="onSelectGoal(g.goalId)">
|
||||
{{ g.category }}
|
||||
</button>
|
||||
}
|
||||
<button class="goal-tab add-goal" (click)="onAddGoal()">+ Goal</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -46,15 +46,15 @@
|
||||
<div class="goal-card">
|
||||
<div class="goal-card-header">
|
||||
<span class="goal-badge">{{ selectedGoal()!.category }} Goal</span>
|
||||
@if (selectedGoal()!.targetCompletionDate) {
|
||||
<span class="goal-due">Due {{ formatDate(selectedGoal()!.targetCompletionDate) }}</span>
|
||||
}
|
||||
<button class="edit-icon" (click)="onEditGoal()" aria-label="Edit goal">
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="#999" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11.5 1.5l3 3L5 14H2v-3L11.5 1.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
@if (selectedGoal()!.targetCompletionDate) {
|
||||
<span class="goal-due">Due {{ formatDate(selectedGoal()!.targetCompletionDate) }}</span>
|
||||
}
|
||||
</div>
|
||||
<p class="goal-description">{{ selectedGoal()!.description }}</p>
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,7 @@ export class Workspace {
|
||||
const goalId = params.get('goalId');
|
||||
|
||||
if (studentId && studentId !== this.studentId()) {
|
||||
this.selectedGoalId.set(null);
|
||||
this.studentId.set(studentId);
|
||||
this.loadStudentData(studentId);
|
||||
} else if (!studentId) {
|
||||
|
||||
@@ -28,7 +28,11 @@
|
||||
</div>
|
||||
|
||||
<div class="student-list">
|
||||
@for (s of students(); track s.studentId) {
|
||||
@for (group of groupedStudents(); track group.label) {
|
||||
@if (group.label) {
|
||||
<div class="group-header">{{ group.label }}</div>
|
||||
}
|
||||
@for (s of group.students; track s.studentId) {
|
||||
<div class="student-item" [class.active]="selectedStudentId() === s.studentId"
|
||||
(click)="onSelectStudent(s)">
|
||||
<div class="student-item-info">
|
||||
@@ -37,9 +41,6 @@
|
||||
</div>
|
||||
<div class="student-item-meta">
|
||||
IEP: {{ formatDate(s.nextIepDate) }}
|
||||
@if (showAll() && s.ownerName) {
|
||||
<span class="owner-tag">· {{ s.ownerName }}</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<button class="edit-pencil" (click)="onEditStudent(s, $event)" aria-label="Edit student">
|
||||
@@ -50,6 +51,7 @@
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
|
||||
@@ -97,6 +97,22 @@
|
||||
padding: 0 8px 8px;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--text-faint);
|
||||
padding: 12px 12px 4px;
|
||||
margin-top: 4px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.student-item {
|
||||
padding: 10px 12px;
|
||||
border-radius: var(--radius-lg);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, effect, inject, signal } from '@angular/core';
|
||||
import { Component, computed, effect, inject, signal } from '@angular/core';
|
||||
import { RouterLink, RouterOutlet, Router } from '@angular/router';
|
||||
import { Auth } from '../../../shared/services/auth';
|
||||
import { StudentService } from '../../../shared/services/student.service';
|
||||
@@ -42,6 +42,39 @@ export class Home {
|
||||
protected readonly showAddStudentModal = signal(false);
|
||||
protected readonly editingStudent = signal<StudentCardDto | null>(null);
|
||||
|
||||
// Groups students by owner when "All" is active.
|
||||
protected readonly groupedStudents = computed(() => {
|
||||
const all = this.students();
|
||||
if (!this.showAll()) {
|
||||
return [{ label: null, students: all }];
|
||||
}
|
||||
|
||||
const mine = all.filter(s => s.isMine);
|
||||
const others = all.filter(s => !s.isMine);
|
||||
|
||||
// Group others by ownerName.
|
||||
const byOwner = new Map<string, StudentCardDto[]>();
|
||||
for (const s of others) {
|
||||
const key = s.ownerName || 'Unknown';
|
||||
const list = byOwner.get(key) || [];
|
||||
list.push(s);
|
||||
byOwner.set(key, list);
|
||||
}
|
||||
|
||||
const groups: { label: string | null; students: StudentCardDto[] }[] = [];
|
||||
if (mine.length) {
|
||||
groups.push({ label: 'My Students', students: mine });
|
||||
}
|
||||
// Sort other teachers alphabetically.
|
||||
const sortedKeys = [...byOwner.keys()].sort((a, b) =>
|
||||
a.localeCompare(b, undefined, { sensitivity: 'base' })
|
||||
);
|
||||
for (const key of sortedKeys) {
|
||||
groups.push({ label: key, students: byOwner.get(key)! });
|
||||
}
|
||||
return groups;
|
||||
});
|
||||
|
||||
// ************************ Event Handlers *************************
|
||||
|
||||
onSelectStudent(student: StudentCardDto) {
|
||||
|
||||
Reference in New Issue
Block a user