diff --git a/tamagui-expo-app/.gitignore b/tamagui-expo-app/.gitignore new file mode 100644 index 0000000..1b3c72a --- /dev/null +++ b/tamagui-expo-app/.gitignore @@ -0,0 +1,43 @@ +# Node +node_modules/ +npm-debug.log +yarn-error.log + +# Expo +.expo/ +.expo-shared/ +dist/ +web-build/ + +# Native +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# Debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# Typescript +*.tsbuildinfo + +# Misc +.DS_Store +*.pem +.env +.env.local +.env.*.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ diff --git a/tamagui-expo-app/App.tsx b/tamagui-expo-app/App.tsx new file mode 100644 index 0000000..a50cca9 --- /dev/null +++ b/tamagui-expo-app/App.tsx @@ -0,0 +1,102 @@ +import React, { useState } from 'react' +import { StatusBar } from 'expo-status-bar' +import { NavigationContainer } from '@react-navigation/native' +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' +import { TamaguiProvider, Theme, YStack, Text } from 'tamagui' +import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context' +import tamaguiConfig from './src/theme/theme' +import { HomePage } from './src/screens/HomePage' +import { DemoPage } from './src/screens/DemoPage' + +const Tab = createBottomTabNavigator() + +export default function App() { + const [isDark, setIsDark] = useState(true) + + return ( + + + + + + + + + + ( + + ), + }} + > + {() => ( + {}} + /> + )} + + + ( + + ), + }} + /> + + + + + + + + ) +} diff --git a/tamagui-expo-app/README.md b/tamagui-expo-app/README.md new file mode 100644 index 0000000..707ca14 --- /dev/null +++ b/tamagui-expo-app/README.md @@ -0,0 +1,162 @@ +# Tamagui Expo App + +A beautiful React Native app built with Expo and Tamagui, featuring a stunning teal → blue gradient theme and a comprehensive UI component library. + +## Features + +- **Tamagui UI Framework**: Fast, performant UI components with zero-runtime styling +- **Custom Theme System**: Beautiful gradient theme with teal → blue palette +- **Complete Component Library**: Buttons, inputs, cards, sliders, switches, and more +- **Tab Navigation**: Smooth navigation between Home and Components showcase +- **Dark/Light Mode**: Seamless theme switching support +- **Gradient Components**: Stunning gradient cards and buttons +- **TypeScript**: Full type safety and IntelliSense +- **Expo**: Easy development and deployment across iOS, Android, and Web +- **High-End Design**: Clean, professional UI with attention to detail + +## Theme Colors + +- **Primary A**: `#00B4DB` (Teal) +- **Primary B**: `#0083B0` (Deep Blue) +- **Hover States**: Lighter gradient variations +- **Press States**: Darker gradient variations + +## Getting Started + +### Prerequisites + +- Node.js (v18 or newer) +- npm or yarn +- Expo CLI (optional, but recommended) + +### Installation + +1. Install dependencies: +```bash +cd tamagui-expo-app +npm install +``` + +2. Start the development server: +```bash +npm start +``` + +3. Run on your platform: +```bash +npm run ios # Run on iOS simulator +npm run android # Run on Android emulator +npm run web # Run on web browser +``` + +## Project Structure + +``` +tamagui-expo-app/ +├── src/ +│ ├── components/ +│ │ ├── CubeButton.tsx # Gradient button with interactive states +│ │ ├── StyledCard.tsx # Card component with variants +│ │ ├── StyledInput.tsx # Form input with validation +│ │ └── GradientCard.tsx # Gradient background card +│ ├── screens/ +│ │ ├── HomePage.tsx # Home screen with theme toggle +│ │ └── DemoPage.tsx # Complete UI showcase +│ └── theme/ +│ └── theme.ts # Tamagui theme configuration +├── App.tsx # Main app with navigation +├── package.json +├── tsconfig.json +├── babel.config.js +└── app.json +``` + +## UI Components + +### CubeButton +Interactive gradient button with hover and press states: +```tsx + console.log('Pressed!')} + disabled={false} +/> +``` + +### StyledCard +Versatile card component with multiple variants: +```tsx + + Card content + +``` +Variants: `default`, `elevated`, `outlined` + +### GradientCard +Beautiful gradient background card: +```tsx + + Gradient content + +``` +Variants: `base`, `hover`, `press` + +### StyledInput +Form input with labels and validation: +```tsx + +``` + +## Screens + +### HomePage +- Interactive counter demo +- Theme toggle (dark/light mode) +- Quick stats showcase +- Feature list +- Navigation to component library + +### DemoPage (Components Showcase) +A comprehensive showcase featuring: +- **Gradient Cards**: Multiple gradient card examples +- **Buttons**: Primary, outlined, text, and disabled states +- **Form Inputs**: Text, password, multiline, and validation states +- **Switches & Controls**: Toggle switches with descriptions +- **Sliders & Progress**: Interactive sliders and progress bars +- **Avatars & Badges**: User avatars and status indicators +- **Card Variants**: Different card styles and elevations +- **Statistics Grid**: Beautiful stat displays +- **Typography**: Complete type scale showcase + +## Theme System + +The theme is configured in `src/theme/theme.ts` and includes: +- **Color Tokens**: Complete color palette with gradient variations +- **Spacing**: Consistent spacing scale (0-48px) +- **Sizing**: Component size tokens +- **Radius**: Border radius tokens (0-999) +- **Typography**: Font families, sizes, and weights +- **Shorthands**: px, py, mx, my for faster development +- **Theme Variants**: Dark and light mode support + +## Customization + +To customize the theme, edit `src/theme/theme.ts`: + +```typescript +const colors = { + primaryA: '#00B4DB', // Change these colors + primaryB: '#0083B0', + // ... +} +``` + +## License + +MIT diff --git a/tamagui-expo-app/app.json b/tamagui-expo-app/app.json new file mode 100644 index 0000000..9f1f2af --- /dev/null +++ b/tamagui-expo-app/app.json @@ -0,0 +1,33 @@ +{ + "expo": { + "name": "Tamagui Expo App", + "slug": "tamagui-expo-app", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "userInterfaceStyle": "automatic", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#0b1f32" + }, + "assetBundlePatterns": [ + "**/*" + ], + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.tamagui.expoapp" + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#0b1f32" + }, + "package": "com.tamagui.expoapp" + }, + "web": { + "favicon": "./assets/favicon.png", + "bundler": "metro" + } + } +} diff --git a/tamagui-expo-app/assets/.gitkeep b/tamagui-expo-app/assets/.gitkeep new file mode 100644 index 0000000..f38479e --- /dev/null +++ b/tamagui-expo-app/assets/.gitkeep @@ -0,0 +1,2 @@ +# Placeholder for assets +# Add icon.png, splash.png, adaptive-icon.png, and favicon.png here diff --git a/tamagui-expo-app/babel.config.js b/tamagui-expo-app/babel.config.js new file mode 100644 index 0000000..09a4702 --- /dev/null +++ b/tamagui-expo-app/babel.config.js @@ -0,0 +1,17 @@ +module.exports = function(api) { + api.cache(true); + return { + presets: ['babel-preset-expo'], + plugins: [ + [ + '@tamagui/babel-plugin', + { + components: ['tamagui'], + config: './src/theme/theme.ts', + logTimings: true, + }, + ], + 'react-native-reanimated/plugin', + ], + }; +}; diff --git a/tamagui-expo-app/package.json b/tamagui-expo-app/package.json new file mode 100644 index 0000000..58a0b63 --- /dev/null +++ b/tamagui-expo-app/package.json @@ -0,0 +1,36 @@ +{ + "name": "tamagui-expo-app", + "version": "1.0.0", + "main": "node_modules/expo/AppEntry.js", + "scripts": { + "start": "expo start", + "android": "expo start --android", + "ios": "expo start --ios", + "web": "expo start --web" + }, + "dependencies": { + "@react-navigation/bottom-tabs": "^6.5.20", + "@react-navigation/native": "^6.1.17", + "@tamagui/config": "^1.112.21", + "@tamagui/core": "^1.112.21", + "@tamagui/font-inter": "^1.112.21", + "@tamagui/shorthands": "^1.112.21", + "@tamagui/theme-base": "^1.112.21", + "expo": "~51.0.0", + "expo-linear-gradient": "~13.0.2", + "expo-status-bar": "~1.12.1", + "react": "18.2.0", + "react-native": "0.74.5", + "react-native-safe-area-context": "4.10.5", + "react-native-screens": "~3.31.1", + "react-native-svg": "15.2.0", + "react-native-web": "~0.19.10", + "tamagui": "^1.112.21" + }, + "devDependencies": { + "@babel/core": "^7.24.0", + "@types/react": "~18.2.79", + "typescript": "~5.3.3" + }, + "private": true +} diff --git a/tamagui-expo-app/src/components/CubeButton.tsx b/tamagui-expo-app/src/components/CubeButton.tsx new file mode 100644 index 0000000..ecc48ba --- /dev/null +++ b/tamagui-expo-app/src/components/CubeButton.tsx @@ -0,0 +1,78 @@ +import React from 'react' +import { Pressable, StyleSheet } from 'react-native' +import { LinearGradient } from 'expo-linear-gradient' +import { Text, YStack, styled } from 'tamagui' +import { buttonTokens } from '../theme/theme' + +interface CubeButtonProps { + title: string + onPress?: () => void + disabled?: boolean +} + +export const CubeButton: React.FC = ({ + title, + onPress, + disabled = false +}) => { + const [isPressed, setIsPressed] = React.useState(false) + const [isHovered, setIsHovered] = React.useState(false) + + const getGradientColors = () => { + if (disabled) return ['#cccccc', '#999999'] + if (isPressed) return buttonTokens.gradient.press + if (isHovered) return buttonTokens.gradient.hover + return buttonTokens.gradient.base + } + + return ( + setIsPressed(true)} + onPressOut={() => setIsPressed(false)} + onHoverIn={() => setIsHovered(true)} + onHoverOut={() => setIsHovered(false)} + style={styles.container} + > + + + + {title} + + + + + ) +} + +const styles = StyleSheet.create({ + container: { + borderRadius: 12, + overflow: 'hidden', + shadowColor: '#000', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.15, + shadowRadius: 8, + elevation: 4, + }, + gradient: { + borderRadius: 12, + }, +}) diff --git a/tamagui-expo-app/src/components/GradientCard.tsx b/tamagui-expo-app/src/components/GradientCard.tsx new file mode 100644 index 0000000..91b27c0 --- /dev/null +++ b/tamagui-expo-app/src/components/GradientCard.tsx @@ -0,0 +1,47 @@ +import React from 'react' +import { StyleSheet } from 'react-native' +import { LinearGradient } from 'expo-linear-gradient' +import { YStack } from 'tamagui' +import { buttonTokens } from '../theme/theme' + +interface GradientCardProps { + children: React.ReactNode + variant?: 'base' | 'hover' | 'press' +} + +export const GradientCard: React.FC = ({ + children, + variant = 'base', +}) => { + const colors = buttonTokens.gradient[variant] + + return ( + + + + {children} + + + + ) +} + +const styles = StyleSheet.create({ + container: { + borderRadius: 16, + overflow: 'hidden', + shadowColor: '#000', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.15, + shadowRadius: 12, + elevation: 5, + }, + gradient: { + borderRadius: 16, + }, +}) diff --git a/tamagui-expo-app/src/components/StyledCard.tsx b/tamagui-expo-app/src/components/StyledCard.tsx new file mode 100644 index 0000000..64813bb --- /dev/null +++ b/tamagui-expo-app/src/components/StyledCard.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { YStack, styled } from 'tamagui' + +export const StyledCard = styled(YStack, { + padding: '$20', + borderRadius: '$16', + borderWidth: 1, + borderColor: '$borderColor', + backgroundColor: '$bg', + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.1, + shadowRadius: 8, + elevation: 3, + + variants: { + variant: { + elevated: { + shadowOpacity: 0.15, + shadowRadius: 12, + elevation: 5, + }, + outlined: { + borderWidth: 2, + shadowOpacity: 0, + elevation: 0, + }, + gradient: { + borderWidth: 0, + }, + }, + } as const, +}) diff --git a/tamagui-expo-app/src/components/StyledInput.tsx b/tamagui-expo-app/src/components/StyledInput.tsx new file mode 100644 index 0000000..f633039 --- /dev/null +++ b/tamagui-expo-app/src/components/StyledInput.tsx @@ -0,0 +1,71 @@ +import React from 'react' +import { Input, YStack, Text, styled } from 'tamagui' + +const BaseInput = styled(Input, { + backgroundColor: '$bg', + borderWidth: 1, + borderColor: '$borderColor', + borderRadius: '$12', + paddingHorizontal: '$16', + paddingVertical: '$12', + fontSize: 16, + color: '$color', + + focusStyle: { + borderColor: '$primaryA', + borderWidth: 2, + }, + + variants: { + error: { + true: { + borderColor: '#ef4444', + borderWidth: 2, + }, + }, + } as const, +}) + +interface StyledInputProps { + label?: string + placeholder?: string + value?: string + onChangeText?: (text: string) => void + error?: string + multiline?: boolean + secureTextEntry?: boolean +} + +export const StyledInput: React.FC = ({ + label, + placeholder, + value, + onChangeText, + error, + multiline = false, + secureTextEntry = false, +}) => { + return ( + + {label && ( + + {label} + + )} + + {error && ( + + {error} + + )} + + ) +} diff --git a/tamagui-expo-app/src/screens/DemoPage.tsx b/tamagui-expo-app/src/screens/DemoPage.tsx new file mode 100644 index 0000000..5395e4c --- /dev/null +++ b/tamagui-expo-app/src/screens/DemoPage.tsx @@ -0,0 +1,548 @@ +import React, { useState } from 'react' +import { ScrollView, Alert } from 'react-native' +import { + YStack, + XStack, + H1, + H2, + H3, + Text, + Button, + Switch, + Slider, + Progress, + Separator, + Avatar, + Circle, +} from 'tamagui' +import { StyledCard } from '../components/StyledCard' +import { StyledInput } from '../components/StyledInput' +import { GradientCard } from '../components/GradientCard' +import { CubeButton } from '../components/CubeButton' + +export const DemoPage = () => { + const [switchValue, setSwitchValue] = useState(true) + const [sliderValue, setSliderValue] = useState([50]) + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + + return ( + + + {/* Header Section */} + +

