feat: rename --font-cal to --font-heading + use Cal Sans UI (#26064)

* feat: rename --font-cal to --font-heading + use Cal Sans UI

* chore: remove font-weight from font-heading elements and CSS variables

Co-Authored-By: pasquale@cal.com <pasquale@cal.com>

* chore: remove unneeded css vars

* fix: cubic issues

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: pasquale@cal.com <pasquale@cal.com>
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
This commit is contained in:
Pasquale Vitiello
2026-01-09 10:42:23 +00:00
committed by GitHub
co-authored by pasquale@cal.com <pasquale@cal.com> Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> pasquale@cal.com <pasquale@cal.com> Rajiv Sahal
parent 56b29b5df6
commit c380ea810c
74 changed files with 159 additions and 141 deletions
@@ -27,7 +27,7 @@ export function ShellMainAppDir(props: LayoutProps) {
{props.heading && (
<h3
className={classNames(
"font-cal text-emphasis max-w-28 sm:max-w-72 md:max-w-80 inline truncate text-lg font-semibold tracking-wide sm:text-xl md:block xl:max-w-full",
"font-heading text-emphasis max-w-28 sm:max-w-72 md:max-w-80 inline truncate text-lg tracking-wide sm:text-xl md:block xl:max-w-full",
props.smallHeading ? "text-base" : "text-xl"
)}>
{props.heading}
@@ -183,7 +183,7 @@ function RoutingForm({ form, profile, ...restProps }: Props) {
<form onSubmit={handleOnSubmit}>
<div className="mb-8">
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl tracking-wide">
{form.name}
</h1>
{form.description ? (
@@ -19,7 +19,7 @@ export function AvailabilityScheduleSkeleton() {
{/* Title section */}
<header className="flex w-full max-w-full items-center truncate">
<div className="w-full truncate ltr:mr-4 rtl:ml-4 md:block">
<SkeletonText className="font-cal max-w-28 sm:max-w-72 md:max-w-80 hidden h-6 truncate text-xl font-semibold tracking-wide md:block" />
<SkeletonText className="font-heading max-w-28 sm:max-w-72 md:max-w-80 hidden h-6 truncate text-xl tracking-wide md:block" />
{/* Title */}
<SkeletonText className="mt-1 hidden h-4 w-64 text-sm md:block" /> {/* Subtitle */}
</div>
@@ -51,7 +51,7 @@ export function PbacOptInModal({ open, onOpenChange, revalidateRolesPath }: Pbac
<FingerprintAnimation isHovered={isButtonHovered} />
<div className="flex w-full flex-col items-center gap-1 text-center">
<h2 className="font-cal text-emphasis text-xl font-semibold">{t("pbac_opt_in_title")}</h2>
<h2 className="font-heading text-emphasis text-xl">{t("pbac_opt_in_title")}</h2>
<p className="text-default text-sm">{t("pbac_opt_in_description")}</p>
</div>
</div>
+1 -1
View File
@@ -10,7 +10,7 @@ export const IconGrid = (props: {
iconClassName?: string;
}) => (
<div className={props.rootClassName}>
<h2 className="font-cal mt-6 text-lg font-medium">{props.title}</h2>
<h2 className="font-heading mt-6 text-lg">{props.title}</h2>
<div className="grid grid-cols-2 lg:grid-cols-6">
{props.icons.map((icon) => {
return (
+11 -22
View File
@@ -15,32 +15,21 @@ export async function generateMetadata(): Promise<Metadata> {
return await _generateMetadataForStaticPage("Icons Showcase", "", undefined, undefined, "/icons");
}
const interFont = Inter({ subsets: ["latin"], variable: "--font-sans", preload: true, display: "swap" });
const calFont = localFont({
src: "../../fonts/CalSans-SemiBold.woff2",
variable: "--font-cal",
preload: true,
display: "swap",
weight: "600",
});
export default function IconsPage() {
const icons = Array.from(lucideIconList).sort() as IconName[];
return (
<div className={`${interFont.variable} ${calFont.variable}`}>
<div className="bg-subtle flex h-screen">
<IconSprites />
<div className="bg-default m-auto min-w-full rounded-md p-10 text-right ltr:text-left">
<h1 className="text-emphasis font-cal text-2xl font-medium">Icons Showcase</h1>
<IconGrid title="Regular Icons" icons={icons} />
<IconGrid
title="Filled Icons"
icons={icons}
rootClassName="bg-inverted text-inverted"
iconClassName="fill-blue-500"
/>
</div>
<div className="bg-subtle flex h-screen">
<IconSprites />
<div className="bg-default m-auto min-w-full rounded-md p-10 text-right ltr:text-left">
<h1 className="text-emphasis font-heading text-2xl">Icons Showcase</h1>
<IconGrid title="Regular Icons" icons={icons} />
<IconGrid
title="Filled Icons"
icons={icons}
rootClassName="bg-inverted text-inverted"
iconClassName="fill-blue-500"
/>
</div>
</div>
);
+2 -19
View File
@@ -1,6 +1,4 @@
import { dir } from "i18next";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import { headers, cookies } from "next/headers";
import React from "react";
@@ -15,14 +13,7 @@ import { AppRouterI18nProvider } from "./AppRouterI18nProvider";
import { SpeculationRules } from "./SpeculationRules";
import { Providers } from "./providers";
const interFont = Inter({ subsets: ["latin"], variable: "--font-sans", preload: true, display: "swap" });
const calFont = localFont({
src: "../fonts/CalSans-SemiBold.woff2",
variable: "--font-cal",
preload: true,
display: "block",
weight: "600",
});
import { fontHeading, fontSans } from "@coss/ui/fonts";
export const viewport = {
width: "device-width",
@@ -114,16 +105,8 @@ export default async function RootLayout({ children }: { children: React.ReactNo
style={embedColorScheme ? { colorScheme: embedColorScheme as string } : undefined}
suppressHydrationWarning
data-nextjs-router="app">
<head nonce={nonce}>
<style>{`
:root {
--font-sans: ${interFont.style.fontFamily.replace(/\'/g, "")};
--font-cal: ${calFont.style.fontFamily.replace(/\'/g, "")};
}
`}</style>
</head>
<body
className="dark:bg-default bg-subtle antialiased"
className={`${fontSans.variable} ${fontHeading.variable} font-sans dark:bg-default bg-subtle antialiased`}
style={
isEmbed
? {
+2 -2
View File
@@ -92,7 +92,7 @@ export function NotFound({ host }: { host: string }) {
<main className="mx-auto max-w-xl pb-6 pt-16 sm:pt-24">
<div className="text-center">
<p className="text-sm font-semibold uppercase tracking-wide text-black">{t("error_404")}</p>
<h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 sm:text-5xl">
<h1 className="font-heading mt-2 text-4xl text-gray-900 sm:text-5xl">
{t("feature_currently_disabled") ?? "Feature is currently disabled"}
</h1>
</div>
@@ -114,7 +114,7 @@ export function NotFound({ host }: { host: string }) {
<main className="mx-auto max-w-xl pb-6 pt-16 sm:pt-24">
<div className="text-center">
<p className="text-emphasis text-sm font-semibold uppercase tracking-wide">{t("error_404")}</p>
<h1 className="font-cal text-emphasis mt-2 text-4xl font-extrabold sm:text-5xl">
<h1 className="font-heading text-emphasis mt-2 text-4xl sm:text-5xl">
{isBookingSuccessPage ? "Booking not found" : t("page_doesnt_exist")}
</h1>
{isSubpage && pageType !== PageType.TEAM ? (
-17
View File
@@ -10,8 +10,6 @@
"use client";
import { DefaultSeo } from "next-seo";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import Head from "next/head";
import Script from "next/script";
@@ -33,15 +31,6 @@ export interface CalPageWrapper {
PageWrapper?: AppProps["Component"]["PageWrapper"];
}
const interFont = Inter({ subsets: ["latin"], variable: "--font-sans", preload: true, display: "swap" });
const calFont = localFont({
src: "../fonts/CalSans-SemiBold.woff2",
variable: "--font-cal",
preload: true,
display: "swap",
weight: "600",
});
function PageWrapper(props: AppProps) {
const { Component, pageProps, err, router } = props;
let pageStatus = "200";
@@ -87,12 +76,6 @@ function PageWrapper(props: AppProps) {
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
/>
<style jsx global>{`
:root {
--font-sans: ${interFont.style.fontFamily};
--font-cal: ${calFont.style.fontFamily};
}
`}</style>
<IconSprites />
{getLayout(
+1 -1
View File
@@ -343,7 +343,7 @@ export const AppPage = ({
src={logo}
alt={name}
/>
<h1 className="font-cal text-emphasis ml-4 text-3xl">{name}</h1>
<h1 className="font-heading text-emphasis ml-4 text-3xl">{name}</h1>
</div>
<h2 className="text-default text-sm font-medium">
<Link
@@ -9,7 +9,7 @@ export const StepHeader: FC<StepHeaderProps> = ({ children, title, subtitle }) =
return (
<div>
<header>
<p className="font-cal mb-3 text-[28px] font-medium capitalize leading-7">{title}</p>
<p className="font-heading mb-3 text-[28px] capitalize leading-7">{title}</p>
<p className="text-subtle font-sans text-sm font-normal">{subtitle}</p>
</header>
@@ -95,7 +95,7 @@ function NewFormDialog({
<Dialog open={newFormDialogState !== null} onOpenChange={(open) => !open && setNewFormDialogState(null)}>
<DialogContent className="overflow-y-auto">
<div className="mb-1">
<h3 className="text-emphasis !font-cal text-semibold text-xl font-medium" id="modal-title">
<h3 className="text-emphasis font-heading! text-xl" id="modal-title">
{teamId ? t("add_new_team_form") : t("add_new_form")}
</h3>
<div>
+1 -1
View File
@@ -804,7 +804,7 @@ const RerouteDialogContentAndFooterWithFormResponse = ({
<div>
<div>
<Link
className="text-emphasis text-semibold font-cal mb-4 flex underline"
className="text-emphasis font-heading mb-4 flex underline"
href={`/apps/routing-forms/form-edit/${form.id}`}
target="_blank">
{form.name}
+1 -1
View File
@@ -71,7 +71,7 @@ export const ErrorPage: React.FC<Props> = (props) => {
<>
<div className="bg-subtle flex h-screen">
<div className="rtl: bg-default m-auto rounded-md p-10 text-right ltr:text-left">
<h1 className="font-cal text-emphasis text-6xl">{statusCode}</h1>
<h1 className="font-heading text-emphasis text-6xl">{statusCode}</h1>
<h2 className="text-emphasis mt-6 max-w-2xl text-2xl font-medium">
It&apos;s not you, it&apos;s us.
</h2>
@@ -21,7 +21,7 @@ const DisableUserImpersonation = ({ disableImpersonation }: { disableImpersonati
<div className="flex flex-col justify-between pl-2 pt-9 sm:flex-row">
<div>
<div className="flex flex-row items-center">
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">
<h2 className="font-heading text-emphasis text-lg leading-6">
{t("user_impersonation_heading")}
</h2>
<Badge className="ml-2 text-xs" variant={!disableImpersonation ? "success" : "gray"}>
@@ -18,7 +18,7 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
<div className="flex flex-col justify-between pl-2 pt-9 sm:flex-row">
<div>
<div className="flex flex-row items-center">
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">{t("2fa")}</h2>
<h2 className="font-heading text-emphasis text-lg leading-6">{t("2fa")}</h2>
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
{enabled ? t("enabled") : t("disabled")}
</Badge>
@@ -7,7 +7,7 @@ const TwoFactorModalHeader = ({ title, description }: { title: string; descripti
<Icon name="shield" className="text-inverted h-6 w-6" />
</div>
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<h3 className="font-cal text-emphasis text-lg font-medium leading-6" id="modal-title">
<h3 className="font-heading text-emphasis text-lg leading-6" id="modal-title">
{title}
</h3>
<p className="text-muted text-sm">{description}</p>
@@ -17,7 +17,7 @@ export const OAuthClientsList = ({ oauthClients, isDeleting, handleDelete }: OAu
<div className="mb-10">
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
<div className="flex w-full flex-col">
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold leading-5 tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl leading-5 tracking-wide">
OAuth Clients
</h1>
<p className="text-default text-sm ltr:mr-4 rtl:ml-4">
+2 -2
View File
@@ -39,7 +39,7 @@ const ChooseLicense = (
"bg-default cursor-pointer stack-y-2 rounded-md border p-4 hover:border-black",
value === "FREE" && "ring-2 ring-black"
)}>
<h2 className="font-cal text-emphasis text-xl">{t("agplv3_license")}</h2>
<h2 className="font-heading text-emphasis text-xl">{t("agplv3_license")}</h2>
<p className="font-medium text-green-800">{t("free_license_fee")}</p>
<p className="text-subtle">{t("forever_open_and_free")}</p>
<ul className="text-subtle ml-4 list-disc text-left text-xs">
@@ -52,7 +52,7 @@ const ChooseLicense = (
<RadioGroup.Item value="EE" disabled>
<Link href="https://cal.com/sales" target="_blank">
<div className={classNames("bg-default h-full cursor-pointer stack-y-2 rounded-md border p-4")}>
<h2 className="font-cal text-emphasis text-xl">{t("custom_plan")}</h2>
<h2 className="font-heading text-emphasis text-xl">{t("custom_plan")}</h2>
<p className="font-medium text-green-800">{t("contact_sales")}</p>
<p className="text-subtle">Build on top of Cal.com</p>
<ul className="text-subtle ml-4 list-disc text-left text-xs">
@@ -122,7 +122,7 @@ const LicenseSelection = (
"bg-default h-full cursor-pointer stack-y-2 rounded-md border p-4 hover:border-black",
value === "FREE" && "ring-2 ring-black"
)}>
<h2 className="font-cal text-emphasis text-xl">{t("agplv3_license")}</h2>
<h2 className="font-heading text-emphasis text-xl">{t("agplv3_license")}</h2>
<p className="font-medium text-green-800">{t("free_license_fee")}</p>
<p className="text-subtle">{t("forever_open_and_free")}</p>
<ul className="text-subtle ml-4 list-disc text-left text-xs">
@@ -139,7 +139,7 @@ const LicenseSelection = (
"bg-default h-full cursor-pointer stack-y-2 rounded-md border p-4 hover:border-black",
value === "EXISTING" && "ring-2 ring-black"
)}>
<h2 className="font-cal text-emphasis text-xl">{t("enter_license_key")}</h2>
<h2 className="font-heading text-emphasis text-xl">{t("enter_license_key")}</h2>
<p className="font-medium text-green-800">{t("enter_existing_license")}</p>
<p className="text-subtle">{t("enter_your_license_key")}</p>
<p className="text-subtle text-xs">
+1 -1
View File
@@ -17,7 +17,7 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
{props.showLogo && <Logo small inline={false} className="mx-auto mb-auto" />}
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
{props.heading && <h2 className="font-cal text-emphasis text-center text-3xl">{props.heading}</h2>}
{props.heading && <h2 className="font-heading text-emphasis text-center text-3xl">{props.heading}</h2>}
</div>
{props.loading && (
<div className="bg-cal-muted absolute z-50 flex h-screen w-full items-center">
@@ -23,7 +23,7 @@ function Success() {
<>
<div className="stack-y-6">
<div>
<h2 className="font-cal text-emphasis mt-6 text-center text-3xl font-extrabold">
<h2 className="font-heading text-emphasis mt-6 text-center text-3xl">
{t("password_updated")}
</h2>
</div>
@@ -41,7 +41,7 @@ function Expired() {
<>
<div className="stack-y-6">
<div>
<h2 className="font-cal text-emphasis mt-6 text-center text-3xl font-extrabold">{t("whoops")}</h2>
<h2 className="font-heading text-emphasis mt-6 text-center text-3xl">{t("whoops")}</h2>
<h2 className="text-emphasis text-center text-3xl font-extrabold">{t("request_is_expired")}</h2>
</div>
<p>{t("request_is_expired_instructions")}</p>
+1 -1
View File
@@ -172,7 +172,7 @@ export default function Verify({ EMAIL_FROM }: { EMAIL_FROM?: string }) {
) : (
<MailOpenIcon />
)}
<h3 className="font-cal text-emphasis my-6 text-2xl font-normal leading-none">
<h3 className="font-heading text-emphasis my-6 text-2xl leading-none">
{hasPaymentFailed
? t("your_payment_failed")
: isPremiumUsername
@@ -53,7 +53,7 @@ export const BookEventFormWrapperComponent = ({
}
return (
<>
<h1 className="font-cal text-emphasis text-xl leading-5">{t("confirm_your_details")} </h1>
<h1 className="font-heading text-emphasis text-xl leading-5">{t("confirm_your_details")} </h1>
<div className="my-4 flex flex-wrap gap-2 rounded-md leading-none">
<Badge variant="grayWithoutHover" startIcon="calendar" size="lg">
<FromTime
@@ -3,7 +3,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
const UnAvailableMessage = ({ children, title }: { children: React.ReactNode; title: string }) => (
<div className="mx-auto w-full max-w-2xl">
<div className="border-subtle bg-default dark:bg-cal-muted overflow-hidden rounded-lg border p-10">
<h2 className="font-cal mb-4 text-3xl">{title}</h2>
<h2 className="font-heading mb-4 text-3xl">{title}</h2>
{children}
</div>
</div>
@@ -1061,7 +1061,7 @@ export default function Success(props: PageProps) {
))}
</div>
<div className="stack-y-1 my-4 text-center">
<h2 className="font-cal text-lg">{t("submitted_feedback")}</h2>
<h2 className="font-heading text-lg">{t("submitted_feedback")}</h2>
<p className="text-sm">{rateValue < 4 ? t("how_can_we_improve") : t("most_liked")}</p>
</div>
<TextArea
@@ -97,7 +97,7 @@ export default function ApiKeyDialogForm({
{successfulNewApiKeyModal ? (
<>
<div className="mb-6">
<h2 className="font-semi-bold font-cal text-emphasis mb-2 text-xl tracking-wide">
<h2 className="font-heading text-emphasis mb-2 text-xl tracking-wide">
{t("success_api_key_created")}
</h2>
<div className="text-emphasis text-sm">
@@ -153,7 +153,7 @@ export default function ApiKeyDialogForm({
}}
className="stack-y-4">
<div className="mb-4 mt-1">
<h2 className="font-semi-bold font-cal text-emphasis text-xl tracking-wide">
<h2 className="font-heading text-emphasis text-xl tracking-wide">
{defaultValues ? t("edit_api_key") : t("create_api_key")}
</h2>
{IS_CALCOM ? (
@@ -56,7 +56,7 @@ const CreateDirectory = ({ orgId }: { orgId: number | null }) => {
});
}}>
<div className="mb-5 mt-1">
<h2 className="font-semi-bold font-cal text-emphasis text-xl tracking-wide">
<h2 className="font-heading text-emphasis text-xl tracking-wide">
{t("directory_sync_configure")}
</h2>
<p className="mt-1 text-sm text-gray-500">{t("directory_sync_configure_description")}</p>
@@ -70,7 +70,7 @@ function CreateAttributeHeader(props: { isPending: boolean }) {
href="/settings/organizations/attributes">
<span className="sr-only">{t("back_to_attributes")}</span>
</Button>
<div className="font-cal text-cal flex space-x-1 text-xl font-semibold leading-none">
<div className="font-heading text-cal flex space-x-1 text-xl leading-none">
<h1 className="text-emphasis">{t("attribute")}</h1>
{watchedTitle && (
<>
@@ -92,7 +92,7 @@ function EditAttributeHeader(props: { isPending: boolean }) {
href="/settings/organizations/attributes">
<span className="sr-only">{t("back_to_attributes")}</span>
</Button>
<div className="font-cal text-cal flex space-x-1 text-xl font-semibold leading-none">
<div className="font-heading text-cal flex space-x-1 text-xl leading-none">
<h1 className="text-emphasis">{t("attribute")}</h1>
{watchedTitle && (
<>
@@ -181,7 +181,7 @@ function OrganizationAttributesPage({
<div className="bg-emphasis text-emphasis flex h-16 w-16 items-center justify-center rounded-full p-2">
<Icon name="tags" />
</div>
<h2 className="font-cal text-emphasis mt-6 text-xl font-semibold leading-none">
<h2 className="font-heading text-emphasis mt-6 text-xl leading-none">
{t("add_attributes")}
</h2>
@@ -326,7 +326,7 @@ const CreateANewOrganizationFormChild = ({ session }: { session: Ensure<SessionC
{isBillingEnabled && !isAdmin && (
<>
<div className="bg-subtle stack-y-5 rounded-lg p-5">
<h3 className="font-cal text-default text-lg font-semibold leading-4">
<h3 className="font-heading text-default text-lg leading-4">
Upgrade to Organizations
</h3>
<RadioArea.Group className={classNames("mt-1 flex flex-col gap-4")} value="ORGANIZATION">
@@ -136,7 +136,7 @@ export function WelcomeToOrganizationsModal() {
</div>
<div className="mb-2 flex flex-col gap-2 text-center">
<h2 className="font-cal text-emphasis text-2xl leading-none">
<h2 className="font-heading text-emphasis text-2xl leading-none">
{t("welcome_to_organizations")}
</h2>
<p className="text-default text-sm leading-normal">{t("organizations_welcome_description")}</p>
@@ -39,7 +39,7 @@ const PaymentStatusView = () => {
<Icon name="x" className="h-6 w-6 text-red-600" />
</div>
<div className="text-center">
<h1 className="font-cal text-emphasis text-2xl">{t("payment_failed")}</h1>
<h1 className="font-heading text-emphasis text-2xl">{t("payment_failed")}</h1>
<p className="text-default mt-2 text-sm">{paymentError || t("payment_failed_description")}</p>
</div>
<Button color="secondary" href="/settings/organizations/new/onboard-members">
@@ -55,7 +55,7 @@ const PaymentStatusView = () => {
<Icon name="check" className="h-6 w-6 text-green-600 dark:text-green-400" />
</div>
<div className="text-center">
<h1 className="font-cal text-emphasis text-2xl">{t("payment_successful")}</h1>
<h1 className="font-heading text-emphasis text-2xl">{t("payment_successful")}</h1>
<p className="text-default mt-2 text-sm">{t("creating_your_organization", { orgName: name })}</p>
<p className="text-subtle mt-1 text-sm">{t("this_may_take_a_few_seconds")}</p>
</div>
@@ -95,7 +95,7 @@ const CreateConnectionDialog = ({
wellKnownUrl,
});
}}>
<h2 className="font-semi-bold font-cal text-emphasis text-xl tracking-wide">
<h2 className="font-heading text-emphasis text-xl tracking-wide">
{t("sso_oidc_configuration_title")}
</h2>
<p className="text-subtle mb-4 mt-1 text-sm">{t("sso_oidc_configuration_description")}</p>
@@ -90,7 +90,7 @@ const CreateConnectionDialog = ({
});
}}>
<div className="mb-1">
<h2 className="font-semi-bold font-cal text-emphasis text-xl tracking-wide">
<h2 className="font-heading text-emphasis text-xl tracking-wide">
{t("sso_saml_configuration_title")}
</h2>
<p className="text-subtle mb-5 mt-1 text-sm">{t("sso_saml_configuration_description")}</p>
@@ -157,7 +157,7 @@ export default function MemberChangeRoleModal(props: {
<>
<div className="mb-4 sm:flex sm:items-start">
<div className="text-center sm:text-left">
<h3 className="text-emphasis !font-cal text-semibold text-xl font-medium" id="modal-title">
<h3 className="text-emphasis font-heading! text-xl" id="modal-title">
{t("change_member_role")}
</h3>
</div>
@@ -119,7 +119,7 @@ export default function EmptyScreen(props: { isFilteredView: boolean }) {
<Icon name="zap" className="dark:text-default inline-block h-10 w-10 stroke-[1.3px]" />
</div>
<div className="max-w-[420px] text-center">
<h2 className="text-semibold font-cal mt-6 text-xl dark:text-gray-300">{t("workflows")}</h2>
<h2 className="font-heading mt-6 text-xl dark:text-gray-300">{t("workflows")}</h2>
<p className="text-default line-clamp-2 mt-3 text-sm font-normal leading-6 dark:text-gray-300">
{t("no_workflows_description")}
</p>
+1 -1
View File
@@ -199,7 +199,7 @@ const ChooseEmbedTypesDialogContent = ({
return (
<DialogContent className="rounded-lg p-10" type="creation" size="lg">
<div className="mb-2">
<h3 className="font-cal text-emphasis mb-2 text-2xl font-semibold leading-none" id="modal-title">
<h3 className="font-heading text-emphasis mb-2 text-2xl leading-none" id="modal-title">
{t("how_you_want_add_cal_site", { appName: APP_NAME })}
</h3>
<div>
@@ -163,7 +163,7 @@ const OnboardingPage = (props: PageProps) => {
<div className="sm:mx-auto sm:w-full sm:max-w-[600px]">
<div className="mx-auto px-4 sm:max-w-[520px]">
<header>
<p className="font-cal mb-3 text-[28px] font-medium leading-7">
<p className="font-heading mb-3 text-[28px] leading-7">
{headers[currentStepIndex]?.title || "Undefined title"}
</p>
@@ -58,14 +58,14 @@ export const OnboardingCard = ({
{/* Card Header */}
<div className="mb-2 flex w-full gap-1.5 py-2 md:mb-0 md:py-4">
<div className="flex w-full flex-col gap-2">
<h1 className="font-cal text-xl font-semibold leading-6">{title}</h1>
<h1 className="font-heading text-xl leading-6">{title}</h1>
<p className="text-subtle text-sm leading-tight">{subtitle}</p>
</div>
</div>
{/* Content */}
<div
className={`flex h-full min-h-0 w-full flex-1 flex-col gap-4 [container-type:size] ${
className={`flex h-full min-h-0 w-full flex-1 flex-col gap-4 @container-[size] ${
floatingFooter ? "pb-10" : ""
}`}>
{isLoading ? (
@@ -165,7 +165,7 @@ export const OnboardingInviteBrowserView = ({
className="border-default mb-4 h-12 w-12 border-2"
/>
)}
<h2 className="text-emphasis font-cal w-full text-left text-xl font-semibold leading-tight">
<h2 className="text-emphasis font-heading w-full text-left text-xl leading-tight">
{displayName}
</h2>
<p className="text-subtle text-left text-sm font-normal leading-tight">
@@ -180,7 +180,7 @@ export const OrganizationCSVUploadModal = ({ isOpen, onClose }: OrganizationCSVU
</div>
<div className="mb-2 flex flex-col gap-2 text-center">
<h2 className="font-cal text-emphasis text-2xl leading-none">{t("upload_csv_file")}</h2>
<h2 className="font-heading text-emphasis text-2xl leading-none">{t("upload_csv_file")}</h2>
<p className="text-default text-sm leading-normal">{t("upload_csv_description")}</p>
</div>
@@ -17,7 +17,7 @@ export const OnboardingCard = ({ title, subtitle, children, footer, isLoading }:
{/* Card Header */}
<div className="flex w-full gap-1.5 px-5 py-4">
<div className="flex w-full flex-col gap-1">
<h1 className="font-cal text-xl font-semibold leading-6">{title}</h1>
<h1 className="font-heading text-xl leading-6">{title}</h1>
<p className="text-subtle text-sm font-medium leading-tight">{subtitle}</p>
</div>
</div>
@@ -179,7 +179,7 @@ export const CSVUploadModal = ({ isOpen, onClose }: CSVUploadModalProps) => {
</div>
<div className="mb-2 flex flex-col gap-2 text-center">
<h2 className="font-cal text-emphasis text-2xl leading-none">{t("upload_csv_file")}</h2>
<h2 className="font-heading text-emphasis text-2xl leading-none">{t("upload_csv_file")}</h2>
<p className="text-default text-sm leading-normal">{t("upload_csv_description")}</p>
</div>
@@ -74,7 +74,7 @@ export default function EditOAuthClient() {
<div className="m-2 md:mx-14 md:mx-5">
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
<div className="flex w-full flex-col">
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold leading-5 tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl leading-5 tracking-wide">
{t("oAuth_client_updation_form")}
</h1>
<p className="text-default text-sm ltr:mr-4 rtl:ml-4">
@@ -48,7 +48,7 @@ export default function EditOAuthClientWebhooks() {
<div className="m-2 md:mx-5">
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
<div className="flex w-full flex-col">
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold leading-5 tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl leading-5 tracking-wide">
{t("webhook_update_form")}
</h1>
<p className="text-default text-sm ltr:mr-4 rtl:ml-4">
@@ -67,7 +67,7 @@ export default function CreateOAuthClient() {
<div className="m-2 md:mx-5">
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
<div className="flex w-full flex-col">
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold leading-5 tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl leading-5 tracking-wide">
{t("oAuth_client_creation_form")}
</h1>
<p className="text-default text-sm ltr:mr-4 rtl:ml-4">
@@ -167,7 +167,7 @@ const PasswordView = ({ user }: PasswordViewProps) => {
{user && user.identityProvider !== IdentityProvider.CAL && !user.passwordAdded ? (
<div className="border-subtle rounded-b-xl border border-t-0">
<div className="px-4 py-6 sm:px-6">
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">
<h2 className="font-heading text-emphasis text-lg leading-6">
{t("account_managed_by_identity_provider", {
provider: IdentityProvider[user.identityProvider],
})}
+1 -1
View File
@@ -156,7 +156,7 @@ export function ShellMain(props: LayoutProps) {
{props.heading && (
<h3
className={classNames(
"font-cal text-emphasis max-w-28 sm:max-w-72 md:max-w-80 hidden truncate text-lg font-semibold tracking-wide sm:text-xl md:block xl:max-w-full",
"font-heading text-emphasis max-w-28 sm:max-w-72 md:max-w-80 hidden truncate text-lg tracking-wide sm:text-xl md:block xl:max-w-full",
props.smallHeading ? "text-base" : "text-xl"
)}>
{!isLocaleReady ? <SkeletonText invisible /> : props.heading}
+2 -2
View File
@@ -55,7 +55,7 @@ export function UpgradeTip({
/>
</picture>
<div className="relative my-4 w-full px-4 pb-4 sm:px-8 md:px-14">
<h1 className={classNames("font-cal mt-4 text-2xl sm:text-3xl")}>{title}</h1>
<h1 className={classNames("font-heading mt-4 text-2xl sm:text-3xl")}>{title}</h1>
<p className={classNames("mb-8 mt-4 max-w-sm text-sm sm:text-base")}>{description}</p>
{buttons}
</div>
@@ -65,7 +65,7 @@ export function UpgradeTip({
{features.map((feature) => (
<div key={feature.title} className="bg-cal-muted mb-4 min-h-[180px] w-full rounded-md p-8 md:mb-0">
{feature.icon}
<h2 className="font-cal text-emphasis mt-4 text-lg">{feature.title}</h2>
<h2 className="font-heading text-emphasis mt-4 text-lg">{feature.title}</h2>
<p className="text-default">{feature.description}</p>
</div>
))}
@@ -83,7 +83,7 @@ export function WelcomeToCalcomModal() {
</div>
<div className="mb-2 flex flex-col gap-2 text-center">
<h2 className="font-cal text-emphasis text-2xl leading-none">
<h2 className="font-heading text-emphasis text-2xl leading-none">
{t("welcome_to_calcom", { appName: APP_NAME })}
</h2>
<p className="text-default text-sm leading-normal">{t("personal_welcome_description")}</p>
+1 -1
View File
@@ -385,7 +385,7 @@ export default function Signup({
</div>
)}
<div className="flex flex-col gap-2">
<h1 className="font-cal text-[28px] leading-none ">
<h1 className="font-heading text-[28px] leading-none ">
{IS_CALCOM ? t("create_your_calcom_account") : t("create_your_account")}
</h1>
{IS_CALCOM ? (
+2 -2
View File
@@ -132,7 +132,7 @@ function TeamPage({ team, considerUnpublished, isValidOrgDomain }: PageProps) {
<div className="stack-y-6" data-testid="event-types">
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
<div className="text-muted p-8 text-center">
<h2 className="font-cal text-emphasis mb-2 text-3xl">{` ${t("org_no_teams_yet")}`}</h2>
<h2 className="font-heading text-emphasis mb-2 text-3xl">{` ${t("org_no_teams_yet")}`}</h2>
<p className="text-emphasis mx-auto max-w-md">{t("org_no_teams_yet_description")}</p>
</div>
</div>
@@ -148,7 +148,7 @@ function TeamPage({ team, considerUnpublished, isValidOrgDomain }: PageProps) {
<div className="relative">
<Avatar alt={teamName} imageSrc={profileImageSrc} size="lg" />
</div>
<p className="font-cal text-emphasis mb-2 text-2xl tracking-wider" data-testid="team-name">
<p className="font-heading text-emphasis mb-2 text-2xl tracking-wider" data-testid="team-name">
{team.parent && `${team.parent.name} `}
{teamName}
</p>
@@ -80,7 +80,7 @@ export function UserPage(props: PageProps) {
}}
className={isOrg && user.profile.organization?.bannerUrl ? "-mt-14" : ""}
/>
<h1 className={classNames("font-cal text-emphasis mb-1 text-xl", isOrg && user.profile.organization?.bannerUrl ? "" : "mt-4")} data-testid="name-title">
<h1 className={classNames("font-heading text-emphasis mb-1 text-xl", isOrg && user.profile.organization?.bannerUrl ? "" : "mt-4")} data-testid="name-title">
{profile.name}
{!isOrg && user.verified && (
<Icon
@@ -37,7 +37,7 @@ export default function MeetingUnavailable(props: PageProps) {
</h3>
</div>
<div className="mt-4 border-b border-t py-4">
<h2 className="font-cal text-default mb-2 text-center text-lg font-medium">
<h2 className="font-heading text-default mb-2 text-center text-lg">
{props.booking.title}
</h2>
<p className="text-subtle text-center">
@@ -569,7 +569,7 @@ export function VideoMeetingInfo(props: VideoMeetingInfo) {
"no-scrollbar fixed left-0 top-0 z-30 flex h-full w-64 transform justify-between overflow-x-hidden overflow-y-scroll transition-all duration-300 ease-in-out",
open ? "translate-x-0" : "-translate-x-[232px]"
)}>
<main className="prose-sm prose max-w-64 prose-a:text-white prose-h3:text-white prose-h3:font-cal scroll-bar scrollbar-track-w-20 overflow-x-hidden! bg-default w-full overflow-scroll border-r border-gray-300/20 p-4 text-white shadow-sm backdrop-blur-lg">
<main className="prose-sm prose max-w-64 prose-a:text-white prose-h3:text-white prose-h3:font-heading scroll-bar scrollbar-track-w-20 overflow-x-hidden! bg-default w-full overflow-scroll border-r border-gray-300/20 p-4 text-white shadow-sm backdrop-blur-lg">
<h3>{t("what")}:</h3>
<p>{booking.title}</p>
<h3>{t("invitee_timezone")}:</h3>
+2 -1
View File
@@ -4,6 +4,7 @@ import { dir } from "i18next";
import type { DocumentContext, DocumentProps } from "next/document";
import Document, { Head, Html, Main, NextScript } from "next/document";
import { fontHeading, fontSans } from "@coss/ui/fonts";
import { IS_PRODUCTION } from "@calcom/lib/constants";
import { applyTheme, applyToDesktopClass } from "./../lib/pages/document/_applyThemeForDocument";
@@ -82,7 +83,7 @@ class MyDocument extends Document<Props> {
</Head>
<body
className="dark:bg-default bg-subtle antialiased"
className={`${fontSans.variable} ${fontHeading.variable} font-sans dark:bg-default bg-subtle antialiased`}
style={
isEmbed
? {
@@ -11,7 +11,7 @@ export default function AppNotInstalledMessage({ appName }: { appName: string })
<div className="mb-5 rounded-full bg-gray-100 p-3 dark:bg-[#292929] ">
<Icon name="circle-alert" className="h-9 w-9 p-0.5" strokeWidth={1.5} />
</div>
<h3 className="font-cal mb-2 text-2xl font-semibold">{t("app_not_installed")}</h3>
<h3 className="font-heading mb-2 text-2xl">{t("app_not_installed")}</h3>
<p className="text-subtle px-1 leading-normal">{t("visit_our_app_store")}</p>
<div className="mt-5">
@@ -118,7 +118,7 @@ export const SearchDialog = (props: ISearchDialog) => {
return (
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
<DialogContent>
<h3 className="font-cal text-emphasis text-xl" id="modal-title">
<h3 className="font-heading text-emphasis text-xl" id="modal-title">
{t("add_gif_to_confirmation")}
</h3>
<p className="text-subtle mb-3 text-sm font-light">{t("find_gif_spice_confirmation")}</p>
+1 -1
View File
@@ -15,7 +15,7 @@
@theme inline {
--font-sans: var(--font-sans);
--font-cal: var(--font-cal);
--font-heading: var(--font-heading);
/* Resets the preference from coss-ui which was to "use single --radius variable for all radius values" */
--radius: var(--radius);
+2 -1
View File
@@ -6,7 +6,8 @@
"./styles.css": "./src/styles/globals.css",
"./lib/*": "./src/lib/*.ts",
"./components/*": "./src/components/*.tsx",
"./hooks/*": "./src/hooks/*.ts"
"./hooks/*": "./src/hooks/*.ts",
"./fonts": "./src/fonts/index.ts"
},
"scripts": {
"lint": "biome lint src",
+49
View File
@@ -0,0 +1,49 @@
# Shared Fonts
This directory contains shared font files and configurations used across all apps in the monorepo.
## Usage
Import fonts directly from the shared UI package:
```tsx
import { fontSans, fontHeading } from "@coss/ui/fonts";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={`${fontSans.variable} ${fontHeading.variable}`}>
{children}
</body>
</html>
);
}
```
## Available Fonts
- `fontSans` - Cal Sans UI variable font (supports multiple weights and modes)
- `fontHeading` - Cal Sans Regular font
## Adding New Fonts
1. Place the font file in this directory (`packages/coss-ui/src/fonts/`)
2. Add a new font configuration in `index.ts`:
```typescript
export const yourNewFont = localFont({
display: "swap",
src: "./YourFont.woff2",
variable: "--font-your-name",
});
```
3. Use it in any app by importing from `@coss/ui/fonts`
## Benefits of This Approach
- Single source of truth for fonts
- No fragile relative paths
- Type-safe imports
- Versioned with the UI package
- Easy to update across all apps
+13
View File
@@ -0,0 +1,13 @@
import localFont from "next/font/local";
export const fontSans = localFont({
display: "swap",
src: "./CalSansUI[MODE,wght].woff2",
variable: "--font-sans",
});
export const fontHeading = localFont({
display: "swap",
src: "./CalSans-SemiBold.woff2",
variable: "--font-heading",
});
@@ -63,7 +63,7 @@ export default function Header({
)}
<div>
{title ? (
<h1 className="font-cal text-emphasis mb-1 text-xl font-semibold leading-5 tracking-wide">
<h1 className="font-heading text-emphasis mb-1 text-xl leading-5 tracking-wide">
{title}
</h1>
) : (
+6 -7
View File
@@ -242,7 +242,6 @@
"Courier New", monospace;
--radius: var(--radius);
--font-heading: var(--font-heading);
--font-cal: var(--font-cal);
--shadow-dropdown: var(--shadow-dropdown);
--shadow-switch-thumb: var(--shadow-switch-thumb);
--shadow-solid-gray-rested: var(--shadow-solid-gray-rested);
@@ -4949,14 +4948,14 @@
.align-top {
vertical-align: top;
}
.\!font-cal {
font-family: var(--font-cal) !important;
.\!font-heading {
font-family: var(--font-heading) !important;
}
.font-\(family-name\:--font-sans\) {
font-family: var(--font-sans);
}
.font-cal {
font-family: var(--font-cal);
.font-heading {
font-family: var(--font-heading);
}
.font-mono {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New,
@@ -9270,8 +9269,8 @@
.prose-headings\:text-emphasis :where(h1, h2, h3, h4, h5, h6, th):not(:where([class~="not-prose"] *)) {
color: var(--cal-text-emphasis);
}
.prose-h3\:font-cal :where(h3):not(:where([class~="not-prose"] *)) {
font-family: var(--font-cal);
.prose-h3\:font-heading :where(h3):not(:where([class~="not-prose"] *)) {
font-family: var(--font-heading);
}
.prose-h3\:text-white :where(h3):not(:where([class~="not-prose"] *)) {
color: var(--color-white);
+2 -2
View File
@@ -85,7 +85,7 @@ const cvaCardTypeByVariant = cva("", {
{
variant: "SidebarCard",
structure: "title",
className: "text-sm font-cal",
className: "text-sm font-heading",
},
{
variant: "SidebarCard",
@@ -107,7 +107,7 @@ const cvaCardTypeByVariant = cva("", {
{
variant: "NewLaunchSidebarCard",
structure: "title",
className: "text-sm font-cal text-white",
className: "text-sm font-heading text-white",
},
{
variant: "NewLaunchSidebarCard",
@@ -65,7 +65,7 @@ export const ConfirmationContent = (props: PropsWithChildren<ConfirmationDialogC
</div>
)}
<div className="w-full">
<DialogPrimitive.Title className="font-cal text-emphasis mt-2 text-xl">
<DialogPrimitive.Title className="font-heading text-emphasis mt-2 text-xl">
{title}
</DialogPrimitive.Title>
<DialogPrimitive.Description asChild>
+1 -1
View File
@@ -129,7 +129,7 @@ export function DialogHeader(props: DialogHeaderProps) {
<div className="mb-4">
<h2
data-testid="dialog-title"
className="text-semibold text-emphasis font-cal mb-1 text-xl"
className="text-emphasis font-heading mb-1 text-xl"
id="modal-title">
{props.title}
</h2>
@@ -67,7 +67,7 @@ export function EmptyScreen({
<div className={`flex ${limitWidth ? "max-w-[420px]" : ""} flex-col items-center`}>
<h2
className={classNames(
"text-semibold font-cal text-emphasis text-center text-xl normal-nums",
"font-heading text-emphasis text-center text-xl normal-nums",
icon && "mt-6",
!description && "mb-8"
)}>
@@ -61,7 +61,7 @@ export function WizardForm({
<div className="mx-auto mt-4 print:w-full" data-testid="wizard-form">
<div className={classNames("overflow-hidden md:mb-2 md:w-[700px]", containerClassname)}>
<div className="px-6 py-5">
<h1 className="font-cal text-emphasis text-2xl" data-testid="step-title">
<h1 className="font-heading text-emphasis text-2xl" data-testid="step-title">
{currentStepData.title}
</h1>
<p className="text-subtle text-sm" data-testid="step-description">
@@ -46,7 +46,7 @@ export function WizardLayout({
<header>
{isLocaleReady ? (
<>
<p className="font-cal mb-3 text-[28px] font-medium leading-7">
<p className="font-heading mb-3 text-[28px] leading-7">
{title.replace(` | ${APP_NAME}`, "")}&nbsp;
</p>
<p className="text-subtle font-sans text-sm font-normal">{subtitle}&nbsp;</p>