Skip to content
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

feat: convert barn-01 to new format #74

Merged
merged 11 commits into from
Jan 16, 2025
133 changes: 108 additions & 25 deletions src/components/Recipe.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import type { CollectionEntry } from 'astro:content'
import { getRelativeLocaleUrl } from 'astro:i18n'

import { commonMessages } from '@/i18n/locales/common/en'
import { createPropertyFormatters } from '@/i18n/utils'

import { getRecipeMessages } from '../i18n/locales/recipe/en'
import { humanTimeToSeconds, secondsTimeToHuman } from '../utils'
import Author from './Author.astro'
import RecipeProperties from './RecipeProperties.astro'

Expand All @@ -15,8 +18,45 @@ const { recipe } = Astro.props

const locale = Astro.currentLocale || 'en'
const messages = commonMessages(locale)
const recipeMessages = getRecipeMessages(locale)
const { time, weight } = createPropertyFormatters(Astro.currentLocale)

const href = getRelativeLocaleUrl(locale, `/recipes/${recipe.method}`)
const DEFAULT_GROUP = Symbol('default')

const formattedSteps = recipe.steps
?.reduce<({ endTime: number; startTime: number; totalWater: number } & Exclude<Entry['data']['steps'], undefined>[number])[]>((acc, step, index) => {
const previousStepEndTime = index > 0 ? acc[index - 1].endTime : 0
const previousStepTotalWater = index > 0 ? acc[index - 1].totalWater : 0
acc.push({
...step,
endTime: humanTimeToSeconds(step.time) + previousStepEndTime,
startTime: previousStepEndTime,
totalWater: step.water + previousStepTotalWater
})
return acc
}, [])
.map(step => ({
...step,
endTime: time(secondsTimeToHuman(step.endTime)),
startTime: time(secondsTimeToHuman(step.startTime)),
time: time(step.time),
totalWater: weight(step.totalWater),
water: weight(step.water)
}))

const groupedSteps = formattedSteps
?.reduce((acc, step) => {
const lastGroup = acc[acc.length - 1]
const group = step.group ?? DEFAULT_GROUP

if (lastGroup && lastGroup[0] === group) {
lastGroup[1].push(step)
} else {
acc.push([group, [step]])
}
return acc
}, [] as [string | typeof DEFAULT_GROUP, typeof formattedSteps][])
---

<div class="root">
Expand All @@ -26,31 +66,29 @@ const href = getRelativeLocaleUrl(locale, `/recipes/${recipe.method}`)
<RecipeProperties properties={recipe.properties} />
<div>
{
recipe.steps
groupedSteps
? (
<>
<h2>Recipe</h2>
<table>
<thead>
<tr>
<th>Time</th>
<th>Weight</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{recipe.steps.map(it => {
return (
<tr>
<td>{it.time}</td>
<td>{it.water} gr.</td>
<td>{it.description}</td>
</tr>
)
})}
</tbody>
</table>
</>
<div class="recipe-steps">
<div class="cell cell--header cell--first">{recipeMessages.startTime}</div>
<div class="cell cell--header cell--last">{recipeMessages.totalWeight}</div>
{groupedSteps.map(([group, steps]) =>
(
<>
{group !== DEFAULT_GROUP
? <div class="recipe-steps-subheader">{group}</div>
: null}
{steps.map(step => (
<>
<div class="cell cell--first">{step.startTime}</div>
<div class="cell">{step.totalWater}</div>
<div class="cell cell--description">{step.description}</div>
</>))}
</>
))}
</div>
</>
)
: null
}
Expand Down Expand Up @@ -90,19 +128,64 @@ const href = getRelativeLocaleUrl(locale, `/recipes/${recipe.method}`)
color: inherit;
}

