Skip to content
Merged
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
6 changes: 3 additions & 3 deletions docs/app/(home)/benchmarks/BenchmarksContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,13 @@ export function BenchmarksContent() {
</div>

<CloudCtaSection
title="Improve your Generative UI reliability with OpenUI Cloud."
title="Improve your Generative UI reliability with OpenUI Gateway."
primary={{
label: "Get OpenUI Cloud",
label: "Get OpenUI Gateway",
href: "https://console.thesys.dev/keys",
external: true,
}}
secondary={{ label: "Learn more", href: "/docs/openui-cloud" }}
secondary={{ label: "Learn more", href: "/cloud/gateway" }}
/>
</VizSkin>
</main>
Expand Down
29 changes: 24 additions & 5 deletions docs/app/(home)/cloud/CloudCodeBlock.module.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
.panel {
overflow: hidden;
min-height: 360px;
min-height: var(--cloud-code-min-height, 420px);
border: 1px solid var(--openui-border-default);
border-radius: 20px;
background: var(--openui-foreground);
animation: codePanelIn 220ms ease-out both;
}

@keyframes codePanelIn {
from {
opacity: 0.65;
transform: translateY(4px);
}

to {
opacity: 1;
transform: translateY(0);
}
}

.code {
margin: 0;
overflow-x: auto;
padding: 40px 0;
padding: 48px 0;
font-family: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
font-size: 15px;
font-size: 16px;
line-height: 1.7;
text-align: left;
}

.codeLine {
display: block;
min-width: max-content;
padding: 0 40px;
padding: 0 48px;
white-space: pre;
}

.changedLine {
border-left: 3px solid #22c55e;
padding-left: 37px;
padding-left: 45px;
background: rgb(34 197 94 / 14%);
}

Expand All @@ -38,3 +51,9 @@
display: none;
}
}

@media (prefers-reduced-motion: reduce) {
.panel {
animation: none;
}
}
15 changes: 13 additions & 2 deletions docs/app/(home)/cloud/CloudCodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { Highlight, themes } from "prism-react-renderer";
import { useEffect, useState } from "react";
import styles from "./CloudCodeBlock.module.css";

