Skip to content
Draft
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
7 changes: 1 addition & 6 deletions docs/app/(home)/cloud/CloudCodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

import { useTheme } from "next-themes";
import { Highlight, themes } from "prism-react-renderer";
import { useEffect, useState } from "react";
import styles from "./CloudCodeBlock.module.css";

export function CloudCodeBlock({ code }: { code: string }) {
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);

useEffect(() => setMounted(true), []);

const isDark = mounted && resolvedTheme === "dark";
const isDark = resolvedTheme === "dark";

return (
<div className={styles.panel}>
Expand Down
139 changes: 139 additions & 0 deletions docs/app/(home)/cloud/CloudHero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { ArrowUpRight } from "lucide-react";
import { BevelButton } from "../components/Button/BevelButton";
import heroStyles from "../sections/HeroSection/HeroSection.module.css";
import cloudStyles from "./page.module.css";

function CloudCtas() {
return (
<div className={cloudStyles.ctaGroup}>
<BevelButton
href="https://console.thesys.dev/keys"
external
variant="primary"
label="Get API Key"
badge={<ArrowUpRight size={16} strokeWidth={2.25} />}
/>
<BevelButton
href="https://zcal.co/t/thesys/demo"
external
variant="secondary"
label="Get a demo"
badge={<ArrowUpRight size={16} strokeWidth={2.25} />}
/>
</div>
);
}

function CloudTitle() {
return (
<span className={cloudStyles.titleBlock}>
<span className={cloudStyles.eyebrow}>
OpenUI <span className={cloudStyles.cloudTag}>Cloud</span>
</span>
<span className={cloudStyles.title}>API for running OpenUI in Production</span>
</span>
);
}

function CloudSubtitle() {
return (
<span className={cloudStyles.subtitle}>
One API for models, fallbacks, validation, rendering, and observability.
</span>
);
}

function CloudPreview({ decorative = false }: { decorative?: boolean }) {
return (
<picture>
<source
data-theme-source
media="(prefers-color-scheme: dark)"
type="image/webp"
srcSet="/openui-cloud/hero-dark-720.webp 720w, /openui-cloud/hero-dark-1280.webp 1280w"
sizes="(max-width: 767px) calc(100vw - 50px), 1280px"
/>
<img
className={cloudStyles.heroImage}
src="/openui-cloud/hero-light-1280.webp"
srcSet="/openui-cloud/hero-light-720.webp 720w, /openui-cloud/hero-light-1280.webp 1280w"
sizes="(max-width: 767px) calc(100vw - 50px), 1280px"
alt={decorative ? "" : "OpenUI Cloud production interface preview"}
aria-hidden={decorative || undefined}
width={1280}
height={600}
loading="eager"
decoding="async"
fetchPriority="high"
/>
</picture>
);
}

export function CloudHero() {
return (
<section className={heroStyles.section}>
<div className={heroStyles.desktopHero}>
<div
className={`${heroStyles.desktopHeroInner} ${heroStyles.desktopHeroInnerLeft} ${heroStyles.desktopHeroInnerFlushInline}`}
>
<div
className={`${heroStyles.desktopHeroLockup} ${heroStyles.desktopHeroLockupLeft} ${heroStyles.desktopHeroLockupSplit}`}
>
<h1 className={`${heroStyles.desktopTitle} ${heroStyles.desktopTitleLeft}`}>
<CloudTitle />
</h1>
<p
className={`${heroStyles.desktopSubtitle} ${heroStyles.desktopSubtitleLeft} ${heroStyles.desktopSubtitleSmall}`}
>
<CloudSubtitle />
</p>
</div>

<div
className={`${heroStyles.desktopCtaStack} ${heroStyles.desktopCtaStackShadowRoom} ${heroStyles.desktopCtaStackLeft}`}
>
<div className={heroStyles.commandGroup}>
<CloudCtas />
</div>
</div>
</div>
</div>

<div className={heroStyles.mobileHero}>
<div className={heroStyles.mobileHeroIntro}>
<div className={heroStyles.mobileHeroStack}>
<div className={heroStyles.mobileBrandGroup}>
<h1 className={`${heroStyles.mobileTitle} ${heroStyles.mobileTitleCompact}`}>
<CloudTitle />
</h1>
</div>
<p className={`${heroStyles.mobileSubtitle} ${heroStyles.mobileSubtitleSmall}`}>
<CloudSubtitle />
</p>
</div>
</div>

<div className={heroStyles.mobileCtaStack}>
<div className={heroStyles.commandGroup}>
<CloudCtas />
</div>
</div>

<div
className={`${heroStyles.mobileIllustrationViewport} ${heroStyles.mobileIllustrationViewportSlot}`}
>
<CloudPreview />
</div>
</div>

<div className={heroStyles.previewSection}>
<div className={heroStyles.previewDesktopOnly}>
<div className={`${heroStyles.previewFrame} ${heroStyles.previewFrameSlot}`}>
<CloudPreview decorative />
</div>
</div>
</div>
</section>
);
}
21 changes: 6 additions & 15 deletions docs/app/(home)/cloud/FeaturesSection.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,21 @@
height: 400px;
}

