managarten/apps-archived/presi/apps/mobile/components/common/ContextMenu.tsx
Till-JS 44897ae758 chore: archive inventory, presi, storage apps
Move these apps to apps-archived/ as they are not actively developed:
- inventory: Inventory management app
- presi: Presentation tool
- storage: Cloud storage app

These can be reactivated by moving back to apps/ when needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 15:22:38 +01:00

100 lines
2.1 KiB
TypeScript

import React from 'react';
import { View, Modal, TouchableOpacity, Text, StyleSheet, Platform } from 'react-native';
import { useTheme } from '../ThemeProvider';
export interface ContextMenuItem {
label: string;
icon: string;
onPress: () => void;
destructive?: boolean;
}
interface ContextMenuProps {
visible: boolean;
onClose: () => void;
items: ContextMenuItem[];
position?: { x: number; y: number };
}
export const ContextMenu: React.FC<ContextMenuProps> = ({ visible, onClose, items, position }) => {
const { theme } = useTheme();
if (!visible) return null;
return (
<Modal visible={visible} transparent animationType="fade" onRequestClose={onClose}>
<TouchableOpacity style={styles.overlay} onPress={onClose} activeOpacity={1}>
<View
style={[
styles.menuContainer,
{
backgroundColor: theme.colors.backgroundSecondary,
top: position?.y || 0,
left: position?.x || 0,
},
]}
>
{items.map((item, index) => (
<TouchableOpacity
key={index}
style={[
styles.menuItem,
index < items.length - 1 && styles.menuItemBorder,
{ borderBottomColor: theme.colors.border },
]}
onPress={() => {
item.onPress();
onClose();
}}
>
<Text
style={[
styles.menuItemText,
{
color: item.destructive ? theme.colors.error : theme.colors.textPrimary,
},
]}
>
{item.label}
</Text>
</TouchableOpacity>
))}
</View>
</TouchableOpacity>
</Modal>
);
};
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
menuContainer: {
position: 'absolute',
minWidth: 150,
borderRadius: 8,
...Platform.select({
web: {
boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.15)',
},
default: {
elevation: 4,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
},
}),
},
menuItem: {
paddingVertical: 12,
paddingHorizontal: 16,
},
menuItemBorder: {
borderBottomWidth: 1,
},
menuItemText: {
fontSize: 16,
},
});