diff --git a/pages/applications/[repo].tsx b/pages/applications/[repo].tsx deleted file mode 100644 index 085b1e42..00000000 --- a/pages/applications/[repo].tsx +++ /dev/null @@ -1,478 +0,0 @@ -import { type ComponentProps, useEffect } from 'react' - -import { AppIcon, Code, ColorModeProvider } from '@pluralsh/design-system' -import { - type GetStaticPaths, - type GetStaticProps, - type InferGetStaticPropsType, -} from 'next' -import { useRouter } from 'next/router' - -import { until } from '@open-draft/until' -import { providerToProviderName } from '@pluralsh/design-system/dist/markdoc/utils/text' -import { isEmpty } from 'lodash-es' -import styled, { useTheme } from 'styled-components' -import { type MergeDeep } from 'type-fest' - -// import { ProductValueSection } from '@pages/plural-stacks/ProductValueSection' -import client, { directusClient } from '@src/apollo-client' -import { mqs } from '@src/breakpoints' -import { BasicMarkdoc } from '@src/components/BasicMarkdoc' -import Embed from '@src/components/Embed' -import { FooterVariant } from '@src/components/FooterFull' -import { Columns, EqualColumn } from '@src/components/layout/Columns' -import { - StandardPageSection, - StandardPageWidth, -} from '@src/components/layout/LayoutHelpers' -import { TextLimiter } from '@src/components/layout/TextLimiter' -import { BackButton } from '@src/components/Nav' -import BuildStackSection from '@src/components/page-sections/BuildStackSection' -import { - CaseStudySection, - getCaseStudyApps, -} from '@src/components/page-sections/CaseStudySection' -import { HPWMiniSectionAppStacks } from '@src/components/page-sections/HowPluralWorksMiniSection' -import { StandardFAQSection } from '@src/components/page-sections/StandardFAQSection' -import { TestimonialsSection } from '@src/components/QuoteCards' -import RepoReadmeMd from '@src/components/RepoReadme/RepoReadmeMd' -import { SingleAccordion } from '@src/components/SingleAccordion' -import { AppTitle, Cta } from '@src/components/Typography' -import { QUICKSTART_VIDEO_URL, getAppMeta, getProviderIcon } from '@src/consts' -import { - type BasicRepo, - type FullRepo, - type TinyRepo, - getFullRepo, - getTinyRepos, -} from '@src/data/getRepos' -import { getStacks } from '@src/data/getStacks' -import { getStackTabData } from '@src/data/getStackTabData' -import { - type AppDefaultsFragment, - AppExtrasDocument, - type AppExtrasFragment, - type AppExtrasQuery, - type AppExtrasQueryVariables, - type FaqItemFragment, - FaqListDocument, - type FaqListQuery, - type FaqListQueryVariables, - type QuoteFragment, -} from '@src/generated/graphqlDirectus' -import { - type Recipe, - type RecipeFragment, - RecipesDocument, - type RecipesQuery, - type RecipesQueryVariables, -} from '@src/generated/graphqlPlural' -import { cn as classNames } from '@src/utils/cn' -import { combineErrors } from '@src/utils/combineErrors' -import { - type GlobalProps, - propsWithGlobalSettings, -} from '@src/utils/getGlobalProps' -import { normalizeM2mItems, normalizeQuotes } from '@src/utils/normalizeQuotes' - -import { CompanyLogosSection } from '../../src/components/CompanyLogos' -import { GradientBG } from '../../src/components/layout/GradientBG' -import { HeaderPad } from '../../src/components/layout/HeaderPad' -import { ProviderIcon } from '../../src/components/ProviderIcon' -import { RepoSocials } from '../../src/components/RepoSocials' - -const DEFAULT_HERO_VIDEO = QUICKSTART_VIDEO_URL - -function isRecipe( - recipe: RecipeFragment | null | undefined -): recipe is RecipeFragment { - return !!recipe -} - -const AppPageTitle = styled( - ({ app, ...props }: { app: BasicRepo } & ComponentProps<'div'>) => { - const theme = useTheme() - const iconProps = { - url: - (theme.mode === 'light' - ? app.icon || app.darkIcon - : app.darkIcon || app.icon) ?? '', - } - - return ( -
-
-
- -
-
- -
-
- {app.displayName} -
- ) - } -)(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - gap: theme.spacing.small, - '.icon > .largeIcon': { - display: 'none', - }, - [mqs.md]: { - '.icon': { - '& > .smallIcon': { - display: 'none', - }, - '& > .largeIcon': { - display: 'flex', - }, - }, - }, -})) - -export type ProviderProps = { - label?: string | null | undefined - iconDark: string - iconLight: string -} - -export default function App({ - repo, - heroVideo, - heroText, - secondaryTitle, - secondaryText, - caseStudy, - quotes, - recipes, - buildStackTabs, - caseStudyApps, - faqs, - globalProps, -}: InferGetStaticPropsType) { - const router = useRouter() - const recipeTabs = - recipes?.filter(isRecipe).map((recipe) => ({ - key: recipe.name, - label: - providerToProviderName[recipe?.provider?.toUpperCase() || ''] || - recipe.provider || - '', - language: 'shell', - content: `plural bundle install ${repo?.name} ${recipe.name}`, - iconLight: getProviderIcon({ provider: recipe?.provider, mode: 'light' }), - iconDark: getProviderIcon({ provider: recipe?.provider, mode: 'dark' }), - })) || [] - - useEffect(() => { - if (!repo) { - router.push('/marketplace') - } - }, [repo, router]) - if (!repo) { - return null - } - - return ( - - -
- -
- - - - -
- {heroText ? ( - - ) : ( -

{repo.description}

- )} -
-
-

Available providers

- {!isEmpty(recipeTabs) ? ( -
- {recipeTabs.map((provider) => ( - - ))} -
- ) : ( -

Coming soon

- )} -
-
-
- - - -
-
- - - -

- -

-
- -
-
- -
-
-
- - {!isEmpty(recipeTabs) && ( - <> -
-
- Deploying {repo.displayName} is a matter of executing - these 3 commands: -
- - plural build - - {`plural deploy --commit "deploying ${repo.name}"`} - -
- - Read the install documentation - - - )} -
-
- {repo?.readme && ( - -
- -
-
- )} -
-
- - {buildStackTabs && } - - - - - -
- ) -} - -export function CaseStudyFAQSection({ - caseStudyProps, - faqProps, -}: { - caseStudyProps?: ComponentProps - faqProps: ComponentProps -}) { - return ( - - - {caseStudyProps?.featuredArticle && ( - - - - )} - - - - ) -} - -export const getStaticPaths: GetStaticPaths = async () => { - if (process.env.NODE_ENV === 'development') { - return { - paths: [], - fallback: 'blocking', - } - } - - const repos = (await getTinyRepos()) || [] - - return { - paths: repos.map((repo) => ({ params: { repo: repo?.name } })), - fallback: true, - } -} - -export type AppPageProps = { - repo?: FullRepo | null - quotes: QuoteFragment[] | null - heroVideo: Exclude< - ReturnType['heroVideo'], - undefined - > - heroText: Exclude< - ReturnType['hero_text'], - undefined - > - secondaryTitle: Exclude< - ReturnType['secondary_title'], - undefined - > - secondaryText: Exclude< - ReturnType['secondary_text'], - undefined - > - caseStudy: Exclude< - ReturnType['case_study'], - undefined - > - recipes?: Recipe[] - buildStackTabs?: ReturnType - caseStudyApps: TinyRepo[] - faqs: (FaqItemFragment | null)[] - globalProps: GlobalProps -} - -const normalizeAppExtras = (extras: AppExtrasQuery) => - ({ - ...(extras.app_defaults || {}), - ...Object.fromEntries( - Object.entries(extras.apps?.[0] || {}).filter(([_, val]) => !!val) - ), - }) as MergeDeep - -export const getStaticProps: GetStaticProps = async (context) => { - const repoName = context?.params?.repo - - const { data: repos, error: reposError } = await until(() => getTinyRepos()) - - const { data: repo, error: repoError } = await until(() => - getFullRepo(`${repoName}`) - ) - - const { data: stacks, error: stacksError } = await until(() => getStacks()) - - const thisRepo = repo - - if (!thisRepo || !repoName || typeof repoName !== 'string') { - return { notFound: true } - } - - const { data: appData, error: appError } = await directusClient.query< - AppExtrasQuery, - AppExtrasQueryVariables - >({ - query: AppExtrasDocument, - variables: { name: repoName }, - }) - - const { data: recipesData, error: recipesError } = await client.query< - RecipesQuery, - RecipesQueryVariables - >({ - query: RecipesDocument, - variables: { - repoName, - }, - }) - - const buildStackTabs = getStackTabData({ repos, stacks }) - - if (recipesError) { - throw new Error(`${recipesError.name}: ${recipesError.message}`) - } - - const recipes = - recipesData?.recipes?.edges - ?.map((edge) => edge?.node) - .filter((r): r is Recipe => !!r && !r?.private) || [] - - const appExtras = normalizeAppExtras(appData) || {} - - const { data: faqData, error: faqError } = await directusClient.query< - FaqListQuery, - FaqListQueryVariables - >({ - query: FaqListDocument, - variables: { slug: 'generic' }, - }) - - return propsWithGlobalSettings({ - repo: thisRepo - ? { - ...thisRepo, - } - : null, - caseStudy: appExtras.case_study || null, - heroVideo: appExtras.heroVideo || null, - heroText: appExtras.hero_text || null, - secondaryText: appExtras.secondary_text || null, - secondaryTitle: appExtras.secondary_title || null, - quotes: normalizeQuotes(appExtras.quotes), - recipes, - ...getAppMeta(thisRepo), - faqs: normalizeM2mItems(faqData.collapsible_lists?.[0]) || [], - buildStackTabs, - caseStudyApps: getCaseStudyApps( - repos, - (appExtras.case_study?.stack_apps as string[]) || [] - ), - footerVariant: FooterVariant.kitchenSink, - errors: combineErrors([ - reposError, - stacksError, - repoError, - appError, - faqError, - ]), - }) -} diff --git a/pages/index.tsx b/pages/index.tsx index 5b826154..12ed8ae5 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -176,6 +176,7 @@ function HeroImages({ ...props }: ComponentProps) { export default function Index({ articleCards, + quotes, }: InferGetStaticPropsType) { const [showVideo, setShowVideo] = useState(false) @@ -307,10 +308,7 @@ export default function Index({ diff --git a/pages/kubernetes-fleet-management.tsx b/pages/kubernetes-fleet-management.tsx deleted file mode 100644 index 08738636..00000000 --- a/pages/kubernetes-fleet-management.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { Button } from 'honorable' -import { type InferGetStaticPropsType } from 'next' -import Link from 'next/link' - -import { directusClient } from '@src/apollo-client' -import { FooterVariant } from '@src/components/FooterFull' -import { GradientBG } from '@src/components/layout/GradientBG' -import { - StandardPageSection, - StandardPageWidth, -} from '@src/components/layout/LayoutHelpers' -import { TextLimiter } from '@src/components/layout/TextLimiter' -import ArticleSection from '@src/components/page-sections/articleSection' -import { ProductFeaturesSection } from '@src/components/page-sections/ProductFeatureSection' -import { QuoteSection } from '@src/components/page-sections/QuoteSection' -import { CenteredSectionHead } from '@src/components/SectionHeads' -import { ResponsiveText } from '@src/components/Typography' -import { - PageHomepageDocument, - type PageHomepageQuery, - type PageHomepageQueryVariables, -} from '@src/generated/graphqlDirectus' -import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' - -import { HeaderPad } from '../src/components/layout/HeaderPad' - -export default function Legal( - _props: InferGetStaticPropsType -) { - return ( - <> - -
- - - Automating Kubernetes management and enhancing security for - enterprises - - - -
-
- - -
-
- - Import manifests and helm charts from Git repositories and - deploy services to clusters in a couple of clicks. -

- } - /> -
- -
-
-
-
-
- - - - - ) -} - -export const getStaticProps = async () => { - const { data } = await directusClient.query< - PageHomepageQuery, - PageHomepageQueryVariables - >({ - query: PageHomepageDocument, - }) - - return propsWithGlobalSettings({ - metaTitle: 'Kubernetes fleet management', - metaDescription: - 'An end-to-end solution for managing Kubernetes clusters and application deployment.', - footerVariant: FooterVariant.kitchenSink, - articleCards: data.page_homepage?.article_cards || null, - }) -} diff --git a/pages/plural-stacks/[stack].tsx b/pages/plural-stacks/[stack].tsx deleted file mode 100644 index 7ccd0355..00000000 --- a/pages/plural-stacks/[stack].tsx +++ /dev/null @@ -1,383 +0,0 @@ -import { useEffect, useRef, useState } from 'react' - -import { Button, TabList, TabPanel } from '@pluralsh/design-system' -import { - type GetStaticPaths, - type GetStaticProps, - type InferGetStaticPropsType, -} from 'next' -import Link from 'next/link' -import { useRouter } from 'next/router' - -import { until } from '@open-draft/until' -import { providerToProviderName } from '@pluralsh/design-system/dist/markdoc/utils/text' -import { isEmpty } from 'lodash-es' -import styled from 'styled-components' -import { type MergeDeep } from 'type-fest' - -import { CaseStudyFAQSection } from '@pages/applications/[repo]' -import { directusClient } from '@src/apollo-client' -import { AppCard } from '@src/components/AppOrStackCard' -import Embed from '@src/components/Embed' -import { FooterVariant } from '@src/components/FooterFull' -import { GradientBG } from '@src/components/layout/GradientBG' -import { - StandardPageSection, - StandardPageWidth, -} from '@src/components/layout/LayoutHelpers' -import { BackButton } from '@src/components/Nav' -import BuildStackSection from '@src/components/page-sections/BuildStackSection' -import { getCaseStudyApps } from '@src/components/page-sections/CaseStudySection' -import { HPWMiniSectionAppStacks } from '@src/components/page-sections/HowPluralWorksMiniSection' -import { ProviderIcon } from '@src/components/ProviderIcon' -import { TestimonialsSection } from '@src/components/QuoteCards' -import { RepoSocials } from '@src/components/RepoSocials' -import { AppTitle } from '@src/components/Typography' -import { getProviderIcon, getStackMeta } from '@src/consts' -import { appUrl } from '@src/consts/routes' -import { type TinyRepo, getTinyRepos, normalizeRepo } from '@src/data/getRepos' -import { type FullStack, getFullStack, getStacks } from '@src/data/getStacks' -import { getStackTabData } from '@src/data/getStackTabData' -import { - type FaqItemFragment, - FaqListDocument, - type FaqListQuery, - type FaqListQueryVariables, - type QuoteFragment, - type StackDefaultsFragment, - StackExtrasDocument, - type StackExtrasFragment, - type StackExtrasQuery, - type StackExtrasQueryVariables, -} from '@src/generated/graphqlDirectus' -import { - type BasicRepoFragment, - type StackCollectionFragment, -} from '@src/generated/graphqlPlural' -import { cn as classNames } from '@src/utils/cn' -import { combineErrors } from '@src/utils/combineErrors' -import { - type GlobalProps, - propsWithGlobalSettings, -} from '@src/utils/getGlobalProps' -import { normalizeM2mItems, normalizeQuotes } from '@src/utils/normalizeQuotes' -import { startsWithVowel } from '@src/utils/text' - -import { CompanyLogosSection } from '../../src/components/CompanyLogos' -import { Columns, EqualColumn } from '../../src/components/layout/Columns' -import { HeaderPad } from '../../src/components/layout/HeaderPad' -import { TextLimiter } from '../../src/components/layout/TextLimiter' - -// import { ProductValueSection } from './ProductValueSection' - -const DEFAULT_HERO_VIDEO = 'https://www.youtube.com/watch?v=LOUshNTgPV0' - -function isCollection( - collection: StackCollectionFragment | null | undefined -): collection is StackCollectionFragment { - return !!collection -} - -const StackAppsTabList = styled(TabList)(({ theme }) => ({ - flexDirection: 'column', - border: theme.borders['fill-two'], - padding: theme.spacing.xsmall, - rowGap: theme.spacing.xsmall, - borderRadius: theme.borderRadiuses.medium, -})) - -const StackAppsTabPanel = styled(TabPanel)((_) => ({})) - -export default function Stack({ - stack, - quotes, - heroVideo, - caseStudy, - faqs, - buildStackTabs, - caseStudyApps, - globalProps, -}: InferGetStaticPropsType) { - const router = useRouter() - const providers = - stack?.collections?.filter(isCollection).map((collection) => ({ - key: collection.id, - label: - providerToProviderName[collection?.provider?.toUpperCase() || ''] || - collection.provider, - // language: 'shell', - // content: `plural stack install ${stack?.name}`, - iconLight: getProviderIcon({ - provider: collection?.provider, - mode: 'light', - }), - iconDark: getProviderIcon({ - provider: collection?.provider, - mode: 'dark', - }), - })) || [] - - const apps = stack?.collections?.[0]?.bundles - ?.map((bundle) => bundle?.recipe.repository) - .filter((repo): repo is BasicRepoFragment => !!repo) - .map((repo) => normalizeRepo(repo)) - - const appsTabStateRef = useRef() - const [curAppTabKey, setCurTabKey] = useState(apps?.[0].name ?? '') - const curApp = apps?.find((app) => app.name === curAppTabKey) - - useEffect(() => { - if (!stack) { - // router.push('/marketplace') - } - }, [stack, router]) - if (!stack) { - return null - } - - return ( - - -
- -
- - - - - Build {startsWithVowel(stack.displayName) ? 'an' : 'a'}{' '} - {stack.displayName} Stack with Plural - -

{stack.description}

-
-

- Available providers -

- {!isEmpty(providers) && ( -
- {providers.map((provider) => ( - - ))} -
- )} -
-
- -
-
-
- - - -
-
- - -

The stack

-
- -
- - - {/* @ts-no-check */} - setCurTabKey(key as string), - }} - > - {apps?.map((repo) => { - if (!repo || !repo.name) { - return null - } - - return ( - - {repo.name} - - ) - })} - - - - -

