chore: UI Nits onboarding v3 (#25409)

* Fix UI nits

* fix bio + team name on invite orgs

* use bg-cal-muted

* Fix error from mass edit

* Update apps/web/public/static/locales/en/common.json

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix org labels

* Fix i18n

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
sean-brydon
2025-11-27 08:18:43 +00:00
committed by GitHub
co-authored by cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
parent d9cddd85ff
commit ff1533d344
19 changed files with 50 additions and 42 deletions
@@ -64,10 +64,10 @@ export function EmailInviteForm({
<div
className={
showTeamSelect ? "flex flex-col gap-2" : "scroll-bar flex max-h-72 flex-col gap-1 overflow-y-auto"
showTeamSelect ? "flex flex-col gap-2" : "scroll-bar flex max-h-72 flex-col gap-2 overflow-y-auto"
}>
{fields.map((field, index) => (
<div key={field.id} className="flex items-start gap-0.5 p-0.5">
<div key={field.id} className="flex items-start gap-2">
<div className={showTeamSelect ? "grid flex-1 items-start gap-2 md:grid-cols-2" : "flex-1"}>
<TextField
labelSrOnly
@@ -28,7 +28,7 @@ export const OnboardingLayout = ({ userEmail, currentStep, totalSteps, children
const column2 = childrenArray[1];
return (
<div className="bg-muted flex min-h-screen w-full flex-col items-center justify-between overflow-clip rounded-[12px] px-4 py-2 md:px-6">
<div className="bg-cal-muted flex min-h-screen w-full flex-col items-center justify-between overflow-clip rounded-[12px] px-4 py-2 md:px-6">
{/* Logo and container - centered */}
<div className="flex w-full flex-1 flex-col items-center justify-center gap-6">
<Logo className="mt-4 h-5 w-auto shrink-0" />
@@ -94,14 +94,14 @@ export const OnboardingBrowserView = ({
<Icon name="arrow-right" className="text-subtle h-4 w-4" />
<Icon name="rotate-cw" className="text-subtle h-4 w-4" />
</div>
<div className="bg-muted flex w-full min-w-0 items-center gap-2 rounded-[32px] px-3 py-2">
<div className="bg-cal-muted flex w-full min-w-0 items-center gap-2 rounded-[32px] px-3 py-2">
<Icon name="lock" className="text-subtle h-4 w-4" />
<p className="text-default truncate text-sm font-medium leading-tight">{displayUrl}</p>
</div>
<Icon name="ellipsis-vertical" className="text-subtle h-4 w-4" />
</div>
{/* Content */}
<div className="bg-muted h-full pl-11 pt-11">
<div className="bg-cal-muted h-full pl-11 pt-11">
<AnimatePresence mode="wait">
<motion.div
key={pathname}
@@ -63,6 +63,7 @@ export const OnboardingInviteBrowserView = ({
const displayName = useOrganizationInvites
? organizationDetails.name || teamName || "Deel"
: teamName || teamDetails.name || "Deel";
const displayBio = useOrganizationInvites ? organizationDetails.bio || "" : teamDetails.bio || "";
const avatar = useOrganizationInvites ? organizationBrand.logo || null : teamBrand.logo || null;
// Get invites based on context - use watched invites if provided, otherwise fall back to store
@@ -117,7 +118,7 @@ export const OnboardingInviteBrowserView = ({
}
return (
<div className="border-subtle bg-muted hidden h-full w-full flex-col overflow-hidden rounded-l-2xl border xl:flex">
<div className="border-subtle bg-cal-muted hidden h-full w-full flex-col overflow-hidden rounded-l-2xl border xl:flex">
{/* Content */}
<div className="h-full px-6 pt-6">
<AnimatePresence mode="wait">
@@ -142,21 +143,23 @@ export const OnboardingInviteBrowserView = ({
/>
<div className="flex w-full flex-col items-start gap-1">
<h2 className="text-emphasis font-cal w-full text-left text-xl font-semibold leading-tight">
{displayInviterName} invited you to join {displayName}
{displayName}
</h2>
<p className="text-subtle text-left text-sm font-normal leading-tight">
We&apos;re emailing you all the details
{displayBio || "We're emailing you all the details"}
</p>
</div>
</div>
</div>
{/* Email Body */}
<div className="bg-default border-subtle mt-3 grid grid-cols-3 gap-4 rounded-t-2xl border p-6 opacity-60">
<div className="bg-default border-subtle mt-3 grid grid-cols-3 gap-4 rounded-t-2xl border p-6">
{displayItems.map((item, index) => (
<div
key={`${item.email}-${index}`}
className="bg-default border-subtle flex aspect-square w-full min-w-0 flex-col items-center justify-center gap-2 overflow-hidden rounded-lg border p-4">
className={`bg-default border-subtle flex aspect-square w-full min-w-0 flex-col items-center justify-center gap-2 overflow-hidden rounded-lg border p-4 ${
!item.isReal ? "opacity-60" : ""
}`}>
<Avatar size="mdLg" imageSrc={undefined} alt={item.name} className="mt-4" />
<div className="flex w-full min-w-0 flex-col items-center gap-4">
<div className="flex w-full min-w-0 flex-col items-center">
@@ -88,14 +88,14 @@ export const OnboardingOrganizationBrowserView = ({
<Icon name="arrow-right" className="text-subtle h-4 w-4" />
<Icon name="rotate-cw" className="text-subtle h-4 w-4" />
</div>
<div className="bg-muted flex w-full min-w-0 items-center gap-2 rounded-[32px] px-3 py-2">
<div className="bg-cal-muted flex w-full min-w-0 items-center gap-2 rounded-[32px] px-3 py-2">
<Icon name="lock" className="text-subtle h-4 w-4" />
<p className="text-default truncate text-sm font-medium leading-tight">{displayUrl}</p>
</div>
<Icon name="ellipsis-vertical" className="text-subtle h-4 w-4" />
</div>
{/* Content */}
<div className="bg-muted h-full pl-11 pt-11">
<div className="bg-cal-muted h-full pl-11 pt-11">
<AnimatePresence mode="wait">
<motion.div
key={pathname}
@@ -54,7 +54,7 @@ export const OnboardingTeamsBrowserView = ({
<Icon name="arrow-right" className="text-subtle h-4 w-4" />
<Icon name="rotate-cw" className="text-subtle h-4 w-4" />
</div>
<div className="bg-muted flex w-full items-center gap-2 rounded-[32px] px-3 py-2">
<div className="bg-cal-muted flex w-full items-center gap-2 rounded-[32px] px-3 py-2">
<Icon name="lock" className="text-subtle h-4 w-4" />
<p className="text-default text-sm font-medium leading-tight">{webappUrl}/teams</p>
</div>
@@ -62,7 +62,7 @@ export const OnboardingTeamsBrowserView = ({
</div>
{/* Content */}
<div className="bg-muted h-full pl-11 pt-11">
<div className="bg-cal-muted h-full pl-11 pt-11">
<AnimatePresence mode="wait">
<motion.div
key={pathname}
@@ -149,7 +149,7 @@ export const OnboardingTeamsBrowserView = ({
))
) : (
<div className="flex flex-col items-center justify-center gap-3 px-5 py-12">
<div className="bg-muted flex h-16 w-16 items-center justify-center rounded-full">
<div className="bg-cal-muted flex h-16 w-16 items-center justify-center rounded-full">
<Icon name="users" className="text-subtle h-8 w-8" />
</div>
<div className="flex flex-col gap-1 text-center">
@@ -126,7 +126,7 @@ export const OnboardingView = ({ userEmail }: OnboardingViewProps) => {
</div>
}>
{/* Card */}
<div className="bg-muted border-muted relative flex min-h-0 w-full flex-col overflow-hidden rounded-xl border p-1">
<div className="bg-cal-muted border-muted relative flex min-h-0 w-full flex-col overflow-hidden rounded-xl border p-1">
<div className="rounded-inherit flex w-full flex-col items-start overflow-clip">
{/* Plan options */}
<RadioAreaGroup.Group
@@ -174,7 +174,7 @@ export const OnboardingView = ({ userEmail }: OnboardingViewProps) => {
</OnboardingCard>
{/* Right column - Icon display */}
<div className="bg-muted border-subtle hidden h-full w-full rounded-l-2xl border-b border-l border-t xl:flex xl:items-center xl:justify-center">
<div className="bg-cal-muted border-subtle hidden h-full w-full rounded-l-2xl border-b border-l border-t xl:flex xl:items-center xl:justify-center">
<AnimatePresence mode="wait">
{selectedPlanData && (
<PlanIcon
@@ -109,7 +109,7 @@ export const OrganizationBrandView = ({ userEmail }: OrganizationBrandViewProps)
<div className="flex w-full flex-col gap-2">
<p className="text-emphasis text-sm font-medium leading-4">{t("onboarding_banner_label")}</p>
<div className="flex w-full flex-col gap-2">
<div className="bg-muted border-muted relative h-[92px] w-full overflow-hidden rounded-md border">
<div className="bg-cal-muted border-muted relative h-[92px] w-full overflow-hidden rounded-md border">
{bannerPreview && (
<img
src={bannerPreview}
@@ -143,7 +143,7 @@ export const OrganizationBrandView = ({ userEmail }: OrganizationBrandViewProps)
<div className="flex w-full flex-col gap-2">
<p className="text-emphasis text-sm font-medium leading-4">{t("logo")}</p>
<div className="flex items-center gap-2">
<div className="bg-muted border-muted relative h-16 w-16 shrink-0 overflow-hidden rounded-md border">
<div className="bg-cal-muted border-muted relative h-16 w-16 shrink-0 overflow-hidden rounded-md border">
{logoPreview && (
<img
src={logoPreview}
@@ -105,7 +105,7 @@ export const OrganizationDetailsView = ({ userEmail }: OrganizationDetailsViewPr
<div className="flex w-full flex-col gap-4 rounded-xl">
{/* Organization Name */}
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">
{t("organization_name")}
</Label>
<TextField
@@ -124,7 +124,7 @@ export const OrganizationDetailsView = ({ userEmail }: OrganizationDetailsViewPr
{/* Organization Bio */}
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">
{t("onboarding_org_bio_label")}
</Label>
<TextArea
@@ -76,7 +76,7 @@ export function ValidatedOrganizationSlug({
return (
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">Organization link</Label>
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">Organization link</Label>
<TextField
value={value}
onChange={(e) => onChange(e.target.value)}
@@ -148,7 +148,9 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
<Logo className="h-10 w-auto" />
</div>
<div className="relative mx-auto flex items-center justify-center" style={{ width: 320, height: 180 }}>
<div
className="relative mx-auto flex items-center justify-center"
style={{ width: 320, height: 180 }}>
<div
className="from-default to-muted border-subtle flex items-center justify-center rounded-2xl border bg-gradient-to-br p-8 shadow-sm"
style={{ width: 200, height: 150 }}>
@@ -165,7 +167,11 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
) : (
<div className="flex flex-col items-center gap-3">
<div className="from-default to-muted border-subtle flex items-center justify-center rounded-full border bg-gradient-to-b p-4 shadow-sm">
<Icon name="upload" className="text-emphasis opacity-70" style={{ width: 32, height: 32 }} />
<Icon
name="upload"
className="text-emphasis opacity-70"
style={{ width: 32, height: 32 }}
/>
</div>
<p className="text-subtle text-center text-sm">{t("upload_csv_subtitle")}</p>
</div>
@@ -179,7 +185,7 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
</div>
<div className="mb-2 flex flex-col gap-3">
<div className="bg-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="bg-cal-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="from-default to-muted border-subtle flex items-center justify-center rounded-full border bg-gradient-to-b p-2 shadow-sm">
<Icon name="download" className="text-emphasis" style={{ width: 16, height: 16 }} />
</div>
@@ -192,7 +198,7 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
</Button>
</div>
<div className="bg-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="bg-cal-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="from-default to-muted border-subtle flex items-center justify-center rounded-full border bg-gradient-to-b p-2 shadow-sm">
<Icon name="upload" className="text-emphasis" style={{ width: 16, height: 16 }} />
</div>
@@ -220,7 +226,7 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
</div>
</div>
<div className="bg-muted border-subtle mt-6 flex items-center justify-between rounded-b-2xl border-t px-8 py-6">
<div className="bg-cal-muted border-subtle mt-6 flex items-center justify-between rounded-b-2xl border-t px-8 py-6">
<Button color="minimal" onClick={handleClose} disabled={isUploading}>
{t("cancel")}
</Button>
@@ -236,4 +242,3 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
</Dialog>
);
};
@@ -167,9 +167,9 @@ export const OrganizationInviteEmailView = ({ userEmail }: OrganizationInviteEma
</div>
</div>
}>
<div className="flex h-full w-full flex-col gap-4">
<Form form={form} handleSubmit={handleContinue} className="h-full w-full">
<div className="flex h-full w-full flex-col gap-4">
<div className="flex w-full flex-col gap-4">
<Form form={form} handleSubmit={handleContinue} className="w-full">
<div className="flex w-full flex-col gap-4">
<EmailInviteForm
fields={fields}
append={append}
@@ -12,7 +12,7 @@ type OnboardingCardProps = {
export const OnboardingCard = ({ title, subtitle, children, footer, isLoading }: OnboardingCardProps) => {
return (
<div className="bg-muted border-muted relative rounded-xl border p-1">
<div className="bg-cal-muted border-muted relative rounded-xl border p-1">
<div className="rounded-inherit flex w-full flex-col items-start overflow-clip">
{/* Card Header */}
<div className="flex w-full gap-1.5 px-5 py-4">
@@ -38,7 +38,7 @@ export const OnboardingLayout = ({ userEmail, currentStep, children }: Onboardin
))}
</div>
<div className="bg-muted flex items-center gap-2 rounded-full px-3 py-2">
<div className="bg-cal-muted flex items-center gap-2 rounded-full px-3 py-2">
<p className="text-emphasis text-sm font-medium leading-none">{userEmail}</p>
</div>
</div>
@@ -136,7 +136,7 @@ export const TeamDetailsView = ({ userEmail }: TeamDetailsViewProps) => {
{/* Team Name */}
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">{t("team_name")}</Label>
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">{t("team_name")}</Label>
<TextField
value={teamName}
onChange={(e) => setTeamName(e.target.value)}
@@ -154,7 +154,7 @@ export const TeamDetailsView = ({ userEmail }: TeamDetailsViewProps) => {
{/* Team Bio */}
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">{t("team_bio")}</Label>
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">{t("team_bio")}</Label>
<TextArea
value={teamBio}
onChange={(e) => setTeamBio(e.target.value)}
@@ -87,7 +87,7 @@ export function ValidatedTeamSlug({ value, onChange, onValidationChange }: Valid
return (
<div className="flex w-full flex-col gap-1.5">
<Label className="text-emphasis text-sm font-medium leading-4">{t("team_url")}</Label>
<Label className="text-emphasis mb-0 text-sm font-medium leading-4">{t("team_url")}</Label>
<TextField
value={value}
onChange={(e) => onChange(e.target.value)}
@@ -185,7 +185,7 @@ export const CSVUploadModal = ({ isOpen, onClose }: CSVUploadModalProps) => {
<div className="mb-2 flex flex-col gap-3">
{/* Download template */}
<div className="bg-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="bg-cal-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="from-default to-muted border-subtle flex items-center justify-center rounded-full border bg-gradient-to-b p-2 shadow-sm">
<Icon name="download" className="text-emphasis" style={{ width: 16, height: 16 }} />
</div>
@@ -199,7 +199,7 @@ export const CSVUploadModal = ({ isOpen, onClose }: CSVUploadModalProps) => {
</div>
{/* File upload */}
<div className="bg-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="bg-cal-muted border-subtle flex items-center gap-3 rounded-lg border p-4">
<div className="from-default to-muted border-subtle flex items-center justify-center rounded-full border bg-gradient-to-b p-2 shadow-sm">
<Icon name="upload" className="text-emphasis" style={{ width: 16, height: 16 }} />
</div>
@@ -227,7 +227,7 @@ export const CSVUploadModal = ({ isOpen, onClose }: CSVUploadModalProps) => {
</div>
</div>
<div className="bg-muted border-subtle mt-6 flex items-center justify-between rounded-b-2xl border-t px-8 py-6">
<div className="bg-cal-muted border-subtle mt-6 flex items-center justify-between rounded-b-2xl border-t px-8 py-6">
<Button color="minimal" onClick={handleClose} disabled={isUploading}>
{t("cancel")}
</Button>
@@ -138,7 +138,7 @@ export const TeamInviteEmailView = ({ userEmail }: TeamInviteEmailViewProps) =>
{/* Left column - Main content */}
<div className="flex h-full w-full flex-col gap-4">
<OnboardingCard
title={t("invite_via_email")}
title={t("invite")}
subtitle={t("team_invite_subtitle")}
footer={
<div className="flex w-full items-center justify-end gap-4">
@@ -399,7 +399,7 @@
"welcome_to_calcom": "Welcome to {{appName}}",
"personal_welcome_description": "You're all set! Start scheduling meetings and managing your calendar.",
"unlimited_event_types": "Unlimited event types",
"workflows_feature": "Workflows (or another popular feature)",
"workflows_feature": "Workflows",
"and_more": "And more…",
"welcome_instructions": "Tell us what to call you and let us know what timezone you're in. You'll be able to edit this later.",
"connect_caldav": "Connect to CalDav (Beta)",
@@ -2558,7 +2558,7 @@
"no_organization_slug": "There was an error creating teams for this organization. Missing URL slug.",
"copy_link_org": "Copy link to organization",
"welcome_to_organizations": "Welcome to Organizations!",
"organizations_welcome_description": "We're excited to connect your bookers with your team members. With your Teams's plan you get:",
"organizations_welcome_description": "We're excited to connect your bookers with your team members. With your Organization's plan you get:",
"1_parent_team_unlimited_subteams": "1 parent team and unlimited sub-teams",
"organization_workflows": "Organization workflows",
"custom_subdomain": "Yourcompany.cal.com subdomain",