+ UI Components +

+ + A comprehensive showcase of beautifully styled components + +
+ + {/* Gradient Cards Section */} + +

+ Gradient Cards +

+ + + +

+ Premium Feature +

+ + Experience the power of gradient design with smooth color transitions + + + + + + +
+
+ + + + + + 2.5k + + + Active Users + + + + + + + + 98% + + + Satisfaction + + + + +
+ + {/* Buttons Section */} + +

+ Buttons +

+ + + + Alert.alert('Success', 'Button pressed!')} + /> + + + + {}} + /> + + + {}} + /> + + + + + + + + + + +
+ + {/* Form Inputs Section */} + +

+ Form Inputs +

+ + + + + + + + + + + + {}} /> + + +
+ + {/* Toggles & Switches Section */} + +

+ Switches & Controls +

+ + + + + + + Push Notifications + + + Receive updates about your account + + + + + + + + + + + + + Email Updates + + + Get weekly newsletter + + + + + + + + + + + + + Dark Mode + + + Toggle appearance + + + + + + + + +
+ + {/* Sliders & Progress Section */} + +

+ Sliders & Progress +

+ + + + + + + Volume + + + {sliderValue[0]}% + + + + + + + + + + + + + + + + Upload Progress + + + 75% + + + + + + + + + + + Storage Used + + + 45% + + + + + + + + +
+ + {/* Avatars & Badges Section */} + +

