android ui bugs

This commit is contained in:
DocNR 2025-03-12 22:35:41 -04:00
parent 43df1aeb79
commit ea5dde32f4
3 changed files with 165 additions and 75 deletions

View File

@ -14,6 +14,7 @@ import { FilterSheet, type FilterOptions, type SourceType } from '@/components/l
import { useWorkoutStore } from '@/stores/workoutStore'; import { useWorkoutStore } from '@/stores/workoutStore';
import { generateId } from '@/utils/ids'; import { generateId } from '@/utils/ids';
import { useNDKStore } from '@/lib/stores/ndk'; import { useNDKStore } from '@/lib/stores/ndk';
import { useIconColor } from '@/lib/theme/iconUtils';
// Default available filters // Default available filters
const availableFilters = { const availableFilters = {
@ -35,7 +36,8 @@ export default function ExercisesScreen() {
const [filterSheetOpen, setFilterSheetOpen] = useState(false); const [filterSheetOpen, setFilterSheetOpen] = useState(false);
const [currentFilters, setCurrentFilters] = useState<FilterOptions>(initialFilters); const [currentFilters, setCurrentFilters] = useState<FilterOptions>(initialFilters);
const [activeFilters, setActiveFilters] = useState(0); const [activeFilters, setActiveFilters] = useState(0);
const { getIconProps } = useIconColor();
// Exercise sheet state // Exercise sheet state
const [showExerciseSheet, setShowExerciseSheet] = useState(false); const [showExerciseSheet, setShowExerciseSheet] = useState(false);
const [exerciseToEdit, setExerciseToEdit] = useState<ExerciseDisplay | undefined>(undefined); const [exerciseToEdit, setExerciseToEdit] = useState<ExerciseDisplay | undefined>(undefined);
@ -200,36 +202,37 @@ export default function ExercisesScreen() {
return ( return (
<View className="flex-1 bg-background"> <View className="flex-1 bg-background">
{/* Search bar with filter button */} {/* Search bar with filter button */}
<View className="px-4 py-2 border-b border-border"> <View className="px-4 py-2 border-b border-border">
<View className="flex-row items-center"> <View className="flex-row items-center">
<View className="relative flex-1"> <View className="relative flex-1">
<View className="absolute left-3 z-10 h-full justify-center"> <View className="absolute left-3 z-10 h-full justify-center">
<Search size={18} className="text-muted-foreground" /> <Search size={18} {...getIconProps('primary')} />
</View>
<Input
value={searchQuery}
onChangeText={setSearchQuery}
placeholder="Search exercises"
className="pl-9 pr-10 bg-muted/50 border-0"
/>
<View className="absolute right-2 z-10 h-full justify-center">
<Button
variant="ghost"
size="icon"
onPress={() => setFilterSheetOpen(true)}
>
<View className="relative">
<ListFilter className="text-muted-foreground" size={20} />
{activeFilters > 0 && (
<View className="absolute -top-1 -right-1 w-2.5 h-2.5 rounded-full" style={{ backgroundColor: '#f7931a' }} />
)}
</View> </View>
</Button> <Input
value={searchQuery}
onChangeText={setSearchQuery}
placeholder="Search exercises"
className="pl-9 pr-10 border-0 bg-background"
/>
<View className="absolute right-2 z-10 h-full justify-center">
<Button
variant="ghost"
size="icon"
onPress={() => setFilterSheetOpen(true)}
>
<View className="relative">
<ListFilter size={20} {...getIconProps('primary')} />
{activeFilters > 0 && (
<View className="absolute -top-1 -right-1 w-2.5 h-2.5 rounded-full" style={{ backgroundColor: '#f7931a' }} />
)}
</View>
</Button>
</View>
</View>
</View> </View>
</View> </View>
</View> );
</View>
{/* Filter Sheet */} {/* Filter Sheet */}
<FilterSheet <FilterSheet

View File

@ -1,47 +0,0 @@
// components/library/SearchPopover.tsx
import React from 'react';
import { View } from 'react-native';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Search, X } from 'lucide-react-native';
interface SearchPopoverProps {
searchQuery: string;
onSearchChange: (query: string) => void;
}
export function SearchPopover({ searchQuery, onSearchChange }: SearchPopoverProps) {
const [isOpen, setIsOpen] = React.useState(false);
return (
<Popover onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon">
<Search className="text-foreground" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-80 p-0" align="end">
<View className="flex-row items-center p-2 gap-2">
<Input
placeholder="Search exercises..."
value={searchQuery}
onChangeText={onSearchChange}
className="flex-1"
autoFocus
placeholderTextColor="text-muted-foreground"
/>
{searchQuery.length > 0 && (
<Button
variant="ghost"
size="icon"
onPress={() => onSearchChange('')}
>
<X size={20} className="text-muted-foreground" />
</Button>
)}
</View>
</PopoverContent>
</Popover>
);
}

View File

@ -0,0 +1,134 @@
# POWR App Styling Guide
This document outlines how to consistently style components in the POWR fitness app.
## Color System
All colors are defined in the theme system and should be accessed through it rather than hardcoded values.
### Import Path
```typescript
import { useIconColor } from '@/lib/theme/iconUtils';
import { FIXED_COLORS } from '@/lib/theme/colors';
Icon Styling
Icons must use the icon utility to ensure visibility on both iOS and Android:
typescriptCopy// Import icon utility
import { useIconColor } from '@/lib/theme/iconUtils';
// Inside your component
const { getIconProps, getIconColor } = useIconColor();
// Apply to icons
<Icon
size={24}
{...getIconProps('primary')} // Use appropriate variant
/>
Icon Variants
primary - For main actions and interactive elements (purple)
muted - For secondary or less important actions (gray)
destructive - For delete/remove actions (red)
success - For confirmation/complete actions (green)
warning - For caution indicators (yellow/orange)
Examples
tsxCopy// Primary action icon
<Play {...getIconProps('primary')} size={20} />
// Destructive action icon
<Trash2 {...getIconProps('destructive')} size={20} />
// Icon with custom fill
<Star
{...getIconProps(isFavorite ? 'primary' : 'muted')}
fill={isFavorite ? getIconColor('primary') : "none"}
size={20}
/>
Button Styling
Use the standard button component with appropriate variants:
tsxCopy// Primary button
<Button variant="default" className="w-full">
<Text className="text-primary-foreground">Primary Action</Text>
</Button>
// Destructive button
<Button variant="destructive" className="w-full">
<Text className="text-destructive-foreground">Delete</Text>
</Button>
// Outline button
<Button variant="outline" className="w-full">
<Text>Secondary Action</Text>
</Button>
Header Component
Use the Header component consistently:
tsxCopy// Standard header with title
<Header title="Screen Title" showNotifications={true} />
// Header with logo
<Header useLogo={true} showNotifications={true} />
// Header with custom right element
<Header
title="Screen Title"
rightElement={<YourCustomElement />}
/>
Text Styling
Use the Text component with appropriate Tailwind classes:
tsxCopy// Headings
<Text className="text-xl font-semibold text-foreground">Heading</Text>
// Body text
<Text className="text-base text-foreground">Regular text</Text>
// Secondary text
<Text className="text-sm text-muted-foreground">Secondary text</Text>
Card Components
Use the Card component for content blocks:
tsxCopy<Card className="mx-4">
<CardContent className="p-4">
{/* Card content */}
</CardContent>
</Card>
Dialog/Alert Styling
Center buttons in dialogs:
tsxCopy<AlertDialog>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
<Text>Alert Title</Text>
</AlertDialogTitle>
<AlertDialogDescription>
<Text>Alert description text.</Text>
</AlertDialogDescription>
</AlertDialogHeader>
<View className="flex-row justify-center gap-3">
<AlertDialogCancel>
<Text>Cancel</Text>
</AlertDialogCancel>
<AlertDialogAction className="bg-destructive">
<Text className="text-destructive-foreground">Confirm</Text>
</AlertDialogAction>
</View>
</AlertDialogContent>
</AlertDialog>
Best Practices
Never use hardcoded colors - Always use theme variables through Tailwind classes
Always use getIconProps for icons - Ensures visibility on both iOS and Android
Use semantic variants - Choose button and icon variants based on their purpose
Maintain consistent spacing - Use Tailwind spacing classes (p-4, m-2, etc.)
Check both platforms - Test UI changes on both iOS and Android
Troubleshooting
If icons aren't appearing on Android:
Ensure you're using getIconProps() instead of className for the icon
Add strokeWidth={2} for better visibility on Android
Check that the icon has a size specified
If colors seem inconsistent:
Verify you're using Tailwind classes (text-primary vs #8B5CF6)
Check that the correct variant is being used for your component