feat(mobile): Handy-Optimierung – Tap-to-place, Bottom-Nav, kompakte Banner (v1.4.12)
- Tap-to-place: Symbol antippen → auf Karte tippen platziert es (Alternative zu Drag&Drop, mobil-tauglich); schwebender Hinweis mit Abbrechen - Mobile Bottom-Navigation: Karte / Journal(Auswertung) / Symbole ohne Menü erreichbar - FAB entfernt; Karten-Steuerung (Zoom/Standort/Massstab) hebt sich mobil über die Bottom-Nav - Touch-Ziele in der Werkzeugleiste auf 44px vergrössert - "Einsatz/Übung beenden" jetzt auch im Mobile-Overflow-Menü - Banner (Übung/Offline/E-Mail/Live) mobil kompakt: kleinere Höhe, gekürzte Texte, truncate - Einsatz-beenden-Bestätigung als In-App-Dialog statt Browser-confirm() Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ interface TenantSymbolGroup {
|
||||
|
||||
interface RightSidebarProps {
|
||||
onSymbolDrop: (iconId: string, coordinates: [number, number], imageUrl?: string) => void
|
||||
onSymbolSelect?: (symbol: { id: string; imageUrl: string }) => void
|
||||
canEdit: boolean
|
||||
isOpen?: boolean
|
||||
onToggle?: () => void
|
||||
@@ -56,9 +57,10 @@ const categoryIcons: Record<string, typeof Flame> = {
|
||||
'Eigene': Upload,
|
||||
}
|
||||
|
||||
function DraggableSymbol({ symbol, canEdit }: {
|
||||
function DraggableSymbol({ symbol, canEdit, onSelect }: {
|
||||
symbol: DisplaySymbol
|
||||
canEdit: boolean
|
||||
onSelect?: (symbol: DisplaySymbol) => void
|
||||
}) {
|
||||
const [{ isDragging }, drag, preview] = useDrag(() => ({
|
||||
type: 'SYMBOL',
|
||||
@@ -77,6 +79,7 @@ function DraggableSymbol({ symbol, canEdit }: {
|
||||
return (
|
||||
<div
|
||||
ref={drag as unknown as React.LegacyRef<HTMLDivElement>}
|
||||
onClick={() => { if (canEdit && onSelect) onSelect(symbol) }}
|
||||
className={`
|
||||
flex flex-col items-center gap-1 p-1.5 md:p-2 lg:p-2.5 rounded-lg border-2 transition-all
|
||||
border-transparent hover:border-border hover:bg-accent
|
||||
@@ -84,7 +87,7 @@ function DraggableSymbol({ symbol, canEdit }: {
|
||||
${isDragging ? 'opacity-0' : ''}
|
||||
${!canEdit ? 'opacity-50 cursor-not-allowed' : ''}
|
||||
`}
|
||||
title={symbol.name}
|
||||
title={canEdit ? `${symbol.name} — antippen zum Platzieren, oder auf die Karte ziehen` : symbol.name}
|
||||
>
|
||||
<div className="w-10 h-10 md:w-11 md:h-11 lg:w-14 lg:h-14 flex items-center justify-center rounded-lg bg-white border border-gray-200 dark:border-gray-600">
|
||||
<img
|
||||
@@ -101,7 +104,7 @@ function DraggableSymbol({ symbol, canEdit }: {
|
||||
)
|
||||
}
|
||||
|
||||
export function RightSidebar({ onSymbolDrop, canEdit, isOpen, onToggle, activeTab, onTabChange, isCollapsed, onToggleCollapse, tenantId, mode }: RightSidebarProps) {
|
||||
export function RightSidebar({ onSymbolDrop, onSymbolSelect, canEdit, isOpen, onToggle, activeTab, onTabChange, isCollapsed, onToggleCollapse, tenantId, mode }: RightSidebarProps) {
|
||||
const journalLabel = mode === 'UEBUNG' ? 'Auswertung' : 'Journal'
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [activeCategory, setActiveCategory] = useState<string>('')
|
||||
@@ -206,17 +209,6 @@ export function RightSidebar({ onSymbolDrop, canEdit, isOpen, onToggle, activeTa
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Mobile toggle button */}
|
||||
{!isOpen && onToggle && (
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="md:hidden fixed bottom-4 right-4 z-50 w-14 h-14 bg-primary text-primary-foreground rounded-full shadow-lg flex items-center justify-center active:scale-95 transition-transform"
|
||||
title="Symbole"
|
||||
>
|
||||
<LayoutGrid className="w-6 h-6" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Backdrop on mobile */}
|
||||
{isOpen && onToggle && (
|
||||
<div className="md:hidden fixed inset-0 bg-black/40 z-40" onClick={onToggle} />
|
||||
@@ -375,7 +367,7 @@ export function RightSidebar({ onSymbolDrop, canEdit, isOpen, onToggle, activeTa
|
||||
<div className="px-1.5 pb-1.5">
|
||||
<div className="grid grid-cols-3 md:grid-cols-2 lg:grid-cols-3 gap-1">
|
||||
{g.symbols.map(symbol => (
|
||||
<DraggableSymbol key={symbol.id} symbol={symbol} canEdit={canEdit} />
|
||||
<DraggableSymbol key={symbol.id} symbol={symbol} canEdit={canEdit} onSelect={onSymbolSelect} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -440,7 +432,7 @@ export function RightSidebar({ onSymbolDrop, canEdit, isOpen, onToggle, activeTa
|
||||
) : (
|
||||
<div className="grid grid-cols-3 md:grid-cols-2 lg:grid-cols-3 gap-1">
|
||||
{currentCategory.symbols.map((symbol) => (
|
||||
<DraggableSymbol key={symbol.id} symbol={symbol} canEdit={canEdit} />
|
||||
<DraggableSymbol key={symbol.id} symbol={symbol} canEdit={canEdit} onSelect={onSymbolSelect} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user