Sidebar-Kompaktmodus polieren, Dashboard-Kalender ergänzen

- MainWindow: App-Titel durch ein kompaktes Logo-Badge ersetzt; im
  minimierten Zustand der Sidebar werden Nav-Icons automatisch größer
  und zentriert, Beschriftungen sowie Abschnittsüberschriften blenden
  aus (Classes-Binding auf DrawerPage.IsOpen).
- LearningGroup.IsOwnClass: neues Feld, per Checkbox im Gruppen-Dialog
  editierbar ("Gehört zu meiner Klasse"), mehrere Gruppen markierbar.
- Dashboard: kleiner Monatskalender mit Monatsnavigation, dezenter
  Einfärbung für Unterrichtstage, Klausur-Marker und Rahmen-Hervor-
  hebung für Tage der eigenen Klasse, inkl. Tooltip und Legende.
  Feste Kartenposition/-breite, damit weder Monatsnamenlänge noch die
  wachsende Lerngruppen-Liste das Layout verschieben.
- TODO.md: geplante Kalender-Detailansicht (Tag auswählen → Termine
  des Tages mit Sprung in die jeweilige Ansicht) unter 9.8 vermerkt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 00:14:28 +02:00
co-authored by Claude Sonnet 5
parent 8cbd4475d7
commit d00cea0bfe
7 changed files with 329 additions and 29 deletions
+1
View File
@@ -12,6 +12,7 @@ public class LearningGroup
public GradingSystem GradingSystem { get; set; } public GradingSystem GradingSystem { get; set; }
public int? HoursPerWeek { get; set; } public int? HoursPerWeek { get; set; }
public bool IsActive { get; set; } = true; public bool IsActive { get; set; } = true;
public bool IsOwnClass { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
} }
@@ -10,34 +10,44 @@ namespace LehrerApp.Desktop.ViewModels;
public partial class DashboardViewModel : ObservableObject public partial class DashboardViewModel : ObservableObject
{ {
private static readonly CultureInfo De = new("de-DE");
private readonly IGroupRepository _groups; private readonly IGroupRepository _groups;
private readonly ILessonRepository _lessons; private readonly ILessonRepository _lessons;
private readonly IExamRepository _exams;
private readonly IWorkTaskRepository _tasks; private readonly IWorkTaskRepository _tasks;
private readonly SchoolYearService _sy; private readonly SchoolYearService _sy;
[ObservableProperty] private string _greeting = ""; [ObservableProperty] private string _greeting = "";
[ObservableProperty] private string _currentDate = ""; [ObservableProperty] private string _currentDate = "";
[ObservableProperty] private string _currentSchoolYear = ""; [ObservableProperty] private string _currentSchoolYear = "";
[ObservableProperty] private DateOnly _calendarMonth = FirstOfMonth(DateTime.Today);
public string CalendarMonthLabel => CalendarMonth.ToString("MMMM yyyy", De);
public ObservableCollection<LessonItem> TodaysLessons { get; } = []; public ObservableCollection<LessonItem> TodaysLessons { get; } = [];
public ObservableCollection<TaskItem> OpenTasks { get; } = []; public ObservableCollection<TaskItem> OpenTasks { get; } = [];
public ObservableCollection<GroupChip> CurrentGroups { get; } = []; public ObservableCollection<GroupChip> CurrentGroups { get; } = [];
public ObservableCollection<CalendarDayCell> CalendarDays { get; } = [];
public static string[] CalendarWeekdayHeaders { get; } = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
// Navigation-Callback wird von App.axaml.cs verdrahtet // Navigation-Callback wird von App.axaml.cs verdrahtet
public Action<Guid>? OnNavigateToGroup { get; set; } public Action<Guid>? OnNavigateToGroup { get; set; }
public DashboardViewModel(IGroupRepository groups, ILessonRepository lessons, public DashboardViewModel(IGroupRepository groups, ILessonRepository lessons,
IWorkTaskRepository tasks, SchoolYearService sy) IExamRepository exams, IWorkTaskRepository tasks, SchoolYearService sy)
{ {
_groups = groups; _lessons = lessons; _tasks = tasks; _sy = sy; _groups = groups; _lessons = lessons; _exams = exams; _tasks = tasks; _sy = sy;
Load(); Load();
} }
private static DateOnly FirstOfMonth(DateTime d) => new(d.Year, d.Month, 1);
private void Load() private void Load()
{ {
var now = DateTime.Now; var now = DateTime.Now;
var today = DateOnly.FromDateTime(now); var today = DateOnly.FromDateTime(now);
CurrentDate = now.ToString("dddd, d. MMMM yyyy", new CultureInfo("de-DE")); CurrentDate = now.ToString("dddd, d. MMMM yyyy", De);
CurrentSchoolYear = _sy.CurrentSchoolYear(); CurrentSchoolYear = _sy.CurrentSchoolYear();
Greeting = now.Hour < 12 ? "Guten Morgen" : now.Hour < 18 ? "Guten Tag" : "Guten Abend"; Greeting = now.Hour < 12 ? "Guten Morgen" : now.Hour < 18 ? "Guten Tag" : "Guten Abend";
@@ -61,12 +71,120 @@ public partial class DashboardViewModel : ObservableObject
CurrentGroups.Clear(); CurrentGroups.Clear();
foreach (var g in groups.Values.OrderBy(g => g.Name)) foreach (var g in groups.Values.OrderBy(g => g.Name))
CurrentGroups.Add(new() { GroupId = g.Id, Name = g.Name, Subject = g.Subject ?? "" }); CurrentGroups.Add(new() { GroupId = g.Id, Name = g.Name, Subject = g.Subject ?? "" });
CalendarMonth = FirstOfMonth(now);
LoadCalendar();
}
private void LoadCalendar()
{
CalendarDays.Clear();
var today = DateOnly.FromDateTime(DateTime.Today);
// Rasterstart: Montag der Woche, die den 1. des Monats enthält 6 Wochen (42 Tage) Raster.
var firstOfMonth = CalendarMonth;
var mondayOffset = ((int)firstOfMonth.DayOfWeek + 6) % 7; // Montag=0 ... Sonntag=6
var gridStart = firstOfMonth.AddDays(-mondayOffset);
var gridEnd = gridStart.AddDays(41);
var groups = _groups.GetBySchoolYear(_sy.CurrentSchoolYear());
var byDay = new Dictionary<DateOnly, DayAgg>();
DayAgg Agg(DateOnly d)
{
if (!byDay.TryGetValue(d, out var agg)) byDay[d] = agg = new DayAgg();
return agg;
}
foreach (var g in groups)
{
foreach (var lesson in _lessons.GetByGroupAndRange(g.Id, gridStart, gridEnd))
{
var agg = Agg(lesson.Date);
agg.HasLesson = true;
if (g.IsOwnClass) agg.IsOwnClassDay = true;
agg.Details.Add($"Unterricht: {g.Name}" +
(string.IsNullOrWhiteSpace(lesson.Topic) ? "" : $" {lesson.Topic}"));
}
foreach (var exam in _exams.GetByGroup(g.Id).Where(e => e.Date >= gridStart && e.Date <= gridEnd))
{
var agg = Agg(exam.Date);
agg.HasExam = true;
if (g.IsOwnClass) agg.IsOwnClassDay = true;
agg.Details.Add($"Klausur: {exam.Title} ({g.Name})");
}
}
for (var i = 0; i < 42; i++)
{
var date = gridStart.AddDays(i);
byDay.TryGetValue(date, out var agg);
CalendarDays.Add(new CalendarDayCell(date, date.Month == firstOfMonth.Month, date == today,
agg?.HasLesson ?? false, agg?.HasExam ?? false, agg?.IsOwnClassDay ?? false,
agg?.Details ?? []));
}
}
[RelayCommand]
private void PrevMonth()
{
CalendarMonth = CalendarMonth.AddMonths(-1);
OnPropertyChanged(nameof(CalendarMonthLabel));
LoadCalendar();
}
[RelayCommand]
private void NextMonth()
{
CalendarMonth = CalendarMonth.AddMonths(1);
OnPropertyChanged(nameof(CalendarMonthLabel));
LoadCalendar();
}
[RelayCommand]
private void CalendarToday()
{
CalendarMonth = FirstOfMonth(DateTime.Today);
OnPropertyChanged(nameof(CalendarMonthLabel));
LoadCalendar();
} }
[RelayCommand] private void OpenGroup(GroupChip? c) { if (c is not null) OnNavigateToGroup?.Invoke(c.GroupId); } [RelayCommand] private void OpenGroup(GroupChip? c) { if (c is not null) OnNavigateToGroup?.Invoke(c.GroupId); }
[RelayCommand] private void Refresh() => Load(); [RelayCommand] private void Refresh() => Load();
private class DayAgg
{
public bool HasLesson;
public bool HasExam;
public bool IsOwnClassDay;
public List<string> Details { get; } = [];
}
} }
public class LessonItem { public string GroupName { get; set; } = ""; public string Topic { get; set; } = ""; } public class LessonItem { public string GroupName { get; set; } = ""; public string Topic { get; set; } = ""; }
public class TaskItem { public string Title { get; set; } = ""; public string DueDate { get; set; } = ""; public bool IsOverdue { get; set; } } public class TaskItem { public string Title { get; set; } = ""; public string DueDate { get; set; } = ""; public bool IsOverdue { get; set; } }
public class GroupChip { public Guid GroupId { get; set; } public string Name { get; set; } = ""; public string Subject { get; set; } = ""; } public class GroupChip { public Guid GroupId { get; set; } public string Name { get; set; } = ""; public string Subject { get; set; } = ""; }
public class CalendarDayCell
{
public int DayNumber { get; }
public bool IsCurrentMonth { get; }
public bool IsToday { get; }
public bool HasLesson { get; }
public bool HasExam { get; }
public bool IsOwnClassDay { get; }
public string Tooltip { get; }
internal CalendarDayCell(DateOnly date, bool isCurrentMonth, bool isToday,
bool hasLesson, bool hasExam, bool isOwnClassDay, List<string> details)
{
DayNumber = date.Day;
IsCurrentMonth = isCurrentMonth;
IsToday = isToday;
HasLesson = hasLesson;
HasExam = hasExam;
IsOwnClassDay = isOwnClassDay;
Tooltip = details.Count == 0 ? date.ToString("dd.MM.yyyy") : string.Join("\n", details);
}
}
@@ -529,6 +529,7 @@ public partial class AddGroupDialogViewModel : ObservableObject
[ObservableProperty] private string _selectedGradingName = "Noten 16"; [ObservableProperty] private string _selectedGradingName = "Noten 16";
[ObservableProperty] private string _selectedSchoolYear = ""; [ObservableProperty] private string _selectedSchoolYear = "";
[ObservableProperty] private int? _hoursPerWeek; [ObservableProperty] private int? _hoursPerWeek;
[ObservableProperty] private bool _isOwnClass;
[ObservableProperty] private string _validationMessage = ""; [ObservableProperty] private string _validationMessage = "";
public List<string> SchoolYears { get; } public List<string> SchoolYears { get; }
@@ -565,6 +566,7 @@ public partial class AddGroupDialogViewModel : ObservableObject
? "Noten 16" : "Punkte 015"; ? "Noten 16" : "Punkte 015";
SelectedSchoolYear = group.SchoolYear; SelectedSchoolYear = group.SchoolYear;
HoursPerWeek = group.HoursPerWeek; HoursPerWeek = group.HoursPerWeek;
IsOwnClass = group.IsOwnClass;
OnPropertyChanged(nameof(DialogTitle)); OnPropertyChanged(nameof(DialogTitle));
OnPropertyChanged(nameof(SaveButtonText)); OnPropertyChanged(nameof(SaveButtonText));
} }
@@ -604,6 +606,7 @@ public partial class AddGroupDialogViewModel : ObservableObject
? GradingSystem.Points0To15 : GradingSystem.Grades1To6; ? GradingSystem.Points0To15 : GradingSystem.Grades1To6;
Result.SchoolYear = SelectedSchoolYear; Result.SchoolYear = SelectedSchoolYear;
Result.HoursPerWeek = HoursPerWeek; Result.HoursPerWeek = HoursPerWeek;
Result.IsOwnClass = IsOwnClass;
_groups.Save(Result); _groups.Save(Result);
if (_editingGroup is not null && _originalSchoolYear != SelectedSchoolYear) if (_editingGroup is not null && _originalSchoolYear != SelectedSchoolYear)
@@ -13,7 +13,7 @@
<TextBlock Text="{Binding CurrentDate}" FontSize="24" FontWeight="SemiBold"/> <TextBlock Text="{Binding CurrentDate}" FontSize="24" FontWeight="SemiBold"/>
</StackPanel> </StackPanel>
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto"> <Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto,Auto">
<!-- Heutige Stunden --> <!-- Heutige Stunden -->
<Border Grid.Column="0" Grid.Row="0" Margin="0,0,8,8" <Border Grid.Column="0" Grid.Row="0" Margin="0,0,8,8"
@@ -67,8 +67,108 @@
</StackPanel> </StackPanel>
</Border> </Border>
<!-- Meine Lerngruppen --> <!-- Kalender: feste Position direkt unter Heute/Aufgaben, damit die wachsende
<Border Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Lerngruppen-Liste darunter ihn nicht nach unten verdrängt. -->
<Border Grid.Column="0" Grid.Row="1" Margin="0,0,8,8" HorizontalAlignment="Left"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel Spacing="8">
<StackPanel.Styles>
<!-- Basiswerte als Style (nicht lokal), damit die spezifischeren Selektoren
(z.B. .daycell.ownclass) sie überschreiben können. -->
<Style Selector="Border.daycell">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="Border.daycell.haslesson">
<Setter Property="Background" Value="#14808080"/>
</Style>
<Style Selector="Border.daycell.ownclass">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
</Style>
<Style Selector="Border.daycell.outside">
<Setter Property="Opacity" Value="0.35"/>
</Style>
<Style Selector="TextBlock.daynum">
<Setter Property="FontWeight" Value="Normal"/>
</Style>
<Style Selector="TextBlock.daynum.today">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundAccentBrush}"/>
</Style>
</StackPanel.Styles>
<Grid ColumnDefinitions="Auto,*,Auto,Auto,Auto">
<TextBlock Grid.Column="0" Text="KALENDER" FontSize="11" FontWeight="Bold"
Opacity="0.5" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding CalendarMonthLabel}" FontSize="13"
FontWeight="SemiBold" TextAlignment="Center" VerticalAlignment="Center"
Width="130" Margin="12,0"/>
<Button Grid.Column="2" Content="Heute" FontSize="11" Padding="8,2"
Command="{Binding CalendarTodayCommand}" Margin="0,0,4,0"/>
<Button Grid.Column="3" Content="" Padding="8,2" Command="{Binding PrevMonthCommand}"/>
<Button Grid.Column="4" Content="" Padding="8,2" Command="{Binding NextMonthCommand}" Margin="4,0,0,0"/>
</Grid>
<ItemsControl ItemsSource="{Binding CalendarWeekdayHeaders}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="7"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="10" Opacity="0.5" FontWeight="Bold"
HorizontalAlignment="Center" Width="32"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding CalendarDays}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="7"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CalendarDayCell">
<Border Classes="daycell" Classes.ownclass="{Binding IsOwnClassDay}"
Classes.haslesson="{Binding HasLesson}"
Classes.outside="{Binding !IsCurrentMonth}"
Width="32" Height="32" Margin="1" CornerRadius="6"
ToolTip.Tip="{Binding Tooltip}">
<Grid>
<TextBlock Classes="daynum" Classes.today="{Binding IsToday}"
Text="{Binding DayNumber}" FontSize="12"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Ellipse Width="5" Height="5" Fill="#E53935" Margin="0,0,0,3"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
IsVisible="{Binding HasExam}"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal" Spacing="14" Margin="0,4,0,0">
<StackPanel Orientation="Horizontal" Spacing="4">
<Border Width="10" Height="10" CornerRadius="3" Background="#14808080"/>
<TextBlock Text="Unterricht" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<Ellipse Width="7" Height="7" Fill="#E53935"/>
<TextBlock Text="Klausur" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<Border Width="10" Height="10" CornerRadius="3" BorderThickness="2"
BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}"/>
<TextBlock Text="Meine Klasse" FontSize="10" Opacity="0.6"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<!-- Meine Lerngruppen: wächst mit der Zeit, deshalb ganz unten und volle Breite -->
<Border Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}" Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16"> CornerRadius="8" Padding="16">
<StackPanel> <StackPanel>
@@ -64,6 +64,9 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
<CheckBox Content="Gehört zu meiner Klasse" IsChecked="{Binding IsOwnClass}"
ToolTip.Tip="Für die farbliche Hervorhebung im Dashboard-Kalender. Mehrere Gruppen (Klasse + zugehörige Kurse) können markiert werden."/>
<TextBlock Text="{Binding ValidationMessage}" Foreground="Red" FontSize="12" <TextBlock Text="{Binding ValidationMessage}" Foreground="Red" FontSize="12"
IsVisible="{Binding ValidationMessage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/> IsVisible="{Binding ValidationMessage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel> </StackPanel>
+91 -23
View File
@@ -21,10 +21,10 @@
darunter als Overlay-Drawer mit Hamburger-Button (automatisch). darunter als Overlay-Drawer mit Hamburger-Button (automatisch).
Kein eigener Code nötig. Kein eigener Code nötig.
--> -->
<DrawerPage DrawerLength="220" <DrawerPage x:Name="RootDrawer"
DrawerLength="220"
DrawerBehavior="Auto" DrawerBehavior="Auto"
DrawerLayoutBehavior="CompactInline" DrawerLayoutBehavior="CompactInline"
Content="{Binding CurrentPage}"> Content="{Binding CurrentPage}">
<DrawerPage.DataTemplates> <DrawerPage.DataTemplates>
@@ -52,15 +52,48 @@
</DrawerPage.DataTemplates> </DrawerPage.DataTemplates>
<DrawerPage.Drawer> <DrawerPage.Drawer>
<DockPanel> <DockPanel Classes.compact="{Binding !#RootDrawer.IsOpen}">
<DockPanel.Styles>
<!-- Basisgröße der Icons als Style (nicht lokal), damit der Compact-Selector sie
überschreiben kann lokale Werte hätten immer Vorrang vor Style-Settern. -->
<Style Selector="TextBlock.navicon">
<Setter Property="FontSize" Value="15"/>
</Style>
<!-- Minimierter Zustand: Icons größer & zentriert, Beschriftungen ausgeblendet -->
<Style Selector="DockPanel.compact TextBlock.navlabel">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DockPanel.compact TextBlock.navicon">
<Setter Property="FontSize" Value="20"/>
</Style>
<Style Selector="DockPanel.compact Button.navitem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
<Style Selector="DockPanel.compact TextBlock.navsection">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DockPanel.compact TextBlock.appsubtitle">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DockPanel.compact Border.appheader">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</DockPanel.Styles>
<Border DockPanel.Dock="Top" Padding="16,20,16,14" <Border DockPanel.Dock="Top" Padding="16,20,16,14"
BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}" BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
BorderThickness="0,0,0,1"> BorderThickness="0,0,0,1">
<StackPanel> <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Text="LehrerApp" FontSize="20" FontWeight="SemiBold"/> <Border Classes="appheader" Width="32" Height="32" CornerRadius="8"
<TextBlock Text="{Binding CurrentSchoolYear}" Background="{DynamicResource SystemControlBackgroundAccentBrush}">
FontSize="12" Opacity="0.55" Margin="0,2,0,0"/> <TextBlock Text="L" FontSize="16" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<StackPanel Classes="appsubtitle" VerticalAlignment="Center">
<TextBlock Text="LehrerApp" FontSize="15" FontWeight="SemiBold"/>
<TextBlock Text="{Binding CurrentSchoolYear}"
FontSize="11" Opacity="0.55"/>
</StackPanel>
</StackPanel> </StackPanel>
</Border> </Border>
@@ -72,49 +105,84 @@
<ScrollViewer> <ScrollViewer>
<StackPanel Margin="8,12,8,0" Spacing="2"> <StackPanel Margin="8,12,8,0" Spacing="2">
<Button Content="📊 Dashboard" HorizontalAlignment="Stretch" <Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Dashboard}"/> CommandParameter="{x:Static vm:NavItem.Dashboard}">
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="📊" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Dashboard"/>
</StackPanel>
</Button>
<TextBlock Text="UNTERRICHT" FontSize="10" FontWeight="Bold" <TextBlock Classes="navsection" Text="UNTERRICHT" FontSize="10" FontWeight="Bold"
Opacity="0.4" Margin="10,14,0,4"/> Opacity="0.4" Margin="10,14,0,4"/>
<Button Content="🏫 Lerngruppen" HorizontalAlignment="Stretch" <Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Groups}"/> CommandParameter="{x:Static vm:NavItem.Groups}">
<Button Content="👤 Schüler" HorizontalAlignment="Stretch" <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="🏫" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Lerngruppen"/>
</StackPanel>
</Button>
<Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Students}"/> CommandParameter="{x:Static vm:NavItem.Students}">
<Button Content="📝 Klausuren" HorizontalAlignment="Stretch" <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="👤" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Schüler"/>
</StackPanel>
</Button>
<Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Exams}"/> CommandParameter="{x:Static vm:NavItem.Exams}">
<Button Content="📅 Planung" HorizontalAlignment="Stretch" <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="📝" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Klausuren"/>
</StackPanel>
</Button>
<Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Planner}"/> CommandParameter="{x:Static vm:NavItem.Planner}">
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="📅" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Planung"/>
</StackPanel>
</Button>
<TextBlock Text="VERWALTUNG" FontSize="10" FontWeight="Bold" <TextBlock Classes="navsection" Text="VERWALTUNG" FontSize="10" FontWeight="Bold"
Opacity="0.4" Margin="10,14,0,4"/> Opacity="0.4" Margin="10,14,0,4"/>
<Button Content="⏱ Arbeitszeit" HorizontalAlignment="Stretch" <Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Workload}"/> CommandParameter="{x:Static vm:NavItem.Workload}">
<Button Content="⚙️ Einstellungen" HorizontalAlignment="Stretch" <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="⏱" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Arbeitszeit"/>
</StackPanel>
</Button>
<Button Classes="navitem" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left" Background="Transparent" HorizontalContentAlignment="Left" Background="Transparent"
Padding="10,8" CornerRadius="6" Padding="10,8" CornerRadius="6"
Command="{Binding NavigateToCommand}" Command="{Binding NavigateToCommand}"
CommandParameter="{x:Static vm:NavItem.Settings}"/> CommandParameter="{x:Static vm:NavItem.Settings}">
<StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Classes="navicon" Text="⚙️" Width="20" TextAlignment="Center"/>
<TextBlock Classes="navlabel" Text="Einstellungen"/>
</StackPanel>
</Button>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</DockPanel> </DockPanel>
+7
View File
@@ -297,6 +297,8 @@ Format dokumentiert in [Kompetenzkatalog-KI-Prompt.md](docs/Kompetenzkatalog-KI-
## 9. Dashboard ## 9. Dashboard
Basis vorhanden in [DashboardViewModel.cs](LehrerApp.Desktop/ViewModels/DashboardViewModel.cs). Basis vorhanden in [DashboardViewModel.cs](LehrerApp.Desktop/ViewModels/DashboardViewModel.cs).
Kleiner Monatskalender ist bereits umgesetzt (Farbcodierung Unterricht/Klausur,
Hervorhebung "eigene Klasse" über `LearningGroup.IsOwnClass`, feste Kartenbreite/-position).
- [ ] **9.1** Heutige Stunden mit Uhrzeit und Raum anzeigen (Abhängigkeit zu 4.3). - [ ] **9.1** Heutige Stunden mit Uhrzeit und Raum anzeigen (Abhängigkeit zu 4.3).
- [ ] **9.2** Direkter Absprung von einer Stunde in Mitarbeitserfassung bzw. Stundenplanung. - [ ] **9.2** Direkter Absprung von einer Stunde in Mitarbeitserfassung bzw. Stundenplanung.
@@ -305,6 +307,11 @@ Basis vorhanden in [DashboardViewModel.cs](LehrerApp.Desktop/ViewModels/Dashboar
- [ ] **9.5** Kachel "Auffälligkeiten": Fehlzeitenüberschreitungen, Notenabfall, Versetzungsgefährdung. - [ ] **9.5** Kachel "Auffälligkeiten": Fehlzeitenüberschreitungen, Notenabfall, Versetzungsgefährdung.
- [ ] **9.6** Dashboard-Kacheln ein-/ausblendbar und in der Reihenfolge konfigurierbar. - [ ] **9.6** Dashboard-Kacheln ein-/ausblendbar und in der Reihenfolge konfigurierbar.
- [ ] **9.7** Automatische Aktualisierung beim Zurücknavigieren (aktuell nur manueller Refresh). - [ ] **9.7** Automatische Aktualisierung beim Zurücknavigieren (aktuell nur manueller Refresh).
- [ ] **9.8** Kalender-Detailansicht: Tag im Monatskalender anklickbar/auswählbar, zeigt in
einem angrenzenden Feld die Termine dieses Tages (Unterricht, Klausuren, perspektivisch
Konferenzen/Sondertermine) mit Details und Sprungmöglichkeit in die jeweilige Ansicht.
Sinnvoll erst, wenn weitere Terminarten existieren — Abhängigkeit zu Kapitel 4
(Unterrichtsplanung/Termine) sowie ggf. einem neuen Termine-Modell.
--- ---