Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
954 changes: 954 additions & 0 deletions documentation/design-tokens.css

Large diffs are not rendered by default.

531 changes: 531 additions & 0 deletions documentation/design-tokens.rn.ts

Large diffs are not rendered by default.

583 changes: 583 additions & 0 deletions documentation/design.md

Large diffs are not rendered by default.

98 changes: 98 additions & 0 deletions documentation/mobile-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# YSTEM Mobile App — UI/UX Screen Library

Designed by Sandith Hewage (UI/UX Engineer, Y STEM and Chess)
For the Cal Poly CSS team building the React Native + Expo mobile app.

---

## Overview

This directory contains all screen components for the YSTEM mobile app across 5 SOW deliverables:

| Deliverable | Screens |
|---|---|
| D1 — Auth + Navigation | `LoginScreen`, `SignUpScreen`, `TabNavigator`, `HomeScreen` |
| D2 — Lessons | `LessonsSelectionScreen`, `LessonScreen` |
| D3 — Puzzles | `PuzzlesScreen` |
| D4 — Play vs Computer | `PlaySetupScreen`, `PlayGameScreen` |

---

## File Structure

```
mobile-ui/
├── screens/
│ ├── LoginScreen.tsx # D1 — Email/password login
│ ├── SignUpScreen.tsx # D1 — Registration with role selector
│ ├── HomeScreen.tsx # D1 — Welcome hero, stats, activity feed
│ ├── LessonsSelectionScreen.tsx # D2 — Piece cards + lesson list
│ ├── LessonScreen.tsx # D2 — Board + instruction walkthrough
│ ├── PuzzlesScreen.tsx # D3 — Full-width board + puzzle info
│ ├── PlaySetupScreen.tsx # D4 — Color picker + difficulty grid
│ └── PlayGameScreen.tsx # D4 — Live game board + tutor panel
├── navigation/
│ └── TabNavigator.tsx # D1 — Bottom tab bar
└── README.md
```

---

## Setup

### 1. Install dependencies

```bash
npx expo install @expo-google-fonts/lato expo-font expo-linear-gradient
npx expo install react-native-safe-area-context @react-navigation/native @react-navigation/bottom-tabs
```

### 2. Copy design tokens

Copy `design-tokens.rn.ts` (one level up: `documentation/design-tokens.rn.ts`) into your project src:

```bash
cp documentation/design-tokens.rn.ts src/design-tokens.rn.ts
```

### 3. Update token imports

Each screen imports from `'../design-tokens.rn'` — adjust the relative path to match your project structure.

### 4. Load fonts in App.tsx

```tsx
import { useFonts, Lato_400Regular, Lato_700Bold } from '@expo-google-fonts/lato';

export default function App() {
const [fontsLoaded] = useFonts({ Lato_400Regular, Lato_700Bold });
if (!fontsLoaded) return null;
// ...
}
```

---

## Design Principles

- **All colors, spacing, radius, and shadows** come from `design-tokens.rn.ts` — no hardcoded hex values
- **Screen background:** `colors.soft` (#E5F3D2)
- **Card surfaces:** `colors.light` (#F9FAF7)
- **Primary CTA:** `btnPrimaryStyle` (dark pill)
- **Green CTA:** `btnGreenStyle` (brand green rounded)
- **Min tap target:** 44pt for all interactive elements
- **Chess board:** `aspectRatio: 1` + `width: '100%'` for square constraint
- **Safe area:** All screens wrap content in `SafeAreaView` or add `paddingBottom` for home indicator

---

## Brand Colors Quick Reference

| Token | Hex | Use |
|---|---|---|
| `primary` | `#7FCC26` | CTAs, active states, progress |
| `secondary` | `#BFD99E` | Inactive tabs, muted accents |
| `soft` | `#E5F3D2` | Screen backgrounds |
| `accent` | `#EAD94C` | Streaks, badges, highlights |
| `dark` | `#1F1F1F` | Text, btn-primary background |
| `light` | `#F9FAF7` | Card surfaces, form fields |
237 changes: 237 additions & 0 deletions documentation/mobile-ui/navigation/TabNavigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/**
* TabNavigator.tsx
* D1 — Auth + Navigation
*
* YSTEM Mobile App — Y STEM and Chess
* Designed by Sandith Hewage (UI/UX Engineer)
*
* Bottom tab bar: Home | Lessons | Puzzles | Play | Profile
*
* Requires:
* @react-navigation/native
* @react-navigation/bottom-tabs
* react-native-safe-area-context
*/

import React from 'react';
import { View, Text, StyleSheet, Platform } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import {
colors,
spacing,
fontSize,
fontFamily,
fontWeight,
radius,
shadows,
} from '../design-tokens.rn';

// ---------------------------------------------------------------------------
// Tab Param List
// ---------------------------------------------------------------------------

export type TabParamList = {
Home: undefined;
Lessons: undefined;
Puzzles: undefined;
Play: undefined;
Profile: undefined;
};

const Tab = createBottomTabNavigator<TabParamList>();

// ---------------------------------------------------------------------------
// Icon components (SVG-free placeholders — swap for lucide-react-native icons)
// ---------------------------------------------------------------------------

interface TabIconProps {
label: string;
focused: boolean;
emoji: string;
}

function TabIcon({ label, focused, emoji }: TabIconProps) {
return (
<View style={[styles.iconWrapper, focused && styles.iconWrapperActive]}>
<Text style={[styles.iconEmoji, focused && styles.iconEmojiActive]}>{emoji}</Text>
</View>
);
}

// ---------------------------------------------------------------------------
// Screen placeholders (replace with actual screen imports)
// ---------------------------------------------------------------------------

// Import your screens here:
// import HomeScreen from '../screens/HomeScreen';
// import LessonsSelectionScreen from '../screens/LessonsSelectionScreen';
// import PuzzlesScreen from '../screens/PuzzlesScreen';
// import PlaySetupScreen from '../screens/PlaySetupScreen';
// import ProfileScreen from '../screens/ProfileScreen';

// Placeholder components for development
const Placeholder = ({ name }: { name: string }) => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.soft }}>
<Text style={{ fontFamily: fontFamily.bold, fontSize: fontSize.xl, color: colors.dark }}>{name}</Text>
</View>
);

