diff --git a/studio/next.config.mjs b/studio/next.config.mjs index 3fa913897c..4d5b5cf068 100644 --- a/studio/next.config.mjs +++ b/studio/next.config.mjs @@ -62,7 +62,7 @@ const lightweightCspHeader = ` frame-src 'self' https://js.stripe.com https://hooks.stripe.com https://www.googletagmanager.com${ isPreview || isProduction ? ' https://vercel.live https://vercel.com' : '' }; - img-src 'self'${ + img-src 'self' https://wundergraph.com ${ isPreview || isProduction ? ' https://vercel.live/ https://vercel.com *.pusher.com data: blob:' : '' @@ -108,6 +108,15 @@ const lightweightCspHeader = ` /** @type {import("next").NextConfig} */ const config = { output: "standalone", + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "wundergraph.com", + pathname: "/images/**", + }, + ], + }, // This is done to reduce the production build size // see: https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/tree-shaking/ webpack: (config, { webpack }) => { diff --git a/studio/public/login/auth-bg.png b/studio/public/login/auth-bg.png new file mode 100644 index 0000000000..561e0985b1 Binary files /dev/null and b/studio/public/login/auth-bg.png differ diff --git a/studio/src/components/auth/auth-components.tsx b/studio/src/components/auth/auth-components.tsx new file mode 100644 index 0000000000..9ae64bf3ac --- /dev/null +++ b/studio/src/components/auth/auth-components.tsx @@ -0,0 +1,239 @@ +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import Link from "next/link"; +import { Logo } from "../logo"; +import { ReactNode } from "react"; +import { + BoltIcon, + CodeBracketIcon, + ShieldCheckIcon, + ShareIcon, + MagnifyingGlassIcon, + RocketLaunchIcon, +} from "@heroicons/react/24/outline"; + +/** + * Auth Card - The card container for auth forms + */ +export interface AuthCardProps { + children: ReactNode; + className?: string; +} + +export const AuthCard = ({ children, className }: AuthCardProps) => { + return ( +
+ {children} +
+ ); +}; + +/** + * Auth Logo Header - WunderGraph Cosmo logo with text + */ +export const AuthLogoHeader = () => { + return ( + + + + WunderGraph Cosmo + + + ); +}; + +/** + * Auth Footer - Footer with links for auth pages + * Height: 65px / 900px = 7.2% + */ +export const AuthFooter = () => { + const currentYear = new Date().getFullYear(); + + const footerLinks = [ + { + href: "https://wundergraph.com/privacy-policy", + label: "Privacy Policy", + }, + { + href: "https://trust.wundergraph.com/", + label: "Trust Center", + }, + { + href: "https://wundergraph.com/terms", + label: "Website Terms of Use", + }, + { + href: "https://wundergraph.com/cosmo-managed-service-terms", + label: "Cosmo Managed Service Terms", + }, + { + href: "https://wundergraph.com/pricing", + label: "Pricing", + }, + ]; + + return ( + + ); +}; + +/** + * Trusted Companies - "Trusted by companies like:" section with logos + */ +export const TrustedCompanies = () => { + const companies = [ + { name: "Shutterstock", logo: "https://wundergraph.com/images/logos/shutterstock.svg", width: 120, height: 24 }, + { name: "eBay", logo: "https://wundergraph.com/images/logos/ebay.svg", width: 60, height: 24 }, + { name: "SoundCloud", logo: "https://wundergraph.com/images/logos/soundcloud.svg", width: 120, height: 24 }, + ]; + + return ( +
+

Trusted by platform teams managing complex API ecosystems

+
+ {companies.map((company) => ( + {company.name} + ))} +
+
+ ); +}; + +/** + * Marketing Header - Title and description for the right side + */ +export const MarketingHeader = () => { + return ( +
+

+ Cosmo: Open-Source +
+ GraphQL Federation Solution +

+

+ Unify distributed APIs into one federated graph. Platform teams get observability and control. Service teams ship independently. +

+
+ ); +}; + +/** + * Feature Item - Individual feature with icon box + */ +const FeatureItem = ({ + icon, + title, + description, +}: { + icon: React.ReactNode; + title: string; + description: string; +}) => ( +
+
+ {icon} +
+
+

{title}

+

{description}

+
+
+); + +/** + * Product Cosmo Stack - Marketing content with features list + */ +export const ProductCosmoStack = ({ variant = "login" }: { variant?: "login" | "signup" }) => { + const loginFeatures = [ + { + icon: , + title: "Real time subscriptions without new infrastructure", + description: + "Cosmo Streams turns existing event streams into GraphQL subscriptions by handling authorization, filtering, and fan out in the Cosmo Router, keeping subgraphs stateless and avoiding a separate service.", + }, + { + icon: , + title: "Extend the router with TypeScript", + description: + "With TypeScript plugin support in Cosmo Connect, you can extend the Cosmo Router using TypeScript and run custom logic directly inside the router, without deploying separate services.", + }, + { + icon: , + title: "Enforce custom schema rules before deploy", + description: + "With Subgraph Check Extensions, you can run your own validation logic as part of Cosmo's subgraph checks, enforcing custom schema rules before changes are deployed.", + }, + ]; + + const signupFeatures = [ + { + icon: , + title: "Federate Any API, Not Just GraphQL", + description: + "Connect REST, gRPC, and GraphQL services without rewrites. Cosmo Connect wraps existing APIs into your graph without forcing migrations.", + }, + { + icon: , + title: "Track Every Query Across Your Entire Graph", + description: + "Native OpenTelemetry tracing from gateway to subgraph. Find slow queries and failing services in seconds with zero instrumentation required.", + }, + { + icon: , + title: "Catch Breaking Changes Before Deployment", + description: + "Schema checks run automatically in CI/CD. Service teams ship on their own schedule, while platform teams prevent breaking changes from reaching production.", + }, + { + icon: , + title: "Built for Scale and Performance", + description: + "Go router with sub-millisecond overhead. Deploy with built-in caching, rate limiting, and security controls wherever your infrastructure lives.", + }, + ]; + + const features = variant === "login" ? loginFeatures : signupFeatures; + + return ( +
+ +
+ {features.map((feature, index) => ( + + ))} +
+
+ ); +}; diff --git a/studio/src/components/auth/cosmo-stack.tsx b/studio/src/components/auth/cosmo-stack.tsx deleted file mode 100644 index f83b8ea739..0000000000 --- a/studio/src/components/auth/cosmo-stack.tsx +++ /dev/null @@ -1,601 +0,0 @@ -import { - CommandLineIcon, - DocumentCheckIcon, - RocketLaunchIcon, -} from "@heroicons/react/24/outline"; -import { SVGProps, useId } from "react"; -import { SiGraphql } from "react-icons/si"; - -const Illustration = (props: SVGProps) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -); - -export const Arc = (props: SVGProps) => { - const a = useId(); - const b = useId(); - const c = useId(); - - return ( - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export const ProductCosmoStack = () => { - return ( -
-
-
-
-

- Full Lifecycle (Federated) GraphQL API Management -

-

- Cosmo is a drop-in replacement to other services like Apollo - GraphOS. It's the only OSS solution that bundles everything - from Router to Schema Registry, Analytics and Tracing in one - package. Perfect for monolithic and Federated GraphQL APIs. -

-
-
-
-

- - Federation v1 and v2 compatible -

-

- All your existing GraphQL Services will work out of the box. - Any framework, any language. -

-
-
-

- - Fast and Reliable Router -

-

- The fastest and most reliable Router for GraphQL with - support for Subscriptions and JWT Auth. -

-
-
-
-
-

- - Maximized compliance -

-

- Deploy Cosmo 100% on-prem for strict compliance requirements - or use our managed service. -

-
-
-

- - Powerful CLI -

-

- Manage all your GraphQL Workflows from the command line. -

-
-
-
-
- {/* */} -
-
-
- ); -}; diff --git a/studio/src/components/layout/auth-layout.tsx b/studio/src/components/layout/auth-layout.tsx index 535bfbffbc..b08b7fbb50 100644 --- a/studio/src/components/layout/auth-layout.tsx +++ b/studio/src/components/layout/auth-layout.tsx @@ -1,19 +1,15 @@ -import { Arc } from "../auth/cosmo-stack"; - export interface LayoutProps { children?: React.ReactNode; } export const AuthLayout = ({ children }: LayoutProps) => { return ( -
-
-
- - -
+
+ {/* Background image overlay */} +
-
{children}
+ {/* Content */} +
{children}
); }; diff --git a/studio/src/pages/login.tsx b/studio/src/pages/login.tsx index a745c150c1..aac070ff4e 100644 --- a/studio/src/pages/login.tsx +++ b/studio/src/pages/login.tsx @@ -1,6 +1,11 @@ -import { ProductCosmoStack } from "@/components/auth/cosmo-stack"; +import { + AuthCard, + AuthLogoHeader, + AuthFooter, + TrustedCompanies, + ProductCosmoStack, +} from "@/components/auth/auth-components"; import { AuthLayout } from "@/components/layout/auth-layout"; -import { Logo } from "@/components/logo"; import { Button } from "@/components/ui/button"; import { NextPageWithLayout } from "@/lib/page"; import { ArrowRightIcon, GitHubLogoIcon } from "@radix-ui/react-icons"; @@ -54,102 +59,117 @@ const LoginPage: NextPageWithLayout = () => { }, [cosmoIdpHintCookieValue, sso, router]); return ( -
-
- - -

WunderGraph Cosmo

-
-
-

Sign in

-
-

- Don't have an account yet?{" "} - - Sign up - -

-
- - - {sso ? ( - + + + + {sso && ( + + )} + + +
+ + {/* Divider line */} +
+ +

+ Don't have an account? - - Sign in with SSO + Sign Up - - ) : null} - - - - +

+
+ + + {/* Trusted companies */} +
+ +
+ + {/* Right section */} +
+ +
-
- -
+ + {/* Footer */} +
); }; -const Divider = () => ( -
-
- or -
-
-); - LoginPage.getLayout = (page) => { return {page}; }; diff --git a/studio/src/pages/signup.tsx b/studio/src/pages/signup.tsx index f0fd398321..ad1ef1ce01 100644 --- a/studio/src/pages/signup.tsx +++ b/studio/src/pages/signup.tsx @@ -1,6 +1,11 @@ -import { ProductCosmoStack } from "@/components/auth/cosmo-stack"; +import { + AuthCard, + AuthLogoHeader, + AuthFooter, + TrustedCompanies, + ProductCosmoStack, +} from "@/components/auth/auth-components"; import { AuthLayout } from "@/components/layout/auth-layout"; -import { Logo } from "@/components/logo"; import { Button } from "@/components/ui/button"; import { NextPageWithLayout } from "@/lib/page"; import { ArrowRightIcon, GitHubLogoIcon } from "@radix-ui/react-icons"; @@ -38,77 +43,99 @@ const SignupPage: NextPageWithLayout = () => { const { redirectURL } = querySchema.parse(router.query); return ( -
-
- - -

WunderGraph Cosmo

-
-
-

Sign up

-

- Already have an account?{" "} - - Sign in - -

- -
- - - -
-
- or -
+
+ {/* Main content area - two columns */} +
+
+ {/* Left section */} +
+
+ + + +
+

+ Sign up for free +

+ +
+ + + + + +
+ + {/* Divider line */} +
+ +

+ Already have an account? + + Log in + +

+
+ + + {/* Trusted companies */} +
+ +
+
- + {/* Right section */} +
+
-
- -
+ + {/* Footer */} +
); };