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
2 changes: 1 addition & 1 deletion .screenmap/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The Methods tab has an "About this guide" row that opens a modal.

## Real params

- `/brew/:id` → the id is a method id: `v60`, `aeropress` or `french-press`.
- `/brew/:id` → the id is a method id: `v60`, `aeropress`, `french-press` or `moka-pot`.
Use `v60`. Anything else falls back to the first method rather than erroring.

## Screens worth extra states
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ on-screen.
| `/method/v60` | Hario V60 — recipe, pour schedule, tips |
| `/method/aeropress` | AeroPress |
| `/method/french-press` | French Press |
| `/method/moka-pot` | Moka Pot |
| `/brew/[id]` | Brew timer for one method |
| `/grind` | Grind guide |
| `/about` | About, presented as a modal |
Expand Down
3 changes: 3 additions & 0 deletions src/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export default function MethodsScreen() {
<Link href="/method/french-press" asChild>
<MethodCard method={methodById('french-press')!} />
</Link>
<Link href="/method/moka-pot" asChild>
<MethodCard method={methodById('moka-pot')!} />
</Link>
</View>

<Link href="/about" asChild>
Expand Down
1 change: 1 addition & 0 deletions src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default function RootLayout() {
<Stack.Screen name="method/v60" options={{ title: 'Hario V60' }} />
<Stack.Screen name="method/aeropress" options={{ title: 'AeroPress' }} />
<Stack.Screen name="method/french-press" options={{ title: 'French Press' }} />
<Stack.Screen name="method/moka-pot" options={{ title: 'Moka Pot' }} />
<Stack.Screen name="brew/[id]" options={{ title: 'Brew timer' }} />
<Stack.Screen name="grind" options={{ title: 'Grind guide' }} />
<Stack.Screen name="about" options={{ presentation: 'modal', title: 'About Brew' }} />
Expand Down
19 changes: 19 additions & 0 deletions src/app/method/moka-pot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Link } from 'expo-router';

import { BrewTimerButton } from '@/components/brew-button';
import { MethodScreen } from '@/components/method-screen';
import { methodById } from '@/data/methods';

export default function MokaPotRoute() {
const method = methodById('moka-pot')!;
return (
<MethodScreen
method={method}
timer={
<Link href="/brew/moka-pot" asChild>
<BrewTimerButton seconds={method.totalTime} />
</Link>
}
/>
);
}
27 changes: 27 additions & 0 deletions src/data/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,33 @@ export const METHODS: Method[] = [
'Coarse means coarse. Fines are what make it muddy.',
],
},
{
id: 'moka-pot',
name: 'Moka Pot',
tagline: 'Stovetop, steam pressure',
ratio: '1:10',
dose: '18 g',
grind: 'fine',
water: '180 g, already boiling',
totalTime: 300,
body: 5,
clarity: 2,
effort: 3,
blurb:
'Steam pressure from the bottom chamber pushes water up through the coffee in one continuous shot. It is not espresso and it is not filter — it is thick, dark and closer to a stovetop lungo than either.',
steps: [
{ at: 0, label: 'Fill hot', detail: 'Boiling water to just under the valve. Cold water stews the grounds.' },
{ at: 30, label: 'Level the basket', detail: 'Fine grind, level, never tamped. Tamping chokes it.' },
{ at: 60, label: 'Low heat', detail: 'Assemble with a towel, medium-low flame, lid open.' },
{ at: 210, label: 'Listen', detail: 'A steady gurgle means it is done. A violent splutter means it is over.' },
{ at: 270, label: 'Kill the heat', detail: 'Off the flame, base into cold water, pour straight away.' },
],
tips: [
'Start with boiling water — the shorter the metal sits on the flame, the less scorched it tastes.',
'Never tamp. The basket only needs to be full and flat.',
'Stop at the gurgle. Everything after it is the bitter tail.',
],
},
];

export function methodById(id: string): Method | undefined {
Expand Down
Loading