Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f9fe9e2
docs(tools): add peptide calculator spec, plan and syringe assets
Snouzy Jul 29, 2026
af48ca6
feat(tools): add peptide dose calculation engine with vitest
Snouzy Jul 29, 2026
e99bd1e
feat(tools): add peptide vial size presets
Snouzy Jul 29, 2026
aa3a07e
feat(i18n): add peptide calculator ui strings for 6 locales
Snouzy Jul 29, 2026
9a1bbf2
feat(tools): add peptide calculator option chips and syringe selector
Snouzy Jul 29, 2026
8140e7a
feat(tools): add peptide syringe ruler and result card
Snouzy Jul 29, 2026
482ef11
fix(tools): keep syringe ruler cursor label inside its container at e…
Snouzy Jul 29, 2026
5eb48a0
feat(tools): add peptide calculator client with url state and reverse…
Snouzy Jul 29, 2026
6e53814
refactor(tools): collapse duplicated calculator steps and unify clien…
Snouzy Jul 29, 2026
280d3df
feat(tools): add peptide calculator seo metadata for 6 locales
Snouzy Jul 29, 2026
a236bc0
feat(tools): add peptide calculator seo content structure and english…
Snouzy Jul 29, 2026
7bf96da
fix(tools): render faq lead, make chart lead self-contained, normalis…
Snouzy Jul 29, 2026
a8131b1
feat(tools): add peptide calculator page with faq and howto schema
Snouzy Jul 29, 2026
80ca588
fix(tools): drop dead structuredData block and stop widening shared s…
Snouzy Jul 29, 2026
76832d4
feat(tools): link peptide calculator from hub and sibling calculators
Snouzy Jul 29, 2026
9110d19
feat(tools): add peptide calculator long-form content for pt
Snouzy Jul 29, 2026
9caf737
fix(tools): correct portuguese calques and the mcg/mg error magnitude…
Snouzy Jul 29, 2026
1ceb8fb
feat(tools): add peptide calculator long-form content for fr
Snouzy Jul 29, 2026
b9bea29
fix(tools): correct french agreement, calques and impersonal construc…
Snouzy Jul 29, 2026
6e9d7a9
feat(tools): add peptide calculator long-form content for es
Snouzy Jul 29, 2026
52f22fd
fix(tools): correct spanish unit definition, clause coordination and …
Snouzy Jul 29, 2026
87e72dd
feat(tools): add peptide calculator long-form content for ru
Snouzy Jul 29, 2026
c89988d
fix(tools): correct russian collocations, homonym collisions and vial…
Snouzy Jul 29, 2026
ca66a19
feat(tools): add peptide calculator long-form content for zh-CN and c…
Snouzy Jul 29, 2026
a46d262
fix(tools): correct chinese collocations, garden paths and punctuatio…
Snouzy Jul 30, 2026
43302ef
feat(tools): localise the decimal separator in the peptide calculator…
Snouzy Jul 30, 2026
2cb207e
fix(tools): add sitemap entry, second disclaimer, localised table sep…
Snouzy Jul 30, 2026
af75c6d
feat(tools): add peptide vial diagram, visible syringe graduations an…
Snouzy Jul 30, 2026
39fdfbf
fix(tools): connect vial leader lines to their parts and fade the cak…
Snouzy Jul 30, 2026
c64a9ee
refactor(tools): simplify the vial to a labelled illustration and fix…
Snouzy Jul 30, 2026
fd38291
refactor(tools): hold the vial cake static so only the liquid respond…
Snouzy Jul 30, 2026
3ae8223
refactor(tools): remove the peptide preset row and its dead data
Snouzy Jul 30, 2026
2d18072
feat(peptide-calculator): rebuild on a single mobile-first layout
Snouzy Jul 30, 2026
2376701
feat(layout): dock the bottom navigation at every width
Snouzy Jul 30, 2026
972b463
fix(eslint): make the ignore list global and configure two rules
Snouzy Jul 30, 2026
625f81d
chore(lint): apply eslint --fix across the repo
Snouzy Jul 30, 2026
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
5 changes: 3 additions & 2 deletions app/[locale]/(app)/auth/(auth-layout)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { redirect } from "next/navigation";
import { headers } from "next/headers";

import { getI18n } from "locales/server";

import type { LayoutParams } from "@/shared/types/next";

import { paths } from "@/shared/constants/paths";
import { auth } from "@/features/auth/lib/better-auth";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";

import type { LayoutParams } from "@/shared/types/next";

