Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 1 addition & 9 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@ export default {
trailingSlash: true,
tagline: "GraphQL platform engineered for scale",
headTags: [
{
tagName: "script",
attributes: {
id: "chatbotscript",
"data-accountid": "CZPG9aVdtk59Tjz4SMTu8w==",
"data-websiteid": "75VGI0NlBqessD4BQn2pFg==",
src: "https://app.robofy.ai/bot/js/common.js?v=" + new Date().getTime(),
},
},
{
tagName: "script",
attributes: {
Expand Down Expand Up @@ -152,6 +143,7 @@ export default {
tableOfContents: {},
} satisfies Preset.ThemeConfig,
plugins: [
"./plugins/home-performance-plugin.ts",
[
"./plugins/custom-blog-plugin.ts",
{
Expand Down
1 change: 1 addition & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export {}
declare global {
interface Window {
gtag: (...args: any[]) => void
__homeAssetsRequested?: boolean
}
}
153 changes: 153 additions & 0 deletions plugins/home-performance-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {readFileSync, writeFileSync} from "fs"
import {join} from "path"
import type {Plugin} from "@docusaurus/types"

const CRITICAL_HOME_CSS = String.raw`
html,body{margin:0;background:#fff;color:#121315;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
*,*::before,*::after{box-sizing:border-box}
a{color:inherit;text-decoration:none}
img,svg{display:block;max-width:100%}
.skipToContent_fXgn{position:absolute;left:-999px}
.navbar{position:sticky;top:0;z-index:20;height:72px;background:#fff;border-bottom:1px solid #f3f4f7;padding:0 24px;display:flex;align-items:center}
.navbar__inner{align-items:center;display:flex;justify-content:space-between;margin:0 auto;max-width:1280px;width:100%}
.navbar__items{align-items:center;display:flex;gap:24px}
.navbar__items--right{margin-left:auto}
.navbar__brand,.navbar__link{align-items:center;display:flex}
.navbar__logo img{height:44px;width:auto}
.themedComponent--dark_xIcU{display:none}
.navbar__link{color:#323335;font-size:16px;font-weight:500}
.navbar__link--active{color:#121315;font-weight:700}
.navbar__toggle{background:transparent;border:0;color:#121315;display:none;padding:8px}
.dropdown{position:relative}
.dropdown__menu{background:#fff;border:1px solid #e7e7e7;border-radius:12px;box-shadow:0 16px 48px rgba(18,19,21,.12);display:none;list-style:none;margin:0;padding:8px;position:absolute;top:100%;width:180px}
.dropdown:hover .dropdown__menu,.dropdown:focus-within .dropdown__menu{display:block}
.dropdown__link{border-radius:8px;color:#323335;display:block;padding:8px 10px}
.DocSearch{display:none}
.hidden{display:none!important}
.flex{display:flex}
.grid{display:grid}
.items-center{align-items:center}
.justify-center{justify-content:center}
.justify-between{justify-content:space-between}
.relative{position:relative}
.absolute{position:absolute}
.inset-0{inset:0}
.z-20{position:relative;z-index:2}
.w-full{width:100%}
.h-full{height:100%}
.max-w-7xl{max-width:80rem}
.max-w-xs{max-width:20rem}
.max-w-md{max-width:28rem}
.mx-auto{margin-left:auto;margin-right:auto}
.mb-0{margin-bottom:0}
.mt-SPACE_06{margin-top:24px}
.space-x-SPACE_04>*+*{margin-left:16px}
main.grid{justify-content:center}
section.w-full{padding:24px 32px 0;width:100%}
.hero-banner-title{color:#121315;font-size:32px;font-weight:700;letter-spacing:0;line-height:41.6px;margin:0}
.hero-banner-sub-title{color:#545556;font-size:16px;font-weight:400;line-height:24px;margin-top:16px}
.bg-tailCall-yellow{background:#fdea2e}
.rounded-md{border-radius:8px}
.px-SPACE_02{padding-left:8px;padding-right:8px}
main a.group{align-items:center;border-radius:8px;display:flex;font-size:16px;font-weight:700;height:48px;justify-content:center;overflow:hidden;padding:12px 24px;position:relative;width:100%}
.border{border:1px solid #121315}
.border-2{border:2px solid #121315}
.border-solid{border-style:solid}
.bg-tailCall-dark-500{background:#121315}
.bg-transparent{background:transparent}
.text-tailCall-light-100{color:#fff}
.text-tailCall-dark-500{color:#121315}
html[data-has-hydrated="false"] footer.flex{display:none!important}
@media (max-width:767px){
.navbar{height:72px;padding:0 20px}
.navbar__toggle{display:block}
.navbar__item,.navbar__items--right{display:none}
}
@media (min-width:640px){
.sm\:flex{display:flex!important}
.sm\:hidden{display:none!important}
.sm\:items-center{align-items:center}
.sm\:text-center{text-align:center}
.sm\:max-w-5xl{max-width:64rem}
.sm\:max-w-2xl{max-width:42rem}
.sm\:m-auto{margin:auto}
.sm\:mt-SPACE_04{margin-top:16px}
.sm\:mt-SPACE_10{margin-top:40px}
.sm\:space-x-SPACE_06>*+*{margin-left:24px}
.sm\:rounded-2xl{border-radius:16px}
.sm\:rounded-xl{border-radius:12px}
.sm\:text-display-small{font-size:56px;letter-spacing:0;line-height:67.2px}
.sm\:text-content-medium{font-size:20px;line-height:32px}
.sm\:text-title-small{font-size:20px;line-height:26px}
.sm\:h-16{height:64px}
.sm\:px-SPACE_08{padding-left:32px;padding-right:32px}
.sm\:py-SPACE_04{padding-bottom:16px;padding-top:16px}
}
@media (min-width:768px){
section.w-full{padding:48px 96px 0}
}
@media (min-width:1024px){
section.w-full{padding:80px 144px 0}
.lg\:flex{display:flex!important}
.lg\:block{display:block!important}
.lg\:text-display-large{font-size:96px;letter-spacing:0;line-height:105.6px}
.lg\:text-content-large{font-size:24px;line-height:36px}
.lg\:px-SPACE_10{padding-left:40px;padding-right:40px}
.lg\:py-SPACE_05{padding-bottom:20px;padding-top:20px}
}
`

const createDeferredAssetLoader = (stylesheets: string[], scripts: string[]) => `<script>
(function(){
var loaded=false;
var styles=${JSON.stringify(stylesheets)};
var scripts=${JSON.stringify(scripts)};
function loadAssets(){
if(loaded)return;
loaded=true;
window.__homeAssetsRequested=true;
styles.forEach(function(href){
var link=document.createElement("link");
link.rel="stylesheet";
link.href=href;
document.head.appendChild(link);
});
scripts.reduce(function(chain,src){
return chain.then(function(){
return new Promise(function(resolve){
var script=document.createElement("script");
script.src=src;
script.defer=true;
script.onload=resolve;
script.onerror=resolve;
document.body.appendChild(script);
});
});
},Promise.resolve());
}
["scroll","pointerdown","touchstart","keydown"].forEach(function(eventName){
window.addEventListener(eventName,loadAssets,{once:true,passive:true});
});
window.__loadTailcallHomeAssets=loadAssets;
})();
</script>`

export default function homePerformancePlugin(): Plugin<void> {
return {
name: "home-performance-plugin",
postBuild({outDir}) {
const indexPath = join(outDir, "index.html")
let html = readFileSync(indexPath, "utf8")
const stylesheets = Array.from(html.matchAll(/<link rel="stylesheet" href="([^"]+)">/g), (match) => match[1])
const scripts = Array.from(html.matchAll(/<script src="([^"]+)" defer="defer"><\/script>/g), (match) => match[1])

html = html.replace(/<script data-rh="true">function insertBanner\(\)[\s\S]*?<\/script>/, "")
html = html.replace(/<link rel="stylesheet" href="[^"]+">\n?/g, "")
html = html.replace(/<script src="[^"]+" defer="defer"><\/script>\n?/g, "")
html = html.replace("</head>", `<style>${CRITICAL_HOME_CSS}</style></head>`)
html = html.replace("</body>", `${createDeferredAssetLoader(stylesheets, scripts)}</body>`)

writeFileSync(indexPath, html)
},
}
}
10 changes: 7 additions & 3 deletions src/components/home/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import React from "react"
import Heading from "@theme/Heading"

import LinkButton from "../shared/LinkButton"
import HeroImage from "@site/static/images/home/hero.svg"
import {analyticsHandler} from "@site/src/utils"
import {Theme, codeSandboxUrl} from "@site/src/constants"
import {pageLinks} from "@site/src/constants/routes"
import Link from "@docusaurus/Link"
import Section from "../shared/Section"

const Banner = (): JSX.Element => {
Expand Down Expand Up @@ -59,7 +57,13 @@ const Banner = (): JSX.Element => {
</div>
</div>
</Section>
<HeroImage className="object-contain h-full sm:h-full w-full mt-8 max-w-7xl" />
<img
src="/images/home/hero.svg"
alt=""
loading="lazy"
decoding="async"
className="hidden sm:block object-contain h-full sm:h-full w-full mt-8 max-w-7xl"
/>
</main>
)
}
Expand Down
23 changes: 23 additions & 0 deletions src/components/home/DeferredSections.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react"

import Benefits from "./Benefits"
import Configuration from "./Configuration"
import Discover from "../shared/Discover"
import Graph from "./Graph"
import IntroductionVideo from "./IntroductionVideo"
import Testimonials from "./Testimonials"

const DeferredSections = (): JSX.Element => {
return (
<>
<Configuration />
<IntroductionVideo />
<Testimonials />
<Benefits />
<Graph />
<Discover />
</>
)
}

export default DeferredSections
25 changes: 16 additions & 9 deletions src/components/home/IntroductionVideo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, {useRef} from "react"
import React, {useRef, useState} from "react"
import {useCookieConsent} from "@site/src/utils/hooks/useCookieConsent"
import "./style.css"

const IntroductionVideo: React.FC = () => {
const videoId = "1011521201"
const videoRef = useRef<HTMLDivElement>(null)
const [isLoaded, setIsLoaded] = useState(false)
const {getCookieConsent} = useCookieConsent()
const cookieConsent = getCookieConsent()

Expand All @@ -15,14 +16,20 @@ const IntroductionVideo: React.FC = () => {
return (
<div className="video-wrapper" ref={videoRef}>
<div className="video-container">
<iframe
src={`https://player.vimeo.com/video/${videoId}?autoplay=0&badge=0&autopause=0&player_id=0&app_id=58479${handleVimeoAnalytics()}`}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="absolute top-0 left-0 w-full h-full"
title="Tailcall Introduction Video"
loading="lazy"
/>
{isLoaded ? (
<iframe
src={`https://player.vimeo.com/video/${videoId}?autoplay=1&badge=0&autopause=0&player_id=0&app_id=58479${handleVimeoAnalytics()}`}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="absolute top-0 left-0 w-full h-full"
title="Tailcall Introduction Video"
/>
) : (
<button className="video-play-button" type="button" onClick={() => setIsLoaded(true)}>
<span className="video-play-icon" aria-hidden="true" />
<span className="sr-only">Play Tailcall introduction video</span>
</button>
)}
</div>
</div>
)
Expand Down
27 changes: 27 additions & 0 deletions src/components/home/IntroductionVideo/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@
background-size: 100%;
}

.video-play-button {
align-items: center;
background: rgba(18, 19, 21, 0.74);
border: 0;
cursor: pointer;
display: flex;
inset: 0;
justify-content: center;
position: absolute;
transition: background 0.2s ease;
width: 100%;
}

.video-play-button:hover,
.video-play-button:focus-visible {
background: rgba(18, 19, 21, 0.62);
}

.video-play-icon {
border-bottom: 24px solid transparent;
border-left: 34px solid #fff;
border-top: 24px solid transparent;
height: 0;
margin-left: 8px;
width: 0;
}

.video-background {
position: absolute;
top: 0;
Expand Down
51 changes: 36 additions & 15 deletions src/components/home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
import React from "react"
import React, {Suspense, useEffect, useState} from "react"

import Banner from "./Banner"
import Graph from "./Graph"
import Benefits from "./Benefits"
import Discover from "../shared/Discover"
import Configuration from "./Configuration"
import Testimonials from "./Testimonials"
import Announcement from "../shared/Announcement"
import IntroductionVideo from "./IntroductionVideo"

const DeferredSections = React.lazy(() => import("./DeferredSections"))

const DeferredSectionsLoader = (): JSX.Element | null => {
const [isReady, setIsReady] = useState(() => {
return typeof window !== "undefined" && Boolean(window.__homeAssetsRequested)
})

useEffect(() => {
if (typeof window === "undefined") return

const loadSections = () => setIsReady(true)
const events: Array<keyof WindowEventMap> = ["scroll", "pointerdown", "touchstart", "keydown"]

events.forEach((eventName) => {
window.addEventListener(eventName, loadSections, {once: true, passive: true})
})

return () => {
events.forEach((eventName) => {
window.removeEventListener(eventName, loadSections)
})
}
}, [])

if (!isReady) return null

return (
<Suspense fallback={null}>
<DeferredSections />
</Suspense>
)
}

const HomePage = (): JSX.Element => {
return (
<div className="">
<Banner />
<Configuration />
<IntroductionVideo />
<Testimonials />
<Benefits />
<Graph />
{/* <Playground /> */}
<Discover />
<DeferredSectionsLoader />
</div>
)
}
Expand Down
Loading
Loading