feat: mobilni responsivita, testy, klavesove zkratky, drag & drop, univerzalizace

- Mobile responsive CSS (touch targets 44px, iOS anti-zoom, reduced motion)
- Vitest setup s 39 testy (formatters, attendanceHelpers, useTableSort)
- Klavesove zkratky (Shift+? napoveda, Ctrl+S ulozit, navigace)
- Drag & drop pro polozky nabidek (@dnd-kit, SortableRow, useSortableList)
- Univerzalizace: odstraneni BOHA brandingu z UI, emailu, PDF
- Smazany nepotrebne soubory (deploy.sh, AUTH_SYSTEM.md, example_design, .htaccess)
- CORS konfigurovatelny pres env promennou

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 17:33:37 +01:00
parent 5ef6fc8064
commit bb2bbb8ff6
35 changed files with 2716 additions and 4392 deletions

View File

@@ -0,0 +1,53 @@
import { useSortable } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
export function DragHandle({ listeners, attributes }) {
return (
<button
type="button"
className="admin-drag-handle"
{...attributes}
{...listeners}
title="Přetáhnout"
aria-label="Přetáhnout pro změnu pořadí"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<circle cx="9" cy="5" r="1.5" />
<circle cx="15" cy="5" r="1.5" />
<circle cx="9" cy="12" r="1.5" />
<circle cx="15" cy="12" r="1.5" />
<circle cx="9" cy="19" r="1.5" />
<circle cx="15" cy="19" r="1.5" />
</svg>
</button>
)
}
export default function SortableRow({ id, children, disabled }) {
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id, disabled })
const style = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
position: 'relative',
zIndex: isDragging ? 10 : undefined,
background: isDragging ? 'var(--bg-secondary)' : undefined,
}
return (
<tr ref={setNodeRef} style={style}>
{typeof children === 'function'
? children({ attributes, listeners })
: children
}
</tr>
)
}