P11SlotPlanner Component
The
P11SlotPlanner is a high-performance, logic-driven time management engine designed for Blazor WASM and Capacitor. Unlike traditional date-pickers, it uses a zero-latency boolean-map architecture to handle 24h schedules with micro-second precision. Key features include an interactive 'Hollow-Donut' SVG visualization, WCAG-compliant keyboard navigation, and a hybrid data model that allows for both standalone confirmation and real-time parent-state synchronization. Optimized for mobile-first UX, it ensures fluid slot toggling even on low-powered devices.Single Day Planning
Classic standalone mode with integrated range selection and internal accept button.
Processing hours: 8:00 - 18:00
Range Selection
Weekend Planner
Select slots for Saturday and Sunday. Changes are synced instantly.
Saturday
Sunday
Implementation
<div class="container mt-5">
<div class="border-bottom mb-4 pb-2">
<h2 class="fw-bold"><i class="bi bi-clock-history me-2"></i> Single Day Planning</h2>
<p class="text-muted">Classic standalone mode with integrated range selection and internal accept button.</p>
</div>
<P11SlotPlanner SlotSize="15"
ViewRangeStartHour="8"
ViewRangeEndHour="18"
ColorActive="#b02a37"
ColorInactive="#e9ecef"
ColorAccent="#212529"
IsVisibleRangeSelection="true"
UseRangeSelector="true"
IsVisibleAcceptButton="true"
EnableInstantBinding="false"
@bind-OccupiedSlotIndices="_myBookings"
OnAccept="HandleSave" />
</div>
<hr />
<div class="container mt-5">
<div class="card shadow-lg border-0">
<div class="card-header bg-dark text-white p-4">
<h3 class="mb-0"><i class="bi bi-calendar3-range me-2"></i> Weekend Planner</h3>
<p class="mb-0 opacity-75">Select slots for Saturday and Sunday. Changes are synced instantly.</p>
</div>
<div class="card-body p-4 bg-light">
<div class="row">
@* SATURDAY COLUMN *@
<div class="col-md-6 border-end">
<h5 class="fw-bold text-primary mb-3"><i class="bi bi-calendar-event me-2"></i> Saturday</h5>
<P11SlotPlanner SlotSize="30"
ViewRangeStartHour="10"
ViewRangeEndHour="22"
ColorActive="#0d6efd"
IsVisibleRangeSelection="false"
IsVisibleAcceptButton="false"
EnableInstantBinding="true"
@bind-OccupiedSlotIndices="_saturdayBookings" />
</div>
@* SUNDAY COLUMN *@
<div class="col-md-6">
<h5 class="fw-bold text-danger mb-3"><i class="bi bi-calendar-check me-2"></i> Sunday</h5>
<P11SlotPlanner SlotSize="30"
ViewRangeStartHour="10"
ViewRangeEndHour="18"
ColorActive="#dc3545"
IsVisibleRangeSelection="false"
IsVisibleAcceptButton="false"
EnableInstantBinding="true"
@bind-OccupiedSlotIndices="_sundayBookings" />
</div>
</div>
</div>
@* MASTER ACTION FOOTER *@
<div class="card-footer bg-white p-4 d-flex justify-content-between align-items-center">
<div class="text-muted small">
Total Slots: <strong>@(_saturdayBookings.Count + _sundayBookings.Count)</strong>
</div>
<button type="button" class="btn btn-success btn-lg px-5 fw-bold shadow" @onclick="HandleMasterSave">
SAVE WEEKEND PLAN <i class="bi bi-cloud-upload-fill ms-2"></i>
</button>
</div>
</div>
</div> @code {
// Initial data: 08:00 (Slot 33 for 15m), 08:30 (Slot 35)
private List<int> _myBookings = new() { 33, 35 };
private void HandleSave()
{
Console.WriteLine($"--- SAVING SINGLE DAY ---");
foreach (var slotId in _myBookings.OrderBy(x => x))
{
int totalMinutes = (slotId - 1) * 15;
int h = totalMinutes / 60;
int m = totalMinutes % 60;
Console.WriteLine($"Slot: {slotId} ({h:D2}:{m:D2})");
}
}
private List<int> _saturdayBookings = new() { 21, 22 }; // Beispiel-Daten
private List<int> _sundayBookings = new();
private void HandleMasterSave()
{
// Da EnableInstantBinding="true" ist, sind _saturdayBookings
// und _sundayBookings bereits auf dem neuesten Stand!
Console.WriteLine("--- SAVING WEEKEND PLAN ---");
ProcessDay("Saturday", _saturdayBookings, 30);
ProcessDay("Sunday", _sundayBookings, 30);
}
private void ProcessDay(string dayName, List<int> indices, int slotSize)
{
Console.WriteLine($"{dayName} selection:");
foreach (var slotId in indices.OrderBy(x => x))
{
int totalMinutes = (slotId - 1) * slotSize;
int h = totalMinutes / 60;
int m = totalMinutes % 60;
Console.WriteLine($" - Slot: {slotId} ({h:D2}:{m:D2})");
}
}
} Component API: P11SlotPlanner
| Parameter / Event | Type | Default | Description |
|---|---|---|---|
| Core Logic & Data | |||
OccupiedSlotIndices |
List<int> |
new() |
The 1-based indices of selected slots. Primary data source for binding. |
SlotSize |
int |
5 |
Size of a single slot in minutes. Supports 5, 10, 15, 30, 60. |
EnableInstantBinding |
bool |
false |
If true, updates the parent immediately on every click without needing 'Accept'. |
OccupiedSlotIndicesChanged |
EventCallback |
- | Fired when the selection changes (manually or via instant binding). |
| View & UI Control | |||
ViewRangeStartHour |
int |
8 |
First visible hour in the UI grid (0-23). |
ViewRangeEndHour |
int |
18 |
Last visible hour in the UI grid (1-24). |
IsVisibleRangeSelection |
bool |
true |
Toggles the visibility of the time-range adjustment header. |
UseRangeSelector |
bool |
false |
Switch between slider-track and dropdown-menus for range selection. |
IsVisibleAcceptButton |
bool |
true |
Shows/Hides the footer 'Accept' button. |
| Styling & Branding | |||
ColorActive |
string |
#0d6efd |
Hex/CSS color for selected slots and active donut segments. |
ColorAccent |
string |
#0d6efd |
Accent color for UI highlights like the range track bridge. |
CssClass |
string? |
null |
Optional CSS classes for the root container. |
| Localization (Texts) | |||
TextAcceptButton |
string? |
"ACCEPT..." |
Custom label for the confirmation button. |
IconAcceptButton |
string? |
"bi-check..." |
Bootstrap icon class for the confirmation button. |
TextProcessingHours |
string? |
"Processing..." |
Label for the active time range display. |