Files
calendar/apps/web/app/layout.tsx
T
Benny JooGitHubbenny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

172 lines
4.9 KiB
TypeScript

import { getLocale } from "@calcom/features/auth/lib/getLocale";
import { loadTranslations } from "@calcom/i18n/server";
import { IconSprites } from "@calcom/ui/components/icon";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
import { dir } from "i18next";
import { Inter } from "next/font/google";
import localFont from "next/font/local";
import { cookies, headers } from "next/headers";
import Script from "next/script";
import type React from "react";
import "../styles/globals.css";
import { AppRouterI18nProvider } from "./AppRouterI18nProvider";
import { Providers } from "./providers";
import { SpeculationRules } from "./SpeculationRules";
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",
});
export const viewport = {
width: "device-width",
initialScale: 1.0,
maximumScale: 1.0,
userScalable: false,
viewportFit: "cover",
themeColor: [
{
media: "(prefers-color-scheme: light)",
color: "#f9fafb",
},
{
media: "(prefers-color-scheme: dark)",
color: "#1C1C1C",
},
],
};
export const metadata = {
icons: {
icon: "/api/logo?type=favicon-32",
apple: "/api/logo?type=apple-touch-icon",
other: [
{
rel: "icon-mask",
url: "/safari-pinned-tab.svg",
color: "#000000",
},
{
url: "/api/logo?type=favicon-16",
sizes: "16x16",
type: "image/png",
},
{
url: "/api/logo?type=favicon-32",
sizes: "32x32",
type: "image/png",
},
],
},
manifest: "/site.webmanifest",
other: {
"application-TileColor": "#ff0000",
},
twitter: {
site: "@calcom",
creator: "@calcom",
card: "summary_large_image",
},
robots: {
index: true,
follow: true,
},
};
const getInitialProps = async () => {
const h = await headers();
const isEmbed = h.get("x-isEmbed") === "true";
const embedColorScheme = h.get("x-embedColorScheme");
const newLocale = (await getLocale(buildLegacyRequest(await headers(), await cookies()))) ?? "en";
const direction = dir(newLocale) ?? "ltr";
return {
isEmbed,
embedColorScheme,
locale: newLocale,
direction,
};
};
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const h = await headers();
const nonce = h.get("x-csp-nonce") ?? "";
const country = h.get("cf-ipcountry") || h.get("x-vercel-ip-country") || "Unknown";
const { locale, direction, isEmbed, embedColorScheme } = await getInitialProps();
const ns = "common";
const translations = await loadTranslations(locale, ns);
return (
<html
className="notranslate"
translate="no"
lang={locale}
dir={direction}
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>
{process.env.NODE_ENV === "development" && (
<Script
src="//unpkg.com/react-grab/dist/index.global.js"
crossOrigin="anonymous"
strategy="beforeInteractive"
data-options='{"activationKey":"Meta+c"}'
/>
)}
</head>
<body
className="dark:bg-default bg-subtle antialiased"
style={
isEmbed
? {
background: "transparent",
// Keep the embed hidden till parent initializes and
// - gives it the appropriate styles if UI instruction is there.
// - gives iframe the appropriate height(equal to document height) which can only be known after loading the page once in browser.
// - Tells iframe which mode it should be in (dark/light) - if there is a a UI instruction for that
visibility: "hidden",
// This in addition to visibility: hidden is to ensure that elements with specific opacity set are not visible
opacity: 0,
}
: {
visibility: "visible",
opacity: 1,
}
}>
<IconSprites />
<SpeculationRules
// URLs In Navigation
prerenderPathsOnHover={[
"/event-types",
"/availability",
"/bookings/upcoming",
"/teams",
"/apps",
]}
/>
<Providers isEmbed={isEmbed} nonce={nonce} country={country}>
<AppRouterI18nProvider translations={translations} locale={locale} ns={ns}>
{children}
</AppRouterI18nProvider>
</Providers>
</body>
</html>
);
}