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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ jobs:
run: yarn build
working-directory: website-next

- name: Visual Regression Tests
run: yarn test:visual
working-directory: website-next

- name: Upload Playwright Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: playwright-report
path: website-next/playwright-report/
retention-days: 7

configure:
name: Generate Test Matrix
runs-on: ubuntu-latest
Expand Down
6 changes: 6 additions & 0 deletions website-next/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
# testing
/coverage

# playwright visual tests (committed baselines live in tests/visual/__screenshots__)
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

# next.js
/.next/
/out/
Expand Down
41 changes: 24 additions & 17 deletions website-next/app/(content)/help/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next";

import { type Plan, PlanGrid } from "@/src/components/PlanGrid";
import { Offering } from "@/src/components/Offering";
import { OfferingGrid } from "@/src/components/OfferingGrid";
import { Section } from "@/src/components/Section";

export const metadata: Metadata = {
Expand All @@ -9,45 +10,51 @@ export const metadata: Metadata = {
"Need urgent GraphQL help? Join the ChilliCream community Slack, book a session with an expert, or choose a support plan that fits your team.",
};

const PLANS: Plan[] = [
const PLANS = [
{
title: "Community",
price: 0,
period: "hour",
price: "Free",
description:
"Be part of the Community, get help, and help others. Together we're strong.",
features: ["Public Slack Channel", "7000+ Individuals"],
ctaText: "Join Slack",
ctaLink: "https://slack.chillicream.com/",
perks: ["Public Slack Channel", "7000+ Individuals"],
callToAction: {
title: "Join Slack",
link: "https://slack.chillicream.com/",
},
},
{
title: "Consultancy",
price: 300,
period: "hour",
price: "$300",
priceNote: "per hour",
description: "You need immediate help and want to talk to an Expert.",
features: ["Dedicated Session", "Dedicated Expert"],
ctaText: "Book a Session",
ctaLink: "https://calendly.com/chillicream/60min",
perks: ["Dedicated Session", "Dedicated Expert"],
callToAction: {
title: "Book a Session",
link: "https://calendly.com/chillicream/60min",
},
},
{
title: "Support",
price: "custom",
price: "Custom",
description: "You need a Support Plan. Here you go.",
features: [
perks: [
"Dedicated Account Manager",
"Private Slack Channel",
"E-Mail Support",
"And More...",
],
ctaText: "Check out Plans",
ctaLink: "/services/support",
callToAction: { title: "Check out Plans", link: "/services/support" },
},
];

export default function HelpPage() {
return (
<Section title="In Need of Urgent Help">
<PlanGrid plans={PLANS} />
<OfferingGrid columns="md:grid-cols-2 lg:grid-cols-3">
{PLANS.map((plan) => (
<Offering key={plan.title} {...plan} />
))}
</OfferingGrid>
</Section>
);
}
5 changes: 3 additions & 2 deletions website-next/app/(content)/services/advisory/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next";

import { Offering } from "@/src/components/Offering";
import { OfferingGrid } from "@/src/components/OfferingGrid";
import { PageHero } from "@/src/components/PageHero";

export const metadata: Metadata = {
Expand Down Expand Up @@ -50,7 +51,7 @@ export default function AdvisoryPage() {
teaser="At ChilliCream, we want you to be successful. From guidance to embedded experts, find the right level for your business."
/>
<section className="py-8">
<div className="grid gap-6 md:grid-cols-2">
<OfferingGrid columns="md:grid-cols-2">
{PLANS.map((plan) => (
<Offering
key={plan.title}
Expand All @@ -61,7 +62,7 @@ export default function AdvisoryPage() {
callToAction={{ title: plan.ctaText, link: plan.ctaLink }}
/>
))}
</div>
</OfferingGrid>
</section>
</>
);
Expand Down
56 changes: 34 additions & 22 deletions website-next/app/(content)/services/support/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next";

import { type Plan, PlanGrid } from "@/src/components/PlanGrid";
import { Offering } from "@/src/components/Offering";
import { OfferingGrid } from "@/src/components/OfferingGrid";
import { PageHero } from "@/src/components/PageHero";
import { Section } from "@/src/components/Section";
import {
Expand All @@ -19,55 +20,62 @@ export const metadata: Metadata = {
"Get GraphQL support from ChilliCream experts: plans from a free community Slack to enterprise SLAs with dedicated account managers and phone support.",
};

const SUPPORT_PLANS: Plan[] = [
const SUPPORT_PLANS = [
{
title: "Community",
price: 0,
period: "month",
price: "Free",
description: "For personal or non-commercial projects, to start hacking.",
features: ["Public Slack Channel"],
ctaText: "Join Slack",
ctaLink: "https://slack.chillicream.com/",
perks: ["Public Slack Channel"],
callToAction: {
title: "Join Slack",
link: "https://slack.chillicream.com/",
},
},
{
title: "Startup",
price: 450,
period: "month",
price: "$450",
priceNote: "per month",
description:
"For small teams with moderate bandwidth and projects of low to medium complexity.",
features: ["Private Slack Channel", "2 critical incidents"],
ctaText: "Contact Us",
ctaLink: "/services/support/contact?plan=Startup",
perks: ["Private Slack Channel", "2 critical incidents"],
callToAction: {
title: "Contact Us",
link: "/services/support/contact?plan=Startup",
},
},
{
title: "Business",
price: 1300,
period: "month",
price: "$1,300",
priceNote: "per month",
description: "For larger teams with business-critical projects.",
features: [
perks: [
"Private Slack Channel",
"5 critical incidents",
"2 non-critical incidents",
"Email support",
],
ctaText: "Contact Us",
ctaLink: "/services/support/contact?plan=Business",
callToAction: {
title: "Contact Us",
link: "/services/support/contact?plan=Business",
},
},
{
title: "Enterprise",
price: "custom",
price: "Custom",
description:
"For the whole organization, all your teams and business units, and with tailor made SLAs.",
features: [
perks: [
"Private Slack Channel",
"Unlimited critical incidents",
"10 non-critical incidents",
"Phone support",
"Dedicated account manager",
"Status reviews",
],
ctaText: "Contact Us",
ctaLink: "/services/support/contact?plan=Enterprise",
callToAction: {
title: "Contact Us",
link: "/services/support/contact?plan=Enterprise",
},
},
];

Expand Down Expand Up @@ -110,7 +118,11 @@ export default function SupportPage() {
/>

<Section title="Support Plans">
<PlanGrid plans={SUPPORT_PLANS} />
<OfferingGrid columns="md:grid-cols-2 lg:grid-cols-3">
{SUPPORT_PLANS.map((plan) => (
<Offering key={plan.title} {...plan} />
))}
</OfferingGrid>
</Section>

<Section title="Compare our Support Plans">
Expand Down
5 changes: 3 additions & 2 deletions website-next/app/(content)/services/training/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next";

import { Offering } from "@/src/components/Offering";
import { OfferingGrid } from "@/src/components/OfferingGrid";
import { PageHero } from "@/src/components/PageHero";
import { Section } from "@/src/components/Section";

Expand Down Expand Up @@ -51,7 +52,7 @@ export default function TrainingPage() {
teaser="At ChilliCream, we want you to be successful. We'll tell you how it is, and what you need to get there."
/>
<Section title="Corporate Offers">
<div className="grid gap-6 md:grid-cols-2">
<OfferingGrid columns="md:grid-cols-2">
{SERVICES.map((service) => (
<Offering
key={service.kind}
Expand All @@ -64,7 +65,7 @@ export default function TrainingPage() {
}}
/>
))}
</div>
</OfferingGrid>
</Section>
</>
);
Expand Down
5 changes: 4 additions & 1 deletion website-next/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
/* Disable default Tailwind colors */
--color-*: initial;

--color-cc-heading: #f5f0ea;
--color-cc-ink: #a1a3af;

/* The cc-* colors below are mirrored in src/theme/colors.ts for the OG share cards. */
--color-cc-ink: #f5f1ea;
/* --color-cc-ink: #f5f1ea; */
/* Long-form body prose: lighter than `cc-ink-dim` so paragraphs stay readable. */
--color-cc-prose: rgba(245, 241, 234, 0.8);
--color-cc-ink-dim: rgba(245, 241, 234, 0.62);
Expand Down
14 changes: 14 additions & 0 deletions website-next/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { FromOurBlog } from "@/src/components/FromOurBlog";
import { BuildYourWay } from "@/src/components/home/BuildYourWay";
import { FusionFlow } from "@/src/components/home/FusionFlow";
import { GrabADrink } from "@/src/components/home/GrabADrink";
import { HomeHero } from "@/src/components/home/HomeHero";
import { LogoCloud } from "@/src/components/home/LogoCloud";
import { NitroPricing } from "@/src/components/home/NitroPricing";
import { ProtocolCards } from "@/src/components/home/ProtocolCards";
import { StackDiagrams } from "@/src/components/home/StackDiagrams";

export default function Home() {
return (
<>
<HomeHero />
<LogoCloud />
<BuildYourWay />
<StackDiagrams />
<FusionFlow />
<ProtocolCards />
<NitroPricing />
<GrabADrink />
<div className="px-5 py-8 sm:px-12">
<div className="mx-auto flex max-w-6xl flex-col gap-12">
<FromOurBlog />
Expand Down
7 changes: 6 additions & 1 deletion website-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
"format": "prettier --write .",
"format:check": "prettier --check .",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
"build-storybook": "storybook build",
"build-storybook:test": "storybook build --quiet --output-dir storybook-static",
"test:visual": "yarn build-storybook:test && playwright test",
"test:visual:update": "yarn build-storybook:test && playwright test --update-snapshots"
},
"dependencies": {
"@chillicream/mocha-visualizer": "file:../src/Mocha/src/mocha-visualizer",
Expand Down Expand Up @@ -42,6 +45,7 @@
"styled-components": "^6.4.2"
},
"devDependencies": {
"@playwright/test": "1.60.0",
"@storybook/nextjs-vite": "^10.4.1",
"@tailwindcss/postcss": "^4",
"@tailwindcss/vite": "^4.3.0",
Expand All @@ -51,6 +55,7 @@
"eslint": "^9",
"eslint-config-next": "16.2.6",
"eslint-plugin-storybook": "10.4.1",
"http-server": "^14.1.1",
"playwright": "^1.60.0",
"prettier": "^3.8.3",
"prettier-plugin-tailwindcss": "^0.8.0",
Expand Down
49 changes: 49 additions & 0 deletions website-next/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { defineConfig, devices } from "@playwright/test";

// Dedicated port for the static build under test. Deliberately not 6006 so it
// never reuses a running `storybook dev` server, whose on-demand story index
// would make screenshots non-deterministic.
const PORT = 6166;
const STORYBOOK_URL = `http://127.0.0.1:${PORT}`;

/**
* Visual regression tests for Storybook stories.
*
* Baselines are rendered in a Linux + Chromium environment (the devcontainer,
* which mirrors CI). Generate and update them there, never from a host OS,
* otherwise font rendering will differ and every screenshot will diff.
*/
export default defineConfig({
testDir: "./tests/visual",
snapshotPathTemplate: "tests/visual/__screenshots__/{arg}{ext}",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
reporter: process.env.CI ? [["html", { open: "never" }], ["list"]] : "list",
expect: {
toHaveScreenshot: {
// Animations are frozen by Playwright; this absorbs minor anti-aliasing noise.
maxDiffPixelRatio: 0.01,
},
},
use: {
baseURL: STORYBOOK_URL,
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
webServer: {
// Serves the static Storybook. The build itself runs in the "test:visual"
// script beforehand, because Playwright enumerates the per-story tests by
// reading storybook-static/index.json at collection time (before webServer
// would otherwise run). During iteration you can pre-run a server on this
// port and it will be reused.
command: `yarn http-server storybook-static -p ${PORT} -s`,
url: `${STORYBOOK_URL}/index.json`,
reuseExistingServer: !process.env.CI,
timeout: 60_000,
},
});
6 changes: 3 additions & 3 deletions website-next/src/components/BlogTeaser.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ export const WithImage: Story = {
},
};

export const NoImage: Story = {
export const BrokenImage: Story = {
args: {
post: {
href: "/blog/2024/01/01/example",
title: "A post without a featured image still renders cleanly",
title: "A post whose featured image fails to load",
date: "2024-01-01",
featuredImage: null,
featuredImage: "https://example.com/does-not-exist.jpg",
author: "Jane Doe",
authorImageUrl: null,
},
Expand Down
Loading
Loading