- About {curApp?.displayName} -

-

- {curApp?.description} -

-
- -
-
- -
-
-
-
-
-
- - - {/* */} - {buildStackTabs && } - - - - - -
- ) -} - -export const getStaticPaths: GetStaticPaths = async () => { - if (process.env.NODE_ENV === 'development') { - return { - paths: [], - fallback: 'blocking', - } - } - - const stacks = (await getStacks()) || [] - - return { - paths: stacks.map((stack) => ({ params: { stack: stack?.name } })), - fallback: true, - } -} - -export type StackPageProps = { - stack: FullStack | null - quotes: QuoteFragment[] | null - heroVideo: Exclude< - ReturnType['heroVideo'], - undefined - > - caseStudy: Exclude< - ReturnType['case_study'], - undefined - > - buildStackTabs?: ReturnType - caseStudyApps: TinyRepo[] - faqs: (FaqItemFragment | null)[] - globalProps: GlobalProps -} - -const normalizeStackExtras = (extras: StackExtrasQuery) => - ({ - ...(extras.stack_defaults || {}), - ...(extras.stacks?.[0] || {}), - }) as MergeDeep - -export const getStaticProps: GetStaticProps = async ( - context -) => { - const stackName = context?.params?.stack - - if (!stackName || typeof stackName !== 'string') { - return { notFound: true } - } - const { data: repos, error: reposError } = await until(() => getTinyRepos()) - - const { data: stacks, error: stacksError } = await until(() => getStacks()) - const { data: stack, error: stackError } = await until(() => - getFullStack(stackName) - ) - - const thisStack = stack // stacks?.find((r) => r.name === stackName) - - if (!thisStack || !stackName || typeof stackName !== 'string') { - return { notFound: true } - } - - const { data: stackData, error: appError } = await directusClient.query< - StackExtrasQuery, - StackExtrasQueryVariables - >({ - query: StackExtrasDocument, - variables: { name: stackName }, - }) - - const buildStackTabs = getStackTabData({ repos, stacks }) - - const { data: faqData, error: faqError } = await directusClient.query< - FaqListQuery, - FaqListQueryVariables - >({ - query: FaqListDocument, - variables: { slug: 'generic' }, - }) - - const stackExtras = normalizeStackExtras(stackData) || {} - - return propsWithGlobalSettings({ - stack: thisStack - ? { - ...thisStack, - } - : null, - heroVideo: stackExtras.heroVideo || null, - caseStudy: stackExtras.case_study || null, - quotes: normalizeQuotes(stackExtras.quotes), - ...getStackMeta(thisStack), - faqs: normalizeM2mItems(faqData.collapsible_lists?.[0]) || [], - buildStackTabs, - caseStudyApps: getCaseStudyApps( - repos, - (stackExtras.case_study?.stack_apps as string[]) || [] - ), - footerVariant: FooterVariant.kitchenSink, - errors: combineErrors([ - reposError, - stacksError, - stackError, - appError, - faqError, - ]), - }) -} diff --git a/pages/product.tsx b/pages/product.tsx deleted file mode 100644 index 9279ef33..00000000 --- a/pages/product.tsx +++ /dev/null @@ -1,260 +0,0 @@ -import { Button, ColorModeProvider } from '@pluralsh/design-system' -import { type InferGetStaticPropsType } from 'next' -import Head from 'next/head' -import Link from 'next/link' -import Script from 'next/script' - -import styled from 'styled-components' - -import { mqs } from '@src/breakpoints' -import { QuickstartDemoCard } from '@src/components/ArticleCard' -import { FeaturedQuote } from '@src/components/FeaturedQuote' -import { FooterVariant } from '@src/components/FooterFull' -import { Columns, EqualColumn } from '@src/components/layout/Columns' -import { GradientBG } from '@src/components/layout/GradientBG' -import { HeaderPad } from '@src/components/layout/HeaderPad' -import { - StandardPageSection, - StandardPageWidth, -} from '@src/components/layout/LayoutHelpers' -import { TextLimiter } from '@src/components/layout/TextLimiter' -import { HowPluralWorksSection } from '@src/components/page-sections/HowPluralWorksSection' -import { StandardFAQSection } from '@src/components/page-sections/StandardFAQSection' -import { WhatIsPluralSection } from '@src/components/page-sections/WhatIsPluralSection' -import { CenteredSectionHead } from '@src/components/SectionHeads' -import { getProductPageData } from '@src/data/getProductPageData' -import { useAnimationPauser } from '@src/hooks/useAnimationPauser' -import { cn as classNames } from '@src/utils/cn' -import { combineErrors } from '@src/utils/combineErrors' -import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' -import { normalizeM2mItems } from '@src/utils/normalizeQuotes' - -import { TryPluralForFreeSection } from '../src/components/page-sections/TryPluralForFreeSection' -import { HeroMainText } from '../src/components/PageHeros' - -export const ArchitectureContentSC = styled(TextLimiter)(({ theme }) => ({ - color: theme.colors['text-light'], - 'h1, h2, h3, h4, h5, h6': { - ...theme.partials.text.body1Bold, - marginBottom: theme.spacing.small, - }, - 'p, li': { - ...theme.partials.text.body2, - }, - '& :is(p, ul) + :is(p, ul)': { - marginTop: theme.spacing.medium, - }, -})) - -const AnimationWrapSC = styled.div((_) => ({ - flex: 1, - '& > div': { - width: '100%', - position: 'relative', - height: 0, - }, - iframe: { - position: 'absolute', - top: 0, - left: 0, - width: '100%', - height: '100%;', - }, -})) - -const HeroAnimationWrapSC = styled(AnimationWrapSC)((_) => ({ - display: 'none', - height: 0, - - '& > div': { - paddingBottom: 'calc((455/700) * 100%)', - }, - [mqs.columns]: { - display: 'block', - marginTop: '-32%', - marginLeft: '-12%', - marginRight: '-8%', - }, - [mqs.xl]: { - marginTop: '-35%', - marginLeft: '-24%', - marginRight: '-0%', - }, - [mqs.max]: { - marginTop: '-41%', - marginLeft: '-25%', - marginRight: '-5%', - }, -})) - -export default function Index({ - featuredQuote, - faqs, -}: InferGetStaticPropsType) { - useAnimationPauser() - - return ( - <> - -