// ---------------------------------------------------------------------------
// Navigator
// ---------------------------------------------------------------------------

export default function TabNavigator() {
return (
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarStyle: styles.tabBar,
tabBarActiveTintColor: colors.primary,
tabBarInactiveTintColor: colors.secondary,
tabBarLabelStyle: styles.tabLabel,
tabBarItemStyle: styles.tabItem,
tabBarHideOnKeyboard: true,
}}
>
<Tab.Screen
name="Home"
component={() => <Placeholder name="Home" />}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<TabIcon label="Home" focused={focused} emoji="🏠" />
),
}}
/>

<Tab.Screen
name="Lessons"
component={() => <Placeholder name="Lessons" />}
options={{
tabBarLabel: 'Lessons',
tabBarIcon: ({ focused }) => (
<TabIcon label="Lessons" focused={focused} emoji="📚" />
),
}}
/>

{/* Center Play tab — visually elevated */}
<Tab.Screen
name="Play"
component={() => <Placeholder name="Play" />}
options={{
tabBarLabel: 'Play',
tabBarIcon: ({ focused }) => (
<View style={styles.centerTabContainer}>
<View style={[styles.centerTabButton, focused && styles.centerTabButtonActive]}>
<Text style={styles.centerTabEmoji}>♟</Text>
</View>
</View>
),
tabBarLabelStyle: { ...styles.tabLabel, marginTop: 28 },
}}
/>

<Tab.Screen
name="Puzzles"
component={() => <Placeholder name="Puzzles" />}
options={{
tabBarLabel: 'Puzzles',
tabBarIcon: ({ focused }) => (
<TabIcon label="Puzzles" focused={focused} emoji="🧩" />
),
}}
/>

<Tab.Screen
name="Profile"
component={() => <Placeholder name="Profile" />}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ focused }) => (
<TabIcon label="Profile" focused={focused} emoji="👤" />
),
}}
/>
</Tab.Navigator>
);
}

// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------

const styles = StyleSheet.create({
tabBar: {
backgroundColor: colors.light,
borderTopWidth: 1,
borderTopColor: colors.borderLight,
height: Platform.OS === 'ios' ? 88 : 68,
paddingBottom: Platform.OS === 'ios' ? 28 : 8,
paddingTop: spacing[2],
...shadows.md,
},

tabItem: {
paddingTop: spacing[1],
},

tabLabel: {
fontSize: fontSize.xs,
fontFamily: fontFamily.bold,
fontWeight: fontWeight.bold,
letterSpacing: 0.3,
marginTop: 2,
},

// ── Regular tab icon ─────────────────────────────────

iconWrapper: {
width: 32,
height: 32,
borderRadius: radius.lg,
alignItems: 'center',
justifyContent: 'center',
},

iconWrapperActive: {
backgroundColor: colors.primaryFaint,
},

iconEmoji: {
fontSize: 18,
opacity: 0.5,
},

iconEmojiActive: {
opacity: 1,
},

// ── Center Play tab ───────────────────────────────────

centerTabContainer: {
alignItems: 'center',
justifyContent: 'center',
marginTop: -20, // Lifts the button above the tab bar
},

centerTabButton: {
width: 56,
height: 56,
borderRadius: radius.full,
backgroundColor: colors.dark,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 3,
borderColor: colors.light,
...shadows.lg,
},

centerTabButtonActive: {
backgroundColor: colors.primary,
},

centerTabEmoji: {
fontSize: 24,
},
});
Loading
Loading