export default async function AuthLayout(props: LayoutParams<{}>) {
const t = await getI18n();
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/auth/(auth-layout)/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Link from "next/link";

import { getI18n } from "locales/server";

import { paths } from "@/shared/constants/paths";
import { SignUpForm } from "@/features/auth/signup/ui/signup-form";

Expand Down
3 changes: 2 additions & 1 deletion app/[locale]/(app)/auth/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import { useEffect } from "react";

import type { ErrorParams } from "@/shared/types/next";

import { logger } from "@/shared/lib/logger";
import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";

import type { ErrorParams } from "@/shared/types/next";

export default function RouteError({ error, reset }: ErrorParams) {
useEffect(() => {
Expand Down
3 changes: 2 additions & 1 deletion app/[locale]/(app)/auth/verify-email/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ReactNode } from "react";
import { redirect } from "next/navigation";

import type { ReactNode } from "react";

import { getServerUrl } from "@/shared/lib/server-url";
import { paths } from "@/shared/constants/paths";
import { serverRequiredUser } from "@/entities/user/model/get-server-session-user";
Expand Down
3 changes: 2 additions & 1 deletion app/[locale]/(app)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export default async function RootLayout({ children }: RootLayoutProps) {
return (
<div className="mx-auto card w-full max-w-3xl min-h-[500px] max-sm:min-h-screen bg-white dark:bg-[#232324] shadow-xl border border-base-200 dark:border-slate-700 flex flex-col max-sm:rounded-none rounded-lg">
<Header />
<div className="flex-1 flex flex-col max-sm:pb-16">{children}</div>
{/* pb-16 clears the docked BottomNavigation, which is fixed at every width. */}
<div className="flex-1 flex flex-col pb-16">{children}</div>
<BottomNavigation />
<Footer />
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/leaderboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Metadata } from "next";

import { Locale } from "locales/types";
import { getI18n } from "locales/server";

import LeaderboardPage from "@/features/leaderboard/ui/leaderboard-page";
import { Breadcrumbs } from "@/components/seo/breadcrumbs";

Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
import { useRouter } from "next/navigation";

import { useI18n } from "locales/client";

import { WorkoutSessionList } from "@/features/workout-session/ui/workout-session-list";
import { WorkoutSessionHeatmap } from "@/features/workout-session/ui/workout-session-heatmap";
import { useWorkoutSessions } from "@/features/workout-session/model/use-workout-sessions";
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/programs/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { notFound } from "next/navigation";
import { headers } from "next/headers";
import { Metadata } from "next";

import { Locale } from "locales/types";
import { getI18n } from "locales/server";

import { generateStructuredData, StructuredDataScript } from "@/shared/lib/structured-data";
import { getLocalizedMetadata } from "@/shared/config/localized-metadata";
import { ProgramDetailPage } from "@/features/programs/ui/program-detail-page";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import { ArrowLeft, Play } from "lucide-react";
import { useCurrentLocale, useI18n } from "locales/client";
import { ExerciseAttributeNameEnum, ProgramWeek } from "@prisma/client";

import { useCurrentLocale, useI18n } from "locales/client";
import { canStartSession } from "@/shared/lib/access-control";
import { WorkoutSessionSets } from "@/features/workout-session/ui/workout-session-sets";
import { WorkoutSessionHeader } from "@/features/workout-session/ui/workout-session-header";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { notFound } from "next/navigation";
import { headers } from "next/headers";
import { Metadata } from "next";

import { Locale } from "locales/types";
import { getI18n } from "locales/server";

import { ProgramSessionClient } from "./ProgramSessionClient";

import { generateStructuredData, StructuredDataScript } from "@/shared/lib/structured-data";
import { getSessionTitle, getProgramTitle } from "@/features/programs/lib/translations-mapper";
import { generateSessionMetadata } from "@/features/programs/lib/session-metadata";
Expand All @@ -12,7 +14,6 @@ import { auth } from "@/features/auth/lib/better-auth";
import { Breadcrumbs } from "@/components/seo/breadcrumbs";

// Import the existing session client component
import { ProgramSessionClient } from "./ProgramSessionClient";

interface SessionDetailPageProps {
params: Promise<{ slug: string; sessionSlug: string; locale: Locale }>;
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/programs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Metadata } from "next";

import { Locale } from "locales/types";
import { getI18n } from "locales/server";

import { ProgramsPage } from "@/features/programs/ui/programs-page";
import { Breadcrumbs } from "@/components/seo/breadcrumbs";

Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/sponsor/onboarding/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Metadata } from "next";
import { Sparkles } from "lucide-react";

import { getI18n } from "locales/server";

import { SponsorOnboardingForm } from "@/features/sponsor/onboarding/SponsorOnboardingForm";

export const metadata: Metadata = {
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/(app)/statistics/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import { getI18n } from "locales/server";

import { ExercisesBrowser } from "@/features/statistics/components/ExercisesBrowser";
import { PremiumGate } from "@/components/ui/premium-gate";

Expand Down
9 changes: 7 additions & 2 deletions app/[locale]/(app)/tools/bmi-calculator/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";
import { Metadata } from "next";

import { getI18n } from "locales/server";
import { BmiEducationalContent } from "app/[locale]/(app)/tools/bmi-calculator/shared/components/BmiEducationalContent";
import { BmiCalculatorClient } from "app/[locale]/(app)/tools/bmi-calculator/shared/BmiCalculatorClient";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { RelatedTools } from "@/components/tools/RelatedTools";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
import { HorizontalBottomBanner, HorizontalTopBanner } from "@/components/ads";

Expand Down Expand Up @@ -115,6 +115,11 @@ export default async function BmiCalculatorPage({ params }: { params: Promise<{
<div className="mt-16">
<BmiEducationalContent />
</div>

<RelatedTools
heading={t("tools.related_title")}
tools={[{ href: `/${locale}/tools/peptide-calculator`, label: t("tools.peptide-calculator.title") }]}
/>
</div>
{(env.NEXT_PUBLIC_BOTTOM_BMI_BANNER_AD_SLOT || env.NEXT_PUBLIC_EZOIC_BOTTOM_BMI_PLACEMENT_ID) && (
<HorizontalBottomBanner
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import React, { useState, useEffect } from "react";

import { useState, useEffect } from "react";
import { useI18n } from "locales/client";
import {
BmiData,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"use client";

import { useI18n } from "locales/client";

import { FormulaCard, createFraction, createSuperscript } from "./MathEquation";

import { env } from "@/env";
import { InArticle } from "@/components/ads";

import { FormulaCard, createFraction, createSuperscript } from "./MathEquation";

export function BmiEducationalContent() {
const t = useI18n();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";

import { useI18n } from "locales/client";
import { UnitSystem } from "app/[locale]/(app)/tools/bmi-calculator/bmi-calculator.utils";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"use client";

import React from "react";
import { CheckCircleIcon, AlertTriangleIcon, XCircleIcon, InfoIcon, TrendingUpIcon, TrendingDownIcon } from "lucide-react";

import { useI18n } from "locales/client";
import { BmiResult, BmiCategory, HealthRisk } from "app/[locale]/(app)/tools/bmi-calculator/bmi-calculator.utils";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";

import { useI18n } from "locales/client";
import { UnitSystem } from "app/[locale]/(app)/tools/bmi-calculator/bmi-calculator.utils";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";

import { useI18n } from "locales/client";
import { UnitSystem } from "app/[locale]/(app)/tools/bmi-calculator/bmi-calculator.utils";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import React from "react";
import Link from "next/link";
import { TrendingUpIcon, AwardIcon, TargetIcon, BrainIcon, GlobeIcon, ChartBarIcon } from "lucide-react";

import { useI18n } from "locales/client";

import { env } from "@/env";
import { HorizontalBottomBanner, HorizontalTopBanner } from "@/components/ads";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import React, { useState } from "react";

import { useState } from "react";
import { useI18n } from "locales/client";
import { BodyFatInput } from "app/[locale]/(app)/tools/calorie-calculator/shared/components/BodyFatInput";
import {
Expand All @@ -18,6 +17,7 @@
CalorieCalculatorInputs,
CalorieResults,
} from "app/[locale]/(app)/tools/calorie-calculator/shared/calorie-formulas.utils";

import { env } from "@/env";
import { HorizontalBottomBanner } from "@/components/ads";

Expand Down Expand Up @@ -147,7 +147,7 @@

<GoalSelector onChange={(goal) => updateInput("goal", goal)} value={inputs.goal} />

{(env.NEXT_PUBLIC_BOTTOM_CALORIE_CALCULATOR_COMPARISON_AD_SLOT || env.NEXT_PUBLIC_EZOIC_BOTTOM_CALORIE_COMPARISON_PLACEMENT_ID) && (

Check warning on line 150 in app/[locale]/(app)/tools/calorie-calculator/calorie-calculator-comparison/CalorieCalculatorComparison.tsx

View workflow job for this annotation

GitHub Actions / lint

This line has a length of 142. Maximum allowed is 140
<HorizontalBottomBanner
adSlot={env.NEXT_PUBLIC_BOTTOM_CALORIE_CALCULATOR_COMPARISON_AD_SLOT}
ezoicPlacementId={env.NEXT_PUBLIC_EZOIC_BOTTOM_CALORIE_COMPARISON_PLACEMENT_ID}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import Link from "next/link";
import { Metadata } from "next";
import { ChevronLeftIcon } from "lucide-react";

import { getI18n } from "locales/server";
import { CalorieCalculatorClient } from "app/[locale]/(app)/tools/calorie-calculator/shared/CalorieCalculatorClient";
import { calculatorConfigs } from "app/[locale]/(app)/tools/calorie-calculator/shared/calculator-configs";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import Link from "next/link";
import { Metadata } from "next";
import { ChevronLeftIcon } from "lucide-react";

import { getI18n } from "locales/server";
import { CalorieCalculatorClient } from "app/[locale]/(app)/tools/calorie-calculator/shared/CalorieCalculatorClient";
import { calculatorConfigs } from "app/[locale]/(app)/tools/calorie-calculator/shared/calculator-configs";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import Link from "next/link";
import { Metadata } from "next";
import { ChevronLeftIcon } from "lucide-react";

import { getI18n } from "locales/server";
import { CalorieCalculatorClient } from "app/[locale]/(app)/tools/calorie-calculator/shared/CalorieCalculatorClient";
import { calculatorConfigs } from "app/[locale]/(app)/tools/calorie-calculator/shared/calculator-configs";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import Link from "next/link";
import { Metadata } from "next";
import { ChevronLeftIcon } from "lucide-react";

import { getI18n } from "locales/server";
import { CalorieCalculatorClient } from "app/[locale]/(app)/tools/calorie-calculator/shared/CalorieCalculatorClient";
import { calculatorConfigs } from "app/[locale]/(app)/tools/calorie-calculator/shared/calculator-configs";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React from "react";
import Link from "next/link";
import { Metadata } from "next";
import { ChevronLeftIcon } from "lucide-react";

import { getI18n } from "locales/server";
import { CalorieCalculatorClient } from "app/[locale]/(app)/tools/calorie-calculator/shared/CalorieCalculatorClient";
import { calculatorConfigs } from "app/[locale]/(app)/tools/calorie-calculator/shared/calculator-configs";

import { getServerUrl } from "@/shared/lib/server-url";
import { env } from "@/env";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";
Expand Down
13 changes: 9 additions & 4 deletions app/[locale]/(app)/tools/calorie-calculator/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from "react";
import { Metadata } from "next";

import { getI18n } from "locales/server";
import { getServerUrl } from "@/shared/lib/server-url";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";

import { CalorieCalculatorHub } from "./CalorieCalculatorHub";

import { getServerUrl } from "@/shared/lib/server-url";
import { RelatedTools } from "@/components/tools/RelatedTools";
import { generateSEOMetadata, SEOScripts } from "@/components/seo/SEOHead";

export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
const { locale } = await params;
const t = await getI18n();
Expand Down Expand Up @@ -71,6 +71,11 @@ export default async function CalorieCalculatorPage({ params }: { params: Promis
<div className="light:bg-white dark:bg-base-200/20">
<div className="container mx-auto px-2 sm:px-4 py-4 sm:py-8 max-w-4xl">
<CalorieCalculatorHub />

<RelatedTools
heading={t("tools.related_title")}
tools={[{ href: `/${locale}/tools/peptide-calculator`, label: t("tools.peptide-calculator.title") }]}
/>
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"use client";

import React, { useState } from "react";
import { useState } from "react";
import { Calculator } from "lucide-react";

import { useI18n } from "locales/client";
import { env } from "@/env";
import { HorizontalBottomBanner } from "@/components/ads";


import { BodyFatInput } from "./components/BodyFatInput";
import {
Expand All @@ -22,6 +20,9 @@ import { calculateCalories, type CalorieCalculatorInputs, type CalorieResults }

import type { CalculatorConfig } from "./types";

import { env } from "@/env";
import { HorizontalBottomBanner } from "@/components/ads";

interface CalorieCalculatorClientProps {
config: CalculatorConfig;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import React from "react";
import { ActivityIcon, BedIcon, BedDoubleIcon, BikeIcon, ZapIcon } from "lucide-react";

import { useI18n } from "locales/client";
import { ActivityLevel } from "app/[locale]/(app)/tools/calorie-calculator/calorie-calculator.utils";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";

import { useI18n } from "locales/client";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";

import { useI18n } from "locales/client";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"use client";

import React, { useState } from "react";
import { useState } from "react";
import { ChevronDownIcon, HelpCircleIcon } from "lucide-react";

import { useI18n } from "locales/client";

export function FAQSection() {
Expand Down
Loading
Loading