Add 52-week planting calendar with month fallback

Add indoor_sowing_weeks, direct_sowing_weeks, transplanting_weeks,
glasshouse_weeks, harvesting_weeks (integer[]) to backend Cultivar and
CreateCultivar structs with INSERT/UPDATE SQL bindings.

Frontend PlantingCalendar component rewritten as a compact 52-column
Gantt-style grid grouped by month headers. Prefers week data when
available, falls back to expanding month data into week ranges.
Calendar displayed full-width on cultivar detail page with color legend.
This commit is contained in:
2026-03-15 14:36:17 +01:00
parent 3ecfdfadf2
commit 170aa84a0f
6 changed files with 245 additions and 39 deletions
+80
View File
@@ -468,6 +468,86 @@ tr:hover td {
background: var(--cal-harvest);
}
/* 52-Week Planting Calendar */
.week-calendar {
padding: 0.5rem;
border: none;
box-shadow: none;
background: transparent;
}
.wcal-month-row {
display: grid;
grid-template-columns: 100px repeat(52, 1fr);
gap: 1px;
margin-bottom: 2px;
}
.wcal-month-header {
font-size: 0.7rem;
font-weight: 600;
color: var(--text-muted);
text-align: center;
padding: 0.2rem 0;
border-bottom: 1px solid var(--border);
}
.wcal-label {
font-size: 0.75rem;
padding: 0.15rem 0.4rem;
white-space: nowrap;
display: flex;
align-items: center;
}
.wcal-row {
display: grid;
grid-template-columns: 100px repeat(52, 1fr);
gap: 1px;
margin-bottom: 1px;
}
.wcal-cell {
height: 18px;
border-radius: 2px;
background: #f0f0f0;
}
.wcal-cell.active.cal-indoor { background: var(--cal-indoor); }
.wcal-cell.active.cal-direct { background: var(--cal-direct); }
.wcal-cell.active.cal-transplant { background: var(--cal-transplant); }
.wcal-cell.active.cal-glass { background: var(--cal-glass); }
.wcal-cell.active.cal-harvest { background: var(--cal-harvest); }
.wcal-legend {
display: flex;
gap: 1rem;
margin-top: 0.5rem;
padding-left: 100px;
flex-wrap: wrap;
}
.wcal-legend-item {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.7rem;
color: var(--text-muted);
}
.wcal-legend-swatch {
width: 14px;
height: 10px;
border-radius: 2px;
}
.wcal-legend-swatch.cal-indoor { background: var(--cal-indoor); }
.wcal-legend-swatch.cal-direct { background: var(--cal-direct); }
.wcal-legend-swatch.cal-transplant { background: var(--cal-transplant); }
.wcal-legend-swatch.cal-glass { background: var(--cal-glass); }
.wcal-legend-swatch.cal-harvest { background: var(--cal-harvest); }
/* Pagination */
.pagination {