feat: SAZLT info row, 16/24h shifts, VN/NN font colors

- Added SAZLT info row (between TKB and Metro) with toggle
- Added 16h and 24h shift codes (progressive green shades)
- VN people get red font color on A/B shifts
- NN people get blue font color on A/B shifts
- Changed B (Noční) background to light blue-gray for readability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Docker Config Backup
2026-04-02 10:49:30 +02:00
parent 177975c70c
commit 785966463c
5 changed files with 125 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
import { useMemo, useState, useCallback, useRef, memo, useEffect } from 'react'
import type { DayInfo, Person, DragState, ScheduleData } from './types'
import { getCellStyle, getContrastColor } from './cellColors'
import { getCellStyle, getCellStyleForPerson, getContrastColor } from './cellColors'
import { getHolidayMap } from './holidays'
const CELL_W = 32
@@ -27,6 +27,8 @@ interface ScheduleTableProps {
metroColors: Map<number, string>
d8Closures: Map<number, string>
d8Colors: Map<number, string>
sazltClosures: Map<number, string>
sazltColors: Map<number, string>
dayComments: Map<number, string>
cellComments: Map<string, string>
dragState: DragState | null
@@ -35,9 +37,11 @@ interface ScheduleTableProps {
onSetTunnelClosure: (dayIdx: number, text: string | null) => void
onSetMetroClosure: (dayIdx: number, text: string | null) => void
onSetD8Closure: (dayIdx: number, text: string | null) => void
onSetSazltClosure: (dayIdx: number, text: string | null) => void
scrollRef: React.RefObject<HTMLDivElement | null>
showMetro: boolean
showD8: boolean
showSazlt: boolean
hiddenValues: Set<string>
onContextMenu: (dayIdx: number, personId: string | null, x: number, y: number, selectedCells: SelectedCell[]) => void
onTunnelContextMenu: (dayIdx: number, x: number, y: number) => void
@@ -46,7 +50,7 @@ interface ScheduleTableProps {
}
interface EditingCell {
personId: string | '__tunnel__' | '__metro__' | '__d8__'
personId: string | '__tunnel__' | '__metro__' | '__d8__' | '__sazlt__'
dayIdx: number
value: string
}
@@ -101,7 +105,7 @@ const PersonRow = memo(function PersonRow({
const value = cellData?.v ?? ''
const isColorOnly = !value && !!cellData?.color
const isValueHidden = !!(value && hiddenValues.has(value)) || (isColorOnly && hiddenValues.has('__color_only__'))
const style = getCellStyle(value || undefined)
const style = getCellStyleForPerson(value || undefined, person.note)
const isHoliday = holidays.has(`${d.year}-${d.month}-${d.day}`)
const isWeekend = d.weekend || isHoliday
const commentKey = `${person.id}-${d.idx}`
@@ -232,11 +236,11 @@ const PersonRow = memo(function PersonRow({
export function ScheduleTable(props: ScheduleTableProps) {
const {
dayIndex, people, tunnelClosures, tunnelColors,
metroClosures, metroColors, d8Closures, d8Colors,
metroClosures, metroColors, d8Closures, d8Colors, sazltClosures, sazltColors,
dayComments, cellComments,
dragState, onCellPointerDown, onSetCell, onSetTunnelClosure,
onSetMetroClosure, onSetD8Closure,
showMetro, showD8, hiddenValues,
onSetMetroClosure, onSetD8Closure, onSetSazltClosure,
showMetro, showD8, showSazlt, hiddenValues,
scrollRef, onContextMenu, onTunnelContextMenu, onInfoRowContextMenu, compareData,
} = props
@@ -324,6 +328,10 @@ export function ScheduleTable(props: ScheduleTableProps) {
setEditingCell({ personId: '__d8__', dayIdx, value: currentValue })
}, [])
const onStartEditSazlt = useCallback((dayIdx: number, currentValue: string) => {
setEditingCell({ personId: '__sazlt__', dayIdx, value: currentValue })
}, [])
const onEditChange = useCallback((value: string) => {
setEditingCell(prev => prev ? { ...prev, value } : null)
}, [])
@@ -337,11 +345,13 @@ export function ScheduleTable(props: ScheduleTableProps) {
onSetMetroClosure(editingCell.dayIdx, trimmed || null)
} else if (editingCell.personId === '__d8__') {
onSetD8Closure(editingCell.dayIdx, trimmed || null)
} else if (editingCell.personId === '__sazlt__') {
onSetSazltClosure(editingCell.dayIdx, trimmed || null)
} else {
onSetCell(editingCell.personId, editingCell.dayIdx, trimmed || null)
}
setEditingCell(null)
}, [editingCell, onSetCell, onSetTunnelClosure, onSetMetroClosure, onSetD8Closure])
}, [editingCell, onSetCell, onSetTunnelClosure, onSetMetroClosure, onSetD8Closure, onSetSazltClosure])
const onEditCancel = useCallback(() => {
setEditingCell(null)
@@ -601,7 +611,7 @@ export function ScheduleTable(props: ScheduleTableProps) {
// Helper: render info row cells (right column)
const renderInfoRowCells = (
rowId: '__tunnel__' | '__metro__' | '__d8__',
rowId: '__tunnel__' | '__metro__' | '__d8__' | '__sazlt__',
closures: Map<number, string>,
colors: Map<number, string>,
defaultBgClass: string,
@@ -698,7 +708,10 @@ export function ScheduleTable(props: ScheduleTableProps) {
</div>
{/* TKB info row label */}
{renderInfoRowLabel('TKB', 'border-slate-600')}
{renderInfoRowLabel('TKB', 'border-slate-700')}
{/* SAZLT info row label */}
{showSazlt && renderInfoRowLabel('SAZLT', 'border-slate-700')}
{/* Metro info row label */}
{showMetro && renderInfoRowLabel('Metro', 'border-slate-700')}
@@ -811,9 +824,14 @@ export function ScheduleTable(props: ScheduleTableProps) {
{/* TKB info row */}
{renderInfoRowCells('__tunnel__', tunnelClosures, tunnelColors,
'bg-orange-700/40 text-orange-200', 'border-slate-600', 'border-orange-400', 'TKB',
'bg-orange-700/40 text-orange-200', 'border-slate-700', 'border-orange-400', 'TKB',
onTunnelContextMenu, onStartEditTunnel)}
{/* SAZLT info row */}
{showSazlt && renderInfoRowCells('__sazlt__', sazltClosures, sazltColors,
'bg-amber-700/40 text-amber-200', 'border-slate-700', 'border-amber-400', 'SAZLT',
(dayIdx, x, y) => onInfoRowContextMenu(dayIdx, 'sazlt', x, y), onStartEditSazlt)}
{/* Metro info row */}
{showMetro && renderInfoRowCells('__metro__', metroClosures, metroColors,
'bg-blue-700/40 text-blue-200', 'border-slate-700', 'border-blue-400', 'Metro',