th,
td {
.recipe-steps {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
margin-block-end: 32px;
}

.recipe-steps-subheader {
margin-block-start: 24px;
color: var(--text-secondary);
font-size: 14px;
text-transform: uppercase;
font-weight: 600;
grid-column: 1 / -1;
}

.cell {
padding: 6px 12px;
}

.cell--header {
font-weight: 600;
}

.cell--first {
padding-inline-start: 0;
}

/* Special case required only for the header of the last column to take the place of description column header if there are 3 columns. */
.cell--header.cell--last {
grid-column: 2 / -1;
}

/* These classes grouped under one query since changes are highly coupled */
@media screen and (max-width: 600px) {

.recipe-steps {
grid-template-columns: 1fr 1fr;
}

.cell--description {
grid-column: 1 / -1;
padding-inline: 0;
margin-block-end: 24px;
}

.cell--description:empty {
display: none;
}
}

.source {
display: flex;
align-items: center;
gap: 12px;
}
</style>

<!-- TODO: Drop thies styles, when we migrate new recipes ro MDX or frontmatter -->
<!-- TODO: Drop these styles, when we migrate new recipes to MDX or frontmatter -->
<style is:global>
.time-line {
display: grid;
Expand Down
10 changes: 8 additions & 2 deletions src/content/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
/* eslint-disable perfectionist/sort-objects */
import { defineCollection, z } from 'astro:content'

const recipeStep = z.object({
description: z.string().optional(),
time: z.string(),
water: z.number(),
group: z.string().optional()
})

const recipesCollection = defineCollection({
schema: z.object({
title: z.string(),
Expand All @@ -14,8 +21,7 @@ const recipesCollection = defineCollection({
temperature: z.union([z.string(), z.number()]).optional(),
ice: z.number().optional()
}),
// TODO: describe schema for steps
steps: z.array(z.any()).optional(),
steps: z.array(recipeStep).optional(),
author: z.string(),
authorImg: z.string().optional(),
link: z.string().optional(),
Expand Down
14 changes: 7 additions & 7 deletions src/content/recipes/en/pourover/aeroplan-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ properties:
steps:
- description: Pre-wetting in a spiral and intensely
water: 50
time: 50
time: "0:50"
- description: From the center to the edges of the coffee tablet
water: 120
time: 30
water: 70
time: "0:30"
- description: To the center and back to spiral brewing
water: 180
time: 40
water: 60
time: "0:40"
- description: Into the center of the funnel
water: 309
time: 85
water: 29
time: "1:25"

author: Aeroplan.Coffee
authorImg: aeroplan
Expand Down
90 changes: 17 additions & 73 deletions src/content/recipes/en/pourover/barn-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ properties:
time: '2:30'
temperature: 94

steps:
- water: 35
time: '0:30'
group: Pre-wetting
- water: 65
time: '0:30'
group: Infusions
- water: 50
time: '0:20'
group: Infusions
- water: 50
time: '0:25'
group: Infusions
- water: 50
time: '0:25'
group: Infusions

author: The Barn
authorImg: barn

Expand All @@ -19,77 +36,4 @@ tags:
- pourover
---

## Recipe


<div class="time-line">

Time

Weight

Total

</div>

### Pre-wetting

<div class="time-line">

0:00

35 gr

35 gr

</div>

### Infusions

<div class="time-line">

0:30

65 gr

100 gr

</div>

<div class="time-line">

1:00

50 gr.

150 gr.

</div>

<div class="time-line">

1:20

50 gr.

200 gr.

</div>

<div class="time-line">

1:45

50 gr.

250 gr.

</div>

<br>

Total extraction time __2:00 - 2:30__

<br>


10 changes: 10 additions & 0 deletions src/i18n/locales/recipe/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { t } from '../../utils'

export const getRecipeMessages = (locale?: string) => {
return t(locale, 'recipe', {
infusions: 'Infusions',
prewetting: 'Pre-wetting',
startTime: 'Start at',
totalWeight: 'Total weight'
})
}
4 changes: 4 additions & 0 deletions src/i18n/locales/recipe/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"infusions": "Вливания",
"prewetting": "Предсмачивание"
}
12 changes: 12 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ export async function getCollectionByLocale (
})
return recipes
}

export function humanTimeToSeconds (time: string) {
const coefficients = [1, 60, 24 * 60]
return time.split(':').map(Number).reverse().reduce((acc, cur, index) => acc + cur * coefficients[index], 0)
}

export function secondsTimeToHuman (time: number) {
const minutes = Math.floor((time % 3600) / 60)
const seconds = Math.floor((time % 60))

return minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0')
}
Loading