From 66234ffba94b2921d926621a4e7abf4b14cd95b4 Mon Sep 17 00:00:00 2001
From: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Date: Mon, 27 Oct 2025 17:32:06 +0000
Subject: [PATCH] chore: illustrations to getting-started page in onboarding v3
(#24673)
* i18n
* WIP icon stuff
* More icon work
* More gradient tuning
* Mvoe plan-icon to planicon.tsx
* Fix cubic suggestion
* Fix darkmode icon and gradients
* Fix type error
---
.../onboarding/components/plan-icon.tsx | 107 +++++++++++++++++
.../getting-started/onboarding-view.tsx | 108 ++++++++++++------
apps/web/public/static/locales/en/common.json | 11 ++
3 files changed, 191 insertions(+), 35 deletions(-)
create mode 100644 apps/web/modules/onboarding/components/plan-icon.tsx
diff --git a/apps/web/modules/onboarding/components/plan-icon.tsx b/apps/web/modules/onboarding/components/plan-icon.tsx
new file mode 100644
index 0000000000..bd04740979
--- /dev/null
+++ b/apps/web/modules/onboarding/components/plan-icon.tsx
@@ -0,0 +1,107 @@
+import classNames from "@calcom/ui/classNames";
+import { Icon, type IconName } from "@calcom/ui/components/icon";
+
+export function PlanIcon({ icon, variant = "single" }: { icon: IconName; variant?: "single" | "double" }) {
+ const renderIconContainer = (index: number) => {
+ // For double variant: 55px icon width + 24px gap = 79px between centers, so ±39.5px from center
+ const leftPosition = variant === "double" ? `calc(50% + ${index === 0 ? -39.5 : 39.5}px)` : "50%";
+
+ return (
+
+ {/* Icon */}
+
+
+
+
+ {/* Inner highlight/shine effect */}
+
+
+ );
+ };
+
+ return (
+
+ {/* Outer ring - SVG with linear gradient */}
+
+
+
+
+
+
+
+
+
+
+ {/* Middle ring - SVG with linear gradient */}
+
+
+
+
+
+
+
+
+
+
+ {/* Main icon container(s) with gradient background */}
+ {variant === "single" ? renderIconContainer(0) : [renderIconContainer(0), renderIconContainer(1)]}
+
+ );
+}
diff --git a/apps/web/modules/onboarding/getting-started/onboarding-view.tsx b/apps/web/modules/onboarding/getting-started/onboarding-view.tsx
index e2d0f8252c..d9e49c1c27 100644
--- a/apps/web/modules/onboarding/getting-started/onboarding-view.tsx
+++ b/apps/web/modules/onboarding/getting-started/onboarding-view.tsx
@@ -3,12 +3,16 @@
import { useRouter } from "next/navigation";
import { isCompanyEmail } from "@calcom/features/ee/organizations/lib/utils";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import classNames from "@calcom/ui/classNames";
import { Badge } from "@calcom/ui/components/badge";
import { Button } from "@calcom/ui/components/button";
+import { type IconName } from "@calcom/ui/components/icon";
import { Logo } from "@calcom/ui/components/logo";
import { RadioAreaGroup } from "@calcom/ui/components/radio";
import { OnboardingContinuationPrompt } from "../components/onboarding-continuation-prompt";
+import { PlanIcon } from "../components/plan-icon";
import { useOnboardingStore, type PlanType } from "../store/onboarding-store";
type OnboardingViewProps = {
@@ -18,6 +22,7 @@ type OnboardingViewProps = {
export const OnboardingView = ({ userName, userEmail }: OnboardingViewProps) => {
const router = useRouter();
+ const { t } = useLocale();
const { selectedPlan, setSelectedPlan } = useOnboardingStore();
const handleContinue = () => {
@@ -30,25 +35,36 @@ export const OnboardingView = ({ userName, userEmail }: OnboardingViewProps) =>
}
};
+ const planIconByType: Record = {
+ personal: "user",
+ team: "users",
+ organization: "users",
+ };
+
const allPlans = [
{
id: "personal" as PlanType,
- title: "For personal use",
- badge: "Free",
- description: "Good for individuals who are just starting out and simply want the essentials.",
+ title: t("onboarding_plan_personal_title"),
+ badge: t("onboarding_plan_personal_badge"),
+ description: t("onboarding_plan_personal_description"),
+ icon: planIconByType.personal,
+ variant: "single" as const,
},
{
id: "team" as PlanType,
- title: "With my team",
- badge: "$15 p/mo p/person",
- description:
- "Highly recommended for small teams who seek to upgrade their time and perform better as a unit.",
+ title: t("onboarding_plan_team_title"),
+ badge: t("onboarding_plan_team_badge"),
+ description: t("onboarding_plan_team_description"),
+ icon: planIconByType.team,
+ variant: "single" as const,
},
{
id: "organization" as PlanType,
- title: "For my organization",
- badge: "$37 p/mo p/person",
- description: "Robust scheduling for larger teams looking to have more control, privacy, and security.",
+ title: t("onboarding_plan_organization_title"),
+ badge: t("onboarding_plan_organization_badge"),
+ description: t("onboarding_plan_organization_description"),
+ icon: planIconByType.organization,
+ variant: "double" as const,
},
];
@@ -89,9 +105,11 @@ export const OnboardingView = ({ userName, userEmail }: OnboardingViewProps) =>
{/* Card Header */}
-
Hey {userName}
+
+ {t("onboarding_welcome_message", { userName })}
+
- To personalize your experience, what do you plan to use Cal.com for?
+ {t("onboarding_welcome_question")}
@@ -101,35 +119,55 @@ export const OnboardingView = ({ userName, userEmail }: OnboardingViewProps) =>
value={selectedPlan ?? undefined}
onValueChange={(value) => setSelectedPlan(value as PlanType)}
className="flex w-full flex-col gap-1 rounded-[10px]">
- {plans.map((plan) => (
-
-
-
-
{plan.title}
-
- {plan.badge}
-
+ {plans.map((plan) => {
+ const isSelected = selectedPlan === plan.id;
+
+ return (
+
button]:left-auto [&>button]:right-6 [&>button]:mt-0 [&>button]:transform"
+ )}
+ classNames={{
+ container: "flex w-full items-center gap-4 p-4 pl-5 pr-12 md:p-5 md:pr-14",
+ }}>
+
+
+
+
+
{plan.title}
+
+
+ {plan.badge}
+
+
+
+
+ {plan.badge}
+
+
+ {plan.description}
+
+
-
- {plan.badge}
-
-
- {plan.description}
-
-
-
- ))}
+
+ );
+ })}
{/* Footer */}
- Continue
+ {t("continue")}
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index b178ff4523..9f08bed0f1 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -3886,5 +3886,16 @@
"onboarding_skip_for_now": "Skip for now",
"onboarding_or_divider": "or",
"onboarding_team_required": "Team is required",
+ "onboarding_welcome_message": "Hey {{userName}}",
+ "onboarding_welcome_question": "To personalize your experience, what do you plan to use Cal.com for?",
+ "onboarding_plan_personal_title": "For personal use",
+ "onboarding_plan_personal_badge": "Free",
+ "onboarding_plan_personal_description": "Good for individuals who are just starting out and simply want the essentials.",
+ "onboarding_plan_team_title": "With my team",
+ "onboarding_plan_team_description": "Highly recommended for small teams who seek to upgrade their time and perform better as a unit.",
+ "onboarding_plan_organization_title": "For my organization",
+ "onboarding_plan_team_badge": "$15/user/mo",
+ "onboarding_plan_organization_badge": "$37/user/mo",
+ "onboarding_plan_organization_description": "Robust scheduling for larger teams looking to have more control, privacy, and security.",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}