+ Avatars & Badges +

+ + + + + + + + + + + John Doe + + + john.doe@example.com + + + + + + + + + + + + JD + + + + + + + AB + + + + + + + CD + + + + + + + EF + + + + + + +
+ + {/* Cards Variants Section */} + +

+ Card Variants +

+ + + +

+ Elevated Card +

+ + This card has enhanced shadow for more depth + +
+
+ + + +

+ Outlined Card +

+ + This card uses a border instead of shadow + +
+
+ + + +

+ Default Card +

+ + Standard card with subtle shadow + +
+
+
+ + {/* Stats Grid */} + +

+ Statistics +

+ + + + + + 1.2k + + + Downloads + + + + + + + + 4.8 + + + Rating + + + + + + + + + + 256 + + + Reviews + + + + + + + + 99% + + + Uptime + + + + +
+ + {/* Typography Section */} + +

+ Typography +

+ + + + +

+ Heading 1 +

+ + 36px / 800 weight + +
+ + + + +

+ Heading 2 +

+ + 28px / 700 weight + +
+ + + + +

+ Heading 3 +

+ + 20px / 600 weight + +
+ + + + + + Body Text - Medium + + + 16px / 500 weight + + + + + + + + Body Text - Regular + + + 14px / 400 weight + + + + + + + + Caption Text + + + 12px / 400 weight + + +
+
+
+
+
+ ) +} diff --git a/tamagui-expo-app/src/screens/HomePage.tsx b/tamagui-expo-app/src/screens/HomePage.tsx new file mode 100644 index 0000000..ab172a0 --- /dev/null +++ b/tamagui-expo-app/src/screens/HomePage.tsx @@ -0,0 +1,246 @@ +import React, { useState } from 'react' +import { ScrollView } from 'react-native' +import { + YStack, + XStack, + H1, + H2, + Text, + Button, + Switch, +} from 'tamagui' +import { StyledCard } from '../components/StyledCard' +import { CubeButton } from '../components/CubeButton' +import { GradientCard } from '../components/GradientCard' + +interface HomePageProps { + isDark: boolean + onToggleTheme: (value: boolean) => void + onNavigateToDemo: () => void +} + +export const HomePage: React.FC = ({ + isDark, + onToggleTheme, + onNavigateToDemo, +}) => { + const [count, setCount] = useState(0) + + return ( + + + {/* Header */} + +

+ Tamagui Expo App +

+ + Beautiful UI with teal → blue gradient theme + +
+ + {/* Hero Gradient Card */} + + +

+ Welcome to Premium Design +

+ + Experience a carefully crafted UI system with beautiful gradients, + smooth animations, and perfect attention to detail. + + +
+
+ + {/* Theme Toggle */} + + + + + {isDark ? 'Dark' : 'Light'} Mode + + + Toggle appearance theme + + + + + + + + + {/* Counter Demo */} + +

+ Interactive Demo +

+ + + + + {count} + + + + + setCount(count + 1)} + /> + + + setCount(count - 1)} + /> + + + + + + +
+ + {/* Quick Stats */} + +