.featureImage {
.featureMedia {
flex: 0 0 720px;
width: 720px;
height: 400px;
border-radius: 24px;
overflow: hidden;
}

.featureImage {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

.featureImageDark {
display: none;
}

[data-theme="dark"] .featureImageLight {
display: none;
}

[data-theme="dark"] .featureImageDark {
display: block;
}

.content {
display: flex;
flex: 0 0 400px;
Expand Down Expand Up @@ -107,7 +98,7 @@
height: auto;
}

.featureImage {
.featureMedia {
flex: 0 0 auto;
width: 100%;
height: auto;
Expand All @@ -131,7 +122,7 @@
padding-inline: var(--home-section-padding-inline);
}

.featureImage {
.featureMedia {
order: -1;
border-radius: 12px;
}
Expand Down
101 changes: 53 additions & 48 deletions docs/app/(home)/cloud/FeaturesSection.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Button } from "@/components/button";
import Image from "next/image";
import type { ReactNode } from "react";
import {
FeatureGridSection,
Expand Down Expand Up @@ -64,21 +63,23 @@ export function FeaturesSection() {
<>
<section className={styles.section} aria-label="OpenUI Cloud features">
<article className={styles.card}>
<Image
className={`${styles.featureImage} ${styles.featureImageLight}`}
src="/openui-cloud/llm-gateway.svg"
alt="OpenUI Cloud routing requests across model providers"
width={720}
height={400}
/>
<Image
className={`${styles.featureImage} ${styles.featureImageDark}`}
src="/openui-cloud/llm-gateway-dark.svg"
alt=""
aria-hidden="true"
width={720}
height={400}
/>
<picture className={styles.featureMedia}>
<source
data-theme-source
media="(prefers-color-scheme: dark)"
type="image/webp"
srcSet="/openui-cloud/llm-gateway-dark.webp"
/>
<img
className={styles.featureImage}
src="/openui-cloud/llm-gateway.webp"
alt="OpenUI Cloud routing requests across model providers"
width={720}
height={400}
loading="lazy"
decoding="async"
/>
</picture>
<FeatureCopy
title="Reliable model access"
headline={
Expand All @@ -100,41 +101,45 @@ export function FeaturesSection() {
description="Make sure broken responses never reach your user. OpenUI Cloud detects invalid responses, corrects issues, and safely renders the result, in real-time."
docsHref="https://www.openui.com/docs/openui-cloud/production-readiness"
/>
<Image
className={`${styles.featureImage} ${styles.featureImageLight}`}
src="/openui-cloud/validation.svg"
alt="OpenUI Cloud validating and correcting model output"
width={720}
height={400}
/>
<Image
className={`${styles.featureImage} ${styles.featureImageDark}`}
src="/openui-cloud/validation-dark.svg"
alt=""
aria-hidden="true"
width={720}
height={400}
/>
<picture className={styles.featureMedia}>
<source
data-theme-source
media="(prefers-color-scheme: dark)"
srcSet="/openui-cloud/validation-dark.svg"
/>
<img
className={styles.featureImage}
src="/openui-cloud/validation.svg"
alt="OpenUI Cloud validating and correcting model output"
width={720}
height={400}
loading="lazy"
decoding="async"
/>
</picture>
</article>

<article className={styles.card}>
<Image
className={`${styles.featureImage} ${styles.featureImageLight}`}
src="/openui-cloud/reports&presentation.png?v=20260723-1444"
alt="OpenUI Cloud reports and presentation artifacts"
width={720}
height={400}
unoptimized
/>
<Image
className={`${styles.featureImage} ${styles.featureImageDark}`}
src="/openui-cloud/reports&presentations-dark.png"
alt=""
aria-hidden="true"
width={720}
height={400}
unoptimized
/>
<picture className={styles.featureMedia}>
<source
data-theme-source
media="(prefers-color-scheme: dark)"
srcSet="/openui-cloud/reports-dark-720.webp 720w, /openui-cloud/reports-dark-1440.webp 1440w"
sizes="(max-width: 1023px) calc(100vw - 32px), 720px"
type="image/webp"
/>
<img
className={styles.featureImage}
src="/openui-cloud/reports-light-720.webp"
srcSet="/openui-cloud/reports-light-720.webp 720w, /openui-cloud/reports-light-1440.webp 1440w"
sizes="(max-width: 1023px) calc(100vw - 32px), 720px"
alt="OpenUI Cloud reports and presentation artifacts"
width={720}
height={400}
loading="lazy"
decoding="async"
/>
</picture>
<FeatureCopy
title="Live & Static Artifacts"
headline="Generate more than chat responses"
Expand Down
34 changes: 34 additions & 0 deletions docs/app/(home)/cloud/ThemeImageController.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import { useEffect } from "react";

export function ThemeImageController() {
useEffect(() => {
const root = document.documentElement;

const syncSources = () => {
const dark = root.dataset.theme === "dark";
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const media =
dark === prefersDark ? "(prefers-color-scheme: dark)" : dark ? "all" : "not all";

document
.querySelectorAll<HTMLSourceElement>("source[data-theme-source]")
.forEach((source) => {
if (source.media !== media) source.media = media;
});
};

syncSources();

const observer = new MutationObserver(syncSources);
observer.observe(root, {
attributes: true,
attributeFilter: ["data-theme"],
});

return () => observer.disconnect();
}, []);

return null;
}
12 changes: 0 additions & 12 deletions docs/app/(home)/cloud/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@
height: auto;
}

.heroImageDark {
display: none;
}

[data-theme="dark"] .heroImageLight {
display: none;
}

[data-theme="dark"] .heroImageDark {
display: block;
}

@media (max-width: 1023px) {
.title {
font-size: inherit;
Expand Down
Loading
Loading