export function CloudCodeBlock({ code }: { code: string }) {
/* `highlightLines` are 0-based indices into the trimmed source. It defaults to
the single line Cloud's integration section has always marked, so existing
callers keep their highlight without passing anything. */
export function CloudCodeBlock({
code,
highlightLines = [4],
}: {
code: string;
highlightLines?: number[];
}) {
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);

Expand All @@ -30,7 +39,9 @@ export function CloudCodeBlock({ code }: { code: string }) {
<span
key={lineIndex}
{...getLineProps({ line })}
className={`${styles.codeLine} ${lineIndex === 4 ? styles.changedLine : ""}`}
className={`${styles.codeLine} ${
highlightLines.includes(lineIndex) ? styles.changedLine : ""
}`}
>
{line.map((token, tokenIndex) => (
<span key={tokenIndex} {...getTokenProps({ token })} />
Expand Down
4 changes: 2 additions & 2 deletions docs/app/(home)/cloud/CloudCtaSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ interface CtaAction {

export function CloudCtaSection({
title = "Turn your OpenUI application into a production-grade experience.",
primary = { label: "Get API Key", href: "https://console.thesys.dev/keys", external: true },
secondary = { label: "Talk to our team", href: "https://zcal.co/t/thesys/demo", external: true },
primary = { label: "Get API key", href: "https://console.thesys.dev/keys", external: true },
secondary = { label: "Book a demo", href: "https://zcal.co/t/thesys/demo", external: true },
}: {
title?: string;
primary?: CtaAction;
Expand Down
51 changes: 48 additions & 3 deletions docs/app/(home)/cloud/CloudIntegrationSection.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
.inner {
display: flex;
align-items: stretch;
gap: 120px;
gap: 72px;
width: 100%;
max-width: 1200px;
margin-inline: auto;
Expand All @@ -23,7 +23,14 @@
text-align: left;
}

.intro {
display: flex;
flex-direction: column;
gap: 20px;
}

.title {
max-width: 460px;
margin: 0;
color: var(--openui-text-neutral-primary);
font-family: "Inter Display", sans-serif;
Expand All @@ -33,6 +40,21 @@
letter-spacing: var(--home-title-tracking);
}

.title[data-size="medium"] {
font-size: var(--home-title-medium-size);
}

.description {
max-width: 460px;
margin: 0;
color: var(--openui-text-neutral-secondary);
font-family: var(--home-font-text);
font-size: var(--home-body-size);
font-weight: var(--home-body-weight);
line-height: var(--home-body-leading);
text-wrap: pretty;
}

.stepper {
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -84,6 +106,10 @@
font-size: 13px;
font-weight: 500;
line-height: 1;
transition:
border-color 160ms ease,
background-color 160ms ease,
color 160ms ease;
}

.stepContent {
Expand Down Expand Up @@ -131,11 +157,15 @@
line-height: var(--home-body-leading);
}

.integrationAction {
margin-top: 24px;
}

.codeColumn {
display: flex;
box-sizing: border-box;
flex: 0 0 600px;
width: 600px;
flex: 0 0 640px;
width: 640px;
max-width: 100%;
}

Expand Down Expand Up @@ -293,6 +323,14 @@
gap: 32px;
}

.stepper[data-interactive="true"][data-step-count="2"] {
height: 248px;
}

.stepper[data-interactive="true"][data-step-count="3"] {
height: 312px;
}

.title {
font-size: 28px;
}
Expand Down Expand Up @@ -334,3 +372,10 @@
font-size: 17px;
}
}

@media (prefers-reduced-motion: reduce) {
.stepper[data-interactive="true"] .step[data-active="true"]:not(:last-child)::after,
.stepper[data-interactive="true"] .stepDescription {
animation: none;
}
}
140 changes: 102 additions & 38 deletions docs/app/(home)/cloud/CloudIntegrationSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"use client";

import { Button } from "@/components/button";
import { ArrowUpRight } from "lucide-react";
import Image from "next/image";
import { Button } from "@/components/button";
import { type ReactNode } from "react";
import { CloudCodeBlock } from "./CloudCodeBlock";
import styles from "./CloudIntegrationSection.module.css";

Expand Down Expand Up @@ -44,50 +47,111 @@ const CUSTOMERS = [
},
] as const;

export function CloudIntegrationSection() {
export type CloudIntegrationStep = {
title: string;
description: string;
href?: string;
};

export function CloudIntegrationSetup({
title,
titleId,
description,
steps,
code,
codeLabel,
action,
highlightLines,
titleSize = "default",
}: {
title: ReactNode;
titleId?: string;
description?: ReactNode;
steps: CloudIntegrationStep[];
code: string;
codeLabel: string;
action?: { label: string; href: string };
highlightLines?: number[];
titleSize?: "default" | "medium";
}) {
return (
<section className={styles.section} aria-labelledby="cloud-integration-title">
<div className={styles.inner}>
<div className={styles.content}>
<h2 id="cloud-integration-title" className={styles.title}>
Switch to OpenUI <span className={styles.cloudTag}>Cloud</span>
<br />
in seconds
<div className={styles.inner}>
<div className={styles.content}>
<div className={styles.intro}>
<h2 id={titleId} className={styles.title} data-size={titleSize}>
{title}
</h2>
<ol className={styles.stepper} aria-label="Upgrade to OpenUI Cloud">
<li className={styles.step}>
<span className={styles.stepMarker}>1</span>
<div className={styles.stepContent}>
<a
className={styles.stepLink}
href="https://console.thesys.dev/keys"
target="_blank"
rel="noreferrer"
>
Generate an API Key
<ArrowUpRight size={16} strokeWidth={2} aria-hidden="true" />
</a>
<p className={styles.stepDescription}>
Create a Cloud API key from the OpenUI console.
</p>
</div>
</li>
<li className={styles.step}>
<span className={styles.stepMarker}>2</span>
{description ? <p className={styles.description}>{description}</p> : null}
</div>
<ol className={styles.stepper} aria-label={codeLabel}>
{steps.map((step, index) => (
<li className={styles.step} key={step.title}>
<span className={styles.stepMarker}>{index + 1}</span>
<div className={styles.stepContent}>
<span className={styles.stepTitle}>Update your base URL</span>
<p className={styles.stepDescription}>
Point your OpenAI-compatible client to the OpenUI Cloud endpoint.
</p>
{step.href ? (
<a
className={styles.stepLink}
href={step.href}
target="_blank"
rel="noreferrer"
>
{step.title}
<ArrowUpRight size={16} strokeWidth={2} aria-hidden="true" />
</a>
) : (
<span className={styles.stepTitle}>{step.title}</span>
)}
<p className={styles.stepDescription}>{step.description}</p>
</div>
</li>
</ol>
</div>
))}
</ol>
{action ? (
<div className={styles.integrationAction}>
<Button href={action.href} text={action.label} variant="tertiary" />
</div>
) : null}
</div>

<div className={styles.codeColumn} aria-label="OpenUI Cloud client configuration">
<CloudCodeBlock code={CLIENT_EXAMPLE} />
</div>
<div
className={styles.codeColumn}
id={`${titleId ?? "cloud-integration"}-code`}
aria-label={codeLabel}
>
<CloudCodeBlock code={code} highlightLines={highlightLines} />
</div>
</div>
);
}

export function CloudIntegrationSection() {
const steps: CloudIntegrationStep[] = [
{
title: "Generate an API Key",
description: "Create a Cloud API key from the OpenUI console.",
href: "https://console.thesys.dev/keys",
},
{
title: "Update your base URL",
description: "Point your OpenAI-compatible client to the OpenUI Cloud endpoint.",
},
];

return (
<section className={styles.section} aria-labelledby="cloud-integration-title">
<CloudIntegrationSetup
title={
<>
Switch to OpenUI <span className={styles.cloudTag}>Cloud</span>
<br />
in seconds
</>
}
titleId="cloud-integration-title"
steps={steps}
code={CLIENT_EXAMPLE}
codeLabel="Upgrade to OpenUI Cloud"
/>

<div className={styles.customers}>
<h2 className={styles.customersTitle}>
Expand Down
Loading
Loading