+ Quick Stats +

+ + + + + + 50+ + + + Components + + + + + + + + 100% + + + Responsive + + + + +
+ + {/* Features List */} + +

+ Features +

+ + + + + + + + + +
+ + {/* CTA */} + + + + View the complete component library + + +
+
+ ) +} + +const FeatureItem: React.FC<{ title: string; description: string }> = ({ + title, + description, +}) => ( + + + + + {title} + + + {description} + + + +) diff --git a/tamagui-expo-app/src/theme/theme.ts b/tamagui-expo-app/src/theme/theme.ts new file mode 100644 index 0000000..5053084 --- /dev/null +++ b/tamagui-expo-app/src/theme/theme.ts @@ -0,0 +1,100 @@ +// theme.ts — Tamagui theme config generated from the Cube Button preview +// Uses teal → blue palette to match your logo + +import { createTamagui } from 'tamagui' + +// --- Color tokens (logo-inspired) --- +const colors = { + white: '#FFFFFF', + black: '#000000', + // primary gradient endpoints + primaryA: '#00B4DB', // teal + primaryB: '#0083B0', // deep blue + primaryHoverA: '#00C6E0', + primaryHoverB: '#0092C4', + primaryPressA: '#009EC7', + primaryPressB: '#006C9E', + + // neutrals + gray50: '#f6f8fb', + gray900: '#101828', + night900: '#0b1f32', + sky50: '#e6f6ff', +} + +// --- Themes --- +const themes = { + light: { + bg: colors.gray50, + color: colors.gray900, + // brand surface + brandBg: colors.primaryA, + brandColor: colors.white, + borderColor: 'rgba(0,0,0,0.08)', + }, + dark: { + bg: colors.night900, + color: colors.sky50, + brandBg: colors.primaryB, + brandColor: colors.white, + borderColor: 'rgba(255,255,255,0.12)', + }, +} + +// --- Design tokens --- +const tokens = { + color: colors, + radius: { 0: 0, 4: 4, 8: 8, 12: 12, 16: 16, round: 999 }, + space: { + 0: 0, 2: 2, 4: 4, 6: 6, 8: 8, 10: 10, 12: 12, 14: 14, + 16: 16, 20: 20, 24: 24, 32: 32, 40: 40, 48: 48 + }, + size: { 1: 28, 2: 36, 3: 44, 4: 52, 5: 60 }, + zIndex: { 0: 0, 1: 1, 2: 2, 3: 3 }, +} + +// --- Shorthands --- +const shorthands = { + px: 'paddingHorizontal', + py: 'paddingVertical', + mx: 'marginHorizontal', + my: 'marginVertical', +} as const + +// --- Fonts --- +const fonts = { + body: { + family: 'System', + size: { 3: 16, 4: 18, 5: 20 }, + weight: { 4: '500', 6: '600' }, + lineHeight: { 3: 22, 4: 24, 5: 28 }, + letterSpacing: { 1: 0.4 }, + }, +} + +// --- Optional: semantic button colors to pair with CubeButton --- +export const buttonTokens = { + gradient: { + base: ['#00B4DB', '#0083B0'], // gradient colors for LinearGradient + hover: ['#00C6E0', '#0092C4'], + press: ['#009EC7', '#006C9E'], + }, + text: colors.white, +} + +// --- Create Tamagui config --- +export const tamaguiConfig = createTamagui({ + defaultTheme: 'dark', + themes, + tokens, + shorthands, + fonts, +}) + +export default tamaguiConfig + +export type AppConfig = typeof tamaguiConfig + +declare module 'tamagui' { + interface TamaguiCustomConfig extends AppConfig {} +} diff --git a/tamagui-expo-app/tsconfig.json b/tamagui-expo-app/tsconfig.json new file mode 100644 index 0000000..0557d1d --- /dev/null +++ b/tamagui-expo-app/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "jsx": "react-native", + "moduleResolution": "node", + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ".expo/types/**/*.ts", + "expo-env.d.ts" + ], + "exclude": [ + "node_modules" + ] +}