diff --git a/.prettierignore b/.prettierignore index 7ab2d4ca8..ff55b871a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -19,3 +19,4 @@ integration-tests/fixtures/init-invalid-schema.graphql tmp pnpm-lock.yaml +.bob/ diff --git a/package.json b/package.json index fdf1666fb..707293f59 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,8 @@ "eslint-plugin-import": "2.26.0", "eslint-plugin-simple-import-sort": "8.0.0", "fs-extra": "10.1.0", - "graphql": "16.5.0", "glob": "8.0.3", + "graphql": "16.5.0", "husky": "7.0.4", "jest": "29.2.2", "lint-staged": "11.2.6", diff --git a/packages/web/docs/tsconfig.json b/packages/web/docs/tsconfig.json index 87ad9582b..19adceac3 100644 --- a/packages/web/docs/tsconfig.json +++ b/packages/web/docs/tsconfig.json @@ -15,6 +15,6 @@ "jsx": "preserve", "incremental": false }, - "include": ["next-env.d.ts", "src", "pages"], + "include": ["next-env.d.ts", "src"], "exclude": ["node_modules"] } diff --git a/packages/web/landing-page/.babelrc.js b/packages/web/landing-page/.babelrc.js deleted file mode 100644 index 6e4750165..000000000 --- a/packages/web/landing-page/.babelrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - presets: [['next/babel', { 'preset-react': { runtime: 'automatic' } }]], - plugins: ['babel-plugin-macros', ['styled-components', { ssr: true }]], -}; diff --git a/packages/web/landing-page/.gitignore b/packages/web/landing-page/.gitignore deleted file mode 100644 index d57b8c985..000000000 --- a/packages/web/landing-page/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* - -# local env files -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel - -# Graphql -lib/graphql-operations.ts diff --git a/packages/web/landing-page/components/logo.tsx b/packages/web/landing-page/components/logo.tsx deleted file mode 100644 index 2424fd6ed..000000000 --- a/packages/web/landing-page/components/logo.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from 'react'; - -export const Logo: React.FC<{ className?: string }> = ({ className }) => { - return ( - - - - - - - - - - - - - - - - ); - - // return ( - // - // - // - // - // - // - // - // - // - // - // - // - // - // ); -}; diff --git a/packages/web/landing-page/components/pricing.tsx b/packages/web/landing-page/components/pricing.tsx deleted file mode 100644 index 09d14fe80..000000000 --- a/packages/web/landing-page/components/pricing.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import React from 'react'; -import 'twin.macro'; -import * as RadixTooltip from '@radix-ui/react-tooltip'; - -function Tooltip( - props: React.PropsWithChildren<{ - content: string; - }> -) { - return ( - - {props.children} - - {props.content} - - - - ); -} - -function Plan(plan: { - name: string; - description: string; - price: React.ReactNode | string; - features: Array; - footer?: React.ReactNode; -}) { - return ( -
-
-
-

{plan.name}

-
{plan.price}
-
{plan.description}
-
-
    - {plan.features.map((feature, i) => { - return ( -
  • -
    {feature}
    -
  • - ); - })} -
