diff --git a/examples/with-relay-modern/.babelrc b/examples/with-relay-modern/.babelrc deleted file mode 100644 index d236bcb94689a..0000000000000 --- a/examples/with-relay-modern/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["next/babel"], - "plugins": ["relay"] -} diff --git a/examples/with-relay-modern/.env b/examples/with-relay-modern/.env deleted file mode 100644 index d54ff189f6c02..0000000000000 --- a/examples/with-relay-modern/.env +++ /dev/null @@ -1 +0,0 @@ -NEXT_PUBLIC_RELAY_ENDPOINT=https://nextjs-graphql-with-prisma-relay.vercel.app/api diff --git a/examples/with-relay-modern/.graphqlconfig b/examples/with-relay-modern/.graphqlconfig deleted file mode 100644 index f973e3a39dead..0000000000000 --- a/examples/with-relay-modern/.graphqlconfig +++ /dev/null @@ -1,8 +0,0 @@ -{ - "schemaPath": "schema/schema.graphql", - "extensions": { - "endpoints": { - "dev": "https://nextjs-graphql-with-prisma-relay.vercel.app/api" - } - } -} \ No newline at end of file diff --git a/examples/with-relay-modern/README.md b/examples/with-relay-modern/README.md index 0dbcaa4bd67a1..c4f85fb5f2361 100644 --- a/examples/with-relay-modern/README.md +++ b/examples/with-relay-modern/README.md @@ -1,49 +1 @@ -# Relay Modern Example - -[Relay Modern](https://relay.dev/) is a new version of Relay designed from the ground up to be easier to use, more extensible and, most of all, able to improve performance on mobile devices. Relay Modern accomplishes this with static queries and ahead-of-time code generation. - -This example relies on [Prisma + Nexus](https://github.com/prisma-labs/nextjs-graphql-api-examples) for its GraphQL backend. - -## Deploy your own - -Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-relay-modern&project-name=with-relay-modern&repository-name=with-relay-modern) - -## How to use - -Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: - -```bash -npx create-next-app --example with-relay-modern with-relay-modern-app -# or -yarn create next-app --example with-relay-modern with-relay-modern-app -# or -pnpm create next-app --example with-relay-modern with-relay-modern-app -``` - -Download schema introspection data from configured Relay endpoint - -```bash -npm run schema -# or -yarn schema -``` - -Run Relay ahead-of-time compilation (should be re-run after any edits to components that query data with Relay) - -```bash -npm run relay -# or -yarn relay -``` - -Run the project - -```bash -npm run dev -# or -yarn dev -``` - -Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). +This example has been moved to [with-relay](https://github.com/vercel/next.js/tree/canary/examples/with-relay). diff --git a/examples/with-relay-modern/components/BlogPostPreview.js b/examples/with-relay-modern/components/BlogPostPreview.js deleted file mode 100644 index 4988b2290312d..0000000000000 --- a/examples/with-relay-modern/components/BlogPostPreview.js +++ /dev/null @@ -1,12 +0,0 @@ -import { createFragmentContainer, graphql } from 'react-relay' - -const BlogPostPreview = ({ post }) =>
  • {post.title}
  • - -export default createFragmentContainer(BlogPostPreview, { - post: graphql` - fragment BlogPostPreview_post on BlogPost { - id - title - } - `, -}) diff --git a/examples/with-relay-modern/components/BlogPosts.js b/examples/with-relay-modern/components/BlogPosts.js deleted file mode 100644 index 4936c20e5452c..0000000000000 --- a/examples/with-relay-modern/components/BlogPosts.js +++ /dev/null @@ -1,28 +0,0 @@ -import { createFragmentContainer, graphql } from 'react-relay' -import BlogPostPreview from './BlogPostPreview' - -const BlogPosts = ({ viewer }) => ( -
    -

    Blog posts

    - -
    -) - -export default createFragmentContainer(BlogPosts, { - viewer: graphql` - fragment BlogPosts_viewer on Viewer { - allBlogPosts(first: 10, orderBy: { createdAt: desc }) { - edges { - node { - ...BlogPostPreview_post - id - } - } - } - } - `, -}) diff --git a/examples/with-relay-modern/lib/relay.js b/examples/with-relay-modern/lib/relay.js deleted file mode 100644 index 4f91b008a6b10..0000000000000 --- a/examples/with-relay-modern/lib/relay.js +++ /dev/null @@ -1,50 +0,0 @@ -import { useMemo } from 'react' -import { Environment, Network, RecordSource, Store } from 'relay-runtime' - -let relayEnvironment - -// Define a function that fetches the results of an operation (query/mutation/etc) -// and returns its results as a Promise -function fetchQuery(operation, variables, cacheConfig, uploadables) { - return fetch(process.env.NEXT_PUBLIC_RELAY_ENDPOINT, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, // Add authentication and other headers here - body: JSON.stringify({ - query: operation.text, // GraphQL text from input - variables, - }), - }).then((response) => response.json()) -} - -function createEnvironment(initialRecords) { - return new Environment({ - // Create a network layer from the fetch function - network: Network.create(fetchQuery), - store: new Store(new RecordSource()), - }) -} - -export function initEnvironment(initialRecords) { - // Create a network layer from the fetch function - const environment = relayEnvironment ?? createEnvironment(initialRecords) - - // If your page has Next.js data fetching methods that use Relay, the initial records - // will get hydrated here - if (initialRecords) { - environment.getStore().publish(new RecordSource(initialRecords)) - } - // For SSG and SSR always create a new Relay environment - if (typeof window === 'undefined') return environment - // Create the Relay environment once in the client - if (!relayEnvironment) relayEnvironment = environment - - return relayEnvironment -} - -export function useEnvironment(initialRecords) { - const store = useMemo(() => initEnvironment(initialRecords), [initialRecords]) - return store -} diff --git a/examples/with-relay-modern/package.json b/examples/with-relay-modern/package.json deleted file mode 100644 index 4f3232f9014a4..0000000000000 --- a/examples/with-relay-modern/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "private": true, - "scripts": { - "dev": "next", - "build": "next build", - "start": "next start", - "relay": "relay-compiler --src ./ --exclude '**/.next/**' '**/node_modules/**' '**/test/**' '**/__generated__/**' --exclude '**/schema/**' --schema ./schema/schema.graphql", - "schema": "graphql get-schema -e dev" - }, - "dependencies": { - "graphql": "^14.6.0", - "next": "latest", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-relay": "^9.0.0" - }, - "devDependencies": { - "babel-plugin-relay": "^9.0.0", - "graphql-cli": "^3.0.14", - "relay-compiler": "^9.0.0" - } -} diff --git a/examples/with-relay-modern/pages/_app.js b/examples/with-relay-modern/pages/_app.js deleted file mode 100644 index 838595f393e65..0000000000000 --- a/examples/with-relay-modern/pages/_app.js +++ /dev/null @@ -1,12 +0,0 @@ -import { ReactRelayContext } from 'react-relay' -import { useEnvironment } from '../lib/relay' - -export default function App({ Component, pageProps }) { - const environment = useEnvironment(pageProps.initialRecords) - - return ( - - - - ) -} diff --git a/examples/with-relay-modern/pages/about.js b/examples/with-relay-modern/pages/about.js deleted file mode 100644 index 3b24db70d9963..0000000000000 --- a/examples/with-relay-modern/pages/about.js +++ /dev/null @@ -1,12 +0,0 @@ -import Link from 'next/link' - -export default function About() { - return ( -
    - - Home - -

    This is the about page

    -
    - ) -} diff --git a/examples/with-relay-modern/pages/index.js b/examples/with-relay-modern/pages/index.js deleted file mode 100644 index bec104d03a543..0000000000000 --- a/examples/with-relay-modern/pages/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import Link from 'next/link' -import { fetchQuery } from 'react-relay' -import { initEnvironment } from '../lib/relay' -import BlogPosts from '../components/BlogPosts' -import indexPageQuery from '../queries/indexPage' - -const Index = ({ viewer }) => ( -
    - - About - - -
    -) - -export async function getStaticProps() { - const environment = initEnvironment() - const queryProps = await fetchQuery(environment, indexPageQuery) - const initialRecords = environment.getStore().getSource().toJSON() - - return { - props: { - ...queryProps, - initialRecords, - }, - } -} - -export default Index diff --git a/examples/with-relay-modern/queries/indexPage.js b/examples/with-relay-modern/queries/indexPage.js deleted file mode 100644 index 780c8c16d1abb..0000000000000 --- a/examples/with-relay-modern/queries/indexPage.js +++ /dev/null @@ -1,9 +0,0 @@ -import { graphql } from 'react-relay' - -export default graphql` - query indexPage_indexQuery { - viewer { - ...BlogPosts_viewer - } - } -` diff --git a/examples/with-relay-modern/schema/init-schema.graphql b/examples/with-relay-modern/schema/init-schema.graphql deleted file mode 100644 index aafc0574a9df7..0000000000000 --- a/examples/with-relay-modern/schema/init-schema.graphql +++ /dev/null @@ -1,7 +0,0 @@ -type BlogPost implements Node { - content: String! - createdAt: DateTime! - id: ID! @isUnique - title: String! - updatedAt: DateTime! -} diff --git a/examples/with-relay/.env b/examples/with-relay/.env new file mode 100644 index 0000000000000..85b2428c28b5c --- /dev/null +++ b/examples/with-relay/.env @@ -0,0 +1,2 @@ +NEXT_PUBLIC_GRAPHQL_API_ENDPOINT="https://api.github.com/graphql" +NEXT_PUBLIC_GITHUB_API_TOKEN= \ No newline at end of file diff --git a/examples/with-relay-modern/.gitignore b/examples/with-relay/.gitignore similarity index 72% rename from examples/with-relay-modern/.gitignore rename to examples/with-relay/.gitignore index c86f6fff985cc..42e7235ea0848 100644 --- a/examples/with-relay-modern/.gitignore +++ b/examples/with-relay/.gitignore @@ -23,16 +23,16 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* # local env files -.env.local -.env.development.local -.env.test.local -.env.production.local +.env*.local # vercel .vercel -# relay -__generated__/ -schema/schema.graphql +# typescript +*.tsbuildinfo + +# Relay +__generated__/** \ No newline at end of file diff --git a/examples/with-relay/README.md b/examples/with-relay/README.md new file mode 100644 index 0000000000000..0e5c04de21c75 --- /dev/null +++ b/examples/with-relay/README.md @@ -0,0 +1,35 @@ +# Relay and TypeScript Example + +This example shows how to integrate Relay in Next.js. The application is built with TypeScript and +leverages the +[Next.js compiler's built-in Relay support](https://nextjs.org/docs/advanced-features/compiler#relay) +for converting GraphQL operations to runtime artifacts. + +Note this example uses with the [GitHub GraphQL API](https://docs.github.com/en/graphql) which requires authentication. In order to make requests to the API, you must first [generate a personal access token on GitHub](https://github.com/settings/tokens/new) and store it in the environment variable `NEXT_PUBLIC_GITHUB_API_TOKEN`. + +## Deploy your own + +Deploy the example using +[Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) or +preview live with +[StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-relay) + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-relay&project-name=with-relay&repository-name=with-relay) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) +with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), +or [pnpm](https://pnpm.io) to bootstrap the example: + +```bash +npx create-next-app --example with-relay with-relay-app +# or +yarn create next-app --example with-relay with-relay-app +# or +pnpm create next-app --example with-relay with-relay-app +``` + +Deploy it to the cloud with +[Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) +([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-relay/codegen.yml b/examples/with-relay/codegen.yml new file mode 100644 index 0000000000000..4f6a04f4a08bd --- /dev/null +++ b/examples/with-relay/codegen.yml @@ -0,0 +1,8 @@ +schema: + - ${NEXT_PUBLIC_GRAPHQL_API_ENDPOINT}: + headers: + Authorization: Bearer ${NEXT_PUBLIC_GITHUB_API_TOKEN} +generates: + ./schema.graphql: + plugins: + - schema-ast diff --git a/examples/with-relay/graphql/IssuesQuery.ts b/examples/with-relay/graphql/IssuesQuery.ts new file mode 100644 index 0000000000000..897da713f20c9 --- /dev/null +++ b/examples/with-relay/graphql/IssuesQuery.ts @@ -0,0 +1,21 @@ +import { graphql } from 'relay-runtime' + +export default graphql` + query IssuesQuery($owner: String!, $name: String!, $first: Int!) { + repository(name: $name, owner: $owner) { + issues( + first: $first + states: [OPEN] + orderBy: { field: UPDATED_AT, direction: DESC } + ) { + edges { + node { + number + title + url + } + } + } + } + } +` diff --git a/examples/with-relay/lib/relay.ts b/examples/with-relay/lib/relay.ts new file mode 100644 index 0000000000000..86bfae5ed74d0 --- /dev/null +++ b/examples/with-relay/lib/relay.ts @@ -0,0 +1,71 @@ +import { useMemo } from 'react' +import { + Environment, + Network, + RecordSource, + Store, + type GraphQLResponse, +} from 'relay-runtime' + +let relayEnvironment: Environment | null = null + +function createRelayNetwork() { + return Network.create(async ({ text: query }, variables) => { + const response = await fetch( + process.env.NEXT_PUBLIC_GRAPHQL_API_ENDPOINT as string, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + Authorization: `Bearer ${process.env.NEXT_PUBLIC_GITHUB_API_TOKEN}`, + }, // Add authentication and other headers here + body: JSON.stringify({ query, variables }), + } + ) + + if (response.status !== 200) { + console.error(await response.text()) + throw new Error('Relay Network Error: Invalid response from server') + } + + return (await response.json()) as GraphQLResponse + }) +} + +export const initEnvironment = (records = {}): Environment => { + const source = new RecordSource(records) + const store = new Store(source, { gcReleaseBufferSize: 10 }) + + // Create a new instance of Relay environment for every server-side request + if (typeof window === 'undefined') { + return new Environment({ + configName: 'server', + network: createRelayNetwork(), + store, + isServer: true, + }) + } + + // Reuse Relay environment on client-side + if (!relayEnvironment) { + relayEnvironment = new Environment({ + configName: 'client', + network: createRelayNetwork(), + store, + isServer: false, + }) + } + + return relayEnvironment +} + +export function useRelayEnvironment(initialRecords = {}) { + return useMemo(() => { + return initEnvironment(initialRecords) + }, [initialRecords]) +} + +export function dehydrateStore(environment: Environment) { + return environment.getStore().getSource().toJSON() +} diff --git a/examples/with-relay/next-env.d.ts b/examples/with-relay/next-env.d.ts new file mode 100644 index 0000000000000..4f11a03dc6cc3 --- /dev/null +++ b/examples/with-relay/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/with-relay/next.config.js b/examples/with-relay/next.config.js new file mode 100644 index 0000000000000..a5d5e7f4949d7 --- /dev/null +++ b/examples/with-relay/next.config.js @@ -0,0 +1,15 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + reactStrictMode: true, + compiler: { + relay: { + src: './', + artifactDirectory: './__generated__', + language: 'typescript', + }, + }, +} + +module.exports = nextConfig diff --git a/examples/with-relay/package.json b/examples/with-relay/package.json new file mode 100644 index 0000000000000..83740fdb3b67a --- /dev/null +++ b/examples/with-relay/package.json @@ -0,0 +1,30 @@ +{ + "private": true, + "scripts": { + "dev": "yarn schema && yarn relay && next dev", + "build": "yarn schema && yarn relay && next build", + "start": "next start", + "lint": "next lint", + "relay": "relay-compiler", + "schema": "graphql-codegen" + }, + "dependencies": { + "next": "latest", + "react": "18.1.0", + "react-dom": "18.1.0", + "react-relay": "^13.2.0", + "relay-runtime": "^13.2.0" + }, + "devDependencies": { + "@graphql-codegen/cli": "^2.6.2", + "@graphql-codegen/schema-ast": "^2.4.1", + "@types/node": "17.0.40", + "@types/react": "18.0.12", + "@types/react-dom": "18.0.5", + "@types/react-relay": "^13.0.2", + "@types/relay-runtime": "^13.0.3", + "graphql": "^16.5.0", + "relay-compiler": "^13.2.0", + "typescript": "4.7.3" + } +} diff --git a/examples/with-relay/pages/_app.tsx b/examples/with-relay/pages/_app.tsx new file mode 100644 index 0000000000000..d17ddb9fb178f --- /dev/null +++ b/examples/with-relay/pages/_app.tsx @@ -0,0 +1,17 @@ +import '../styles/globals.css' +import type { AppProps } from 'next/app' +import { RelayEnvironmentProvider } from 'react-relay' + +import { useRelayEnvironment } from '../lib/relay' + +function MyApp({ Component, pageProps }: AppProps) { + const relayEnvironment = useRelayEnvironment(pageProps.initialRecords) + + return ( + + + + ) +} + +export default MyApp diff --git a/examples/with-relay/pages/csr.tsx b/examples/with-relay/pages/csr.tsx new file mode 100644 index 0000000000000..9a08f7d420914 --- /dev/null +++ b/examples/with-relay/pages/csr.tsx @@ -0,0 +1,68 @@ +import type { NextPage } from 'next' +import Head from 'next/head' +import Image from 'next/image' +import { Suspense } from 'react' +import { useLazyLoadQuery } from 'react-relay' + +import type { IssuesQuery } from '../__generated__/IssuesQuery.graphql' +import IssuesQueryDocument from '../graphql/IssuesQuery' +import styles from '../styles/Home.module.css' + +const CSR: NextPage = () => { + const data = useLazyLoadQuery(IssuesQueryDocument, { + owner: 'vercel', + name: 'next.js', + first: 4, + }) + + return ( +
    + + Create Next App + + + + +
    +

    + Welcome to Next.js! +

    + +

    + Get started by editing{' '} + pages/index.tsx +

    + +
    + Loading
    }> + {data?.repository?.issues?.edges?.map((edge) => ( + +

    Issue {edge?.node?.number}

    +

    {edge?.node?.title}

    +
    + ))} + +
    + + + + + ) +} + +export default CSR diff --git a/examples/with-relay/pages/index.tsx b/examples/with-relay/pages/index.tsx new file mode 100644 index 0000000000000..0a19652dbb4f9 --- /dev/null +++ b/examples/with-relay/pages/index.tsx @@ -0,0 +1,60 @@ +import type { NextPage } from 'next' +import Link from 'next/link' +import Head from 'next/head' +import Image from 'next/image' + +import styles from '../styles/Home.module.css' + +const Home: NextPage = () => { + return ( +
    + + Create Next App + + + + +
    +

    + Welcome to Next.js! +

    + +

    + Get started by editing{' '} + pages/index.tsx +

    + + +
    + + +
    + ) +} + +export default Home diff --git a/examples/with-relay/pages/ssr.tsx b/examples/with-relay/pages/ssr.tsx new file mode 100644 index 0000000000000..77be706a22340 --- /dev/null +++ b/examples/with-relay/pages/ssr.tsx @@ -0,0 +1,83 @@ +import type { NextPage, InferGetServerSidePropsType } from 'next' +import Head from 'next/head' +import Image from 'next/image' +import { fetchQuery } from 'react-relay' + +import type { IssuesQuery } from '../__generated__/IssuesQuery.graphql' +import IssuesQueryDocument from '../graphql/IssuesQuery' +import { initEnvironment, dehydrateStore } from '../lib/relay' +import styles from '../styles/Home.module.css' + +const SSR: NextPage> = ({ + issues, +}) => { + return ( +
    + + Create Next App + + + + +
    +

    + Welcome to Next.js! +

    + +

    + Get started by editing{' '} + pages/index.tsx +

    + +
    + {issues?.edges?.map((edge) => ( + +

    Issue {edge?.node?.number}

    +

    {edge?.node?.title}

    +
    + ))} +
    +
    + + +
    + ) +} + +export default SSR + +export const getServerSideProps = async () => { + const environment = initEnvironment() + + const result = await fetchQuery( + environment, + IssuesQueryDocument, + { + owner: 'vercel', + name: 'next.js', + first: 4, + } + ).toPromise() + + return { + props: { + initialRecords: dehydrateStore(environment), + issues: result?.repository?.issues, + }, + } +} diff --git a/examples/with-relay/public/favicon.ico b/examples/with-relay/public/favicon.ico new file mode 100644 index 0000000000000..718d6fea4835e Binary files /dev/null and b/examples/with-relay/public/favicon.ico differ diff --git a/examples/with-relay/public/vercel.svg b/examples/with-relay/public/vercel.svg new file mode 100644 index 0000000000000..fbf0e25a651c2 --- /dev/null +++ b/examples/with-relay/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/with-relay/relay.config.cjs b/examples/with-relay/relay.config.cjs new file mode 100644 index 0000000000000..c9e1307ae5da9 --- /dev/null +++ b/examples/with-relay/relay.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + src: './', + artifactDirectory: './__generated__', + language: 'typescript', + schema: './schema.graphql', + exclude: ['**/.next/**', '**/node_modules/**', '**/__generated__/**'], +} diff --git a/examples/with-relay/styles/Home.module.css b/examples/with-relay/styles/Home.module.css new file mode 100644 index 0000000000000..32a57d52f34c4 --- /dev/null +++ b/examples/with-relay/styles/Home.module.css @@ -0,0 +1,116 @@ +.container { + padding: 0 2rem; +} + +.main { + min-height: 100vh; + padding: 4rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + display: flex; + flex: 1; + padding: 2rem 0; + border-top: 1px solid #eaeaea; + justify-content: center; + align-items: center; +} + +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} + +.title a { + color: #0070f3; + text-decoration: none; +} + +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} + +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} + +.title, +.description { + text-align: center; +} + +.description { + margin: 4rem 0; + line-height: 1.5; + font-size: 1.5rem; +} + +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, + Bitstream Vera Sans Mono, Courier New, monospace; +} + +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; +} + +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + max-width: 300px; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/examples/with-relay/styles/globals.css b/examples/with-relay/styles/globals.css new file mode 100644 index 0000000000000..e5e2dcc23baf1 --- /dev/null +++ b/examples/with-relay/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/examples/with-relay/tsconfig.json b/examples/with-relay/tsconfig.json new file mode 100644 index 0000000000000..99710e857874f --- /dev/null +++ b/examples/with-relay/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +}