Projects included: - maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing) - manacore (Expo mobile + SvelteKit web + Astro landing) - manadeck (NestJS backend + Expo mobile + SvelteKit web) - memoro (Expo mobile + SvelteKit web + Astro landing) This commit preserves the current state before monorepo restructuring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| ReadMes | ||
| AndroidContextMenu.tsx | ||
| Header.tsx | ||
| HeaderContext.tsx | ||
| HeaderMenu.tsx | ||
| MemoHeaderMenu.tsx | ||
| MemoMenu.tsx | ||
| README.md | ||
Memoro Menü-System
Dieses Dokument beschreibt die Verwendung von Menüs in der Memoro-App. Wir verwenden zwei verschiedene Menü-Typen für unterschiedliche Anwendungsfälle.
Übersicht
| Menü-Typ | Verwendung | Bibliothek | Plattformunterstützung |
|---|---|---|---|
| Action Sheet | Bestätigungsdialoge, Aktionsauswahl | @expo/react-native-action-sheet |
iOS, Android, Web, macOS |
| Context Menu | Kontext-/Dropdown-Menüs | react-native-context-menu-view |
iOS (nativ), Android (adaptiert), NICHT macOS |
⚠️ Wichtiger Hinweis: macOS (Mac Catalyst) Kompatibilität
Die react-native-context-menu-view Bibliothek ist nicht kompatibel mit Mac Catalyst und verursacht Abstürze beim Rendern auf macOS. Alle Menü-Komponenten müssen ein spezielles Import-Pattern verwenden, um macOS-Kompatibilität sicherzustellen.
Implementierungs-Pattern für Context Menus
// Nur ContextMenu für unterstützte native Plattformen importieren
let ContextMenu: any = null;
// Erst Platform.OS statisch prüfen, dann Runtime-Check
if (Platform.OS !== 'web') {
try {
// Nur importieren wenn nicht auf macOS - Runtime-Check im require-Block
const contextMenuModule = require('react-native-context-menu-view');
// Doppelcheck zur Laufzeit nach Import
if (!shouldDisableContextMenu()) {
ContextMenu = contextMenuModule.default;
}
} catch (error) {
console.warn('ContextMenu not available on', getPlatformString());
}
}
Schlüsselpunkte für macOS-Kompatibilität
- Zweistufige Prüfung: Erst
Platform.OS !== 'web'statisch prüfen, dannshouldDisableContextMenu()zur Laufzeit - Runtime-Validierung: Die
shouldDisableContextMenu()Funktion erkennt Mac Catalyst und gibttruezurück - Fallback-Mechanismus: Wenn
ContextMenunullist, fallen Komponenten auf Web-Style Implementierungen zurück
Platform Detection
Die Platform-Detection-Logik befindet sich in /features/utils/platformDetection.ts:
isMacOS(): Erkennt ob die App auf Mac Catalyst läuftshouldDisableContextMenu(): Gibttruefür Plattformen zurück, auf denen Context Menus deaktiviert werden sollengetPlatformString(): Gibt einen Plattform-Identifier für Logging zurück
1. Action Sheet für Bestätigungsdialoge
Wir verwenden Action Sheets anstelle von modalen Dialogen für alle Bestätigungsabfragen und Aktionsauswahlen.
Installation
npm install @expo/react-native-action-sheet
Einrichtung
Das Action Sheet Provider ist bereits im Root Layout (app/_layout.tsx) eingerichtet:
import { ActionSheetProvider } from '@expo/react-native-action-sheet';
export default function RootLayout() {
return (
<SafeAreaProvider>
<ThemeProvider>
<ActionSheetProvider>
<AuthProvider>
<RootLayoutNav />
</AuthProvider>
</ActionSheetProvider>
</ThemeProvider>
</SafeAreaProvider>
);
}
Verwendung
import { useActionSheet } from '@expo/react-native-action-sheet';
import { useTheme } from '~/features/theme/ThemeProvider';
function YourComponent() {
const { showActionSheetWithOptions } = useActionSheet();
const { isDark } = useTheme();
const handleShowActionSheet = () => {
const options = ['Option 1', 'Löschen', 'Abbrechen'];
const destructiveButtonIndex = 1;
const cancelButtonIndex = 2;
showActionSheetWithOptions({
options,
cancelButtonIndex,
destructiveButtonIndex,
title: 'Titel',
message: 'Beschreibung der verfügbaren Optionen',
// iOS: Native Dark Mode Unterstützung
userInterfaceStyle: isDark ? 'dark' : 'light',
// Android/Web: Benutzerdefiniertes Styling für Dark Mode
containerStyle: isDark ? {
backgroundColor: '#1e1e1e',
} : undefined,
textStyle: {
color: isDark ? '#FFFFFF' : '#000000',
},
titleTextStyle: {
color: isDark ? '#FFFFFF' : '#000000',
},
messageTextStyle: {
color: isDark ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.7)',
},
}, (selectedIndex?: number) => {
if (selectedIndex === undefined) return; // Abgebrochen
switch (selectedIndex) {
case 0:
// Option 1 ausgewählt
break;
case destructiveButtonIndex:
// Löschen ausgewählt
break;
}
});
};
return (
<Pressable onPress={handleShowActionSheet}>
<Text>Action Sheet anzeigen</Text>
</Pressable>
);
}
Anwendungsfälle
- Bestätigung von Löschaktionen
- Bestätigung von Abbruch-Aktionen
- Auswahl aus einer Liste von Optionen
- Jede Art von Bestätigungsdialog
2. Context Menu für Kontext- und Dropdown-Menüs
Wir verwenden Context Menus für Kontext- und Dropdown-Menüs, die an bestimmte UI-Elemente gebunden sind.
Installation
npm install react-native-context-menu-view
Verwendung
import ContextMenu from 'react-native-context-menu-view';
import { useTheme } from '~/features/theme/ThemeProvider';
function YourComponent() {
const { isDark, themeVariant } = useTheme();
const handleMenuPress = (e) => {
const { index, name } = e.nativeEvent;
switch (name) {
case 'edit':
// Bearbeiten-Aktion
break;
case 'delete':
// Löschen-Aktion
break;
}
};
return (
<ContextMenu
title="Optionen"
actions={[
{
title: 'Bearbeiten',
subtitle: 'Element bearbeiten',
systemIcon: 'square.and.pencil', // iOS SF Symbol
id: 'edit',
},
{
title: 'Löschen',
systemIcon: 'trash',
destructive: true,
id: 'delete',
},
]}
onPress={handleMenuPress}
previewBackgroundColor={isDark ? '#1e1e1e' : '#ffffff'}
>
<View style={styles.yourElement}>
<Text>Rechtsklick oder lange drücken für Optionen</Text>
</View>
</ContextMenu>
);
}
Anwendungsfälle
- Kontextmenüs für Listenelemente
- Dropdown-Menüs für Schaltflächen
- Zusätzliche Aktionen für UI-Elemente
- Alle Menüs, die an ein bestimmtes Element gebunden sind
Richtlinien für die Menüauswahl
-
Action Sheet verwenden wenn:
- Eine Bestätigung vom Benutzer benötigt wird
- Eine Auswahl aus einer Liste von Optionen angeboten wird
- Die Aktion nicht an ein bestimmtes UI-Element gebunden ist
- Modale Dialoge ersetzt werden sollen
-
Context Menu verwenden wenn:
- Das Menü an ein bestimmtes UI-Element gebunden ist
- Rechtsklick- oder Long-Press-Funktionalität benötigt wird
- Mehrere Aktionen für ein Element angeboten werden
- Eine native Menüerfahrung gewünscht ist
Dark Mode Unterstützung
Beide Menütypen unterstützen den Dark Mode:
- Action Sheet: Verwendet
userInterfaceStyleauf iOS und benutzerdefinierte Styling-Props auf Android/Web - Context Menu: Verwendet
previewBackgroundColorund native Darstellung
Beispiele
Beispiele für die Verwendung beider Menütypen findest du in:
components/organisms/AudioPlayer.tsx- Action Sheet für Löschbestätigungcomponents/atoms/RecordingButton.tsx- Action Sheet für Aufnahmebestätigung