-
Notifications
You must be signed in to change notification settings - Fork 0
finishing: Mvp/kopi maker #5 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9030be0
aebdd05
0fd08a7
5509d35
075d39f
1bd6f72
636db6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| ## Runtime & Framework | ||
| - Expo SDK `~54.0.25`, React `19.1.0`, React Native `0.81.5`, web via `react-native-web ~0.21.0`. | ||
| - `expo-router ~6.0.15` entry (`main: expo-router/entry`), React Navigation 7.x stack libs present. | ||
|
|
||
| ## Routing & Navigation | ||
| - Root stack in `app/_layout.tsx`; tabs group in `app/(tabs)/_layout.tsx` uses custom bottom bar. | ||
| - Tabs: Home, Favorites, Kopi (center FAB-style), Orders, Me. Custom tab bar has rounded background, inset, and lifted Kopi button sized via constants at top of the file. | ||
| - Modal example removed (deleted `app/modal.tsx` and stack registration). | ||
|
|
||
| ## Styling | ||
| - NativeWind `^4.2.1` with Babel `jsxImportSource: "nativewind"` + `nativewind/babel`; Metro wrapped with `withNativeWind(config, { input: "./global.css" })`. | ||
| - Tailwind `^3.4.18`; `tailwind.config.js` scans `./App.tsx`, `./app/**/*`, `./components/**/*`. Colors extended to coffee palette via CSS variables in `global.css` (currently only light-mode values). | ||
|
|
||
| ## State & Domain | ||
| - Zustand store `stores/kopiMakerStore.ts`: holds kopi selection (`milkiness`, `sweetness`, `strength`, `temperature`), setters/reset, derived `baseName/displayName/phrase` via `utils/kopiInfer`. | ||
| - Domain types `types/kopi.ts`: option groups, option lists, `KopiSelection`, default selection. Temperature replaces earlier “state” naming. | ||
| - `utils/kopiInfer.ts`: maps selection to kopi naming parts. | ||
|
|
||
| ## UI Pages | ||
| - Tab screens (`app/(tabs)/*.tsx`) are placeholders using Tailwind color tokens; Home/Kopi/Favorites/Orders/Me minimal content. | ||
| - Template components `hello-wave`, `parallax-scroll-view`, `external-link` removed. `haptic-tab.tsx` remains for tab haptics; `themed-text`/`themed-view` only used in deleted modal. | ||
|
|
||
| ## Tooling | ||
| - TypeScript `~5.9.2`, strict with `@/*` alias. ESLint `^9.25.0` + `eslint-config-expo ~10.0.0`; `prettier-plugin-tailwindcss ^0.5.14`. | ||
| - Metro customized only for NativeWind; Babel preset is `babel-preset-expo`. | ||
|
|
||
| ## Platform Config | ||
| - app.json: slug/name `kopi-shop`, scheme `kopishop`, portrait, automatic UI mode, static web output. | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,114 @@ | ||||||||||||||||||||||||||||||||||||||
| import { Text, View } from 'react-native'; | ||||||||||||||||||||||||||||||||||||||
| import { KopiCupPreview, OptionSelector } from "@/components/kopi"; | ||||||||||||||||||||||||||||||||||||||
| import { useKopiMakerStore } from "@/stores/kopiMakerStore"; | ||||||||||||||||||||||||||||||||||||||
| import { Colors } from "@/constants/theme"; | ||||||||||||||||||||||||||||||||||||||
| import { useColorScheme } from "@/hooks/use-color-scheme"; | ||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||
| MILKINESS_OPTIONS, | ||||||||||||||||||||||||||||||||||||||
| STRENGTH_OPTIONS, | ||||||||||||||||||||||||||||||||||||||
| SWEETNESS_OPTIONS, | ||||||||||||||||||||||||||||||||||||||
| TEMPERATURE_OPTIONS, | ||||||||||||||||||||||||||||||||||||||
| } from "@/types/kopi"; | ||||||||||||||||||||||||||||||||||||||
| import { Dimensions, Pressable, ScrollView, Text, View } from "react-native"; | ||||||||||||||||||||||||||||||||||||||
| import Svg, { Path } from "react-native-svg"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const { width } = Dimensions.get("window"); | ||||||||||||||||||||||||||||||||||||||
| const CURVE_HEIGHT = 80; | ||||||||||||||||||||||||||||||||||||||
| const CURVE_DEPTH = 50; | ||||||||||||||||||||||||||||||||||||||
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export default function KopiScreen() { | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+11
to
19
|
||||||||||||||||||||||||||||||||||||||
| import { Dimensions, Pressable, ScrollView, Text, View } from "react-native"; | |
| import Svg, { Path } from "react-native-svg"; | |
| const { width } = Dimensions.get("window"); | |
| const CURVE_HEIGHT = 80; | |
| const CURVE_DEPTH = 50; | |
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | |
| export default function KopiScreen() { | |
| import { Pressable, ScrollView, Text, View, useWindowDimensions } from "react-native"; | |
| import Svg, { Path } from "react-native-svg"; | |
| const CURVE_HEIGHT = 80; | |
| const CURVE_DEPTH = 50; | |
| const SVG_H = CURVE_HEIGHT + CURVE_DEPTH; | |
| export default function KopiScreen() { | |
| const { width } = useWindowDimensions(); |
Copilot
AI
Nov 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
{/* Smile curve divider */}| {/* 微笑曲线分界 */} | |
| {/* Smile curve divider */} |
Copilot
AI
Nov 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This inline comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
// Key: Push down by CURVE_DEPTH so the "curve edge" aligns at the boundary| // 关键:往下压 CURVE_DEPTH,让“曲线边”贴在分界处 | |
| // Key: Push down by CURVE_DEPTH so the "curve edge" aligns at the boundary |
Copilot
AI
Nov 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This inline comment is in Chinese. Code comments should be in English for consistency and accessibility.
Suggestion: Replace with an English comment like:
elevation: 999, // Needed for Android| elevation: 999, // 安卓需要 | |
| elevation: 999, // Needed for Android |
Copilot
AI
Nov 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "Brew" button lacks accessibility properties, which makes it less accessible to users with screen readers.
Recommendation: Add accessibilityLabel and accessibilityRole:
<Pressable
className="bg-dark-coffee py-4 rounded-2xl items-center shadow-lg active:opacity-90"
onPress={() => console.log("Brewing:", phrase)}
accessibilityLabel={`Brew ${phrase}`}
accessibilityRole="button"
>| onPress={() => console.log("Brewing:", phrase)} | |
| onPress={() => console.log("Brewing:", phrase)} | |
| accessibilityLabel={`Brew ${phrase}`} | |
| accessibilityRole="button" |
Copilot
AI
Nov 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a console.log statement in the production code. While this might be a placeholder for future functionality, console logs should generally be removed from production code or replaced with proper logging/handling.
Recommendation: Either implement the actual brew functionality or remove the console log and add a TODO comment:
onPress={() => {
// TODO: Implement brew functionality
}}| onPress={() => console.log("Brewing:", phrase)} | |
| onPress={() => { | |
| // TODO: Implement brew functionality | |
| }} |
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| import React from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { Dimensions, Text, View } from 'react-native'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| interface KopiCupPreviewProps { | ||||||||||||||||||||||||||||||||||||||||||||||
| name: string; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const { width } = Dimensions.get('window'); | ||||||||||||||||||||||||||||||||||||||||||||||
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+2
to
+11
|
||||||||||||||||||||||||||||||||||||||||||||||
| import { Dimensions, Text, View } from 'react-native'; | |
| interface KopiCupPreviewProps { | |
| name: string; | |
| } | |
| const { width } = Dimensions.get('window'); | |
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge | |
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { | |
| import { useWindowDimensions, Text, View } from 'react-native'; | |
| interface KopiCupPreviewProps { | |
| name: string; | |
| } | |
| export const KopiCupPreview = ({ name }: KopiCupPreviewProps) => { | |
| const { width } = useWindowDimensions(); | |
| const curveRadius = width; // big radius to form a smooth smile at the bottom edge |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import type { OptionItem } from '@/types/kopi'; | ||
| import React from 'react'; | ||
| import { Pressable, Text, View } from 'react-native'; | ||
|
|
||
| interface OptionSelectorProps<T extends string> { | ||
| label: string; | ||
| options: OptionItem<T>[]; | ||
| value: T; | ||
| onChange: (value: T) => void; | ||
| } | ||
|
|
||
| export const OptionSelector = <T extends string>({ | ||
| label, | ||
| options, | ||
| value, | ||
| onChange, | ||
| }: OptionSelectorProps<T>) => { | ||
| return ( | ||
| <View className="mb-6"> | ||
| <Text className="text-lg font-bold text-dark-coffee mb-3 px-4">{label}</Text> | ||
| <View | ||
| style={{ | ||
| flexDirection: 'row', | ||
| flexWrap: 'wrap', | ||
| gap: 10, | ||
| rowGap: 10, | ||
| paddingHorizontal: 16, | ||
| }}> | ||
| {options.map((option) => { | ||
| const isSelected = option.code === value; | ||
| return ( | ||
| <Pressable | ||
| key={option.code} | ||
| onPress={() => onChange(option.code)} | ||
| className={`px-4 py-2 rounded-md border ${ | ||
| isSelected | ||
| ? 'bg-dark-coffee border-dark-coffee' | ||
| : 'bg-cream border-grey' | ||
| }`} | ||
|
Comment on lines
+32
to
+39
|
||
| > | ||
| <Text className={`text-base font-semibold ${isSelected ? 'text-white' : 'text-dark-coffee'}`}> | ||
| {option.label} | ||
| </Text> | ||
| </Pressable> | ||
| ); | ||
| })} | ||
| </View> | ||
| </View> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * from './KopiCupPreview'; | ||
| export * from './OptionSelector'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence is unclear: "Temperature replaces earlier 'state' naming." This seems to reference previous code state that reviewers cannot see, making the documentation confusing for someone new to the codebase.
Recommendation: Either clarify what this means or remove this historical reference: