diff --git a/.eslintrc.js b/.eslintrc.js
index 7162f468..22a4e4f5 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -82,6 +82,7 @@ module.exports = {
'postcss.config.js',
'codegen.ts',
'index-pages.mjs',
+ 'next-sitemap.config.js',
],
parserOptions: {
project: null,
diff --git a/.gitignore b/.gitignore
index 815c235a..3c011011 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,7 @@ yarn-error.log*
/build
/dist
.env.local
+
+# Sitemap
+public/sitemap*.xml
+
diff --git a/next-sitemap.config.js b/next-sitemap.config.js
new file mode 100644
index 00000000..fa238bb6
--- /dev/null
+++ b/next-sitemap.config.js
@@ -0,0 +1,10 @@
+/** @type {import('next-sitemap').IConfig} */
+module.exports = {
+ siteUrl: 'https://plural.sh',
+ transform: async (_config, path) => ({
+ loc: path,
+ changefreq: 'weekly',
+ priority: 0.5,
+ lastmod: new Date().toISOString(),
+ }),
+}
diff --git a/package.json b/package.json
index 55d93bee..0b84f334 100644
--- a/package.json
+++ b/package.json
@@ -7,8 +7,9 @@
"scripts": {
"dev": "run-s generate:pageindex dev:watch",
"dev:watch": "concurrently \"next dev\" \"yarn graphql:codegen:watch\"",
- "build": "run-s generate:pageindex build:next",
+ "build": "run-s generate:pageindex build:next postbuild",
"build:next": "next build",
+ "postbuild": "next-sitemap",
"start": "next start",
"lint": "run-p lint:format lint:js lint:css",
"lint:format": "prettier --check --no-error-on-unmatched-pattern ./{src,pages}/**/*.{js,jsx,ts,tsx,graphql,md,mdpart}",
@@ -61,6 +62,7 @@
"moment-timezone": "0.5.43",
"next": "13.4.12",
"next-compose-plugins": "2.2.1",
+ "next-sitemap": "4.2.3",
"next-transpile-modules": "10.0.0",
"octokit": "3.1.0",
"query-string": "8.1.0",
diff --git a/pages/index.tsx b/pages/index.tsx
index 962f81d7..47b50632 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -4,7 +4,6 @@ import { Button, CloseIcon } from '@pluralsh/design-system'
import { type InferGetStaticPropsType } from 'next'
import Link from 'next/link'
-import { until } from '@open-draft/until'
import { type Variants, motion } from 'framer-motion'
import styled from 'styled-components'
// @ts-expect-error
@@ -21,9 +20,6 @@ import { ImpactCardSection } from '@src/components/page-sections/ImpactCardSecti
import { QuoteSection } from '@src/components/page-sections/QuoteSection'
import { HomePageHero } from '@src/components/PageHeros'
import { CenteredSectionHead } from '@src/components/SectionHeads'
-import { getTinyRepos } from '@src/data/getRepos'
-import { getStacks } from '@src/data/getStacks'
-import { getStackTabData } from '@src/data/getStackTabData'
import {
PageHomepageDocument,
type PageHomepageQuery,
@@ -349,11 +345,6 @@ export const getStaticProps = async () => {
>({
query: PageHomepageDocument,
})
- const { data: repos, error: reposError } = await until(() => getTinyRepos())
- const { data: stacks, error: stacksError } = await until(() => getStacks())
-
- const buildStackTabs = getStackTabData({ repos, stacks })
-
const page = data.page_homepage
return propsWithGlobalSettings({
@@ -362,10 +353,8 @@ export const getStaticProps = async () => {
'Open-source application deployment, faster than ever without sacrificing compliance.',
articleCards: data.page_homepage?.article_cards || null,
quotes: normalizeQuotes(page?.quotes),
- featuredQuote: page?.featured_quote || null,
- buildStackTabs,
footerVariant: FooterVariant.kitchenSink,
- errors: combineErrors([error, stacksError, reposError]),
+ errors: combineErrors([error]),
})
}
diff --git a/pages/kubecon.tsx b/pages/kubecon.tsx
index fd9e4992..3a7958d4 100644
--- a/pages/kubecon.tsx
+++ b/pages/kubecon.tsx
@@ -87,10 +87,10 @@ export default function KubeCon() {
rel="noopener noreferrer"
target="_blank"
as={Link}
- href="/contact-sales"
+ href="https://calendly.com/sam-plural/30min"
className="mt-medium w-fit"
>
- Book a demo
+ Let's meet in person
@@ -149,9 +149,9 @@ export default function KubeCon() {
rel="noopener noreferrer"
target="_blank"
as={Link}
- href="/contact-sales"
+ href="https://calendly.com/sam-plural/30min"
>
- Book a demo
+ Let's meet in person
@@ -248,7 +248,7 @@ export default function KubeCon() {
-
+
Learn more
About Plural
diff --git a/pages/about/[keyword].tsx b/pages/kubernetes/[keyword].tsx
similarity index 96%
rename from pages/about/[keyword].tsx
rename to pages/kubernetes/[keyword].tsx
index 04753084..1f95c3bd 100644
--- a/pages/about/[keyword].tsx
+++ b/pages/kubernetes/[keyword].tsx
@@ -85,12 +85,11 @@ export const getStaticProps = async (context) => {
{
metaTitle: 'Plural',
metaDescription: page.slug,
- footerVariant: FooterVariant.none,
- hideHeader: true,
+ footerVariant: FooterVariant.kitchenSink,
components: page.components ?? [],
},
{
- revalidate: 20,
+ revalidate: 60,
}
)
}
diff --git a/pages/marketplace.tsx b/pages/marketplace.tsx
deleted file mode 100644
index 4560f231..00000000
--- a/pages/marketplace.tsx
+++ /dev/null
@@ -1,618 +0,0 @@
-import {
- type ComponentProps,
- useCallback,
- useMemo,
- useRef,
- useState,
-} from 'react'
-
-import {
- Button,
- Card,
- type CardProps,
- Chip,
- TabPanel,
-} from '@pluralsh/design-system'
-import { type GetStaticProps, type InferGetStaticPropsType } from 'next'
-
-import { until } from '@open-draft/until'
-import Fuse from 'fuse.js'
-import { isEmpty, orderBy, upperFirst } from 'lodash-es'
-import styled, { useTheme } from 'styled-components'
-
-import { directusClient } from '@src/apollo-client'
-import { mqs } from '@src/breakpoints'
-import { CardCta } from '@src/components/CardCta'
-import {
- type SetSearchParams,
- useSearchParams,
-} from '@src/components/hooks/useSearchParams'
-import { HeaderPad } from '@src/components/layout/HeaderPad'
-import { FullPageWidth } from '@src/components/layout/LayoutHelpers'
-import { TextLimiter } from '@src/components/layout/TextLimiter'
-import { FAQList } from '@src/components/page-sections/FAQList'
-import { MarketplaceCarousel } from '@src/components/page-sections/MarketplaceCarousel'
-import MarketplaceFilters from '@src/components/page-sections/MarketplaceFilters'
-import {
- MarketSearchTabKey,
- SearchBar,
- useSearchTabKey,
-} from '@src/components/page-sections/MarketplaceSearchBar'
-import StackHero from '@src/components/page-sections/MarketplaceStackHero'
-import { RepoCard, RepoCardList, StackCard } from '@src/components/RepoCardList'
-import { Body1, Heading1, Subtitle } from '@src/components/Typography'
-import { type BasicRepo, getRepos, reposCache } from '@src/data/getRepos'
-import {
- type Categories,
- type Tags,
- getSearchMetadata,
-} from '@src/data/getSearchMetadata'
-import { type MinStack, getStacks, stacksCache } from '@src/data/getStacks'
-import {
- type FaqItemFragment,
- FaqListDocument,
- type FaqListQuery,
- type FaqListQueryVariables,
-} from '@src/generated/graphqlDirectus'
-import { type BasicRepoFragment } from '@src/generated/graphqlPlural'
-import { combineErrors } from '@src/utils/combineErrors'
-import {
- type GlobalProps,
- propsWithGlobalSettings,
-} from '@src/utils/getGlobalProps'
-import { normalizeM2mItems } from '@src/utils/normalizeQuotes'
-
-type PageProps = {
- repositories: BasicRepo[]
- stacks: MinStack[]
- categories: Categories
- tags: Tags
- globalProps: GlobalProps
- faqs: (FaqItemFragment | null)[]
-}
-const reposSearchOptions = {
- keys: ['name', 'description', 'tags.tag'],
- threshold: 0.25,
-}
-const stacksSearchOptions = {
- keys: ['name', 'description', 'collections.bundles.recipe.repository.tag'],
- threshold: 0.25,
-}
-
-export const mqMarketTwoCol = mqs.xl
-
-export function getStackRepos(stack: MinStack) {
- return stack.collections?.[0]?.bundles
- ?.map((bundle) => bundle?.recipe?.repository)
- .filter(
- (repo: BasicRepoFragment | null | undefined): repo is BasicRepoFragment =>
- !!repo
- )
-}
-
-export const MarketplacePage = styled.div((_) => ({
- width: '100%',
- position: 'relative',
- marginBottom: 200,
-}))
-
-export const SearchBarArea = styled.div(({ theme }) => {
- const mB = theme.spacing.medium
-
- return {
- backgroundColor: theme.colors['fill-zero'],
- marginBottom: mB,
- zIndex: theme.zIndexes.base + 10,
- flexShrink: 0,
- '&::after': {
- content: '""',
- position: 'absolute',
- top: '100%',
- height: mB,
- width: '100%',
- background: `linear-gradient(0deg, transparent 0%, ${theme.colors['fill-zero']} 90%)`,
- },
- }
-})
-
-function FilterChip(props: ComponentProps) {
- return (
-
- )
-}
-
-const ContentContainer = styled.div<{ $reverse?: boolean }>(
- ({ theme, $reverse }) => ({
- display: 'flex',
- flexDirection: 'column',
- [mqMarketTwoCol]: {
- flexDirection: $reverse ? 'row-reverse' : 'row',
- columnGap: theme.spacing.xlarge,
- },
- [mqs.xxl]: {
- columnGap: theme.spacing.xxlarge,
- },
- })
-)
-
-const MainContent = styled.div(({ theme: _ }) => ({
- flexGrow: '1',
- // minWidth must be set to prevent expanding beyond available width
- minWidth: 200,
-}))
-
-const Sidecar = styled.div(({ theme }) => ({
- display: 'none',
- [mqMarketTwoCol]: {
- display: 'block',
- width: 248,
- flexShrink: 0,
- flexDirection: 'row',
- columnGap: theme.spacing.xlarge,
- },
-}))
-
-const SidecarFilters = styled(MarketplaceFilters)(({ theme }) => ({
- [mqMarketTwoCol]: {
- maxHeight: `calc(100vh - var(--top-nav-height) - ${theme.spacing.medium}px)`,
- 'maxHeight ': `calc(100dvh - var(--top-nav-height) - ${theme.spacing.medium}px)`,
- position: 'sticky',
- top: 'var(--top-nav-height)',
- },
-}))
-
-function FilterChips({
- categories,
- handleClearToken,
- tags,
- handleClearTokens,
- ...props
-}: {
- categories: string[]
- handleClearToken: (key: any, value: any) => void
- tags: string[]
- handleClearTokens: () => void
-} & ComponentProps<'div'>) {
- return (
-
- {categories.map((category) => (
- handleClearToken('category', category)}
- onKeyDown={(event) =>
- (event.key === 'Enter' || event.key === ' ') &&
- handleClearToken('category', category)
- }
- >
- {upperFirst(category)}
-
- ))}
- {tags.map((tag) => (
- handleClearToken('tag', tag)}
- onKeyDown={(event) =>
- (event.key === 'Enter' || event.key === ' ') &&
- handleClearToken('tag', tag)
- }
- >
- {tag}
-
- ))}
- handleClearTokens()}
- >
- Clear all
-
-
- )
-}
-
-export function clearToken({
- key,
- value,
- setSearchParams,
-}: {
- key: string
- value: string
- setSearchParams: SetSearchParams
-}) {
- setSearchParams((params) => {
- const newParams = params
- .getAll(key)
- .filter((v) => v.toLowerCase() !== value.toLowerCase())
-
- params.delete(key)
- newParams.forEach((p) => params.append(key, p))
-
- return params
- })
-}
-
-const SidecarCardTitle = styled.h5(({ theme }) => ({
- ...theme.partials.marketingText.body2Bold,
-}))
-
-export default function Marketplace({
- ...props
-}: InferGetStaticPropsType) {
- const [searchParams, setSearchParams] = useSearchParams()
- const categories = searchParams.getAll('category')
- const tags = searchParams.getAll('tag')
- const [search, setSearch] = useState('')
- const isFiltered = !isEmpty(categories) || !isEmpty(tags)
- const searchTabStateRef = useRef()
- const [searchTabKey] = useSearchTabKey()
- const searchTopRef = useRef()
- const isFilteredOrSearched = isFiltered || search
-
- const handleClearToken = useCallback(
- (key, value) => {
- clearToken({ key, value, setSearchParams })
- },
- [setSearchParams]
- )
-
- const handleClearTokens = useCallback(() => {
- setSearchParams({})
- }, [setSearchParams])
-
- const { repositories, stacks } = props
- const filteredStacks = useMemo(
- () =>
- stacks
- .filter((stack) =>
- !isEmpty(categories)
- ? categories.some(
- (category) =>
- stack.name.toLowerCase() === category.toLowerCase() ||
- getStackRepos(stack)?.some(
- (repo) =>
- repo.category?.toLowerCase() === category.toLowerCase()
- )
- )
- : true
- )
- .filter((stack) =>
- !isEmpty(tags)
- ? tags.some(
- (tag) =>
- stack.name.toLowerCase() === tag.toLowerCase() ||
- getStackRepos(stack)?.some(
- (repo) =>
- repo.name.toLowerCase() === tag.toLowerCase() ||
- repo?.tags?.some(
- (t) => t?.tag?.toLowerCase() === tag.toLowerCase()
- )
- )
- )
- : true
- ),
- [categories, stacks, tags]
- )
- const stacksFuse = useMemo(
- () => new Fuse(filteredStacks, stacksSearchOptions),
- [filteredStacks]
- )
-
- const resultStacks = useMemo(
- () =>
- search
- ? (orderBy(
- stacksFuse.search(search).map(({ item }) => item),
- [
- 'trending',
- (r) => (r as (typeof stacks)[number])?.name.toLowerCase(),
- ],
- ['desc', 'asc']
- ) as typeof stacks)
- : filteredStacks,
- [filteredStacks, search, stacksFuse]
- )
-
- const sortedRepositories = useMemo(
- () =>
- orderBy(
- repositories,
- [
- 'trending',
- (r) => (r as (typeof repositories)[number])?.name?.toLowerCase(),
- ],
- ['desc', 'asc']
- ) as typeof repositories,
- [repositories]
- )
- const filteredRepositories = useMemo(
- () =>
- sortedRepositories
- .filter((repository) =>
- categories.length
- ? categories.some(
- (category) =>
- category === repository?.category?.toLowerCase() ||
- (category === 'trending' && repository.trending)
- )
- : true
- )
- .filter((repository) => {
- if (!tags.length) return true
-
- const repositoryTags = repository?.tags?.map((t) =>
- t?.tag.toLowerCase()
- )
-
- return tags.some((tag) => repositoryTags?.includes(tag))
- }),
- [categories, sortedRepositories, tags]
- )
-
- const reposFuse = useMemo(
- () => new Fuse(filteredRepositories, reposSearchOptions),
- [filteredRepositories]
- )
-
- const resultRepositories = useMemo(
- () =>
- search
- ? (orderBy(
- reposFuse.search(search).map(({ item }) => item),
- [
- 'trending',
- (r) => (r as (typeof repositories)[number])?.name.toLowerCase(),
- ],
- ['desc', 'asc']
- ) as typeof repositories)
- : filteredRepositories,
- [reposFuse, search, filteredRepositories]
- )
-
- const filterProps = {
- categories: props.categories,
- tags: props.tags,
- }
-
- return (
-
-
-
-
- Explore the open-source marketplace
-
-
-
- Discover over 90 incredible applications ready to deploy in your
- cloud in minutes using our guided deployment flow. With security,
- observability, and scale out of the box, we elevate you from the
- work of building and maintaining your open-source infrastructure
- and let teams focus on delivering value.
-
-
-
-
-
-
-
- {isFiltered && (
-
- )}
-
-
- {!isFilteredOrSearched &&
- searchTabKey === MarketSearchTabKey.all && (
-
-
- Plural curated stacks
-
-
- {stacks.map((stack) =>
- stack ? (
-
- ) : null
- )}
-
-
- )}
- {(searchTabKey === MarketSearchTabKey.all ||
- searchTabKey === MarketSearchTabKey.apps) && (
- <>
-
- {!isFiltered && !search ? <>All apps> : <>Results>}
-
-
- {isFilteredOrSearched &&
- resultStacks.map((stack) => (
-
- ))}
- {resultRepositories.map((repository) => (
-
- ))}
-
- >
- )}
- {searchTabKey === MarketSearchTabKey.stacks && (
- <>
-
- Plural curated stacks
-
-
- {stacks.map((stack) => (
-
- ))}
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Don’t see what you’re looking for?
-
-
-
-
-
-
-
- )
-}
-
-function AddAppCard() {
- return (
-
-
- Add an application
-
-
- Is something missing from the Plural marketplace? Are you a vendor who
- wants to add your solution? We'd love for you to onboard your
- application.
-
-
- Read the guide
-
-
- )
-}
-
-function ContributorCard() {
- return (
-
-
- Join our contributor program
-
-
- Add a new application to the Plural catalog or take a deep dive into the
- Plural internals.
-
-
- Learn more
-
-
- )
-}
-
-function SidecarCard({
- variant,
- ...props
-}: CardProps & { variant?: 'fill-one' | 'feature' }) {
- const theme = useTheme()
-
- return (
-
- )
-}
-
-const PBody2 = styled.p(({ theme }) => ({
- ...theme.partials.text.body2,
- color: theme.colors['text-light'],
-}))
-
-export const getStaticProps: GetStaticProps = async () => {
- const { data: repos, error: reposError } = await until(() => getRepos())
- const { data: stacks, error: stacksError } = await until(() => getStacks())
- const { data: faqData, error: faqError } = await directusClient.query<
- FaqListQuery,
- FaqListQueryVariables
- >({
- query: FaqListDocument,
- variables: { slug: 'marketplace' },
- })
-
- const { categories, tags } = await getSearchMetadata()
-
- return propsWithGlobalSettings({
- metaTitle: 'Explore the open-source marketplace',
- metaDescription:
- 'Discover over 90 open-source applications ready to deploy in your cloud in minutes.',
- repositories: repos || reposCache.filtered,
- stacks: stacks || stacksCache.filtered,
- tags: tags || [],
- categories: categories || [],
- faqs: normalizeM2mItems(faqData.collapsible_lists?.[0]) || [],
- errors: combineErrors([reposError, stacksError, faqError]),
- })
-}
diff --git a/pages/pricing.tsx b/pages/pricing.tsx
index 98a76546..25e32ea3 100644
--- a/pages/pricing.tsx
+++ b/pages/pricing.tsx
@@ -82,10 +82,7 @@ export default function Pricing({
}
/>
-
+
diff --git a/pages/sitemap.xml.ts b/pages/sitemap.xml.ts
deleted file mode 100644
index 7635de1e..00000000
--- a/pages/sitemap.xml.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { until } from '@open-draft/until'
-
-import { appUrl, stackUrl } from '@src/consts/routes'
-import { getRepos } from '@src/data/getRepos'
-import { getStacks } from '@src/data/getStacks'
-
-import pages from '../src/generated/pages.json'
-
-const S_MAXAGE = 1 * 60 * 60 // 1s * 60s/m * 60m/h = 1 hour
-const STALE_WHILE_REVALIDATE = S_MAXAGE * 2
-
-function urlTag({
- location,
- lastMod,
- priority = '0.5',
-}: {
- location: string
- lastMod: string
- priority?: string | number
-}) {
- return `
- ${process.env.NEXT_PUBLIC_ROOT_URL}${location}
- ${lastMod}
- weekly
- ${priority || '0.5'}
- `
-}
-
-function wrapSiteMap(content: string) {
- return `
-
-${content}
-
-`
-}
-
-export default function SiteMap() {
- // getServerSideProps will do the heavy lifting
-}
-
-function generateSiteMap({
- repos,
- stacks,
-}: {
- repos?: Awaited
>
- stacks?: Awaited>
-} = {}) {
- const lastMod = new Date().toISOString()
-
- // We generate the XML sitemap with the posts data
- const sitemap = wrapSiteMap(
- `${pages
- ?.map((page) => urlTag({ location: `${page.path}`, lastMod }))
- .join('\n')}
-${stacks
- ?.map((stack) => urlTag({ location: stackUrl(stack.name), lastMod }))
- .join('\n')}
-${repos
- ?.map((repo) => urlTag({ location: appUrl(repo.name), lastMod }))
- .join('\n')}`
- )
-
- return sitemap
-}
-
-let cachedSiteMap = generateSiteMap()
-
-export async function getServerSideProps({ res }) {
- // We make an API call to gather the URLs for our site
- const { data: repos, error: reposError } = await until(() => getRepos())
- const { data: stacks, error: stacksError } = await until(() => getStacks())
-
- let sitemap: string = cachedSiteMap
-
- if (!reposError && !stacksError) {
- sitemap = await generateSiteMap({ repos, stacks })
- cachedSiteMap = sitemap
- }
-
- res.setHeader('Content-Type', 'text/xml')
- res.setHeader(
- 'Cache-Control',
- `public, s-maxage=${S_MAXAGE}, stale-while-revalidate=${STALE_WHILE_REVALIDATE}`
- )
- // we send the XML to the browser
- res.write(sitemap)
- res.end()
-
- return {
- props: {},
- }
-}
diff --git a/pages/solutions/[solution].tsx b/pages/solutions/[solution].tsx
index b49e27f0..48ae8abe 100644
--- a/pages/solutions/[solution].tsx
+++ b/pages/solutions/[solution].tsx
@@ -1,13 +1,11 @@
import { Button, ColorModeProvider } from '@pluralsh/design-system'
import {
type GetStaticPaths,
- type GetStaticProps,
+ type GetStaticPropsContext,
type InferGetStaticPropsType,
} from 'next'
import Link from 'next/link'
-import { until } from '@open-draft/until'
-
import { directusClient } from '@src/apollo-client'
import { FooterVariant } from '@src/components/FooterFull'
import { StandardPageSection } from '@src/components/layout/LayoutHelpers'
@@ -15,11 +13,7 @@ import SolutionDownloadSection from '@src/components/page-sections/SolutionDownl
import SolutionFeatureSection from '@src/components/page-sections/SolutionFeatureSection'
import { BasicPageHero } from '@src/components/PageHeros'
import SolutionProblem from '@src/components/SolutionProblem'
-import { getTinyRepos } from '@src/data/getRepos'
-import { getStacks } from '@src/data/getStacks'
-import { getStackTabData } from '@src/data/getStackTabData'
import {
- type SolutionFragment,
SolutionsDocument,
type SolutionsQuery,
type SolutionsQueryVariables,
@@ -28,10 +22,7 @@ import {
type SolutionsSlugsQueryVariables,
} from '@src/generated/graphqlDirectus'
import { combineErrors } from '@src/utils/combineErrors'
-import {
- type GlobalProps,
- propsWithGlobalSettings,
-} from '@src/utils/getGlobalProps'
+import { propsWithGlobalSettings } from '@src/utils/getGlobalProps'
import { GradientBG } from '../../src/components/layout/GradientBG'
import { HeaderPad } from '../../src/components/layout/HeaderPad'
@@ -67,16 +58,18 @@ export default function Solution({
>
Book a demo
-
- Download full e-book
-
+ {solution.ebook_url && (
+
+ Download full e-book
+
+ )}
}
/>
@@ -102,7 +95,6 @@ export default function Solution({
-
{
}
}
-export type AppPageProps = {
- solution: SolutionFragment
- globalProps: GlobalProps
- buildStackTabs?: ReturnType
-}
-
-export const getStaticProps: GetStaticProps = async (context) => {
+export const getStaticProps = async (context: GetStaticPropsContext) => {
const slug =
typeof context?.params?.solution === 'string'
? context?.params?.solution
@@ -176,17 +162,11 @@ export const getStaticProps: GetStaticProps = async (context) => {
return { notFound: true }
}
- const { data: repos, error: reposError } = await until(() => getTinyRepos())
- const { data: stacks, error: stacksError } = await until(() => getStacks())
-
- const buildStackTabs = getStackTabData({ repos, stacks })
-
return propsWithGlobalSettings({
solution,
- metaTitle: `Solution${solution.title ? ` – ${solution.title}` : ''}`,
+ metaTitle: `Solution${solution.title ? ` - ${solution.title}` : ''}`,
metaDescription: solution.description || null,
- buildStackTabs,
footerVariant: FooterVariant.kitchenSink,
- errors: combineErrors([solutionError, reposError, stacksError]),
+ errors: combineErrors([solutionError]),
})
}
diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx
index 1e9f5c53..b7df1738 100644
--- a/src/components/PageHeader.tsx
+++ b/src/components/PageHeader.tsx
@@ -24,7 +24,6 @@ import { FullPageWidth } from './layout/LayoutHelpers'
import { NavigationDesktop } from './NavigationDesktop'
import { NavigationMobile } from './NavigationMobile'
import { HamburgerButton } from './PageHeaderButtons'
-import { PromoBanner, type PromoBannerProps } from './PromoBanner'
const DARKEN_FILTER_ID = 'svg-darken-filter'
@@ -36,11 +35,10 @@ export const PAGE_HEADER_ID = 'plural-page-header'
export function PageHeader({
showHeaderBG,
- promoBanner,
+
...props
}: {
showHeaderBG?: boolean
- promoBanner?: PromoBannerProps
}) {
const theme = useTheme()
const [menuIsOpen, setMenuIsOpen] = useState(false)
@@ -71,7 +69,6 @@ export function PageHeader({
alwaysShowBG={showHeaderBG}
id={PAGE_HEADER_ID}
>
-
- path.startsWith(p)
- )
- ) {
- return 'og_image_marketplace.png'
- }
- if (['/community'].some((p) => path.startsWith(p))) {
- return 'og_image_community.png'
- }
-
- return 'og_image.png'
-}
-
export const GlobalPropsContext = createContext(
undefined
)
@@ -46,8 +27,7 @@ export default function PrimaryPage({
}) {
const { metaTitle, metaTitleFull, metaDescription } = pageProps || {}
const { siteSettings } = globalProps || {}
- const router = useRouter()
- const ogImage = selectOgImage(router)
+
const headProps = {
title:
metaTitleFull ||
@@ -55,7 +35,7 @@ export default function PrimaryPage({
? `${PAGE_TITLE_PREFIX}${metaTitle}${PAGE_TITLE_SUFFIX}`
: ROOT_TITLE),
description: metaDescription || siteSettings?.og_description || '',
- ...(ogImage ? { ogImage } : {}),
+ ogImage: siteSettings.og_image,
}
const navData = Object.values(siteSettings?.main_nav ?? []) as NavList[]
@@ -66,13 +46,7 @@ export default function PrimaryPage({
{!pageProps.hideHeader && (
-
+
)}
{children}
diff --git a/src/components/PromoBanner.tsx b/src/components/PromoBanner.tsx
deleted file mode 100644
index aa873c12..00000000
--- a/src/components/PromoBanner.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-import { type ComponentProps, useEffect, useState } from 'react'
-
-import { ArrowRightIcon, isExternalUrl } from '@pluralsh/design-system'
-import Link from 'next/link'
-
-import { type Maybe } from 'graphql/jsutils/Maybe'
-import styled, { createGlobalStyle } from 'styled-components'
-import { type Merge } from 'type-fest'
-
-import { mqs } from '@src/breakpoints'
-
-import BasicMarkdown from './BasicMarkdown'
-
-export type PromoBannerProps = { content?: Maybe; url?: Maybe }
-
-const PromoBannerSC = styled.div(({ theme }) => ({
- ...theme.partials.marketingText.body2,
- backgroundColor: theme.colors.blue[500],
- display: 'flex',
- position: 'relative',
- gap: theme.spacing.large,
- height: 'var(--top-nav-banner-height)',
- overflow: 'hidden',
- transition: 'height 0.2s ease',
-}))
-
-const PromoBannerLink = styled.div(({ theme }) => ({
- position: 'absolute',
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- textAlign: 'center',
- color: 'white',
- paddingLeft: theme.spacing.xxlarge,
- paddingRight: theme.spacing.xxlarge,
- [`&:hover ${ArrowSC}`]: {
- transform: 'translateX(50%)',
- },
-}))
-
-const ArrowSC = styled.div(({ theme }) => ({
- position: 'relative',
- top: 1,
- display: 'inline-block',
- color: 'white',
- marginLeft: theme.spacing.medium,
- transition: 'transform 0.2s ease',
-}))
-
-// const CloseButtonSC = styled.div(({ theme }) => ({
-// ...theme.partials.marketingText.body2,
-// zIndex: 1,
-// position: 'absolute',
-// top: 0,
-// right: 0,
-// width: theme.spacing.xlarge,
-// height: theme.spacing.xlarge,
-// display: 'flex',
-// alignItems: 'center',
-// justifyContent: 'center',
-// cursor: 'pointer',
-// color: 'white',
-// }))
-
-const GlobalStyle = createGlobalStyle<{ $isOpen: boolean }>(
- ({ $isOpen, theme }) => {
- if (!$isOpen) {
- return {}
- }
-
- return {
- ':root': {
- '--top-nav-banner-height': `${theme.spacing.medium + 25.6 * 4}px`,
- },
- [mqs.xs]: {
- ':root': {
- '--top-nav-banner-height': `${theme.spacing.medium + 25.6 * 3}px`,
- },
- },
- [mqs.sm]: {
- ':root': {
- '--top-nav-banner-height': `${theme.spacing.medium + 25.6 * 2}px`,
- },
- },
- [mqs.lg]: {
- ':root': {
- '--top-nav-banner-height': `${theme.spacing.medium + 25.6 * 1}px`,
- },
- },
- }
- }
-)
-
-export function PromoBanner({
- content,
- url,
- ...props
-}: Merge, PromoBannerProps>) {
- const [isOpen, setIsOpen] = useState(true)
-
- useEffect(() => {
- const listener = (e) => {
- const scrolled = window.scrollY !== 0
-
- if (e.currentTarget.scroll) {
- setIsOpen(!scrolled)
- }
- }
- const scrolled = window.scrollY !== 0
-
- setIsOpen(!scrolled)
-
- window.addEventListener('scroll', listener, { passive: true })
-
- return () => {
- window.removeEventListener('scroll', listener)
- }
- }, [])
-
- if (!content) {
- return null
- }
- const linkProps = {
- ...(url
- ? {
- as: Link,
- href: url,
- ...(isExternalUrl(url) ? { target: '_blank' } : {}),
- }
- : { as: 'div' }),
- }
-
- return (
- <>
-
-
- {/* @ts-expect-error */}
-
-
-
-
-
-
- {/* setIsOpen(false)}>
-
- */}
-
- >
- )
-}
diff --git a/src/components/RepoCardList.tsx b/src/components/RepoCardList.tsx
deleted file mode 100644
index 28506418..00000000
--- a/src/components/RepoCardList.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-import {
- Children,
- type ReactNode,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react'
-
-import {
- EmptyState,
- StackCard as PluralStackCard,
- RepositoryCard,
- usePrevious,
-} from '@pluralsh/design-system'
-import Link from 'next/link'
-
-import { drop, isEmpty } from 'lodash-es'
-
-import { getStackRepos } from '@pages/marketplace'
-import { breakpointIsGreaterOrEqual } from '@src/breakpoints'
-import { appUrl, stackUrl } from '@src/consts/routes'
-import { type BasicRepo, fakeDisplayName } from '@src/data/getRepos'
-import { type MinStack } from '@src/data/getStacks'
-
-import { useBreakpoint } from './contexts/BreakpointProvider'
-import { ResponsivePageNavigation } from './ResponsivePageNavigation'
-
-function getPaginatedItems(items: T[], pageIndex = 0, pageSize = 24) {
- const offset = pageIndex * pageSize
- const pageItems = drop(items, offset).slice(0, pageSize)
-
- return {
- pageIndex,
- pageSize,
- total: items.length,
- totalPages: Math.ceil(items.length / pageSize),
- pageItems,
- }
-}
-
-export function RepoCardList({
- children,
- pageSize = 24,
-}: {
- children: ReactNode
- pageSize?: number
-}) {
- const [cPI, setCurPageIndex] = useState(0)
- const curPageIndex = cPI ?? 0
- const lastPageIndex = usePrevious(curPageIndex) ?? 0
- const childArray = useMemo(() => Children.toArray(children), [children])
- const { pageItems, totalPages } = useMemo(
- () => getPaginatedItems(childArray, curPageIndex, pageSize),
- [curPageIndex, pageSize, childArray]
- )
- const searchTopRef = useRef(null)
- const breakpoint = useBreakpoint()
-
- const scrollOffset = breakpointIsGreaterOrEqual(breakpoint, 'md') ? 130 : 200
-
- useEffect(() => {
- if (curPageIndex === lastPageIndex) {
- return
- }
- const top = searchTopRef.current?.getBoundingClientRect()?.top
-
- if (top) {
- window.scrollTo({
- top: top + window.scrollY - scrollOffset,
- behavior: 'smooth',
- })
- }
- }, [curPageIndex, lastPageIndex, scrollOffset])
-
- useEffect(() => {
- setCurPageIndex(0)
- }, [childArray])
-
- return (
-
- {isEmpty(pageItems) ? (
-
- ) : (
-
- {pageItems}
-
- )}
-
-
- )
-}
-
-export function RepoCard({
- repository: repo,
- urlParams,
- wideFeatures = true,
- ...props
-}: {
- repository: BasicRepo
- urlParams?: string
- wideFeatures: boolean
-}) {
- const featuredLabel = repo.trending ? 'Trending' : undefined
-
- return (
- t?.tag || [])}
- priv={repo.private ?? undefined}
- verified={repo.verified ?? undefined}
- featuredLabel={featuredLabel}
- releaseStatus={repo.releaseStatus ?? undefined}
- size="small"
- {...props}
- />
- )
-}
-
-export function StackCard({
- stack,
- urlParams,
- ...props
-}: {
- stack: MinStack
- urlParams?: string
- wideFeatures: boolean
-}) {
- const apps = getStackRepos(stack)?.map((repo) => ({
- name: fakeDisplayName(repo.name),
- imageUrl: repo.darkIcon || repo.icon || '',
- }))
-
- return (
-
- )
-}
diff --git a/src/components/custom-page/CallToAction.tsx b/src/components/custom-page/CallToAction.tsx
index 23597193..25908771 100644
--- a/src/components/custom-page/CallToAction.tsx
+++ b/src/components/custom-page/CallToAction.tsx
@@ -19,7 +19,7 @@ export function CallToAction({
{heading}
diff --git a/src/components/custom-page/Cards.tsx b/src/components/custom-page/Cards.tsx
index 47ef4995..f80211ff 100644
--- a/src/components/custom-page/Cards.tsx
+++ b/src/components/custom-page/Cards.tsx
@@ -22,7 +22,15 @@ export function Cards({ spacing, cards }: CardsComponentFragment) {
'flex gap-xxlarge px-xxxlarge'
)}
>
- {cards?.map((c) => c?.card_id && )}
+ {cards?.map(
+ (c, i) =>
+ c?.card_id && (
+
+ )
+ )}
)
}
diff --git a/src/components/custom-page/CustomerQuote.tsx b/src/components/custom-page/CustomerQuote.tsx
index 643fdf4b..c4374b90 100644
--- a/src/components/custom-page/CustomerQuote.tsx
+++ b/src/components/custom-page/CustomerQuote.tsx
@@ -1,6 +1,7 @@
import { Flex } from '@pluralsh/design-system'
import { type CustomerQuoteComponentFragment } from '@src/generated/graphqlDirectus'
+import { cn } from '@src/utils/cn'
import { Body1, Subtitle2 } from '../Typography'
@@ -11,7 +12,7 @@ export function CustomerQuote({
quote,
}: CustomerQuoteComponentFragment) {
return (
-
+
(({ $size, $reverse = false, theme }) => ({
@@ -57,7 +57,7 @@ const ArticleCardSC = styled(ShadowedCard)<{
export function QuickstartDemoCard() {
return (
- ,
+ ComponentProps,
Pick<
- ArticleCardFragment,
+ MediaCardComponentFragment,
'heading' | 'url' | 'ctas' | 'videoUrl' | 'author' | 'date'
> & {
- thumbnail?: ArticleCardFragment['thumbnail'] | string
- description?: ArticleCardFragment['description'] | ReactNode
+ thumbnail?: MediaCardComponentFragment['thumbnail'] | string
+ description?: MediaCardComponentFragment['description'] | ReactNode
size?: 'medium' | 'small'
reverse?: boolean
preHeading?: string
@@ -115,7 +115,7 @@ export function ArticleCard({
})
return (
-
))}
-
+
)
}
-export const ArticleCardNoBorder = styled(ArticleCard)(() => ({
+export const MediaCardNoBorder = styled(MediaCard)(() => ({
border: 'none',
}))
diff --git a/src/components/custom-page/MultiColumnText.tsx b/src/components/custom-page/MultiColumnText.tsx
index e9229388..ee275740 100644
--- a/src/components/custom-page/MultiColumnText.tsx
+++ b/src/components/custom-page/MultiColumnText.tsx
@@ -51,7 +51,7 @@ export function MultiColumnText({
{columns?.map((c, index) => {
diff --git a/src/components/custom-page/SectionHeader.tsx b/src/components/custom-page/SectionHeader.tsx
index a85a0b77..4de1faf8 100644
--- a/src/components/custom-page/SectionHeader.tsx
+++ b/src/components/custom-page/SectionHeader.tsx
@@ -15,7 +15,7 @@ export function SectionHeader({
{overline && {overline} }
diff --git a/src/components/page-sections/CaseStudySection.tsx b/src/components/page-sections/CaseStudySection.tsx
deleted file mode 100644
index 550e2fcd..00000000
--- a/src/components/page-sections/CaseStudySection.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import Link from 'next/link'
-
-import { isEmpty } from 'lodash-es'
-
-import { Columns, EqualColumn } from '@src/components/layout/Columns'
-import { Body2, Cta, ResponsiveText } from '@src/components/Typography'
-import { appUrl, getImageUrl } from '@src/consts/routes'
-import { type TinyRepo } from '@src/data/getRepos'
-import { type CaseStudyFragment } from '@src/generated/graphqlDirectus'
-
-import { AppCard } from '../AppOrStackCard'
-import BasicMarkdown from '../BasicMarkdown'
-import { SubsectionHead } from '../SectionHeads'
-
-export function CaseStudySection({
- apps,
- featuredArticle,
-}: {
- apps: TinyRepo[]
- featuredArticle?: CaseStudyFragment | null | undefined
-}) {
- if (!featuredArticle) {
- return null
- }
- const heroUrl = getImageUrl(featuredArticle.hero_image)
-
- return (
-
-
-
-
-
-
- {!isEmpty(featuredArticle.ctas) && (
-
- {featuredArticle.ctas?.map(
- (cta, i) =>
- cta?.url && (
-
- {cta.label || 'Read full study'}
-
- )
- )}
-
- )}
-
-
-
- {heroUrl &&
}
-
- {!isEmpty(apps) && (
-
- {featuredArticle.stack_label && (
-
- {featuredArticle.stack_label}
-
- )}
-
- {apps.map((app) => (
-
- ))}
-
-
- )}
-
-
- )
-}
-
-export const getCaseStudyApps = (
- repos: TinyRepo[] | null | undefined,
- appList: string[]
-) => repos?.filter((repo) => appList.includes(repo.name)) || []
diff --git a/src/components/page-sections/CommunityCalloutsSection.tsx b/src/components/page-sections/CommunityCalloutsSection.tsx
deleted file mode 100644
index 503b9a6e..00000000
--- a/src/components/page-sections/CommunityCalloutsSection.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import { type ComponentProps } from 'react'
-
-import { Chip, FillLevelProvider } from '@pluralsh/design-system'
-
-import { isEmpty } from 'lodash-es'
-import styled from 'styled-components'
-
-import { mqs } from '@src/breakpoints'
-import { type Callouts } from '@src/data/getCommunityPageData'
-import { type CalloutFragment } from '@src/generated/graphqlDirectus'
-
-import { TextLimiter } from '../layout/TextLimiter'
-import { Cta } from '../Typography'
-
-const CalloutCardSC = styled.div(({ theme }) => ({
- background: theme.colors['fill-two'],
- border: theme.borders['fill-one'],
- borderRadius: theme.borderRadiuses.large,
- padding: theme.spacing.xlarge,
- display: 'flex',
- flexDirection: 'column',
- gap: theme.spacing.large,
- '.columns': {
- display: 'flex',
- alignItems: 'flex-start',
- flexDirection: 'column',
- rowGap: theme.spacing.medium,
- columnGap: theme.spacing.large,
- [mqs.md]: {
- flexDirection: 'row-reverse',
- },
- },
- '.mainColumn': {
- display: 'flex',
- flexDirection: 'column',
- rowGap: theme.spacing.xlarge,
- flexGrow: 1,
- },
- '.mainContent': {
- display: 'flex',
- flexDirection: 'column',
- rowGap: theme.spacing.small,
- },
- '.title': {
- ...theme.partials.marketingText.title1,
- },
- '.content': {
- ...theme.partials.marketingText.body2,
- color: theme.colors['text-xlight'],
- },
- '.ctas': {
- display: 'flex',
- flexDirection: 'column',
- gap: 0,
- },
-}))
-
-function CalloutCard({
- callout,
- ...props
-}: { callout: CalloutFragment } & ComponentProps) {
- return (
-
-
-
- {callout.category && (
-
- {callout.category}
-
- )}
-
-
- {callout.title && (
- {callout.title}
- )}
- {callout.content && (
- {callout.content}
- )}
-
-
- {!isEmpty(callout?.ctas) && (
-
- {callout?.ctas?.map(
- (cta, i) =>
- !!cta?.url && (
-
- {cta.label || cta.url}
-
- )
- )}
-
- )}
-
-
-
-
- )
-}
-
-export default function CalloutsSection({ callouts }: { callouts: Callouts }) {
- if (isEmpty(callouts)) {
- return null
- }
-
- return (
-
- {(callouts || []).map(
- (c) =>
- c && (
-
- )
- )}
-
- )
-}
diff --git a/src/components/page-sections/EventsSection.tsx b/src/components/page-sections/EventsSection.tsx
index dd852653..5898b409 100644
--- a/src/components/page-sections/EventsSection.tsx
+++ b/src/components/page-sections/EventsSection.tsx
@@ -144,17 +144,6 @@ function formatDates(
return dateString
}
-const FieldContent = styled.span(({ theme }) => ({
- '&:any-link': {
- ...theme.partials.text.inlineLink,
- textDecoration: 'none',
- // color: theme.colors['action-link-inline'],
- '&:hover': {
- textDecoration: 'underline',
- },
- },
-}))
-
const EventCardSC = styled.div(({ theme }) => ({
background: theme.colors['fill-one'],
border: theme.borders['fill-one'],
@@ -208,23 +197,7 @@ function EventCard({
{event.name}
-
- {dateString && {dateString} }
- {event?.fields?.map(
- (field: { url?: string; label?: string; content?: string }) => (
-
- {field.label && <>{field.label}: >}
-
- {field.content && field.content}
-
-
- )
- )}
-
+ {dateString && {dateString} }
{event.description && (
{event.description}
)}
diff --git a/src/components/page-sections/FeaturedContributorsSection.tsx b/src/components/page-sections/FeaturedContributorsSection.tsx
deleted file mode 100644
index eed6f623..00000000
--- a/src/components/page-sections/FeaturedContributorsSection.tsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import { type ComponentProps, cloneElement } from 'react'
-
-import { GitHubLogoIcon, TwitterIcon } from '@pluralsh/design-system'
-
-import { isEmpty } from 'lodash-es'
-import styled from 'styled-components'
-
-import { getImageUrl } from '@src/consts/routes'
-import { type FeaturedContributorFragment } from '@src/generated/graphqlDirectus'
-
-import LinkedInIcon from '../icons/LinkedInIcon'
-import { Cta, ResponsiveText } from '../Typography'
-
-const SocialLinkSC = styled.a(({ theme }) => ({
- padding: theme.spacing.xxsmall,
- borderRadius: theme.borderRadiuses.medium,
-}))
-
-function SocialLink({ icon, ...props }: any) {
- const iconClone = cloneElement(icon, { size: 16 })
-
- return (
-
- {iconClone}
-
- )
-}
-
-const FeaturedContributorCardSC = styled.div(({ theme }) => ({
- background: theme.colors['fill-one'],
- border: theme.borders['fill-one'],
- borderRadius: theme.borderRadiuses.large,
- padding: theme.spacing.large,
- display: 'flex',
- flexDirection: 'column',
- gap: theme.spacing.large,
- '.headerSection': {
- display: 'flex',
- alignItems: 'flex-start',
- gap: theme.spacing.large,
- },
- '.portrait': {
- width: theme.spacing.xxxxlarge,
- height: theme.spacing.xxxxlarge,
- borderRadius: '50%',
- overflow: 'hidden',
- backgroundSize: 'cover',
- backgroundPosition: '50% 50%',
- },
- '.name': {
- ...theme.partials.marketingText.title1,
- },
- '.title': {
- ...theme.partials.marketingText.label,
- marginTop: theme.spacing.xsmall,
- },
- '.socials': {
- ...theme.partials.marketingText.label,
- color: theme.colors['text-light'],
- display: 'flex',
- flexWrap: 'wrap',
- gap: theme.spacing.xxsmall,
- marginTop: theme.spacing.small,
- },
- '.content': {
- ...theme.partials.marketingText.body2,
- color: theme.colors['text-xlight'],
- },
- '.ctas': {
- display: 'flex',
- flexDirection: 'column',
- gap: 0,
- },
-}))
-
-function FeaturedContributorCard({
- contributor,
- ...props
-}: { contributor: FeaturedContributorFragment } & ComponentProps<
- typeof FeaturedContributorCardSC
->) {
- return (
-
-
-
-
-
-
{contributor.name}
-
{contributor.title}
-
- {contributor?.social_github_url && (
-
- }
- href={contributor.social_github_url}
- />
-
- )}
- {contributor?.social_twitter_url && (
-
- }
- href={contributor.social_twitter_url}
- />
-
- )}
- {contributor?.social_linkedin_url && (
-
- }
- href={contributor.social_linkedin_url}
- />
-
- )}
-
-
-
- {contributor.content && (
- {contributor.content}
- )}
- {!isEmpty(contributor?.ctas) && (
-
- {contributor?.ctas?.map(
- (cta, i) =>
- !!cta?.url && (
-
- {cta.label || cta.url}
-
- )
- )}
-
- )}
-
- )
-}
-
-export default function FeaturedContributorsSection({
- featuredContributors,
-}: {
- featuredContributors: FeaturedContributorFragment[]
-}) {
- if (!isEmpty(featuredContributors)) {
- return null
- }
-
- return (
-
-
- Featured Contributor{(featuredContributors || []).length > 1 && 's'}
-
-
- {featuredContributors.map((c) => (
-
- ))}
-
-
- )
-}
diff --git a/src/components/page-sections/MarketplaceCarousel.tsx b/src/components/page-sections/MarketplaceCarousel.tsx
deleted file mode 100644
index c0a30ad8..00000000
--- a/src/components/page-sections/MarketplaceCarousel.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import { Children, type ComponentProps, useState } from 'react'
-
-import { Button, CaretRightIcon } from '@pluralsh/design-system'
-import { type ButtonProps } from 'honorable'
-
-import { useVisuallyHidden } from 'react-aria'
-import styled, { useTheme } from 'styled-components'
-import { Autoplay } from 'swiper'
-import { Swiper, SwiperSlide } from 'swiper/react'
-import { type Swiper as SwiperT } from 'swiper/types'
-
-import { mqs } from '@src/breakpoints'
-
-import { CarouselDot, CarouselDotsWrapperSC } from '../CarouselDots'
-
-const switchPointMQ = mqs.sm
-
-const NavButton = styled(
- ({ direction, ...props }: { direction: 'left' | 'right' } & ButtonProps) => {
- const { visuallyHiddenProps } = useVisuallyHidden()
-
- return (
-
-
-
-
- {direction}
-
- )
- }
-)(({ direction }) => ({
- pointerEvents: 'auto',
- '&&': {
- width: 38,
- },
- '.icon': {
- display: 'flex',
- alignItems: 'center',
- transform: `scaleX(${direction === 'left' ? '-100%' : '100%'})`,
- },
-}))
-
-const InterfaceOverlay = styled.div(({ theme }) => ({
- position: 'absolute',
- top: theme.spacing.large,
- left: theme.spacing.large,
- bottom: theme.spacing.large,
- right: theme.spacing.large,
- pointerEvents: 'none',
- zIndex: 1,
-}))
-
-const Buttons = styled.div(({ theme }) => ({
- display: 'flex',
- width: '100%',
- height: '100%',
- alignItems: 'start',
- paddingTop: '208px',
- justifyContent: 'space-between',
- [switchPointMQ]: {
- paddingTop: 'unset',
- gap: theme.spacing.medium,
- justifyContent: 'end',
- alignItems: 'end',
- },
-}))
-
-const Dots = styled(CarouselDotsWrapperSC)((_) => ({
- display: 'flex',
- width: '100%',
- height: '100%',
- alignItems: 'end',
- justifyContent: 'center',
- [switchPointMQ]: {
- justifyContent: 'start',
- },
-}))
-
-export const MarketplaceCarousel = styled(
- ({ children, ...props }: ComponentProps<'div'>) => {
- const [activeIndex, setActiveIndex] = useState(0)
- const theme = useTheme()
- const [swiper, setSwiper] = useState(null)
-
- const dots = Children.map(children, (child, i) => (
- {
- swiper?.slideToLoop(i)
- }}
- $selected={i === activeIndex}
- />
- ))
-
- return (
-
-
- {
- setActiveIndex(s.realIndex)
- }}
- onSwiper={setSwiper}
- >
- {Children.map(children, (child, i) => (
- {child}
- ))}
-
-
-
- {dots}
-
- {
- swiper?.slidePrev()
- }}
- />
- {
- swiper?.slideNext()
- }}
- />
-
-
-
- )
- }
-)(({ theme: _ }) => ({
- position: 'relative',
-}))
diff --git a/src/components/page-sections/MarketplaceFilters.tsx b/src/components/page-sections/MarketplaceFilters.tsx
deleted file mode 100644
index be6dcbb8..00000000
--- a/src/components/page-sections/MarketplaceFilters.tsx
+++ /dev/null
@@ -1,259 +0,0 @@
-import { useCallback, useMemo, useState } from 'react'
-
-import { Card, Checkbox, CloseIcon, Input } from '@pluralsh/design-system'
-import { A } from 'honorable'
-
-import Fuse from 'fuse.js'
-import { capitalize } from 'lodash-es'
-import styled from 'styled-components'
-
-import { clearToken } from '@pages/marketplace'
-import { useSearchParams } from '@src/components/hooks/useSearchParams'
-import { Categories } from '@src/data/getSearchMetadata'
-import { type CategoryFragment } from '@src/generated/graphqlPlural'
-
-import { type AccordionProps, SingleAccordion } from '../SingleAccordion'
-
-function useParamToggle(key: string) {
- const [searchParams, setSearchParams] = useSearchParams()
-
- const isToggled = useCallback(
- (value: string) => searchParams.getAll(key).includes(value?.toLowerCase()),
- [key, searchParams]
- )
- const handleToggle = useCallback(
- (value) => {
- const existing = searchParams.getAll(key)
- const formattedValue = value.toLowerCase()
-
- if (existing.includes(formattedValue)) {
- clearToken({ key, value, setSearchParams })
- } else {
- setSearchParams((params) => {
- params.append(key, formattedValue)
-
- return params
- })
- }
- },
- [key, searchParams, setSearchParams]
- )
-
- return useMemo(
- () => ({
- isToggled,
- handleToggle,
- }),
- [handleToggle, isToggled]
- )
-}
-
-const FilterSection = styled.div(({ theme }) => ({
- paddingLeft: theme.spacing.xsmall,
- paddingRight: theme.spacing.xsmall,
- paddingBottom: theme.spacing.small,
- overflow: 'hidden',
-}))
-
-const CheckboxList = styled.div(({ theme }) => ({
- display: 'flex',
- flexDirection: 'column',
- rowGap: theme.spacing.xxsmall,
- '*': {
- tabIndex: -1,
- },
-}))
-
-const MarketplaceSidebarCheckbox = styled(
- ({ toggled, onClick, label, trapFocus, className }: any) => (
-
- {label}
-
- )
-)(({ theme }) => ({
- paddingBottom: theme.spacing.xsmall,
- paddingTop: theme.spacing.xsmall,
- paddingLeft: theme.spacing.xsmall,
- paddingRight: 0,
- // Temporary hack to prevent scrollbars when accordions are collapsed
- // Remove when design system Checkbox is updated
- position: 'relative',
-}))
-
-const searchOptions = {
- keys: ['tag'],
-}
-
-function Categories({ categories }: { categories: Categories }) {
- const { isToggled, handleToggle } = useParamToggle('category')
- const sortedCategories = useMemo(
- () => [
- { category: 'Trending' },
- ...categories
- .slice()
- .filter((cat): cat is CategoryFragment => !!cat?.category)
- .sort((a, b) =>
- !(a.category && b.category)
- ? 0
- : a?.category?.localeCompare(b?.category)
- ),
- ],
- [categories]
- )
-
- return (
-
- {(expanded) => (
-
-
- {sortedCategories.map(({ category }) =>
- category ? (
- handleToggle(category)}
- label={capitalize(category)}
- trapFocus={expanded}
- />
- ) : null
- )}
-
-
- )}
-
- )
-}
-
-const FilterAccordion = styled((props: AccordionProps) => (
-
-))(({ theme }) => ({
- borderBottom: theme.borders.default,
- '&:last-of-type': {
- borderBottom: 'none',
- },
-}))
-
-function Tags({ tags, fetchMore = () => {}, search, setSearch }) {
- const [nDisplayedTags, setNDisplayedTags] = useState(12)
- const { handleToggle, isToggled } = useParamToggle('tag')
- const sortedTags = tags.slice().sort((a, b) => a?.tag?.localeCompare(b?.tag))
- const fuse = new Fuse(sortedTags, searchOptions)
- const resultTags = search
- ? fuse.search(search).map(({ item }) => item)
- : sortedTags.filter((x, i) => i < nDisplayedTags)
-
- function handleMoreTagsClick() {
- if (tags.length > nDisplayedTags) setNDisplayedTags((x) => x + 12)
- else fetchMore()
- }
-
- function handleMoreTagsKeyDown(event) {
- if (event.key === 'Enter' || event.key === ' ') handleMoreTagsClick()
- }
-
- return (
-
- {(expanded) => (
-
- setSearch(event.target.value)}
- inputProps={{
- tabIndex: expanded ? 0 : -1,
- }}
- endIcon={
- search ? (
- setSearch('')}
- />
- ) : null
- }
- marginBottom="xsmall"
- />
-
- {resultTags.map(({ tag, count }) => (
- handleToggle(tag)}
- label={`${tag} (${count})`}
- trapFocus={expanded}
- />
- ))}
-
- {nDisplayedTags < tags.length && !search && (
-
- See More +
-
- )}
-
- )}
-
- )
-}
-
-const MarketplaceFilters = styled(MarketplaceFiltersUnstyled)(
- ({ theme: _ }) => ({
- display: 'flex',
- flexDirection: 'column',
- height: 'auto',
- overflowY: 'scroll',
- overflowX: 'auto',
- flexShrink: 0,
- })
-)
-
-function MarketplaceFiltersUnstyled({
- tags,
- categories,
- className,
-}: {
- tags: any[]
- categories: any[]
- className?: string
-}) {
- const [search, setSearch] = useState('')
- const filteredCategories = categories?.filter((c) => !!c.category)
-
- return (
-
-
-
-
- )
-}
-
-export default MarketplaceFilters
diff --git a/src/components/page-sections/MarketplaceSearchBar.tsx b/src/components/page-sections/MarketplaceSearchBar.tsx
deleted file mode 100644
index f66d395c..00000000
--- a/src/components/page-sections/MarketplaceSearchBar.tsx
+++ /dev/null
@@ -1,279 +0,0 @@
-import {
- type ComponentProps,
- type Dispatch,
- type MutableRefObject,
- type SetStateAction,
- forwardRef,
- useCallback,
- useEffect,
- useState,
-} from 'react'
-
-import {
- BrowseAppsIcon,
- Button,
- FiltersIcon,
- Input,
- SubTab,
- TabList,
-} from '@pluralsh/design-system'
-import { type ReadonlyURLSearchParams } from 'next/navigation'
-
-import { useDebounce } from 'rooks'
-import styled from 'styled-components'
-
-import { mqMarketTwoCol } from '@pages/marketplace'
-import { mqs } from '@src/breakpoints'
-import { BareModal } from '@src/components/BareModal'
-import { useSearchParams } from '@src/components/hooks/useSearchParams'
-
-import MarketplaceFilters from './MarketplaceFilters'
-
-const mqMoveTabs = mqs.md
-
-const SearchBarWrap = styled.div(({ theme }) => ({
- display: 'flex',
- gap: theme.spacing.small,
- backgroundColor: theme.colors['fill-zero'],
- marginBottom: theme.spacing.small,
- flexWrap: 'wrap',
- '& > *:first-child': { flexGrow: 1 },
- [mqs.xs]: {
- gap: theme.spacing.medium,
- },
- [mqMoveTabs]: {
- flexWrap: 'nowrap',
- },
- [mqs.lg]: {
- columnGap: theme.spacing.large,
- },
-}))
-
-export enum MarketSearchTabKey {
- all = 'all',
- stacks = 'stacks',
- apps = 'apps',
-}
-const tabs: {
- key: MarketSearchTabKey
- label: string
-}[] = [
- { key: MarketSearchTabKey.all, label: 'View all' },
- { key: MarketSearchTabKey.stacks, label: 'Stacks' },
- { key: MarketSearchTabKey.apps, label: 'Apps' },
-]
-
-export const TAB_PARAM = 'type'
-
-function hasValidTypeParam(
- searchParams: ReadonlyURLSearchParams | URLSearchParams
-) {
- return (
- !searchParams.has('type') ||
- tabs.slice(1).some((t) => t.key === searchParams.get('type'))
- )
-}
-
-export function useSearchTabKey(): [
- MarketSearchTabKey,
- (k: MarketSearchTabKey) => void,
-] {
- const [searchParams, setSearchParams] = useSearchParams()
-
- // If 'type' is 'all' or not a known tab key, delete 'type' search param as irrelevant
- useEffect(() => {
- if (!hasValidTypeParam(searchParams)) {
- setSearchParams((p) => {
- p.delete(TAB_PARAM)
-
- return p
- })
- }
- }, [searchParams, setSearchParams])
-
- const setTabKey = useCallback(
- (tabKey: MarketSearchTabKey) => {
- setSearchParams((p) => {
- if (!hasValidTypeParam(p)) {
- p.delete(TAB_PARAM)
- } else {
- p.set(TAB_PARAM, tabKey)
- }
-
- return p
- })
- },
- [setSearchParams]
- )
-
- return [
- (tabs.find(({ key }) => key === searchParams.get(TAB_PARAM)) || tabs[0])
- .key,
- setTabKey,
- ]
-}
-
-const MarketTabs = styled(({ ...props }: ComponentProps) => (
-
- {tabs.map(({ key, label }) => (
- {label}
- ))}
-
-))(({ theme: _ }) => ({
- order: 3,
- width: '100%',
- justifyContent: 'stretch',
- '& > *': {
- flexGrow: 1,
- textAlign: 'center',
- },
- [mqMoveTabs]: {
- width: 'auto',
- order: 'initial',
- },
-}))
-
-const MarketFilterBtn = styled(
- ({ ...props }: ComponentProps) => (
- }
- {...props}
- >
- Filter
-
- )
-)(({ theme }) => ({
- '& > span:first-child': {
- marginRight: `0 !important`,
- },
- width: '40px',
- '.text': {
- display: 'none',
- },
- [mqs.md]: {
- width: 'auto',
- '& > span:first-child': {
- marginRight: `${theme.spacing.small}px !important`,
- },
- '.text': {
- display: 'inline',
- },
- },
- [mqMarketTwoCol]: {
- '&&': {
- display: 'none',
- },
- },
-}))
-
-const ModalFilters = styled(MarketplaceFilters)(({ theme: _ }) => ({
- maxHeight: '100%',
- flexShrink: 1,
-}))
-
-const SearchBarLabel = styled.span(({ theme }) => ({
- display: 'none',
- [mqs.md]: {
- display: 'inline',
- marginLeft: theme.spacing.small,
- },
-}))
-
-const SearchTitleContent = styled.div(({ theme }) => ({
- display: 'flex',
- flexAlign: 'center',
- marginLeft: -theme.spacing.xxsmall,
- marginRight: -theme.spacing.xxsmall,
- [mqs.xs]: {
- marginLeft: 0,
- marginRight: 0,
- },
-}))
-
-const SearchInput = styled(
- forwardRef>((props, ref) => (
-
-
- Marketplace
-
- }
- showClearButton
- placeholder="Search"
- caption
- {...props}
- />
- ))
-)(({ theme }) => ({
- '& > *:first-child > *:last-child': {
- marginLeft: -theme.spacing.xxsmall,
- marginRight: -theme.spacing.xxxsmall,
- [mqs.xs]: {
- marginLeft: 0,
- marginRight: 0,
- },
- },
- '&&': {
- paddingRight: theme.spacing.xsmall,
- [mqs.xs]: {
- marginRight: 0,
- },
- },
-}))
-
-export function SearchBar({
- search: searchProp,
- setSearch: setSearchProp,
- filterProps,
- tabStateRef,
-}: {
- search: string
- filterProps: any
- setSearch: Dispatch>
- tabStateRef: MutableRefObject
-}) {
- const [search, setSearch] = useState(searchProp)
- const debouncedSetSearch = useDebounce(setSearchProp, 300)
- const [tabKey, setTabKey] = useSearchTabKey()
- const [filtersOpen, setFiltersOpen] = useState(false)
-
- const tabs = (
- setTabKey(key as MarketSearchTabKey),
- }}
- />
- )
-
- return (
-
- {
- setSearch(event.target.value)
- debouncedSetSearch(event.target.value)
- }}
- />
- {tabs}
- {
- setFiltersOpen(!filtersOpen)
- }}
- />
-
- setFiltersOpen(false)}
- closeButton
- >
-
-
-
- )
-}
diff --git a/src/components/page-sections/MarketplaceStackHero.tsx b/src/components/page-sections/MarketplaceStackHero.tsx
deleted file mode 100644
index 0b7b7b16..00000000
--- a/src/components/page-sections/MarketplaceStackHero.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import { Chip, StackIcon, useNavigationContext } from '@pluralsh/design-system'
-
-import styled from 'styled-components'
-
-import { mqs } from '@src/breakpoints'
-import { stackUrl } from '@src/consts/routes'
-import { type MinStack } from '@src/data/getStacks'
-
-import { CardCta } from '../CardCta'
-import { AppBody1, Heading1, TextLabel } from '../Typography'
-
-const knownStacks = new Set(['data', 'devops', 'security', 'observability'])
-
-const StackHeroSC = styled.div<{
- $bgPrefix: string
- $bgSuffix: string
-}>(({ theme, $bgPrefix, $bgSuffix }) => ({
- backgroundImage: `url(${$bgPrefix}-sm${$bgSuffix})`,
- backgroundSize: 'cover',
- backgroundPosition: 'center bottom',
- borderRadius: theme.borderRadiuses.large,
- border: theme.borders['fill-one'],
- overflow: 'hidden',
- display: 'flex',
- minHeight: '454px',
- '& > *': { flexShrink: 0 },
- '.contentWrap': {
- width: '100%',
- zIndex: 1,
- },
- [mqs.sm]: {
- backgroundImage: `url(${$bgPrefix}-md${$bgSuffix})`,
- backgroundPosition: 'right center',
- minHeight: '303px',
- },
- // [mqs.md]: {
- // backgroundImage: `url(${$bgPrefix}-lg${$bgSuffix})`,
- // backgroundPosition: 'center center',
- // },
- [mqs.lg]: {
- backgroundImage: `url(${$bgPrefix}-xl${$bgSuffix})`,
- backgroundPosition: 'right center',
- },
- // [mqs.xl]: {
- // backgroundImage: `url(${$bgPrefix}-lg${$bgSuffix})`,
- // backgroundPosition: 'center center',
- // },
- [mqs.max]: {
- backgroundImage: `url(${$bgPrefix}-xl${$bgSuffix})`,
- backgroundPosition: 'right center',
- },
- [`&:hover [data-card-cta]`]: {
- textDecoration: 'underline',
- },
-}))
-
-export default function StackHero({ stack }: { stack: MinStack }) {
- const imgSrcPart = knownStacks.has(stack.name) ? stack.name : 'data'
- const numApps = stack?.collections?.[0]?.bundles?.length
- const { Link } = useNavigationContext()
-
- return (
-
-
-
-
-
- {stack.displayName}
- {numApps ? {numApps} Apps : null}
-
-
- }
- >
- Stack
-
-
-
-
{stack.description}
-
- View stack
-
-
-
-
- )
-}
diff --git a/src/components/page-sections/PricingTable.tsx b/src/components/page-sections/PricingTable.tsx
index 8271e638..e1739415 100644
--- a/src/components/page-sections/PricingTable.tsx
+++ b/src/components/page-sections/PricingTable.tsx
@@ -2,9 +2,25 @@ import { Button, CheckIcon, CloseIcon } from '@pluralsh/design-system'
import styled from 'styled-components'
+import {
+ breakpointIsGreaterOrEqual,
+ breakpointIsLessThan,
+} from '@src/breakpoints'
+
+import { useBreakpoint } from '../contexts/BreakpointProvider'
+
export function PlanComparisonTableDesktop() {
+ const breakpoint = useBreakpoint()
+
+ if (!breakpointIsGreaterOrEqual(breakpoint, 'md')) {
+ return null
+ }
+
return (
-
+
@@ -39,8 +55,17 @@ export function PlanComparisonTableDesktop() {
)
}
export function PlanComparisonTablesMobile() {
+ const breakpoint = useBreakpoint()
+
+ if (!breakpointIsLessThan(breakpoint, 'md')) {
+ return null
+ }
+
return (
-
+
{plans.map((plan) => (
->['data']
-
-export type Callouts = (CalloutFragment | null)[] | null | undefined
-
-export async function getCommunityPageData() {
- const { data, error } = await client.query<
- PageCommunityQuery,
- PageCommunityQueryVariables
- >({
- query: PageCommunityDocument,
- })
-
- if (data?.page_community) {
- cache = data?.page_community
- }
-
- return { data: data?.page_community || cache, error }
-}
diff --git a/src/data/getFeaturedContributors.ts b/src/data/getFeaturedContributors.ts
deleted file mode 100644
index bd6b49f4..00000000
--- a/src/data/getFeaturedContributors.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { directusClient as client } from '@src/apollo-client'
-import {
- FeaturedContributorsDocument,
- type FeaturedContributorsQuery,
- type FeaturedContributorsQueryVariables,
-} from '@src/generated/graphqlDirectus'
-
-let cache: FeaturedContributorsQuery['featured_contributors'] | null = null
-
-export async function getFeaturedContributors() {
- const { data, error } = await client.query<
- FeaturedContributorsQuery,
- FeaturedContributorsQueryVariables
- >({
- query: FeaturedContributorsDocument,
- })
-
- if (data?.featured_contributors) {
- cache = data?.featured_contributors
- }
-
- return { data: data?.featured_contributors || cache, error }
-}
diff --git a/src/data/getSiteSettings.tsx b/src/data/getSiteSettings.tsx
index 8ac34f96..eb46a006 100644
--- a/src/data/getSiteSettings.tsx
+++ b/src/data/getSiteSettings.tsx
@@ -1,5 +1,9 @@
+import { getImageUrl } from '@src/consts/routes'
import { type NavList } from '@src/contexts/NavDataContext'
-import { type ProductPageTinyFragment } from '@src/generated/graphqlDirectus'
+import {
+ type ProductPageTinyFragment,
+ type SiteSettingsFragment,
+} from '@src/generated/graphqlDirectus'
type Solution = {
slug?: string | null
@@ -8,81 +12,12 @@ type Solution = {
}
export const getSiteSettings = (
+ siteSettings: SiteSettingsFragment,
solutions?: Solution[],
products?: ProductPageTinyFragment[]
) => ({
- og_description:
- 'Open-source application deployment, faster than ever without sacrificing compliance."',
- partner_logos: {
- items: [
- {
- item: {
- id: '1',
- logo_dark: '/images/partner-logos/logo-coachhub-dark.svg',
- logo_light: '/images/partner-logos/logo-coachhub-light.svg',
- name: 'CoachHub',
- slug: 'coachhub',
- url: 'https://www.coachhub.com/',
- width: 96,
- },
- },
- {
- item: {
- id: '2',
- logo_dark: '/images/partner-logos/logo-digitas-dark.png',
- logo_light: '/images/partner-logos/logo-digitas-light.png',
- name: 'Digitas',
- slug: 'digitas',
- url: 'https://www.digitas.com/',
- width: 60,
- },
- },
- {
- item: {
- id: '3',
- logo_dark: '/images/partner-logos/logo-fnatic-dark.svg',
- logo_light: '/images/partner-logos/logo-fnatic-light.svg',
- name: 'Fnatic',
- slug: 'fnatic',
- url: 'https://fnatic.com/',
- width: 52,
- },
- },
- {
- item: {
- id: '4',
- logo_dark: '/images/partner-logos/logo-fsn-dark.png',
- logo_light: '/images/partner-logos/logo-fsn-light.png',
- name: 'Fsn',
- slug: 'fsn',
- url: 'https://www.fsncapital.com/',
- width: 58,
- },
- },
- {
- item: {
- id: '5',
- logo_dark: '/images/partner-logos/logo-justos-dark.png',
- logo_light: '/images/partner-logos/logo-justos-light.png',
- name: 'Justos',
- slug: 'justos',
- url: 'https://www.justos.com.br/',
- width: 92,
- },
- },
- {
- item: {
- id: '6',
- logo_dark: '/images/partner-logos/logo-mott-mac-dark.png',
- logo_light: '/images/partner-logos/logo-mott-mac-light.png',
- name: 'Mot Mac',
- slug: 'mot-mac',
- url: 'https://www.mottmac.com/',
- width: 58,
- },
- },
- ],
- },
+ og_description: siteSettings.og_description ?? 'Plural',
+ og_image: getImageUrl(siteSettings.og_image),
main_nav: {
product: {
id: 'product',
@@ -182,24 +117,8 @@ export const getSiteSettings = (
],
},
},
- promo_banner_content: '',
- promo_banner_url: '',
})
-export type PartnerLogos = {
- items: {
- item: {
- id: string
- logo_dark: string
- logo_light: string
- name: string
- slug: string
- url: string
- width: number
- }
- }[]
-}
-
function getProductSubnav(products?: ProductPageTinyFragment[]): NavList[] {
if (!products || !products.length) return []
diff --git a/src/generated/graphqlDirectus.ts b/src/generated/graphqlDirectus.ts
index bdf496e1..0e70f9ce 100644
--- a/src/generated/graphqlDirectus.ts
+++ b/src/generated/graphqlDirectus.ts
@@ -26,22 +26,20 @@ export type Scalars = {
export type Mutation = {
__typename?: 'Mutation';
- create_apps_item?: Maybe;
- create_apps_items: Array;
create_article_cards_item?: Maybe;
create_article_cards_items: Array;
create_blog_cards_item?: Maybe;
create_blog_cards_items: Array;
- create_callouts_item?: Maybe;
- create_callouts_items: Array;
create_card_item?: Maybe;
create_card_items: Array;
+ create_card_with_image_item?: Maybe;
+ create_card_with_image_items: Array;
+ create_card_with_image_rich_text_columns_item?: Maybe;
+ create_card_with_image_rich_text_columns_items: Array;
create_cards_card_item?: Maybe;
create_cards_card_items: Array;
create_cards_item?: Maybe;
create_cards_items: Array;
- create_case_studies_item?: Maybe;
- create_case_studies_items: Array;
create_collapsible_lists_item?: Maybe;
create_collapsible_lists_items: Array;
create_collapsible_lists_items_item?: Maybe;
@@ -66,10 +64,6 @@ export type Mutation = {
create_customer_quote_items: Array;
create_events_item?: Maybe;
create_events_items: Array;
- create_faqs_item?: Maybe;
- create_faqs_items: Array;
- create_featured_contributors_item?: Maybe;
- create_featured_contributors_items: Array;
create_hero_item?: Maybe;
create_hero_items: Array;
create_job_listings_item?: Maybe;
@@ -84,10 +78,6 @@ export type Mutation = {
create_multi_column_text_items: Array;
create_multi_column_text_rich_text_columns_item?: Maybe;
create_multi_column_text_rich_text_columns_items: Array;
- create_nav_link_item?: Maybe;
- create_nav_link_items: Array;
- create_nav_list_item?: Maybe;
- create_nav_list_items: Array;
create_pricing_plan_features_item?: Maybe;
create_pricing_plan_features_items: Array;
create_pricing_plans_item?: Maybe;
@@ -116,28 +106,24 @@ export type Mutation = {
create_solutions_pages_items: Array;
create_solutions_pages_solution_problems_item?: Maybe;
create_solutions_pages_solution_problems_items: Array;
- create_stacks_item?: Maybe;
- create_stacks_items: Array;
create_team_members_item?: Maybe;
create_team_members_items: Array;
create_two_column_text_item?: Maybe;
create_two_column_text_items: Array;
- delete_apps_item?: Maybe;
- delete_apps_items?: Maybe;
delete_article_cards_item?: Maybe;
delete_article_cards_items?: Maybe;
delete_blog_cards_item?: Maybe;
delete_blog_cards_items?: Maybe;
- delete_callouts_item?: Maybe;
- delete_callouts_items?: Maybe;
delete_card_item?: Maybe;
delete_card_items?: Maybe;
+ delete_card_with_image_item?: Maybe;
+ delete_card_with_image_items?: Maybe;
+ delete_card_with_image_rich_text_columns_item?: Maybe;
+ delete_card_with_image_rich_text_columns_items?: Maybe;
delete_cards_card_item?: Maybe;
delete_cards_card_items?: Maybe;
delete_cards_item?: Maybe;
delete_cards_items?: Maybe;
- delete_case_studies_item?: Maybe;
- delete_case_studies_items?: Maybe;
delete_collapsible_lists_item?: Maybe;
delete_collapsible_lists_items?: Maybe;
delete_collapsible_lists_items_item?: Maybe;
@@ -162,10 +148,6 @@ export type Mutation = {
delete_customer_quote_items?: Maybe;
delete_events_item?: Maybe;
delete_events_items?: Maybe;
- delete_faqs_item?: Maybe;
- delete_faqs_items?: Maybe;
- delete_featured_contributors_item?: Maybe;
- delete_featured_contributors_items?: Maybe;
delete_hero_item?: Maybe;
delete_hero_items?: Maybe;
delete_job_listings_item?: Maybe;
@@ -180,10 +162,6 @@ export type Mutation = {
delete_multi_column_text_items?: Maybe;
delete_multi_column_text_rich_text_columns_item?: Maybe;
delete_multi_column_text_rich_text_columns_items?: Maybe;
- delete_nav_link_item?: Maybe;
- delete_nav_link_items?: Maybe;
- delete_nav_list_item?: Maybe;
- delete_nav_list_items?: Maybe;
delete_pricing_plan_features_item?: Maybe;
delete_pricing_plan_features_items?: Maybe;
delete_pricing_plans_item?: Maybe;
@@ -212,37 +190,31 @@ export type Mutation = {
delete_solutions_pages_items?: Maybe;
delete_solutions_pages_solution_problems_item?: Maybe;
delete_solutions_pages_solution_problems_items?: Maybe;
- delete_stacks_item?: Maybe;
- delete_stacks_items?: Maybe;
delete_team_members_item?: Maybe;
delete_team_members_items?: Maybe;
delete_two_column_text_item?: Maybe;
delete_two_column_text_items?: Maybe;
- update_app_defaults?: Maybe;
- update_apps_batch: Array;
- update_apps_item?: Maybe;
- update_apps_items: Array;
update_article_cards_batch: Array;
update_article_cards_item?: Maybe;
update_article_cards_items: Array;
update_blog_cards_batch: Array;
update_blog_cards_item?: Maybe;
update_blog_cards_items: Array;
- update_callouts_batch: Array;
- update_callouts_item?: Maybe;
- update_callouts_items: Array;
update_card_batch: Array;
update_card_item?: Maybe;
update_card_items: Array;
+ update_card_with_image_batch: Array;
+ update_card_with_image_item?: Maybe;
+ update_card_with_image_items: Array;
+ update_card_with_image_rich_text_columns_batch: Array;
+ update_card_with_image_rich_text_columns_item?: Maybe;
+ update_card_with_image_rich_text_columns_items: Array;
update_cards_batch: Array;
update_cards_card_batch: Array;
update_cards_card_item?: Maybe;
update_cards_card_items: Array;
update_cards_item?: Maybe;
update_cards_items: Array;
- update_case_studies_batch: Array;
- update_case_studies_item?: Maybe;
- update_case_studies_items: Array;
update_collapsible_lists_batch: Array;
update_collapsible_lists_item?: Maybe;
update_collapsible_lists_items: Array;
@@ -279,12 +251,6 @@ export type Mutation = {
update_events_batch: Array;
update_events_item?: Maybe;
update_events_items: Array;
- update_faqs_batch: Array;
- update_faqs_item?: Maybe;
- update_faqs_items: Array;
- update_featured_contributors_batch: Array;
- update_featured_contributors_item?: Maybe;
- update_featured_contributors_items: Array;
update_hero_batch: Array;
update_hero_item?: Maybe;
update_hero_items: Array;
@@ -306,13 +272,6 @@ export type Mutation = {
update_multi_column_text_rich_text_columns_batch: Array;
update_multi_column_text_rich_text_columns_item?: Maybe;
update_multi_column_text_rich_text_columns_items: Array;
- update_nav_link_batch: Array;
- update_nav_link_item?: Maybe;
- update_nav_link_items: Array;
- update_nav_list_batch: Array;
- update_nav_list_item?: Maybe;
- update_nav_list_items: Array;
- update_page_community?: Maybe;
update_page_homepage?: Maybe;
update_page_legal?: Maybe;
update_pricing_page?: Maybe;
@@ -359,10 +318,6 @@ export type Mutation = {
update_solutions_pages_solution_problems_batch: Array;
update_solutions_pages_solution_problems_item?: Maybe;
update_solutions_pages_solution_problems_items: Array;
- update_stack_defaults?: Maybe;
- update_stacks_batch: Array;
- update_stacks_item?: Maybe;
- update_stacks_items: Array;
update_team_members_batch: Array;
update_team_members_item?: Maybe;
update_team_members_items: Array;
@@ -372,22 +327,6 @@ export type Mutation = {
};
-export type MutationCreate_Apps_ItemArgs = {
- data: Create_Apps_Input;
-};
-
-
-export type MutationCreate_Apps_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
- limit?: InputMaybe;
- offset?: InputMaybe;
- page?: InputMaybe;
- search?: InputMaybe;
- sort?: InputMaybe>>;
-};
-
-
export type MutationCreate_Article_Cards_ItemArgs = {
data: Create_Article_Cards_Input;
};
@@ -420,14 +359,14 @@ export type MutationCreate_Blog_Cards_ItemsArgs = {
};
-export type MutationCreate_Callouts_ItemArgs = {
- data: Create_Callouts_Input;
+export type MutationCreate_Card_ItemArgs = {
+ data: Create_Card_Input;
};
-export type MutationCreate_Callouts_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
+export type MutationCreate_Card_ItemsArgs = {
+ data?: InputMaybe>;
+ filter?: InputMaybe;
limit?: InputMaybe;
offset?: InputMaybe;
page?: InputMaybe;
@@ -436,14 +375,14 @@ export type MutationCreate_Callouts_ItemsArgs = {
};
-export type MutationCreate_Card_ItemArgs = {
- data: Create_Card_Input;
+export type MutationCreate_Card_With_Image_ItemArgs = {
+ data: Create_Card_With_Image_Input;
};
-export type MutationCreate_Card_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
+export type MutationCreate_Card_With_Image_ItemsArgs = {
+ data?: InputMaybe>;
+ filter?: InputMaybe;
limit?: InputMaybe;
offset?: InputMaybe;
page?: InputMaybe;
@@ -452,14 +391,14 @@ export type MutationCreate_Card_ItemsArgs = {
};
-export type MutationCreate_Cards_Card_ItemArgs = {
- data: Create_Cards_Card_Input;
+export type MutationCreate_Card_With_Image_Rich_Text_Columns_ItemArgs = {
+ data: Create_Card_With_Image_Rich_Text_Columns_Input;
};
-export type MutationCreate_Cards_Card_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
+export type MutationCreate_Card_With_Image_Rich_Text_Columns_ItemsArgs = {
+ data?: InputMaybe>;
+ filter?: InputMaybe;
limit?: InputMaybe;
offset?: InputMaybe;
page?: InputMaybe;
@@ -468,14 +407,14 @@ export type MutationCreate_Cards_Card_ItemsArgs = {
};
-export type MutationCreate_Cards_ItemArgs = {
- data: Create_Cards_Input;
+export type MutationCreate_Cards_Card_ItemArgs = {
+ data: Create_Cards_Card_Input;
};
-export type MutationCreate_Cards_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
+export type MutationCreate_Cards_Card_ItemsArgs = {
+ data?: InputMaybe>;
+ filter?: InputMaybe;
limit?: InputMaybe;
offset?: InputMaybe;
page?: InputMaybe;
@@ -484,14 +423,14 @@ export type MutationCreate_Cards_ItemsArgs = {
};
-export type MutationCreate_Case_Studies_ItemArgs = {
- data: Create_Case_Studies_Input;
+export type MutationCreate_Cards_ItemArgs = {
+ data: Create_Cards_Input;
};
-export type MutationCreate_Case_Studies_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
+export type MutationCreate_Cards_ItemsArgs = {
+ data?: InputMaybe>;
+ filter?: InputMaybe;
limit?: InputMaybe;
offset?: InputMaybe;
page?: InputMaybe;
@@ -692,38 +631,6 @@ export type MutationCreate_Events_ItemsArgs = {
};
-export type MutationCreate_Faqs_ItemArgs = {
- data: Create_Faqs_Input;
-};
-
-
-export type MutationCreate_Faqs_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
- limit?: InputMaybe;
- offset?: InputMaybe;
- page?: InputMaybe;
- search?: InputMaybe;
- sort?: InputMaybe>>;
-};
-
-
-export type MutationCreate_Featured_Contributors_ItemArgs = {
- data: Create_Featured_Contributors_Input;
-};
-
-
-export type MutationCreate_Featured_Contributors_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
- limit?: InputMaybe;
- offset?: InputMaybe;
- page?: InputMaybe;
- search?: InputMaybe;
- sort?: InputMaybe>>;
-};
-
-
export type MutationCreate_Hero_ItemArgs = {
data: Create_Hero_Input;
};
@@ -836,38 +743,6 @@ export type MutationCreate_Multi_Column_Text_Rich_Text_Columns_ItemsArgs = {
};
-export type MutationCreate_Nav_Link_ItemArgs = {
- data: Create_Nav_Link_Input;
-};
-
-
-export type MutationCreate_Nav_Link_ItemsArgs = {
- data?: InputMaybe>;
- filter?: InputMaybe;
- limit?: InputMaybe;
- offset?: InputMaybe