-
-
- {plan.footer && ( -
-
-
{plan.footer}
-
- )} -
-
- ); -} - -const usageDataRetentionExplainer = 'How long to store GraphQL requests reported to GraphQL Hive'; -const operationsExplainer = 'GraphQL requests reported to GraphQL Hive'; - -export function Pricing({ gradient }: { gradient: [string, string] }) { - return ( -
-
-

- Pricing -

-

All features are available in every plan

-
- Limit of 1M operations monthly, - 7 days of usage data retention, - ]} - /> - - $10/mo - - } - features={[ - 'Unlimited seats', - 'Unlimited schema pushes', - $10 per 1M operations monthly, - 90 days of usage data retention, - ]} - footer={ - <> -
Free 30 days trial period
- - } - /> - { - if (typeof window !== 'undefined' && (window as any).$crisp) { - (window as any).$crisp.push(['do', 'chat:open']); - } - }} - > - Contact us - - } - features={[ - 'Unlimited seats', - 'Unlimited schema pushes', - Unlimited operations, - 12 months of usage data retention, - - Support from - - The Guild - - , - ]} - footer={<>Shape a custom plan for your business} - /> -
-
-
- ); -} diff --git a/packages/web/landing-page/components/the-guild-logo.tsx b/packages/web/landing-page/components/the-guild-logo.tsx deleted file mode 100644 index b8b59540f..000000000 --- a/packages/web/landing-page/components/the-guild-logo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function TheGuildLogo() { - return ( - - - - ); -} diff --git a/packages/web/landing-page/next.config.js b/packages/web/landing-page/next.config.js index 990b4c276..ee49c5dd7 100644 --- a/packages/web/landing-page/next.config.js +++ b/packages/web/landing-page/next.config.js @@ -1,5 +1,4 @@ -/* eslint-disable no-undef */ -module.exports = { +export default { poweredByHeader: false, eslint: { ignoreDuringBuilds: true, diff --git a/packages/web/landing-page/package.json b/packages/web/landing-page/package.json index 3f37059f8..955bd1513 100644 --- a/packages/web/landing-page/package.json +++ b/packages/web/landing-page/package.json @@ -2,32 +2,25 @@ "name": "@hive/landing-page", "private": true, "version": "0.0.0", + "type": "module", "scripts": { - "dev": "next dev", + "dev": "next", "build": "bob runify --single" }, "dependencies": { - "@radix-ui/react-tooltip": "0.1.7", - "@theguild/components": "1.12.1-alpha-bbdd479.0", - "framer-motion": "^6.3.3", - "next": "12.3.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-icons": "4.4.0", - "react-use": "^17.3.2", - "styled-components": "5.3.5", - "twin.macro": "2.8.2" + "@radix-ui/react-tooltip": "1.0.2", + "@theguild/components": "4.3.2", + "clsx": "1.2.1", + "next": "12.3.3", + "next-themes": "*", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-icons": "4.6.0" }, "devDependencies": { - "tslib": "2.4.0", - "tailwindcss": "2.2.19", - "@types/react": "17.0.45", - "@types/react-dom": "17.0.17" - }, - "babelMacros": { - "twin": { - "preset": "styled-components" - } + "@theguild/tailwind-config": "0.2.1", + "@types/react": "18.0.25", + "tailwindcss": "3.2.3" }, "buildOptions": { "runify": true, diff --git a/packages/web/landing-page/pages/index.tsx b/packages/web/landing-page/pages/index.tsx deleted file mode 100644 index 3b61a61bc..000000000 --- a/packages/web/landing-page/pages/index.tsx +++ /dev/null @@ -1,428 +0,0 @@ -import React from 'react'; -import tw from 'twin.macro'; -import Head from 'next/head'; -import { GlobalStyles } from 'twin.macro'; -import { - Header, - FooterExtended, - ThemeProvider, - GlobalStyles as TGCStyles, - useThemeContext, -} from '@theguild/components'; -import * as Tooltip from '@radix-ui/react-tooltip'; -import { FiServer, FiGlobe, FiRadio, FiGithub } from 'react-icons/fi'; -import { Pricing } from '../components/pricing'; - -const PrimaryLink = tw.a` - inline-block - bg-yellow-500 hover:bg-opacity-75 - dark:bg-yellow-600 dark:hover:bg-opacity-100 dark:hover:bg-yellow-500 - text-white px-6 py-3 rounded-lg font-medium - shadow-sm -`; - -const SecondaryLink = tw.a` - inline-block - bg-gray-100 hover:bg-gray-200 - dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 - text-gray-600 px-6 py-3 rounded-lg font-medium - shadow-sm -`; - -const FeatureWrapper = tw.div` - w-full py-24 - odd:bg-gray-50 - odd:dark:bg-gray-900 - even:bg-white - even:dark:bg-black -`; - -const CookiesConsent: React.FC = () => { - const [show, setShow] = React.useState(typeof window !== 'undefined' && localStorage.getItem('cookies') === null); - - const accept = React.useCallback(() => { - setShow(false); - localStorage.setItem('cookies', 'true'); - }, [setShow]); - - if (!show) { - return null; - } - - return ( -
-
-

This website uses cookies to analyze site usage and improve your experience.

-

If you continue to use our services, you are agreeing to the use of such cookies.

-
-
- - Privacy Policy - - -
-
- ); -}; - -const gradients: [string, string][] = [ - ['#ff9472', '#f2709c'], - ['#4776e6', '#8e54e9'], - ['#f857a6', '#ff5858'], - ['#4AC29A', '#BDFFF3'], - ['#00c6ff', '#0072ff'], -]; - -function pickGradient(i: number) { - const gradient = gradients[i % gradients.length]; - - if (!gradient) { - throw new Error('No gradient found'); - } - - return gradient; -} - -function GuildHeader() { - const { isDarkTheme } = useThemeContext(); - const color = isDarkTheme ? '#000' : '#f9fafb'; - - return ( -
- ); -} - -function Hero() { - return ( -
-
-

- Take full control of your GraphQL API -

-

- Prevent breaking changes, monitor performance of your GraphQL API, and manage your API gateway -

-
- Sign up for free - Documentation - - GitHub - -
-
-
- ); -} - -const Highlight = { - Root: tw.div`flex flex-row md:flex-col lg:flex-row flex-1 gap-6`, - Icon: tw.div`w-16 h-16 text-yellow-500 flex-shrink-0`, - Content: tw.div`flex flex-col text-black dark:text-white`, - Title: tw.h3`text-xl font-semibold`, - Description: tw.p`text-gray-600 dark:text-gray-400`, -}; - -function Feature(props: { - title: string; - description: React.ReactNode; - highlights?: Array<{ - title: string; - description: React.ReactNode; - icon?: React.ReactNode; - }>; - image: string; - gradient: number; - flipped?: boolean; -}) { - const { title, description, highlights, image, gradient, flipped } = props; - const [start, end] = pickGradient(gradient); - - return ( - -
-
-
-

- {title} -

-
{description}
-
-
- {title} -
-
- {Array.isArray(highlights) && highlights.length > 0 ? ( -
- {highlights.map(({ title, description, icon }, i) => ( - - {icon} - - {title} - {description} - - - ))} -
- ) : null} -
-
- ); -} - -export default function Index() { - const title = 'GraphQL Hive - Schema Registry and Monitoring'; - const fullDescription = - 'Prevent breaking changes, monitor performance of your GraphQL API, and manage your API gateway (Federation, Stitching) with the Schema Registry. GraphQL Hive is a SAAS solution that is also 100% open source and can be self-hosted.'; - - return ( - - - - {title} - - - - - - - - - - - - - - -
- - - - - -
- -

Push GraphQL schema to the registry and track the history of changes.

-

All your GraphQL services in one place.

-
- } - highlights={[ - { - title: 'Manage your Gateway', - description: 'Connect to Apollo Federation, GraphQL Mesh, Stitching and more.', - icon: , - }, - { - title: 'Global Edge Network', - description: 'Access the registry from any place on earth within milliseconds.', - icon: , - }, - { - title: 'Make it smarter', - description: 'Detect unused parts of Schema thanks to GraphQL analytics.', - icon: , - }, - ]} - image="/features/schema-history.png" - gradient={0} - /> - -
-

Be aware of how your GraphQL API is used and what is the experience of its final users.

-
-
- - - GraphQL Consumers - - Track every source of GraphQL requests and see how the API is consumed. - - - - - - Overall performance - - Get a global overview of the usage of your GraphQL API. - - - - - - Query performance - - Detect slow GraphQL Operations and identify the culprits. - - - -
-
- } - image="/features/monitoring-preview.png" - gradient={1} - flipped - /> - -
-

Maintain your GraphQL API across many teams without concerns.

-
-
- - - Prevent Breaking Changes - - Combination of Schema Registry and GraphQL Monitoring helps you evolve your GraphQL API. - - - - - - Detect unused fields - - Helps you understand the coverage of GraphQL schema and safely remove the unused part. - - - - - - Alerts and notifications - - Stay on top of everything with Slack notifications. - - - -
-
- } - image="/any-ci-cd.svg" - gradient={2} - /> - -
-
-

- Open-Source -

-

Built entirely in public.

-
-
- - - Public roadmap - Influence the future of GraphQL Hive. - - - - - Cloud and Self-Hosted - - MIT licensed, host it on your own infrastructure. - - - - - - Available for free - - Free Hobby plan that fits perfectly for most side projects. - - - - - - Community - - Implement your own features with our help. - - - -
-
-
- - - - - - - - ); -} diff --git a/packages/web/landing-page/postcss.config.cjs b/packages/web/landing-page/postcss.config.cjs new file mode 100644 index 000000000..204207501 --- /dev/null +++ b/packages/web/landing-page/postcss.config.cjs @@ -0,0 +1 @@ +module.exports = require('@theguild/tailwind-config/postcss.config'); diff --git a/packages/web/landing-page/src/pages/_app.tsx b/packages/web/landing-page/src/pages/_app.tsx new file mode 100644 index 000000000..e7dbb4f3b --- /dev/null +++ b/packages/web/landing-page/src/pages/_app.tsx @@ -0,0 +1,47 @@ +import { ReactElement } from 'react'; +import { AppProps } from 'next/app'; +import Head from 'next/head'; +import { FooterExtended, Header } from '@theguild/components'; +import { ThemeProvider } from 'next-themes'; +import '@theguild/components/style.css'; + +const TITLE = 'GraphQL Hive - Schema Registry and Monitoring'; +const DESCRIPTION = + 'Prevent breaking changes, monitor performance of your GraphQL API, and manage your API gateway (Federation, Stitching) with the Schema Registry. GraphQL Hive is a SAAS solution that is also 100% open source and can be self-hosted.'; + +export default function App({ Component, pageProps }: AppProps): ReactElement { + return ( + + + + {TITLE} + + + + + + + + + + + + + +
+ + + + + + ); +} diff --git a/packages/web/landing-page/pages/_document.tsx b/packages/web/landing-page/src/pages/_document.tsx similarity index 71% rename from packages/web/landing-page/pages/_document.tsx rename to packages/web/landing-page/src/pages/_document.tsx index b83a4202f..cd58ae91f 100644 --- a/packages/web/landing-page/pages/_document.tsx +++ b/packages/web/landing-page/src/pages/_document.tsx @@ -1,36 +1,10 @@ import Document, { Html, Head, Main, NextScript } from 'next/document'; -import { ServerStyleSheet } from 'styled-components'; -// eslint-disable-next-line no-process-env -export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_TRACKING_ID; -// eslint-disable-next-line no-process-env +/* eslint-disable no-process-env */ +const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_TRACKING_ID; const CRISP_WEBSITE_ID = process.env.NEXT_PUBLIC_CRISP_WEBSITE_ID; export default class MyDocument extends Document { - static async getInitialProps(ctx) { - const sheet = new ServerStyleSheet(); - const originalRenderPage = ctx.renderPage; - try { - ctx.renderPage = () => - originalRenderPage({ - enhanceApp: App => props => sheet.collectStyles(), - }); - const initialProps = await Document.getInitialProps(ctx); - - return { - ...initialProps, - styles: ( - <> - {initialProps.styles} - {sheet.getStyleElement()} - - ), - }; - } finally { - sheet.seal(); - } - } - render() { const richData = { '@context': 'https://schema.org', @@ -44,18 +18,16 @@ export default class MyDocument extends Document { return ( - {GA_TRACKING_ID &&