diff --git a/public/robots.txt b/public/robots.txt index ce2fcc1..13a32c1 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,4 +1,5 @@ User-agent: * Allow: / +Disallow: /*/recipes/*/timer/ Sitemap: https://trybrew.app/sitemap-index.xml diff --git a/src/components/Recipe.astro b/src/components/Recipe.astro index a81257f..6eb0cc7 100644 --- a/src/components/Recipe.astro +++ b/src/components/Recipe.astro @@ -15,13 +15,15 @@ type Entry = CollectionEntry<'recipes'> type Props = { recipe: Entry['data'] } const { recipe } = Astro.props +const { name } = Astro.params 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 methodHref = getRelativeLocaleUrl(locale, `/recipes/${recipe.method}`) +const timerHref = getRelativeLocaleUrl(locale, `/recipes/${recipe.method}/${name}/timer`) const DEFAULT_GROUP = Symbol('default') const formattedSteps = recipe.steps @@ -61,7 +63,7 @@ const groupedSteps = formattedSteps

- {messages[recipe.method as keyof typeof messages]} / {recipe.name} + {messages[recipe.method]} / {recipe.name}

@@ -94,6 +96,9 @@ const groupedSteps = formattedSteps }
+ {recipe.steps + ? Open timer + : null}
{messages.source}: @@ -183,6 +188,12 @@ const groupedSteps = formattedSteps align-items: center; gap: 12px; } + + .timer-link { + display: inline-block; + margin-block: 24px; + color: inherit; + } diff --git a/src/components/Timer.astro b/src/components/Timer.astro index a0d467a..4a8eb74 100644 --- a/src/components/Timer.astro +++ b/src/components/Timer.astro @@ -1,47 +1,66 @@ --- +import { commonMessages } from '@/i18n/locales/common/en' interface Props { steps: { - description: null | string; - time: number; - water: number; - } + description?: string + group?: string + time: number + totalWater: string + }[] } +const locale = Astro.currentLocale || 'en' +const messages = commonMessages(locale) const { steps } = Astro.props --- -
+
- + -
+
+
- -
-
- - - +
+ +
- diff --git a/src/constants/brewMethods.ts b/src/constants/brewMethods.ts new file mode 100644 index 0000000..86cfabd --- /dev/null +++ b/src/constants/brewMethods.ts @@ -0,0 +1,8 @@ +export const BREW_METHODS = [ + 'aeropress', + 'cezve', + 'chemex', + 'coldbrew', + 'pourover', + 'summer' +] as const diff --git a/src/content/config.ts b/src/content/config.ts index a30b940..5b7b4b1 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -1,6 +1,8 @@ /* eslint-disable perfectionist/sort-objects */ import { defineCollection, z } from 'astro:content' +import { BREW_METHODS } from '@/constants/brewMethods.ts' + const recipeStep = z.object({ description: z.string().optional(), time: z.string(), @@ -13,7 +15,7 @@ const recipesCollection = defineCollection({ title: z.string(), description: z.string(), name: z.string(), - method: z.string(), + method: z.enum(BREW_METHODS), properties: z.object({ coffeeWeight: z.number(), water: z.number(), diff --git a/src/content/recipes/en/pourover/aeroplan-01.md b/src/content/recipes/en/pourover/aeroplan-01.md index 4186f0e..e3b9f99 100644 --- a/src/content/recipes/en/pourover/aeroplan-01.md +++ b/src/content/recipes/en/pourover/aeroplan-01.md @@ -12,18 +12,22 @@ properties: temperature: 95 steps: - - description: Pre-wetting in a spiral and intensely + - description: In a spiral and intensely water: 50 time: "0:50" + group: Pre-wetting - description: From the center to the edges of the coffee tablet water: 70 time: "0:30" + group: Infusions - description: To the center and back to spiral brewing water: 60 time: "0:40" + group: Infusions - description: Into the center of the funnel water: 29 time: "1:25" + group: Infusions author: Aeroplan.Coffee authorImg: aeroplan diff --git a/src/content/recipes/ru/pourover/aeroplan-01.md b/src/content/recipes/ru/pourover/aeroplan-01.md index a4ff5d0..fba82e9 100644 --- a/src/content/recipes/ru/pourover/aeroplan-01.md +++ b/src/content/recipes/ru/pourover/aeroplan-01.md @@ -11,6 +11,24 @@ properties: time: '3:25' temperature: 95 +steps: + - description: Интенсивно по спирали + water: 50 + time: '0:50' + group: Предсмачивание + - description: От центра к краям кофейной таблетки + water: 120 + time: '0:30' + group: Вливания + - description: В центр и возвращаемся к завариванию по спирали + water: 180 + time: '0:40' + group: Вливания + - description: В центр воронки + water: 309 + time: '1:25' + group: Вливания + author: Aeroplan.Coffee authorImg: aeroplan @@ -19,78 +37,6 @@ tags: - pourover --- -## Рецепт - - -
- -Время - -Вес - -Итого - -
- -### Предсмачивание - -
- -0:00 - -50 г - -50 г - -
- -

по спирали и интенсивно

- -### Вливания - -
- -0:50 - -70 г - -120 г - -
- -

от центра к краям кофейной таблетки

- - -
- -1:20 - -60 г - -180 г - -
- -

в центр и возвращаемся к завариванию по спирали

- -
- -2:00 - -129 г - -309 г - -
- -

в центр воронки

- -
- -Общее время экстракции __3:25__ - -
-
## Примечание diff --git a/src/i18n/locales/common/en.ts b/src/i18n/locales/common/en.ts index ab2426e..03b4f24 100644 --- a/src/i18n/locales/common/en.ts +++ b/src/i18n/locales/common/en.ts @@ -13,11 +13,14 @@ export function commonMessages (locale?: string) { description: 'Recipes for brewing alternatives', languageName: 'English', menu: 'Menu', + pause: 'Pause', pourover: 'Pourover', + reset: 'Reset', sections: 'Sections', settings: 'Settings', source: 'Source', sourceCode: params('Source code on {link}'), + start: 'Start', summer: 'Summer', switchTo: params('Switch to {link}'), title: 'Recipes' diff --git a/src/i18n/locales/common/ru.json b/src/i18n/locales/common/ru.json index 00555ad..e5d54aa 100644 --- a/src/i18n/locales/common/ru.json +++ b/src/i18n/locales/common/ru.json @@ -15,5 +15,8 @@ "settings": "Настройки", "sourceCode": "Исходный код на {link}", "summer": "Лето", - "switchTo": "Переключиться на {link}" + "switchTo": "Переключиться на {link}", + "start": "Старт", + "pause": "Пауза", + "reset": "Сбросить" } diff --git a/src/pages/[lang]/recipes/[method]/[name].astro b/src/pages/[lang]/recipes/[method]/[name]/index.astro similarity index 100% rename from src/pages/[lang]/recipes/[method]/[name].astro rename to src/pages/[lang]/recipes/[method]/[name]/index.astro diff --git a/src/pages/[lang]/recipes/[method]/[name]/timer.astro b/src/pages/[lang]/recipes/[method]/[name]/timer.astro new file mode 100644 index 0000000..2aebfff --- /dev/null +++ b/src/pages/[lang]/recipes/[method]/[name]/timer.astro @@ -0,0 +1,81 @@ +--- +import type { GetStaticPaths } from 'astro' +import type { CollectionEntry } from 'astro:content' + +import { getCollection } from 'astro:content' +import { getRelativeLocaleUrl } from 'astro:i18n' + +import TimerComponent from '@/components/Timer.astro' +import { commonMessages } from '@/i18n/locales/common/en' +import { createPropertyFormatters } from '@/i18n/utils' +import Layout from '@/layouts/Layout.astro' +import { humanTimeToSeconds } from '@/utils' + +type Entry = CollectionEntry<'recipes'> +interface Props { + entry: CollectionEntry<'recipes'> +} + +const { entry } = Astro.props +const { method, name } = Astro.params +const locale = Astro.currentLocale || 'en' +const messages = commonMessages(locale) + +export const getStaticPaths = (async () => { + const recipes = await getCollection('recipes') + return recipes + .filter(entry => entry.data.steps !== undefined) + .map(entry => { + const [lang, method, name] = entry.slug.split('/') + + return { + params: { lang, method, name }, + props: { entry } + } + }) +}) satisfies GetStaticPaths +const { weight } = createPropertyFormatters(Astro.currentLocale) + +const methodHref = getRelativeLocaleUrl(locale, `/recipes/${method}`) +const recipeHref = getRelativeLocaleUrl(locale, `/recipes/${method}/${name}`) +const formattedSteps = entry.data.steps! + .reduce<({ totalWater: number } & Exclude[number])[]>((acc, step, index) => { + const previousStepTotalWater = index > 0 ? acc[index - 1].totalWater : 0 + acc.push({ + ...step, + totalWater: step.water + previousStepTotalWater + }) + return acc + }, []) + .map(step => ({ + ...step, + time: humanTimeToSeconds(step.time), + totalWater: weight(step.totalWater) + })) +--- + + +

+ {messages[entry.data.method]} + / {entry.data.name} + / Timer +

+ +
+ + diff --git a/src/styles/colors.css b/src/styles/colors.css index 70d6295..e13b70b 100644 --- a/src/styles/colors.css +++ b/src/styles/colors.css @@ -21,6 +21,9 @@ --color-author-icon-background: transparent; --color-focus: black; + + --color-timer-progress-arc: oklch(0 0 0); + --color-timer-base-arc: oklch(0 0 0 / 0.08); } html[data-theme='dark'] { @@ -42,4 +45,7 @@ html[data-theme='dark'] { --color-footer-boder: transparent; --color-author-icon-background: white; --color-focus: white; + + --color-timer-progress-arc: oklch(100 0 0); + --color-timer-base-arc: oklch(100 0 0 / 0.08); }